diff --git a/client/components/Reader/ContentsPage/ContentsPage.vue b/client/components/Reader/ContentsPage/ContentsPage.vue index f3621baa..c90cde27 100644 --- a/client/components/Reader/ContentsPage/ContentsPage.vue +++ b/client/components/Reader/ContentsPage/ContentsPage.vue @@ -26,7 +26,7 @@
-
+
@@ -41,7 +41,7 @@
-
+
@@ -60,15 +60,16 @@
-
+
-
- +
+
JPG
PNG
+
INET
@@ -100,19 +101,28 @@ import Component from 'vue-class-component'; import Window from '../../share/Window.vue'; import * as utils from '../../../share/utils'; +const ContentsPageProps = Vue.extend({ + props: { + bookPos: Number + } +}); + export default @Component({ components: { Window, }, watch: { + bookPos: function(newValue) { + this.updateBookPosSelection(newValue); + } }, }) -class ContentsPage extends Vue { +class ContentsPage extends ContentsPageProps { selectedTab = 'contents'; contents = []; images = []; imageSrc = []; - imageLoaded = false; + imageLoaded = []; created() { } @@ -122,10 +132,12 @@ class ContentsPage extends Vue { //закладки - //далее формирование оглавления - if (this.parsed == parsed) + //проверим, надо ли обновлять списки + if (this.parsed == parsed) { return; + } + //далее формирование оглавления this.parsed = parsed; this.contents = []; await this.$nextTick(); @@ -210,7 +222,7 @@ class ContentsPage extends Vue { const p = parsed.para[image.paraIndex]; newImages.push({perc: (p.offset/parsed.textLength*100).toFixed(0), label, key: i, offset: p.offset, - indentStyle, labelStyle, type, imageId: image.id}); + indentStyle, labelStyle, type, id: image.id, local: image.local}); } this.images = newImages; @@ -218,21 +230,65 @@ class ContentsPage extends Vue { if (this.selectedTab == 'contents' && !this.contents.length && this.images.length) this.selectedTab = 'images'; + //выделим на bookPos + this.updateBookPosSelection(currentBook.bookPos); + //асинхронная загрузка изображений this.imageSrc = []; - this.imageLoaded = false; + this.imageLoaded = []; await utils.sleep(50); (async() => { for (i = 0; i < ims.length; i++) { - const id = ims[i].id; + const {id, local} = ims[i]; const bin = this.parsed.binary[id]; - this.$set(this.imageSrc, id, (bin ? `data:${bin.type};base64,${bin.data}` : '')); + if (local) + this.$set(this.imageSrc, id, (bin ? `data:${bin.type};base64,${bin.data}` : '')); + else + this.$set(this.imageSrc, id, id); + this.imageLoaded[id] = true; await utils.sleep(5); } - this.imageLoaded = true; })(); } + async updateBookPosSelection(bp) { + await utils.sleep(100); + for (let i = 0; i < this.contents.length; i++) { + const item = this.contents[i]; + const nextOffset = (i < this.contents.length - 1 ? this.contents[i + 1].offset : this.parsed.textLength); + + for (let j = 0; j < item.list.length; j++) { + const subitem = item.list[j]; + const nextSubOffset = (j < item.list.length - 1 ? item.list[j + 1].offset : nextOffset); + + if (bp >= subitem.offset && bp < nextSubOffset) { + subitem.isBookPos = true; + this.$set(this.contents, i, Object.assign(item, {list: item.list})); + } else if (subitem.isBookPos) { + subitem.isBookPos = false; + this.$set(this.contents, i, Object.assign(item, {list: item.list})); + } + } + + if (bp >= item.offset && bp < nextOffset) { + this.$set(this.contents, i, Object.assign(item, {isBookPos: true})); + } else if (item.isBookPos) { + this.$set(this.contents, i, Object.assign(item, {isBookPos: false})); + } + } + + for (let i = 0; i < this.images.length; i++) { + const img = this.images[i]; + const nextOffset = (i < this.images.length - 1 ? this.images[i + 1].offset : this.parsed.textLength); + + if (bp >= img.offset && bp < nextOffset) { + this.$set(this.images, i, Object.assign(img, {isBookPos: true})); + } else if (img.isBookPos) { + this.$set(this.images, i, Object.assign(img, {isBookPos: false})); + } + } + } + async expandClick(key) { const item = this.contents[key]; const expanded = !item.expanded; @@ -284,7 +340,7 @@ class ContentsPage extends Vue { padding: 10px 0 10px 0; } -.item, .subitem { +.item, .subitem, .item-book-pos, .subitem-book-pos { border-bottom: 1px solid #e0e0e0; } @@ -292,6 +348,22 @@ class ContentsPage extends Vue { background-color: #f0f0f0; } +.item-book-pos { + background-color: #b0f0b0; +} + +.subitem-book-pos { + background-color: #d0f5d0; +} + +.item-book-pos:hover { + background-color: #b0e0b0; +} + +.subitem-book-pos:hover { + background-color: #d0f0d0; +} + .expand-button, .no-expand-button { width: 40px; } @@ -323,6 +395,9 @@ class ContentsPage extends Vue { .it-png-color { background: linear-gradient(to right, #4bc4e5, #6bf4ff); } +.it-net-color { + background: linear-gradient(to right, #00c400, #00f400); +} .image-thumb-box { width: 120px; diff --git a/client/components/Reader/Reader.vue b/client/components/Reader/Reader.vue index f1ee8e8b..ec93ca48 100644 --- a/client/components/Reader/Reader.vue +++ b/client/components/Reader/Reader.vue @@ -99,7 +99,7 @@ - +
diff --git a/client/components/Reader/share/BookParser.js b/client/components/Reader/share/BookParser.js index 67f575c1..b1f60615 100644 --- a/client/components/Reader/share/BookParser.js +++ b/client/components/Reader/share/BookParser.js @@ -196,6 +196,7 @@ export default class BookParser { if (tag == 'binary') { let attrs = sax.getAttrsSync(tail); binaryType = (attrs['content-type'] && attrs['content-type'].value ? attrs['content-type'].value : ''); + binaryType = (binaryType == 'image/jpg' ? 'image/jpeg' : binaryType); if (binaryType == 'image/jpeg' || binaryType == 'image/png' || binaryType == 'application/octet-stream') binaryId = (attrs.id.value ? attrs.id.value : ''); } @@ -204,7 +205,7 @@ export default class BookParser { let attrs = sax.getAttrsSync(tail); if (attrs.href && attrs.href.value) { const href = attrs.href.value; - const {id} = this.imageHrefToId(href); + const {id, local} = this.imageHrefToId(href); if (href[0] == '#') {//local imageNum++; @@ -213,7 +214,7 @@ export default class BookParser { else newParagraph(`${' '.repeat(maxImageLineCount)}`, maxImageLineCount); - this.images.push({paraIndex, num: imageNum, id}); + this.images.push({paraIndex, num: imageNum, id, local}); if (inPara && this.showInlineImagesInCenter) newParagraph(' ', 1); @@ -223,7 +224,7 @@ export default class BookParser { dimPromises.push(getExternalImageDimensions(href)); newParagraph(`${' '.repeat(maxImageLineCount)}`, maxImageLineCount); - this.images.push({paraIndex, num: imageNum, id}); + this.images.push({paraIndex, num: imageNum, id, local}); } } } diff --git a/server/core/Reader/BookConverter/ConvertFb2.js b/server/core/Reader/BookConverter/ConvertFb2.js index 1d1ec8b9..2bc3cb52 100644 --- a/server/core/Reader/BookConverter/ConvertFb2.js +++ b/server/core/Reader/BookConverter/ConvertFb2.js @@ -24,6 +24,11 @@ class ConvertFb2 extends ConvertBase { if (!this.check(newData, opts)) return false; + //Корректируем пробелы, всякие файлы попадаются :( + if (newData[0] == 32) { + newData = Buffer.from(newData.toString().trim()); + } + return this.checkEncoding(newData); }