import Vue from 'vue' import router from '@/router' import api from '@/api' import { parseNodesQueryParams, getUniqueNodesIds, getRelatedNodesIds, getRandomIds, parseTree, buildTree } from '@/store/utils.js' export default { state: { trees: {}, randomNodes: undefined, nodebook: [], // LibraryOptions options tagsOptions: [], // LibraryOptions state mode: undefined, nodeDepartId: undefined, search: '', tags: [], strangeness: undefined }, mutations: { // ╷ ╶┬╴┌─╮┌─╮╭─┐┌─╮╷ ╷ // │ │ │╶┤├┬╯├─┤├┬╯╰─┤ // ╰─╴╶┴╴└─╯╵ ╰╵ ╵╵ ╰╶─╯ 'SET_NODEBOOK' (state, nodes) { state.nodebook = nodes }, 'ADD_NODEBOOK_NODE' (state, [stack, parentId, childId]) { if (stack === undefined) { stack = childId === undefined ? [parentId] : [parentId, childId] state.nodebook.push(stack) return } if (stack !== undefined && parentId !== undefined) { state.nodebook.push(state.nodebook.splice(state.nodebook.indexOf(stack), 1)[0]) } if (childId) { if (stack.includes(childId)) { stack.push(stack.splice(stack.indexOf(childId), 1)[0]) } else { stack.push(childId) } } }, 'REMOVE_NODEBOOK_NODE' (state, [stack, nodeId]) { if (stack[0] === nodeId) { state.nodebook.splice(state.nodebook.indexOf(stack), 1) } else { stack.splice(stack.indexOf(nodeId), 1) } }, 'ADD_NODE_TREE' (state, [id, tree]) { Vue.set(state.trees, id, tree) }, // ╭─╮┌─╮╶┬╴╶┬╴╭─╮╭╮╷╭─╴ // │ │├─╯ │ │ │ ││││╰─╮ // ╰─╯╵ ╵ ╶┴╴╰─╯╵╰╯╶─╯ 'SET_TAGS_OPTIONS' (state, nodes) { const tags = nodes.reduce((tags, node) => tags.concat(node.tags || []), []) state.tagsOptions = Array.from(new Set(tags.map(tag => tag.name))) }, 'UPDATE_TAGS' (state, tags) { state.tags = tags }, 'UPDATE_STRANGENESS' (state, strangenessLvl) { state.strangeness = strangenessLvl }, 'SET_MODE' (state, mode) { state.mode = mode }, 'SET_NODE_DEPART_ID' (state, id) { state.nodeDepartId = id }, 'SET_RANDOM_NODES' (state, ids) { state.randomNodes = ids }, 'SET_SEARCH' (state, str) { state.search = str } }, actions: { // ╷ ╶┬╴┌─╮┌─╮╭─┐┌─╮╷ ╷ // │ │ │╶┤├┬╯├─┤├┬╯╰─┤ // ╰─╴╶┴╴└─╯╵ ╰╵ ╵╵ ╰╶─╯ async 'INIT_LIBRARY' ({ state, commit, dispatch, rootState }, { dataLevel = 'initial' } = {}) { await dispatch('GET_ALL_NODES_IDS', { variant: 'depart', dataLevel }) if (state.nodebook && state.nodebook.length) { commit('UPDATE_OPTIONS_VISIBILITY', false) } return rootState.ids.depart }, async 'INIT_LIBRARY_TREE' ({ state, commit, dispatch, rootState }) { const ids = await dispatch('INIT_LIBRARY') // set Katalin Molnár "Quant à je" (id: 8) as default selected node return dispatch('SET_NODE_DEPART_ID', 8) }, async 'INIT_LIBRARY_MAP' ({ state, commit, dispatch }) { await dispatch('INIT_LIBRARY') return dispatch('ROLL_RANDOM_NODES') }, async 'INIT_LIBRARY_LIST' ({ state, commit, dispatch }) { const departIds = await dispatch('INIT_LIBRARY', { dataLevel: 'partial' }) const nodes = await dispatch('GET_NODES', { ids: departIds, dataLevel: 'partial' }) commit('SET_TAGS_OPTIONS', nodes) return nodes }, async 'UPDATE_NODEBOOK' ({ state, commit, dispatch }, query) { const { mode = 'tree', nodebook } = parseNodesQueryParams(query) commit('SET_MODE', mode) const ids = [].concat(...nodebook) await dispatch('GET_NODES', { ids, dataLevel: 'full' }) commit('SET_NODEBOOK', nodebook) commit('ADD_HISTORY_ENTRIES', ids) }, // ╭╮╷╭─╮┌─╮┌─╴╭─╴ // ││││ ││ │├─╴╰─╮ // ╵╰╯╰─╯└─╯╰─╴╶─╯ 'UPDATE_QUERY_NODES' ({ state }) { const query = { mode: state.mode, nodes: [...state.nodebook.map(ids => ids.join(','))] } if (router.currentRoute.name !== 'library') { router.push({ name: 'library', query }) } else { router.push({ query }) } }, async 'OPEN_NODE' ({ state, commit, dispatch }, { parentId, childId }) { if (state.nodebook === undefined || !state.nodebook.length) { commit('UPDATE_OPTIONS_VISIBILITY', false) } const stack = state.nodebook.find(stack => stack[0] === parentId) commit('ADD_NODEBOOK_NODE', [stack, parentId, childId]) dispatch('UPDATE_QUERY_NODES') commit('ADD_HISTORY_ENTRIES', [childId || parentId]) }, 'CLOSE_NODE' ({ state, commit, dispatch }, { parentId, childId }) { const stack = state.nodebook.find(stack => stack.includes(parentId) && (childId ? stack.includes(childId) : true)) commit('REMOVE_NODEBOOK_NODE', [stack, childId || parentId]) if (!state.nodebook.length) { commit('UPDATE_OPTIONS_VISIBILITY', true) } dispatch('UPDATE_QUERY_NODES') }, // ╭─╮┌─╮╶┬╴╶┬╴╭─╮╭╮╷╭─╴ // │ │├─╯ │ │ │ ││││╰─╮ // ╰─╯╵ ╵ ╶┴╴╰─╯╵╰╯╶─╯ async 'SET_NODE_DEPART_ID' ({ state, rootState, commit, dispatch, getters }, id) { if (state.nodeDepartId === id) return commit('SET_NODE_DEPART_ID', id) if (!(id in state.trees)) { const treeData = parseTree(await api.queryRecursiveNodes([id])) const nodes = await dispatch('GET_NODES', { ids: getUniqueNodesIds(treeData), dataLevel: 'initial' }) commit('ADD_NODE_TREE', [id, buildTree(treeData, nodes)]) } return getters.nodeTree }, async 'ROLL_RANDOM_NODES' ({ state, rootState, commit, dispatch }) { commit('SET_RANDOM_NODES', undefined) const ids = getRandomIds(rootState.ids.depart) const departNodes = await dispatch('GET_NODES', { ids, dataLevel: 'partial' }) const relatedIds = getRelatedNodesIds(departNodes, ids) const relatedNodes = await dispatch('GET_NODES', { ids: relatedIds, dataLevel: 'partial' }) const nodes = [...departNodes, ...relatedNodes] commit('SET_RANDOM_NODES', [...ids, ...relatedIds]) commit('SET_TAGS_OPTIONS', nodes) }, 'UPDATE_QUERY_MODE' (store, mode) { if (router.currentRoute.query.mode === mode) return router.push({ query: { mode } }) } }, getters: { // LibraryOptions state mode: state => state.mode, nodeDepartId: state => state.nodeDepartId, search: state => state.search, tags: state => state.tags, strangeness: state => state.strangeness, // LibraryOptions options tagsOptions: state => state.tagsOptions, nodesDeparts: (state, getters, rootState) => { const departIds = rootState.ids.depart if (departIds === undefined) return const nodes = departIds.map(id => rootState.nodes[id]) if (nodes.some(node => node === undefined)) return return nodes }, nodesDepartsOptions: (state, getters, rootState) => { const nodes = getters.nodesDeparts if (nodes === undefined) return return nodes.sort((a, b) => { const prev = a.authors[0].last_name.toLowerCase() const next = b.authors[0].last_name.toLowerCase() if (prev === next) return 0 return prev < next ? -1 : 1 }) }, // Library nodebook: (state, getters, rootState) => { return state.nodebook.map(([parentId, ...childrenIds]) => { return { parent: rootState.nodes[parentId], children: childrenIds.map(id => rootState.nodes[id]) } }) }, // LibraryList orderedTextsDepart: (state, getters, rootState) => { const departIds = rootState.ids.depart if (departIds === undefined || rootState.nodes[departIds[0]] === undefined) return const nodesDict = {} for (const node of rootState.ids.depart.map(id => rootState.nodes[id])) { if (!node.authors) { if (!('~' in nodesDict)) nodesDict['~'] = [] nodesDict['~'].push(node) } else { node.authors.forEach((author, i) => { const firstChar = author.last_name[0].toUpperCase() if (!(firstChar in nodesDict)) nodesDict[firstChar] = [] nodesDict[firstChar].push({ last_name: author.last_name, node }) }) } } return Object.entries(nodesDict).sort((a, b) => a[0] < b[0] ? -1 : 1).map(group => { if (group[0] === '~') return group return [group[0], group[1].sort((a, b) => { const prev = a.last_name.toLowerCase() const next = b.last_name.toLowerCase() return prev.localeCompare(next) }).map(node => node.node)] }) }, // LibraryMap randomNodes: (state, getters, rootState) => { if (state.randomNodes === undefined) return return state.randomNodes.map(id => rootState.nodes[id]) }, // LibraryTree nodeTree: state => { return state.trees[state.nodeDepartId] || { nodes: [], links: [] } }, // Commons activeNodes: state => { if (!state.nodebook) return [] return state.nodebook.reduce((acc, ids) => [...acc, ...ids], []) } } }