diff --git a/client/components/Reader/ProgressPage/ProgressPage.vue b/client/components/Reader/ProgressPage/ProgressPage.vue index 86785de8..8ebd77eb 100644 --- a/client/components/Reader/ProgressPage/ProgressPage.vue +++ b/client/components/Reader/ProgressPage/ProgressPage.vue @@ -11,7 +11,6 @@ //----------------------------------------------------------------------------- import Vue from 'vue'; import Component from 'vue-class-component'; -import {sleep} from '../../../share/utils'; const ruMessage = { 'start': ' ', @@ -33,7 +32,7 @@ class ProgressPage extends Vue { progress = 0; visible = false; - async show() { + show() { this.$el.style.width = this.$parent.$el.offsetWidth + 'px'; this.$el.style.height = this.$parent.$el.offsetHeight + 'px'; this.text = ''; @@ -42,14 +41,10 @@ class ProgressPage extends Vue { this.progress = 0; this.visible = true; - await sleep(1); - return true; } async hide() { - await sleep(350); this.visible = false; - return false; } setState(state) { @@ -57,10 +52,13 @@ class ProgressPage extends Vue { this.text = (ruMessage[state.state] ? ruMessage[state.state] : state.state); this.step = (state.step ? state.step : this.step); this.totalSteps = (state.totalSteps > this.totalSteps ? state.totalSteps : this.totalSteps); - this.progress = (state.progress ? state.progress : this.progress); + this.progress = state.progress || 0; } get percentage() { + let circle = document.querySelector('path[class="el-progress-circle__path"]'); + if (circle) + circle.style.transition = ''; return Math.round(((this.step - 1)/this.totalSteps + this.progress/(100*this.totalSteps))*100); } } diff --git a/client/components/Reader/Reader.vue b/client/components/Reader/Reader.vue index 52d239b2..8a35ac66 100644 --- a/client/components/Reader/Reader.vue +++ b/client/components/Reader/Reader.vue @@ -127,7 +127,7 @@ class Reader extends Vue { this.progressActive = true; this.$nextTick(async() => { const progress = this.$refs.page; - await progress.show(); + progress.show(); progress.setState({totalSteps: 5}); try { @@ -135,7 +135,7 @@ class Reader extends Vue { progress.setState(state); }); - progress.setState({state: 'parse', step: 5, progress: 0}); + progress.setState({state: 'parse', step: 5}); const addedBook = await bookManager.addBook(book, (prog) => { progress.setState({progress: prog}); }); @@ -143,9 +143,9 @@ class Reader extends Vue { this.commit('reader/addOpenedBook', bookManager.metaOnly(addedBook)); this.commit('reader/setLoaderActive', false); - this.progressActive = await progress.hide(); + progress.hide(); this.progressActive = false; } catch (e) { - this.progressActive = await progress.hide(); + progress.hide(); this.progressActive = false; this.$alert(e.message, 'Ошибка', {type: 'error'}); } }); diff --git a/client/components/Reader/TextPage/TextPage.vue b/client/components/Reader/TextPage/TextPage.vue index 2abf7c5a..4d1c3dde 100644 --- a/client/components/Reader/TextPage/TextPage.vue +++ b/client/components/Reader/TextPage/TextPage.vue @@ -1,6 +1,7 @@ diff --git a/client/components/Reader/share/BookParser.js b/client/components/Reader/share/BookParser.js index 2137ae1f..6da93e36 100644 --- a/client/components/Reader/share/BookParser.js +++ b/client/components/Reader/share/BookParser.js @@ -1,12 +1,69 @@ +import EasySAXParser from './easysax'; +import {sleep} from '../../../share/utils'; + export default class BookParser { constructor() { + this.parser = new EasySAXParser(); } async parse(data, callback) { + if (!callback) + callback = () => {}; + callback(0); + this.data = data; - + + if (data.indexOf(' {// eslint-disable-line no-unused-vars + }); + + parser.on('startNode', (elemName, getAttr, isTagEnd, getStrNode) => {// eslint-disable-line no-unused-vars + //console.log(elemName, ' start'); + }); + + parser.on('endNode', (elemName, isTagStart, getStrNode) => {// eslint-disable-line no-unused-vars + //console.log(elemName, ' end'); + }); + + parser.on('textNode', (text) => {// eslint-disable-line no-unused-vars + //console.log(text); + }); + + parser.on('cdata', (data) => {// eslint-disable-line no-unused-vars + }); + + parser.on('comment', (text) => {// eslint-disable-line no-unused-vars + }); + + parser.on('progress', async(progress) => { + if (progress > nextPerc) { + await sleep(1); + callback(progress); + nextPerc += 10; + } + }); + + await parser.parse(data); if (callback) callback(100); - return {author: 'Захарова Елена', title: 'Возвращение'}; + + return result; } } \ No newline at end of file diff --git a/client/components/Reader/share/easysax.js b/client/components/Reader/share/easysax.js index fa2444b6..6d4f4ff9 100644 --- a/client/components/Reader/share/easysax.js +++ b/client/components/Reader/share/easysax.js @@ -52,12 +52,12 @@ export default EasySAXParser; var stringFromCharCode = String.fromCharCode; var objectCreate = Object.create; -function NULL_FUNC() {}; +function NULL_FUNC() {} function entity2char(x) { if (x === 'amp') { return '&'; - }; + } switch(x.toLocaleLowerCase()) { case 'quot': return '"'; @@ -77,25 +77,25 @@ function entity2char(x) { case 'reg': return '\u00AE'; case 'deg': return '\u00B0'; case 'apos': return '\''; - }; + } return '&' + x + ';'; -}; +} function replaceEntities(s, d, x, z) { if (z) { return entity2char(z); - }; + } if (d) { return stringFromCharCode(d); - }; + } return stringFromCharCode(parseInt(x, 16)); -}; +} function xmlEntityDecode(s) { - var s = ('' + s); + s = ('' + s); if (s.length > 3 && s.indexOf('&') !== -1) { if (s.indexOf('<') !== -1) {s = s.replace(/</g, '<');} @@ -104,28 +104,29 @@ function xmlEntityDecode(s) { if (s.indexOf('&') !== -1) { s = s.replace(/&#(\d+);|&#x([0123456789abcdef]+);|&(\w+);/ig, replaceEntities); - }; - }; + } + } return s; -}; +} function cloneMatrixNS(nsmatrix) { var nn = objectCreate(null); for (var n in nsmatrix) { nn[n] = nsmatrix[n]; - }; + } return nn; -}; +} function EasySAXParser(config) { if (!this) { return null; - }; + } - var onTextNode = NULL_FUNC, onStartNode = NULL_FUNC, onEndNode = NULL_FUNC, onCDATA = NULL_FUNC, onError = NULL_FUNC, onComment, onQuestion, onAttention, onUnknownNS; - var is_onComment = false, is_onQuestion = false, is_onAttention = false, is_onUnknownNS = false; + var onTextNode = NULL_FUNC, onStartNode = NULL_FUNC, onEndNode = NULL_FUNC, onCDATA = NULL_FUNC, onError = NULL_FUNC, + onComment, onQuestion, onAttention, onUnknownNS, onProgress; + var is_onComment = false, is_onQuestion = false, is_onAttention = false, is_onUnknownNS = false, is_onProgress = false; var isAutoEntity = true; // делать "EntityDecode" всегда var entityDecode = xmlEntityDecode; @@ -139,7 +140,7 @@ function EasySAXParser(config) { var xml = ''; // string - this.setup = function (op) { + this.setup = function(op) { for (var name in op) { switch(name) { case 'entityDecode': entityDecode = op.entityDecode || entityDecode; break; @@ -150,18 +151,18 @@ function EasySAXParser(config) { var listeners = op.on; for (var ev in listeners) { this.on(ev, listeners[ev]); - }; + } break; - }; - }; + } + } }; this.on = function(name, cb) { if (typeof cb !== 'function') { if (cb !== null) { - throw error('required args on(string, function||null)'); - }; - }; + throw Error('required args on(string, function||null)'); + } + } switch(name) { case 'startNode': onStartNode = cb || NULL_FUNC; break; @@ -174,7 +175,8 @@ function EasySAXParser(config) { case 'attention': onAttention = cb; is_onAttention = !!cb; break; // case 'question': onQuestion = cb; is_onQuestion = !!cb; break; // case 'comment': onComment = cb; is_onComment = !!cb; break; - }; + case 'progress': onProgress = cb; is_onProgress = !!cb; break; + } }; this.ns = function(root, ns) { @@ -183,11 +185,11 @@ function EasySAXParser(config) { defaultNS = null; useNS = null; return this; - }; + } if (!ns || typeof root !== 'string') { - throw error('required args ns(string, object)'); - }; + throw Error('required args ns(string, object)'); + } isNamespace = !!(useNS = ns || null); defaultNS = root || null; @@ -195,10 +197,10 @@ function EasySAXParser(config) { return this; }; - this.parse = function(_xml) { + this.parse = async function(_xml) { if (typeof _xml !== 'string') { return 'required args parser(string)'; // error - }; + } returnError = null; xml = _xml; @@ -207,13 +209,13 @@ function EasySAXParser(config) { nsmatrix = objectCreate(null); nsmatrix.xmlns = defaultNS; - parse(); + await parse(); nsmatrix = null; } else { - parse(); - }; + await parse(); + } parseStop = false; attrRes = true; @@ -228,7 +230,7 @@ function EasySAXParser(config) { if (config) { this.setup(config); - }; + } // ----------------------------------------------------- @@ -250,7 +252,7 @@ function EasySAXParser(config) { function getAttrs() { if (attrRes !== null) { return attrRes; - }; + } var xmlnsAlias; var nsAttrName; @@ -274,34 +276,34 @@ function EasySAXParser(config) { if (w === 32 || (w < 14 && w > 8) ) { // \f\n\r\t\v continue - }; + } if (w < 65 || w > 122 || (w > 90 && w < 97) ) { // недопустимые первые символы if (w !== 95 && w !== 58) { // char 95"_" 58":" return attrRes = false; // error. invalid first char - }; - }; + } + } for(j = i + 1; j < l; j++) { // проверяем все символы имени атрибута w = s.charCodeAt(j); if ( w > 96 && w < 123 || w > 64 && w < 91 || w > 47 && w < 59 || w === 45 || w === 95) { continue; - }; + } if (w !== 61) { // "=" == 61 return attrRes = false; // error. invalid char "=" - }; + } break; - }; + } name = s.substring(i, j); ok = true; if (name === 'xmlns:xmlns') { return attrRes = false; // error. invalid name - }; + } w = s.charCodeAt(j + 1); @@ -311,14 +313,14 @@ function EasySAXParser(config) { } else { if (w !== 39) { // "'" return attrRes = false; // error. invalid char - }; + } j = s.indexOf('\'', i = j + 2 ); - }; + } if (j === -1) { return attrRes = false; // error. invalid char - }; + } if (j + 1 < l) { w = s.charCodeAt(j + 1); @@ -326,8 +328,8 @@ function EasySAXParser(config) { if (w > 32 || w < 9 || (w < 32 && w > 13)) { // error. invalid char return attrRes = false; - }; - }; + } + } value = s.substring(i, j); @@ -335,12 +337,12 @@ function EasySAXParser(config) { if (isAutoEntity) { value = entityDecode(value); - }; + } if (!isNamespace) { // res[name] = value; continue; - }; + } if (hasSurmiseNS) { // есть подозрение что в атрибутах присутствует xmlns @@ -353,52 +355,53 @@ function EasySAXParser(config) { alias = useNS[entityDecode(value)]; if (is_onUnknownNS && !alias) { alias = onUnknownNS(value); - }; + } if (alias) { if (nsmatrix[newalias] !== alias) { if (!hasNewMatrix) { nsmatrix = cloneMatrixNS(nsmatrix); hasNewMatrix = true; - }; + } nsmatrix[newalias] = alias; - }; + } } else { if (nsmatrix[newalias]) { if (!hasNewMatrix) { nsmatrix = cloneMatrixNS(nsmatrix); hasNewMatrix = true; - }; + } nsmatrix[newalias] = false; - }; - }; + } + } res[name] = value; continue; - }; + } attrList.push(name, value); continue; - }; + } w = name.indexOf(':'); if (w === -1) { res[name] = value; continue; - }; + } - if (nsAttrName = nsmatrix[name.substring(0, w)]) { + nsAttrName = nsmatrix[name.substring(0, w)]; + if (nsAttrName) { nsAttrName = nsmatrix['xmlns'] === nsAttrName ? name.substr(w + 1) : nsAttrName + name.substr(w); res[nsAttrName + name.substr(w)] = value; - }; - }; + } + } if (!ok) { return attrRes = true; // атрибутов нет, ошибок тоже нет - }; + } if (hasSurmiseNS) { xmlnsAlias = nsmatrix['xmlns']; @@ -408,25 +411,26 @@ function EasySAXParser(config) { w = name.indexOf(':'); if (w !== -1) { - if (nsAttrName = nsmatrix[name.substring(0, w)]) { + nsAttrName = nsmatrix[name.substring(0, w)]; + if (nsAttrName) { nsAttrName = xmlnsAlias === nsAttrName ? name.substr(w + 1) : nsAttrName + name.substr(w); res[nsAttrName] = attrList[i]; - }; + } continue; - }; + } res[name] = attrList[i]; - }; - }; + } + } return attrRes = res; - }; + } function getStringNode() { return xml.substring(stringNodePosStart, stringNodePosEnd + 1); - }; + } - function parse() { + async function parse() { var stacknsmatrix = []; var nodestack = []; var stopIndex = 0; @@ -439,7 +443,9 @@ function EasySAXParser(config) { var xmlns; var elem; var stop; // используется при разборе "namespace" . если встретился неизвестное пространство то события не генерируются - + var xmlLength = xml.length; + var progStep = xmlLength/100; + var progCur = 0; while(j !== -1) { stop = stopIndex > 0; @@ -448,28 +454,28 @@ function EasySAXParser(config) { i = j; } else { i = xml.indexOf('<', j); - }; + } if (i === -1) { // конец разбора if (nodestack.length) { onError(returnError = 'unexpected end parse'); return; - }; + } if (j === 0) { onError(returnError = 'missing first tag'); return; - }; + } return; - }; + } if (j !== i && !stop) { onTextNode(isAutoEntity ? entityDecode(xml.substring(j, i)) : xml.substring(j, i)); if (parseStop) { return; - }; - }; + } + } w = xml.charCodeAt(i+1); @@ -480,18 +486,18 @@ function EasySAXParser(config) { if (j === -1) { onError(returnError = 'cdata'); return; - }; + } if (!stop) { onCDATA(xml.substring(i + 9, j)); if (parseStop) { return; - }; - }; + } + } j += 3; continue; - }; + } if (w === 45 && xml.charCodeAt(i + 3) === 45) { // 45 == "-" @@ -499,61 +505,61 @@ function EasySAXParser(config) { if (j === -1) { onError(returnError = 'expected -->'); return; - }; + } if (is_onComment && !stop) { onComment(isAutoEntity ? entityDecode(xml.substring(i + 4, j)) : xml.substring(i + 4, j)); if (parseStop) { return; - }; - }; + } + } j += 3; continue; - }; + } j = xml.indexOf('>', i + 1); if (j === -1) { onError(returnError = 'expected ">"'); return; - }; + } if (is_onAttention && !stop) { onAttention(xml.substring(i, j + 1)); if (parseStop) { return; - }; - }; + } + } j += 1; continue; - }; + } if (w === 63) { // "?" j = xml.indexOf('?>', i); if (j === -1) { // error onError(returnError = '...?>'); return; - }; + } if (is_onQuestion) { onQuestion(xml.substring(i, j + 2)); if (parseStop) { return; - }; - }; + } + } j += 2; continue; - }; + } j = xml.indexOf('>', i + 1); if (j == -1) { // error onError(returnError = 'unclosed tag'); // ...> return; - }; + } attrRes = true; // атрибутов нет @@ -566,7 +572,7 @@ function EasySAXParser(config) { if (!nodestack.length) { onError(returnError = 'close tag, requires open tag'); return; - }; + } x = elem = nodestack.pop(); q = i + 2 + elem.length; @@ -574,7 +580,7 @@ function EasySAXParser(config) { if (elem !== xml.substring(i + 2, q)) { onError(returnError = 'close tag, not equal to the open tag'); return; - }; + } // проверим что в закрываюшем теге нет лишнего for(; q < j; q++) { @@ -582,11 +588,11 @@ function EasySAXParser(config) { if (w === 32 || (w > 8 && w < 14)) { // \f\n\r\t\v пробел continue; - }; + } onError(returnError = 'close tag'); return; - }; + } } else { if (xml.charCodeAt(j - 1) === 47) { // .../> @@ -600,34 +606,34 @@ function EasySAXParser(config) { isTagStart = true; isTagEnd = false; - }; + } if (!(w > 96 && w < 123 || w > 64 && w < 91 || w === 95 || w === 58)) { // char 95"_" 58":" onError(returnError = 'first char nodeName'); return; - }; + } for (q = 1, y = x.length; q < y; q++) { w = x.charCodeAt(q); if (w > 96 && w < 123 || w > 64 && w < 91 || w > 47 && w < 59 || w === 45 || w === 95) { continue; - }; + } if (w === 32 || (w < 14 && w > 8)) { // \f\n\r\t\v пробел attrRes = null; // возможно есть атирибуты elem = x.substring(0, q) break; - }; + } onError(returnError = 'invalid nodeName'); return; - }; + } if (!isTagEnd) { nodestack.push(elem); - }; - }; + } + } if (isNamespace) { @@ -636,33 +642,34 @@ function EasySAXParser(config) { if (!isTagStart) { if (--stopIndex === 0) { nsmatrix = stacknsmatrix.pop(); - }; - }; + } + } } else { stopIndex += 1; - }; + } j += 1; continue; - }; + } // добавляем в stacknsmatrix только если !isTagEnd, иначе сохраняем контекст пространств в переменной _nsmatrix = nsmatrix; if (!isTagEnd) { stacknsmatrix.push(nsmatrix); - }; + } if (isTagStart && (attrRes === null)) { - if (hasSurmiseNS = x.indexOf('xmlns', q) !== -1) { // есть подозрение на xmlns + hasSurmiseNS = x.indexOf('xmlns', q) !== -1; + if (hasSurmiseNS) { // есть подозрение на xmlns attrStartPos = q; attrString = x; getAttrs(); hasSurmiseNS = false; - }; - }; + } + } w = elem.indexOf(':'); if (w !== -1) { @@ -671,7 +678,7 @@ function EasySAXParser(config) { } else { xmlns = nsmatrix.xmlns; - }; + } if (!xmlns) { @@ -680,14 +687,14 @@ function EasySAXParser(config) { nsmatrix = _nsmatrix; // так как тут всегда isTagStart } else { stopIndex = 1; // первый элемент для которого не определено пространство имен - }; + } j += 1; continue; - }; + } elem = xmlns + ':' + elem; - }; + } stringNodePosStart = i; stringNodePosEnd = j; @@ -699,25 +706,31 @@ function EasySAXParser(config) { onStartNode(elem, getAttrs, isTagEnd, getStringNode); if (parseStop) { return; - }; - }; + } + } if (isTagEnd) { onEndNode(elem, isTagStart, getStringNode); if (parseStop) { return; - }; + } if (isNamespace) { if (isTagStart) { nsmatrix = _nsmatrix; } else { nsmatrix = stacknsmatrix.pop(); - }; - }; - }; + } + } + } j += 1; - }; - }; -}; + + if (j > progCur) { + if (is_onProgress) + await onProgress(Math.round(j*100/xmlLength)); + progCur += progStep; + } + } + } +} diff --git a/server/core/BookConverter.js b/server/core/BookConverter.js index 31668c63..6edac3bd 100644 --- a/server/core/BookConverter.js +++ b/server/core/BookConverter.js @@ -12,7 +12,7 @@ class BookConverter { if (fileType && (fileType.ext == 'html' || fileType.ext == 'xml')) { const data = await fs.readFile(inputFile, 'utf8'); - if (data.indexOf('FictionBook') >= 0) { + if (data.indexOf('= 0) { await fs.writeFile(outputFile, data); return; }