From 5511b6e0136ee3f585527d0371268556265811b7 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 21 May 2019 03:07:11 +0900 Subject: Refactoring --- src/client/app/common/scripts/note-subscriber.ts | 2 - src/client/app/common/scripts/paging.ts | 169 +++++++++++++++++++++++ 2 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 src/client/app/common/scripts/paging.ts (limited to 'src/client/app/common/scripts') diff --git a/src/client/app/common/scripts/note-subscriber.ts b/src/client/app/common/scripts/note-subscriber.ts index d881fe01ce..5b31a9f9d0 100644 --- a/src/client/app/common/scripts/note-subscriber.ts +++ b/src/client/app/common/scripts/note-subscriber.ts @@ -144,8 +144,6 @@ export default prop => ({ break; } } - - this.$emit(`update:${prop}`, this.$_ns_note_); }, } }); diff --git a/src/client/app/common/scripts/paging.ts b/src/client/app/common/scripts/paging.ts new file mode 100644 index 0000000000..458ee7e5ca --- /dev/null +++ b/src/client/app/common/scripts/paging.ts @@ -0,0 +1,169 @@ +import Vue from 'vue'; + +export default (opts) => ({ + data() { + return { + items: [], + queue: [], + fetching: true, + moreFetching: false, + inited: false, + more: false + }; + }, + + computed: { + empty(): boolean { + return this.items.length == 0 && !this.fetching && this.inited; + }, + + error(): boolean { + return !this.fetching && !this.inited; + } + }, + + watch: { + queue(x) { + if (opts.onQueueChanged) opts.onQueueChanged(this, x); + }, + + pagination() { + this.init(); + } + }, + + created() { + opts.displayLimit = opts.displayLimit || 30; + this.init(); + }, + + mounted() { + if (opts.captureWindowScroll) { + this.isScrollTop = () => { + return window.scrollY <= 8; + }; + + window.addEventListener('scroll', this.onWindowScroll, { passive: true }); + } + }, + + beforeDestroy() { + if (opts.captureWindowScroll) { + window.removeEventListener('scroll', this.onWindowScroll); + } + }, + + methods: { + updateItem(i, item) { + Vue.set((this as any).items, i, item); + }, + + reload() { + this.queue = []; + this.items = []; + this.init(); + }, + + async init() { + this.fetching = true; + let params = typeof this.pagination.params === 'function' ? this.pagination.params(true) : this.pagination.params; + if (params && params.then) params = await params; + await this.$root.api(this.pagination.endpoint, { + limit: (this.pagination.limit || 10) + 1, + ...params + }).then(x => { + if (x.length == (this.pagination.limit || 10) + 1) { + x.pop(); + this.items = x; + this.more = true; + } else { + this.items = x; + this.more = false; + } + this.inited = true; + this.fetching = false; + }, e => { + this.fetching = false; + }); + }, + + async fetchMore() { + if (!this.more || this.moreFetching || this.items.length === 0) return; + this.moreFetching = true; + let params = typeof this.pagination.params === 'function' ? this.pagination.params(false) : this.pagination.params; + if (params && params.then) params = await params; + await this.$root.api(this.pagination.endpoint, { + limit: (this.pagination.limit || 10) + 1, + untilId: this.items[this.items.length - 1].id, + ...params + }).then(x => { + if (x.length == (this.pagination.limit || 10) + 1) { + x.pop(); + this.items = this.items.concat(x); + this.more = true; + } else { + this.items = this.items.concat(x); + this.more = false; + } + this.moreFetching = false; + }, e => { + this.moreFetching = false; + }); + }, + + prepend(item, silent = false) { + if (opts.onPrepend) { + const cancel = opts.onPrepend(this, item, silent); + if (cancel) return; + } + + if (this.isScrollTop()) { + // Prepend the item + this.items.unshift(item); + + // オーバーフローしたら古い投稿は捨てる + if (this.items.length >= opts.displayLimit) { + this.items = this.items.slice(0, opts.displayLimit); + this.more = true; + } + } else { + this.queue.push(item); + } + }, + + append(item) { + this.items.push(item); + }, + + releaseQueue() { + for (const n of this.queue) { + this.prepend(n, true); + } + this.queue = []; + }, + + onWindowScroll() { + if (this.isScrollTop()) { + this.onTop(); + } + + if (this.$store.state.settings.fetchOnScroll) { + // 親要素が display none だったら弾く + // https://github.com/syuilo/misskey/issues/1569 + // http://d.hatena.ne.jp/favril/20091105/1257403319 + if (this.$el.offsetHeight == 0) return; + + const current = window.scrollY + window.innerHeight; + if (current > document.body.offsetHeight - 8) this.onBottom(); + } + }, + + onTop() { + this.releaseQueue(); + }, + + onBottom() { + this.fetchMore(); + } + } +}); -- cgit v1.2.3-freya From b335975c972685fc5e47f22eef623f58a81ef315 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 21 May 2019 03:20:16 +0900 Subject: Refactoring --- src/client/app/common/scripts/paging.ts | 2 +- .../app/desktop/views/components/notifications.vue | 66 +++++++--------------- 2 files changed, 20 insertions(+), 48 deletions(-) (limited to 'src/client/app/common/scripts') diff --git a/src/client/app/common/scripts/paging.ts b/src/client/app/common/scripts/paging.ts index 458ee7e5ca..4875ce620f 100644 --- a/src/client/app/common/scripts/paging.ts +++ b/src/client/app/common/scripts/paging.ts @@ -117,7 +117,7 @@ export default (opts) => ({ if (cancel) return; } - if (this.isScrollTop()) { + if (this.isScrollTop == null || this.isScrollTop()) { // Prepend the item this.items.unshift(item); diff --git a/src/client/app/desktop/views/components/notifications.vue b/src/client/app/desktop/views/components/notifications.vue index 0bf0132926..9ca06f4118 100644 --- a/src/client/app/desktop/views/components/notifications.vue +++ b/src/client/app/desktop/views/components/notifications.vue @@ -6,7 +6,7 @@ -
+
-

+

{{ notification._datetext }} {{ _notifications[i + 1]._datetext }}

- -

{{ $t('empty') }}

+

{{ $t('empty') }}

+ @@ -143,23 +144,29 @@ import Vue from 'vue'; import i18n from '../../../i18n'; import getNoteSummary from '../../../../../misc/get-note-summary'; +import paging from '../../../common/scripts/paging'; export default Vue.extend({ i18n: i18n(), + + mixins: [ + paging({}), + ], + data() { return { - fetching: true, - fetchingMoreNotifications: false, - notifications: [], - moreNotifications: false, connection: null, - getNoteSummary + getNoteSummary, + pagination: { + endpoint: 'i/notifications', + limit: 10, + } }; }, computed: { _notifications(): any[] { - return (this.notifications as any).map(notification => { + return (this.items as any).map(notification => { const date = new Date(notification.createdAt).getDate(); const month = new Date(notification.createdAt).getMonth() + 1; notification._date = date; @@ -171,22 +178,7 @@ export default Vue.extend({ mounted() { this.connection = this.$root.stream.useSharedConnection('main'); - this.connection.on('notification', this.onNotification); - - const max = 10; - - this.$root.api('i/notifications', { - limit: max + 1 - }).then(notifications => { - if (notifications.length == max + 1) { - this.moreNotifications = true; - notifications.pop(); - } - - this.notifications = notifications; - this.fetching = false; - }); }, beforeDestroy() { @@ -194,33 +186,13 @@ export default Vue.extend({ }, methods: { - fetchMoreNotifications() { - this.fetchingMoreNotifications = true; - - const max = 30; - - this.$root.api('i/notifications', { - limit: max + 1, - untilId: this.notifications[this.notifications.length - 1].id - }).then(notifications => { - if (notifications.length == max + 1) { - this.moreNotifications = true; - notifications.pop(); - } else { - this.moreNotifications = false; - } - this.notifications = this.notifications.concat(notifications); - this.fetchingMoreNotifications = false; - }); - }, - onNotification(notification) { // TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない this.$root.stream.send('readNotification', { id: notification.id }); - this.notifications.unshift(notification); + this.prepend(notification); } } }); -- cgit v1.2.3-freya From 0d3117e4722e1ced87ad4bdc81a794c03609c3dd Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 21 May 2019 03:40:18 +0900 Subject: Fix --- src/client/app/common/scripts/paging.ts | 2 ++ src/client/app/mobile/views/components/notes.vue | 4 ++++ src/client/app/mobile/views/components/ui.header.vue | 1 - src/client/app/mobile/views/pages/home.timeline.vue | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src/client/app/common/scripts') diff --git a/src/client/app/common/scripts/paging.ts b/src/client/app/common/scripts/paging.ts index 4875ce620f..c13a607e6f 100644 --- a/src/client/app/common/scripts/paging.ts +++ b/src/client/app/common/scripts/paging.ts @@ -82,8 +82,10 @@ export default (opts) => ({ } this.inited = true; this.fetching = false; + if (opts.onInited) opts.onInited(this); }, e => { this.fetching = false; + if (opts.onInited) opts.onInited(this); }); }, diff --git a/src/client/app/mobile/views/components/notes.vue b/src/client/app/mobile/views/components/notes.vue index 2112259564..1a0cd5cc24 100644 --- a/src/client/app/mobile/views/components/notes.vue +++ b/src/client/app/mobile/views/components/notes.vue @@ -59,6 +59,10 @@ export default Vue.extend({ if (document.hidden || !self.isScrollTop()) { self.$store.commit('pushBehindNote', note); } + }, + + onInited: (self) => { + self.$emit('loaded'); } }), ], diff --git a/src/client/app/mobile/views/components/ui.header.vue b/src/client/app/mobile/views/components/ui.header.vue index b636041d63..f20f64e7ff 100644 --- a/src/client/app/mobile/views/components/ui.header.vue +++ b/src/client/app/mobile/views/components/ui.header.vue @@ -1,6 +1,5 @@ -- cgit v1.2.3-freya