From 9fde555cc389cd2d68128b25598449b1d3ada74b Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Thu, 22 Feb 2018 00:07:37 +0900
Subject: [PATCH] wip

---
 package.json                                  |   1 +
 src/web/app/desktop/views/components/home.vue | 155 +++++++++---------
 src/web/app/desktop/views/components/index.ts |   2 +
 .../components/widgets/server.cpu-memory.vue  |   2 +-
 .../views/components/widgets/server.cpu.vue   |   4 +-
 .../views/components/widgets/server.info.vue  |   4 +-
 .../views/components/widgets/server.pie.vue   |   2 +-
 7 files changed, 87 insertions(+), 83 deletions(-)

diff --git a/package.json b/package.json
index 033f76c30..4521b0ceb 100644
--- a/package.json
+++ b/package.json
@@ -187,6 +187,7 @@
 		"vue-loader": "^14.1.1",
 		"vue-router": "^3.0.1",
 		"vue-template-compiler": "^2.5.13",
+		"vuedraggable": "^2.16.0",
 		"web-push": "3.2.5",
 		"webpack": "3.10.0",
 		"webpack-replace-loader": "^1.3.0",
diff --git a/src/web/app/desktop/views/components/home.vue b/src/web/app/desktop/views/components/home.vue
index 9d2198d9d..9962e0da1 100644
--- a/src/web/app/desktop/views/components/home.vue
+++ b/src/web/app/desktop/views/components/home.vue
@@ -31,38 +31,51 @@
 				<button @click="addWidget">追加</button>
 			</div>
 			<div class="trash">
-				<div ref="trash"></div>
+				<x-draggable v-model="trash" :options="{ group: 'x' }" @add="onTrash"></x-draggable>
 				<p>ゴミ箱</p>
 			</div>
 		</div>
 	</div>
 	<div class="main">
-		<div v-for="place in ['left', 'main', 'right']" :class="place" :ref="place" :data-place="place">
-			<template v-if="place != 'main'">
-				<template v-for="widget in widgets[place]">
-					<div class="customize-container" v-if="customize" :key="widget.id" @contextmenu.stop.prevent="onWidgetContextmenu(widget.id)" :data-widget-id="widget.id">
-						<component :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id"/>
-					</div>
-					<template v-else>
-						<component :is="`mkw-${widget.name}`" :key="widget.id" :widget="widget" :ref="widget.id" @chosen="warp"/>
-					</template>
-				</template>
-			</template>
-			<template v-else>
-				<mk-timeline ref="tl" @loaded="onTlLoaded" v-if="place == 'main' && mode == 'timeline'"/>
-				<mk-mentions @loaded="onTlLoaded" v-if="place == 'main' && mode == 'mentions'"/>
-			</template>
-		</div>
+		<template v-if="customize">
+			<x-draggable v-for="place in ['left', 'right']"
+				:list="widgets[place]"
+				:class="place"
+				:data-place="place"
+				:options="{ group: 'x', animation: 150 }"
+				@sort="onWidgetSort"
+				:key="place"
+			>
+				<div v-for="widget in widgets[place]" class="customize-container" :key="widget.id" @contextmenu.stop.prevent="onWidgetContextmenu(widget.id)">
+					<component :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id"/>
+				</div>
+			</x-draggable>
+			<div class="main">
+				<mk-timeline ref="tl" @loaded="onTlLoaded"/>
+			</div>
+		</template>
+		<template v-else>
+			<div v-for="place in ['left', 'right']" :class="place">
+				<component v-for="widget in widgets[place]" :is="`mkw-${widget.name}`" :key="widget.id" :widget="widget" @chosen="warp"/>
+			</div>
+			<div class="main">
+				<mk-timeline ref="tl" @loaded="onTlLoaded" v-if="mode == 'timeline'"/>
+				<mk-mentions @loaded="onTlLoaded" v-if="mode == 'mentions'"/>
+			</div>
+		</template>
 	</div>
 </div>
 </template>
 
 <script lang="ts">
 import Vue from 'vue';
+import * as XDraggable from 'vuedraggable';
 import * as uuid from 'uuid';
