Edition.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. <template>
  2. <MainContentLayout
  3. id="edition"
  4. :reftoscrollto="reftoscrollto"
  5. :navopened="navopened"
  6. @onCenterScrolled="onCenterScrolled"
  7. >
  8. <!-- <transition name="fade" mode="out-in"> -->
  9. <template v-if="!corpusLoaded" #header>
  10. <span class="loading">Chargement ...</span>
  11. </template>
  12. <template v-else #header>
  13. <h1>
  14. <router-link :to="{ name:'edition', params: { id: editionid }}">{{ title }}</router-link>
  15. </h1>
  16. <div v-if="author">
  17. <p>{{ author }}</p>
  18. </div>
  19. <div v-if="date">
  20. <p>{{ date }}</p>
  21. </div>
  22. <div v-if="description">
  23. <p v-html="description" />
  24. </div>
  25. <div v-if="biblio" class="biblio">
  26. <p v-html="biblio.description" />
  27. <a
  28. :href="edition_manifestation_href"
  29. @click.prevent="onClickManifestation"
  30. @keyup.enter="onClickManifestation"
  31. >
  32. // todo better label
  33. {{ biblio.uuid }}
  34. </a>
  35. </div>
  36. <!-- displayed on hover entity on texte -->
  37. <aside
  38. v-if="indexitem"
  39. class="index-tooltip"
  40. :style="{ top:tooltip_top + 'px' }"
  41. :data-index="indexitem.index"
  42. :data-uuid="indexitem.uuid"
  43. @click.prevent="onClickTooltip"
  44. @keyup.enter="onClickTooltip"
  45. >
  46. <span v-if="indexitem == 'loading'" class="loading">Chargement ...</span>
  47. <template v-if="indexitem !== 'loading'">
  48. <h1 v-html="indexitem.title" />
  49. <p v-if="indexitem.birthDate" class="birthdeath">
  50. <time>{{ indexitem.birthDate }}</time>, <span class="place">{{ indexitem.birthPlace }}</span><br>
  51. <time>{{ indexitem.deathDate }}</time>, <span class="place">{{ indexitem.deathPlace }}</span>
  52. </p>
  53. <p v-if="indexitem.occupation" class="occupation">
  54. {{ indexitem.occupation }}
  55. </p>
  56. <p v-if="indexitem.type" class="type">
  57. {{ indexitem.type }}
  58. </p>
  59. </template>
  60. </aside>
  61. </template>
  62. <!-- </transition> -->
  63. <!-- default slot -->
  64. <div id="text">
  65. <template v-if="texts.length">
  66. <infinite-loading
  67. v-if="flattoc && center_scrolled"
  68. :identifier="inifinite_load_id"
  69. direction="top"
  70. :distance="inifinite_load_distance"
  71. @infinite="prevText"
  72. />
  73. <!-- <transition-group name="edition-texts" tag="div"> -->
  74. <EdText
  75. v-for="text in texts"
  76. :ref="text.content.uuid"
  77. :key="text.content.uuid"
  78. :tei="text.content.tei"
  79. :uuid="text.content.uuid"
  80. :url="text.content.url"
  81. :textid="textid"
  82. :extractid="extractid"
  83. @onHoverLink="onHoverLink"
  84. @onLeaveLink="onLeaveLink"
  85. />
  86. <!-- </transition-group> -->
  87. <infinite-loading
  88. v-if="flattoc"
  89. :identifier="inifinite_load_id"
  90. @infinite="nextText"
  91. />
  92. </template>
  93. </div>
  94. <template #nav>
  95. <span
  96. class="nav-title"
  97. @click.prevent="onOpenCloseNav"
  98. @keyup.enter="onOpenCloseNav"
  99. >
  100. <svg xmlns="http://www.w3.org/2000/svg" width="14" height="10" role="presentation" class="vs__open-indicator"><path d="M9.211364 7.59931l4.48338-4.867229c.407008-.441854.407008-1.158247 0-1.60046l-.73712-.80023c-.407008-.441854-1.066904-.441854-1.474243 0L7 5.198617 2.51662.33139c-.407008-.441853-1.066904-.441853-1.474243 0l-.737121.80023c-.407008.441854-.407008 1.158248 0 1.600461l4.48338 4.867228L7 10l2.211364-2.40069z" /></svg>
  101. Sommaire
  102. </span>
  103. <EdToc
  104. id="toc"
  105. :toc="toc"
  106. :loadedtextsuuids="textsuuids"
  107. :selectedindex="selectedindex"
  108. @onClickTocItem="onClickTocItem"
  109. />
  110. <EdIndexes
  111. v-if="indexes"
  112. id="indexes-filters"
  113. :indexes="indexes"
  114. @onClickIndexItem="onClickIndexItem"
  115. />
  116. <EdPagination
  117. v-if="pagination"
  118. id="page-nav"
  119. :pagination="pagination"
  120. @onClickPaginationItem="onClickPaginationItem"
  121. />
  122. </template>
  123. </MainContentLayout>
  124. </template>
  125. <script>
  126. import qs from 'querystring'
  127. import { REST } from 'api/rest-axios'
  128. import { mapState, mapActions } from 'vuex'
  129. import MainContentLayout from '../components/Layouts/MainContentLayout'
  130. import EdText from '../components/Content/EdText'
  131. import EdToc from '../components/Content/EdToc'
  132. import EdIndexes from '../components/Content/EdIndexes'
  133. import EdPagination from '../components/Content/EdPagination'
  134. export default {
  135. name: 'Edition',
  136. metaInfo () {
  137. // console.log('metainfo', this.meta)
  138. return {
  139. title: this.metainfotitle,
  140. meta: this.meta
  141. }
  142. },
  143. components: {
  144. MainContentLayout,
  145. EdText,
  146. EdToc,
  147. EdIndexes,
  148. EdPagination
  149. },
  150. data: () => ({
  151. meta: [],
  152. editionid: null,
  153. textid: null,
  154. extract: null,
  155. extractid: null,
  156. texts: [],
  157. textsuuids: [],
  158. metainfotitle: undefined,
  159. title: undefined,
  160. biblio: undefined,
  161. author: undefined,
  162. date: undefined,
  163. description: undefined,
  164. texttitle: undefined,
  165. //
  166. indexitem: null,
  167. tooltip_top: null,
  168. //
  169. next_loaded: false,
  170. center_scrolled: false,
  171. inifinite_load_distance: 10,
  172. inifinite_load_id: +new Date(),
  173. reftoscrollto: null,
  174. //
  175. toc: null,
  176. flattoc: null,
  177. //
  178. indexes: null,
  179. selectedindex: null,
  180. //
  181. pagination: null,
  182. //
  183. navopened: false
  184. }),
  185. computed: {
  186. ...mapState({
  187. corpusLoaded: state => state.Corpus.corpusLoaded,
  188. editionslist: state => state.Corpus.editionslist,
  189. editionsbyuuid: state => state.Corpus.editionsbyuuid
  190. }),
  191. edition_manifestation_href () {
  192. return `${this.biblio.path}${this.biblio.uuid}`
  193. }
  194. },
  195. watch: {
  196. $route (to, from) {
  197. console.log('Edition Watcher $route', from, to)
  198. if (to.params.textid) {
  199. // change textid when route change
  200. this.textid = to.params.textid
  201. // change also extract if exists
  202. this.extractid = null
  203. if (to.params.extract) {
  204. console.log('extract params from route', to.params.extract)
  205. this.extractid = to.params.ocid
  206. // scrolling is not working :(
  207. this.reftoscrollto = '#mark-1'
  208. }
  209. } else if (this.toc) {
  210. // if no textid in new route (e.g. edition front)
  211. // but we have toc
  212. // get the first item
  213. // will be replaced by front page of edition
  214. this.textid = this.toc[0].children[1].uuid
  215. } else {
  216. this.textid = null
  217. }
  218. },
  219. reftoscrollto (newref, oldref) {
  220. console.log('reftoscrollto changed', oldref, newref)
  221. },
  222. textid (newid, oldid) {
  223. // triggered when route change (when TOC item clicked)
  224. console.log('textid watcher', this, oldid, newid)
  225. this.texts = []
  226. this.textsuuids = []
  227. this.pages = []
  228. this.pagesOtpions = []
  229. if (newid) {
  230. this.getTextContent(newid)
  231. this.inifinite_load_id += 1
  232. }
  233. },
  234. // textdata (newtxtdata, oldtxtdata) {
  235. // console.log('textdata watcher', oldtxtdata, newtxtdata)
  236. // this.metainfotitle = `${this.title} ${newtxtdata.meta.title}`
  237. // },
  238. page_selected (newp, oldp) {
  239. console.log('page_selected watcher', oldp, newp)
  240. this.scrollToPage(newp)
  241. },
  242. flattoc (n, o) {
  243. console.log('flattoc watcher', o, n)
  244. // this.scrollToPage(newp)
  245. }
  246. },
  247. created () {
  248. // console.log('Edition this.$route.params.id', this.$route.params.id)
  249. this.editionid = this.$route.params.id
  250. // get the text if textid available
  251. if (this.$route.params.textid) {
  252. this.textid = this.$route.params.textid
  253. }
  254. // get the searchkeys from route param (only comming from result item) for text highlighting
  255. if (this.$route.params.ocid) {
  256. this.extractid = this.$route.params.ocid
  257. // scrolling is not working :(
  258. this.reftoscrollto = '#mark-1'
  259. }
  260. // wait for editions list from Corpus Store if not already loaded
  261. if (!this.corpusLoaded) {
  262. // this.getCorpuses()
  263. // subsribe to store to get the editionbyuuid list
  264. // https://dev.to/viniciuskneves/watch-for-vuex-state-changes-2mgj
  265. this.edUuuidsUnsubscribe = this.$store.subscribe((mutation, state) => {
  266. // console.log('Edition store subscribe', mutation.type)
  267. if (mutation.type === 'Corpus/setEditionsByUUID') {
  268. // console.log('Edition state.Coprus.editionsbyuuid', this.editionid, state.Corpus.editionsbyuuid)
  269. this.title = this.metainfotitle = state.Corpus.editionsbyuuid[this.editionid].title
  270. this.meta = [
  271. { name: 'test', content: 'edition chargé' }
  272. ]
  273. this.biblio = state.Corpus.editionsbyuuid[this.editionid].biblio
  274. this.description = state.Corpus.editionsbyuuid[this.editionid].description
  275. this.date = state.Corpus.editionsbyuuid[this.editionid].date
  276. this.author = state.Corpus.editionsbyuuid[this.editionid].author
  277. }
  278. if (mutation.type === 'Corpus/setTocs') {
  279. console.log('Edition Corpus/setTocs', this.editionid, state.Corpus.editionsbyuuid)
  280. this.toc = state.Corpus.editionsbyuuid[this.editionid].toc
  281. }
  282. if (mutation.type === 'Corpus/buildFlatTocsAndFilters') {
  283. console.log('Edition Corpus/buildFlatTocsAndFilters', this.editionid, state.Corpus.editionsbyuuid)
  284. this.flattoc = state.Corpus.editionsbyuuid[this.editionid].flattoc
  285. // launch infinitloading
  286. this.inifinite_load_id += 1
  287. // if no textid in new route (e.g. edition front)
  288. // but we have toc
  289. // get the first item
  290. // will be replaced by front page of edition
  291. if (!this.textid) { this.textid = this.flattoc[1] }
  292. //
  293. this.indexes = state.Corpus.editionsbyuuid[this.editionid].indexes
  294. }
  295. if (mutation.type === 'Corpus/setPaginations') {
  296. // console.log('Edition state.Coprus.editionsbyuuid', this.editionid, state.Corpus.editionsbyuuid)
  297. this.pagination = state.Corpus.editionsbyuuid[this.editionid].pagination
  298. }
  299. })
  300. } else {
  301. // console.log('');
  302. this.title = this.metainfotitle = this.editionsbyuuid[this.editionid].title
  303. this.meta = [
  304. { name: 'test', content: 'edition deja là' }
  305. ]
  306. this.biblio = this.editionsbyuuid[this.editionid].biblio
  307. this.description = this.editionsbyuuid[this.editionid].description
  308. this.date = this.editionsbyuuid[this.editionid].date
  309. this.author = this.editionsbyuuid[this.editionid].author
  310. this.toc = this.editionsbyuuid[this.editionid].toc
  311. this.flattoc = this.editionsbyuuid[this.editionid].flattoc
  312. // if no textid in new route (e.g. edition front)
  313. // but we have toc
  314. // get the first item
  315. // will be replaced by front page of edition
  316. if (!this.textid) { this.textid = this.toc[0].children[0].uuid }
  317. this.indexes = this.editionsbyuuid[this.editionid].indexes
  318. this.pagination = this.editionsbyuuid[this.editionid].pagination
  319. }
  320. },
  321. methods: {
  322. ...mapActions({
  323. getCorpuses: 'Corpus/getCorpuses'
  324. }),
  325. getTextContent (textid, $state = null, direction = 'next') {
  326. console.log('getTextContent', textid)
  327. let params = {
  328. depth: 0
  329. }
  330. let q = qs.stringify(params)
  331. REST.get(`${window.apipath}/items/${textid}?${q}`, {})
  332. .then(({ data }) => {
  333. console.log('text REST: data', data)
  334. if (direction === 'next') {
  335. this.texts.push(data)
  336. this.textsuuids.push(data.content.uuid)
  337. } else {
  338. this.texts.unshift(data)
  339. this.textsuuids.unshift(data.content.uuid)
  340. }
  341. if ($state) {
  342. // triggered by infinite scroll
  343. $state.loaded()
  344. this.next_loaded = true
  345. } else {
  346. // triggered by TOC item click
  347. // UPDATE METATAGS
  348. this.updateMetaData(data.meta.metadata)
  349. }
  350. })
  351. .catch((error) => {
  352. console.warn('Issue with getTextContent', error)
  353. Promise.reject(error)
  354. // if some item don't load and if we come from infinite loading
  355. // retry with next step
  356. if ($state) {
  357. switch (direction) {
  358. case 'next':
  359. this.nextText($state, 2)
  360. break
  361. case 'prev':
  362. this.prevText($state, 2)
  363. break
  364. }
  365. }
  366. // this.$router.replace({
  367. // name: 'notfound',
  368. // query: { fullpath: this.$route.path }
  369. // })
  370. })
  371. },
  372. updateMetaData (metadata) {
  373. this.meta = []
  374. metadata.forEach(m => {
  375. let o = {}
  376. o.name = m.name
  377. if (Array.isArray(m.content)) {
  378. o.content = m.content.join(', ')
  379. } else {
  380. o.content = m.content
  381. }
  382. if (typeof m.scheme !== 'undefined') {
  383. o.scheme = m.scheme
  384. }
  385. this.meta.push(o)
  386. })
  387. },
  388. onCenterScrolled (e) {
  389. console.log('Edition centerScrolled(e)', e.target.scrollTop)
  390. if (!this.center_scrolled && e.target.scrollTop > this.inifinite_load_distance * 1.5) {
  391. this.center_scrolled = true
  392. // this.$store.commit('History/setOpened', false)
  393. }
  394. this.indexitem = null
  395. },
  396. nextText ($state, indent = 1) {
  397. console.log('infinite loading nextText()')
  398. let indexofnext = this.flattoc.indexOf(this.textsuuids[this.textsuuids.length - 1]) + indent
  399. if (indexofnext < this.flattoc.length) {
  400. this.getTextContent(this.flattoc[indexofnext], $state, 'next')
  401. } else {
  402. $state.complete()
  403. }
  404. },
  405. prevText ($state, indent = 1) {
  406. console.log('infinite loading prevText()')
  407. let indexofprev = this.flattoc.indexOf(this.textsuuids[0]) - indent
  408. if (indexofprev >= 0) {
  409. this.getTextContent(this.flattoc[indexofprev], $state, 'prev')
  410. } else {
  411. $state.complete()
  412. }
  413. },
  414. onHoverLink (elmt) {
  415. console.log('Edition onHoverLink(elmt)', elmt)
  416. this.tooltip_top = elmt.rect.top
  417. this.getIndexItem(elmt)
  418. },
  419. onLeaveLink () {
  420. console.log('Edition onLeaveLink()')
  421. this.indexitem = null
  422. },
  423. getIndexItem (item) {
  424. this.indexitem = 'loading'
  425. REST.get(`${window.apipath}/index${item.index.charAt(0).toUpperCase()}${item.index.slice(1)}/${item.uuid}`, {})
  426. .then(({ data }) => {
  427. console.log('index tooltip REST: data', data)
  428. if (this.indexitem === 'loading') {
  429. this.indexitem = data.content
  430. this.indexitem.index = item.index
  431. }
  432. })
  433. .catch((error) => {
  434. console.warn('Issue with index tooltip rest', error)
  435. Promise.reject(error)
  436. this.indexitem = null
  437. })
  438. },
  439. onClickTocItem (uuid) {
  440. console.log('Edition onClickTocItem', uuid, this.$refs)
  441. if (this.textsuuids.indexOf(uuid) !== -1) {
  442. // if already loaded, scroll to uuid
  443. this.reftoscrollto = `.tei[data-uuid="${uuid}"]`
  444. } else {
  445. // if not already loaded, change route
  446. this.$router.push({
  447. name: `editiontext`,
  448. params: {
  449. id: this.editionid,
  450. textid: uuid
  451. }
  452. })
  453. }
  454. },
  455. onClickIndexItem (o) {
  456. this.selectedindex = o
  457. },
  458. onClickPaginationItem (o) {
  459. console.log('onClickPaginationItem', o)
  460. if (this.textsuuids.indexOf(o.uuid) !== -1) {
  461. // if already loaded, scroll to uuid
  462. // this.scrollToPage(o)
  463. this.reftoscrollto = `span[role="pageBreak"][id="${o.code}"]`
  464. } else {
  465. // if not already loaded, change route
  466. this.$router.push({
  467. name: `editiontext`,
  468. params: {
  469. id: this.editionid,
  470. textid: o.uuid
  471. }
  472. })
  473. }
  474. },
  475. // scrollToPage (p) {
  476. // console.log('scrollToPage', p)
  477. //
  478. // },
  479. onOpenCloseNav (e) {
  480. console.log('onOpenCloseNav', e)
  481. this.navopened = !this.navopened
  482. },
  483. onClickTooltip (e) {
  484. console.log(`onClickTooltip index: ${e.target.dataset.index}, uuid: ${e.target.dataset.uuid}`)
  485. this.$router.push({
  486. name: e.target.dataset.index,
  487. params: { id: e.target.dataset.uuid }
  488. })
  489. },
  490. onClickManifestation (e) {
  491. console.log(`onClickManifestation`)
  492. this.$router.push({
  493. name: 'bibliographieItem',
  494. params: { type: 'manifestations', uuid: this.biblio.uuid }
  495. })
  496. }
  497. }
  498. }
  499. </script>
  500. <style lang="scss" scoped>
  501. </style>