Edition.vue 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. <template>
  2. <MainContentLayout id="edition" :reftoscrollto="reftoscrollto" @onCenterScrolled="onCenterScrolled">
  3. <template v-if="!content" #header>
  4. <span>Loading ...</span>
  5. </template>
  6. <template #header>
  7. <h1>{{ title }}</h1>
  8. <p v-if="meta">{{ meta.author }}</p>
  9. <aside
  10. v-if="indexitem"
  11. class="index-tooltip"
  12. :style="{ top:tooltip_top + 'px' }"
  13. >
  14. <span v-if="indexitem == 'loading'">Loading ...</span>
  15. <template v-if="indexitem !== 'loading'">
  16. <h1 v-html="indexitem.title" />
  17. <p v-if="indexitem.birthDate" class="birthdeath">
  18. <time>{{ indexitem.birthDate }}</time>, <span class="place">{{ indexitem.birthPlace }}</span><br>
  19. <time>{{ indexitem.deathDate }}</time>, <span class="place">{{ indexitem.deathPlace }}</span>
  20. </p>
  21. <p v-if="indexitem.occupation" class="occupation">
  22. {{ indexitem.occupation }}
  23. </p>
  24. <p v-if="indexitem.type" class="type">
  25. {{ indexitem.type }}
  26. </p>
  27. </template>
  28. </aside>
  29. </template>
  30. <!-- default slot -->
  31. <div id="text">
  32. <template v-if="texts.length">
  33. <infinite-loading
  34. v-if="center_scrolled"
  35. :identifier="textid"
  36. direction="top"
  37. :distance="inifinite_load_distance"
  38. @infinite="prevText"
  39. />
  40. <EdText
  41. v-for="text in texts"
  42. :ref="text.content.uuid"
  43. :key="text.content.uuid"
  44. :tei="text.content.tei"
  45. :uuid="text.content.uuid"
  46. :textid="textid"
  47. @onHoverLink="onHoverLink"
  48. @onLeaveLink="onLeaveLink"
  49. />
  50. <infinite-loading
  51. :identifier="textid"
  52. @infinite="nextText"
  53. />
  54. </template>
  55. </div>
  56. <template #nav>
  57. <EdToc :toc="toc" :loadedtextsuuids="textsuuids" @onClickTocItem="onClickTocItem" />
  58. </template>
  59. </MainContentLayout>
  60. </template>
  61. <script>
  62. import { REST } from 'api/rest-axios'
  63. import { mapState, mapActions } from 'vuex'
  64. import MainContentLayout from '../components/Layouts/MainContentLayout'
  65. import EdText from '../components/Content/EdText'
  66. import EdToc from '../components/Content/EdToc'
  67. export default {
  68. name: 'Edition',
  69. metaInfo () {
  70. // console.log('metainfo', this.meta)
  71. return {
  72. title: this.metainfotitle
  73. }
  74. },
  75. components: {
  76. MainContentLayout,
  77. EdText,
  78. EdToc
  79. },
  80. data: () => ({
  81. toc: null,
  82. meta: null,
  83. editionid: null,
  84. textid: null,
  85. texts: [],
  86. textsuuids: [],
  87. metainfotitle: undefined,
  88. title: undefined,
  89. author: undefined,
  90. texttitle: undefined,
  91. //
  92. indexitem: null,
  93. tooltip_top: null,
  94. //
  95. next_loaded: false,
  96. center_scrolled: false,
  97. inifinite_load_distance: 10,
  98. reftoscrollto: null
  99. }),
  100. computed: {
  101. ...mapState({
  102. editionslist: state => state.Corpus.editionslist,
  103. editionsbyuuid: state => state.Corpus.editionsbyuuid
  104. })
  105. },
  106. watch: {
  107. textid: function (newid, oldid) {
  108. console.log('textid watcher', this, oldid, newid)
  109. this.texts = []
  110. this.textsuuids = []
  111. this.getTextContent(newid)
  112. },
  113. textdata: function (newtxtdata, oldtxtdata) {
  114. console.log('textdata watcher', oldtxtdata, newtxtdata)
  115. this.metainfotitle = `${this.title} ${newtxtdata.meta.title}`
  116. }
  117. },
  118. beforeCreate () {
  119. console.log('texts this.$route', this.$route)
  120. // http://localhost:8984/texts/gdpSauval1724/toc
  121. // get the edition's toc
  122. REST.get(`${window.apipath}/texts/` + this.$route.params.id + `/toc`, {})
  123. .then(({ data }) => {
  124. console.log('texts/toc REST: data', data)
  125. this.meta = data.meta
  126. this.author = data.meta.author
  127. if (data.content) {
  128. if (Array.isArray(data.content)) {
  129. this.toc = data.content
  130. } else {
  131. this.toc = [data.content]
  132. }
  133. // if front page get the first item in toc
  134. if (!this.$route.params.textid) {
  135. // console.log('toc', this.toc)
  136. this.textid = this.toc[0].children[1].uuid
  137. }
  138. }
  139. })
  140. .catch((error) => {
  141. console.warn('Issue with locorum', error)
  142. Promise.reject(error)
  143. })
  144. },
  145. created () {
  146. // console.log('Edition this.$route.params.id', this.$route.params.id)
  147. this.editionid = this.$route.params.id
  148. // load editions list from Corpus Store if not exist
  149. if (!this.editionslist.length) {
  150. this.getCorpuses()
  151. // subsribe to store to get the editionbyuuid list
  152. // https://dev.to/viniciuskneves/watch-for-vuex-state-changes-2mgj
  153. this.unsubscribe = this.$store.subscribe((mutation, state) => {
  154. // console.log('Edition store subscribe', mutation.type)
  155. if (mutation.type === 'Corpus/setEditionsByUUID') {
  156. console.log('Edition state.Coprus.editionsbyuuid', this.editionid, state.Corpus.editionsbyuuid)
  157. // this.title = 'HoHoHo'
  158. this.title = this.metainfotitle = state.Corpus.editionsbyuuid[this.editionid].title
  159. }
  160. })
  161. } else {
  162. this.title = this.metainfotitle = this.editionsbyuuid[this.editionid].title
  163. }
  164. // get the text if textid available
  165. if (this.$route.params.textid) {
  166. this.textid = this.$route.params.textid
  167. }
  168. },
  169. beforeRouteUpdate (to, from, next) {
  170. // called when the route that renders this component has changed,
  171. // but this component is reused in the new route.
  172. // For example, for a route with dynamic params `/foo/:id`, when we
  173. // navigate between `/foo/1` and `/foo/2`, the same `Foo` component instance
  174. // will be reused, and this hook will be called when that happens.
  175. // has access to `this` component instance.
  176. // console.log('beforeRouteUpdate to', to)
  177. if (to.params.textid) {
  178. this.textid = to.params.textid
  179. }
  180. next()
  181. },
  182. methods: {
  183. ...mapActions({
  184. getCorpuses: 'Corpus/getCorpuses'
  185. }),
  186. getTextContent (textid, $state = null, direction = 'next') {
  187. console.log('getTextContent', textid)
  188. REST.get(`${window.apipath}/items/${textid}`, {})
  189. .then(({ data }) => {
  190. console.log('text REST: data', data)
  191. if (direction === 'next') {
  192. this.texts.push(data)
  193. this.textsuuids.push(data.content.uuid)
  194. } else {
  195. this.texts.unshift(data)
  196. this.textsuuids.unshift(data.content.uuid)
  197. }
  198. if ($state) {
  199. $state.loaded()
  200. this.next_loaded = true
  201. }
  202. })
  203. .catch((error) => {
  204. console.warn('Issue with getTextContent', error)
  205. Promise.reject(error)
  206. })
  207. },
  208. onCenterScrolled (e) {
  209. // console.log('Edition centerScrolled(e)', e.target.scrollTop)
  210. if (!this.center_scrolled && e.target.scrollTop > this.inifinite_load_distance * 1.5) {
  211. this.center_scrolled = true
  212. }
  213. this.indexitem = null
  214. },
  215. nextText ($state) {
  216. console.log('infinite loading nextText()', this.texts[this.texts.length - 1].content.itemAfterUuid, $state)
  217. if (this.texts[this.texts.length - 1].content.itemAfterUuid) {
  218. this.getTextContent(this.texts[this.texts.length - 1].content.itemAfterUuid, $state, 'next')
  219. } else {
  220. $state.complete()
  221. }
  222. },
  223. prevText ($state) {
  224. console.log('infinite loading prevText()', this.texts[0].content.itemBeforeUuid, $state)
  225. if (this.texts[0].content.itemBeforeUuid) {
  226. this.getTextContent(this.texts[0].content.itemBeforeUuid, $state, 'prev')
  227. } else {
  228. $state.complete()
  229. }
  230. },
  231. onHoverLink (elmt) {
  232. console.log('Edition onHoverLink(elmt)', elmt)
  233. this.tooltip_top = elmt.rect.top
  234. this.getIndexItem(elmt)
  235. },
  236. onLeaveLink () {
  237. console.log('Edition onLeaveLink()')
  238. this.indexitem = null
  239. },
  240. getIndexItem (item) {
  241. this.indexitem = 'loading'
  242. REST.get(`${window.apipath}/index${item.index.charAt(0).toUpperCase()}${item.index.slice(1)}/${item.uuid}`, {})
  243. .then(({ data }) => {
  244. console.log('index tooltip REST: data', data)
  245. if (this.indexitem === 'loading') {
  246. this.indexitem = data.content
  247. }
  248. })
  249. .catch((error) => {
  250. console.warn('Issue with index tooltip rest', error)
  251. Promise.reject(error)
  252. this.indexitem = null
  253. })
  254. },
  255. onClickTocItem (uuid) {
  256. console.log('Edition onClickTocItem', uuid, this.$refs)
  257. if (this.textsuuids.indexOf(uuid) !== -1) {
  258. // if already loaded, scroll to uuid
  259. this.reftoscrollto = `.tei[data-uuid="${uuid}"]`
  260. } else {
  261. // if not already loaded, change route
  262. this.$router.push({
  263. name: `editiontext`,
  264. params: {
  265. id: this.editionid,
  266. textid: uuid
  267. }
  268. })
  269. }
  270. }
  271. }
  272. }
  273. </script>
  274. <style lang="scss" scoped>
  275. </style>