-import * as Sortable from 'sortablejs';
 
 export default Vue.extend({
+	components: {
+		XDraggable
+	},
 	props: {
 		customize: Boolean,
 		mode: {
@@ -72,50 +85,49 @@ export default Vue.extend({
 	},
 	data() {
 		return {
-			widgetAdderSelected: null
+			widgetAdderSelected: null,
+			trash: [],
+			widgets: {
+				left: [],
+				right: []
+			}
 		};
 	},
 	computed: {
-		home(): any {
-			//#region 互換性のため
-			(this as any).os.i.client_settings.home.forEach(w => {
-				if (w.name == 'rss-reader') w.name = 'rss';
-				if (w.name == 'user-recommendation') w.name = 'users';
-				if (w.name == 'recommended-polls') w.name = 'polls';
-			});
-			//#endregion
-			return (this as any).os.i.client_settings.home;
+		home: {
+			get(): any[] {
+				//#region 互換性のため
+				(this as any).os.i.client_settings.home.forEach(w => {
+					if (w.name == 'rss-reader') w.name = 'rss';
+					if (w.name == 'user-recommendation') w.name = 'users';
+					if (w.name == 'recommended-polls') w.name = 'polls';
+				});
+				//#endregion
+				return (this as any).os.i.client_settings.home;
+			},
+			set(value) {
+				(this as any).os.i.client_settings.home = value;
+			}
 		},
-		leftWidgets(): any {
+		left(): any[] {
 			return this.home.filter(w => w.place == 'left');
 		},
-		rightWidgets(): any {
+		right(): any[] {
 			return this.home.filter(w => w.place == 'right');
-		},
-		widgets(): any {
-			return {
-				left: this.leftWidgets,
-				right: this.rightWidgets,
-			};
-		},
-		leftEl(): Element {
-			return (this.$refs.left as Element[])[0];
-		},
-		rightEl(): Element {
-			return (this.$refs.right as Element[])[0];
 		}
 	},
+	created() {
+		this.widgets.left = this.left;
+		this.widgets.right = this.right;
+		this.$watch('os.i', i => {
+			this.widgets.left = this.left;
+			this.widgets.right = this.right;
+		}, {
+			deep: true
+		});
+	},
 	mounted() {
 		this.$nextTick(() => {
-			if (!this.customize) {
-				if (this.leftEl.children.length == 0) {
-					this.leftEl.parentNode.removeChild(this.leftEl);
-				}
-				if (this.rightEl.children.length == 0) {
-					this.rightEl.parentNode.removeChild(this.rightEl);
-				}
-			}
-
 			if (this.customize) {
 				(this as any).apis.dialog({
 					title: '%fa:info-circle%カスタマイズのヒント',
@@ -127,30 +139,6 @@ export default Vue.extend({
 						text: 'Got it!'
 					}]
 				});
-
-				const sortableOption = {
-					group: 'kyoppie',
-					animation: 150,
-					onMove: evt => {
-						const id = evt.dragged.getAttribute('data-widget-id');
-						this.home.find(w => w.id == id).place = evt.to.getAttribute('data-place');
-					},
-					onSort: () => {
-						this.saveHome();
-					}
-				};
-
-				new Sortable(this.leftEl, sortableOption);
-				new Sortable(this.rightEl, sortableOption);
-				new Sortable(this.$refs.trash, Object.assign({}, sortableOption, {
-					onAdd: evt => {
-						const el = evt.item;
-						const id = el.getAttribute('data-widget-id');
-						el.parentNode.removeChild(el);
-						this.home = this.home.filter(w => w.id != id);
-						this.saveHome();
-					}
-				}));
 			}
 		});
 	},
@@ -161,6 +149,12 @@ export default Vue.extend({
 		onWidgetContextmenu(widgetId) {
 			(this.$refs[widgetId] as any)[0].func();
 		},
+		onWidgetSort() {
+			this.saveHome();
+		},
+		onTrash(evt) {
+			this.saveHome();
+		},
 		addWidget() {
 			const widget = {
 				name: this.widgetAdderSelected,
@@ -169,11 +163,15 @@ export default Vue.extend({
 				data: {}
 			};
 
-			this.home.unshift(widget);
-
+			this.widgets.left.unshift(widget);
 			this.saveHome();
 		},
 		saveHome() {
+			const left = this.widgets.left;
+			const right = this.widgets.right;
+			this.home = left.concat(right);
+			left.forEach(w => w.place = 'left');
+			right.forEach(w => w.place = 'right');
 			(this as any).api('i/update_home', {
 				home: this.home
 			});
@@ -282,6 +280,7 @@ export default Vue.extend({
 		> .main
 			padding 16px
 			width calc(100% - 275px * 2)
+			order 2
 
 		> *:not(main)
 			width 275px
@@ -292,9 +291,11 @@ export default Vue.extend({
 
 		> .left
 			padding-left 16px
+			order 1
 
 		> .right
 			padding-right 16px
+			order 3
 
 		@media (max-width 1100px)
 			> *:not(main)
diff --git a/src/web/app/desktop/views/components/index.ts b/src/web/app/desktop/views/components/index.ts
index 86606a14a..2b5e863ea 100644
--- a/src/web/app/desktop/views/components/index.ts
+++ b/src/web/app/desktop/views/components/index.ts
@@ -36,6 +36,7 @@ import wNotifications from './widgets/notifications.vue';
 import wBroadcast from './widgets/broadcast.vue';
 import wTimemachine from './widgets/timemachine.vue';
 import wProfile from './widgets/profile.vue';
+import wServer from './widgets/server.vue';
 
 Vue.component('mk-ui', ui);
 Vue.component('mk-ui-notification', uiNotification);
@@ -73,3 +74,4 @@ Vue.component('mkw-notifications', wNotifications);
 Vue.component('mkw-broadcast', wBroadcast);
 Vue.component('mkw-timemachine', wTimemachine);
 Vue.component('mkw-profile', wProfile);
+Vue.component('mkw-server', wServer);
diff --git a/src/web/app/desktop/views/components/widgets/server.cpu-memory.vue b/src/web/app/desktop/views/components/widgets/server.cpu-memory.vue
index 00b3dc3af..d75a14256 100644
--- a/src/web/app/desktop/views/components/widgets/server.cpu-memory.vue
+++ b/src/web/app/desktop/views/components/widgets/server.cpu-memory.vue
@@ -53,7 +53,7 @@
 
 <script lang="ts">
 import Vue from 'vue';
-import uuid from 'uuid';
+import * as uuid from 'uuid';
 
 export default Vue.extend({
 	props: ['connection'],
diff --git a/src/web/app/desktop/views/components/widgets/server.cpu.vue b/src/web/app/desktop/views/components/widgets/server.cpu.vue
index 96184d188..596c856da 100644
--- a/src/web/app/desktop/views/components/widgets/server.cpu.vue
+++ b/src/web/app/desktop/views/components/widgets/server.cpu.vue
@@ -3,8 +3,8 @@
 	<x-pie class="pie" :value="usage"/>
 	<div>
 		<p>%fa:microchip%CPU</p>
-		<p>{{ cores }} Cores</p>
-		<p>{{ model }}</p>
+		<p>{{ meta.cpu.cores }} Cores</p>
+		<p>{{ meta.cpu.model }}</p>
 	</div>
 </div>
 </template>
diff --git a/src/web/app/desktop/views/components/widgets/server.info.vue b/src/web/app/desktop/views/components/widgets/server.info.vue
index 870baf149..bed6a1b74 100644
--- a/src/web/app/desktop/views/components/widgets/server.info.vue
+++ b/src/web/app/desktop/views/components/widgets/server.info.vue
@@ -14,8 +14,8 @@ export default Vue.extend({
 });
 </script>
 
-<style lang="info" scoped>
-.uptimes
+<style lang="stylus" scoped>
+.info
 	padding 10px 14px
 
 	> p
diff --git a/src/web/app/desktop/views/components/widgets/server.pie.vue b/src/web/app/desktop/views/components/widgets/server.pie.vue
index 45ca8101b..ce2cff1d0 100644
--- a/src/web/app/desktop/views/components/widgets/server.pie.vue
+++ b/src/web/app/desktop/views/components/widgets/server.pie.vue
@@ -14,7 +14,7 @@
 		fill="none"
 		stroke-width="0.1"
 		:stroke="color"/>
-	<text x="50%" y="50%" dy="0.05" text-anchor="middle">{{ (p * 100).toFixed(0) }}%</text>
+	<text x="50%" y="50%" dy="0.05" text-anchor="middle">{{ (value * 100).toFixed(0) }}%</text>
 </svg>
 </template>