Эх сурвалжийг харах

Работа над ContentsPage

Book Pauk 4 жил өмнө
parent
commit
bd1e5485d7

+ 109 - 1
client/components/Reader/ContentsPage/ContentsPage.vue

@@ -1,8 +1,67 @@
 <template>
     <Window width="600px" ref="window" @close="close">
         <template slot="header">
+            Оглавление/закладки
         </template>
 
+    <div class="bg-grey-3 row">
+        <q-tabs
+            v-model="selectedTab"
+            active-color="black"
+            active-bg-color="white"
+            indicator-color="white"
+            dense
+            no-caps
+            inline-label
+            class="no-mp bg-grey-4 text-grey-7"
+        >
+            <q-tab name="contents" icon="la la-list" label="Оглавление" />
+            <q-tab name="bookmarks"  icon="la la-bookmark" label="Закладки" />
+        </q-tabs>
+    </div>
+
+    <div class="q-mb-sm"/>
+
+    <div class="tab-panel" v-show="selectedTab == 'contents'">
+        <div>
+            <div class="row" v-for="item in contents" :key="item.key">                
+                <q-expansion-item v-if="item.list.length"
+                    class="item"
+                    expand-icon-toggle
+                    switch-toggle-side
+                    expand-icon="la la-arrow-circle-down"
+                >
+                    <template slot="header">
+                        <div class="row no-wrap clickable" style="width: 470px">
+                            <div class="q-mr-sm col overflow-hidden column justify-center" v-html="item.label"></div>
+                            <div class="column justify-center">{{ item.perc }}%</div>
+                        </div>
+                    </template>
+
+                    <q-item class="subitem clickable" v-for="subitem in item.list" :key="subitem.key">
+                        <div class="row no-wrap" style="margin-left: 55px; padding-left: 60px; width: 470px">
+                            <div class="q-mr-sm col overflow-hidden column justify-center"  v-html="subitem.label"></div>
+                            <div class="column justify-center">{{ item.perc }}%</div>
+                        </div>
+                    </q-item>
+                </q-expansion-item>
+                <q-item v-else class="item clickable">
+                    <div class="row no-wrap" style="margin-left: 55px; width: 470px">
+                        <div class="q-mr-sm col overflow-hidden column justify-center" v-html="item.label"></div>
+                        <div class="column justify-center">{{ item.perc }}%</div>
+                    </div>
+                </q-item>
+
+                <q-separator />
+            </div>
+        </div>
+    </div>
+
+    <div class="tab-panel" v-show="selectedTab == 'bookmarks'">
+        <div>
+        </div>
+    </div>
+
     </Window>
 </template>
 
