Начало переделки ServerStorage

This commit is contained in:
Book Pauk
2019-09-06 18:47:07 +07:00
parent 30eb3001ef
commit 96945dfc4a
5 changed files with 151 additions and 283 deletions

View File

@@ -73,7 +73,7 @@
<SettingsPage v-if="settingsActive" ref="settingsPage" @settings-toggle="settingsToggle"></SettingsPage> <SettingsPage v-if="settingsActive" ref="settingsPage" @settings-toggle="settingsToggle"></SettingsPage>
<HelpPage v-if="helpActive" ref="helpPage" @help-toggle="helpToggle"></HelpPage> <HelpPage v-if="helpActive" ref="helpPage" @help-toggle="helpToggle"></HelpPage>
<ClickMapPage v-show="clickMapActive" ref="clickMapPage"></ClickMapPage> <ClickMapPage v-show="clickMapActive" ref="clickMapPage"></ClickMapPage>
<!--ServerStorage v-show="hidden" ref="serverStorage"></ServerStorage--> <ServerStorage v-show="hidden" ref="serverStorage"></ServerStorage>
<el-dialog <el-dialog
title="Что нового:" title="Что нового:"
@@ -191,7 +191,7 @@ import RecentBooksPage from './RecentBooksPage/RecentBooksPage.vue';
import SettingsPage from './SettingsPage/SettingsPage.vue'; import SettingsPage from './SettingsPage/SettingsPage.vue';
import HelpPage from './HelpPage/HelpPage.vue'; import HelpPage from './HelpPage/HelpPage.vue';
import ClickMapPage from './ClickMapPage/ClickMapPage.vue'; import ClickMapPage from './ClickMapPage/ClickMapPage.vue';
//import ServerStorage from './ServerStorage/ServerStorage.vue'; import ServerStorage from './ServerStorage/ServerStorage.vue';
import bookManager from './share/bookManager'; import bookManager from './share/bookManager';
import readerApi from '../../api/reader'; import readerApi from '../../api/reader';
@@ -211,7 +211,7 @@ export default @Component({
SettingsPage, SettingsPage,
HelpPage, HelpPage,
ClickMapPage, ClickMapPage,
//ServerStorage, ServerStorage,
}, },
watch: { watch: {
bookPos: function(newValue) { bookPos: function(newValue) {
@@ -301,18 +301,6 @@ class Reader extends Vue {
} }
}, 500); }, 500);
/*this.debouncedSaveRecent = _.debounce(async() => {
const serverStorage = this.$refs.serverStorage;
while (!serverStorage.inited) await utils.sleep(1000);
await serverStorage.saveRecent();
}, 1000);
this.debouncedSaveRecentLast = _.debounce(async() => {
const serverStorage = this.$refs.serverStorage;
while (!serverStorage.inited) await utils.sleep(1000);
await serverStorage.saveRecentLast();
}, 1000);*/
document.addEventListener('fullscreenchange', () => { document.addEventListener('fullscreenchange', () => {
this.fullScreenActive = (document.fullscreenElement !== null); this.fullScreenActive = (document.fullscreenElement !== null);
}); });
@@ -347,6 +335,7 @@ class Reader extends Vue {
this.checkActivateDonateHelpPage(); this.checkActivateDonateHelpPage();
this.loading = false; this.loading = false;
await this.$refs.serverStorage.init();
await this.showWhatsNew(); await this.showWhatsNew();
await this.showMigration(); await this.showMigration();
})(); })();
@@ -516,14 +505,6 @@ class Reader extends Vue {
} }
async bookManagerEvent(eventName) { async bookManagerEvent(eventName) {
/*const serverStorage = this.$refs.serverStorage;
if (eventName == '') {
serverStorage.init();
const result = await bookManager.cleanRecentBooks();
if (result)
this.debouncedSaveRecent();
}*/
if (eventName == 'recent-changed') { if (eventName == 'recent-changed') {
if (this.recentBooksActive) { if (this.recentBooksActive) {
await this.$refs.recentBooksPage.updateTableData(); await this.$refs.recentBooksPage.updateTableData();
@@ -545,12 +526,6 @@ class Reader extends Vue {
this.bookPosChanged({bookPos: newBook.bookPos}); this.bookPosChanged({bookPos: newBook.bookPos});
} }
} }
/*if (eventName == 'recent-changed') {
this.debouncedSaveRecentLast();
} else {
this.debouncedSaveRecent();
}*/
} }
} }

