Files
liberama/client/components/Reader/Reader.vue
2019-01-15 22:01:19 +07:00

356 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<el-container>
<el-header height='50px'>
<div class="header">
<el-tooltip content="Загрузить книгу" :open-delay="1000" effect="light">
<el-button class="tool-button" :class="buttonActiveClass('loader')" @click="buttonClick('loader')"><i class="el-icon-back"></i></el-button>
</el-tooltip>
<div>
<el-tooltip content="Действие назад" :open-delay="1000" effect="light">
<el-button class="tool-button" @click="buttonClick('undoAction')" ><i class="el-icon-arrow-left"></i></el-button>
</el-tooltip>
<el-tooltip content="Действие вперед" :open-delay="1000" effect="light">
<el-button class="tool-button" @click="buttonClick('redoAction')" ><i class="el-icon-arrow-right"></i></el-button>
</el-tooltip>
<div class="space"></div>
<el-tooltip content="На весь экран" :open-delay="1000" effect="light">
<el-button class="tool-button" :class="buttonActiveClass('fullscreen')" @click="buttonClick('fullscreen')"><i class="el-icon-rank"></i></el-button>
</el-tooltip>
<el-tooltip content="Прокрутка книги" :open-delay="1000" effect="light">
<el-button class="tool-button" @click="buttonClick('setPosition')"><i class="el-icon-d-arrow-right"></i></el-button>
</el-tooltip>
<el-tooltip content="Плавный скроллинг" :open-delay="1000" effect="light">
<el-button class="tool-button" @click="buttonClick('scrolling')"><i class="el-icon-sort"></i></el-button>
</el-tooltip>
<el-tooltip content="Найти в тексте" :open-delay="1000" effect="light">
<el-button class="tool-button" @click="buttonClick('search')"><i class="el-icon-search"></i></el-button>
</el-tooltip>
<el-tooltip content="Принудительно обновить книгу в обход кеша" :open-delay="1000" effect="light">
<el-button class="tool-button" @click="buttonClick('refresh')"><i class="el-icon-refresh"></i></el-button>
</el-tooltip>
<div class="space"></div>
<el-tooltip content="История" :open-delay="1000" effect="light">
<el-button class="tool-button" @click="buttonClick('history')"><i class="el-icon-document"></i></el-button>
</el-tooltip>
</div>
<el-tooltip content="Настроить" :open-delay="1000" effect="light">
<el-button class="tool-button" @click="buttonClick('settings')"><i class="el-icon-setting"></i></el-button>
</el-tooltip>
</div>
</el-header>
<pre>{{ lastOpenedBook }}</pre>
<el-main>
<keep-alive>
<component ref="page" :is="pageActive" @load-book="loadBook" @book-pos-changed="bookPosChanged"></component>
</keep-alive>
</el-main>
</el-container>
</template>
<script>
//-----------------------------------------------------------------------------
import Vue from 'vue';
import Component from 'vue-class-component';
import LoaderPage from './LoaderPage/LoaderPage.vue';
import TextPage from './TextPage/TextPage.vue';
import ProgressPage from './ProgressPage/ProgressPage.vue';
import bookManager from './share/bookManager';
import readerApi from '../../api/reader';
export default @Component({
components: {
LoaderPage,
TextPage,
ProgressPage
},
watch: {
bookPos: function(newValue) {
if (newValue !== undefined && this.pageActive == 'TextPage') {
const textPage = this.$refs.page;
if (textPage.bookPos != newValue) {
textPage.bookPos = newValue;
this.commit('reader/setOpenedBook', Object.assign({}, this.lastOpenedBook, {bookPos: newValue}));
}
}
},
routeParamPos: function(newValue) {
if (newValue !== undefined && newValue != this.bookPos) {
this.bookPos = newValue;
}
},
routeParamUrl: function(newValue) {
if (newValue !== '' && newValue !== this.lastOpenedBook.url) {
this.loadBook({url: newValue, bookPos: this.routeParamPos});
}
}
},
})
class Reader extends Vue {
loaderActive = false;
progressActive = false;
bookPos = null;
created() {
this.commit = this.$store.commit;
this.dispatch = this.$store.dispatch;
this.reader = this.$store.state.reader;
this.$root.addKeyHook(this.keyHook);
this.lastActivePage = false;
}
mounted() {
/*while (this.lastOpenedBook) {
this.commit('reader/delOpenedBook', this.lastOpenedBook);
}*/
if (this.$root.rootRoute == '/reader') {
if (this.routeParamUrl) {
this.loadBook({url: this.routeParamUrl, bookPos: this.routeParamPos});
} else if (this.lastOpenedBook) {
this.loadBook({url: this.lastOpenedBook.url});
} else {
this.loaderActive = true;
}
}
}
get routeParamPos() {
let result = undefined;
const q = this.$route.query;
if (q['__p']) {
result = q['__p'];
if (Array.isArray(result))
result = result[0];
}
return (result ? parseInt(result, 10) || 0 : result);
}
updateRoute(isNewRoute) {
const pos = (this.bookPos != undefined ? `__p=${this.bookPos}&` : '');
if (isNewRoute)
this.$router.push(`/reader?${pos}url=${this.lastOpenedBook.url}`);
else
this.$router.replace(`/reader?${pos}url=${this.lastOpenedBook.url}`);
}
get routeParamUrl() {
let result = '';
const path = this.$route.fullPath;
const i = path.indexOf('url=');
if (i >= 0) {
result = path.substr(i + 4);
}
return decodeURIComponent(result);
}
bookPosChanged(event) {
this.bookPos = event.bookPos;
this.updateRoute();
}
get fullScreenActive() {
return this.reader.fullScreenActive;
}
get lastOpenedBook() {
return this.$store.getters['reader/lastOpenedBook'];
}
buttonClick(button) {
switch (button) {
case 'loader': this.loaderActive = !this.loaderActive; break;
case 'fullscreen': this.commit('reader/setFullScreenActive', !this.fullScreenActive); break;
}
}
buttonActiveClass(button) {
const classActive = { 'tool-button-active': true, 'tool-button-active:hover': true };
switch (button) {
case 'loader': return (this.loaderActive ? classActive : {});
case 'fullscreen': return (this.fullScreenActive ? classActive : {});
}
return {};
}
get pageActive() {
let result = '';
if (this.progressActive)
result = 'ProgressPage';
else if (this.loaderActive)
result = 'LoaderPage';
else if (this.lastOpenedBook)
result = 'TextPage';
if (!result) {
this.loaderActive = true;
result = 'LoaderPage';
}
if (result != 'TextPage') {
this.$root.$emit('set-app-title');
}
if (this.lastActivePage != result && result == 'TextPage') {
//акивируем страницу с текстом
this.$nextTick(async() => {
const last = this.lastOpenedBook;
const isParsed = await bookManager.hasBookParsed(last);
if (!isParsed) {
this.$root.$emit('set-app-title');
return;
}
this.updateRoute();
const textPage = this.$refs.page;
if (textPage.showBook) {
textPage.lastBook = last;
textPage.bookPos = (last.bookPos !== undefined ? last.bookPos : 0);
textPage.showBook();
}
});
}
this.lastActivePage = result;
return result;
}
loadBook(opts) {
this.progressActive = true;
this.$nextTick(async() => {
const progress = this.$refs.page;
try {
progress.show();
progress.setState({state: 'parse'});
const key = bookManager.keyFromUrl(opts.url);
let wasOpened = this.reader.openedBook[key];
wasOpened = (wasOpened ? wasOpened : {});
const bookPos = (opts.bookPos !== undefined ? opts.bookPos : wasOpened.bookPos);
const bookParsed = await bookManager.getBook({url: opts.url}, (prog) => {
progress.setState({progress: prog});
});
if (bookParsed) {
this.commit('reader/setOpenedBook', Object.assign({bookPos}, bookManager.metaOnly(bookParsed)));
this.loaderActive = false;
progress.hide(); this.progressActive = false;
return;
}
progress.setState({totalSteps: 5});
const book = await readerApi.loadBook(opts.url, (state) => {
progress.setState(state);
});
progress.setState({state: 'parse', step: 5});
const addedBook = await bookManager.addBook(book, (prog) => {
progress.setState({progress: prog});
});
this.commit('reader/setOpenedBook', Object.assign({bookPos}, bookManager.metaOnly(addedBook)));
this.updateRoute(true);
this.loaderActive = false;
progress.hide(); this.progressActive = false;
} catch (e) {
progress.hide(); this.progressActive = false;
this.loaderActive = true;
this.$alert(e.message, 'Ошибка', {type: 'error'});
}
});
}
keyHook(event) {
if (this.$root.rootRoute == '/reader') {
if (this.$refs.page && this.$refs.page.keyHook)
this.$refs.page.keyHook(event);
}
}
}
//-----------------------------------------------------------------------------
</script>
<style scoped>
.el-container {
padding: 0;
margin: 0;
height: 100%;
}
.el-header {
padding-left: 5px;
padding-right: 5px;
background-color: #1B695F;
color: #000;
overflow-x: auto;
overflow-y: hidden;
}
.header {
display: flex;
justify-content: space-between;
min-width: 500px;
}
.el-main {
display: flex;
padding: 0;
margin: 0;
background-color: #EBE2C9;
color: #000;
}
.tool-button {
margin: 0;
margin-left: 2px;
margin-right: 2px;
padding: 0;
color: #3E843E;
background-color: #E6EDF4;
margin-top: 5px;
height: 38px;
width: 38px;
border: 0;
box-shadow: 3px 3px 5px black;
}
.tool-button:hover {
background-color: white;
}
.tool-button-active {
box-shadow: 0 0 0;
color: white;
background-color: #8AB45F;
position: relative;
top: 1px;
left: 1px;
}
.tool-button-active:hover {
color: white;
background-color: #81C581;
}
i {
font-size: 200%;
}
.space {
width: 10px;
display: inline-block;
}
</style>