Article.vue 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. <template>
  2. <div class="loading" v-if="!content || loading">
  3. <span>Loading ...</span>
  4. </div>
  5. <article class="article" v-else>
  6. <nav class="prevnext top">
  7. <ul>
  8. <li>
  9. <a
  10. @click.prevent="onPrev"
  11. href="#"
  12. v-if="prevnext.prev"
  13. v-html="prevnext.prev.title"
  14. />
  15. </li>
  16. <li>
  17. <a
  18. @click.prevent="onNext"
  19. href="#"
  20. v-if="prevnext.next"
  21. v-html="prevnext.next.title"
  22. />
  23. </li>
  24. </ul>
  25. </nav>
  26. <section class="accroche">
  27. <figure>
  28. <img
  29. :src="content.image_accroche.src"
  30. :alt="content.image_accroche.alt"
  31. :title="content.image_accroche.title"
  32. />
  33. </figure>
  34. </section>
  35. <section class="taxonomy">
  36. <div class="thesaurus">
  37. <ul>
  38. <li
  39. v-for="term in content.field_thesaurus" v-bind:key="term.id"
  40. >{{ term.name }}</li>
  41. </ul>
  42. </div>
  43. <div class="tags">
  44. <ul>
  45. <li
  46. v-for="term in content.field_tags" v-bind:key="term.id"
  47. >{{ term.name }}</li>
  48. </ul>
  49. </div>
  50. </section>
  51. <section class="body" v-html="content.body"></section>
  52. <section class="visuels">
  53. <figure
  54. v-for="visuel in content.field_visuel" v-bind:key="visuel.id"
  55. >
  56. <img
  57. :src="visuel.src"
  58. :alt="visuel.alt"
  59. :title="visuel.title"
  60. />
  61. <caption></caption>
  62. </figure>
  63. </section>
  64. <aside class="linked-materials">
  65. <h3 class="field__label">Linked Materials</h3>
  66. <div class="card-list">
  67. <ul class="">
  68. <li v-for="node in content.field_linked_materials" v-bind:key="node.id">
  69. <Card :item="node" />
  70. </li>
  71. </ul>
  72. </div>
  73. </aside>
  74. <nav class="prevnext bottom">
  75. <ul>
  76. <li>
  77. <a
  78. @click.prevent="onPrev"
  79. href="#"
  80. v-if="prevnext.prev"
  81. v-html="prevnext.prev.title"
  82. />
  83. </li>
  84. <li>
  85. <a
  86. @click.prevent="onNext"
  87. href="#"
  88. v-if="prevnext.next"
  89. v-html="prevnext.next.title"
  90. />
  91. </li>
  92. </ul>
  93. </nav>
  94. </article>
  95. </template>
  96. <script>
  97. import router from 'vuejs/route'
  98. import store from 'vuejs/store'
  99. import { JSONAPI } from 'vuejs/api/json-axios'
  100. import qs from 'querystring'
  101. import Card from 'vuejs/components/Content/Card'
  102. import { mapState, mapActions } from 'vuex'
  103. export default {
  104. name: "Article",
  105. router,
  106. store,
  107. props: ['item'],
  108. data(){
  109. return {
  110. index:-1,
  111. prevnext:{},
  112. uuid:null,
  113. content:null,
  114. loading:true,
  115. }
  116. },
  117. computed: {
  118. ...mapState({
  119. items: state => state.Blabla.items
  120. })
  121. },
  122. created(){
  123. this.getArticle()
  124. },
  125. methods: {
  126. ...mapActions({
  127. getItems: 'Blabla/getItems',
  128. getItemIndex: 'Blabla/getItemIndex',
  129. getPrevNextItems: 'Blabla/getPrevNextItems'
  130. }),
  131. getArticle(){
  132. console.log(this.$route);
  133. // get the article uuid
  134. if(this.$route.query.uuid){
  135. // we come from internal link with vuejs
  136. // directly record uuid
  137. this.uuid = this.$route.query.uuid
  138. }else if(drupalDecoupled.entity_type == 'node' && drupalDecoupled.entity_bundle == 'article'){
  139. // we landed in an internal page
  140. // get the uuid from drupalDeclouped, provided by materio_decoupled.module
  141. this.uuid = drupalDecoupled.entity_uuid
  142. }
  143. if(this.uuid){
  144. this.loadArticle()
  145. // get the prev next items
  146. if(!this.items.length){
  147. // if items list not yet loaded preload them
  148. this.getItems().then(() => {
  149. // then get the index
  150. this.getIndex()
  151. })
  152. }else{
  153. // or directly get the index
  154. this.getIndex()
  155. }
  156. }else{
  157. // if for any reason we dont have the uuid
  158. // redirect to home
  159. this.$route.replace('home')
  160. }
  161. },
  162. getIndex(){
  163. console.log("Article getIndex");
  164. this.getItemIndex(this.uuid).then((index) => {
  165. this.index = index
  166. // console.log('article index', index, this);
  167. this.getPrevNextItems(index).then((pn) => {
  168. this.prevnext = pn
  169. })
  170. })
  171. },
  172. loadArticle(){
  173. console.log('loadArticle', this.uuid)
  174. this.loading = true;
  175. let params = {
  176. include:'field_linked_materials.images,field_showroom,field_tags,field_thesaurus,field_visuel,uid'
  177. }
  178. let q = qs.stringify(params)
  179. JSONAPI.get(`node/article/${this.uuid}?${q}`)
  180. .then(({ data }) => {
  181. console.log('loadArticle data', data)
  182. this.parseData(data)
  183. })
  184. .catch(( error ) => {
  185. console.warn('Issue with loadArticle', error)
  186. Promise.reject(error)
  187. })
  188. },
  189. parseData(data){
  190. let attrs = data.data.attributes
  191. let relations = data.data.relationships
  192. console.log('relations', relations);
  193. let inc = data.included
  194. console.log('included', inc);
  195. this.content = {
  196. title:attrs.title,
  197. body: attrs.body.value
  198. }
  199. // parse all relationships
  200. for (let key in relations) {
  201. // skip loop if the property is from prototype
  202. if (!relations.hasOwnProperty(key)) continue;
  203. let relation_obj = relations[key]
  204. console.log('typeof relation_obj.data', typeof relation_obj.data);
  205. // skip relation_obj if data is not array
  206. if(!Array.isArray(relation_obj.data)) continue
  207. // create empty field array
  208. this.content[key] = []
  209. // parse relationship values using included
  210. let field = {}
  211. // loop through all relation items
  212. relation_obj.data.forEach((e) => {
  213. // get the included values for each item using id
  214. let included = inc.find((i) => { return i.id == e.id })
  215. // if we not found an included item skip the item
  216. if(typeof included != 'undefined'){
  217. // fill the item values
  218. switch (key) {
  219. case 'field_visuel':
  220. field = e.meta
  221. field.id = e.id
  222. field.src = included.links.article_card_medium.href
  223. break;
  224. case 'field_linked_materials':
  225. field = included.attributes
  226. field.id = included.id
  227. // get the linked material included images
  228. field.images = [];
  229. included.relationships.images.data.forEach((img) => {
  230. // console.log('href', img.meta.imageDerivatives.links.card_medium.href);
  231. if(img.meta.imageDerivatives){
  232. field.images.push({
  233. title:img.meta.title,
  234. url:img.meta.imageDerivatives.links.card_medium.href
  235. })
  236. }
  237. })
  238. break;
  239. case 'field_thesaurus':
  240. case 'field_tags':
  241. field = included.attributes
  242. field.id = included.id
  243. break;
  244. // case 'field_showroom':
  245. // field = included.attributes
  246. // break
  247. default:
  248. }
  249. this.content[key].push(field)
  250. }
  251. })
  252. }
  253. // extract first visuel as accroche
  254. this.content.image_accroche = this.content.field_visuel.shift()
  255. // update main page title
  256. this.$store.commit('Common/setPagetitle', this.content.title)
  257. this.loading = false;
  258. console.log('article.content',this.content);
  259. },
  260. onNext(){
  261. // console.log('clicked on next', this.prevnext.next);
  262. let alias = this.prevnext.next.view_node.replace(/^.?\/blabla\//g, '')
  263. this.$router.push({
  264. name:`article`,
  265. params: { alias:alias },
  266. query: { uuid: this.prevnext.next.uuid }
  267. })
  268. },
  269. onPrev(){
  270. // console.log('clicked on prev', this.prevnext.next);
  271. let alias = this.prevnext.prev.view_node.replace(/^.?\/blabla\//g, '')
  272. this.$router.push({
  273. name:`article`,
  274. params: { alias:alias },
  275. query: { uuid: this.prevnext.prev.uuid }
  276. })
  277. }
  278. },
  279. components: {
  280. Card
  281. },
  282. watch: {
  283. '$route' (to, from) {
  284. console.log('route change')
  285. this.getArticle()
  286. }
  287. }
  288. }
  289. </script>
  290. <style lang="scss" scoped>
  291. </style>