View File

@@ -13,8 +13,6 @@ import readerApi from '../../../api/reader';
import * as utils from '../../../share/utils'; import * as utils from '../../../share/utils';
import * as cryptoUtils from '../../../share/cryptoUtils'; import * as cryptoUtils from '../../../share/cryptoUtils';
const maxSetTries = 5;
export default @Component({ export default @Component({
watch: { watch: {
serverSyncEnabled: function() { serverSyncEnabled: function() {
@@ -46,11 +44,18 @@ class ServerStorage extends Vue {
this.saveSettings(); this.saveSettings();
}, 500); }, 500);
this.debouncedSaveRecent = _.debounce(() => {
this.saveRecent();
}, 1000);
this.debouncedNotifySuccess = _.debounce(() => {
this.success('Данные синхронизированы с сервером');
}, 1000);
this.oldProfiles = {}; this.oldProfiles = {};
this.oldSettings = {}; this.oldSettings = {};
this.oldRecent = {}; this.oldRecent = {};
this.oldRecentLast = {}; this.oldRecentDiff = {};
this.oldRecentLastDiff = {};
} }
async init() { async init() {
@@ -61,13 +66,27 @@ class ServerStorage extends Vue {
} else { } else {
await this.serverStorageKeyChanged(); await this.serverStorageKeyChanged();
} }
this.oldRecent = _.cloneDeep(bookManager.recent); bookManager.addEventListener(this.bookManagerEvent);
this.oldRecentLast = _.cloneDeep(bookManager.recentLast) || {};
} finally { } finally {
this.inited = true; this.inited = true;
} }
} }
async bookManagerEvent(eventName) {
if (eventName == 'load-stored-finish') {
this.oldRecent = _.cloneDeep(bookManager.recent);
this.oldRecentLast = _.cloneDeep(bookManager.recentLast) || {};
}
if (eventName == 'recent-changed') {
let i = 0;
while (!bookManager.loaded && i++ < 1000) await utils.sleep(100);
i = 0;
while (!this.inited && i++ < 1000) await utils.sleep(100);
this.debouncedSaveRecent();
}
}
async generateNewServerStorageKey() { async generateNewServerStorageKey() {
const key = utils.toBase58(utils.randomArray(32)); const key = utils.toBase58(utils.randomArray(32));
this.commit('reader/setServerStorageKey', key); this.commit('reader/setServerStorageKey', key);
@@ -146,10 +165,6 @@ class ServerStorage extends Vue {
} }
} }
notifySuccess() {
this.success('Данные синхронизированы с сервером');
}
success(message) { success(message) {
if (this.showServerStorageMessages) if (this.showServerStorageMessages)
this.$notify.success({message}); this.$notify.success({message});
@@ -165,7 +180,7 @@ class ServerStorage extends Vue {
this.$notify.error({message}); this.$notify.error({message});
} }
async loadSettings(force) { async loadSettings(force = false, doNotifySuccess = true) {
if (!this.keyInited || !this.serverSyncEnabled || !this.currentProfile) if (!this.keyInited || !this.serverSyncEnabled || !this.currentProfile)
return; return;
@@ -202,7 +217,8 @@ class ServerStorage extends Vue {
this.commit('reader/setSettings', sets.data); this.commit('reader/setSettings', sets.data);
this.commit('reader/setSettingsRev', {[setsId]: sets.rev}); this.commit('reader/setSettingsRev', {[setsId]: sets.rev});
this.notifySuccess(); if (doNotifySuccess)
this.debouncedNotifySuccess();
} else { } else {
this.warning(`Неверный ответ сервера: ${sets.state}`); this.warning(`Неверный ответ сервера: ${sets.state}`);
} }
@@ -220,32 +236,18 @@ class ServerStorage extends Vue {
try { try {
const setsId = `settings-${this.currentProfile}`; const setsId = `settings-${this.currentProfile}`;
let result = {state: ''}; let result = {state: ''};
let tries = 0;
while (result.state != 'success' && tries < maxSetTries) {
const oldRev = this.settingsRev[setsId] || 0;
try {
result = await this.storageSet({[setsId]: {rev: oldRev + 1, data: this.settings}});
} catch(e) {
this.savingSettings = false;
this.error(`Ошибка соединения с сервером (${e.message}). Данные не сохранены и могут быть перезаписаны.`);
return;
}
if (result.state == 'reject') { const oldRev = this.settingsRev[setsId] || 0;
await this.loadSettings(true); try {
const newSettings = utils.applyObjDiff(this.settings, diff); result = await this.storageSet({[setsId]: {rev: oldRev + 1, data: this.settings}});
this.commit('reader/setSettings', newSettings); } catch(e) {
} this.error(`Ошибка соединения с сервером (${e.message}). Данные не сохранены и могут быть перезаписаны.`);
tries++;
} }
if (tries >= maxSetTries) { if (result.state == 'reject') {
//отменять изменения не будем, просто предупредим await this.loadSettings(true, false);
//this.commit('reader/setSettings', this.oldSettings); this.warning(`Последние изменения отменены. Данные синхронизированы с сервером.`);
console.error(result); } else if (result.state == 'success') {
this.error('Не удалось отправить настройки на сервер. Данные не сохранены и могут быть перезаписаны.');
} else {
this.oldSettings = _.cloneDeep(this.settings); this.oldSettings = _.cloneDeep(this.settings);
this.commit('reader/setSettingsRev', {[setsId]: this.settingsRev[setsId] + 1}); this.commit('reader/setSettingsRev', {[setsId]: this.settingsRev[setsId] + 1});
} }
@@ -254,7 +256,7 @@ class ServerStorage extends Vue {
} }
} }
async loadProfiles(force) { async loadProfiles(force = false, doNotifySuccess = true) {
if (!this.keyInited || !this.serverSyncEnabled) if (!this.keyInited || !this.serverSyncEnabled)
return; return;
@@ -289,8 +291,10 @@ class ServerStorage extends Vue {
this.oldProfiles = _.cloneDeep(prof.data); this.oldProfiles = _.cloneDeep(prof.data);
this.commit('reader/setProfiles', prof.data); this.commit('reader/setProfiles', prof.data);
this.commit('reader/setProfilesRev', prof.rev); this.commit('reader/setProfilesRev', prof.rev);
this.checkCurrentProfile();
this.notifySuccess(); if (doNotifySuccess)
this.debouncedNotifySuccess();
} else { } else {
this.warning(`Неверный ответ сервера: ${prof.state}`); this.warning(`Неверный ответ сервера: ${prof.state}`);
} }
@@ -304,7 +308,7 @@ class ServerStorage extends Vue {
if (utils.isEmptyObjDiff(diff)) if (utils.isEmptyObjDiff(diff))
return; return;
//обнуляются профили во время разработки, подстраховка //обнуляются профили во время разработки при hotReload, подстраховка
if (!this.$store.state.reader.allowProfilesSave) { if (!this.$store.state.reader.allowProfilesSave) {
console.error('Сохранение профилей не санкционировано'); console.error('Сохранение профилей не санкционировано');
return; return;
@@ -313,33 +317,16 @@ class ServerStorage extends Vue {
this.savingProfiles = true; this.savingProfiles = true;
try { try {
let result = {state: ''}; let result = {state: ''};
let tries = 0; try {
while (result.state != 'success' && tries < maxSetTries) { result = await this.storageSet({profiles: {rev: this.profilesRev + 1, data: this.profiles}});
try { } catch(e) {
result = await this.storageSet({profiles: {rev: this.profilesRev + 1, data: this.profiles}}); this.error(`Ошибка соединения с сервером (${e.message}). Данные не сохранены и могут быть перезаписаны.`);
} catch(e) {
this.savingProfiles = false;
this.commit('reader/setProfiles', this.oldProfiles);
this.checkCurrentProfile();
this.error(`Ошибка соединения с сервером: (${e.message}). Изменения отменены.`);
return;
}
if (result.state == 'reject') {
await this.loadProfiles(true);
const newProfiles = utils.applyObjDiff(this.profiles, diff);
this.commit('reader/setProfiles', newProfiles);
}
tries++;
} }
if (tries >= maxSetTries) { if (result.state == 'reject') {
this.commit('reader/setProfiles', this.oldProfiles); await this.loadProfiles(true, false);
this.checkCurrentProfile(); this.warning(`Последние изменения отменены. Данные синхронизированы с сервером.`);
console.error(result); } else if (result.state == 'success') {
this.error('Не удалось отправить данные на сервер. Изменения отменены.');
} else {
this.oldProfiles = _.cloneDeep(this.profiles); this.oldProfiles = _.cloneDeep(this.profiles);
this.commit('reader/setProfilesRev', this.profilesRev + 1); this.commit('reader/setProfilesRev', this.profilesRev + 1);
} }
@@ -348,21 +335,19 @@ class ServerStorage extends Vue {
} }
} }
async loadRecent(force) { async loadRecent(force = false, doNotifySuccess = true) {
if (!this.keyInited || !this.serverSyncEnabled) if (!this.keyInited || !this.serverSyncEnabled)
return; return;
const oldRev = bookManager.recentRev; const oldRecentRev = bookManager.recentRev;
const oldLastRev = bookManager.recentLastRev; const oldRecentDiffRev = bookManager.recentDiffRev;
const oldLastDiffRev = bookManager.recentLastDiffRev;
//проверим ревизию на сервере //проверим ревизию на сервере
let revs = null; let revs = null;
if (!force) { if (!force) {
try { try {
revs = await this.storageCheck({recent: {}, recentLast: {}, recentLastDiff: {}}); revs = await this.storageCheck({recent: {}, recentDiff: {}});
if (revs.state == 'success' && revs.items.recent.rev == oldRev && if (revs.state == 'success' && revs.items.recent.rev == oldRecentRev &&
revs.items.recentLast.rev == oldLastRev && revs.items.recentDiff.rev == oldRecentDiffRev) {
revs.items.recentLastDiff.rev == oldLastDiffRev) {
return; return;
} }
} catch(e) { } catch(e) {
@@ -371,7 +356,32 @@ class ServerStorage extends Vue {
} }
} }
if (force || revs.items.recent.rev != oldRev) { console.log('load');
let recentDiff = null;
if (force || revs.items.recentDiff.rev != oldRecentDiffRev) {
try {
recentDiff = await this.storageGet({recentDiff: {}});
} catch(e) {
this.error(`Ошибка соединения с сервером: ${e.message}`);
return;
}
if (recentDiff.state == 'success') {
recentDiff = recentDiff.items.recentDiff;
if (recentDiff.rev == 0)
recentDiff.data = {};
this.oldRecentDiff = _.cloneDeep(recentDiff.data);
await bookManager.setRecentDiffRev(recentDiff.rev);
} else {
this.warning(`Неверный ответ сервера: ${recentDiff.state}`);
recentDiff = null;
}
}
if (force || revs.items.recent.rev != oldRecentRev) {
let recent = null; let recent = null;
try { try {
recent = await this.storageGet({recent: {}}); recent = await this.storageGet({recent: {}});
@@ -386,46 +396,23 @@ class ServerStorage extends Vue {
if (recent.rev == 0) if (recent.rev == 0)
recent.data = {}; recent.data = {};
this.oldRecent = _.cloneDeep(recent.data); let newRecent = {};
await bookManager.setRecent(recent.data); if (recentDiff && recentDiff.data) {
newRecent = utils.applyObjDiff(recent.data, recentDiff.data);
} else {
newRecent = recent.data;
}
this.oldRecent = _.cloneDeep(newRecent);
await bookManager.setRecent(newRecent);
await bookManager.setRecentRev(recent.rev); await bookManager.setRecentRev(recent.rev);
} else { } else {
this.warning(`Неверный ответ сервера: ${recent.state}`); this.warning(`Неверный ответ сервера: ${recent.state}`);
} }
} }
if (force || revs.items.recentLast.rev != oldLastRev || revs.items.recentLastDiff.rev != oldLastDiffRev) { if (doNotifySuccess)
let recentLast = null; this.debouncedNotifySuccess();
try {
recentLast = await this.storageGet({recentLast: {}, recentLastDiff: {}});
} catch(e) {
this.error(`Ошибка соединения с сервером: ${e.message}`);
return;
}
if (recentLast.state == 'success') {
const recentLastDiff = recentLast.items.recentLastDiff;
recentLast = recentLast.items.recentLast;
if (recentLast.rev == 0)
recentLast.data = {};
if (recentLastDiff.rev == 0)
recentLastDiff.data = {};
this.oldRecentLastDiff = _.cloneDeep(recentLastDiff.data);
this.oldRecentLast = _.cloneDeep(recentLast.data);
recentLast.data = utils.applyObjDiff(recentLast.data, recentLastDiff.data);
await bookManager.setRecentLast(recentLast.data);
await bookManager.setRecentLastRev(recentLast.rev);
await bookManager.setRecentLastDiffRev(recentLastDiff.rev);
} else {
this.warning(`Неверный ответ сервера: ${recentLast.state}`);
}
}
this.notifySuccess();
} }
async saveRecent() { async saveRecent() {
@@ -437,163 +424,29 @@ class ServerStorage extends Vue {
const diff = utils.getObjDiff(this.oldRecent, bm.recent); const diff = utils.getObjDiff(this.oldRecent, bm.recent);
if (utils.isEmptyObjDiff(diff)) if (utils.isEmptyObjDiff(diff))
return; return;
console.log('save');
this.savingRecent = true; this.savingRecent = true;
try { try {
let result = {state: ''}; let result = {state: ''};
let tries = 0;
while (result.state != 'success' && tries < maxSetTries) {
try {
result = await this.storageSet({recent: {rev: bm.recentRev + 1, data: bm.recent}});
} catch(e) {
this.savingRecent = false;
this.error(`Ошибка соединения с сервером: (${e.message}). Изменения не сохранены.`);
return;
}
if (result.state == 'reject') { try {
await this.loadRecent(true); result = await this.storageSet({recent: {rev: bm.recentRev + 1, data: bm.recent}});
//похоже это лишнее } catch(e) {
/*const newRecent = utils.applyObjDiff(bm.recent, diff); this.error(`Ошибка соединения с сервером (${e.message}). Данные не сохранены и могут быть перезаписаны.`);
await bm.setRecent(newRecent);*/
}
tries++;
} }
if (tries >= maxSetTries) { if (result.state == 'reject') {
console.error(result); await this.loadRecent(true, false);
this.error('Не удалось отправить данные на сервер. Данные не сохранены и могут быть перезаписаны.'); this.warning(`Последние изменения отменены. Данные синхронизированы с сервером.`);
} else { } else if (result.state == 'success') {
this.oldRecent = _.cloneDeep(bm.recent); this.oldRecent = _.cloneDeep(bm.recent);
await bm.setRecentRev(bm.recentRev + 1); await bm.setRecentRev(bm.recentRev + 1);
await this.saveRecentLast(true);
} }
} finally { } finally {
this.savingRecent = false; this.savingRecent = false;
} }
} }
async saveRecentLast(force = false) {
if (!this.keyInited || !this.serverSyncEnabled || this.savingRecentLast)
return;
const bm = bookManager;
let recentLast = bm.recentLast;
recentLast = (recentLast ? recentLast : {});
let lastRev = bm.recentLastRev;
const diff = utils.getObjDiff(this.oldRecentLast, recentLast);
if (utils.isEmptyObjDiff(diff))
return;
if (this.oldRecentLast.key == recentLast.key && JSON.stringify(recentLast) > JSON.stringify(diff)) {
await this.saveRecentLastDiff(diff, force);
return;
}
this.savingRecentLast = true;
try {
let result = {state: ''};
let tries = 0;
while (result.state != 'success' && tries < maxSetTries) {
if (force) {
try {
const revs = await this.storageCheck({recentLast: {}});
if (revs.items.recentLast.rev)
lastRev = revs.items.recentLast.rev;
} catch(e) {
this.error(`Ошибка соединения с сервером: ${e.message}`);
return;
}
}
try {
result = await this.storageSet({recentLast: {rev: lastRev + 1, data: recentLast}}, force);
} catch(e) {
this.savingRecentLast = false;
this.error(`Ошибка соединения с сервером: (${e.message}). Изменения не сохранены.`);
return;
}
if (result.state == 'reject') {
await this.loadRecent(false);
this.savingRecentLast = false;//!!!
return;//!!!
}
tries++;
}
if (tries >= maxSetTries) {
console.error(result);
this.error('Не удалось отправить данные на сервер. Данные не сохранены и могут быть перезаписаны.');
} else {
this.oldRecentLast = _.cloneDeep(recentLast);
await bm.setRecentLastRev(lastRev + 1);
await this.saveRecentLastDiff({}, true);
}
} finally {
this.savingRecentLast = false;
}
}
async saveRecentLastDiff(diff, force = false) {
if (!this.keyInited || !this.serverSyncEnabled || this.savingRecentLastDiff)
return;
const bm = bookManager;
let lastRev = bm.recentLastDiffRev;
const d = utils.getObjDiff(this.oldRecentLastDiff, diff);
if (utils.isEmptyObjDiff(d))
return;
this.savingRecentLastDiff = true;
try {
let result = {state: ''};
let tries = 0;
while (result.state != 'success' && tries < maxSetTries) {
if (force) {
try {
const revs = await this.storageCheck({recentLastDiff: {}});
if (revs.items.recentLastDiff.rev)
lastRev = revs.items.recentLastDiff.rev;
} catch(e) {
this.error(`Ошибка соединения с сервером: ${e.message}`);
return;
}
}
try {
result = await this.storageSet({recentLastDiff: {rev: lastRev + 1, data: diff}}, force);
} catch(e) {
this.savingRecentLastDiff = false;
this.error(`Ошибка соединения с сервером: (${e.message}). Изменения не сохранены.`);
return;
}
if (result.state == 'reject') {
await this.loadRecent(false);
this.savingRecentLastDiff = false;
return;
}
tries++;
}
if (tries >= maxSetTries) {
console.error(result);
this.error('Не удалось отправить данные на сервер. Данные не сохранены и могут быть перезаписаны.');
} else {
this.oldRecentLastDiff = _.cloneDeep(diff);
await bm.setRecentLastDiffRev(lastRev + 1);
}
} finally {
this.savingRecentLastDiff = false;
}
}
async storageCheck(items) { async storageCheck(items) {
return await this.storageApi('check', items); return await this.storageApi('check', items);
} }

View File

@@ -1,5 +1,5 @@
<template> <template>
<Window ref="window" height="70%" width="600px" @close="close"> <Window ref="window" height="95%" width="600px" @close="close">
<template slot="header"> <template slot="header">
Настройки Настройки
</template> </template>
@@ -537,7 +537,8 @@ export default @Component({
this.settingsChanged(); this.settingsChanged();
}, },
form: function(newValue) { form: function(newValue) {
this.commit('reader/setSettings', newValue); if (this.inited)
this.commit('reader/setSettings', newValue);
}, },
fontBold: function(newValue) { fontBold: function(newValue) {
this.fontWeight = (newValue ? 'bold' : ''); this.fontWeight = (newValue ? 'bold' : '');
@@ -588,6 +589,7 @@ class SettingsPage extends Vue {
init() { init() {
this.$refs.window.init(); this.$refs.window.init();
this.inited = true;
} }
settingsChanged() { settingsChanged() {

View File

@@ -31,6 +31,9 @@ class BookManager {
if (this.recentLast) if (this.recentLast)
this.recent[this.recentLast.key] = this.recentLast; this.recent[this.recentLast.key] = this.recentLast;
this.recentRev = await bmRecentStore.getItem('recent-rev') || 0;
this.recentDiffRev = await bmRecentStore.getItem('recent-diff-rev') || 0;
this.recentChanged = true; this.recentChanged = true;
this.loadStored();//no await this.loadStored();//no await
@@ -419,6 +422,41 @@ class BookManager {
return result; return result;
} }
async setRecent(value) {
const mergedRecent = _.cloneDeep(this.recent);
Object.assign(mergedRecent, value);
//"ленивое" обновление хранилища
(async() => {
for (const rec of Object.values(mergedRecent)) {
if (rec.key) {
await bmRecentStore.setItem(rec.key, rec);
await utils.sleep(1);
}
}
})();
this.recent = mergedRecent;
this.recentLast = null;
await bmRecentStore.setItem('recent-last', this.recentLast);
this.recentChanged = true;
this.emit('recent-changed');
}
async setRecentRev(value) {
await bmRecentStore.setItem('recent-rev', value);
this.recentRev = value;
}
async setRecentDiffRev(value) {
await bmRecentStore.setItem('recent-diff-rev', value);
this.recentDiffRev = value;
}
addEventListener(listener) { addEventListener(listener) {
if (this.eventListeners.indexOf(listener) < 0) if (this.eventListeners.indexOf(listener) < 0)
this.eventListeners.push(listener); this.eventListeners.push(listener);
@@ -433,7 +471,7 @@ class BookManager {
emit(eventName, value) { emit(eventName, value) {
if (this.eventListeners) { if (this.eventListeners) {
(async() => { (async() => {
await utils.sleep(1); await utils.sleep(1);//неблокирующая рассылка сообщений
for (const listener of this.eventListeners) { for (const listener of this.eventListeners) {
//console.log(eventName); //console.log(eventName);
listener(eventName, value); listener(eventName, value);

View File

@@ -6,10 +6,10 @@ export const versionHistory = [
` `
<ul> <ul>
<li>налажена работа https-версии сайта, рекомендуется плавный переход</li> <li>налажена работа https-версии сайта, рекомендуется плавный переход</li>
<li>добавлена возможность загрузки и работы читалки в оффлайн-режиме (при отсутствии интернета)</li> <li>добавлена возможность загрузки и работы https-версии читалки в оффлайн-режиме (при отсутствии интернета)</li>
<li>упрощение механизма серверной синхронизации с целью повышения надежности и избавления от багов</li> <li>упрощение механизма серверной синхронизации с целью повышения надежности и избавления от багов</li>
<li>окна теперь можно перемещать за заголовок</li> <li>окна теперь можно перемещать за заголовок</li>
<li>улучшен внешний вид и управление на смартфонах</li> <li>немного улучшен внешний вид и управление на смартфонах</li>
<li>добавлен параметр "Компактность" в раздел "Вид"->"Текст" в настройках</li> <li>добавлен параметр "Компактность" в раздел "Вид"->"Текст" в настройках</li>
</ul> </ul>
` `