Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
956546585c | ||
|
|
3ca0a92442 | ||
|
|
213f7e48c9 | ||
|
|
8b66fd522d | ||
|
|
fdf5009999 | ||
|
|
bbdba0ef16 | ||
|
|
a63602df7a | ||
|
|
587120f984 | ||
|
|
e72ca0de7e | ||
|
|
c44c27d3d2 | ||
|
|
df4e201ccd | ||
|
|
c8c0e9ec1a | ||
|
|
9a4a84a367 | ||
|
|
1dc3424411 | ||
|
|
c13745e913 | ||
|
|
25c12309f2 | ||
|
|
4b632da5af | ||
|
|
87c364b8ee | ||
|
|
efa48fbc8a | ||
|
|
21df6c1d21 | ||
|
|
39d2ceb94b | ||
|
|
1dad013d60 | ||
|
|
add7a03f88 | ||
|
|
0cefaa6d48 | ||
|
|
f08e73f359 |
@@ -0,0 +1,59 @@
|
|||||||
|
<template>
|
||||||
|
<Window ref="window" width="600px" height="95%" @close="close">
|
||||||
|
<template slot="header">
|
||||||
|
Настроить закладки
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</Window>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
import Vue from 'vue';
|
||||||
|
import Component from 'vue-class-component';
|
||||||
|
import Window from '../../share/Window.vue';
|
||||||
|
|
||||||
|
const BookmarkSettingsProps = Vue.extend({
|
||||||
|
props: {
|
||||||
|
libs: Object,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default @Component({
|
||||||
|
components: {
|
||||||
|
Window,
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
libs: function() {
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
class BookmarkSettings extends BookmarkSettingsProps {
|
||||||
|
created() {
|
||||||
|
}
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.$refs.window.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.$emit('close');
|
||||||
|
}
|
||||||
|
|
||||||
|
keyHook(event) {
|
||||||
|
if (event.type == 'keydown' && event.key == 'Escape') {
|
||||||
|
this.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<Window ref="window" @close="close">
|
<Window ref="window" @close="close" margin="2px">
|
||||||
<template slot="header">
|
<template slot="header">
|
||||||
{{ header }}
|
{{ header }}
|
||||||
</template>
|
</template>
|
||||||
@@ -13,7 +13,8 @@
|
|||||||
|
|
||||||
<div v-show="ready" class="col column" style="min-width: 600px">
|
<div v-show="ready" class="col column" style="min-width: 600px">
|
||||||
<div class="row items-center q-px-sm" style="height: 50px">
|
<div class="row items-center q-px-sm" style="height: 50px">
|
||||||
<q-select class="q-mr-sm" v-model="rootLink" :options="rootLinkOptions"
|
<q-select class="q-mr-sm" ref="rootLink" v-model="rootLink" :options="rootLinkOptions" @input="rootLinkInput"
|
||||||
|
@popup-show="onSelectPopupShow" @popup-hide="onSelectPopupHide"
|
||||||
style="width: 230px"
|
style="width: 230px"
|
||||||
dropdown-icon="la la-angle-down la-sm"
|
dropdown-icon="la la-angle-down la-sm"
|
||||||
rounded outlined dense emit-value map-options display-value-sanitize options-sanitize
|
rounded outlined dense emit-value map-options display-value-sanitize options-sanitize
|
||||||
@@ -22,21 +23,26 @@
|
|||||||
<q-btn class="q-mr-xs" round dense color="blue" icon="la la-plus" @click.stop="addBookmark" size="12px">
|
<q-btn class="q-mr-xs" round dense color="blue" icon="la la-plus" @click.stop="addBookmark" size="12px">
|
||||||
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">Добавить закладку</q-tooltip>
|
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">Добавить закладку</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
<q-btn round dense color="blue" icon="la la-bars" @click.stop="bookmarkSettings" size="12px" disabled>
|
<q-btn round dense color="blue" icon="la la-bars" @click.stop="bookmarkSettings" size="12px" disabled>
|
||||||
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">Настроить закладки (пока недоступно)</q-tooltip>
|
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">Настроить закладки</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:selected>
|
<template v-slot:selected>
|
||||||
<div style="overflow: hidden; white-space: nowrap;">{{ removeProtocol(rootLink) }}</div>
|
<div style="overflow: hidden; white-space: nowrap;">{{ removeProtocol(rootLink) }}</div>
|
||||||
</template>
|
</template>
|
||||||
</q-select>
|
</q-select>
|
||||||
<q-select class="q-mr-sm" v-model="selectedLink" :options="selectedLinkOptions" style="width: 50px"
|
|
||||||
|
<q-select class="q-mr-sm" ref="selectedLink" v-model="selectedLink" :options="selectedLinkOptions" @input="selectedLinkInput" style="width: 50px"
|
||||||
|
@popup-show="onSelectPopupShow" @popup-hide="onSelectPopupHide"
|
||||||
dropdown-icon="la la-angle-down la-sm"
|
dropdown-icon="la la-angle-down la-sm"
|
||||||
rounded outlined dense emit-value map-options hide-selected display-value-sanitize options-sanitize
|
rounded outlined dense emit-value map-options hide-selected display-value-sanitize options-sanitize
|
||||||
>
|
>
|
||||||
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">Закладки</q-tooltip>
|
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">Закладки</q-tooltip>
|
||||||
</q-select>
|
</q-select>
|
||||||
<q-input class="col q-mr-sm" ref="input" rounded outlined dense bg-color="white" v-model="bookUrl" placeholder="Скопируйте сюда URL книги" @focus="onInputFocus">
|
|
||||||
|
<q-input class="col q-mr-sm" ref="input" rounded outlined dense bg-color="white" v-model="bookUrl" placeholder="Скопируйте сюда URL книги"
|
||||||
|
@focus="selectAllOnFocus" @keydown="bookUrlKeyDown"
|
||||||
|
>
|
||||||
<template v-slot:prepend>
|
<template v-slot:prepend>
|
||||||
<q-btn class="q-mr-xs" round dense color="blue" icon="la la-home" @click="goToLink(libs.startLink)" size="12px">
|
<q-btn class="q-mr-xs" round dense color="blue" icon="la la-home" @click="goToLink(libs.startLink)" size="12px">
|
||||||
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">Вернуться на стартовую страницу</q-tooltip>
|
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">Вернуться на стартовую страницу</q-tooltip>
|
||||||
@@ -46,13 +52,17 @@
|
|||||||
</q-btn>
|
</q-btn>
|
||||||
</template>
|
</template>
|
||||||
</q-input>
|
</q-input>
|
||||||
|
|
||||||
<q-btn rounded color="green-7" no-caps size="14px" @click="submitUrl">Открыть
|
<q-btn rounded color="green-7" no-caps size="14px" @click="submitUrl">Открыть
|
||||||
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">Открыть в читалке</q-tooltip>
|
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">Открыть в читалке</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</div>
|
</div>
|
||||||
<div class="separator"></div>
|
<div class="separator"></div>
|
||||||
|
|
||||||
<iframe v-if="frameVisible" class="col fit" ref="frame" :src="frameSrc" frameborder="0"></iframe>
|
<div class="col fit" style="position: relative;">
|
||||||
|
<iframe v-if="frameVisible" class="fit" ref="frame" :src="frameSrc" frameborder="0"></iframe>
|
||||||
|
<div v-show="transparentLayoutVisible" ref="transparentLayout" class="fit transparent-layout" @click="transparentLayoutClick"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Dialog ref="dialogAddBookmark" v-model="addBookmarkVisible">
|
<Dialog ref="dialogAddBookmark" v-model="addBookmarkVisible">
|
||||||
<template slot="header">
|
<template slot="header">
|
||||||
@@ -63,11 +73,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="q-mx-md row">
|
<div class="q-mx-md row">
|
||||||
<q-input ref="bookmarkLink" class="col q-mr-sm" outlined dense bg-color="white" v-model="bookmarkLink"
|
<q-input ref="bookmarkLink" class="col q-mr-sm" outlined dense bg-color="white" v-model="bookmarkLink" @keydown="bookmarkLinkKeyDown"
|
||||||
placeholder="Ссылка для закладки" maxlength="2000" @focus="onInputFocus">
|
placeholder="Ссылка для закладки" maxlength="2000" @focus="selectAllOnFocus">
|
||||||
</q-input>
|
</q-input>
|
||||||
|
|
||||||
<q-select class="q-mr-sm" v-model="defaultRootLink" :options="defaultRootLinkOptions" style="width: 50px"
|
<q-select class="q-mr-sm" ref="defaultRootLink" v-model="defaultRootLink" :options="defaultRootLinkOptions" @input="defaultRootLinkInput" style="width: 50px"
|
||||||
dropdown-icon="la la-angle-down la-sm"
|
dropdown-icon="la la-angle-down la-sm"
|
||||||
outlined dense emit-value map-options hide-selected display-value-sanitize options-sanitize
|
outlined dense emit-value map-options hide-selected display-value-sanitize options-sanitize
|
||||||
>
|
>
|
||||||
@@ -76,8 +86,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="q-mx-md q-mt-md">
|
<div class="q-mx-md q-mt-md">
|
||||||
<q-input class="col q-mr-sm" outlined dense bg-color="white" v-model="bookmarkDesc"
|
<q-input class="col q-mr-sm" ref="bookmarkDesc" outlined dense bg-color="white" v-model="bookmarkDesc" @keydown="bookmarkDescKeyDown"
|
||||||
placeholder="Описание" style="width: 400px" maxlength="100" @focus="onInputFocus">
|
placeholder="Описание" style="width: 400px" maxlength="100" @focus="selectAllOnFocus">
|
||||||
</q-input>
|
</q-input>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -87,6 +97,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
|
<BookmarkSettings v-if="bookmarkSettingsActive" ref="bookmarkSettings" :libs="libs" @close="closeBookmarkSettings"></BookmarkSettings>
|
||||||
</Window>
|
</Window>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -98,6 +109,8 @@ import _ from 'lodash';
|
|||||||
|
|
||||||
import Window from '../share/Window.vue';
|
import Window from '../share/Window.vue';
|
||||||
import Dialog from '../share/Dialog.vue';
|
import Dialog from '../share/Dialog.vue';
|
||||||
|
import BookmarkSettings from './BookmarkSettings/BookmarkSettings.vue';
|
||||||
|
|
||||||
import rstore from '../../store/modules/reader';
|
import rstore from '../../store/modules/reader';
|
||||||
import * as utils from '../../share/utils';
|
import * as utils from '../../share/utils';
|
||||||
|
|
||||||
@@ -108,7 +121,8 @@ const proxySubst = {
|
|||||||
export default @Component({
|
export default @Component({
|
||||||
components: {
|
components: {
|
||||||
Window,
|
Window,
|
||||||
Dialog
|
Dialog,
|
||||||
|
BookmarkSettings
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
libs: function() {
|
libs: function() {
|
||||||
@@ -137,19 +151,49 @@ class ExternalLibs extends Vue {
|
|||||||
libs = {};
|
libs = {};
|
||||||
fullScreenActive = false;
|
fullScreenActive = false;
|
||||||
addBookmarkVisible = false;
|
addBookmarkVisible = false;
|
||||||
|
transparentLayoutVisible = false;
|
||||||
|
|
||||||
bookmarkLink = '';
|
bookmarkLink = '';
|
||||||
bookmarkDesc = '';
|
bookmarkDesc = '';
|
||||||
defaultRootLink = '';
|
defaultRootLink = '';
|
||||||
|
|
||||||
|
bookmarkSettingsActive = false;
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.$root.addKeyHook(this.keyHook);
|
this.$root.addKeyHook(this.keyHook);
|
||||||
|
|
||||||
|
document.addEventListener('fullscreenchange', () => {
|
||||||
|
this.fullScreenActive = (document.fullscreenElement !== null);
|
||||||
|
});
|
||||||
|
|
||||||
//this.commit = this.$store.commit;
|
//this.commit = this.$store.commit;
|
||||||
//this.commit('reader/setLibs', rstore.libsDefaults);
|
//this.commit('reader/setLibs', rstore.libsDefaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
|
//Поправка метода toggleOption компонента select фреймворка quasar, необходимо другое поведение
|
||||||
|
//$emit('input'.. вызывается всегда
|
||||||
|
this.toggleOption = function(opt, keepOpen) {
|
||||||
|
if (this.editable !== true || opt === void 0 || this.isOptionDisabled(opt) === true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const optValue = this.getOptionValue(opt);
|
||||||
|
|
||||||
|
if (this.multiple !== true) {
|
||||||
|
if (keepOpen !== true) {
|
||||||
|
this.updateInputValue(this.fillInput === true ? this.getOptionLabel(opt) : '', true, true);
|
||||||
|
this.hidePopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$refs.target !== void 0 && this.$refs.target.focus();
|
||||||
|
this.$emit('input', this.emitValue === true ? optValue : opt);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$refs.rootLink.toggleOption = this.toggleOption;
|
||||||
|
this.$refs.selectedLink.toggleOption = this.toggleOption;
|
||||||
|
|
||||||
(async() => {
|
(async() => {
|
||||||
//подождем this.mode
|
//подождем this.mode
|
||||||
let i = 0;
|
let i = 0;
|
||||||
@@ -320,8 +364,9 @@ class ExternalLibs extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openBookUrlInFrame() {
|
openBookUrlInFrame() {
|
||||||
if (this.bookUrl)
|
if (this.bookUrl) {
|
||||||
this.goToLink(this.addProtocol(this.bookUrl));
|
this.goToLink(this.addProtocol(this.bookUrl));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
goToLink(link) {
|
goToLink(link) {
|
||||||
@@ -332,6 +377,9 @@ class ExternalLibs extends Vue {
|
|||||||
this.frameVisible = false;
|
this.frameVisible = false;
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.frameVisible = true;
|
this.frameVisible = true;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.frame.contentWindow.focus();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,11 +440,20 @@ class ExternalLibs extends Vue {
|
|||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
onInputFocus(event) {
|
selectAllOnFocus(event) {
|
||||||
if (event.target.select)
|
if (event.target.select)
|
||||||
event.target.select();
|
event.target.select();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rootLinkInput() {
|
||||||
|
this.updateSelectedLink();
|
||||||
|
this.updateStartLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedLinkInput() {
|
||||||
|
this.updateStartLink();
|
||||||
|
}
|
||||||
|
|
||||||
submitUrl() {
|
submitUrl() {
|
||||||
if (this.bookUrl) {
|
if (this.bookUrl) {
|
||||||
this.sendMessage({type: 'submitUrl', data: {
|
this.sendMessage({type: 'submitUrl', data: {
|
||||||
@@ -415,6 +472,7 @@ class ExternalLibs extends Vue {
|
|||||||
this.addBookmarkVisible = true;
|
this.addBookmarkVisible = true;
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.$refs.bookmarkLink.focus();
|
this.$refs.bookmarkLink.focus();
|
||||||
|
this.$refs.defaultRootLink.toggleOption = this.toggleOption;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,7 +487,28 @@ class ExternalLibs extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defaultRootLinkInput() {
|
||||||
|
this.updateBookmarkLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
bookmarkLinkKeyDown(event) {
|
||||||
|
if (event.key == 'Enter') {
|
||||||
|
this.$refs.bookmarkDesc.focus();
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bookmarkDescKeyDown(event) {
|
||||||
|
if (event.key == 'Enter') {
|
||||||
|
this.okAddBookmark();
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async okAddBookmark() {
|
async okAddBookmark() {
|
||||||
|
if (!this.bookmarkLink)
|
||||||
|
return;
|
||||||
|
|
||||||
const link = this.addProtocol(this.bookmarkLink);
|
const link = this.addProtocol(this.bookmarkLink);
|
||||||
let index = -1;
|
let index = -1;
|
||||||
try {
|
try {
|
||||||
@@ -476,9 +555,6 @@ class ExternalLibs extends Vue {
|
|||||||
this.addBookmarkVisible = false;
|
this.addBookmarkVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bookmarkSettings() {
|
|
||||||
}
|
|
||||||
|
|
||||||
fullScreenToggle() {
|
fullScreenToggle() {
|
||||||
this.fullScreenActive = !this.fullScreenActive;
|
this.fullScreenActive = !this.fullScreenActive;
|
||||||
if (this.fullScreenActive) {
|
if (this.fullScreenActive) {
|
||||||
@@ -488,26 +564,60 @@ class ExternalLibs extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transparentLayoutClick() {
|
||||||
|
this.transparentLayoutVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelectPopupShow() {
|
||||||
|
this.transparentLayoutVisible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelectPopupHide() {
|
||||||
|
this.transparentLayoutVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
this.sendMessage({type: 'close'});
|
this.sendMessage({type: 'close'});
|
||||||
}
|
}
|
||||||
|
|
||||||
keyHook() {
|
bookUrlKeyDown(event) {
|
||||||
|
if (event.key == 'Enter') {
|
||||||
|
this.submitUrl();
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bookmarkSettings() {
|
||||||
|
this.bookmarkSettingsActive = true;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.bookmarkSettings.init();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
closeBookmarkSettings() {
|
||||||
|
this.bookmarkSettingsActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
keyHook(event) {
|
||||||
if (this.$root.rootRoute() == '/external-libs') {
|
if (this.$root.rootRoute() == '/external-libs') {
|
||||||
|
if (this.bookmarkSettingsActive && this.$refs.bookmarkSettings.keyHook(event))
|
||||||
|
return true;
|
||||||
|
|
||||||
if (this.$refs.dialogAddBookmark.active)
|
if (this.$refs.dialogAddBookmark.active)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//недостатки сторонних ui
|
if (event.type == 'keydown' && event.key == 'F4') {
|
||||||
const input = this.$refs.input.$refs.input;
|
this.addBookmark();
|
||||||
if (document.activeElement === input && event.type == 'keydown' && event.key == 'Enter') {
|
|
||||||
this.submitUrl();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type == 'keydown' && event.key == 'Escape') {
|
if (event.type == 'keydown' && event.key == 'Escape' &&
|
||||||
|
(document.activeElement != this.$refs.rootLink.$refs.target || !this.$refs.rootLink.menu) &&
|
||||||
|
(document.activeElement != this.$refs.selectedLink.$refs.target || !this.$refs.selectedLink.menu)
|
||||||
|
) {
|
||||||
this.close();
|
this.close();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -532,4 +642,9 @@ class ExternalLibs extends Vue {
|
|||||||
background-color: #69C05F;
|
background-color: #69C05F;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.transparent-layout {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="main" class="column no-wrap" style="min-height: 500px">
|
<div ref="main" class="column no-wrap" style="min-height: 500px">
|
||||||
<div class="relative-position">
|
<div v-if="mode != 'liberama.top'" class="relative-position">
|
||||||
<GithubCorner url="https://github.com/bookpauk/liberama" cornerColor="#1B695F" gitColor="#EBE2C9"></GithubCorner>
|
<GithubCorner url="https://github.com/bookpauk/liberama" cornerColor="#1B695F" gitColor="#EBE2C9"></GithubCorner>
|
||||||
</div>
|
</div>
|
||||||
<div class="col column justify-center items-center no-wrap overflow-hidden" style="min-height: 230px">
|
<div class="col column justify-center items-center no-wrap overflow-hidden" style="min-height: 230px">
|
||||||
|
|||||||
@@ -39,6 +39,10 @@
|
|||||||
<q-icon name="la la-copy" size="32px"/>
|
<q-icon name="la la-copy" size="32px"/>
|
||||||
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">{{ rstore.readerActions['copyText'] }}</q-tooltip>
|
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">{{ rstore.readerActions['copyText'] }}</q-tooltip>
|
||||||
</button>
|
</button>
|
||||||
|
<button ref="splitToPara" v-show="showToolButton['splitToPara']" class="tool-button" :class="buttonActiveClass('splitToPara')" @click="buttonClick('splitToPara')" v-ripple>
|
||||||
|
<q-icon name="la la-retweet" size="32px"/>
|
||||||
|
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">{{ rstore.readerActions['splitToPara'] }}</q-tooltip>
|
||||||
|
</button>
|
||||||
<button ref="refresh" v-show="showToolButton['refresh']" class="tool-button" :class="buttonActiveClass('refresh')" @click="buttonClick('refresh')" v-ripple>
|
<button ref="refresh" v-show="showToolButton['refresh']" class="tool-button" :class="buttonActiveClass('refresh')" @click="buttonClick('refresh')" v-ripple>
|
||||||
<q-icon name="la la-sync" size="32px" :class="{clear: !showRefreshIcon}"/>
|
<q-icon name="la la-sync" size="32px" :class="{clear: !showRefreshIcon}"/>
|
||||||
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">{{ rstore.readerActions['refresh'] }}</q-tooltip>
|
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">{{ rstore.readerActions['refresh'] }}</q-tooltip>
|
||||||
@@ -327,6 +331,12 @@ class Reader extends Vue {
|
|||||||
this.checkActivateDonateHelpPage();
|
this.checkActivateDonateHelpPage();
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
|
|
||||||
|
//проверим состояние Settings, и обновим, если надо
|
||||||
|
const newSettings = rstore.addDefaultsToSettings(this.settings);
|
||||||
|
if (newSettings) {
|
||||||
|
this.commit('reader/setSettings', newSettings);
|
||||||
|
}
|
||||||
|
|
||||||
this.updateRoute();
|
this.updateRoute();
|
||||||
|
|
||||||
await this.showWhatsNew();
|
await this.showWhatsNew();
|
||||||
@@ -699,6 +709,12 @@ class Reader extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refreshBookSplitToPara() {
|
||||||
|
if (this.mostRecentBook()) {
|
||||||
|
this.loadBook({url: this.mostRecentBook().url, skipCheck: true, isText: true, force: true});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
recentBooksClose() {
|
recentBooksClose() {
|
||||||
this.recentBooksActive = false;
|
this.recentBooksActive = false;
|
||||||
}
|
}
|
||||||
@@ -816,6 +832,7 @@ class Reader extends Vue {
|
|||||||
case 'scrolling':
|
case 'scrolling':
|
||||||
case 'search':
|
case 'search':
|
||||||
case 'copyText':
|
case 'copyText':
|
||||||
|
case 'splitToPara':
|
||||||
case 'refresh':
|
case 'refresh':
|
||||||
case 'libs':
|
case 'libs':
|
||||||
case 'recentBooks':
|
case 'recentBooks':
|
||||||
@@ -847,8 +864,9 @@ class Reader extends Vue {
|
|||||||
case 'copyText':
|
case 'copyText':
|
||||||
classResult = classDisabled;
|
classResult = classDisabled;
|
||||||
break;
|
break;
|
||||||
case 'recentBooks':
|
case 'splitToPara':
|
||||||
case 'refresh':
|
case 'refresh':
|
||||||
|
case 'recentBooks':
|
||||||
if (!this.mostRecentBookReactive)
|
if (!this.mostRecentBookReactive)
|
||||||
classResult = classDisabled;
|
classResult = classDisabled;
|
||||||
break;
|
break;
|
||||||
@@ -1001,9 +1019,16 @@ class Reader extends Vue {
|
|||||||
// не удалось, скачиваем книгу полностью с конвертацией
|
// не удалось, скачиваем книгу полностью с конвертацией
|
||||||
let loadCached = true;
|
let loadCached = true;
|
||||||
if (!book) {
|
if (!book) {
|
||||||
book = await readerApi.loadBook({url, enableSitesFilter: this.enableSitesFilter}, (state) => {
|
book = await readerApi.loadBook({
|
||||||
progress.setState(state);
|
url,
|
||||||
});
|
skipCheck: (opts.skipCheck ? true : false),
|
||||||
|
isText: (opts.isText ? true : false),
|
||||||
|
enableSitesFilter: this.enableSitesFilter
|
||||||
|
},
|
||||||
|
(state) => {
|
||||||
|
progress.setState(state);
|
||||||
|
}
|
||||||
|
);
|
||||||
loadCached = false;
|
loadCached = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1122,6 +1147,9 @@ class Reader extends Vue {
|
|||||||
case 'copyText':
|
case 'copyText':
|
||||||
this.copyTextToggle();
|
this.copyTextToggle();
|
||||||
break;
|
break;
|
||||||
|
case 'splitToPara':
|
||||||
|
this.refreshBookSplitToPara();
|
||||||
|
break;
|
||||||
case 'refresh':
|
case 'refresh':
|
||||||
this.refreshBook();
|
this.refreshBook();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -69,15 +69,15 @@ class ServerStorage extends Vue {
|
|||||||
try {
|
try {
|
||||||
this.cachedRecent = await ssCacheStore.getItem('recent');
|
this.cachedRecent = await ssCacheStore.getItem('recent');
|
||||||
if (!this.cachedRecent)
|
if (!this.cachedRecent)
|
||||||
await this.setCachedRecent({rev: 0, data: {}});
|
await this.cleanCachedRecent('cachedRecent');
|
||||||
|
|
||||||
this.cachedRecentPatch = await ssCacheStore.getItem('recent-patch');
|
this.cachedRecentPatch = await ssCacheStore.getItem('recent-patch');
|
||||||
if (!this.cachedRecentPatch)
|
if (!this.cachedRecentPatch)
|
||||||
await this.setCachedRecentPatch({rev: 0, data: {}});
|
await this.cleanCachedRecent('cachedRecentPatch');
|
||||||
|
|
||||||
this.cachedRecentMod = await ssCacheStore.getItem('recent-mod');
|
this.cachedRecentMod = await ssCacheStore.getItem('recent-mod');
|
||||||
if (!this.cachedRecentMod)
|
if (!this.cachedRecentMod)
|
||||||
await this.setCachedRecentMod({rev: 0, data: {}});
|
await this.cleanCachedRecent('cachedRecentMod');
|
||||||
|
|
||||||
if (!this.serverStorageKey) {
|
if (!this.serverStorageKey) {
|
||||||
//генерируем новый ключ
|
//генерируем новый ключ
|
||||||
@@ -105,6 +105,15 @@ class ServerStorage extends Vue {
|
|||||||
this.cachedRecentMod = value;
|
this.cachedRecentMod = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async cleanCachedRecent(whatToClean) {
|
||||||
|
if (whatToClean == 'cachedRecent' || whatToClean == 'all')
|
||||||
|
await this.setCachedRecent({rev: 0, data: {}});
|
||||||
|
if (whatToClean == 'cachedRecentPatch' || whatToClean == 'all')
|
||||||
|
await this.setCachedRecentPatch({rev: 0, data: {}});
|
||||||
|
if (whatToClean == 'cachedRecentMod' || whatToClean == 'all')
|
||||||
|
await this.setCachedRecentMod({rev: 0, data: {}});
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
@@ -134,9 +143,12 @@ class ServerStorage extends Vue {
|
|||||||
await this.currentProfileChanged(force);
|
await this.currentProfileChanged(force);
|
||||||
await this.loadLibs(force);
|
await this.loadLibs(force);
|
||||||
|
|
||||||
|
if (force)
|
||||||
|
await this.cleanCachedRecent('all');
|
||||||
const loadSuccess = await this.loadRecent();
|
const loadSuccess = await this.loadRecent();
|
||||||
if (loadSuccess && force)
|
if (loadSuccess && force) {
|
||||||
await this.saveRecent();
|
await this.saveRecent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,7 +505,7 @@ class ServerStorage extends Vue {
|
|||||||
|
|
||||||
const md = newRecentMod.data;
|
const md = newRecentMod.data;
|
||||||
if (md.key && result[md.key])
|
if (md.key && result[md.key])
|
||||||
result[md.key] = utils.applyObjDiff(result[md.key], md.mod, true);
|
result[md.key] = utils.applyObjDiff(result[md.key], md.mod, {isAddChanged: true});
|
||||||
|
|
||||||
if (!bookManager.loaded) {
|
if (!bookManager.loaded) {
|
||||||
this.warning('Ожидание загрузки списка книг перед синхронизацией');
|
this.warning('Ожидание загрузки списка книг перед синхронизацией');
|
||||||
@@ -557,7 +569,7 @@ class ServerStorage extends Vue {
|
|||||||
|
|
||||||
let applyMod = this.cachedRecentMod.data;
|
let applyMod = this.cachedRecentMod.data;
|
||||||
if (applyMod && applyMod.key && newRecentPatch.data[applyMod.key])
|
if (applyMod && applyMod.key && newRecentPatch.data[applyMod.key])
|
||||||
newRecentPatch.data[applyMod.key] = utils.applyObjDiff(newRecentPatch.data[applyMod.key], applyMod.mod, true);
|
newRecentPatch.data[applyMod.key] = utils.applyObjDiff(newRecentPatch.data[applyMod.key], applyMod.mod, {isAddChanged: true});
|
||||||
|
|
||||||
newRecentMod = {rev: this.cachedRecentMod.rev + 1, data: {}};
|
newRecentMod = {rev: this.cachedRecentMod.rev + 1, data: {}};
|
||||||
needSaveRecentPatch = true;
|
needSaveRecentPatch = true;
|
||||||
|
|||||||
@@ -108,8 +108,10 @@ export default @Component({
|
|||||||
},
|
},
|
||||||
vertShift: function(newValue) {
|
vertShift: function(newValue) {
|
||||||
const font = (this.webFontName ? this.webFontName : this.fontName);
|
const font = (this.webFontName ? this.webFontName : this.fontName);
|
||||||
this.fontShifts = Object.assign({}, this.fontShifts, {[font]: newValue});
|
if (this.fontShifts[font] != newValue) {
|
||||||
this.fontVertShift = newValue;
|
this.fontShifts = Object.assign({}, this.fontShifts, {[font]: newValue});
|
||||||
|
this.fontVertShift = newValue;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
fontName: function(newValue) {
|
fontName: function(newValue) {
|
||||||
const font = (this.webFontName ? this.webFontName : newValue);
|
const font = (this.webFontName ? this.webFontName : newValue);
|
||||||
@@ -185,10 +187,18 @@ class SettingsPage extends Vue {
|
|||||||
settingsChanged() {
|
settingsChanged() {
|
||||||
if (_.isEqual(this.form, this.settings))
|
if (_.isEqual(this.form, this.settings))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.form = Object.assign({}, this.settings);
|
this.form = Object.assign({}, this.settings);
|
||||||
|
if (!this.unwatch)
|
||||||
|
this.unwatch = {};
|
||||||
|
|
||||||
for (let prop in rstore.settingDefaults) {
|
for (let prop in rstore.settingDefaults) {
|
||||||
|
if (this.unwatch && this.unwatch[prop])
|
||||||
|
this.unwatch[prop]();
|
||||||
|
|
||||||
this[prop] = this.form[prop];
|
this[prop] = this.form[prop];
|
||||||
this.$watch(prop, (newValue) => {
|
|
||||||
|
this.unwatch[prop] = this.$watch(prop, (newValue) => {
|
||||||
this.form = Object.assign({}, this.form, {[prop]: newValue});
|
this.form = Object.assign({}, this.form, {[prop]: newValue});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,16 @@
|
|||||||
export const versionHistory = [
|
export const versionHistory = [
|
||||||
|
{
|
||||||
|
showUntil: '2020-10-31',
|
||||||
|
header: '0.9.5 (2020-11-01)',
|
||||||
|
content:
|
||||||
|
`
|
||||||
|
<ul>
|
||||||
|
<li>на панель инструментов добавлена новая кнопка "Обновить с разбиением на параграфы"</li>
|
||||||
|
<li>исправления багов</li>
|
||||||
|
</ul>
|
||||||
|
`
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
showUntil: '2020-10-28',
|
showUntil: '2020-10-28',
|
||||||
header: '0.9.4 (2020-10-29)',
|
header: '0.9.4 (2020-10-29)',
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const DialogProps = Vue.extend({
|
|||||||
props: {
|
props: {
|
||||||
value: Boolean,
|
value: Boolean,
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
export default @Component({
|
export default @Component({
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="main" class="main xyfit absolute" @click="close" @mouseup="onMouseUp" @mousemove="onMouseMove">
|
<div ref="main" class="main xyfit absolute" @click="close" @mouseup="onMouseUp" @mousemove="onMouseMove">
|
||||||
<div ref="windowBox" class="xyfit absolute flex no-wrap" @click.stop>
|
<div ref="windowBox" class="xyfit absolute flex no-wrap" @click.stop>
|
||||||
<div class="window flexfit column no-wrap">
|
<div ref="window" class="window flexfit column no-wrap">
|
||||||
<div ref="header" class="header row justify-end" @mousedown.prevent.stop="onMouseDown"
|
<div ref="header" class="header row justify-end" @mousedown.prevent.stop="onMouseDown"
|
||||||
@touchstart.stop="onTouchStart" @touchend.stop="onTouchEnd" @touchmove.stop="onTouchMove">
|
@touchstart.stop="onTouchStart" @touchend.stop="onTouchEnd" @touchmove.stop="onTouchMove">
|
||||||
<span class="header-text col"><slot name="header"></slot></span>
|
<span class="header-text col"><slot name="header"></slot></span>
|
||||||
@@ -26,6 +26,7 @@ export default @Component({
|
|||||||
width: { type: String, default: '100%' },
|
width: { type: String, default: '100%' },
|
||||||
maxWidth: { type: String, default: '' },
|
maxWidth: { type: String, default: '' },
|
||||||
topShift: { type: Number, default: 0 },
|
topShift: { type: Number, default: 0 },
|
||||||
|
margin: '',
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
class Window extends Vue {
|
class Window extends Vue {
|
||||||
@@ -40,6 +41,9 @@ class Window extends Vue {
|
|||||||
const top = (this.$refs.main.offsetHeight - this.$refs.windowBox.offsetHeight)/2 + this.topShift;
|
const top = (this.$refs.main.offsetHeight - this.$refs.windowBox.offsetHeight)/2 + this.topShift;
|
||||||
this.$refs.windowBox.style.left = (left > 0 ? left : 0) + 'px';
|
this.$refs.windowBox.style.left = (left > 0 ? left : 0) + 'px';
|
||||||
this.$refs.windowBox.style.top = (top > 0 ? top : 0) + 'px';
|
this.$refs.windowBox.style.top = (top > 0 ? top : 0) + 'px';
|
||||||
|
|
||||||
|
if (this.margin)
|
||||||
|
this.$refs.window.style.margin = this.margin;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,6 +124,7 @@ class Window extends Vue {
|
|||||||
.main {
|
.main {
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
z-index: 50;
|
z-index: 50;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.xyfit {
|
.xyfit {
|
||||||
|
|||||||
@@ -130,20 +130,53 @@ export function getObjDiff(oldObj, newObj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function isObjDiff(diff) {
|
export function isObjDiff(diff) {
|
||||||
return (_.isObject(diff) && diff.__isDiff);
|
return (_.isObject(diff) && diff.__isDiff && diff.change && diff.add && diff.del);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isEmptyObjDiff(diff) {
|
export function isEmptyObjDiff(diff) {
|
||||||
return (!_.isObject(diff) || !diff.__isDiff ||
|
return (!isObjDiff(diff) ||
|
||||||
(!Object.keys(diff.change).length &&
|
!(Object.keys(diff.change).length ||
|
||||||
!Object.keys(diff.add).length &&
|
Object.keys(diff.add).length ||
|
||||||
!diff.del.length
|
diff.del.length
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyObjDiff(obj, diff, isAddChanged) {
|
export function isEmptyObjDiffDeep(diff, opts = {}) {
|
||||||
const result = _.cloneDeep(obj);
|
if (!isObjDiff(diff))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const {
|
||||||
|
isApplyChange = true,
|
||||||
|
isApplyAdd = true,
|
||||||
|
isApplyDel = true,
|
||||||
|
} = opts;
|
||||||
|
|
||||||
|
let notEmptyDeep = false;
|
||||||
|
const change = diff.change;
|
||||||
|
for (const key of Object.keys(change)) {
|
||||||
|
if (_.isObject(change[key]))
|
||||||
|
notEmptyDeep |= !isEmptyObjDiffDeep(change[key], opts);
|
||||||
|
else if (isApplyChange)
|
||||||
|
notEmptyDeep = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !(
|
||||||
|
notEmptyDeep ||
|
||||||
|
(isApplyAdd && Object.keys(diff.add).length) ||
|
||||||
|
(isApplyDel && diff.del.length)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyObjDiff(obj, diff, opts = {}) {
|
||||||
|
const {
|
||||||
|
isAddChanged = false,
|
||||||
|
isApplyChange = true,
|
||||||
|
isApplyAdd = true,
|
||||||
|
isApplyDel = true,
|
||||||
|
} = opts;
|
||||||
|
|
||||||
|
let result = _.cloneDeep(obj);
|
||||||
if (!diff.__isDiff)
|
if (!diff.__isDiff)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
@@ -151,21 +184,28 @@ export function applyObjDiff(obj, diff, isAddChanged) {
|
|||||||
for (const key of Object.keys(change)) {
|
for (const key of Object.keys(change)) {
|
||||||
if (result.hasOwnProperty(key)) {
|
if (result.hasOwnProperty(key)) {
|
||||||
if (_.isObject(change[key])) {
|
if (_.isObject(change[key])) {
|
||||||
result[key] = applyObjDiff(result[key], change[key], isAddChanged);
|
result[key] = applyObjDiff(result[key], change[key], opts);
|
||||||
} else {
|
} else {
|
||||||
result[key] = _.cloneDeep(change[key]);
|
if (isApplyChange)
|
||||||
|
result[key] = _.cloneDeep(change[key]);
|
||||||
}
|
}
|
||||||
} else if (isAddChanged) {
|
} else if (isAddChanged) {
|
||||||
result[key] = _.cloneDeep(change[key]);
|
result[key] = _.cloneDeep(change[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const key of Object.keys(diff.add)) {
|
if (isApplyAdd) {
|
||||||
result[key] = _.cloneDeep(diff.add[key]);
|
for (const key of Object.keys(diff.add)) {
|
||||||
|
result[key] = _.cloneDeep(diff.add[key]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const key of diff.del) {
|
if (isApplyDel && diff.del.length) {
|
||||||
delete result[key];
|
for (const key of diff.del) {
|
||||||
|
delete result[key];
|
||||||
|
}
|
||||||
|
if (_.isArray(result))
|
||||||
|
result = result.filter(v => v);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import * as utils from '../../share/utils';
|
||||||
|
|
||||||
const readerActions = {
|
const readerActions = {
|
||||||
'help': 'Вызвать cправку',
|
'help': 'Вызвать cправку',
|
||||||
'loader': 'На страницу загрузки',
|
'loader': 'На страницу загрузки',
|
||||||
@@ -10,6 +12,7 @@ const readerActions = {
|
|||||||
'setPosition': 'Установить позицию',
|
'setPosition': 'Установить позицию',
|
||||||
'search': 'Найти в тексте',
|
'search': 'Найти в тексте',
|
||||||
'copyText': 'Скопировать текст со страницы',
|
'copyText': 'Скопировать текст со страницы',
|
||||||
|
'splitToPara': 'Обновить с разбиением на параграфы',
|
||||||
'refresh': 'Принудительно обновить книгу',
|
'refresh': 'Принудительно обновить книгу',
|
||||||
'offlineMode': 'Автономный режим (без интернета)',
|
'offlineMode': 'Автономный режим (без интернета)',
|
||||||
'libs': 'Библиотека',
|
'libs': 'Библиотека',
|
||||||
@@ -37,6 +40,7 @@ const toolButtons = [
|
|||||||
{name: 'setPosition', show: true},
|
{name: 'setPosition', show: true},
|
||||||
{name: 'search', show: true},
|
{name: 'search', show: true},
|
||||||
{name: 'copyText', show: false},
|
{name: 'copyText', show: false},
|
||||||
|
{name: 'splitToPara', show: false},
|
||||||
{name: 'refresh', show: true},
|
{name: 'refresh', show: true},
|
||||||
{name: 'libs', show: true},
|
{name: 'libs', show: true},
|
||||||
{name: 'recentBooks', show: true},
|
{name: 'recentBooks', show: true},
|
||||||
@@ -55,6 +59,7 @@ const hotKeys = [
|
|||||||
{name: 'setPosition', codes: ['P']},
|
{name: 'setPosition', codes: ['P']},
|
||||||
{name: 'search', codes: ['Ctrl+F']},
|
{name: 'search', codes: ['Ctrl+F']},
|
||||||
{name: 'copyText', codes: ['Ctrl+C']},
|
{name: 'copyText', codes: ['Ctrl+C']},
|
||||||
|
{name: 'splitToPara', codes: ['Shift+R']},
|
||||||
{name: 'refresh', codes: ['R']},
|
{name: 'refresh', codes: ['R']},
|
||||||
{name: 'offlineMode', codes: ['O']},
|
{name: 'offlineMode', codes: ['O']},
|
||||||
{name: 'libs', codes: ['L']},
|
{name: 'libs', codes: ['L']},
|
||||||
@@ -253,6 +258,25 @@ const settingDefaults = {
|
|||||||
userHotKeys: {},
|
userHotKeys: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for (const font of fonts)
|
||||||
|
settingDefaults.fontShifts[font.name] = font.fontVertShift;
|
||||||
|
for (const font of webFonts)
|
||||||
|
settingDefaults.fontShifts[font.name] = font.fontVertShift;
|
||||||
|
for (const button of toolButtons)
|
||||||
|
settingDefaults.showToolButton[button.name] = button.show;
|
||||||
|
for (const hotKey of hotKeys)
|
||||||
|
settingDefaults.userHotKeys[hotKey.name] = hotKey.codes;
|
||||||
|
|
||||||
|
function addDefaultsToSettings(settings) {
|
||||||
|
const diff = utils.getObjDiff(settings, settingDefaults);
|
||||||
|
|
||||||
|
if (!utils.isEmptyObjDiffDeep(diff, {isApplyChange: false})) {
|
||||||
|
return utils.applyObjDiff(settings, diff, {isApplyChange: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const libsDefaults = {
|
const libsDefaults = {
|
||||||
startLink: 'http://flibusta.is',
|
startLink: 'http://flibusta.is',
|
||||||
comment: 'Флибуста | Книжное братство',
|
comment: 'Флибуста | Книжное братство',
|
||||||
@@ -276,15 +300,6 @@ const libsDefaults = {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const font of fonts)
|
|
||||||
settingDefaults.fontShifts[font.name] = font.fontVertShift;
|
|
||||||
for (const font of webFonts)
|
|
||||||
settingDefaults.fontShifts[font.name] = font.fontVertShift;
|
|
||||||
for (const button of toolButtons)
|
|
||||||
settingDefaults.showToolButton[button.name] = button.show;
|
|
||||||
for (const hotKey of hotKeys)
|
|
||||||
settingDefaults.userHotKeys[hotKey.name] = hotKey.codes;
|
|
||||||
|
|
||||||
// initial state
|
// initial state
|
||||||
const state = {
|
const state = {
|
||||||
toolBarActive: true,
|
toolBarActive: true,
|
||||||
@@ -338,7 +353,13 @@ const mutations = {
|
|||||||
state.currentProfile = value;
|
state.currentProfile = value;
|
||||||
},
|
},
|
||||||
setSettings(state, value) {
|
setSettings(state, value) {
|
||||||
state.settings = Object.assign({}, state.settings, value);
|
const newSettings = Object.assign({}, state.settings, value);
|
||||||
|
const added = addDefaultsToSettings(newSettings);
|
||||||
|
if (added) {
|
||||||
|
state.settings = added;
|
||||||
|
} else {
|
||||||
|
state.settings = newSettings;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setSettingsRev(state, value) {
|
setSettingsRev(state, value) {
|
||||||
state.settingsRev = Object.assign({}, state.settingsRev, value);
|
state.settingsRev = Object.assign({}, state.settingsRev, value);
|
||||||
@@ -358,6 +379,7 @@ export default {
|
|||||||
fonts,
|
fonts,
|
||||||
webFonts,
|
webFonts,
|
||||||
settingDefaults,
|
settingDefaults,
|
||||||
|
addDefaultsToSettings,
|
||||||
libsDefaults,
|
libsDefaults,
|
||||||
|
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
|
|||||||
85
docs/beta/beta.liberama
Normal file
85
docs/beta/beta.liberama
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
server {
|
||||||
|
listen 443 ssl; # managed by Certbot
|
||||||
|
ssl_certificate /etc/letsencrypt/live/beta.liberama.top/fullchain.pem; # managed by Certbot
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/beta.liberama.top/privkey.pem; # managed by Certbot
|
||||||
|
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||||
|
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||||
|
|
||||||
|
server_name beta.liberama.top;
|
||||||
|
|
||||||
|
client_max_body_size 50m;
|
||||||
|
proxy_read_timeout 1h;
|
||||||
|
|
||||||
|
gzip on;
|
||||||
|
gzip_min_length 1024;
|
||||||
|
gzip_proxied expired no-cache no-store private auth;
|
||||||
|
gzip_types *;
|
||||||
|
|
||||||
|
location /api {
|
||||||
|
proxy_pass http://127.0.0.1:34082;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /ws {
|
||||||
|
proxy_pass http://127.0.0.1:34082;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
root /home/beta.liberama/public;
|
||||||
|
|
||||||
|
location /tmp {
|
||||||
|
types { } default_type "application/xml; charset=utf-8";
|
||||||
|
add_header Content-Encoding gzip;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~* \.(?:manifest|appcache|html)$ {
|
||||||
|
expires -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name beta.liberama.top;
|
||||||
|
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name b.beta.liberama.top;
|
||||||
|
|
||||||
|
client_max_body_size 50m;
|
||||||
|
proxy_read_timeout 1h;
|
||||||
|
|
||||||
|
gzip on;
|
||||||
|
gzip_min_length 1024;
|
||||||
|
gzip_proxied expired no-cache no-store private auth;
|
||||||
|
gzip_types *;
|
||||||
|
|
||||||
|
location /api {
|
||||||
|
proxy_pass http://127.0.0.1:34082;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /ws {
|
||||||
|
proxy_pass http://127.0.0.1:34082;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
root /home/beta.liberama/public;
|
||||||
|
|
||||||
|
location /tmp {
|
||||||
|
types { } default_type "application/xml; charset=utf-8";
|
||||||
|
add_header Content-Encoding gzip;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~* \.(?:manifest|appcache|html)$ {
|
||||||
|
expires -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -64,7 +64,7 @@ sudo -u www-data cp -r docs/omnireader.ru/old/* /home/oldreader
|
|||||||
|
|
||||||
## Запуск по крону
|
## Запуск по крону
|
||||||
```
|
```
|
||||||
* * * * * /root/liberama/docs/omnireader/cron_server.sh
|
* * * * * /root/liberama/docs/omnireader.ru/cron_server.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
## Деплой и запуск
|
## Деплой и запуск
|
||||||
|
|||||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Liberama",
|
"name": "Liberama",
|
||||||
"version": "0.9.4",
|
"version": "0.9.5",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Liberama",
|
"name": "Liberama",
|
||||||
"version": "0.9.4",
|
"version": "0.9.5",
|
||||||
"author": "Book Pauk <bookpauk@gmail.com>",
|
"author": "Book Pauk <bookpauk@gmail.com>",
|
||||||
"license": "CC0-1.0",
|
"license": "CC0-1.0",
|
||||||
"repository": "bookpauk/liberama",
|
"repository": "bookpauk/liberama",
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ class ReaderController extends BaseController {
|
|||||||
throw new Error(`key 'url' is empty`);
|
throw new Error(`key 'url' is empty`);
|
||||||
const workerId = this.readerWorker.loadBookUrl({
|
const workerId = this.readerWorker.loadBookUrl({
|
||||||
url: request.url,
|
url: request.url,
|
||||||
enableSitesFilter: (request.hasOwnProperty('enableSitesFilter') ? request.enableSitesFilter : true)
|
enableSitesFilter: (request.hasOwnProperty('enableSitesFilter') ? request.enableSitesFilter : true),
|
||||||
|
skipCheck: (request.hasOwnProperty('skipCheck') ? request.skipCheck : false),
|
||||||
|
isText: (request.hasOwnProperty('isText') ? request.isText : false),
|
||||||
});
|
});
|
||||||
const state = this.workerState.getState(workerId);
|
const state = this.workerState.getState(workerId);
|
||||||
return (state ? state : {});
|
return (state ? state : {});
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ class ConvertHtml extends ConvertBase {
|
|||||||
|
|
||||||
titleInfo['book-title'] = title;
|
titleInfo['book-title'] = title;
|
||||||
//подозрение на чистый текст, надо разбить на параграфы
|
//подозрение на чистый текст, надо разбить на параграфы
|
||||||
if (isText || pars.length < buf.length/2000) {
|
if (isText || (buf.length > 30*1024 && pars.length < buf.length/2000)) {
|
||||||
let total = 0;
|
let total = 0;
|
||||||
let count = 1;
|
let count = 1;
|
||||||
for (let i = 0; i < spaceCounter.length; i++) {
|
for (let i = 0; i < spaceCounter.length; i++) {
|
||||||
|
|||||||
Reference in New Issue
Block a user