From b0f989dbacbdbdd091b0d220496d22f47c795576 Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Wed, 6 Jun 2018 19:22:45 +0900 Subject: [PATCH] =?UTF-8?q?Deck=E3=81=AB=E3=82=A6=E3=82=A3=E3=82=B8?= =?UTF-8?q?=E3=82=A7=E3=83=83=E3=83=88=E3=82=92=E7=BD=AE=E3=81=91=E3=82=8B?= =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/client/app/common/define-widget.ts | 21 +-- .../app/common/scripts/streaming/home.ts | 25 ++- .../app/common/views/components/menu.vue | 10 +- .../app/common/views/widgets/broadcast.vue | 2 +- .../app/common/views/widgets/calendar.vue | 4 +- .../app/common/views/widgets/donation.vue | 2 +- src/client/app/common/views/widgets/rss.vue | 2 +- .../app/common/views/widgets/slideshow.vue | 2 +- .../app/desktop/views/components/home.vue | 4 +- .../views/components/widget-container.vue | 2 +- .../desktop/views/pages/deck/deck.column.vue | 74 ++++++--- .../pages/deck/deck.notifications-column.vue | 2 +- .../app/desktop/views/pages/deck/deck.vue | 14 +- .../views/pages/deck/deck.widgets-column.vue | 152 ++++++++++++++++++ src/client/app/mobile/views/pages/widgets.vue | 4 +- src/client/app/store.ts | 89 ++++++---- src/server/api/endpoints.ts | 5 + src/server/api/endpoints/i/update_home.ts | 51 +----- .../api/endpoints/i/update_mobile_home.ts | 52 +----- src/server/api/endpoints/i/update_widget.ts | 79 +++++++++ 20 files changed, 417 insertions(+), 179 deletions(-) create mode 100644 src/client/app/desktop/views/pages/deck/deck.widgets-column.vue create mode 100644 src/server/api/endpoints/i/update_widget.ts 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 @@ -189,6 +189,11 @@ const endpoints: Endpoint[] = [ withCredential: true, secure: true }, + { + name: 'i/update_widget', + withCredential: true, + secure: true + }, { name: 'i/change_password', withCredential: 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'); + } +});