big refactoring, opening flagcollection (folder) on the left of main-content

This commit is contained in:
2020-11-27 23:02:59 +01:00
parent 420a879a4e
commit 93c4707c45
19 changed files with 656 additions and 253 deletions

View File

@@ -1,5 +1,5 @@
<template>
<article class="card">
<article class="card search-card">
<header>
<h1>{{ item.title }}</h1>
<h4>{{ item.field_short_description }}</h4>
@@ -45,10 +45,12 @@
<script>
import { mapState, mapActions } from 'vuex'
import cardMixins from 'vuejs/components/cardMixins'
export default {
name: "Card",
props: ['item'],
mixins: [cardMixins],
data() {
return {
blanksrc:`${drupalSettings.path.themePath}/assets/img/blank.gif`,
@@ -60,54 +62,6 @@ export default {
flagcolls: state => state.User.flagcolls
})
},
directives: {
lazy: {
bind(img,binding){
// console.log('lazy bind', img, binding);
if(binding.value === 0){
img.setAttribute('src', img.getAttribute('data-src'))
img.removeAttribute('data-src')
img.classList.remove('lazy')
}
}
},
switcher: {
inserted(el,binding){
// switch images on mousemove
el.addEventListener('mousemove', function(event) {
let figs = this.querySelectorAll('figure')
// console.log('mousemove', this, event, figs.length);
// let len = figs.length
// let w = this.clientWidth;
// let g = w / len;
// let delta = Math.floor(event.layerX / g)
let delta = Math.floor(event.layerX / (this.clientWidth / figs.length))
// console.log('delta', delta);
figs.forEach((fig, index) => {
// console.log(index);
if(index == delta){
fig.style.display = "block"
}else{
fig.style.display = "none"
}
})
})
}
}
},
mounted() {
// lazy load images on mouseover
this.$el.addEventListener('mouseover', function(event) {
let imgs = this.querySelectorAll('.images figure img.lazy')
// console.log('mouseover', this, imgs);
imgs.forEach((img) => {
// console.log('forEach img',img);
img.setAttribute('src', img.getAttribute('data-src'))
img.removeAttribute('data-src')
img.classList.remove('lazy')
})
}, {once : true})
},
methods: {
...mapActions({
flag: 'User/flag',

View File

@@ -0,0 +1,93 @@
<template>
<article class="card minicard">
<header>
<h1>{{ item.title }}</h1>
<span class="ref">{{ item.field_reference }}</span>
</header>
<nav class="tools">
<section class="tool flags">
<span class="mdi mdi-folder-remove-outline"/>
</section>
</nav>
<section class="images" v-switcher>
<figure
v-for="(img, index) in item.images"
:key="img.url"
>
<img
class="lazy"
v-lazy="index"
:data-src="img.url"
:title="img.title"
/>
<img class="blank" :src="blanksrc">
</figure>
</section>
</article>
</template>
<script>
import { mapState, mapActions } from 'vuex'
import cardMixins from 'vuejs/components/cardMixins'
export default {
name: "MiniCard",
props: ['item'],
mixins: [cardMixins],
data() {
return {
blanksrc:`${drupalSettings.path.themePath}/assets/img/blank.gif`,
// loadingFlag: false
}
},
computed: {
// ...mapState({
// flagcolls: state => state.User.flagcolls
// })
},
methods: {
// ...mapActions({
// flag: 'User/flag',
// unFlag: 'User/unFlag'
// }),
// 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;
// },
// 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);
// // console.log('collid', collid);
// // console.log("this.item", this.item);
// this.loadingFlag = collid;
// if (isActive) {
// this.unFlag({uuid: this.item.uuid, collid: collid})
// .then(data => {
// console.log("onFlagActionCard then", data);
// this.loadingFlag = false;
// })
// }else{
// this.flag({uuid: this.item.uuid, collid: collid})
// .then(data => {
// console.log("onFlagActionCard then", data);
// this.loadingFlag = false;
// })
// }
// }
// }
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -1,13 +1,16 @@
<template>
<div id="Base">
<div class="loading" v-if="!items.length">
<div class="loading" v-if="!searchinfos">
<span>Loading ...</span>
</div>
<div class="cards-list" v-else>
<aside class="search-info">
{{ searchinfos }}
</aside>
<ul>
<div class="loading" v-if="!items.length & !noresults">
<span>Loading ...</span>
</div>
<ul v-else>
<li v-for="item in items" v-bind:key="item.uuid">
<Card :item="item"/>
</li>
@@ -42,6 +45,7 @@ export default {
items: state => state.Search.items,
searchinfos: state => state.Search.infos,
count: state => state.Search.count,
noresults: state => state.Search.noresults,
limit: state => state.Search.limit
})
},

View File

@@ -1,11 +1,20 @@
<template>
<section class="flag-collection">
<h3>{{collection.name}}</h3>
<header>
<h3 class="mdi mdi-folder-outline">{{collection.name}}</h3>
<span
class="mdi mdi-close"
title="close"
@click.prevent="onCloseFlagColl"
/>
</header>
<ul v-if="loadedItems">
<li
v-for="item in loadedItems"
:key="item.id"
>{{item.attributes.title}}</li>
>
<MiniCard :item="item"/>
</li>
</ul>
<span v-else class="loading">Loading</span>
</section>
@@ -13,6 +22,7 @@
<script>
import { mapState, mapActions } from 'vuex'
import MiniCard from 'vuejs/components/Content/MiniCard'
export default {
name: "FlagCollection",
@@ -22,8 +32,8 @@ export default {
}),
computed: {
...mapState({
flagcolls: state => state.User.flagcolls
// openedCollid: state => state.User.openedCollid
flagcolls: state => state.User.flagcolls,
openedCollid: state => state.User.openedCollid
})
},
// watch: {
@@ -35,11 +45,22 @@ export default {
// }
// },
created() {
if (typeof this.collection.loadedItems !== 'undefined') {
// if loadedItems are alredy loaded,
// the mutation occurs before this subscription
// so we first check if they are already available
this.loadedItems = this.collection.loadedItems
}
this.unsubscribe = this.$store.subscribe((mutation, state) => {
if (mutation.type === 'User/setLoadedCollItems') {
this.loadedItems = state.User.flagcolls[this.collection.id].loadedItems
console.log("mutation setLoadedCollItems collid", this.openedCollid)
// mutation is triggered before the component update
// so this.collection.id is not good
this.loadedItems = state.User.flagcolls[this.openedCollid].loadedItems
}
});
})
},
beforeDestroy() {
this.unsubscribe()
@@ -49,11 +70,17 @@ export default {
// this.
// }
// },
// methods: {
// ...mapActions({
// loadFlagCollItems: 'User/loadFlagCollItems'
// })
// }
methods: {
...mapActions({
closeFlagColl: 'User/closeFlagColl'
}),
onCloseFlagColl(e) {
this.closeFlagColl()
}
},
components: {
MiniCard
}
}
</script>
<style lang="scss" scoped>

View File

@@ -26,7 +26,7 @@
<span
class="add-btn mdi"
:class="addFlagBtnClassObj"
@click.prevent="onCreateFlagColl"
@click.prevent.stop="onCreateFlagColl"
/>
</li>
</ul>
@@ -92,7 +92,7 @@ export default {
},
onOpenFlagColl (e) {
const flagcollid = e.target.getAttribute('flagcollid');
console.log("UserFlags onDeleteFlagColl", flagcollid);
console.log("UserFlags onOpenFlagColl", flagcollid);
this.openFlagColl(flagcollid)
.then(() => {
// console.log("onDeleteFlagColl then", data);

View File

@@ -0,0 +1,56 @@
// https://forum.vuejs.org/t/how-to-use-helper-functions-for-imported-modules-in-vuejs-vue-template/6266/5
export default {
directives: {
lazy: {
bind(img,binding){
// console.log('lazy bind', img, binding);
if(binding.value === 0){
img.setAttribute('src', img.getAttribute('data-src'))
img.removeAttribute('data-src')
img.classList.remove('lazy')
}
}
},
switcher: {
inserted(el,binding){
// switch images on mousemove
el.addEventListener('mousemove', function(event) {
let figs = this.querySelectorAll('figure')
// console.log('mousemove', this, event, figs.length);
// let len = figs.length
// let w = this.clientWidth;
// let g = w / len;
// let delta = Math.floor(event.layerX / g)
let delta = Math.floor(event.layerX / (this.clientWidth / figs.length))
// console.log('delta', delta);
figs.forEach((fig, index) => {
// console.log(index);
if(index == delta){
fig.style.display = "block"
}else{
fig.style.display = "none"
}
})
})
}
}
},
mounted() {
// lazy load images on mouseover
this.$el.addEventListener('mouseover', function(event) {
let imgs = this.querySelectorAll('.images figure img.lazy')
// console.log('mouseover', this, imgs);
imgs.forEach((img) => {
// console.log('forEach img',img);
img.setAttribute('src', img.getAttribute('data-src'))
img.removeAttribute('data-src')
img.classList.remove('lazy')
})
}, {once : true})
},
methods: {
// deg2rad (deg) {
// return deg * (Math.PI / 180)
// },
}
}

View File

@@ -1,5 +1,11 @@
import Vue from 'vue'
import Vuex from 'vuex'
import { createStore } from 'vuex-extensions'
import { JSONAPI } from 'vuejs/api/json-axios'
import qs from 'querystring-es3'
import Common from './modules/common'
import User from './modules/user'
import Search from './modules/search'
@@ -10,7 +16,8 @@ import Pages from './modules/pages'
// https://github.com/vuejs/vuex/tree/dev/examples/shopping-cart
Vue.use(Vuex)
export default new Vuex.Store({
// export default new Vuex.Store({
export default createStore(Vuex.Store, {
modules: {
Common,
User,
@@ -18,5 +25,87 @@ export default new Vuex.Store({
Blabla,
Showrooms,
Pages
},
// https://github.com/huybuidac/vuex-extensions
mixins: {
actions: {
loadMaterials ({ dispatch }, { uuids, imgStyle, callBack, callBackArgs }) {
const params = {
// include: 'images', // no needs to include thanks to consumers_image_styles module
// include: 'drupal_internal__nid',
'filter[uuids-groupe][group][conjunction]': 'OR'
}
for (let i = 0; i < uuids.length; i++) {
const uuid = uuids[i]
params[`filter[${uuid}][condition][path]`] = 'id'
params[`filter[${uuid}][condition][value]`] = uuid
params[`filter[${uuid}][condition][operator]`] = '='
params[`filter[${uuid}][condition][memberOf]`] = 'uuids-groupe'
}
// console.log('search JSONAPI params', params);
const q = qs.stringify(params)
return JSONAPI.get('node/materiau?' + q)
.then(({ data }) => {
console.log('mixin getMaterials data', data)
dispatch('parseMaterials', { data: data.data, uuids: uuids, imgStyle: imgStyle, callBack: callBack, callBackArgs: callBackArgs })
// commit('setItems', data.items)
})
.catch((error) => {
console.warn('Issue with getItems', error)
Promise.reject(error)
})
},
parseMaterials ({ dispatch }, { data, uuids, imgStyle, callBack, callBackArgs }) {
// data comes from jsonapi query
// uuids comes from original query (solr, FlagCollection, etc)
// so we loop from uuids to conserve the original order
console.log('mixin parseMaterials', data, uuids, callBack, callBackArgs)
const items = []
// for (var i = 0; i < data.length; i++) {
for (let i = 0; i < uuids.length; i++) {
const uuid = uuids[i]
// https://stackoverflow.com/questions/11258077/how-to-find-index-of-an-object-by-key-and-value-in-an-javascript-array
const item_index = data.findIndex(p => p.id === uuid)
// console.log('item_index', item_index);
if (item_index === -1) continue
const item_src = data[item_index]
const attrs = item_src.attributes
const relations = item_src.relationships
// get field values
const item = {
uuid: uuid,
title: attrs.title,
field_short_description: attrs.field_short_description,
body: attrs.body,
field_reference: attrs.field_reference
}
// get images included values
const img_src = relations.images.data
// console.log('img_src', img_src);
// this is a temporary deactivation of images
// img_src = [];
item.images = []
for (let j = 0; j < img_src.length; j++) {
if (img_src[j].meta.imageDerivatives) {
item.images.push({
title: img_src[j].meta.title,
// meta.imageDerivatives.style.href link is provided by drupal consumers_image_styles module
// BUG: missing all image derivative but first
url: img_src[j].meta.imageDerivatives.links.[imgStyle].href
})
} else {
console.warn('missing image derivative ' + j + '/' + img_src.length + ' for ' + attrs.title)
}
}
items.push(item)
}
console.log('items', items)
dispatch(callBack, { items: items, callBackArgs: callBackArgs })
}
}
}
})

View File

@@ -16,6 +16,7 @@ export default {
limit: 15,
infos: null,
count: 0,
noresults: false,
// infinteState will come from vue-infinite-loading plugin
// implemented in vuejs/components/Content/Base.vue
infiniteLoadingState: null
@@ -32,7 +33,7 @@ export default {
resetUuids (state) {
state.uuids = []
},
setItems (state, items) {
setMaterials (state, items) {
state.items = state.items.concat(items)
},
resetItems (state) {
@@ -50,6 +51,15 @@ export default {
setCount (state, count) {
state.count = count
},
resetCount (state, count) {
state.count = false
},
setNoresults (state) {
state.noresults = true
},
resetNoresults (state) {
state.noresults = false
},
resetOffset (state) {
state.offset = 0
},
@@ -67,6 +77,8 @@ export default {
console.log('Search newSearch')
commit('resetUuids')
commit('resetItems')
commit('resetCount')
commit('resetNoresults')
commit('resetOffset')
this.commit('Common/setPagetitle', state.keys)
dispatch('getResults')
@@ -92,89 +104,27 @@ export default {
// commit('setItems', data.items)
commit('setInfos', data.infos)
commit('setCount', data.count)
commit('setUuids', data.uuids)
dispatch('getItems', data.uuids)
if (data.count) {
commit('setUuids', data.uuids)
// loadMaterials is on mixins
// https://github.com/huybuidac/vuex-extensions
dispatch('loadMaterials', {
uuids: data.uuids,
imgStyle: 'card_medium',
callBack: 'loadMaterialsCallBack'
})
}else{
commit('setNoresults')
}
})
.catch((error) => {
console.warn('Issue with getResults', error)
Promise.reject(error)
})
},
getItems ({ dispatch, commit, state }, uuids) {
const params = {
// include: 'images', // no needs to include thanks to consumers_image_styles module
// include: 'drupal_internal__nid',
'filter[uuids-groupe][group][conjunction]': 'OR'
}
for (let i = 0; i < uuids.length; i++) {
const uuid = uuids[i]
params[`filter[${uuid}][condition][path]`] = 'id'
params[`filter[${uuid}][condition][value]`] = uuid
params[`filter[${uuid}][condition][operator]`] = '='
params[`filter[${uuid}][condition][memberOf]`] = 'uuids-groupe'
}
// console.log('search JSONAPI params', params);
const q = qs.stringify(params)
return JSONAPI.get('node/materiau?' + q)
.then(({ data }) => {
console.log('search getItems data', data)
dispatch('parseItems', { data: data.data, uuids: uuids })
// commit('setItems', data.items)
})
.catch((error) => {
console.warn('Issue with getItems', error)
Promise.reject(error)
})
},
parseItems ({ dispatch, commit, state }, { data, uuids }) {
// data comes from jsonapi query
// uuids comes from solr search query (we loop from uuids to conserve the search results order)
console.log('search parseItems data, uuids', data, uuids)
const items = []
// for (var i = 0; i < data.length; i++) {
for (let i = 0; i < uuids.length; i++) {
const uuid = uuids[i]
// https://stackoverflow.com/questions/11258077/how-to-find-index-of-an-object-by-key-and-value-in-an-javascript-array
const item_index = data.findIndex(p => p.id == uuid)
// console.log('item_index', item_index);
if (item_index == -1) continue
const item_src = data[item_index]
const attrs = item_src.attributes
const relations = item_src.relationships
// get field values
const item = {
uuid: uuid,
title: attrs.title,
field_short_description: attrs.field_short_description,
body: attrs.body,
field_reference: attrs.field_reference
}
// get images included values
const img_src = relations.images.data
// console.log('img_src', img_src);
// this is a temporary deactivation of images
// img_src = [];
item.images = []
for (let j = 0; j < img_src.length; j++) {
if (img_src[j].meta.imageDerivatives) {
item.images.push({
title: img_src[j].meta.title,
// meta.imageDerivatives.style.href link is provided by drupal consumers_image_styles module
// BUG: missing all image derivative but first
url: img_src[j].meta.imageDerivatives.links.card_medium.href
})
} else {
console.warn('missing image derivative ' + j + '/' + img_src.length + ' for ' + attrs.title)
}
}
items.push(item)
}
console.log('items', items)
commit('setItems', items)
loadMaterialsCallBack ({ commit, state }, { items, callBackArgs }) {
console.log('search loadMaterialsCallBack', items)
commit('setMaterials', items)
if (state.infiniteLoadingState) {
if (state.offset + state.limit > state.count) {
console.log('Search infinite completed')

View File

@@ -1,5 +1,5 @@
import { REST } from 'vuejs/api/rest-axios'
import { JSONAPI } from 'vuejs/api/json-axios'
// import { JSONAPI } from 'vuejs/api/json-axios'
import { MA } from 'vuejs/api/ma-axios'
import qs from 'querystring-es3'
@@ -89,9 +89,15 @@ export default {
openFlagColl (state, collid) {
state.openedCollid = collid
},
closeFlagColl (state) {
state.openedCollid = null
},
setLoadedCollItems (state, data) {
console.log('setLoadedCollItems', data)
state.flagcolls[data.collid].loadedItems = data.items
// if no data, we are just calling the mutation to trigger the component update
if (data) {
state.flagcolls[data.collid].loadedItems = data.items
}
}
},
@@ -270,38 +276,31 @@ export default {
})
})
},
openFlagColl ({ commit, dispatch }, collid) {
openFlagColl ({ commit, dispatch, state }, collid) {
console.log('user openFlagColl', collid)
commit('openFlagColl', collid)
dispatch('loadFlagCollItems', collid)
if (typeof state.flagcolls[collid].loadedItems === 'undefined') {
// if no loadedItems, load them
// loadMaterials is on mixins
// https://github.com/huybuidac/vuex-extensions
dispatch('loadMaterials', {
uuids: state.flagcolls[collid].items_uuids,
imgStyle: 'card_medium_half',
callBack: 'loadMaterialsCallBack',
callBackArgs: { collid: collid }
})
} else {
// call the mutation without data to only trigger the FlagCollection component update
commit('setLoadedCollItems')
}
},
loadFlagCollItems ({ commit, state }, collid) {
console.log('loadFlagCollItems', state.flagcolls[collid].items_uuids)
const params = {
'filter[uuids-groupe][group][conjunction]': 'OR'
}
const uuids = state.flagcolls[collid].items_uuids
// console.log('uuids', uuids)
for (let i = 0; i < uuids.length; i++) {
let uuid = uuids[i]
// console.log('uuid', uuid)
params[`filter[${uuid}][condition][path]`] = 'id'
params[`filter[${uuid}][condition][value]`] = uuid
params[`filter[${uuid}][condition][operator]`] = '='
params[`filter[${uuid}][condition][memberOf]`] = 'uuids-groupe'
}
console.log('search JSONAPI params', params);
const q = qs.stringify(params)
return JSONAPI.get('node/materiau?' + q)
.then(({ data }) => {
console.log('user loadFlagCollItems data', data)
// dispatch('parseItems', { data: data.data, uuids: uuids })
commit('setLoadedCollItems', {collid: collid, items: data.data})
})
.catch((error) => {
console.warn('Issue with loadFlagCollItems', error)
Promise.reject(error)
})
loadMaterialsCallBack ({ commit }, { items, callBackArgs }) {
console.log('user loadMaterialsCallBack', items)
commit('setLoadedCollItems', { collid: callBackArgs.collid, items: items })
},
closeFlagColl ({ commit, dispatch }) {
console.log('user closeFlagColl')
commit('closeFlagColl')
},
userLogout ({ commit, state }) {
const credentials = qs.stringify({