@@ -23,11 +82,42 @@ export default @Component({
     },
 })
 class ContentsPage extends Vue {
+    selectedTab = 'contents';
+    contents = [];
+
     created() {
     }
 
-    init() {
+    init(currentBook, parsed) {
         this.$refs.window.init();
+
+        const prepareLabel = (title) => {
+            let titleParts = title.split('<p>');
+            const textParts = titleParts.filter(v => v).map(v => v.replace(/(&nbsp;|<([^>]+)>)/ig, ''));
+            return textParts.join('<br>');
+        }
+
+        let i = 0;
+        const newContents = [];
+        parsed.contents.forEach((cont) => {
+            const label = prepareLabel(cont.title);
+
+            let j = 0;
+            const list = [];
+            cont.subtitles.forEach((sub) => {
+                const l = prepareLabel(sub.title);
+                const p = parsed.para[sub.paraIndex];
+                list.push({perc: (p.offset/parsed.textLength*100).toFixed(2), label: l, key: j});
+                j++;
+            });
+
+            const p = parsed.para[cont.paraIndex];
+            newContents.push({perc: (p.offset/parsed.textLength*100).toFixed(0), label, key: i, list});
+
+            i++;
+        });
+
+        this.contents = newContents;
     }
 
     close() {
@@ -45,4 +135,22 @@ class ContentsPage extends Vue {
 </script>
 
 <style scoped>
+.tab-panel {
+    overflow-x: hidden;
+    overflow-y: auto;
+    font-size: 90%;
+    padding: 0 10px 0px 10px;
+}
+
+.clickable {
+    cursor: pointer;
+}
+
+.item:hover {
+    background-color: #f0f0f0;
+}
+
+.subitem:hover {
+    background-color: #e0e0e0;
+}
 </style>

+ 6 - 2
client/components/Reader/Reader.vue

@@ -616,10 +616,14 @@ class Reader extends Vue {
 
     contentsPageToggle() {
         this.contentsPageActive = !this.contentsPageActive;
-        if (this.contentsPageActive) {
+        const page = this.$refs.page;
+        if (this.contentsPageActive && this.activePage == 'TextPage' && page.parsed) {
             this.closeAllWindows();
-            this.$refs.contentsPage.init();
             this.contentsPageActive = true;
+
+            this.$nextTick(() => {
+                this.$refs.contentsPage.init(this.mostRecentBook(), page.parsed);
+            });
         } else {
             this.contentsPageActive = false;
         }

+ 24 - 5
client/components/Reader/share/BookParser.js

@@ -53,9 +53,11 @@ export default class BookParser {
         let dimPromises = [];
 
         //оглавление
-        this.contents = [];//[{paraIndex: <number>, subtitles: [{paraIndex: <number>}, ... ]}, ... ]
-        let curTitle = {paraIndex: -1, subtitles: []};
-        let curSubtitle = {paraIndex: -1};
+        this.contents = [];//[{paraIndex: <number>, title: <string>, subtitles: [{paraIndex: <number>, title: <string>}, ... ]}, ... ]
+        let curTitle = {paraIndex: -1, title: '', subtitles: []};
+        let curSubtitle = {paraIndex: -1, title: ''};
+        let inTitle = false;
+        let inSubtitle = false;
 
         let paraIndex = -1;
         let paraOffset = 0;
@@ -124,6 +126,12 @@ export default class BookParser {
                 addIndex: (addIndex ? addIndex : 0),
             };
 
+            if (inSubtitle) {
+                curSubtitle.title += '<p>';
+            } else if (inTitle) {
+                curTitle.title += '<p>';
+            }
+
             para[paraIndex] = p;
             paraOffset += p.length;
         };
@@ -163,6 +171,13 @@ export default class BookParser {
             p.length += len;
             p.text += text;
 
+            
+            if (inSubtitle) {
+                curSubtitle.title += text;
+            } else if (inTitle) {
+                curTitle.title += text;
+            }
+
             para[paraIndex] = p;
             paraOffset += p.length;
         };
@@ -218,7 +233,8 @@ export default class BookParser {
                     bold = true;
                     center = true;
 
-                    curTitle = {paraIndex, subtitles: []};
+                    inTitle = true;
+                    curTitle = {paraIndex, title: '', subtitles: []};
                     this.contents.push(curTitle);
                 }
 
@@ -247,7 +263,8 @@ export default class BookParser {
                     bold = true;
                     center = true;
 
-                    curSubtitle = {paraIndex};
+                    inSubtitle = true;
+                    curSubtitle = {paraIndex, title: ''};
                     curTitle.subtitles.push(curSubtitle);
                 }
 
@@ -278,6 +295,7 @@ export default class BookParser {
                         isFirstTitlePara = false;
                         bold = false;
                         center = false;
+                        inTitle = false;
                     }
 
                     if (tag == 'emphasis' || tag == 'strong') {
@@ -292,6 +310,7 @@ export default class BookParser {
                         isFirstTitlePara = false;
                         bold = false;
                         center = false;
+                        inSubtitle = false;
                     }
 
                     if (tag == 'epigraph') {

+ 4 - 1
client/quasar.js

@@ -32,6 +32,8 @@ import {QPopupProxy} from 'quasar/src/components/popup-proxy';
 import {QDialog} from 'quasar/src/components/dialog';
 import {QChip} from 'quasar/src/components/chip';
 import {QTree} from 'quasar/src/components/tree';
+import {QExpansionItem} from 'quasar/src/components/expansion-item';
+
 
 const components = {
     //QLayout,
@@ -58,7 +60,8 @@ const components = {
     QPopupProxy,
     QDialog,
     QChip,
-    QTree
+    QTree,
+    QExpansionItem,
 };
 
 //directives