<template> <div class="loading" v-if="!material || loading"> <span>Loading ...</span> </div> <article v-else class="card modal-card" v-touch="onTapCard" v-touch:swipe="onSwipeCard" > <section class="col col-right"> <header> <h1>{{ material.title }}</h1> <h4>{{ material.short_description }}</h4> <span class="ref">{{ material.reference }}</span> </header> <nav ref="tools" class="tools"> <section class="tool close"> <span class="btn mdi mdi-close" @click.prevent="onCloseModalCard" /> </section> <section class="tool flags"> <span class="btn mdi mdi-folder-outline" v-touch.prevent.stop="onTapTool" /> <div class="tool-content"> <span class="label">{{ $t("materio.My folders") }}</span> <ul> <li v-if="flagcolls" v-for="coll in flagcolls" :key="coll.id"> <span class="flag mdi" :class="[ flagIsLoading(coll.id) ? 'mdi-loading mdi-spin' : flagIsActive(coll.id) ? 'mdi-close-circle isActive' : 'mdi-plus' ]" :collid="coll.id" @click.prevent="onFlagActionCard" > {{ coll.name }} </span> </li> <li v-if="collsLength<15" class="create-flag"> <input placeholder="new folder" v-model="new_folder_name" @keyup.enter.prevent.stop="onCreateFlagColl" /> <span class="add-btn mdi" :class="addFlagBtnClassObj" @click.prevent.stop="onCreateFlagColl" /> </li> </ul> </div> </section> <section class="tool samples" v-if="item.samples && item.samples.length"> <span class="btn mdi mdi-beaker-outline" v-touch.prevent.stop="onTapTool" /> <div class="tool-content"> <span class="label">{{ $t("materio.Samples") }}</span> <ul> <li v-for="sample in item.samples" :key="sample.showroom.id" > <span class="showroom">{{ sample.showroom.name }}</span>: {{ sample.location }} </li> </ul> </div> </section> <section class="tool note"> <span v-if="note_id" class="btn mdi mdi-note" v-touch.prevent.stop="onTapTool" /> <span v-else class="btn mdi mdi-note-outline" v-touch.prevent.stop="onTapTool" /> <div class="tool-content"> <textarea spellcheck="false" v-model="note" name="note" @input="onNoteInput"/> </div> </section> <section class="tool print"> <a :href="material.path+'/printable/print'" target="_blank"> <span class="btn mdi mdi-printer"/> </a> </section> <!-- <section class="tool industriels" v-if="material.manufacturer || material.distributor"> <span class="btn mdi mdi-factory"/> <div class="tool-content"> <section v-if="material.distributor"> <span class="label">{{ $t("materio.Distributor") }}</span> <ul> <li v-for="distrib in material.distributor" v-bind:key="distrib.id"> <h2>{{ distrib.name }}</h2> <p v-if="distrib.website"> <a target="_blank" :href="distrib.website.url">distrib.website.url</a> </p> <p v-if="distrib.email"><a :href="'mailto:'+distrib.email">{{ distrib.email }}</a></p> </li> </ul> </section> <section v-if="material.manufacturer"> <span class="label">{{ $t("materio.Manufacturer") }}</span> <ul> <li v-for="manu in material.manufacturer" v-bind:key="manu.id"> <h2>{{ manu.name }}</h2> <p v-if="manu.website"> <a target="_blank" :href="manu.website.url">manu.website.url</a> </p> <p v-if="manu.email"><a :href="'mailto:'+manu.email">{{ manu.email }}</a></p> </li> </ul> </section> </div> </section> --> </nav> <vsa-list> <vsa-item :initActive="true"> <vsa-heading> <span class="label">Description</span> </vsa-heading> <vsa-content> <section class="body" v-html="material.body"/> <section class="attachments"> <!-- <h4 class="label">{{ $t("materio.Attachments") }}</h4> --> <ul> <li v-for="attachmt in material.attachments" :key="attachmt.file.fid" > <a target="_blank" :href="attachmt.file.url">{{ attachmt.file.filename}} <span>({{ prettyFileSize(attachmt.file.filesize) }})</span></a> <p v-if="attachmt.description" class="description" v-html="attachmt.description" /> </li> </ul> </section> <section class="industriels"> <!-- <h4 class="label">{{ $t("default.Contact") }}</h4> --> <section v-if="material.manufacturer"> <span class="label">{{ $t("materio.Manufacturer") }}</span> <ul> <li v-for="manu in material.manufacturer" v-bind:key="manu.id"> <h2>{{ manu.name }}</h2> <p v-if="manu.website"> <a target="_blank" :href="manu.website.url">{{shortUrl(manu.website.url)}}</a> </p> <p v-if="manu.email"><a :href="'mailto:'+manu.email">{{ manu.email }}</a></p> </li> </ul> </section> <section v-if="material.distributor"> <span class="label">{{ $t("materio.Distributor") }}</span> <ul> <li v-for="distrib in material.distributor" v-bind:key="distrib.id"> <h2>{{ distrib.name }}</h2> <p v-if="distrib.website"> <a target="_blank" :href="distrib.website.url">{{shortUrl(distrib.website.url)}}</a> </p> <p v-if="distrib.email"><a :href="'mailto:'+distrib.email">{{ distrib.email }}</a></p> </li> </ul> </section> </section> </vsa-content> </vsa-item> <!-- <vsa-item v-if="item.samples && item.samples.length"> <vsa-heading> <span class="label">{{ $t("materio.Samples") }}</span> </vsa-heading> <vsa-content> <section class="samples"> <ul> <li v-for="sample in material.samples" :key="sample.showroom.id" > <span class="showroom">{{ sample.showroom.name }}</span>: {{ sample.location }} </li> </ul> </section> </vsa-content> </vsa-item> --> <vsa-item v-if="material.linked_materials.length"> <vsa-heading> <span class="label">{{ $t("materio.Linked materials") }}</span> </vsa-heading> <vsa-content> <section class="linked-materials"> <ul> <li v-for="m in material.linked_materials" v-bind:key="m.id"> <LinkedMaterialCard :item="m"/> </li> </ul> </section> </vsa-content> </vsa-item> <!-- <vsa-item v-if="material.manufacturer || material.distributor"> <vsa-heading> <span class="label">{{ $t("default.Contact") }}</span> </vsa-heading> <vsa-content> <section class="industriels"> <section v-if="material.manufacturer"> <span class="label">{{ $t("materio.Manufacturer") }}</span> <ul> <li v-for="manu in material.manufacturer" v-bind:key="manu.id"> <h2>{{ manu.name }}</h2> <p v-if="manu.website"> <a target="_blank" :href="manu.website.url">{{shortUrl(manu.website.url)}}</a> </p> <p v-if="manu.email"><a :href="'mailto:'+manu.email">{{ manu.email }}</a></p> </li> </ul> </section> <section v-if="material.distributor"> <span class="label">{{ $t("materio.Distributor") }}</span> <ul> <li v-for="distrib in material.distributor" v-bind:key="distrib.id"> <h2>{{ distrib.name }}</h2> <p v-if="distrib.website"> <a target="_blank" :href="distrib.website.url">{{shortUrl(distrib.website.url)}}</a> </p> <p v-if="distrib.email"><a :href="'mailto:'+distrib.email">{{ distrib.email }}</a></p> </li> </ul> </section> </section> </vsa-content> </vsa-item> --> <!-- <vsa-item v-if="material.attachments && material.attachments.length"> <vsa-heading> <span class="label">{{ $t("materio.Attachments") }}</span> </vsa-heading> <vsa-content> <section class="attachments"> <ul> <li v-for="attachmt in material.attachments" :key="attachmt.file.fid" > <a target="_blank" :href="attachmt.file.url">{{ attachmt.file.filename}} <span>({{ prettyFileSize(attachmt.file.filesize) }})</span></a> <p v-if="attachmt.description" class="description" v-html="attachmt.description" /> </li> </ul> </section> </vsa-content> </vsa-item> --> </vsa-list> </section> <section class="col col-left images" v-switcher> <figure v-for="(img, index) in material.images" :key="img.url" class="lazy" v-lazy="index" > <img :data-src="img.style_cardfull.url" :title="img.title" /> <img class="blank" :src="blanksrc" @click="lightbox_index = index" > </figure> </section> <CoolLightBox :items="material.images" :index="lightbox_index" srcName="url" :loop="true" @close="lightbox_index = null"> </CoolLightBox> </article> </template> <script> import { mapState, mapActions } from 'vuex' import { VsaList, VsaItem, VsaHeading, VsaContent, VsaIcon } from 'vue-simple-accordion' import 'vue-simple-accordion/dist/vue-simple-accordion.css' import LinkedMaterialCard from 'vuejs/components/Content/LinkedMaterialCard' import cardMixins from 'vuejs/components/cardMixins' import { REST } from 'vuejs/api/rest-axios' import { MGQ } from 'vuejs/api/graphql-axios' import { print } from 'graphql/language/printer' import gql from 'graphql-tag' import materiauFields from 'vuejs/api/gql/materiaumodal.fragment.gql' const prettyBytes = require('pretty-bytes') const _debounce = require('lodash/debounce') export default { name: "ModalCard", props: ['item', 'addNoteId'], mixins: [cardMixins], components: { LinkedMaterialCard, VsaList, VsaItem, VsaHeading, VsaContent, VsaIcon // VsaList: () => import( // /* webpackPrefetch: true */ // /* webpackChunkName: "vsa" */ // /* webpackExports: ["VsaList"] */ // '/app/node_modules/vue-simple-accordion/'), // VsaItem: () => import( // /* webpackPrefetch: true */ // /* webpackChunkName: "vsa" */ // /* webpackExports: ["VsaItem"] */ // '/app/node_modules/vue-simple-accordion/'), // VsaHeading: () => import( // /* webpackPrefetch: true */ // /* webpackChunkName: "vsa" */ // /* webpackExports: ["VsaHeading"] */ // '/app/node_modules/vue-simple-accordion/'), // VsaContent: () => import( // /* webpackPrefetch: true */ // /* webpackChunkName: "vsa" */ // /* webpackExports: ["VsaContent"] */ // '/app/node_modules/vue-simple-accordion/'), // VsaIcon: () => import( // /* webpackPrefetch: true */ // /* webpackChunkName: "vsa" */ // /* webpackExports: ["VsaIcon"] */ // '/app/node_modules/vue-simple-accordion/') }, data() { return { material: null, loading: false, blanksrc:`${drupalSettings.path.themePath}/assets/img/blank.gif`, new_folder_name: "", is_creating_folder: false, loadingFlag: false, lightbox_index: null, note: "", note_id: null } }, computed: { ...mapState({ csrf_token: state => state.User.csrf_token, flagcolls: state => state.User.flagcolls, showrooms: state => state.Showrooms.showrooms_by_tid }), collsLength() { return Object.keys(this.flagcolls).length }, addFlagBtnClassObj() { return { 'mdi-plus-circle-outline': !this.is_creating_folder, 'mdi-loading': this.is_creating_folder, active: this.new_folder_name.length > 4 && !this.is_creating_folder, loading: this.is_creating_folder } } }, created () { console.log('modale item', this.item) this.loadMaterial() this.note_id = this.item.note_id this.debouncedSaveNote = _debounce(this.saveNote, 500) }, // watch: { // // whenever question changes, this function will run // // TODO: on mobile, this is called only on white caractere key // note: function (n, o) { // console.log("note watcher: note", n) // this.debouncedSaveNote() // } // }, methods: { ...mapActions({ // refreshItem: 'Search/refreshItem', createFlagColl: 'User/createFlagColl', flagUnflag: 'User/flagUnflag' }), loadMaterial(){ console.log('loadMaterial', this.item.id) this.loading = true const ast = gql`{ materiau(id: ${this.item.id}, lang: "${drupalDecoupled.lang_code}") { ...MateriauFields } } ${materiauFields} ` MGQ.post('', { query: print(ast) }) .then(({ data:{data:{materiau}}}) => { console.log('loadMaterial material loaded', materiau) this.material = materiau this.loading = false if (materiau.note && materiau.note.id) { this.note_id = materiau.note.id this.note = materiau.note.contenu } // delay the lazyload to let the card the time to update dom // maybe not the best method setTimeout(function () { this.activateLazyLoad() }.bind(this), 5) }) .catch(error => { console.warn('Issue with loadMaterial', error) Promise.reject(error) }) }, onCreateFlagColl () { console.log("Card onCreateFlagColl", this.new_folder_name) this.is_creating_folder = true; this.createFlagColl(this.new_folder_name) .then(data => { console.log("Card onCreateFlagColl then", data) this.new_folder_name = ""; this.is_creating_folder = false; let collid = data.id this.loadingFlag = collid; this.flagUnflag({ action: 'flag', id: this.item.id, collid: collid}) .then(data => { console.log("onFlagActionCard then", data) this.loadingFlag = false; }) }) }, flagIsActive(collid) { // console.log(this.item.uuid) // console.log(this.flagcolls[collid].items_uuids) // return this.flagcolls[collid].items_uuids.indexOf(this.item.uuid) !== -1; return this.flagcolls[collid].items.indexOf(this.item.id) !== -1; }, flagIsLoading(collid) { // console.log(this.item.uuid) // console.log(this.flagcolls[collid].items_uuids) return collid === this.loadingFlag; }, onFlagActionCard (e) { console.log("Card onFlagActionCard", e) if (!this.loadingFlag) { let collid = e.target.getAttribute('collid'); let isActive = this.flagIsActive(collid); let action = isActive ? 'unflag' : 'flag'; // console.log('collid', collid) // console.log("this.item", this.item) this.loadingFlag = collid; this.flagUnflag({ action: action, id: this.item.id, collid: collid}) .then(data => { console.log("onFlagActionCard then", data) this.loadingFlag = false; }) } }, onCloseModalCard (e) { // this.$modal.hideAll() this.$modal.hide(`modal-${this.item.id}`) }, onSwipeCard (e) { console.log('onSwipeCard', e) switch(e){ case 'top': break case 'bottom': break case 'left': case 'right': this.$modal.hide(`modal-${this.item.id}`) break } }, prettyFileSize(bytes){ return prettyBytes(parseInt(bytes)) }, shortUrl(url){ return url.replace(/^http:\/\//, '').replace(/^www\./, '') }, onNoteInput(e){ console.log('onNoteInput', e, this.note) this.note = e.target.value this.debouncedSaveNote() }, saveNote(){ console.log("saveNote", this.note_id, this.note) if (this.note_id) { this.updateNote() } else { this.createNote() } }, updateNote(){ let params = { type: [{target_id:'note'}], field_contenu: this.note } let config = { headers:{ "X-CSRF-Token": this.csrf_token } } REST.patch(`/node/${this.note_id}?_format=json`, params, config) .then(({ data }) => { console.log('updateNote REST data', data) }) .catch(error => { console.warn('Issue with updateNote', error) }) }, createNote(){ let params = { type: [{target_id:'note'}], title: [{value:`note`}], field_contenu: this.note, field_target: this.item.id } let config = { headers:{ "X-CSRF-Token": this.csrf_token } } REST.post('/node?_format=json', params, config) .then(({ data }) => { console.log('createNote REST data', data) this.note_id = data.nid[0].value // call search results refresh of the item to display that note is now existing for this item // this.refreshItem({id: this.item.id}) // no needs to refresh the entire item via searchresults // plus if we are in article, there is not searchresults // instead call the callbackfunction from the parent to add directly the note id this.addNoteId(this.note_id) }) .catch(error => { console.warn('Issue with createNote', error) }) }, onTapTool (e) { console.log('ontapTool', e) let tools = e.target.parentNode.parentNode.querySelectorAll('section.tool') tools.forEach((item, i) => { item.classList.remove('tapped') }) e.target.parentNode.classList.add('tapped') }, onTapCard (e) { console.log('ontapCard', e.target.tagName) // in case we tap on note's textarea if(e.target.tagName == "TEXTAREA"){ return; } let tools = this.$refs['tools'].querySelectorAll('section.tool') // console.log() tools.forEach((item, i) => { console.log('item', item) item.classList.remove('tapped') }) } } } </script> <style lang="scss" scoped> </style>