diff --git a/client/components/App.vue b/client/components/App.vue
index 7cb8b160..a568a3a9 100644
--- a/client/components/App.vue
+++ b/client/components/App.vue
@@ -113,10 +113,13 @@ class App extends Vue {
this.dispatch('config/loadConfig');
this.$watch('apiError', function(newError) {
if (newError) {
+ let mes = newError.message;
+ if (newError.response && newError.response.config)
+ mes = newError.response.config.url + '
' + newError.response.statusText;
this.$notify.error({
title: 'Ошибка API',
dangerouslyUseHTMLString: true,
- message: newError.response.config.url + '
' + newError.response.statusText
+ message: mes
});
}
});
diff --git a/client/components/Reader/HelpPage/CommonHelpPage/CommonHelpPage.vue b/client/components/Reader/HelpPage/CommonHelpPage/CommonHelpPage.vue
index 6ac25e0b..9a0c5769 100644
--- a/client/components/Reader/HelpPage/CommonHelpPage/CommonHelpPage.vue
+++ b/client/components/Reader/HelpPage/CommonHelpPage/CommonHelpPage.vue
@@ -18,9 +18,15 @@
поддерживаемые браузеры: Google Chrome, Mozilla Firefox последних версий
- В качестве URL можно задавать html-страничку с книгой, либо прямую ссылку
+
В качестве URL книги можно задавать html-страничку с книгой, либо прямую ссылку
на файл из онлайн-библиотеки (например, скопировав адрес ссылки или кнопки "скачать fb2").
- Поддерживаемые форматы: fb2, fb2.zip, html, txt и другие
+ Поддерживаемые форматы: fb2, fb2.zip, html, txt и другие.
+
+ Для автономной загрузки читалки (без интернета):
+ В Google Chrome можно установить флаг chrome://flags/#show-saved-copy
+ в значение "Primary". В этом случае на стандартной странице "нет соединения" появится кнопка для автономной загрузки сайта из кэша.
+ В Mozilla Firefox в автономном режиме сайт загружается из кэша автоматически. Если этого не происходит, можно установить опцию
+ "Веб-разработка" -> "Работать автономно".
Связаться с разработчиком: bookpauk@gmail.com
@@ -32,6 +38,8 @@
import Vue from 'vue';
import Component from 'vue-class-component';
+import {copyTextToClipboard} from '../../../../share/utils';
+
export default @Component({
})
class CommonHelpPage extends Vue {
@@ -41,13 +49,22 @@ class CommonHelpPage extends Vue {
get automationHtml() {
if (this.config.mode == 'omnireader') {
- return `Вы можете добавить в свой браузер закладку, указав в ее свойствах вместо адреса следующий код:
+ return `
Вы также можете добавить в свой браузер закладку, указав в ее свойствах вместо адреса следующий код:
javascript:location.href='http://omnireader.ru/?url='+location.href;
Тогда, нажав на получившуюся кнопку на любой странице интернета, вы автоматически откроете ее в Omni Reader.
`;
} else {
return '';
}
}
+
+ async copyText(text) {
+ const result = await copyTextToClipboard(text);
+ const msg = (result ? `Ссылка на флаг успешно скопирована в буфер обмена. Можно открыть ее в новой вкладке.` : 'Копирование не удалось');
+ if (result)
+ this.$notify.success({message: msg});
+ else
+ this.$notify.error({message: msg});
+ }
}
//-----------------------------------------------------------------------------
@@ -64,4 +81,10 @@ class CommonHelpPage extends Vue {
h4 {
margin: 0;
}
+
+.clickable {
+ color: blue;
+ text-decoration: underline;
+ cursor: pointer;
+}
diff --git a/client/components/Reader/ServerStorage/ServerStorage.vue b/client/components/Reader/ServerStorage/ServerStorage.vue
index d59b598d..3f27f755 100644
--- a/client/components/Reader/ServerStorage/ServerStorage.vue
+++ b/client/components/Reader/ServerStorage/ServerStorage.vue
@@ -50,6 +50,7 @@ class ServerStorage extends Vue {
this.oldSettings = {};
this.oldRecent = {};
this.oldRecentLast = {};
+ this.oldRecentLastDiff = {};
}
async init() {
@@ -353,13 +354,15 @@ class ServerStorage extends Vue {
const oldRev = bookManager.recentRev;
const oldLastRev = bookManager.recentLastRev;
+ const oldLastDiffRev = bookManager.recentLastDiffRev;
//проверим ревизию на сервере
let revs = null;
if (!force) {
try {
- revs = await this.storageCheck({recent: {}, recentLast: {}});
+ revs = await this.storageCheck({recent: {}, recentLast: {}, recentLastDiff: {}});
if (revs.state == 'success' && revs.items.recent.rev == oldRev &&
- revs.items.recentLast.rev == oldLastRev) {
+ revs.items.recentLast.rev == oldLastRev &&
+ revs.items.recentLastDiff.rev == oldLastDiffRev) {
return;
}
} catch(e) {
@@ -391,24 +394,32 @@ class ServerStorage extends Vue {
}
}
- if (force || revs.items.recentLast.rev != oldLastRev) {
+ if (force || revs.items.recentLast.rev != oldLastRev || revs.items.recentLastDiff.rev != oldLastDiffRev) {
let recentLast = null;
try {
- recentLast = await this.storageGet({recentLast: {}});
+ 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}`);
}
@@ -476,6 +487,11 @@ class ServerStorage extends Vue {
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: ''};
@@ -515,12 +531,69 @@ class ServerStorage extends Vue {
} 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) {
return await this.storageApi('check', items);
}
diff --git a/client/components/Reader/share/bookManager.js b/client/components/Reader/share/bookManager.js
index 59ad205e..0bb8972e 100644
--- a/client/components/Reader/share/bookManager.js
+++ b/client/components/Reader/share/bookManager.js
@@ -38,6 +38,7 @@ class BookManager {
this.recent[this.recentLast.key] = this.recentLast;
this.recentRev = await bmRecentStore.getItem('recent-rev') || 0;
this.recentLastRev = await bmRecentStore.getItem('recent-last-rev') || 0;
+ this.recentLastDiffRev = await bmRecentStore.getItem('recent-last-diff-rev') || 0;
this.books = Object.assign({}, this.booksCached);
this.recentChanged2 = true;
@@ -428,10 +429,15 @@ class BookManager {
}
async setRecentLastRev(value) {
- bmRecentStore.setItem('recent-last-rev', value);
+ await bmRecentStore.setItem('recent-last-rev', value);
this.recentLastRev = value;
}
+ async setRecentLastDiffRev(value) {
+ await bmRecentStore.setItem('recent-last-diff-rev', value);
+ this.recentLastDiffRev = value;
+ }
+
addEventListener(listener) {
if (this.eventListeners.indexOf(listener) < 0)
this.eventListeners.push(listener);
diff --git a/package-lock.json b/package-lock.json
index fc13440b..8b8e16b9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "Liberama",
- "version": "0.5.6",
+ "version": "0.6.5",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 0a58b078..83774c3d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "Liberama",
- "version": "0.6.5",
+ "version": "0.6.6",
"engines": {
"node": ">=10.0.0"
},