ContentsPage.vue 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. <template>
  2. <Window width="600px" ref="window" @close="close">
  3. <template slot="header">
  4. Оглавление/закладки
  5. </template>
  6. <div class="bg-grey-3 row">
  7. <q-tabs
  8. v-model="selectedTab"
  9. active-color="black"
  10. active-bg-color="white"
  11. indicator-color="white"
  12. dense
  13. no-caps
  14. inline-label
  15. class="no-mp bg-grey-4 text-grey-7"
  16. >
  17. <q-tab name="contents" icon="la la-list" label="Оглавление" />
  18. <q-tab name="bookmarks" icon="la la-bookmark" label="Закладки" />
  19. </q-tabs>
  20. </div>
  21. <div class="q-mb-sm"/>
  22. <div class="tab-panel" v-show="selectedTab == 'contents'">
  23. <div>
  24. <div class="row" v-for="item in contents" :key="item.key">
  25. <q-expansion-item v-if="item.list.length"
  26. class="item separator-bottom"
  27. expand-icon-toggle
  28. switch-toggle-side
  29. expand-icon="la la-arrow-circle-down"
  30. >
  31. <template slot="header">
  32. <div class="row no-wrap clickable" style="width: 465px" @click="setBookPos(item.offset)">
  33. <div :style="item.style"></div>
  34. <div class="q-mr-sm col overflow-hidden column justify-center" v-html="item.label"></div>
  35. <div class="column justify-center">{{ item.perc }}%</div>
  36. </div>
  37. </template>
  38. <q-item class="subitem separator-top column justify-center" v-for="subitem in item.list" :key="subitem.key">
  39. <div class="row no-wrap clickable" style="padding-left: 55px; width: 520px" @click="setBookPos(subitem.offset)">
  40. <div :style="subitem.style"></div>
  41. <div class="q-mr-sm col overflow-hidden column justify-center" v-html="subitem.label"></div>
  42. <div class="column justify-center">{{ subitem.perc }}%</div>
  43. </div>
  44. </q-item>
  45. </q-expansion-item>
  46. <q-item v-else class="item separator-bottom">
  47. <div class="row no-wrap clickable" style="padding-left: 55px; width: 520px" @click="setBookPos(item.offset)">
  48. <div :style="item.style"></div>
  49. <div class="q-mr-sm col overflow-hidden column justify-center" v-html="item.label"></div>
  50. <div class="column justify-center">{{ item.perc }}%</div>
  51. </div>
  52. </q-item>
  53. </div>
  54. </div>
  55. </div>
  56. <div class="tab-panel" v-show="selectedTab == 'bookmarks'">
  57. <div class="column justify-center items-center" style="height: 100px">
  58. Раздел находится в разработке
  59. </div>
  60. </div>
  61. </Window>
  62. </template>
  63. <script>
  64. //-----------------------------------------------------------------------------
  65. import Vue from 'vue';
  66. import Component from 'vue-class-component';
  67. //import _ from 'lodash';
  68. import Window from '../../share/Window.vue';
  69. //import * as utils from '../../../share/utils';
  70. export default @Component({
  71. components: {
  72. Window,
  73. },
  74. watch: {
  75. },
  76. })
  77. class ContentsPage extends Vue {
  78. selectedTab = 'contents';
  79. contents = [];
  80. created() {
  81. }
  82. async init(currentBook, parsed) {
  83. this.$refs.window.init();
  84. if (this.parsed != parsed) {
  85. this.contents = [];
  86. await this.$nextTick();
  87. this.parsed = parsed;
  88. }
  89. const prepareLabel = (title, bolder = false) => {
  90. let titleParts = title.split('<p>');
  91. const textParts = titleParts.filter(v => v).map(v => `<div>${v.replace(/(<([^>]+)>)/ig, '')}</div>`);
  92. if (bolder && textParts.length > 1)
  93. textParts[0] = `<b>${textParts[0]}</b>`;
  94. return textParts.join('');
  95. }
  96. const insetStyle = inset => `width: ${inset*20}px`;
  97. const pc = parsed.contents;
  98. const newpc = [];
  99. //преобразуем не первые разделы body в title-subtitle
  100. let curSubtitles = [];
  101. let prevBodyIndex = -1;
  102. for (let i = 0; i < pc.length; i++) {
  103. const cont = pc[i];
  104. if (prevBodyIndex != cont.bodyIndex)
  105. curSubtitles = [];
  106. prevBodyIndex = cont.bodyIndex;
  107. if (cont.bodyIndex > 1) {
  108. if (cont.inset < 1) {
  109. newpc.push(Object.assign({}, cont, {subtitles: curSubtitles}));
  110. } else {
  111. curSubtitles.push(Object.assign({}, cont, {inset: cont.inset - 1}));
  112. }
  113. } else {
  114. newpc.push(cont);
  115. }
  116. }
  117. //формируем newContents
  118. let i = 0;
  119. const newContents = [];
  120. newpc.forEach((cont) => {
  121. const label = prepareLabel(cont.title, true);
  122. const style = insetStyle(cont.inset);
  123. let j = 0;
  124. const list = [];
  125. cont.subtitles.forEach((sub) => {
  126. const l = prepareLabel(sub.title);
  127. const s = insetStyle(sub.inset + 1);
  128. const p = parsed.para[sub.paraIndex];
  129. list.push({perc: (p.offset/parsed.textLength*100).toFixed(2), label: l, key: j, offset: p.offset, style: s});
  130. j++;
  131. });
  132. const p = parsed.para[cont.paraIndex];
  133. newContents.push({perc: (p.offset/parsed.textLength*100).toFixed(0), label, key: i, offset: p.offset, style, list});
  134. i++;
  135. });
  136. this.contents = newContents;
  137. }
  138. async setBookPos(newValue) {
  139. this.$emit('book-pos-changed', {bookPos: newValue});
  140. await this.$nextTick();
  141. this.close();
  142. }
  143. close() {
  144. this.$emit('do-action', {action: 'contents'});
  145. }
  146. keyHook(event) {
  147. if (!this.$root.stdDialog.active && event.type == 'keydown' && event.key == 'Escape') {
  148. this.close();
  149. }
  150. return true;
  151. }
  152. }
  153. //-----------------------------------------------------------------------------
  154. </script>
  155. <style scoped>
  156. .tab-panel {
  157. overflow-x: hidden;
  158. overflow-y: auto;
  159. font-size: 90%;
  160. padding: 0 10px 0px 10px;
  161. }
  162. .clickable {
  163. cursor: pointer;
  164. }
  165. .item:hover {
  166. background-color: #f0f0f0;
  167. }
  168. .subitem:hover {
  169. background-color: #e0e0e0;
  170. }
  171. .separator-top {
  172. border-top: 1px solid #e0e0e0;
  173. }
  174. .separator-bottom {
  175. border-top: 1px solid #e0e0e0;
  176. }
  177. </style>