summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2018-06-06 19:22:45 +0900
committersyuilo <syuilotan@yahoo.co.jp>2018-06-06 19:22:45 +0900
commitb0f989dbacbdbdd091b0d220496d22f47c795576 (patch)
treec4af330d8eb11c1d0d5dc0a991409060e9287c6b /src
parentUpdate README.md (diff)
downloadsharkey-b0f989dbacbdbdd091b0d220496d22f47c795576.tar.gz
sharkey-b0f989dbacbdbdd091b0d220496d22f47c795576.tar.bz2
sharkey-b0f989dbacbdbdd091b0d220496d22f47c795576.zip
Deckにウィジェットを置けるように
Diffstat (limited to 'src')
-rw-r--r--src/client/app/common/define-widget.ts21
-rw-r--r--src/client/app/common/scripts/streaming/home.ts25
-rw-r--r--src/client/app/common/views/components/menu.vue10
-rw-r--r--src/client/app/common/views/widgets/broadcast.vue2
-rw-r--r--src/client/app/common/views/widgets/calendar.vue4
-rw-r--r--src/client/app/common/views/widgets/donation.vue2
-rw-r--r--src/client/app/common/views/widgets/rss.vue2
-rw-r--r--src/client/app/common/views/widgets/slideshow.vue2
-rw-r--r--src/client/app/desktop/views/components/home.vue4
-rw-r--r--src/client/app/desktop/views/components/widget-container.vue2
-rw-r--r--src/client/app/desktop/views/pages/deck/deck.column.vue74
-rw-r--r--src/client/app/desktop/views/pages/deck/deck.notifications-column.vue2
-rw-r--r--src/client/app/desktop/views/pages/deck/deck.vue14
-rw-r--r--src/client/app/desktop/views/pages/deck/deck.widgets-column.vue152
-rw-r--r--src/client/app/mobile/views/pages/widgets.vue4
-rw-r--r--src/client/app/store.ts89
-rw-r--r--src/server/api/endpoints.ts5
-rw-r--r--src/server/api/endpoints/i/update_home.ts51
-rw-r--r--src/server/api/endpoints/i/update_mobile_home.ts52
-rw-r--r--src/server/api/endpoints/i/update_widget.ts79
20 files changed, 417 insertions, 179 deletions
diff --git a/src/client/app/common/define-widget.ts b/src/client/app/common/define-widget.ts
index 0b2bc36566..2fae28be72 100644
--- a/src/client/app/common/define-widget.ts
+++ b/src/client/app/common/define-widget.ts
@@ -9,9 +9,9 @@ export default function<T extends object>(data: {
widget: {
type: Object
},
- isMobile: {
- type: Boolean,
- default: false
+ platform: {
+ type: String,
+ required: true
},
isCustomizeMode: {
type: Boolean,
@@ -66,17 +66,10 @@ export default function<T extends object>(data: {
this.bakeProps();
- if (this.isMobile) {
- (this as any).api('i/update_mobile_home', {
- id: this.id,
- data: this.props
- });
- } else {
- (this as any).api('i/update_home', {
- id: this.id,
- data: this.props
- });
- }
+ (this as any).api('i/update_widget', {
+ id: this.id,
+ data: this.props
+ });
}
}
});
diff --git a/src/client/app/common/scripts/streaming/home.ts b/src/client/app/common/scripts/streaming/home.ts
index a27c55a60d..dd18c70d70 100644
--- a/src/client/app/common/scripts/streaming/home.ts
+++ b/src/client/app/common/scripts/streaming/home.ts
@@ -58,25 +58,18 @@ export class HomeStream extends Stream {
});
this.on('home_updated', x => {
- if (x.home) {
- os.store.commit('settings/setHome', x.home);
- } else {
- os.store.commit('settings/setHomeWidget', {
- id: x.id,
- data: x.data
- });
- }
+ os.store.commit('settings/setHome', x);
});
this.on('mobile_home_updated', x => {
- if (x.home) {
- os.store.commit('settings/setMobileHome', x.home);
- } else {
- os.store.commit('settings/setMobileHomeWidget', {
- id: x.id,
- data: x.data
- });
- }
+ os.store.commit('settings/setMobileHome', x);
+ });
+
+ this.on('widgetUpdated', x => {
+ os.store.commit('settings/setWidget', {
+ id: x.id,
+ data: x.data
+ });
});
// トークンが再生成されたとき
diff --git a/src/client/app/common/views/components/menu.vue b/src/client/app/common/views/components/menu.vue
index e5df8345b9..73c8403ad3 100644
--- a/src/client/app/common/views/components/menu.vue
+++ b/src/client/app/common/views/components/menu.vue
@@ -2,7 +2,10 @@
<div class="mk-menu">
<div class="backdrop" ref="backdrop" @click="close"></div>
<div class="popover" :class="{ compact }" ref="popover">
- <button v-for="item in items" @click="clicked(item.onClick)" v-html="item.content"></button>
+ <template v-for="item in items">
+ <div v-if="item == null"></div>
+ <button v-else @click="clicked(item.onClick)" v-html="item.content"></button>
+ </template>
</div>
</div>
</template>
@@ -150,4 +153,9 @@ $border-color = rgba(27, 31, 35, 0.15)
color $theme-color-foreground
background darken($theme-color, 10%)
+ > div
+ margin 8px 0
+ height 1px
+ background #eee
+
</style>
diff --git a/src/client/app/common/views/widgets/broadcast.vue b/src/client/app/common/views/widgets/broadcast.vue
index f337cec853..69b2a54fe9 100644
--- a/src/client/app/common/views/widgets/broadcast.vue
+++ b/src/client/app/common/views/widgets/broadcast.vue
@@ -2,7 +2,7 @@
<div class="mkw-broadcast"
:data-found="broadcasts.length != 0"
:data-melt="props.design == 1"
- :data-mobile="isMobile"
+ :data-mobile="platform == 'mobile'"
>
<div class="icon">
<svg height="32" version="1.1" viewBox="0 0 32 32" width="32">
diff --git a/src/client/app/common/views/widgets/calendar.vue b/src/client/app/common/views/widgets/calendar.vue
index 0e9714960a..333b56f629 100644
--- a/src/client/app/common/views/widgets/calendar.vue
+++ b/src/client/app/common/views/widgets/calendar.vue
@@ -1,5 +1,5 @@
<template>
-<div class="mkw-calendar" :data-special="special" :data-mobile="isMobile">
+<div class="mkw-calendar" :data-special="special" :data-mobile="platform == 'mobile'">
<mk-widget-container :naked="props.design == 1" :show-header="false">
<div class="mkw-calendar--body">
<div class="calendar" :data-is-holiday="isHoliday">
@@ -67,7 +67,7 @@ export default define({
},
methods: {
func() {
- if (this.isMobile) return;
+ if (this.platform == 'mobile') return;
if (this.props.design == 2) {
this.props.design = 0;
} else {
diff --git a/src/client/app/common/views/widgets/donation.vue b/src/client/app/common/views/widgets/donation.vue
index 75f5db808a..470576d5e6 100644
--- a/src/client/app/common/views/widgets/donation.vue
+++ b/src/client/app/common/views/widgets/donation.vue
@@ -1,5 +1,5 @@
<template>
-<div class="mkw-donation" :data-mobile="isMobile">
+<div class="mkw-donation" :data-mobile="platform == 'mobile'">
<article>
<h1>%fa:heart%%i18n:@title%</h1>
<p>
diff --git a/src/client/app/common/views/widgets/rss.vue b/src/client/app/common/views/widgets/rss.vue
index 7ac453e450..a777388cdb 100644
--- a/src/client/app/common/views/widgets/rss.vue
+++ b/src/client/app/common/views/widgets/rss.vue
@@ -4,7 +4,7 @@
<template slot="header">%fa:rss-square%RSS</template>
<button slot="func" title="設定" @click="setting">%fa:cog%</button>
- <div class="mkw-rss--body" :data-mobile="isMobile">
+ <div class="mkw-rss--body" :data-mobile="platform == 'mobile'">
<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
<div class="feed" v-else>
<a v-for="item in items" :href="item.link" target="_blank">{{ item.title }}</a>
diff --git a/src/client/app/common/views/widgets/slideshow.vue b/src/client/app/common/views/widgets/slideshow.vue
index 459b24a32f..e1c28f5115 100644
--- a/src/client/app/common/views/widgets/slideshow.vue
+++ b/src/client/app/common/views/widgets/slideshow.vue
@@ -1,5 +1,5 @@
<template>
-<div class="mkw-slideshow" :data-mobile="isMobile">
+<div class="mkw-slideshow" :data-mobile="platform == 'mobile'">
<div @click="choose">
<p v-if="props.folder === undefined">
<template v-if="isCustomizeMode">フォルダを指定するには、カスタマイズモードを終了してください</template>
diff --git a/src/client/app/desktop/views/components/home.vue b/src/client/app/desktop/views/components/home.vue
index c30ca68210..826753c169 100644
--- a/src/client/app/desktop/views/components/home.vue
+++ b/src/client/app/desktop/views/components/home.vue
@@ -47,7 +47,7 @@
: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" :is-customize-mode="true"/>
+ <component :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id" :is-customize-mode="true" platform="desktop"/>
</div>
</x-draggable>
<div class="main">
@@ -60,7 +60,7 @@
</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" :ref="widget.id" :widget="widget" @chosen="warp"/>
+ <component v-for="widget in widgets[place]" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" @chosen="warp" platform="desktop"/>
</div>
<div class="main">
<mk-post-form class="form" v-if="$store.state.settings.showPostFormOnTopOfTl"/>
diff --git a/src/client/app/desktop/views/components/widget-container.vue b/src/client/app/desktop/views/components/widget-container.vue
index 488e9cb249..7cfcd68eba 100644
--- a/src/client/app/desktop/views/components/widget-container.vue
+++ b/src/client/app/desktop/views/components/widget-container.vue
@@ -36,7 +36,7 @@ export default Vue.extend({
<style lang="stylus" scoped>
root(isDark)
background isDark ? #282C37 : #fff
- border solid 1px rgba(#000, 0.075)
+ border solid 1px rgba(#000, isDark ? 0.2 : 0.075)
border-radius 6px
overflow hidden
diff --git a/src/client/app/desktop/views/pages/deck/deck.column.vue b/src/client/app/desktop/views/pages/deck/deck.column.vue
index 3dc2da1c77..e9f013734a 100644
--- a/src/client/app/desktop/views/pages/deck/deck.column.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.column.vue
@@ -1,8 +1,8 @@
<template>
-<div class="dnpfarvgbnfmyzbdquhhzyxcmstpdqzs">
+<div class="dnpfarvgbnfmyzbdquhhzyxcmstpdqzs" :class="{ naked, narrow }">
<header :class="{ indicate }">
<slot name="header"></slot>
- <button ref="menu" @click="menu">%fa:caret-down%</button>
+ <button ref="menu" @click="showMenu">%fa:caret-down%</button>
</header>
<div ref="body">
<slot></slot>
@@ -19,6 +19,20 @@ export default Vue.extend({
id: {
type: String,
required: false
+ },
+ menu: {
+ type: Array,
+ required: false
+ },
+ naked: {
+ type: Boolean,
+ required: false,
+ default: false
+ },
+ narrow: {
+ type: Boolean,
+ required: false,
+ default: false
}
},
@@ -59,26 +73,33 @@ export default Vue.extend({
}
},
- menu() {
+ showMenu() {
+ const items = [{
+ content: '%fa:arrow-left% %i18n:@swap-left%',
+ onClick: () => {
+ this.$store.dispatch('settings/swapLeftDeckColumn', this.id);
+ }
+ }, {
+ content: '%fa:arrow-right% %i18n:@swap-right%',
+ onClick: () => {
+ this.$store.dispatch('settings/swapRightDeckColumn', this.id);
+ }
+ }, {
+ content: '%fa:trash-alt R% %i18n:@remove%',
+ onClick: () => {
+ this.$store.dispatch('settings/removeDeckColumn', this.id);
+ }
+ }];
+
+ if (this.menu) {
+ items.unshift(null);
+ this.menu.reverse().forEach(i => items.unshift(i));
+ }
+
this.os.new(Menu, {
source: this.$refs.menu,
compact: false,
- items: [{
- content: '%fa:arrow-left% %i18n:@swap-left%',
- onClick: () => {
- this.$store.dispatch('settings/swapLeftDeckColumn', this.id);
- }
- }, {
- content: '%fa:arrow-right% %i18n:@swap-right%',
- onClick: () => {
- this.$store.dispatch('settings/swapRightDeckColumn', this.id);
- }
- }, {
- content: '%fa:trash-alt R% %i18n:@remove%',
- onClick: () => {
- this.$store.dispatch('settings/removeDeckColumn', this.id);
- }
- }]
+ items
});
}
}
@@ -100,6 +121,21 @@ root(isDark)
box-shadow 0 2px 16px rgba(#000, 0.1)
overflow hidden
+ &.narrow
+ min-width 285px
+ max-width 285px
+
+ &.naked
+ background rgba(#000, isDark ? 0.25 : 0.1)
+
+ > header
+ background transparent
+ box-shadow none
+
+ if !isDark
+ > button
+ color #bbb
+
> header
z-index 1
line-height $header-height
diff --git a/src/client/app/desktop/views/pages/deck/deck.notifications-column.vue b/src/client/app/desktop/views/pages/deck/deck.notifications-column.vue
index bfc2af1935..b92614314c 100644
--- a/src/client/app/desktop/views/pages/deck/deck.notifications-column.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.notifications-column.vue
@@ -1,7 +1,7 @@
<template>
<div>
<x-column :id="id">
- <span slot="header">%fa:bell R% %i18n:@notifications%</span>
+ <span slot="header">%fa:bell R%%i18n:@notifications%</span>
<x-notifications/>
</x-column>
diff --git a/src/client/app/desktop/views/pages/deck/deck.vue b/src/client/app/desktop/views/pages/deck/deck.vue
index ebec4f096c..4935d9a5bd 100644
--- a/src/client/app/desktop/views/pages/deck/deck.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.vue
@@ -2,6 +2,7 @@
<mk-ui :class="$style.root">
<div class="qlvquzbjribqcaozciifydkngcwtyzje" :data-darkmode="$store.state.device.darkmode">
<template v-for="column in columns">
+ <x-widgets-column v-if="column.type == 'widgets'" :key="column.id" :column="column"/>
<x-notifications-column v-if="column.type == 'notifications'" :key="column.id" :id="column.id"/>
<x-tl-column v-if="column.type == 'home'" :key="column.id" :column="column"/>
<x-tl-column v-if="column.type == 'local'" :key="column.id" :column="column"/>
@@ -17,6 +18,7 @@
import Vue from 'vue';
import XTlColumn from './deck.tl-column.vue';
import XNotificationsColumn from './deck.notifications-column.vue';
+import XWidgetsColumn from './deck.widgets-column.vue';
import Menu from '../../../../common/views/components/menu.vue';
import MkUserListsWindow from '../../components/user-lists-window.vue';
import * as uuid from 'uuid';
@@ -24,7 +26,8 @@ import * as uuid from 'uuid';
export default Vue.extend({
components: {
XTlColumn,
- XNotificationsColumn
+ XNotificationsColumn,
+ XWidgetsColumn
},
computed: {
columns() {
@@ -110,6 +113,15 @@ export default Vue.extend({
type: 'notifications'
});
}
+ }, {
+ content: '%i18n:@widgets%',
+ onClick: () => {
+ this.$store.dispatch('settings/addDeckColumn', {
+ id: uuid(),
+ type: 'widgets',
+ widgets: []
+ });
+ }
}]
});
}
diff --git a/src/client/app/desktop/views/pages/deck/deck.widgets-column.vue b/src/client/app/desktop/views/pages/deck/deck.widgets-column.vue
new file mode 100644
index 0000000000..0b2cc305f4
--- /dev/null
+++ b/src/client/app/desktop/views/pages/deck/deck.widgets-column.vue
@@ -0,0 +1,152 @@
+<template>
+<div class="wtdtxvecapixsepjtcupubtsmometobz">
+ <x-column :id="column.id" :menu="menu" :naked="true" :narrow="true">
+ <span slot="header">%fa:calculator%%i18n:@widgets%</span>
+
+ <div class="gqpwvtwtprsbmnssnbicggtwqhmylhnq">
+ <template v-if="edit">
+ <header>
+ <select v-model="widgetAdderSelected">
+ <option value="profile">%i18n:common.widgets.profile%</option>
+ <option value="analog-clock">%i18n:common.widgets.analog-clock%</option>
+ <option value="calendar">%i18n:common.widgets.calendar%</option>
+ <option value="timemachine">%i18n:common.widgets.timemachine%</option>
+ <option value="activity">%i18n:common.widgets.activity%</option>
+ <option value="rss">%i18n:common.widgets.rss%</option>
+ <option value="trends">%i18n:common.widgets.trends%</option>
+ <option value="photo-stream">%i18n:common.widgets.photo-stream%</option>
+ <option value="slideshow">%i18n:common.widgets.slideshow%</option>
+ <option value="version">%i18n:common.widgets.version%</option>
+ <option value="broadcast">%i18n:common.widgets.broadcast%</option>
+ <option value="notifications">%i18n:common.widgets.notifications%</option>
+ <option value="users">%i18n:common.widgets.users%</option>
+ <option value="polls">%i18n:common.widgets.polls%</option>
+ <option value="post-form">%i18n:common.widgets.post-form%</option>
+ <option value="messaging">%i18n:common.widgets.messaging%</option>
+ <option value="memo">%i18n:common.widgets.memo%</option>
+ <option value="server">%i18n:common.widgets.server%</option>
+ <option value="donation">%i18n:common.widgets.donation%</option>
+ <option value="nav">%i18n:common.widgets.nav%</option>
+ <option value="tips">%i18n:common.widgets.tips%</option>
+ </select>
+ <button @click="addWidget">追加</button>
+ </header>
+ <x-draggable
+ :list="column.widgets"
+ :options="{ handle: '.handle', animation: 150 }"
+ @sort="onWidgetSort"
+ >
+ <div v-for="widget in column.widgets" class="customize-container" :key="widget.id">
+ <header>
+ <span class="handle">%fa:bars%</span>{{ widget.name }}<button class="remove" @click="removeWidget(widget)">%fa:times%</button>
+ </header>
+ <div @click="widgetFunc(widget.id)">
+ <component :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id" :is-customize-mode="true" platform="deck"/>
+ </div>
+ </div>
+ </x-draggable>
+ </template>
+ <template v-else>
+ <component class="widget" v-for="widget in column.widgets" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" platform="deck"/>
+ </template>
+ </div>
+ </x-column>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import XColumn from './deck.column.vue';
+import * as XDraggable from 'vuedraggable';
+import * as uuid from 'uuid';
+
+export default Vue.extend({
+ components: {
+ XColumn,
+ XDraggable
+ },
+
+ props: {
+ column: {
+ type: Object,
+ required: true
+ }
+ },
+
+ data() {
+ return {
+ edit: false,
+ menu: null,
+ widgetAdderSelected: null
+ }
+ },
+
+ created() {
+ this.menu = [{
+ content: '%fa:cog% %i18n:@edit%',
+ onClick: () => {
+ this.edit = !this.edit;
+ }
+ }];
+ },
+
+ methods: {
+ widgetFunc(id) {
+ const w = this.$refs[id][0];
+ if (w.func) w.func();
+ },
+
+ onWidgetSort() {
+ this.saveWidgets();
+ },
+
+ addWidget() {
+ this.$store.dispatch('settings/addDeckWidget', {
+ id: this.column.id,
+ widget: {
+ name: this.widgetAdderSelected,
+ id: uuid(),
+ data: {}
+ }
+ });
+ },
+
+ removeWidget(widget) {
+ this.$store.dispatch('settings/removeDeckWidget', {
+ id: this.column.id,
+ widget
+ });
+ },
+
+ saveWidgets() {
+ this.$store.dispatch('settings/saveDeck');
+ }
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+@import '~const.styl'
+
+root(isDark)
+ .gqpwvtwtprsbmnssnbicggtwqhmylhnq
+ .widget, .customize-container
+ margin 8px
+
+ &:first-of-type
+ margin-top 0
+
+ .customize-container
+ background #fff
+
+ > header
+ color isDark ? #fff : #000
+
+.wtdtxvecapixsepjtcupubtsmometobz[data-darkmode]
+ root(true)
+
+.wtdtxvecapixsepjtcupubtsmometobz:not([data-darkmode])
+ root(false)
+
+</style>
+
diff --git a/src/client/app/mobile/views/pages/widgets.vue b/src/client/app/mobile/views/pages/widgets.vue
index a0893770e8..eab0ca6a38 100644
--- a/src/client/app/mobile/views/pages/widgets.vue
+++ b/src/client/app/mobile/views/pages/widgets.vue
@@ -35,13 +35,13 @@
<span class="handle">%fa:bars%</span>{{ widget.name }}<button class="remove" @click="removeWidget(widget)">%fa:times%</button>
</header>
<div @click="widgetFunc(widget.id)">
- <component :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id" :is-customize-mode="true" :is-mobile="true"/>
+ <component :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id" :is-customize-mode="true" platform="mobile"/>
</div>
</div>
</x-draggable>
</template>
<template v-else>
- <component class="widget" v-for="widget in widgets" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" :is-mobile="true"/>
+ <component class="widget" v-for="widget in widgets" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" platform="mobile"/>
</template>
</main>
</mk-ui>
diff --git a/src/client/app/store.ts b/src/client/app/store.ts
index 17faeb97e5..5582ff6c57 100644
--- a/src/client/app/store.ts
+++ b/src/client/app/store.ts
@@ -124,13 +124,6 @@ export default (os: MiOS) => new Vuex.Store({
state.home = data;
},
- setHomeWidget(state, x) {
- const w = state.home.find(w => w.id == x.id);
- if (w) {
- w.data = x.data;
- }
- },
-
addHomeWidget(state, widget) {
state.home.unshift(widget);
},
@@ -139,11 +132,36 @@ export default (os: MiOS) => new Vuex.Store({
state.mobileHome = data;
},
- setMobileHomeWidget(state, x) {
- const w = state.mobileHome.find(w => w.id == x.id);
- if (w) {
- w.data = x.data;
+ setWidget(state, x) {
+ let w;
+
+ //#region Decktop home
+ if (state.home) {
+ w = state.home.find(w => w.id == x.id);
+ if (w) {
+ w.data = x.data;
+ }
+ }
+ //#endregion
+
+ //#region Mobile home
+ if (state.mobileHome) {
+ w = state.mobileHome.find(w => w.id == x.id);
+ if (w) {
+ w.data = x.data;
+ }
+ }
+ //#endregion
+
+ //#region Deck
+ if (state.deck && state.deck.columns) {
+ state.deck.columns.filter(c => c.type == 'widgets').forEach(c => {
+ c.widgets.forEach(w => {
+ if (w.id == x.id) w.data = x.data;
+ });
+ });
}
+ //#endregion
},
addMobileHomeWidget(state, widget) {
@@ -190,6 +208,20 @@ export default (os: MiOS) => new Vuex.Store({
return true;
}
});
+ },
+
+ addDeckWidget(state, x) {
+ if (state.deck.columns == null) return;
+ const column = state.deck.columns.find(c => c.id == x.id);
+ if (column == null) return;
+ column.widgets.unshift(x.widget);
+ },
+
+ removeDeckWidget(state, x) {
+ if (state.deck.columns == null) return;
+ const column = state.deck.columns.find(c => c.id == x.id);
+ if (column == null) return;
+ column.widgets = column.widgets.filter(w => w.id != x.widget.id);
}
},
@@ -212,40 +244,41 @@ export default (os: MiOS) => new Vuex.Store({
}
},
- addDeckColumn(ctx, column) {
- ctx.commit('addDeckColumn', column);
-
+ saveDeck(ctx) {
os.api('i/update_client_setting', {
name: 'deck',
value: ctx.state.deck
});
},
+ addDeckColumn(ctx, column) {
+ ctx.commit('addDeckColumn', column);
+ ctx.dispatch('saveDeck');
+ },
+
removeDeckColumn(ctx, id) {
ctx.commit('removeDeckColumn', id);
-
- os.api('i/update_client_setting', {
- name: 'deck',
- value: ctx.state.deck
- });
+ ctx.dispatch('saveDeck');
},
swapLeftDeckColumn(ctx, id) {
ctx.commit('swapLeftDeckColumn', id);
-
- os.api('i/update_client_setting', {
- name: 'deck',
- value: ctx.state.deck
- });
+ ctx.dispatch('saveDeck');
},
swapRightDeckColumn(ctx, id) {
ctx.commit('swapRightDeckColumn', id);
+ ctx.dispatch('saveDeck');
+ },
- os.api('i/update_client_setting', {
- name: 'deck',
- value: ctx.state.deck
- });
+ addDeckWidget(ctx, x) {
+ ctx.commit('addDeckWidget', x);
+ ctx.dispatch('saveDeck');
+ },
+
+ removeDeckWidget(ctx, x) {
+ ctx.commit('removeDeckWidget', x);
+ ctx.dispatch('saveDeck');
},
addHomeWidget(ctx, widget) {
diff --git a/src/server/api/endpoints.ts b/src/server/api/endpoints.ts
index e9392d236b..94e649d29b 100644
--- a/src/server/api/endpoints.ts
+++ b/src/server/api/endpoints.ts
@@ -190,6 +190,11 @@ const endpoints: Endpoint[] = [
secure: true
},
{
+ name: 'i/update_widget',
+ withCredential: true,
+ secure: true
+ },
+ {
name: 'i/change_password',
withCredential: true,
secure: true
diff --git a/src/server/api/endpoints/i/update_home.ts b/src/server/api/endpoints/i/update_home.ts
index 8ce551957e..48f6dbbb7a 100644
--- a/src/server/api/endpoints/i/update_home.ts
+++ b/src/server/api/endpoints/i/update_home.ts
@@ -1,6 +1,3 @@
-/**
- * Module dependencies
- */
import $ from 'cafy';
import User from '../../../../models/user';
import event from '../../../../publishers/stream';
@@ -13,50 +10,16 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
.have('id', $.str)
.have('place', $.str)
.have('data', $.obj))
- .optional()
.get(params.home);
if (homeErr) return rej('invalid home param');
- // Get 'id' parameter
- const [id, idErr] = $.str.optional().get(params.id);
- if (idErr) return rej('invalid id param');
+ await User.update(user._id, {
+ $set: {
+ 'clientSettings.home': home
+ }
+ });
- // Get 'data' parameter
- const [data, dataErr] = $.obj.optional().get(params.data);
- if (dataErr) return rej('invalid data param');
+ res();
- if (home) {
- await User.update(user._id, {
- $set: {
- 'clientSettings.home': home
- }
- });
-
- res();
-
- event(user._id, 'home_updated', {
- home
- });
- } else {
- if (id == null && data == null) return rej('you need to set id and data params if home param unset');
-
- const _home = user.clientSettings.home;
- const widget = _home.find(w => w.id == id);
-
- if (widget == null) return rej('widget not found');
-
- widget.data = data;
-
- await User.update(user._id, {
- $set: {
- 'clientSettings.home': _home
- }
- });
-
- res();
-
- event(user._id, 'home_updated', {
- id, data
- });
- }
+ event(user._id, 'home_updated', home);
});
diff --git a/src/server/api/endpoints/i/update_mobile_home.ts b/src/server/api/endpoints/i/update_mobile_home.ts
index d79a77072b..d285a0a72d 100644
--- a/src/server/api/endpoints/i/update_mobile_home.ts
+++ b/src/server/api/endpoints/i/update_mobile_home.ts
@@ -1,6 +1,3 @@
-/**
- * Module dependencies
- */
import $ from 'cafy';
import User from '../../../../models/user';
import event from '../../../../publishers/stream';
@@ -12,49 +9,16 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
.have('name', $.str)
.have('id', $.str)
.have('data', $.obj))
- .optional().get(params.home);
+ .get(params.home);
if (homeErr) return rej('invalid home param');
- // Get 'id' parameter
- const [id, idErr] = $.str.optional().get(params.id);
- if (idErr) return rej('invalid id param');
+ await User.update(user._id, {
+ $set: {
+ 'clientSettings.mobileHome': home
+ }
+ });
- // Get 'data' parameter
- const [data, dataErr] = $.obj.optional().get(params.data);
- if (dataErr) return rej('invalid data param');
+ res();
- if (home) {
- await User.update(user._id, {
- $set: {
- 'clientSettings.mobileHome': home
- }
- });
-
- res();
-
- event(user._id, 'mobile_home_updated', {
- home
- });
- } else {
- if (id == null && data == null) return rej('you need to set id and data params if home param unset');
-
- const _home = user.clientSettings.mobileHome || [];
- const widget = _home.find(w => w.id == id);
-
- if (widget == null) return rej('widget not found');
-
- widget.data = data;
-
- await User.update(user._id, {
- $set: {
- 'clientSettings.mobileHome': _home
- }
- });
-
- res();
-
- event(user._id, 'mobile_home_updated', {
- id, data
- });
- }
+ event(user._id, 'mobile_home_updated', home);
});
diff --git a/src/server/api/endpoints/i/update_widget.ts b/src/server/api/endpoints/i/update_widget.ts
new file mode 100644
index 0000000000..b37761bde1
--- /dev/null
+++ b/src/server/api/endpoints/i/update_widget.ts
@@ -0,0 +1,79 @@
+import $ from 'cafy';
+import User from '../../../../models/user';
+import event from '../../../../publishers/stream';
+
+module.exports = async (params, user) => new Promise(async (res, rej) => {
+ // Get 'id' parameter
+ const [id, idErr] = $.str.get(params.id);
+ if (idErr) return rej('invalid id param');
+
+ // Get 'data' parameter
+ const [data, dataErr] = $.obj.get(params.data);
+ if (dataErr) return rej('invalid data param');
+
+ if (id == null && data == null) return rej('you need to set id and data params if home param unset');
+
+ let widget;
+
+ //#region Desktop home
+ if (widget == null && user.clientSettings.home) {
+ const desktopHome = user.clientSettings.home;
+ widget = desktopHome.find(w => w.id == id);
+ if (widget) {
+ widget.data = data;
+
+ await User.update(user._id, {
+ $set: {
+ 'clientSettings.home': desktopHome
+ }
+ });
+ }
+ }
+ //#endregion
+
+ //#region Mobile home
+ if (widget == null && user.clientSettings.mobileHome) {
+ const mobileHome = user.clientSettings.mobileHome;
+ widget = mobileHome.find(w => w.id == id);
+ if (widget) {
+ widget.data = data;
+
+ await User.update(user._id, {
+ $set: {
+ 'clientSettings.mobileHome': mobileHome
+ }
+ });
+ }
+ }
+ //#endregion
+
+ //#region Deck
+ if (widget == null && user.clientSettings.deck && user.clientSettings.deck.columns) {
+ const deck = user.clientSettings.deck;
+ deck.columns.filter(c => c.type == 'widgets').forEach(c => {
+ c.widgets.forEach(w => {
+ if (w.id == id) widget = w;
+ });
+ });
+ if (widget) {
+ widget.data = data;
+
+ await User.update(user._id, {
+ $set: {
+ 'clientSettings.deck': deck
+ }
+ });
+ }
+ }
+ //#endregion
+
+ if (widget) {
+ event(user._id, 'widgetUpdated', {
+ id, data
+ });
+
+ res();
+ } else {
+ rej('widget not found');
+ }
+});