소스 검색

Работа над BookInfoDialog

Book Pauk 2 년 전
부모
커밋
81d8b476a5
4개의 변경된 파일160개의 추가작업 그리고 15개의 파일을 삭제
  1. 12 11
      client/components/Search/BookInfoDialog/BookInfoDialog.vue
  2. 1 1
      server/core/fb2/Fb2Helper.js
  3. 146 2
      server/core/fb2/Fb2Parser.js
  4. 1 1
      server/core/xml/ObjectInspector.js

+ 12 - 11
client/components/Search/BookInfoDialog/BookInfoDialog.vue

@@ -16,7 +16,6 @@
             </div>
             </div>
 
 
             <div class="q-mt-md" v-html="annotation" />
             <div class="q-mt-md" v-html="annotation" />
-            <pre>{{ annotation }}</pre>
         </div>
         </div>
 
 
         <template #footer>
         <template #footer>
@@ -62,6 +61,7 @@ class BookInfoDialog {
     //info props
     //info props
     coverSrc = '';
     coverSrc = '';
     annotation = '';
     annotation = '';
+    info = [];
 
 
     created() {
     created() {
         this.commit = this.$store.commit;
         this.commit = this.$store.commit;
@@ -78,24 +78,25 @@ class BookInfoDialog {
         //defaults
         //defaults
         this.coverSrc = '';
         this.coverSrc = '';
         this.annotation = '';
         this.annotation = '';
+        this.info = [];
 
 
         //cover
         //cover
         if (bookInfo.cover)
         if (bookInfo.cover)
             this.coverSrc = bookInfo.cover;
             this.coverSrc = bookInfo.cover;
 
 
         //fb2
         //fb2
-        if (bookInfo.fb2 && bookInfo.fb2.fictionbook && bookInfo.fb2.fictionbook.description) {
-            const desc = parser.inspector(bookInfo.fb2.fictionbook.description);
-
-            //annotation
-            const annObj = desc.v('title-info/annotation');
-            if (annObj) {
-                this.annotation = parser.fromObject(annObj).toString({noHeader: true, format: true});
-                this.annotation = parser.toHtml(this.annotation);
-                this.annotation = this.annotation.replace(/<p>/g, `<p class="p-annotation">`);
+        if (bookInfo.fb2) {
+            this.info = parser.bookInfoList(bookInfo.fb2);
+            
+            const infoObj = parser.bookInfo(bookInfo.fb2);
+            if (infoObj) {
+                let ann = infoObj.titleInfo.annotationHtml;
+                if (ann) {
+                    ann = ann.replace(/<p>/g, `<p class="p-annotation">`);
+                    this.annotation = ann;
+                }
             }
             }
         }
         }
-
     }
     }
 
 
     okClick() {
     okClick() {

+ 1 - 1
server/core/fb2/Fb2Helper.js

@@ -70,7 +70,7 @@ class Fb2Helper {
         let coverExt = '';
         let coverExt = '';
         if (coverImage) {
         if (coverImage) {
             const coverAttrs = coverImage.attrs();
             const coverAttrs = coverImage.attrs();
-            const href = coverAttrs['l:href'];
+            const href = coverAttrs[`${parser.xlinkNS}:href`];
             let coverType = coverAttrs['content-type'];
             let coverType = coverAttrs['content-type'];
             coverType = (coverType == 'image/jpg' || coverType == 'application/octet-stream' ? 'image/jpeg' : coverType);
             coverType = (coverType == 'image/jpg' || coverType == 'application/octet-stream' ? 'image/jpeg' : coverType);
             coverExt = (coverType == 'image/png' ? '.png' : '.jpg');
             coverExt = (coverType == 'image/png' ? '.png' : '.jpg');

+ 146 - 2
server/core/fb2/Fb2Parser.js

@@ -1,15 +1,159 @@
 const XmlParser = require('../xml/XmlParser');
 const XmlParser = require('../xml/XmlParser');
 
 
 class Fb2Parser extends XmlParser {
 class Fb2Parser extends XmlParser {
+    get xlinkNS() {
+        if (!this._xlinkNS) {
+            const rootAttrs = this.$self().attrs();
+            let ns = 'l';
+            for (const [key, value] of rootAttrs) {
+                if (value == 'http://www.w3.org/1999/xlink') {
+                    ns = key.split(':')[1] || ns;
+                    break;
+                }
+            }
+
+            this._xlinkNS = ns;
+        }
+
+        return this._xlinkNS;
+    }
+
     bookInfo(fb2Object) {
     bookInfo(fb2Object) {
+        const result = {};
+
         if (!fb2Object)
         if (!fb2Object)
             fb2Object = this.toObject();
             fb2Object = this.toObject();
 
 
-        //const result = {};
+        const desc = this.inspector(fb2Object).$('fictionbook/description');
+
+        if (!desc)
+            return result;
+
+        //title-info
+        const titleInfo = desc.$('title-info');
+        if (titleInfo) {
+            const info = {};
+
+            info.genre = [];
+            for (const g of titleInfo.$$('genre'))
+                info.genre.push(g.text());
+
+            const parseAuthors = (tagName) => {
+                const authors = [];
+                for (const a of titleInfo.$$(tagName)) {
+                    let names = [];
+                    names.push(a.text('last-name'));
+                    names.push(a.text('first-name'));
+                    names.push(a.text('middle-name'));
+                    names = names.filter(n => n);
+                    if (!names.length)
+                        names.push(a.text('nickname'));
+
+                    authors.push(names.join(' '));
+                }
+
+                return authors;
+            }
+
+            info.author = parseAuthors('author');
+
+            info.bookTitle = titleInfo.text('book-title');
+
+            info.annotation = null;
+            info.annotationHtml = null;
+            const node = titleInfo.$('annotation') && titleInfo.$('annotation').value;
+
+            if (node) {
+                //annotation как кусок xml
+                info.annotation = (new XmlParser()).fromObject(node).toString({noHeader: true});
+
+                //annotation как html
+                info.annotationHtml = this.toHtml(info.annotation);
+            }
 
 
+            info.keywords = titleInfo.text('keywords');
+            info.date = titleInfo.text('date');
+            info.coverpage = titleInfo.$('coverpage') && titleInfo.$('coverpage').value;
+            info.lang = titleInfo.text('lang');
+            info.srcLang = titleInfo.text('src-lang');
+
+            info.translator = parseAuthors('translator');
+
+            const seqAttrs = titleInfo.attrs('sequence') || new Map();
+            info.sequenceName = seqAttrs.get('name') || null;
+            info.sequenceNum = seqAttrs.get('number') || null;
+            info.sequenceLang = seqAttrs.get('xml:lang') || null;
+
+            result.titleInfo = info;
+        }
+
+        return result;
     }
     }
 
 
-    bookInfoList(fb2Object) {
+    bookInfoList(fb2Object, options = {}) {
+        let {
+            correctMapping = false,
+            valueToString = false,
+        } = options;
+
+        if (!correctMapping)
+            correctMapping = mapping => mapping;
+
+        if (!valueToString) {
+            valueToString = (value, nodePath) => {//eslint-disable-line no-unused-vars
+                if (typeof(value) === 'string') {
+                    return value;
+                } else if (Array.isArray(value)) {
+                    return value.join(', ');
+                } else if (typeof(value) === 'object') {
+                    return JSON.stringify(value);
+                }
+
+                return value;
+            };
+        }
+
+        let mapping = [
+            {name: 'titleInfo', label: 'Общая информация', value: [
+                {name: 'author', label: 'Автор(ы)'},
+                {name: 'bookTitle', label: 'Название'},
+                {name: 'sequenceName', label: 'Серия'},
+                {name: 'sequenceNum', label: 'Номер в серии'},
+                {name: 'genre', label: 'Жанр'},
+
+                {name: 'date', label: 'Дата'},
+                {name: 'lang', label: 'Язык книги'},
+                {name: 'srcLang', label: 'Язык оригинала'},
+                {name: 'translator', label: 'Переводчик(и)'},
+                {name: 'keywords', label: 'Ключевые слова'},
+            ]},
+        ];
+
+        mapping = correctMapping(mapping);
+        const bookInfo = this.bookInfo(fb2Object);
+
+        //заполняем mapping
+        let result = [];
+        for (const item of mapping) {
+            const itemOut = {name: item.name, label: item.label, value: []};
+            const info = bookInfo[item.name];
+            if (!info)
+                continue;
+
+            for (const subItem of item.value) {
+                if (info[subItem.name] !== null)
+                    itemOut.value.push({
+                        name: subItem.name,
+                        label: subItem.label,
+                        value: valueToString(info[subItem.name])
+                    });
+            }
+
+            if (itemOut.value.length)
+                result.push(itemOut);
+        }
+
+        return result;
     }
     }
 
 
     toHtml(xmlString) {
     toHtml(xmlString) {

+ 1 - 1
server/core/xml/ObjectInspector.js

@@ -56,7 +56,7 @@ class ObjectInspector {
         }
         }
 
 
         if (raw === null)
         if (raw === null)
-            return null;
+            return [];
 
 
         raw = (Array.isArray(raw) ? raw : [raw]);
         raw = (Array.isArray(raw) ? raw : [raw]);