Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
510553b055 | ||
|
|
6c4616892e | ||
|
|
1e79a099b8 | ||
|
|
31a22327f1 | ||
|
|
c1712bebc6 | ||
|
|
cd91541245 | ||
|
|
4c1fc83256 | ||
|
|
34c7a33576 | ||
|
|
23ecfeeb4f | ||
|
|
9703f83eb3 | ||
|
|
0f3cc03d00 | ||
|
|
6f7ba1f9fc | ||
|
|
e1b85e4a1b | ||
|
|
b308dd58cc | ||
|
|
9f4c0479ce | ||
|
|
2c57817dde | ||
|
|
ba85c54d7c | ||
|
|
a80e5c3a65 | ||
|
|
22e2c34da8 | ||
|
|
00a8e4c2c5 | ||
|
|
10d0a4079c | ||
|
|
589f7f3c22 | ||
|
|
d1126a7eb0 | ||
|
|
9f4e72a0e1 | ||
|
|
a024295379 | ||
|
|
dc2b2ec488 | ||
|
|
0c5f5975aa | ||
|
|
dc3f682d2d | ||
|
|
2db8876c66 | ||
|
|
8f6201b0f7 | ||
|
|
4b146c70ad | ||
|
|
0118034b4b | ||
|
|
39217053ca | ||
|
|
fba190c826 | ||
|
|
5e9d528e16 | ||
|
|
c5921d88fc | ||
|
|
eb980b0ea1 | ||
|
|
de5b4216f7 | ||
|
|
495ff57b19 | ||
|
|
57948cf6e3 | ||
|
|
1aebbbcabd | ||
|
|
25b4cb072d | ||
|
|
1cdacc3a08 |
@@ -9,7 +9,7 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|||||||
const CleanWebpackPlugin = require('clean-webpack-plugin');
|
const CleanWebpackPlugin = require('clean-webpack-plugin');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
const AppCachePlugin = require('appcache-webpack-plugin');
|
const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');
|
||||||
|
|
||||||
const publicDir = path.resolve(__dirname, '../dist/tmp/public');
|
const publicDir = path.resolve(__dirname, '../dist/tmp/public');
|
||||||
const clientDir = path.resolve(__dirname, '../client');
|
const clientDir = path.resolve(__dirname, '../client');
|
||||||
@@ -55,6 +55,12 @@ module.exports = merge(baseWpConfig, {
|
|||||||
filename: `${publicDir}/index.html`
|
filename: `${publicDir}/index.html`
|
||||||
}),
|
}),
|
||||||
new CopyWebpackPlugin([{from: `${clientDir}/assets/*`, to: `${publicDir}/`, flatten: true}]),
|
new CopyWebpackPlugin([{from: `${clientDir}/assets/*`, to: `${publicDir}/`, flatten: true}]),
|
||||||
new AppCachePlugin({exclude: ['../index.html']})
|
new SWPrecacheWebpackPlugin({
|
||||||
|
cacheId: 'liberama',
|
||||||
|
filepath: `${publicDir}/service-worker.js`,
|
||||||
|
minify: true,
|
||||||
|
navigateFallback: '/index.html',
|
||||||
|
stripPrefix: publicDir,
|
||||||
|
}),
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|||||||
5
client/assets/sw-register.js
Normal file
5
client/assets/sw-register.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
(function() {
|
||||||
|
if('serviceWorker' in navigator) {
|
||||||
|
navigator.serviceWorker.register('/service-worker.js');
|
||||||
|
}
|
||||||
|
})();
|
||||||
@@ -91,7 +91,7 @@ class CopyTextPage extends Vue {
|
|||||||
|
|
||||||
close() {
|
close() {
|
||||||
this.stopInit = true;
|
this.stopInit = true;
|
||||||
this.$emit('copy-text-toggle');
|
this.$emit('do-action', {action: 'copyText'});
|
||||||
}
|
}
|
||||||
|
|
||||||
keyHook(event) {
|
keyHook(event) {
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ const pages = {
|
|||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
['CommonHelpPage', 'Общее'],
|
['CommonHelpPage', 'Общее'],
|
||||||
['HotkeysHelpPage', 'Клавиатура'],
|
|
||||||
['MouseHelpPage', 'Мышь/тачскрин'],
|
['MouseHelpPage', 'Мышь/тачскрин'],
|
||||||
|
['HotkeysHelpPage', 'Клавиатура'],
|
||||||
['VersionHistoryPage', 'История версий'],
|
['VersionHistoryPage', 'История версий'],
|
||||||
['DonateHelpPage', 'Помочь проекту'],
|
['DonateHelpPage', 'Помочь проекту'],
|
||||||
];
|
];
|
||||||
@@ -56,7 +56,7 @@ class HelpPage extends Vue {
|
|||||||
selectedTab = 'CommonHelpPage';
|
selectedTab = 'CommonHelpPage';
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
this.$emit('help-toggle');
|
this.$emit('do-action', {action: 'help'});
|
||||||
}
|
}
|
||||||
|
|
||||||
get activePage() {
|
get activePage() {
|
||||||
|
|||||||
@@ -1,28 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<span class="text-h6 text-bold">Управление с помощью горячих клавиш:</span>
|
<div style="font-size: 120%">
|
||||||
<ul>
|
<div class="text-h6 text-bold">Доступны следующие клавиатурные команды:</div>
|
||||||
<li><b>F1, H</b> - открыть справку</li>
|
<br>
|
||||||
<li><b>Escape</b> - показать/скрыть страницу загрузки</li>
|
</div>
|
||||||
<li><b>Tab, Q</b> - показать/скрыть панель управления</li>
|
<div class="q-mb-md" style="width: 550px">
|
||||||
<li><b>PageUp, Left, Shift+Space, Backspace</b> - страницу назад</li>
|
<div class="text-right text-italic" style="font-size: 80%">* Изменить сочетания клавиш можно в настройках</div>
|
||||||
<li><b>PageDown, Right, Space</b> - страницу вперед</li>
|
<UserHotKeys v-model="userHotKeys" readonly/>
|
||||||
<li><b>Home</b> - в начало книги</li>
|
</div>
|
||||||
<li><b>End</b> - в конец книги</li>
|
|
||||||
<li><b>Up</b> - строчку назад</li>
|
|
||||||
<li><b>Down</b> - строчку вперёд</li>
|
|
||||||
<li><b>A, Shift+A</b> - изменить размер шрифта</li>
|
|
||||||
<li><b>Enter, F, F11, ` (апостроф)</b> - вкл./выкл. полный экран</li>
|
|
||||||
<li><b>Z</b> - вкл./выкл. плавный скроллинг текста</li>
|
|
||||||
<li><b>Shift+Down/Shift+Up</b> - увеличить/уменьшить скорость скроллинга
|
|
||||||
<li><b>P</b> - установить страницу</li>
|
|
||||||
<li><b>Ctrl+F</b> - найти в тексте</li>
|
|
||||||
<li><b>Ctrl+C</b> - скопировать текст со страницы</li>
|
|
||||||
<li><b>R</b> - принудительно обновить книгу в обход кэша</li>
|
|
||||||
<li><b>X</b> - открыть недавние</li>
|
|
||||||
<li><b>O</b> - автономный режим</li>
|
|
||||||
<li><b>S</b> - открыть окно настроек</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -31,11 +16,25 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import Component from 'vue-class-component';
|
import Component from 'vue-class-component';
|
||||||
|
|
||||||
|
import UserHotKeys from '../../SettingsPage/UserHotKeys/UserHotKeys.vue';
|
||||||
|
|
||||||
export default @Component({
|
export default @Component({
|
||||||
|
components: {
|
||||||
|
UserHotKeys,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
class HotkeysHelpPage extends Vue {
|
class HotkeysHelpPage extends Vue {
|
||||||
created() {
|
created() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get userHotKeys() {
|
||||||
|
return this.$store.state.reader.settings.userHotKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
set userHotKeys(value) {
|
||||||
|
//no setter
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
</script>
|
</script>
|
||||||
@@ -44,7 +43,5 @@ class HotkeysHelpPage extends Vue {
|
|||||||
.page {
|
.page {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
font-size: 120%;
|
|
||||||
line-height: 130%;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -148,12 +148,12 @@ class LoaderPage extends Vue {
|
|||||||
this.pasteTextActive = !this.pasteTextActive;
|
this.pasteTextActive = !this.pasteTextActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
openHelp() {
|
openHelp(event) {
|
||||||
this.$emit('help-toggle');
|
this.$emit('do-action', {action: 'help', event});
|
||||||
}
|
}
|
||||||
|
|
||||||
openDonate() {
|
openDonate() {
|
||||||
this.$emit('donate-toggle');
|
this.$emit('do-action', {action: 'donate'});
|
||||||
}
|
}
|
||||||
|
|
||||||
openComments() {
|
openComments() {
|
||||||
@@ -173,21 +173,19 @@ class LoaderPage extends Vue {
|
|||||||
const input = this.$refs.input.$refs.input;
|
const input = this.$refs.input.$refs.input;
|
||||||
if (document.activeElement === input && event.type == 'keydown' && event.code == 'Enter') {
|
if (document.activeElement === input && event.type == 'keydown' && event.code == 'Enter') {
|
||||||
this.submitUrl();
|
this.submitUrl();
|
||||||
}
|
|
||||||
|
|
||||||
if (event.type == 'keydown' && (event.code == 'F1' || (document.activeElement !== input && event.code == 'KeyH'))) {
|
|
||||||
this.$emit('help-toggle');
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type == 'keydown' && (document.activeElement !== input && event.code == 'KeyQ')) {
|
if (event.type == 'keydown' && document.activeElement !== input) {
|
||||||
this.$emit('tool-bar-toggle');
|
const action = this.$root.readerActionByKeyEvent(event);
|
||||||
event.preventDefault();
|
switch (action) {
|
||||||
event.stopPropagation();
|
case 'help':
|
||||||
return true;
|
this.openHelp(event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -4,57 +4,57 @@
|
|||||||
<div ref="buttons" class="row justify-between no-wrap">
|
<div ref="buttons" class="row justify-between no-wrap">
|
||||||
<button ref="loader" class="tool-button" :class="buttonActiveClass('loader')" @click="buttonClick('loader')" v-ripple>
|
<button ref="loader" class="tool-button" :class="buttonActiveClass('loader')" @click="buttonClick('loader')" v-ripple>
|
||||||
<q-icon name="la la-arrow-left" size="32px"/>
|
<q-icon name="la la-arrow-left" size="32px"/>
|
||||||
<q-tooltip :delay="1500" anchor="bottom right" content-style="font-size: 80%">Загрузить книгу</q-tooltip>
|
<q-tooltip :delay="1500" anchor="bottom right" content-style="font-size: 80%">{{ rstore.readerActions['loader'] }}</q-tooltip>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<button ref="undoAction" v-show="showToolButton['undoAction']" class="tool-button" :class="buttonActiveClass('undoAction')" @click="buttonClick('undoAction')" v-ripple>
|
<button ref="undoAction" v-show="showToolButton['undoAction']" class="tool-button" :class="buttonActiveClass('undoAction')" @click="buttonClick('undoAction')" v-ripple>
|
||||||
<q-icon name="la la-angle-left" size="32px"/>
|
<q-icon name="la la-angle-left" size="32px"/>
|
||||||
<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%">{{ rstore.readerActions['undoAction'] }}</q-tooltip>
|
||||||
</button>
|
</button>
|
||||||
<button ref="redoAction" v-show="showToolButton['redoAction']" class="tool-button" :class="buttonActiveClass('redoAction')" @click="buttonClick('redoAction')" v-ripple>
|
<button ref="redoAction" v-show="showToolButton['redoAction']" class="tool-button" :class="buttonActiveClass('redoAction')" @click="buttonClick('redoAction')" v-ripple>
|
||||||
<q-icon name="la la-angle-right" size="32px"/>
|
<q-icon name="la la-angle-right" size="32px"/>
|
||||||
<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%">{{ rstore.readerActions['redoAction'] }}</q-tooltip>
|
||||||
</button>
|
</button>
|
||||||
<div class="space"></div>
|
<div class="space"></div>
|
||||||
<button ref="fullScreen" v-show="showToolButton['fullScreen']" class="tool-button" :class="buttonActiveClass('fullScreen')" @click="buttonClick('fullScreen')" v-ripple>
|
<button ref="fullScreen" v-show="showToolButton['fullScreen']" class="tool-button" :class="buttonActiveClass('fullScreen')" @click="buttonClick('fullScreen')" v-ripple>
|
||||||
<q-icon :name="(fullScreenActive ? 'la la-compress-arrows-alt': 'la la-expand-arrows-alt')" size="32px"/>
|
<q-icon :name="(fullScreenActive ? 'la la-compress-arrows-alt': 'la la-expand-arrows-alt')" size="32px"/>
|
||||||
<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%">{{ rstore.readerActions['fullScreen'] }}</q-tooltip>
|
||||||
</button>
|
</button>
|
||||||
<button ref="scrolling" v-show="showToolButton['scrolling']" class="tool-button" :class="buttonActiveClass('scrolling')" @click="buttonClick('scrolling')" v-ripple>
|
<button ref="scrolling" v-show="showToolButton['scrolling']" class="tool-button" :class="buttonActiveClass('scrolling')" @click="buttonClick('scrolling')" v-ripple>
|
||||||
<q-icon name="la la-film" size="32px"/>
|
<q-icon name="la la-film" size="32px"/>
|
||||||
<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%">{{ rstore.readerActions['scrolling'] }}</q-tooltip>
|
||||||
</button>
|
</button>
|
||||||
<button ref="setPosition" v-show="showToolButton['setPosition']" class="tool-button" :class="buttonActiveClass('setPosition')" @click="buttonClick('setPosition')" v-ripple>
|
<button ref="setPosition" v-show="showToolButton['setPosition']" class="tool-button" :class="buttonActiveClass('setPosition')" @click="buttonClick('setPosition')" v-ripple>
|
||||||
<q-icon name="la la-angle-double-right" size="32px"/>
|
<q-icon name="la la-angle-double-right" size="32px"/>
|
||||||
<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%">{{ rstore.readerActions['setPosition'] }}</q-tooltip>
|
||||||
</button>
|
</button>
|
||||||
<button ref="search" v-show="showToolButton['search']" class="tool-button" :class="buttonActiveClass('search')" @click="buttonClick('search')" v-ripple>
|
<button ref="search" v-show="showToolButton['search']" class="tool-button" :class="buttonActiveClass('search')" @click="buttonClick('search')" v-ripple>
|
||||||
<q-icon name="la la-search" size="32px"/>
|
<q-icon name="la la-search" size="32px"/>
|
||||||
<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%">{{ rstore.readerActions['search'] }}</q-tooltip>
|
||||||
</button>
|
</button>
|
||||||
<button ref="copyText" v-show="showToolButton['copyText']" class="tool-button" :class="buttonActiveClass('copyText')" @click="buttonClick('copyText')" v-ripple>
|
<button ref="copyText" v-show="showToolButton['copyText']" class="tool-button" :class="buttonActiveClass('copyText')" @click="buttonClick('copyText')" v-ripple>
|
||||||
<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%">Скопировать текст со страницы</q-tooltip>
|
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">{{ rstore.readerActions['copyText'] }}</q-tooltip>
|
||||||
</button>
|
</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%">Принудительно обновить книгу в обход кэша</q-tooltip>
|
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">{{ rstore.readerActions['refresh'] }}</q-tooltip>
|
||||||
</button>
|
</button>
|
||||||
<div class="space"></div>
|
<div class="space"></div>
|
||||||
<button ref="offlineMode" v-show="showToolButton['offlineMode']" class="tool-button" :class="buttonActiveClass('offlineMode')" @click="buttonClick('offlineMode')" v-ripple>
|
<button ref="offlineMode" v-show="showToolButton['offlineMode']" class="tool-button" :class="buttonActiveClass('offlineMode')" @click="buttonClick('offlineMode')" v-ripple>
|
||||||
<q-icon name="la la-unlink" size="32px"/>
|
<q-icon name="la la-unlink" size="32px"/>
|
||||||
<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%">{{ rstore.readerActions['offlineMode'] }}</q-tooltip>
|
||||||
</button>
|
</button>
|
||||||
<button ref="recentBooks" v-show="showToolButton['recentBooks']" class="tool-button" :class="buttonActiveClass('recentBooks')" @click="buttonClick('recentBooks')" v-ripple>
|
<button ref="recentBooks" v-show="showToolButton['recentBooks']" class="tool-button" :class="buttonActiveClass('recentBooks')" @click="buttonClick('recentBooks')" v-ripple>
|
||||||
<q-icon name="la la-book-open" size="32px"/>
|
<q-icon name="la la-book-open" size="32px"/>
|
||||||
<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%">{{ rstore.readerActions['recentBooks'] }}</q-tooltip>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button ref="settings" class="tool-button" :class="buttonActiveClass('settings')" @click="buttonClick('settings')" v-ripple>
|
<button ref="settings" class="tool-button" :class="buttonActiveClass('settings')" @click="buttonClick('settings')" v-ripple>
|
||||||
<q-icon name="la la-cog" size="32px"/>
|
<q-icon name="la la-cog" size="32px"/>
|
||||||
<q-tooltip :delay="1500" anchor="bottom left" content-style="font-size: 80%">Настроить</q-tooltip>
|
<q-tooltip :delay="1500" anchor="bottom left" content-style="font-size: 80%">{{ rstore.readerActions['settings'] }}</q-tooltip>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -65,26 +65,21 @@
|
|||||||
@load-book="loadBook"
|
@load-book="loadBook"
|
||||||
@load-file="loadFile"
|
@load-file="loadFile"
|
||||||
@book-pos-changed="bookPosChanged"
|
@book-pos-changed="bookPosChanged"
|
||||||
@tool-bar-toggle="toolBarToggle"
|
@do-action="doAction"
|
||||||
@full-screen-toogle="fullScreenToggle"
|
|
||||||
@stop-scrolling="stopScrolling"
|
|
||||||
@scrolling-toggle="scrollingToggle"
|
|
||||||
@help-toggle="helpToggle"
|
|
||||||
@donate-toggle="donateToggle"
|
|
||||||
></component>
|
></component>
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
|
|
||||||
<SetPositionPage v-if="setPositionActive" ref="setPositionPage" @set-position-toggle="setPositionToggle" @book-pos-changed="bookPosChanged"></SetPositionPage>
|
<SetPositionPage v-if="setPositionActive" ref="setPositionPage" @set-position-toggle="setPositionToggle" @book-pos-changed="bookPosChanged"></SetPositionPage>
|
||||||
<SearchPage v-show="searchActive" ref="searchPage"
|
<SearchPage v-show="searchActive" ref="searchPage"
|
||||||
@search-toggle="searchToggle"
|
@do-action="doAction"
|
||||||
@book-pos-changed="bookPosChanged"
|
@book-pos-changed="bookPosChanged"
|
||||||
@start-text-search="startTextSearch"
|
@start-text-search="startTextSearch"
|
||||||
@stop-text-search="stopTextSearch">
|
@stop-text-search="stopTextSearch">
|
||||||
</SearchPage>
|
</SearchPage>
|
||||||
<CopyTextPage v-if="copyTextActive" ref="copyTextPage" @copy-text-toggle="copyTextToggle"></CopyTextPage>
|
<CopyTextPage v-if="copyTextActive" ref="copyTextPage" @do-action="doAction"></CopyTextPage>
|
||||||
<RecentBooksPage v-show="recentBooksActive" ref="recentBooksPage" @load-book="loadBook" @recent-books-close="recentBooksClose"></RecentBooksPage>
|
<RecentBooksPage v-show="recentBooksActive" ref="recentBooksPage" @load-book="loadBook" @recent-books-close="recentBooksClose"></RecentBooksPage>
|
||||||
<SettingsPage v-show="settingsActive" ref="settingsPage" @settings-toggle="settingsToggle"></SettingsPage>
|
<SettingsPage v-show="settingsActive" ref="settingsPage" @do-action="doAction"></SettingsPage>
|
||||||
<HelpPage v-if="helpActive" ref="helpPage" @help-toggle="helpToggle"></HelpPage>
|
<HelpPage v-if="helpActive" ref="helpPage" @do-action="doAction"></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>
|
||||||
|
|
||||||
@@ -169,12 +164,13 @@ 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 Dialog from '../share/Dialog.vue';
|
||||||
|
|
||||||
import bookManager from './share/bookManager';
|
import bookManager from './share/bookManager';
|
||||||
|
import rstore from '../../store/modules/reader';
|
||||||
import readerApi from '../../api/reader';
|
import readerApi from '../../api/reader';
|
||||||
import * as utils from '../../share/utils';
|
import * as utils from '../../share/utils';
|
||||||
import {versionHistory} from './versionHistory';
|
import {versionHistory} from './versionHistory';
|
||||||
import Dialog from '../share/Dialog.vue';
|
|
||||||
|
|
||||||
export default @Component({
|
export default @Component({
|
||||||
components: {
|
components: {
|
||||||
@@ -232,6 +228,7 @@ export default @Component({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
class Reader extends Vue {
|
class Reader extends Vue {
|
||||||
|
rstore = {};
|
||||||
loaderActive = false;
|
loaderActive = false;
|
||||||
progressActive = false;
|
progressActive = false;
|
||||||
fullScreenActive = false;
|
fullScreenActive = false;
|
||||||
@@ -261,6 +258,7 @@ class Reader extends Vue {
|
|||||||
donationVisible = false;
|
donationVisible = false;
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
|
this.rstore = rstore;
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.commit = this.$store.commit;
|
this.commit = this.$store.commit;
|
||||||
this.dispatch = this.$store.dispatch;
|
this.dispatch = this.$store.dispatch;
|
||||||
@@ -336,6 +334,11 @@ class Reader extends Vue {
|
|||||||
this.showToolButton = settings.showToolButton;
|
this.showToolButton = settings.showToolButton;
|
||||||
this.enableSitesFilter = settings.enableSitesFilter;
|
this.enableSitesFilter = settings.enableSitesFilter;
|
||||||
|
|
||||||
|
this.readerActionByKeyCode = utils.userHotKeysObjectSwap(settings.userHotKeys);
|
||||||
|
this.$root.readerActionByKeyEvent = (event) => {
|
||||||
|
return this.readerActionByKeyCode[utils.keyEventToCode(event)];
|
||||||
|
}
|
||||||
|
|
||||||
this.updateHeaderMinWidth();
|
this.updateHeaderMinWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -750,66 +753,37 @@ class Reader extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buttonClick(button) {
|
undoAction() {
|
||||||
const activeClass = this.buttonActiveClass(button);
|
if (this.actionCur > 0) {
|
||||||
|
this.actionCur--;
|
||||||
|
this.bookPosChanged({bookPos: this.actionList[this.actionCur]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.$refs[button].blur();
|
redoAction() {
|
||||||
|
if (this.actionCur < this.actionList.length - 1) {
|
||||||
|
this.actionCur++;
|
||||||
|
this.bookPosChanged({bookPos: this.actionList[this.actionCur]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonClick(action) {
|
||||||
|
const activeClass = this.buttonActiveClass(action);
|
||||||
|
|
||||||
|
this.$refs[action].blur();
|
||||||
|
|
||||||
if (activeClass['tool-button-disabled'])
|
if (activeClass['tool-button-disabled'])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (button) {
|
this.doAction({action});
|
||||||
case 'loader':
|
|
||||||
this.loaderToggle();
|
|
||||||
break;
|
|
||||||
case 'undoAction':
|
|
||||||
if (this.actionCur > 0) {
|
|
||||||
this.actionCur--;
|
|
||||||
this.bookPosChanged({bookPos: this.actionList[this.actionCur]});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'redoAction':
|
|
||||||
if (this.actionCur < this.actionList.length - 1) {
|
|
||||||
this.actionCur++;
|
|
||||||
this.bookPosChanged({bookPos: this.actionList[this.actionCur]});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'fullScreen':
|
|
||||||
this.fullScreenToggle();
|
|
||||||
break;
|
|
||||||
case 'setPosition':
|
|
||||||
this.setPositionToggle();
|
|
||||||
break;
|
|
||||||
case 'scrolling':
|
|
||||||
this.scrollingToggle();
|
|
||||||
break;
|
|
||||||
case 'search':
|
|
||||||
this.searchToggle();
|
|
||||||
break;
|
|
||||||
case 'copyText':
|
|
||||||
this.copyTextToggle();
|
|
||||||
break;
|
|
||||||
case 'refresh':
|
|
||||||
this.refreshBook();
|
|
||||||
break;
|
|
||||||
case 'recentBooks':
|
|
||||||
this.recentBooksToggle();
|
|
||||||
break;
|
|
||||||
case 'offlineMode':
|
|
||||||
this.offlineModeToggle();
|
|
||||||
break;
|
|
||||||
case 'settings':
|
|
||||||
this.settingsToggle();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buttonActiveClass(button) {
|
buttonActiveClass(action) {
|
||||||
const classActive = { 'tool-button-active': true, 'tool-button-active:hover': true };
|
const classActive = { 'tool-button-active': true, 'tool-button-active:hover': true };
|
||||||
const classDisabled = { 'tool-button-disabled': true, 'tool-button-disabled:hover': true };
|
const classDisabled = { 'tool-button-disabled': true, 'tool-button-disabled:hover': true };
|
||||||
let classResult = {};
|
let classResult = {};
|
||||||
|
|
||||||
switch (button) {
|
switch (action) {
|
||||||
case 'loader':
|
case 'loader':
|
||||||
case 'fullScreen':
|
case 'fullScreen':
|
||||||
case 'setPosition':
|
case 'setPosition':
|
||||||
@@ -822,7 +796,7 @@ class Reader extends Vue {
|
|||||||
case 'settings':
|
case 'settings':
|
||||||
if (this.progressActive) {
|
if (this.progressActive) {
|
||||||
classResult = classDisabled;
|
classResult = classDisabled;
|
||||||
} else if (this[`${button}Active`]) {
|
} else if (this[`${action}Active`]) {
|
||||||
classResult = classActive;
|
classResult = classActive;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -837,7 +811,7 @@ class Reader extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.activePage == 'LoaderPage' || !this.mostRecentBookReactive) {
|
if (this.activePage == 'LoaderPage' || !this.mostRecentBookReactive) {
|
||||||
switch (button) {
|
switch (action) {
|
||||||
case 'undoAction':
|
case 'undoAction':
|
||||||
case 'redoAction':
|
case 'redoAction':
|
||||||
case 'setPosition':
|
case 'setPosition':
|
||||||
@@ -1030,7 +1004,7 @@ class Reader extends Vue {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
progress.hide(); this.progressActive = false;
|
progress.hide(); this.progressActive = false;
|
||||||
this.loaderActive = true;
|
this.loaderActive = true;
|
||||||
this.$root.stdDialog.alert(e.message, 'Ошибка', {type: 'negative'});
|
this.$root.stdDialog.alert(e.message, 'Ошибка', {color: 'negative'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1054,7 +1028,7 @@ class Reader extends Vue {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
progress.hide(); this.progressActive = false;
|
progress.hide(); this.progressActive = false;
|
||||||
this.loaderActive = true;
|
this.loaderActive = true;
|
||||||
this.$root.stdDialog.alert(e.message, 'Ошибка', {type: 'negative'});
|
this.$root.stdDialog.alert(e.message, 'Ошибка', {color: 'negative'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1086,10 +1060,118 @@ class Reader extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
doAction(opts) {
|
||||||
|
let result = true;
|
||||||
|
let {action = '', event = false} = opts;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case 'loader':
|
||||||
|
this.loaderToggle();
|
||||||
|
break;
|
||||||
|
case 'help':
|
||||||
|
this.helpToggle();
|
||||||
|
break;
|
||||||
|
case 'settings':
|
||||||
|
this.settingsToggle();
|
||||||
|
break;
|
||||||
|
case 'undoAction':
|
||||||
|
this.undoAction();
|
||||||
|
break;
|
||||||
|
case 'redoAction':
|
||||||
|
this.redoAction();
|
||||||
|
break;
|
||||||
|
case 'fullScreen':
|
||||||
|
this.fullScreenToggle();
|
||||||
|
break;
|
||||||
|
case 'scrolling':
|
||||||
|
this.scrollingToggle();
|
||||||
|
break;
|
||||||
|
case 'stopScrolling':
|
||||||
|
this.stopScrolling();
|
||||||
|
break;
|
||||||
|
case 'setPosition':
|
||||||
|
this.setPositionToggle();
|
||||||
|
break;
|
||||||
|
case 'search':
|
||||||
|
this.searchToggle();
|
||||||
|
break;
|
||||||
|
case 'copyText':
|
||||||
|
this.copyTextToggle();
|
||||||
|
break;
|
||||||
|
case 'refresh':
|
||||||
|
this.refreshBook();
|
||||||
|
break;
|
||||||
|
case 'offlineMode':
|
||||||
|
this.offlineModeToggle();
|
||||||
|
break;
|
||||||
|
case 'recentBooks':
|
||||||
|
this.recentBooksToggle();
|
||||||
|
break;
|
||||||
|
case 'switchToolbar':
|
||||||
|
this.toolBarToggle();
|
||||||
|
break;
|
||||||
|
case 'donate':
|
||||||
|
this.donateToggle();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result && this.activePage == 'TextPage' && this.$refs.page) {
|
||||||
|
result = true;
|
||||||
|
const textPage = this.$refs.page;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case 'bookBegin':
|
||||||
|
textPage.doHome();
|
||||||
|
break;
|
||||||
|
case 'bookEnd':
|
||||||
|
textPage.doEnd();
|
||||||
|
break;
|
||||||
|
case 'pageBack':
|
||||||
|
textPage.doPageUp();
|
||||||
|
break;
|
||||||
|
case 'pageForward':
|
||||||
|
textPage.doPageDown();
|
||||||
|
break;
|
||||||
|
case 'lineBack':
|
||||||
|
textPage.doUp();
|
||||||
|
break;
|
||||||
|
case 'lineForward':
|
||||||
|
textPage.doDown();
|
||||||
|
break;
|
||||||
|
case 'incFontSize':
|
||||||
|
textPage.doFontSizeInc();
|
||||||
|
break;
|
||||||
|
case 'decFontSize':
|
||||||
|
textPage.doFontSizeDec();
|
||||||
|
break;
|
||||||
|
case 'scrollingSpeedUp':
|
||||||
|
textPage.doScrollingSpeedUp();
|
||||||
|
break;
|
||||||
|
case 'scrollingSpeedDown':
|
||||||
|
textPage.doScrollingSpeedDown();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result && event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
keyHook(event) {
|
keyHook(event) {
|
||||||
|
let result = false;
|
||||||
if (this.$root.rootRoute() == '/reader') {
|
if (this.$root.rootRoute() == '/reader') {
|
||||||
if (this.$root.stdDialog.active || this.$refs.dialog1.active || this.$refs.dialog2.active)
|
if (this.$root.stdDialog.active || this.$refs.dialog1.active || this.$refs.dialog2.active)
|
||||||
return;
|
return result;
|
||||||
|
|
||||||
let handled = false;
|
let handled = false;
|
||||||
if (!handled && this.helpActive)
|
if (!handled && this.helpActive)
|
||||||
@@ -1114,55 +1196,18 @@ class Reader extends Vue {
|
|||||||
handled = this.$refs.page.keyHook(event);
|
handled = this.$refs.page.keyHook(event);
|
||||||
|
|
||||||
if (!handled && event.type == 'keydown') {
|
if (!handled && event.type == 'keydown') {
|
||||||
if (event.code == 'Escape')
|
const action = this.$root.readerActionByKeyEvent(event);
|
||||||
this.loaderToggle();
|
|
||||||
|
|
||||||
if (this.activePage == 'TextPage') {
|
if (action == 'loader') {
|
||||||
switch (event.code) {
|
result = this.doAction({action, event});
|
||||||
case 'KeyH':
|
}
|
||||||
case 'F1':
|
|
||||||
this.helpToggle();
|
if (!result && this.activePage == 'TextPage') {
|
||||||
event.preventDefault();
|
result = this.doAction({action, event});
|
||||||
event.stopPropagation();
|
|
||||||
break;
|
|
||||||
case 'KeyZ':
|
|
||||||
this.scrollingToggle();
|
|
||||||
break;
|
|
||||||
case 'KeyP':
|
|
||||||
this.setPositionToggle();
|
|
||||||
break;
|
|
||||||
case 'KeyF':
|
|
||||||
if (event.ctrlKey) {
|
|
||||||
this.searchToggle();
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'KeyC':
|
|
||||||
if (event.ctrlKey) {
|
|
||||||
this.copyTextToggle();
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'KeyR':
|
|
||||||
this.refreshBook();
|
|
||||||
break;
|
|
||||||
case 'KeyX':
|
|
||||||
this.recentBooksToggle();
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
break;
|
|
||||||
case 'KeyO':
|
|
||||||
this.offlineModeToggle();
|
|
||||||
break;
|
|
||||||
case 'KeyS':
|
|
||||||
this.settingsToggle();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -303,7 +303,7 @@ class RecentBooksPage extends Vue {
|
|||||||
let errMes = e.message;
|
let errMes = e.message;
|
||||||
if (errMes.indexOf('404') >= 0)
|
if (errMes.indexOf('404') >= 0)
|
||||||
errMes = 'Файл не найден на сервере (возможно был удален как устаревший)';
|
errMes = 'Файл не найден на сервере (возможно был удален как устаревший)';
|
||||||
this.$root.stdDialog.alert(errMes, 'Ошибка', {type: 'negative'});
|
this.$root.stdDialog.alert(errMes, 'Ошибка', {color: 'negative'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ class SearchPage extends Vue {
|
|||||||
|
|
||||||
close() {
|
close() {
|
||||||
this.stopInit = true;
|
this.stopInit = true;
|
||||||
this.$emit('search-toggle');
|
this.$emit('do-action', {action: 'search'});
|
||||||
}
|
}
|
||||||
|
|
||||||
inputKeyDown(event) {
|
inputKeyDown(event) {
|
||||||
|
|||||||
@@ -58,8 +58,11 @@ class SetPositionPage extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
keyHook(event) {
|
keyHook(event) {
|
||||||
if (event.type == 'keydown' && (event.code == 'Escape' || event.code == 'KeyP')) {
|
if (event.type == 'keydown') {
|
||||||
this.close();
|
const action = this.$root.readerActionByKeyEvent(event);
|
||||||
|
if (event.code == 'Escape' || action == 'setPosition') {
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
@@include('./include/ButtonsTab.inc');
|
@@include('./include/ButtonsTab.inc');
|
||||||
</div>
|
</div>
|
||||||
<!-- Управление ------------------------------------------------------------------>
|
<!-- Управление ------------------------------------------------------------------>
|
||||||
<div v-if="selectedTab == 'keys'" class="fit tab-panel">
|
<div v-if="selectedTab == 'keys'" class="fit column">
|
||||||
@@include('./include/KeysTab.inc');
|
@@include('./include/KeysTab.inc');
|
||||||
</div>
|
</div>
|
||||||
<!-- Листание -------------------------------------------------------------------->
|
<!-- Листание -------------------------------------------------------------------->
|
||||||
@@ -76,6 +76,8 @@ import _ from 'lodash';
|
|||||||
import * as utils from '../../../share/utils';
|
import * as utils from '../../../share/utils';
|
||||||
import Window from '../../share/Window.vue';
|
import Window from '../../share/Window.vue';
|
||||||
import NumInput from '../../share/NumInput.vue';
|
import NumInput from '../../share/NumInput.vue';
|
||||||
|
import UserHotKeys from './UserHotKeys/UserHotKeys.vue';
|
||||||
|
|
||||||
import rstore from '../../../store/modules/reader';
|
import rstore from '../../../store/modules/reader';
|
||||||
import defPalette from './defPalette';
|
import defPalette from './defPalette';
|
||||||
|
|
||||||
@@ -85,6 +87,7 @@ export default @Component({
|
|||||||
components: {
|
components: {
|
||||||
Window,
|
Window,
|
||||||
NumInput,
|
NumInput,
|
||||||
|
UserHotKeys,
|
||||||
},
|
},
|
||||||
data: function() {
|
data: function() {
|
||||||
return Object.assign({}, rstore.settingDefaults);
|
return Object.assign({}, rstore.settingDefaults);
|
||||||
@@ -139,6 +142,7 @@ export default @Component({
|
|||||||
class SettingsPage extends Vue {
|
class SettingsPage extends Vue {
|
||||||
selectedTab = 'profiles';
|
selectedTab = 'profiles';
|
||||||
selectedViewTab = 'color';
|
selectedViewTab = 'color';
|
||||||
|
selectedKeysTab = 'mouse';
|
||||||
form = {};
|
form = {};
|
||||||
fontBold = false;
|
fontBold = false;
|
||||||
fontItalic = false;
|
fontItalic = false;
|
||||||
@@ -152,12 +156,14 @@ class SettingsPage extends Vue {
|
|||||||
|
|
||||||
serverStorageKeyVisible = false;
|
serverStorageKeyVisible = false;
|
||||||
toolButtons = [];
|
toolButtons = [];
|
||||||
|
rstore = {};
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.commit = this.$store.commit;
|
this.commit = this.$store.commit;
|
||||||
this.reader = this.$store.state.reader;
|
this.reader = this.$store.state.reader;
|
||||||
|
|
||||||
this.form = {};
|
this.form = {};
|
||||||
|
this.rstore = rstore;
|
||||||
this.toolButtons = rstore.toolButtons;
|
this.toolButtons = rstore.toolButtons;
|
||||||
this.settingsChanged();
|
this.settingsChanged();
|
||||||
}
|
}
|
||||||
@@ -339,7 +345,7 @@ class SettingsPage extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
this.$emit('settings-toggle');
|
this.$emit('do-action', {action: 'settings'});
|
||||||
}
|
}
|
||||||
|
|
||||||
async setDefaults() {
|
async setDefaults() {
|
||||||
|
|||||||
@@ -0,0 +1,248 @@
|
|||||||
|
<template>
|
||||||
|
<div class="table col column no-wrap">
|
||||||
|
<!-- header -->
|
||||||
|
<div class="table-row row">
|
||||||
|
<div class="desc q-pa-sm bg-blue-2">Команда</div>
|
||||||
|
<div class="hotKeys col q-pa-sm bg-blue-2 row no-wrap">
|
||||||
|
<div style="width: 80px">Сочетание клавиш</div>
|
||||||
|
<q-input ref="input" class="q-ml-sm col"
|
||||||
|
outlined dense rounded
|
||||||
|
bg-color="grey-4"
|
||||||
|
placeholder="Найти"
|
||||||
|
v-model="search"
|
||||||
|
@click.stop
|
||||||
|
/>
|
||||||
|
<div v-show="!readonly" class="q-ml-sm column justify-center">
|
||||||
|
<q-btn class="bg-grey-4 text-grey-6" style="height: 35px; width: 35px" rounded flat icon="la la-broom" @click="defaultHotKeyAll">
|
||||||
|
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
|
||||||
|
Установить все сочетания по умолчанию
|
||||||
|
</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- body -->
|
||||||
|
<div class="table-row row" v-for="(action, index) in tableData" :key="index">
|
||||||
|
<div class="desc q-pa-sm">{{ rstore.readerActions[action] }}</div>
|
||||||
|
<div class="hotKeys col q-pa-sm">
|
||||||
|
<q-chip
|
||||||
|
:color="collisions[code] ? 'red' : 'grey-7'"
|
||||||
|
:removable="!readonly" :clickable="collisions[code] ? true : false"
|
||||||
|
text-color="white" v-for="(code, index) in value[action]" :key="index" @remove="removeCode(action, code)"
|
||||||
|
@click="collisionWarning(code)"
|
||||||
|
>
|
||||||
|
{{ code }}
|
||||||
|
</q-chip>
|
||||||
|
</div>
|
||||||
|
<div v-show="!readonly" class="column q-pa-xs">
|
||||||
|
<q-icon
|
||||||
|
name="la la-plus-circle"
|
||||||
|
class="button bg-green-8 text-white"
|
||||||
|
@click="addHotKey(action)"
|
||||||
|
v-ripple
|
||||||
|
:disabled="value[action].length >= maxCodesLength"
|
||||||
|
>
|
||||||
|
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
|
||||||
|
Добавить сочетание клавиш
|
||||||
|
</q-tooltip>
|
||||||
|
</q-icon>
|
||||||
|
<q-icon
|
||||||
|
name="la la-broom"
|
||||||
|
class="button text-grey-5"
|
||||||
|
@click="defaultHotKey(action)"
|
||||||
|
v-ripple
|
||||||
|
>
|
||||||
|
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
|
||||||
|
По умолчанию
|
||||||
|
</q-tooltip>
|
||||||
|
</q-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
import Vue from 'vue';
|
||||||
|
import Component from 'vue-class-component';
|
||||||
|
|
||||||
|
import rstore from '../../../../store/modules/reader';
|
||||||
|
//import * as utils from '../../share/utils';
|
||||||
|
|
||||||
|
const UserHotKeysProps = Vue.extend({
|
||||||
|
props: {
|
||||||
|
value: Object,
|
||||||
|
readonly: Boolean,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default @Component({
|
||||||
|
watch: {
|
||||||
|
search: function() {
|
||||||
|
this.updateTableData();
|
||||||
|
},
|
||||||
|
value: function() {
|
||||||
|
this.checkCollisions();
|
||||||
|
this.updateTableData();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
class UserHotKeys extends UserHotKeysProps {
|
||||||
|
search = '';
|
||||||
|
rstore = {};
|
||||||
|
tableData = [];
|
||||||
|
collisions = {};
|
||||||
|
maxCodesLength = 10;
|
||||||
|
|
||||||
|
created() {
|
||||||
|
this.rstore = rstore;
|
||||||
|
}
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.checkCollisions();
|
||||||
|
this.updateTableData();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTableData() {
|
||||||
|
let result = rstore.hotKeys.map(hk => hk.name);
|
||||||
|
|
||||||
|
const search = this.search.toLowerCase();
|
||||||
|
const codesIncludeSearch = (action) => {
|
||||||
|
for (const code of this.value[action]) {
|
||||||
|
if (code.toLowerCase().includes(search))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
result = result.filter(item => {
|
||||||
|
return !search ||
|
||||||
|
rstore.readerActions[item].toLowerCase().includes(search) ||
|
||||||
|
codesIncludeSearch(item)
|
||||||
|
});
|
||||||
|
|
||||||
|
this.tableData = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkCollisions() {
|
||||||
|
const cols = {};
|
||||||
|
for (const [action, codes] of Object.entries(this.value)) {
|
||||||
|
codes.forEach(code => {
|
||||||
|
if (!cols[code])
|
||||||
|
cols[code] = [];
|
||||||
|
if (cols[code].indexOf(action) < 0)
|
||||||
|
cols[code].push(action);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = {};
|
||||||
|
for (const [code, actions] of Object.entries(cols)) {
|
||||||
|
if (actions.length > 1)
|
||||||
|
result[code] = actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.collisions = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
collisionWarning(code) {
|
||||||
|
if (this.collisions[code]) {
|
||||||
|
const descs = this.collisions[code].map(action => `<b>${rstore.readerActions[action]}</b>`);
|
||||||
|
this.$root.stdDialog.alert(`Сочетание '${code}' одновременно назначено<br>следующим командам:<br>${descs.join('<br>')}<br><br>
|
||||||
|
Возможно неожиданное поведение.`, 'Предупреждение');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeCode(action, code) {
|
||||||
|
let codes = Array.from(this.value[action]);
|
||||||
|
const index = codes.indexOf(code);
|
||||||
|
if (index >= 0) {
|
||||||
|
codes.splice(index, 1);
|
||||||
|
const newValue = Object.assign({}, this.value, {[action]: codes});
|
||||||
|
this.$emit('input', newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async addHotKey(action) {
|
||||||
|
if (this.value[action].length >= this.maxCodesLength)
|
||||||
|
return;
|
||||||
|
try {
|
||||||
|
const result = await this.$root.stdDialog.getHotKey(`Добавить сочетание для:<br><b>${rstore.readerActions[action]}</b>`, '');
|
||||||
|
if (result) {
|
||||||
|
let codes = Array.from(this.value[action]);
|
||||||
|
if (codes.indexOf(result) < 0) {
|
||||||
|
codes.push(result);
|
||||||
|
const newValue = Object.assign({}, this.value, {[action]: codes});
|
||||||
|
this.$emit('input', newValue);
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.collisionWarning(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async defaultHotKey(action) {
|
||||||
|
try {
|
||||||
|
if (await this.$root.stdDialog.confirm(`Подтвердите сброс сочетаний клавиш<br>в значения по умолчанию для команды:<br><b>${rstore.readerActions[action]}</b>`, ' ')) {
|
||||||
|
const codes = Array.from(rstore.settingDefaults.userHotKeys[action]);
|
||||||
|
const newValue = Object.assign({}, this.value, {[action]: codes});
|
||||||
|
this.$emit('input', newValue);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async defaultHotKeyAll() {
|
||||||
|
try {
|
||||||
|
if (await this.$root.stdDialog.confirm('Подтвердите сброс сочетаний клавиш<br>для ВСЕХ команд в значения по умолчанию:', ' ')) {
|
||||||
|
const newValue = Object.assign({}, rstore.settingDefaults.userHotKeys);
|
||||||
|
this.$emit('input', newValue);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.table {
|
||||||
|
border-left: 1px solid grey;
|
||||||
|
border-top: 1px solid grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-row {
|
||||||
|
border-right: 1px solid grey;
|
||||||
|
border-bottom: 1px solid grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-row:nth-child(even) {
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-row:hover {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc {
|
||||||
|
width: 130px;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
word-wrap: break-word;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hotKeys {
|
||||||
|
border-left: 1px solid grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
font-size: 25px;
|
||||||
|
border-radius: 25px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -3,6 +3,6 @@
|
|||||||
<div class="item row" v-for="item in toolButtons" :key="item.name">
|
<div class="item row" v-for="item in toolButtons" :key="item.name">
|
||||||
<div class="label-3"></div>
|
<div class="label-3"></div>
|
||||||
<div class="col row">
|
<div class="col row">
|
||||||
<q-checkbox size="xs" @input="changeShowToolButton(item.name)" :value="showToolButton[item.name]" :label="item.text" />
|
<q-checkbox size="xs" @input="changeShowToolButton(item.name)" :value="showToolButton[item.name]" :label="rstore.readerActions[item.name]" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,33 @@
|
|||||||
<div class="part-header">Управление</div>
|
<div class="bg-grey-3 row">
|
||||||
|
<q-tabs
|
||||||
|
v-model="selectedKeysTab"
|
||||||
|
active-color="black"
|
||||||
|
active-bg-color="white"
|
||||||
|
indicator-color="white"
|
||||||
|
dense
|
||||||
|
no-caps
|
||||||
|
class="no-mp bg-grey-4 text-grey-7"
|
||||||
|
>
|
||||||
|
<q-tab name="mouse" label="Мышь/тачскрин" />
|
||||||
|
<q-tab name="keyboard" label="Клавиатура" />
|
||||||
|
</q-tabs>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="item row">
|
<div class="q-mb-sm"/>
|
||||||
<div class="label-4"></div>
|
|
||||||
<div class="col row">
|
<div class="col tab-panel">
|
||||||
<q-checkbox size="xs" v-model="clickControl" label="Включить управление кликом" />
|
<div v-if="selectedKeysTab == 'mouse'">
|
||||||
|
<div class="item row">
|
||||||
|
<div class="label-4"></div>
|
||||||
|
<div class="col row">
|
||||||
|
<q-checkbox size="xs" v-model="clickControl" label="Включить управление кликом" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="selectedKeysTab == 'keyboard'">
|
||||||
|
<div class="item row">
|
||||||
|
<UserHotKeys v-model="userHotKeys" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -423,7 +423,7 @@ class TextPage extends Vue {
|
|||||||
if (this.lazyParseEnabled)
|
if (this.lazyParseEnabled)
|
||||||
this.lazyParsePara();
|
this.lazyParsePara();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$root.stdDialog.alert(e.message, 'Ошибка', {type: 'negative'});
|
this.$root.stdDialog.alert(e.message, 'Ошибка', {color: 'negative'});
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
@@ -504,7 +504,7 @@ class TextPage extends Vue {
|
|||||||
async startTextScrolling() {
|
async startTextScrolling() {
|
||||||
if (this.doingScrolling || !this.book || !this.parsed.textLength || !this.linesDown || this.pageLineCount < 1 ||
|
if (this.doingScrolling || !this.book || !this.parsed.textLength || !this.linesDown || this.pageLineCount < 1 ||
|
||||||
this.linesDown.length <= this.pageLineCount) {
|
this.linesDown.length <= this.pageLineCount) {
|
||||||
this.$emit('stop-scrolling');
|
this.doStopScrolling();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -545,7 +545,7 @@ class TextPage extends Vue {
|
|||||||
}
|
}
|
||||||
this.resolveTransition1Finish = null;
|
this.resolveTransition1Finish = null;
|
||||||
this.doingScrolling = false;
|
this.doingScrolling = false;
|
||||||
this.$emit('stop-scrolling');
|
this.doStopScrolling();
|
||||||
this.draw();
|
this.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -884,22 +884,26 @@ class TextPage extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doToolBarToggle() {
|
doToolBarToggle(event) {
|
||||||
this.$emit('tool-bar-toggle');
|
this.$emit('do-action', {action: 'switchToolbar', event});
|
||||||
}
|
}
|
||||||
|
|
||||||
doScrollingToggle() {
|
doScrollingToggle() {
|
||||||
this.$emit('scrolling-toggle');
|
this.$emit('do-action', {action: 'scrolling', event});
|
||||||
}
|
}
|
||||||
|
|
||||||
doFullScreenToggle() {
|
doFullScreenToggle() {
|
||||||
this.$emit('full-screen-toogle');
|
this.$emit('do-action', {action: 'fullScreen', event});
|
||||||
|
}
|
||||||
|
|
||||||
|
doStopScrolling() {
|
||||||
|
this.$emit('do-action', {action: 'stopScrolling', event});
|
||||||
}
|
}
|
||||||
|
|
||||||
async doFontSizeInc() {
|
async doFontSizeInc() {
|
||||||
if (!this.settingsChanging) {
|
if (!this.settingsChanging) {
|
||||||
this.settingsChanging = true;
|
this.settingsChanging = true;
|
||||||
const newSize = (this.settings.fontSize + 1 < 100 ? this.settings.fontSize + 1 : 100);
|
const newSize = (this.settings.fontSize + 1 < 200 ? this.settings.fontSize + 1 : 100);
|
||||||
const newSettings = Object.assign({}, this.settings, {fontSize: newSize});
|
const newSettings = Object.assign({}, this.settings, {fontSize: newSize});
|
||||||
this.commit('reader/setSettings', newSettings);
|
this.commit('reader/setSettings', newSettings);
|
||||||
await sleep(50);
|
await sleep(50);
|
||||||
@@ -940,69 +944,6 @@ class TextPage extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keyHook(event) {
|
|
||||||
let result = false;
|
|
||||||
if (event.type == 'keydown' && !event.ctrlKey && !event.altKey) {
|
|
||||||
result = true;
|
|
||||||
switch (event.code) {
|
|
||||||
case 'ArrowDown':
|
|
||||||
if (event.shiftKey)
|
|
||||||
this.doScrollingSpeedUp();
|
|
||||||
else
|
|
||||||
this.doDown();
|
|
||||||
break;
|
|
||||||
case 'ArrowUp':
|
|
||||||
if (event.shiftKey)
|
|
||||||
this.doScrollingSpeedDown();
|
|
||||||
else
|
|
||||||
this.doUp();
|
|
||||||
break;
|
|
||||||
case 'PageDown':
|
|
||||||
case 'ArrowRight':
|
|
||||||
this.doPageDown();
|
|
||||||
break;
|
|
||||||
case 'Space':
|
|
||||||
if (event.shiftKey)
|
|
||||||
this.doPageUp();
|
|
||||||
else
|
|
||||||
this.doPageDown();
|
|
||||||
break;
|
|
||||||
case 'PageUp':
|
|
||||||
case 'ArrowLeft':
|
|
||||||
case 'Backspace':
|
|
||||||
this.doPageUp();
|
|
||||||
break;
|
|
||||||
case 'Home':
|
|
||||||
this.doHome();
|
|
||||||
break;
|
|
||||||
case 'End':
|
|
||||||
this.doEnd();
|
|
||||||
break;
|
|
||||||
case 'KeyA':
|
|
||||||
if (event.shiftKey)
|
|
||||||
this.doFontSizeDec();
|
|
||||||
else
|
|
||||||
this.doFontSizeInc();
|
|
||||||
break;
|
|
||||||
case 'Enter':
|
|
||||||
case 'Backquote'://`
|
|
||||||
case 'KeyF':
|
|
||||||
this.doFullScreenToggle();
|
|
||||||
break;
|
|
||||||
case 'Tab':
|
|
||||||
case 'KeyQ':
|
|
||||||
this.doToolBarToggle();
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
result = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
async startClickRepeat(pointX, pointY) {
|
async startClickRepeat(pointX, pointY) {
|
||||||
this.repX = pointX;
|
this.repX = pointX;
|
||||||
this.repY = pointY;
|
this.repY = pointY;
|
||||||
@@ -1080,7 +1021,7 @@ class TextPage extends Vue {
|
|||||||
//движение вправо
|
//движение вправо
|
||||||
this.doScrollingSpeedUp();
|
this.doScrollingSpeedUp();
|
||||||
} else if (Math.abs(dy) < touchDelta && Math.abs(dx) < touchDelta) {
|
} else if (Math.abs(dy) < touchDelta && Math.abs(dx) < touchDelta) {
|
||||||
this.doToolBarToggle();
|
this.doToolBarToggle(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.startTouch = null;
|
this.startTouch = null;
|
||||||
@@ -1107,7 +1048,7 @@ class TextPage extends Vue {
|
|||||||
} else if (event.button == 1) {
|
} else if (event.button == 1) {
|
||||||
this.doScrollingToggle();
|
this.doScrollingToggle();
|
||||||
} else if (event.button == 2) {
|
} else if (event.button == 2) {
|
||||||
this.doToolBarToggle();
|
this.doToolBarToggle(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1132,7 +1073,7 @@ class TextPage extends Vue {
|
|||||||
if (url && url.indexOf('file://') != 0) {
|
if (url && url.indexOf('file://') != 0) {
|
||||||
window.open(url, '_blank');
|
window.open(url, '_blank');
|
||||||
} else {
|
} else {
|
||||||
this.$root.stdDialog.alert('Оригинал недоступен, т.к. файл книги был загружен с локального диска.', ' ', {type: 'info'});
|
this.$root.stdDialog.alert('Оригинал недоступен, т.к. файл книги был загружен с локального диска.', ' ', {color: 'info'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,17 @@
|
|||||||
export const versionHistory = [
|
export const versionHistory = [
|
||||||
|
{
|
||||||
|
showUntil: '2020-04-25',
|
||||||
|
header: '0.9.2 (2020-03-15)',
|
||||||
|
content:
|
||||||
|
`
|
||||||
|
<ul>
|
||||||
|
<li>в настройки добавлена возможность назначать сочетания клавиш на команды в читалке</li>
|
||||||
|
<li>переход на Service Worker вместо AppCache для автономного режима работы</li>
|
||||||
|
<li>исправления багов</li>
|
||||||
|
</ul>
|
||||||
|
`
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
showUntil: '2020-03-02',
|
showUntil: '2020-03-02',
|
||||||
header: '0.9.1 (2020-03-03)',
|
header: '0.9.1 (2020-03-03)',
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
|
||||||
<!--------------------------------------------------->
|
<!--------------------------------------------------->
|
||||||
<div v-show="type == 'alert'" class="dialog column bg-white no-wrap" style="min-height: 150px">
|
<div v-show="type == 'alert'" class="bg-white no-wrap">
|
||||||
<div class="header row">
|
<div class="header row">
|
||||||
<div class="caption col row items-center q-ml-md">
|
<div class="caption col row items-center q-ml-md">
|
||||||
<q-icon v-show="caption" class="q-mr-sm" :class="iconColor" name="las la-exclamation-circle" size="28px"></q-icon>
|
<q-icon v-show="caption" class="q-mr-sm" :class="iconColor" name="las la-exclamation-circle" size="28px"></q-icon>
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col q-mx-md">
|
<div class="q-mx-md">
|
||||||
<div v-html="message"></div>
|
<div v-html="message"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--------------------------------------------------->
|
<!--------------------------------------------------->
|
||||||
<div v-show="type == 'confirm'" class="dialog column bg-white no-wrap" style="min-height: 150px">
|
<div v-show="type == 'confirm'" class="bg-white no-wrap">
|
||||||
<div class="header row">
|
<div class="header row">
|
||||||
<div class="caption col row items-center q-ml-md">
|
<div class="caption col row items-center q-ml-md">
|
||||||
<q-icon v-show="caption" class="q-mr-sm" :class="iconColor" name="las la-exclamation-circle" size="28px"></q-icon>
|
<q-icon v-show="caption" class="q-mr-sm" :class="iconColor" name="las la-exclamation-circle" size="28px"></q-icon>
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col q-mx-md">
|
<div class="q-mx-md">
|
||||||
<div v-html="message"></div>
|
<div v-html="message"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--------------------------------------------------->
|
<!--------------------------------------------------->
|
||||||
<div v-show="type == 'prompt'" class="dialog column bg-white no-wrap" style="min-height: 250px">
|
<div v-show="type == 'prompt'" class="bg-white no-wrap">
|
||||||
<div class="header row">
|
<div class="header row">
|
||||||
<div class="caption col row items-center q-ml-md">
|
<div class="caption col row items-center q-ml-md">
|
||||||
<q-icon v-show="caption" class="q-mr-sm" :class="iconColor" name="las la-exclamation-circle" size="28px"></q-icon>
|
<q-icon v-show="caption" class="q-mr-sm" :class="iconColor" name="las la-exclamation-circle" size="28px"></q-icon>
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col q-mx-md">
|
<div class="q-mx-md">
|
||||||
<div v-html="message"></div>
|
<div v-html="message"></div>
|
||||||
<q-input ref="input" class="q-mt-xs" outlined dense v-model="inputValue"/>
|
<q-input ref="input" class="q-mt-xs" outlined dense v-model="inputValue"/>
|
||||||
<div class="error"><span v-show="error != ''">{{ error }}</span></div>
|
<div class="error"><span v-show="error != ''">{{ error }}</span></div>
|
||||||
@@ -74,6 +74,34 @@
|
|||||||
<q-btn class="q-px-md q-ml-sm" color="primary" dense no-caps @click="okClick">OK</q-btn>
|
<q-btn class="q-px-md q-ml-sm" color="primary" dense no-caps @click="okClick">OK</q-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!--------------------------------------------------->
|
||||||
|
<div v-show="type == 'hotKey'" class="bg-white no-wrap">
|
||||||
|
<div class="header row">
|
||||||
|
<div class="caption col row items-center q-ml-md">
|
||||||
|
<q-icon v-show="caption" class="q-mr-sm" :class="iconColor" name="las la-exclamation-circle" size="28px"></q-icon>
|
||||||
|
<div v-html="caption"></div>
|
||||||
|
</div>
|
||||||
|
<div class="close-icon column justify-center items-center">
|
||||||
|
<q-btn flat round dense v-close-popup>
|
||||||
|
<q-icon name="la la-times" size="18px"></q-icon>
|
||||||
|
</q-btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="q-mx-md">
|
||||||
|
<div v-html="message"></div>
|
||||||
|
<div class="q-my-md text-center">
|
||||||
|
<div v-show="hotKeyCode == ''" class="text-grey-5">Нет</div>
|
||||||
|
<div>{{ hotKeyCode }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="buttons row justify-end q-pa-md">
|
||||||
|
<q-btn class="q-px-md q-ml-sm" dense no-caps v-close-popup>Отмена</q-btn>
|
||||||
|
<q-btn class="q-px-md q-ml-sm" color="primary" dense no-caps @click="okClick" :disabled="hotKeyCode == ''">OK</q-btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</q-dialog>
|
</q-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -82,7 +110,7 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import Component from 'vue-class-component';
|
import Component from 'vue-class-component';
|
||||||
|
|
||||||
//import * as utils from '../../share/utils';
|
import * as utils from '../../share/utils';
|
||||||
|
|
||||||
export default @Component({
|
export default @Component({
|
||||||
watch: {
|
watch: {
|
||||||
@@ -99,6 +127,7 @@ class StdDialog extends Vue {
|
|||||||
inputValue = '';
|
inputValue = '';
|
||||||
error = '';
|
error = '';
|
||||||
iconColor = '';
|
iconColor = '';
|
||||||
|
hotKeyCode = '';
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
if (this.$root.addKeyHook) {
|
if (this.$root.addKeyHook) {
|
||||||
@@ -117,8 +146,13 @@ class StdDialog extends Vue {
|
|||||||
this.error = '';
|
this.error = '';
|
||||||
|
|
||||||
this.iconColor = 'text-warning';
|
this.iconColor = 'text-warning';
|
||||||
if (opts && opts.type) {
|
if (opts && opts.color) {
|
||||||
this.iconColor = `text-${opts.type}`;
|
this.iconColor = `text-${opts.color}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hotKeyCode = '';
|
||||||
|
if (opts && opts.hotKeyCode) {
|
||||||
|
this.hotKeyCode = opts.hotKeyCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,6 +192,12 @@ class StdDialog extends Vue {
|
|||||||
this.$refs.dialog.shake();
|
this.$refs.dialog.shake();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.type == 'hotKey' && this.hotKeyCode == '') {
|
||||||
|
this.$refs.dialog.shake();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.ok = true;
|
this.ok = true;
|
||||||
this.$refs.dialog.hide();
|
this.$refs.dialog.hide();
|
||||||
}
|
}
|
||||||
@@ -218,9 +258,38 @@ class StdDialog extends Vue {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getHotKey(message, caption, opts) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.init(message, caption, opts);
|
||||||
|
|
||||||
|
this.hideTrigger = () => {
|
||||||
|
if (this.ok) {
|
||||||
|
resolve(this.hotKeyCode);
|
||||||
|
} else {
|
||||||
|
resolve(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.type = 'hotKey';
|
||||||
|
this.active = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
keyHook(event) {
|
keyHook(event) {
|
||||||
if (this.active && event.code == 'Enter') {
|
if (this.active) {
|
||||||
this.okClick();
|
if (this.type == 'hotKey') {
|
||||||
|
if (event.type == 'keydown') {
|
||||||
|
this.hotKeyCode = utils.keyEventToCode(event);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (event.code == 'Enter')
|
||||||
|
this.okClick();
|
||||||
|
if (event.code == 'Escape') {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.dialog.hide();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html manifest="/app/manifest.appcache">
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<title></title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
<meta name="description" content="Браузерная онлайн-читалка книг. Поддерживаются форматы: fb2, html, txt, rtf, doc, docx, pdf, epub, mobi.">
|
<meta name="description" content="Браузерная онлайн-читалка книг. Поддерживаются форматы: fb2, html, txt, rtf, doc, docx, pdf, epub, mobi.">
|
||||||
<meta name="keywords" content="онлайн,читалка,fb2,книги,читать,браузер,интернет">
|
<meta name="keywords" content="онлайн,читалка,fb2,книги,читать,браузер,интернет">
|
||||||
<title></title>
|
<script src="/sw-register.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import {QSelect} from 'quasar/src/components/select';
|
|||||||
import {QColor} from 'quasar/src/components/color';
|
import {QColor} from 'quasar/src/components/color';
|
||||||
import {QPopupProxy} from 'quasar/src/components/popup-proxy';
|
import {QPopupProxy} from 'quasar/src/components/popup-proxy';
|
||||||
import {QDialog} from 'quasar/src/components/dialog';
|
import {QDialog} from 'quasar/src/components/dialog';
|
||||||
|
import {QChip} from 'quasar/src/components/chip';
|
||||||
|
|
||||||
const components = {
|
const components = {
|
||||||
//QLayout,
|
//QLayout,
|
||||||
@@ -55,6 +56,7 @@ const components = {
|
|||||||
QColor,
|
QColor,
|
||||||
QPopupProxy,
|
QPopupProxy,
|
||||||
QDialog,
|
QDialog,
|
||||||
|
QChip,
|
||||||
};
|
};
|
||||||
|
|
||||||
//directives
|
//directives
|
||||||
|
|||||||
@@ -202,4 +202,38 @@ export function escapeXml(str) {
|
|||||||
.replace(/"/g, '"')
|
.replace(/"/g, '"')
|
||||||
.replace(/'/g, ''')
|
.replace(/'/g, ''')
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function keyEventToCode(event) {
|
||||||
|
let result = [];
|
||||||
|
let code = event.code;
|
||||||
|
|
||||||
|
const modCode = code.substring(0, 3);
|
||||||
|
if (event.metaKey && modCode != 'Met')
|
||||||
|
result.push('Meta');
|
||||||
|
if (event.ctrlKey && modCode != 'Con')
|
||||||
|
result.push('Ctrl');
|
||||||
|
if (event.shiftKey && modCode != 'Shi')
|
||||||
|
result.push('Shift');
|
||||||
|
if (event.altKey && modCode != 'Alt')
|
||||||
|
result.push('Alt');
|
||||||
|
|
||||||
|
if (modCode == 'Dig') {
|
||||||
|
code = code.substring(5, 6);
|
||||||
|
} else if (modCode == 'Key') {
|
||||||
|
code = code.substring(3, 4);
|
||||||
|
}
|
||||||
|
result.push(code);
|
||||||
|
|
||||||
|
return result.join('+');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function userHotKeysObjectSwap(userHotKeys) {
|
||||||
|
let result = {};
|
||||||
|
for (const [name, codes] of Object.entries(userHotKeys)) {
|
||||||
|
for (const code of codes) {
|
||||||
|
result[code] = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ Vue.use(Vuex);
|
|||||||
const debug = process.env.NODE_ENV !== 'production';
|
const debug = process.env.NODE_ENV !== 'production';
|
||||||
|
|
||||||
export default new Vuex.Store(Object.assign({}, root, {
|
export default new Vuex.Store(Object.assign({}, root, {
|
||||||
modules: {
|
modules: {
|
||||||
uistate,
|
uistate,
|
||||||
config,
|
config,
|
||||||
reader,
|
reader,
|
||||||
},
|
},
|
||||||
strict: debug,
|
strict: debug,
|
||||||
plugins: [createPersistedState()]
|
plugins: [createPersistedState()]
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -1,15 +1,73 @@
|
|||||||
//занчение toolButtons.name не должно совпадать с settingDefaults-propertyName
|
const readerActions = {
|
||||||
|
'help': 'Вызвать cправку',
|
||||||
|
'loader': 'На страницу загрузки',
|
||||||
|
'settings': 'Настроить',
|
||||||
|
'undoAction': 'Действие назад',
|
||||||
|
'redoAction': 'Действие вперед',
|
||||||
|
'fullScreen': 'На весь экран',
|
||||||
|
'scrolling': 'Плавный скроллинг',
|
||||||
|
'stopScrolling': '',
|
||||||
|
'setPosition': 'Установить позицию',
|
||||||
|
'search': 'Найти в тексте',
|
||||||
|
'copyText': 'Скопировать текст со страницы',
|
||||||
|
'refresh': 'Принудительно обновить книгу',
|
||||||
|
'offlineMode': 'Автономный режим (без интернета)',
|
||||||
|
'recentBooks': 'Открыть недавние',
|
||||||
|
'switchToolbar': 'Показать/скрыть панель управления',
|
||||||
|
'donate': '',
|
||||||
|
'bookBegin': 'В начало книги',
|
||||||
|
'bookEnd': 'В конец книги',
|
||||||
|
'pageBack': 'Страницу назад',
|
||||||
|
'pageForward': 'Страницу вперед',
|
||||||
|
'lineBack': 'Строчку назад',
|
||||||
|
'lineForward': 'Строчку вперед',
|
||||||
|
'incFontSize': 'Увеличить размер шрифта',
|
||||||
|
'decFontSize': 'Уменьшить размер шрифта',
|
||||||
|
'scrollingSpeedUp': 'Увеличить скорость скроллинга',
|
||||||
|
'scrollingSpeedDown': 'Уменьшить скорость скроллинга',
|
||||||
|
};
|
||||||
|
|
||||||
|
//readerActions[name]
|
||||||
const toolButtons = [
|
const toolButtons = [
|
||||||
{name: 'undoAction', show: true, text: 'Действие назад'},
|
{name: 'undoAction', show: true},
|
||||||
{name: 'redoAction', show: true, text: 'Действие вперед'},
|
{name: 'redoAction', show: true},
|
||||||
{name: 'fullScreen', show: true, text: 'На весь экран'},
|
{name: 'fullScreen', show: true},
|
||||||
{name: 'scrolling', show: false, text: 'Плавный скроллинг'},
|
{name: 'scrolling', show: false},
|
||||||
{name: 'setPosition', show: true, text: 'На страницу'},
|
{name: 'setPosition', show: true},
|
||||||
{name: 'search', show: true, text: 'Найти в тексте'},
|
{name: 'search', show: true},
|
||||||
{name: 'copyText', show: false, text: 'Скопировать текст со страницы'},
|
{name: 'copyText', show: false},
|
||||||
{name: 'refresh', show: true, text: 'Принудительно обновить книгу'},
|
{name: 'refresh', show: true},
|
||||||
{name: 'offlineMode', show: false, text: 'Автономный режим (без интернета)'},
|
{name: 'offlineMode', show: false},
|
||||||
{name: 'recentBooks', show: true, text: 'Открыть недавние'},
|
{name: 'recentBooks', show: true},
|
||||||
|
];
|
||||||
|
|
||||||
|
//readerActions[name]
|
||||||
|
const hotKeys = [
|
||||||
|
{name: 'help', codes: ['F1', 'H']},
|
||||||
|
{name: 'loader', codes: ['Escape']},
|
||||||
|
{name: 'settings', codes: ['S']},
|
||||||
|
{name: 'undoAction', codes: ['Ctrl+BracketLeft']},
|
||||||
|
{name: 'redoAction', codes: ['Ctrl+BracketRight']},
|
||||||
|
{name: 'fullScreen', codes: ['Enter', 'Backquote', 'F']},
|
||||||
|
{name: 'scrolling', codes: ['Z']},
|
||||||
|
{name: 'setPosition', codes: ['P']},
|
||||||
|
{name: 'search', codes: ['Ctrl+F']},
|
||||||
|
{name: 'copyText', codes: ['Ctrl+C']},
|
||||||
|
{name: 'refresh', codes: ['R']},
|
||||||
|
{name: 'offlineMode', codes: ['O']},
|
||||||
|
{name: 'recentBooks', codes: ['X']},
|
||||||
|
|
||||||
|
{name: 'switchToolbar', codes: ['Tab', 'Q']},
|
||||||
|
{name: 'bookBegin', codes: ['Home']},
|
||||||
|
{name: 'bookEnd', codes: ['End']},
|
||||||
|
{name: 'pageBack', codes: ['PageUp', 'ArrowLeft', 'Backspace', 'Shift+Space']},
|
||||||
|
{name: 'pageForward', codes: ['PageDown', 'ArrowRight', 'Space']},
|
||||||
|
{name: 'lineBack', codes: ['ArrowUp']},
|
||||||
|
{name: 'lineForward', codes: ['ArrowDown']},
|
||||||
|
{name: 'incFontSize', codes: ['A']},
|
||||||
|
{name: 'decFontSize', codes: ['Shift+A']},
|
||||||
|
{name: 'scrollingSpeedUp', codes: ['Shift+ArrowDown']},
|
||||||
|
{name: 'scrollingSpeedDown', codes: ['Shift+ArrowUp']},
|
||||||
];
|
];
|
||||||
|
|
||||||
const fonts = [
|
const fonts = [
|
||||||
@@ -136,6 +194,7 @@ const webFonts = [
|
|||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------------------------
|
||||||
const settingDefaults = {
|
const settingDefaults = {
|
||||||
textColor: '#000000',
|
textColor: '#000000',
|
||||||
backgroundColor: '#EBE2C9',
|
backgroundColor: '#EBE2C9',
|
||||||
@@ -188,6 +247,7 @@ const settingDefaults = {
|
|||||||
|
|
||||||
fontShifts: {},
|
fontShifts: {},
|
||||||
showToolButton: {},
|
showToolButton: {},
|
||||||
|
userHotKeys: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const font of fonts)
|
for (const font of fonts)
|
||||||
@@ -196,6 +256,8 @@ for (const font of webFonts)
|
|||||||
settingDefaults.fontShifts[font.name] = font.fontVertShift;
|
settingDefaults.fontShifts[font.name] = font.fontVertShift;
|
||||||
for (const button of toolButtons)
|
for (const button of toolButtons)
|
||||||
settingDefaults.showToolButton[button.name] = button.show;
|
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 = {
|
||||||
@@ -256,7 +318,9 @@ const mutations = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
readerActions,
|
||||||
toolButtons,
|
toolButtons,
|
||||||
|
hotKeys,
|
||||||
fonts,
|
fonts,
|
||||||
webFonts,
|
webFonts,
|
||||||
settingDefaults,
|
settingDefaults,
|
||||||
|
|||||||
48
docs/beta.omnireader/beta.omnireader
Normal file
48
docs/beta.omnireader/beta.omnireader
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
server {
|
||||||
|
listen 443 ssl; # managed by Certbot
|
||||||
|
ssl_certificate /etc/letsencrypt/live/beta.omnireader.ru/fullchain.pem; # managed by Certbot
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/beta.omnireader.ru/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.omnireader.ru;
|
||||||
|
|
||||||
|
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:34081;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /ws {
|
||||||
|
proxy_pass http://127.0.0.1:34081;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
root /home/beta.liberama/public;
|
||||||
|
|
||||||
|
location /tmp {
|
||||||
|
add_header Content-Type text/xml;
|
||||||
|
add_header Content-Encoding gzip;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~* \.(?:manifest|appcache|html)$ {
|
||||||
|
expires -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name beta.omnireader.ru;
|
||||||
|
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
4
docs/beta.omnireader/deploy.sh
Executable file
4
docs/beta.omnireader/deploy.sh
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
npm run build:linux
|
||||||
|
sudo -u www-data cp -r ../../dist/linux/* /home/beta.liberama
|
||||||
11
docs/beta.omnireader/run_server.sh
Executable file
11
docs/beta.omnireader/run_server.sh
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
sudo -H -u www-data bash -c "\
|
||||||
|
while true; do\
|
||||||
|
trap '' 2;\
|
||||||
|
cd /var/www;\
|
||||||
|
/home/beta.liberama/liberama;\
|
||||||
|
trap 2;\
|
||||||
|
echo \"Restart after 5 sec. Press Ctrl+C to exit.\";\
|
||||||
|
sleep 5;\
|
||||||
|
done;"
|
||||||
988
package-lock.json
generated
988
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Liberama",
|
"name": "Liberama",
|
||||||
"version": "0.9.1",
|
"version": "0.9.2",
|
||||||
"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",
|
||||||
@@ -41,6 +41,7 @@
|
|||||||
"mini-css-extract-plugin": "^0.5.0",
|
"mini-css-extract-plugin": "^0.5.0",
|
||||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||||
"pkg": "^4.4.4",
|
"pkg": "^4.4.4",
|
||||||
|
"sw-precache-webpack-plugin": "^1.0.0",
|
||||||
"terser-webpack-plugin": "^1.4.1",
|
"terser-webpack-plugin": "^1.4.1",
|
||||||
"url-loader": "^1.1.2",
|
"url-loader": "^1.1.2",
|
||||||
"vue-class-component": "^6.3.2",
|
"vue-class-component": "^6.3.2",
|
||||||
@@ -55,7 +56,6 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@quasar/extras": "^1.5.2",
|
"@quasar/extras": "^1.5.2",
|
||||||
"appcache-webpack-plugin": "^1.4.0",
|
|
||||||
"axios": "^0.18.1",
|
"axios": "^0.18.1",
|
||||||
"base-x": "^3.0.8",
|
"base-x": "^3.0.8",
|
||||||
"chardet": "^0.7.0",
|
"chardet": "^0.7.0",
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
"multer": "^1.4.2",
|
"multer": "^1.4.2",
|
||||||
"pako": "^1.0.11",
|
"pako": "^1.0.11",
|
||||||
"path-browserify": "^1.0.0",
|
"path-browserify": "^1.0.0",
|
||||||
"quasar": "^1.9.6",
|
"quasar": "^1.9.7",
|
||||||
"safe-buffer": "^5.2.0",
|
"safe-buffer": "^5.2.0",
|
||||||
"sjcl": "^1.0.8",
|
"sjcl": "^1.0.8",
|
||||||
"sql-template-strings": "^2.2.2",
|
"sql-template-strings": "^2.2.2",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const signatures = require('./signatures.json');
|
|||||||
class FileDetector {
|
class FileDetector {
|
||||||
detectFile(filename) {
|
detectFile(filename) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.fromFile(filename, 2000, (err, result) => {
|
this.fromFile(filename, 10000, (err, result) => {
|
||||||
if (err) reject(err);
|
if (err) reject(err);
|
||||||
resolve(result);
|
resolve(result);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -653,40 +653,6 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
|
||||||
"type": "svg",
|
|
||||||
"ext": "svg",
|
|
||||||
"mime": "image/svg+xml",
|
|
||||||
"rules": [
|
|
||||||
{ "type": "contains", "bytes": "3c737667" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"type": "html",
|
|
||||||
"ext": "html",
|
|
||||||
"mime": "text/html",
|
|
||||||
"rules": [
|
|
||||||
{ "type": "or", "rules":
|
|
||||||
[
|
|
||||||
{ "type": "contains", "bytes": "3c68746d6c" },
|
|
||||||
{ "type": "contains", "bytes": "3c00680074006d006c00" },
|
|
||||||
{ "type": "equal", "end": 5, "bytes": "3c68746d6c" },
|
|
||||||
{ "type": "equal", "end": 10, "bytes": "3c00680074006d006c00" },
|
|
||||||
{ "type": "equal", "end": 9, "bytes": "3c21646f6374797065" },
|
|
||||||
{ "type": "equal", "end": 5, "bytes": "3c626f6479" },
|
|
||||||
{ "type": "equal", "end": 5, "bytes": "3c68656164" },
|
|
||||||
{ "type": "equal", "end": 7, "bytes": "3c696672616d65" },
|
|
||||||
{ "type": "equal", "end": 4, "bytes": "3c696d67" },
|
|
||||||
{ "type": "equal", "end": 7, "bytes": "3c6f626a656374" },
|
|
||||||
{ "type": "equal", "end": 7, "bytes": "3c736372697074" },
|
|
||||||
{ "type": "equal", "end": 6, "bytes": "3c7461626c65" },
|
|
||||||
{ "type": "equal", "end": 6, "bytes": "3c7469746c65" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
"type": "docx",
|
"type": "docx",
|
||||||
"ext": "docx",
|
"ext": "docx",
|
||||||
@@ -721,6 +687,43 @@
|
|||||||
"rules": [
|
"rules": [
|
||||||
{ "type": "equal", "start": 64, "end": 68, "bytes": "4d4f4249" }
|
{ "type": "equal", "start": 64, "end": 68, "bytes": "4d4f4249" }
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "html",
|
||||||
|
"ext": "html",
|
||||||
|
"mime": "text/html",
|
||||||
|
"rules": [
|
||||||
|
{ "type": "or", "rules":
|
||||||
|
[
|
||||||
|
{ "type": "contains", "bytes": "3c68746d6c" },
|
||||||
|
{ "type": "contains", "bytes": "3c00680074006d006c00" },
|
||||||
|
{ "type": "contains", "bytes": "3c48544d4c" },
|
||||||
|
{ "type": "contains", "bytes": "3c00480054004d004c00" },
|
||||||
|
|
||||||
|
{ "type": "equal", "end": 5, "bytes": "3c68746d6c" },
|
||||||
|
{ "type": "equal", "end": 10, "bytes": "3c00680074006d006c00" },
|
||||||
|
{ "type": "equal", "end": 9, "bytes": "3c21646f6374797065" },
|
||||||
|
{ "type": "equal", "end": 9, "bytes": "3c21444f4354595045" },
|
||||||
|
{ "type": "equal", "end": 5, "bytes": "3c626f6479" },
|
||||||
|
{ "type": "equal", "end": 5, "bytes": "3c68656164" },
|
||||||
|
{ "type": "equal", "end": 7, "bytes": "3c696672616d65" },
|
||||||
|
{ "type": "equal", "end": 4, "bytes": "3c696d67" },
|
||||||
|
{ "type": "equal", "end": 7, "bytes": "3c6f626a656374" },
|
||||||
|
{ "type": "equal", "end": 7, "bytes": "3c736372697074" },
|
||||||
|
{ "type": "equal", "end": 6, "bytes": "3c7461626c65" },
|
||||||
|
{ "type": "equal", "end": 6, "bytes": "3c7469746c65" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "svg",
|
||||||
|
"ext": "svg",
|
||||||
|
"mime": "image/svg+xml",
|
||||||
|
"rules": [
|
||||||
|
{ "type": "contains", "bytes": "3c737667" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user