Merge branch 'release/0.3.3'

This commit is contained in:
Book Pauk
2019-02-19 02:37:29 +07:00
8 changed files with 171 additions and 18 deletions

View File

@@ -4,7 +4,7 @@
<ul>
<li><b>F1, H</b> - открыть справку</li>
<li><b>Escape</b> - показать/скрыть страницу загрузки</li>
<li><b>Tab</b> - показать/скрыть панель управления</li>
<li><b>Tab, Q</b> - показать/скрыть панель управления</li>
<li><b>PageUp, Left, Shift+Space, Backspace</b> - страницу назад</li>
<li><b>PageDown, Right, Space</b> - страницу вперед</li>
<li><b>Home</b> - в начало книги</li>

View File

@@ -103,6 +103,13 @@ class LoaderPage extends Vue {
event.stopPropagation();
return true;
}
if (event.type == 'keydown' && (document.activeElement !== input && event.code == 'KeyQ')) {
this.$emit('tool-bar-toggle');
event.preventDefault();
event.stopPropagation();
return true;
}
}
}
//-----------------------------------------------------------------------------

View File

@@ -930,6 +930,7 @@ class TextPage extends Vue {
this.$emit('full-screen-toogle');
break;
case 'Tab':
case 'KeyQ':
this.doToolBarToggle();
event.preventDefault();
event.stopPropagation();

View File

@@ -2,6 +2,8 @@ import he from 'he';
import sax from '../../../../server/core/BookConverter/sax';
import {sleep} from '../../../share/utils';
const maxImageLineCount = 100;
export default class BookParser {
constructor() {
// defaults
@@ -37,6 +39,10 @@ export default class BookParser {
let center = false;
let bold = false;
let italic = false;
this.binary = {};
let binaryId = '';
let binaryType = '';
let dimPromises = [];
let paraIndex = -1;
let paraOffset = 0;
@@ -50,6 +56,28 @@ export default class BookParser {
addIndex: Number, //индекс добавляемого пустого параграфа (addEmptyParagraphs)
}
*/
const getImageDimensions = (binaryId, binaryType, data) => {
return new Promise (async(resolve, reject) => {
const i = new Image();
let resolved = false;
i.onload = () => {
resolved = true;
this.binary[binaryId] = {
w: i.width,
h: i.height,
type: binaryType,
data
};
resolve();
};
i.src = `data:${binaryType};base64,${data}`;
await sleep(30*1000);
if (!resolved)
reject('Не удалось получить размер изображения');
});
};
const newParagraph = (text, len, addIndex) => {
paraIndex++;
let p = {
@@ -103,13 +131,26 @@ export default class BookParser {
paraOffset += p.length;
};
const onStartNode = (elemName) => {// eslint-disable-line no-unused-vars
const onStartNode = (elemName, tail) => {// eslint-disable-line no-unused-vars
if (elemName == '?xml')
return;
tag = elemName;
path += '/' + elemName;
if (tag == 'binary') {
let attrs = sax.getAttrsSync(tail);
binaryType = (attrs['content-type'].value ? attrs['content-type'].value : '');
if (binaryType == 'image/jpeg' || binaryType == 'image/png')
binaryId = (attrs.id.value ? attrs.id.value : '');
}
if (tag == 'image') {
let attrs = sax.getAttrsSync(tail);
if (attrs.href.value)
newParagraph(`<image href="${attrs.href.value}">${' '.repeat(maxImageLineCount)}</image>`, maxImageLineCount);
}
if (path.indexOf('/fictionbook/body') == 0) {
if (tag == 'title') {
newParagraph(' ', 1);
@@ -146,6 +187,10 @@ export default class BookParser {
const onEndNode = (elemName) => {// eslint-disable-line no-unused-vars
if (tag == elemName) {
if (tag == 'binary') {
binaryId = '';
}
if (path.indexOf('/fictionbook/body') == 0) {
if (tag == 'title') {
bold = false;
@@ -245,6 +290,10 @@ export default class BookParser {
growParagraph(`${tOpen}${text}${tClose}`, text.length);
}
}
if (binaryId) {
dimPromises.push(getImageDimensions(binaryId, binaryType, text));
}
};
const onProgress = async(prog) => {
@@ -256,6 +305,14 @@ export default class BookParser {
onStartNode, onEndNode, onTextNode, onProgress
});
if (dimPromises.length) {
try {
await Promise.all(dimPromises);
} catch (e) {
//
}
}
this.fb2 = fb2;
this.para = para;
@@ -292,18 +349,26 @@ export default class BookParser {
splitToStyle(s) {
let result = [];/*array of {
style: {bold: Boolean, italic: Boolean, center: Boolean},
image: Boolean,
imageId: String,
text: String,
}*/
let style = {};
let image = {};
/*let attrs = sax.getAttrsSync(tail);
if (attrs.href.value)
newParagraph(' '.repeat(maxImageLineCount) + `<image href="${attrs.href.value}" />`, maxImageLineCount);
*/
const onTextNode = async(text) => {// eslint-disable-line no-unused-vars
result.push({
style: Object.assign({}, style),
text: text
image,
text
});
};
const onStartNode = async(elemName) => {// eslint-disable-line no-unused-vars
const onStartNode = async(elemName, tail) => {// eslint-disable-line no-unused-vars
switch (elemName) {
case 'strong':
style.bold = true;
@@ -314,6 +379,9 @@ export default class BookParser {
case 'center':
style.center = true;
break;
case 'image':
image = {};
break;
}
};
@@ -328,6 +396,9 @@ export default class BookParser {
case 'center':
style.center = false;
break;
case 'image':
image = {};
break;
}
};
@@ -335,7 +406,6 @@ export default class BookParser {
onStartNode, onEndNode, onTextNode
});
//длинные слова (или белиберду без пробелов) тоже разобьем
const maxWordLength = this.maxWordLength;
const parts = result;
@@ -350,7 +420,7 @@ export default class BookParser {
if (i - spaceIndex >= maxWordLength && i < p.text.length - 1 &&
this.measureText(p.text.substr(spaceIndex + 1, i - spaceIndex), p.style) >= this.w - this.p) {
result.push({style: p.style, text: p.text.substr(0, i + 1)});
result.push({style: p.style, image: p.image, text: p.text.substr(0, i + 1)});
p = {style: p.style, text: p.text.substr(i + 1)};
spaceIndex = -1;
i = -1;

View File

@@ -1,6 +1,6 @@
{
"name": "Liberama",
"version": "0.3.2",
"version": "0.3.3",
"engines": {
"node": ">=10.0.0"
},

View File

@@ -53,18 +53,16 @@ class BookConverter {
}
decode(data) {
const charsetAll = chardet.detectAll(data.slice(0, 20000));
let selected = 'ISO-8859-5';
for (const charset of charsetAll) {
if (charset.name.indexOf('ISO-8859') < 0) {
selected = charset.name;
break;
}
}
let selected = textUtils.getEncoding(data);
if (selected == 'ISO-8859-5') {
selected = textUtils.getEncoding(data);
const charsetAll = chardet.detectAll(data.slice(0, 20000));
for (const charset of charsetAll) {
if (charset.name.indexOf('ISO-8859') < 0) {
selected = charset.name;
break;
}
}
}
return iconv.decode(data, selected);

View File

@@ -276,7 +276,84 @@ async function parse(xstr, options) {
await _onProgress(100);
}
function getAttrsSync(tail) {
let result = {};
let name = '';
let value = '';
let vOpen = '';
let inName = false;
let inValue = false;
let waitValue = false;
let waitEq = false;
const pushResult = () => {
if (name != '') {
let ns = '';
if (name.indexOf(':') >= 0) {
[ns, name] = name.split(':');
}
result[name] = {value, ns};
}
name = '';
value = '';
vOpen = '';
inName = false;
inValue = false;
waitValue = false;
waitEq = false;
};
tail = tail.replace(/[\t\n\r]/g, ' ');
for (let i = 0; i < tail.length; i++) {
const c = tail.charAt(i);
if (c == ' ') {
if (inValue) {
if (vOpen == '"')
value += c;
else
pushResult();
} else if (inName) {
waitEq = true;
inName = false;
}
} else if (!inValue && c == '=') {
waitEq = false;
waitValue = true;
inName = false;
} else if (c == '"') {
if (inValue) {
pushResult();
} else if (waitValue) {
inValue = true;
vOpen = '"';
}
} else if (inValue) {
value += c;
} else if (inName) {
name += c;
} else if (waitEq) {
pushResult();
inName = true;
name = c;
} else if (waitValue) {
waitValue = false;
inValue = true;
vOpen = ' ';
value = c;
} else {
inName = true;
name = c;
}
}
if (name != '')
pushResult();
return result;
}
module.exports = {
parseSync,
getAttrsSync,
parse
}

View File

@@ -85,7 +85,7 @@ function checkIfText(buf) {
const crFreq = crCount/(buf.length + 1);
const lfFreq = lfCount/(buf.length + 1);
return (spaceFreq > 0.1 || crFreq > 0.03 || lfFreq > 0.03);
return (buf.length < 1000 || spaceFreq > 0.1 || crFreq > 0.03 || lfFreq > 0.03);
}
module.exports = {