From 1ea6fc6926750bf089bdcc4481010963fc55f12b Mon Sep 17 00:00:00 2001 From: Book Pauk Date: Sun, 3 Feb 2019 15:21:11 +0700 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BD=D0=B5=D1=81=20?= =?UTF-8?q?=D1=83=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D0=B8=20=D1=85=D1=80=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20rec?= =?UTF-8?q?entBooks=20=D0=B8=D0=B7=20vuex=20=D0=B2=20bookManager?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Reader/HistoryPage/HistoryPage.vue | 27 ++++-- client/components/Reader/Reader.vue | 55 ++++++------ client/components/Reader/share/bookManager.js | 85 ++++++++++++++++++- client/store/modules/reader.js | 46 +--------- 4 files changed, 129 insertions(+), 84 deletions(-) diff --git a/client/components/Reader/HistoryPage/HistoryPage.vue b/client/components/Reader/HistoryPage/HistoryPage.vue index 0fe320b2..11311576 100644 --- a/client/components/Reader/HistoryPage/HistoryPage.vue +++ b/client/components/Reader/HistoryPage/HistoryPage.vue @@ -99,26 +99,34 @@ import _ from 'lodash'; import {formatDate} from '../../../share/utils'; import Window from '../../share/Window.vue'; +import bookManager from '../share/bookManager'; export default @Component({ components: { Window, }, + watch: { + search: function() { + this.updateTableData(); + } + }, }) class HistoryPage extends Vue { search = null; + tableData = null; created() { - this.commit = this.$store.commit; - this.reader = this.$store.state.reader; } - get tableData() { - const state = this.reader; + mounted() { + this.updateTableData(); + } + + updateTableData() { let result = []; - for (let bookKey in state.openedBook) { - const book = state.openedBook[bookKey]; + for (let bookKey in bookManager.recent) { + const book = bookManager.recent[bookKey]; let d = new Date(); d.setTime(book.touchTime); const t = formatDate(d).split(' '); @@ -151,7 +159,7 @@ class HistoryPage extends Vue { } const search = this.search; - return result.filter(item => { + this.tableData = result.filter(item => { return !search || item.touchTime.includes(search) || item.touchDate.includes(search) || @@ -184,8 +192,9 @@ class HistoryPage extends Vue { window.open(path, '_blank'); } - handleDel(key) { - this.commit('reader/delOpenedBook', {key}); + async handleDel(key) { + await bookManager.delRecentBook({key}); + this.updateTableData(); } loadBook(url) { diff --git a/client/components/Reader/Reader.vue b/client/components/Reader/Reader.vue index 40d9c339..39121b94 100644 --- a/client/components/Reader/Reader.vue +++ b/client/components/Reader/Reader.vue @@ -107,7 +107,7 @@ export default @Component({ if (textPage.bookPos != newValue) { textPage.bookPos = newValue; } - this.debouncedCommitOpenedBook(newValue); + this.debouncedSetRecentBook(newValue); } }, routeParamPos: function(newValue) { @@ -116,7 +116,7 @@ export default @Component({ } }, routeParamUrl: function(newValue) { - if (newValue !== '' && newValue !== this.lastOpenedBook.url) { + if (newValue !== '' && newValue !== this.mostRecentBook().url) { this.loadBook({url: newValue, bookPos: this.routeParamPos}); } }, @@ -155,9 +155,10 @@ class Reader extends Vue { this.updateRoute(); }, 1000); - this.debouncedCommitOpenedBook = _.debounce((newValue) => { - if (this.lastOpenedBook && this.lastOpenedBook.bookPos != newValue) { - this.commit('reader/setOpenedBook', Object.assign({}, this.lastOpenedBook, {bookPos: newValue, bookPosSeen: this.bookPosSeen})); + this.debouncedSetRecentBook = _.debounce(async(newValue) => { + const recent = this.mostRecentBook(); + if (recent && recent.bookPos != newValue) { + await bookManager.setRecentBook(Object.assign({}, recent, {bookPos: newValue, bookPosSeen: this.bookPosSeen})); } }, 500); @@ -169,14 +170,11 @@ class Reader extends Vue { } mounted() { - /*while (this.lastOpenedBook) { - this.commit('reader/delOpenedBook', this.lastOpenedBook); - }*/ if (this.$root.rootRoute == '/reader') { if (this.routeParamUrl) { this.loadBook({url: this.routeParamUrl, bookPos: this.routeParamPos}); - } else if (this.lastOpenedBook) { - this.loadBook({url: this.lastOpenedBook.url}); + } else if (this.mostRecentBook()) { + this.loadBook({url: this.this.mostRecentBook().url}); } else { this.loaderActive = true; } @@ -197,10 +195,11 @@ class Reader extends Vue { updateRoute(isNewRoute) { const pos = (this.bookPos != undefined && this.allowUrlParamBookPos ? `__p=${this.bookPos}&` : ''); + const url = (this.mostRecentBook() ? `url=${this.mostRecentBook().url}` : ''); if (isNewRoute) - this.$router.push(`/reader?${pos}url=${this.lastOpenedBook.url}`); + this.$router.push(`/reader?${pos}${url}`); else - this.$router.replace(`/reader?${pos}url=${this.lastOpenedBook.url}`); + this.$router.replace(`/reader?${pos}${url}`); } @@ -226,8 +225,8 @@ class Reader extends Vue { return this.reader.toolBarActive; } - get lastOpenedBook() { - const result = this.$store.getters['reader/lastOpenedBook']; + mostRecentBook() { + const result = bookManager.mostRecentBook(); if (!result) this.closeAllTextPages(); return result; @@ -281,13 +280,13 @@ class Reader extends Vue { setPositionToggle() { this.setPositionActive = !this.setPositionActive; - if (this.setPositionActive && this.activePage == 'TextPage' && this.lastOpenedBook) { + if (this.setPositionActive && this.activePage == 'TextPage' && this.mostRecentBook()) { this.closeAllTextPages(); this.setPositionActive = true; this.$nextTick(() => { - this.$refs.setPositionPage.sliderMax = this.lastOpenedBook.textLength - 1; - this.$refs.setPositionPage.sliderValue = this.lastOpenedBook.bookPos; + this.$refs.setPositionPage.sliderMax = this.mostRecentBook().textLength - 1; + this.$refs.setPositionPage.sliderValue = this.mostRecentBook().bookPos; }); } else { this.setPositionActive = false; @@ -329,7 +328,7 @@ class Reader extends Vue { searchToggle() { this.searchActive = !this.searchActive; const page = this.$refs.page; - if (this.searchActive && this.activePage == 'TextPage' && page.parsed && this.lastOpenedBook) { + if (this.searchActive && this.activePage == 'TextPage' && page.parsed && this.mostRecentBook()) { this.closeAllTextPages(); this.searchActive = true; @@ -383,8 +382,8 @@ class Reader extends Vue { this.historyToggle(); break; case 'refresh': - if (this.lastOpenedBook) { - this.loadBook({url: this.lastOpenedBook.url, force: true}); + if (this.mostRecentBook()) { + this.loadBook({url: this.mostRecentBook().url, force: true}); } break; case 'settings': @@ -413,7 +412,7 @@ class Reader extends Vue { break; } - if (this.activePage == 'LoaderPage' || !this.lastOpenedBook) { + if (this.activePage == 'LoaderPage' || !this.mostRecentBook()) { switch (button) { case 'undoAction': case 'redoAction': @@ -425,7 +424,7 @@ class Reader extends Vue { break; case 'history': case 'refresh': - if (!this.lastOpenedBook) + if (!this.mostRecentBook()) classResult = classDisabled; break; } @@ -441,7 +440,7 @@ class Reader extends Vue { result = 'ProgressPage'; else if (this.loaderActive) result = 'LoaderPage'; - else if (this.lastOpenedBook) + else if (this.mostRecentBook()) result = 'TextPage'; if (!result) { @@ -456,7 +455,7 @@ class Reader extends Vue { if (this.lastActivePage != result && result == 'TextPage') { //акивируем страницу с текстом this.$nextTick(async() => { - const last = this.lastOpenedBook; + const last = this.mostRecentBook(); const isParsed = await bookManager.hasBookParsed(last); if (!isParsed) { @@ -489,9 +488,9 @@ class Reader extends Vue { progress.show(); progress.setState({state: 'parse'}); - // есть ли среди истории OpenedBook + // есть ли среди недавних const key = bookManager.keyFromUrl(opts.url); - let wasOpened = this.reader.openedBook[key]; + let wasOpened = bookManager.getRecentBook({key}); wasOpened = (wasOpened ? wasOpened : {}); const bookPos = (opts.bookPos !== undefined ? opts.bookPos : wasOpened.bookPos); const bookPosSeen = (opts.bookPos !== undefined ? opts.bookPos : wasOpened.bookPosSeen); @@ -506,7 +505,7 @@ class Reader extends Vue { // если есть в локальном кеше if (bookParsed) { - this.commit('reader/setOpenedBook', Object.assign({bookPos, bookPosSeen}, bookManager.metaOnly(bookParsed))); + await bookManager.setRecentBook(Object.assign({bookPos, bookPosSeen}, bookManager.metaOnly(bookParsed))); this.loaderActive = false; progress.hide(); this.progressActive = false; this.blinkCachedLoadMessage(); @@ -545,7 +544,7 @@ class Reader extends Vue { }); // добавляем в историю - this.commit('reader/setOpenedBook', Object.assign({bookPos, bookPosSeen}, bookManager.metaOnly(addedBook))); + await bookManager.setRecentBook(Object.assign({bookPos, bookPosSeen}, bookManager.metaOnly(addedBook))); this.updateRoute(true); this.loaderActive = false; diff --git a/client/components/Reader/share/bookManager.js b/client/components/Reader/share/bookManager.js index 986742cd..51710b3e 100644 --- a/client/components/Reader/share/bookManager.js +++ b/client/components/Reader/share/bookManager.js @@ -13,12 +13,17 @@ const bmDataStore = localForage.createInstance({ name: 'bmDataStore' }); +const bmRecentStore = localForage.createInstance({ + name: 'bmRecentStore' +}); + class BookManager { async init() { this.books = {}; + this.recent = {}; + this.recentChanged = true; - const len = await bmMetaStore.length(); - + let len = await bmMetaStore.length(); for (let i = 0; i < len; i++) { const key = await bmMetaStore.key(i); const keySplit = key.split('-'); @@ -30,6 +35,13 @@ class BookManager { } } + len = await bmRecentStore.length(); + for (let i = 0; i < len; i++) { + const key = await bmRecentStore.key(i); + let r = await bmRecentStore.getItem(key); + this.recent[r.key] = r; + } + await this.cleanBooks(); } @@ -142,6 +154,75 @@ class BookManager { return utils.stringToHex(url); } + async setRecentBook(value) { + if (!this.recent) + await this.init(); + const result = Object.assign({}, value, {touchTime: Date.now()}); + this.recent[result.key] = result; + + await bmRecentStore.setItem(result.key, result); + await this.cleanRecentBooks(); + + this.recentChanged = true; + return result; + } + + async getRecentBook(value) { + if (!this.recent) + await this.init(); + return this.recent[value.key]; + } + + async delRecentBook(value) { + if (!this.recent) + await this.init(); + + await bmRecentStore.removeItem(value.key); + delete this.recent[value.key]; + this.recentChanged = true; + } + + async cleanRecentBooks() { + if (!this.recent) + await this.init(); + + if (Object.keys(this.recent).length > 3) { + let min = Date.now(); + let found = null; + for (let key in this.recent) { + const book = this.recent[key]; + if (book.touchTime < min) { + min = book.touchTime; + found = book; + } + } + + if (found) { + await this.delRecentBook(found); + await this.cleanRecentBooks(); + } + } + } + + mostRecentBook() { + if (!this.recentChanged && this.mostRecentCached) { + return this.mostRecentCached; + } + + let max = 0; + let result = null; + for (let key in this.recent) { + const book = this.recent[key]; + if (book.touchTime > max) { + max = book.touchTime; + result = book; + } + } + this.mostRecentCached = result; + this.recentChanged = false; + return result; + } + } export default new BookManager(); \ No newline at end of file diff --git a/client/store/modules/reader.js b/client/store/modules/reader.js index fae72ce6..8c27f26a 100644 --- a/client/store/modules/reader.js +++ b/client/store/modules/reader.js @@ -168,64 +168,20 @@ for (const font of webFonts) // initial state const state = { toolBarActive: true, - openedBook: {}, settings: Object.assign({}, settingDefaults), }; // getters -const getters = { - lastOpenedBook: (state) => { - let max = 0; - let result = null; - for (let bookKey in state.openedBook) { - const book = state.openedBook[bookKey]; - if (book.touchTime > max) { - max = book.touchTime; - result = book; - } - } - return result; - }, -}; +const getters = {}; // actions const actions = {}; -function delBook(state, value) { - Vue.delete(state.openedBook, value.key); -} - -function cleanBooks(state) { - if (Object.keys(state.openedBook).length > 100) { - let min = Date.now(); - let found = null; - for (let bookKey in state.openedBook) { - const book = state.openedBook[bookKey]; - if (book.touchTime < min) { - min = book.touchTime; - found = book; - } - } - - if (found) { - delBook(state, found); - cleanBooks(state); - } - } -} - // mutations const mutations = { setToolBarActive(state, value) { state.toolBarActive = value; }, - setOpenedBook(state, value) { - Vue.set(state.openedBook, value.key, Object.assign({}, value, {touchTime: Date.now()})); - cleanBooks(state); - }, - delOpenedBook(state, value) { - delBook(state, value); - }, setSettings(state, value) { state.settings = Object.assign({}, state.settings, value); }