Refactoring

This commit is contained in:
syuilo
2019-05-21 03:07:11 +09:00
parent 262d5ead51
commit 5511b6e013
41 changed files with 764 additions and 1408 deletions

View File

@@ -4,9 +4,9 @@
<div class="newer-indicator" :style="{ top: $store.state.uiHeaderHeight + 'px' }" v-show="queue.length > 0"></div>
<div class="empty" v-if="notes.length == 0 && !fetching && inited">{{ $t('@.no-notes') }}</div>
<div class="empty" v-if="empty">{{ $t('@.no-notes') }}</div>
<mk-error v-if="!fetching && !inited" @retry="init()"/>
<mk-error v-if="error" @retry="init()"/>
<div class="placeholder" v-if="fetching">
<template v-for="i in 10">
@@ -17,8 +17,8 @@
<!-- トランジションを有効にするとなぜかメモリリークする -->
<component :is="!$store.state.device.reduceMotion ? 'transition-group' : 'div'" name="mk-notes" class="notes transition" tag="div" ref="notes">
<template v-for="(note, i) in _notes">
<mk-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)" :compact="true" ref="note"/>
<p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date">
<mk-note :note="note" :key="note.id" :compact="true" ref="note"/>
<p class="date" :key="note.id + '_date'" v-if="i != items.length - 1 && note._date != _notes[i + 1]._date">
<span><fa icon="angle-up"/>{{ note._datetext }}</span>
<span><fa icon="angle-down"/>{{ _notes[i + 1]._datetext }}</span>
</p>
@@ -39,152 +39,66 @@ import Vue from 'vue';
import i18n from '../../../i18n';
import * as config from '../../../config';
import shouldMuteNote from '../../../common/scripts/should-mute-note';
const displayLimit = 30;
import paging from '../../../common/scripts/paging';
export default Vue.extend({
i18n: i18n(),
props: {
makePromise: {
required: true
}
},
mixins: [
paging({
captureWindowScroll: true,
data() {
return {
notes: [],
queue: [],
fetching: true,
moreFetching: false,
inited: false,
more: false
};
onQueueChanged: (self, x) => {
if (x.length > 0) {
self.$store.commit('indicate', true);
} else {
self.$store.commit('indicate', false);
}
},
onPrepend: (self, note, silent) => {
// 弾く
if (shouldMuteNote(self.$store.state.i, self.$store.state.settings, note)) return false;
// タブが非表示またはスクロール位置が最上部ではないならタイトルで通知
if (document.hidden || !self.isScrollTop()) {
self.$store.commit('pushBehindNote', note);
}
if (self.isScrollTop()) {
// サウンドを再生する
if (self.$store.state.device.enableSounds && !silent) {
const sound = new Audio(`${config.url}/assets/post.mp3`);
sound.volume = self.$store.state.device.soundVolume;
sound.play();
}
}
}
}),
],
props: {
pagination: {
required: true
},
},
computed: {
_notes(): any[] {
return (this.notes as any).map(note => {
const date = new Date(note.createdAt).getDate();
const month = new Date(note.createdAt).getMonth() + 1;
note._date = date;
note._datetext = this.$t('@.month-and-day').replace('{month}', month.toString()).replace('{day}', date.toString());
return note;
return (this.items as any).map(item => {
const date = new Date(item.createdAt).getDate();
const month = new Date(item.createdAt).getMonth() + 1;
item._date = date;
item._datetext = this.$t('@.month-and-day').replace('{month}', month.toString()).replace('{day}', date.toString());
return item;
});
}
},
created() {
this.init();
},
mounted() {
window.addEventListener('scroll', this.onScroll, { passive: true });
},
beforeDestroy() {
window.removeEventListener('scroll', this.onScroll);
},
methods: {
isScrollTop() {
return window.scrollY <= 8;
},
focus() {
(this.$refs.notes as any).children[0].focus ? (this.$refs.notes as any).children[0].focus() : (this.$refs.notes as any).$el.children[0].focus();
},
onNoteUpdated(i, note) {
Vue.set((this as any).notes, i, note);
},
reload() {
this.queue = [];
this.notes = [];
this.init();
},
async init() {
this.fetching = true;
await (this.makePromise()).then(x => {
if (Array.isArray(x)) {
this.notes = x;
} else {
this.notes = x.notes;
this.more = x.more;
}
this.inited = true;
this.fetching = false;
this.$emit('inited');
}, e => {
this.fetching = false;
});
},
async fetchMore() {
if (!this.more || this.moreFetching || this.notes.length === 0) return;
this.moreFetching = true;
this.makePromise(this.notes[this.notes.length - 1].id).then(x => {
this.notes = this.notes.concat(x.notes);
this.more = x.more;
this.moreFetching = false;
}, e => {
this.moreFetching = false;
});
},
prepend(note, silent = false) {
// 弾く
if (shouldMuteNote(this.$store.state.i, this.$store.state.settings, note)) return;
// タブが非表示またはスクロール位置が最上部ではないならタイトルで通知
if (document.hidden || !this.isScrollTop()) {
this.$store.commit('pushBehindNote', note);
}
if (this.isScrollTop()) {
// Prepend the note
this.notes.unshift(note);
// サウンドを再生する
if (this.$store.state.device.enableSounds && !silent) {
const sound = new Audio(`${config.url}/assets/post.mp3`);
sound.volume = this.$store.state.device.soundVolume;
sound.play();
}
// オーバーフローしたら古い投稿は捨てる
if (this.notes.length >= displayLimit) {
this.notes = this.notes.slice(0, displayLimit);
this.more = true;
}
} else {
this.queue.push(note);
}
},
append(note) {
this.notes.push(note);
},
releaseQueue() {
for (const n of this.queue) {
this.prepend(n, true);
}
this.queue = [];
},
onScroll() {
if (this.isScrollTop()) {
this.releaseQueue();
}
if (this.$store.state.settings.fetchOnScroll) {
const current = window.scrollY + window.innerHeight;
if (current > document.body.offsetHeight - 8) this.fetchMore();
}
}
}
});
</script>