Commit 3200717b authored by Eva Bardou's avatar Eva Bardou Committed by Bastien Abadie
Browse files

Convert store singleton to Vuex

parent 650813bf
......@@ -1545,6 +1545,11 @@
"resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz",
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw=="
},
"vuex": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.0.tgz",
"integrity": "sha512-W74OO2vCJPs9/YjNjW8lLbj+jzT24waTo2KShI8jLvJW8OaIkgb3wuAMA7D+ZiUxDOx3ubwSZTaJBip9G8a3aQ=="
},
"watchpack": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.0.tgz",
......
......@@ -32,7 +32,8 @@
"undo-manager": "^1.0.5",
"vue": "^2.6.11",
"vue-loader": "^15.9.6",
"vue-template-compiler": "^2.6.11"
"vue-template-compiler": "^2.6.11",
"vuex": "^3.6.0"
},
"devDependencies": {
"compression-webpack-plugin": "^7.1.1",
......
......@@ -16,16 +16,10 @@ export const createContent = async (document_id, part_id, data) => (await axios.
export const updateContent = async (document_id, part_id, id, data) => (await axios.put(`/documents/${document_id}/parts/${part_id}/transcriptions/${id}/`, data))
export const createLine = async (document_id, part_id, data) => (await axios.post(`/documents/${document_id}/parts/${part_id}/lines/`, data))
export const bulkCreateLines = async (document_id, part_id, data) => (await axios.post(`/documents/${document_id}/parts/${part_id}/lines/bulk_create/`, data))
export const updateLine = async (document_id, part_id, id, data) => (await axios.put(`/documents/${document_id}/parts/${part_id}/lines/${id}/`, data))
export const bulkUpdateLines = async (document_id, part_id, data) => (await axios.put(`/documents/${document_id}/parts/${part_id}/lines/bulk_update/`, data))
export const deleteLine = async (document_id, part_id, id) => (await axios.delete(`/documents/${document_id}/parts/${part_id}/lines/${id}/`))
export const bulkDeleteLines = async (document_id, part_id, data) => (await axios.post(`/documents/${document_id}/parts/${part_id}/lines/bulk_delete/`, data))
export const recalculateMasks = async (document_id, part_id, data, params) => (await axios.post(`/documents/${document_id}/parts/${part_id}/reset_masks/`, data, { params: params }))
......
import Vue from 'vue'
import Vuex from 'vuex'
import parts from './store/parts'
import lines from './store/lines'
import regions from './store/regions'
import transcriptions from './store/transcriptions'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
parts,
lines,
regions,
transcriptions
}
})
\ No newline at end of file
window.Vue = require('vue/dist/vue');
import store from './index.js';
import Editor from '../../vue/components/Editor.vue';
export var partVM = new Vue({
el: "#editor",
store,
components: {
'editor': Editor,
}
......
import { assign } from 'lodash'
import * as api from '../api'
export const initialState = () => ({
lines: [],
// internal
masksToRecalc: [],
debouncedRecalculateMasks: null,
debouncedRecalculateOrdering: null
})
export const getters = {
hasMasks: state => {
return state.lines.findIndex(l=>l.mask!=null) != -1
}
}
export const mutations = {
setLines (state, lines) {
assign(state.lines, lines.map(l => ({ ...l, loaded: true })))
},
appendLine (state, line) {
state.lines.push({ ...line, loaded: false })
},
loadLine (state, pk) {
let index = state.lines.findIndex(l => l.pk == pk)
state.lines[index].loaded = true
},
updateLine (state, line) {
let index = state.lines.findIndex(l => l.pk == line.pk)
state.lines[index].baseline =line.baseline
state.lines[index].mask =line.mask
state.lines[index].region =line.region
},
removeLine (state, index) {
Vue.delete(state.lines, index)
},
updateLinesOrder (state, { lines, recalculate }) {
for (let i=0; i<lines.length; i++) {
let lineData = lines[i]
let index = state.lines.findIndex(l => l.pk == lineData.pk)
if (index != -1) {
if (recalculate) {
state.lines[index] = { ...state.lines[index], order: i }
} else {
state.lines[index] = { ...state.lines[index], order: lineData.order }
}
}
}
},
updateLinesCurrentTrans (state, transcription) {
state.lines = state.lines.map(line => {
if (!line.transcriptions[transcription]) return line
return { ...line, currentTrans: line.transcriptions[transcription] }
})
},
setMasksToRecalc (state, value) {
state.masksToRecalc = value
},
setLineTranscriptions (state, { pk, transcription }) {
let index = state.lines.findIndex(l => l.pk == pk)
if (index < 0) return
let tr = state.lines[index].transcriptions || {}
if (transcription) {
tr[transcription.transcription] = transcription
state.lines[index] = { ...state.lines[index], transcriptions: tr }
}
state.lines[index] = { ...state.lines[index], currentTrans: transcription }
},
createLineTranscriptions (state, createdTranscriptions) {
for (let i=0; i<createdTranscriptions.lines.length; i++) {
let lineTrans = createdTranscriptions.lines[i]
let index = state.lines.findIndex(l => l.pk == lineTrans.line)
if (index < 0) return
state.lines[index] = {
...state.lines[index],
currentTrans: { ...state.lines[index].currentTrans, pk: lineTrans.pk }
}
}
},
updateLineTranscriptionVersion (state, { pk, content }) {
let index = state.lines.findIndex(l=>l.pk == pk)
if (index < 0) return
state.lines[index] = {
...state.lines[index],
currentTrans: { ...state.lines[index].currentTrans, content: content }
}
},
reset (state) {
if (state.debouncedRecalculateMasks) {
state.debouncedRecalculateMasks.flush()
}
if (state.debouncedRecalculateOrdering) {
state.debouncedRecalculateOrdering.flush()
}
assign(state, initialState())
}
}
export const actions = {
async bulkCreateLines({commit, dispatch, getters, rootState}, {lines, transcription}) {
lines.forEach(l=>l.document_part = rootState.parts.pk)
const resp = await api.bulkCreateLines(rootState.parts.documentId, rootState.parts.pk, {lines: lines})
let data = resp.data
let createdLines = []
for (let i=0; i<data.lines.length; i++) {
let l = data.lines[i]
let newLine = l
newLine.currentTrans = {
line: newLine.pk,
transcription: transcription,
content: '',
versions: [],
version_author: '',
version_source: '',
version_updated_at: null
}
createdLines.push(newLine)
commit('appendLine', newLine)
}
await dispatch('recalculateOrdering')
if (getters.hasMasks) {
await dispatch('recalculateMasks', createdLines.map(l=>l.pk))
}
return createdLines
},
async bulkUpdateLines({state, commit, dispatch, getters, rootState}, lines) {
let dataLines = lines.map(function(l) {
let type = l.type && rootState.parts.types.lines.find(t=>t.name==l.type)
return {
pk: l.pk,
document_part: rootState.parts.pk,
baseline: l.baseline,
mask: l.mask,
region: l.region,
typology: type && type.pk || null
}
})
const resp = await api.bulkUpdateLines(rootState.parts.documentId, rootState.parts.pk, {lines: dataLines})
let data = resp.data
let updatedLines = []
let updatedBaselines = []
for (let i=0; i<data.lines.length; i++) {
let lineData = data.lines[i]
let line = state.lines.find(function(l) {
return l.pk==lineData.pk
})
if (line) {
if (!_.isEqual(line.baseline, lineData.baseline)) {
updatedBaselines.push(line)
}
commit('updateLine', lineData)
updatedLines.push(line)
}
}
if (getters.hasMasks && updatedBaselines.length) {
await dispatch('recalculateMasks', updatedBaselines.map(l=>l.pk))
}
return updatedLines
},
async bulkDeleteLines({state, dispatch, commit, rootState}, pks) {
await api.bulkDeleteLines(rootState.parts.documentId, rootState.parts.pk, {lines: pks})
let deletedLines = []
for (let i=0; i<pks.length; i++) {
let index = state.lines.findIndex(l=>l.pk==pks[i])
if (index != -1) {
deletedLines.push(pks[i])
commit('removeLine', index)
}
}
await dispatch('recalculateOrdering')
return deletedLines
},
async moveLines({commit, rootState}, movedLines) {
const resp = await api.moveLines(rootState.parts.documentId, rootState.parts.pk, {"lines": movedLines})
let data = resp.data
commit('updateLinesOrder', { lines: data, recalculate: false })
},
recalculateMasks({state, commit, rootState}, only=[]) {
commit('setMasksToRecalc', _.uniq(state.masksToRecalc.concat(only)))
if (!state.debouncedRecalculateMasks) {
// avoid calling this too often
state.debouncedRecalculateMasks = _.debounce(async function(only) {
const params = {}
if (state.masksToRecalc.length > 0) params.only = state.masksToRecalc.toString()
commit('setMasksToRecalc', [])
try {
await api.recalculateMasks(rootState.parts.documentId, rootState.parts.pk, {}, params)
} catch (err) {
console.log('couldnt recalculate masks!', err)
}
}, 2000)
}
state.debouncedRecalculateMasks(only)
},
recalculateOrdering({state, commit, rootState}) {
if (!state.debouncedRecalculateOrdering) {
// avoid calling this too often
state.debouncedRecalculateOrdering = _.debounce(async function() {
try {
const resp = await api.recalculateOrdering(rootState.parts.documentId, rootState.parts.pk, {})
let data = resp.data
commit('updateLinesOrder', { lines: data.lines, recalculate: true })
} catch (err) {
console.log('couldnt recalculate ordering!', err)
}
}, 1000)
}
state.debouncedRecalculateOrdering()
},
}
export default {
namespaced: true,
state: initialState(),
getters,
mutations,
actions
}
\ No newline at end of file
import * as api from '../api'
// singleton!
export const partStore = {
// need to set empty value for vue to watch them
documentId: null,
loaded: false,
pk: null,
lines: [],
regions: [],
image: {},
transcriptions: [],
// internal
masksToRecalc: [],
// mutators
load (part) {
// for each line/region enrich the correct type depending on typology id
part.lines.forEach(function(line) {
let type_ = line.typology && this.types.lines.find(t=>t.pk == line.typology);
line.type = type_ && type_.name;
}.bind(this));
part.regions.forEach(function(reg) {
let type_ = reg.typology && this.types.regions.find(t=>t.pk == reg.typology)
reg.type = type_ && type_.name;
}.bind(this));
// will trigger all bindings
Object.assign(this, part);
this.loaded = true;
},
// helpers
hasPrevious() { return this.loaded && this.previous !== null },
hasNext() { return this.loaded && this.next !== null; },
// properties
get hasMasks() {
return this.lines.findIndex(l=>l.mask!=null) != -1;
},
loadTranscription (line, transcription) {
let tr = line.transcriptions || {};
if (transcription) {
tr[transcription.transcription] = transcription;
Vue.set(line, 'transcriptions', tr);
}
},
// actions
fetchPart(pk, callback) {
this.pk = pk;
this.fetchDocument(function() {
api.retrieveDocumentPart(this.documentId, pk)
.then(function(response) {
let data = response.data;
this.load(data, callback);
if (callback) callback(data);
}.bind(this))
.catch(function(error) {
console.log('couldnt fetch part data!', error);
});
}.bind(this));
},
fetchDocument(callback) {
if (this.transcriptions.length) { // assuming there is always at least one
if (callback) callback({
'transcriptions': this.transcriptions,
'types': this.types
});
return;
}
api.retrieveDocument(this.documentId)
.then(function(response) {
let data = response.data;
this.transcriptions = data.transcriptions;
this.types = {
'regions': data.valid_block_types,
'lines': data.valid_line_types
};
if (callback) callback(data);
}.bind(this));
},
fetchContent(transcription, callback) {
// first create a default transcription for every line
this.lines.forEach(function(line) {
this.loadTranscription(line, {
line: line.pk,
transcription: transcription,
content: '',
version_author: null,
version_source: null,
version_updated_at: null
});
}.bind(this));
// then fetch all content page by page
let fetchPage = function(page) {
api.retrievePage(this.documentId, this.pk, transcription, page)
.then(function(response) {
let data = response.data;
for (var i=0; i<data.results.length; i++) {
let line = this.lines.find(l=>l.pk == data.results[i].line);
this.loadTranscription(line, data.results[i]);
}
if (data.next) fetchPage(page+1);
else if (callback) callback(data);
}.bind(this));
}.bind(this);
fetchPage(1);
},
pushContent(lineTranscription) {
let data = {
content: lineTranscription.content,
line: lineTranscription.line,
transcription: lineTranscription.transcription
}
let pushContentAction = api.createContent;
let params = [this.documentId, this.pk];
if (lineTranscription.pk) {
pushContentAction = api.updateContent
params.push(lineTranscription.pk);
}
pushContentAction(...params, data)
.then((response) => {
let data = response.data;
let line = this.lines.find(l=>l.pk == lineTranscription.line);
this.loadTranscription(line, data);
line.currentTrans = data;
})
.catch(function(error) {
console.log('couldnt update transcription!', error);
}.bind(this));
},
createLine(line, transcription, callback) {
let data = {
document_part: this.pk,
baseline: line.baseline,
mask: line.mask,
region: line.region
};
api.createLine(this.documentId, this.pk, data)
.then(function(response) {
let newLine = response.data;
newLine.currentTrans = {
line: newLine.pk,
transcription: transcription,
content: '',
versions: [],
version_author: '',
version_source: '',
version_updated_at: null
};
this.lines.push(newLine);
this.recalculateOrdering();
if (this.hasMasks) {
this.recalculateMasks();
}
callback(newLine);
}.bind(this))
.catch(function(error) {
console.log('couldnt create line', error)
});
},
bulkCreateLines(lines, transcription, callback) {
lines.forEach(l=>l.document_part = this.pk);
api.bulkCreateLines(this.documentId, this.pk, {lines: lines})
.then(function(response) {
let data = response.data;
let createdLines = [];
for (let i=0; i<data.lines.length; i++) {
let l = data.lines[i];
let newLine = l;
newLine.currentTrans = {
line: newLine.pk,
transcription: transcription,
content: '',
versions: [],
version_author: '',
version_source: '',
version_updated_at: null
}
createdLines.push(newLine)
this.lines.push(newLine);
}
this.recalculateOrdering();
if (this.hasMasks) {
this.recalculateMasks(createdLines.map(l=>l.pk));
}
callback(createdLines);
}.bind(this))
.catch(function(error) {
console.log('couldnt create lines', error)
});
},
updateLine(line, callback) {
line.document_part = this.pk;
api.updateLine(this.documentId, this.pk, line.pk, line)
.then(function(response) {
let data = response.data;
let index = this.lines.findIndex(l=>l.pk==line.pk);
this.lines[index].baseline = data.baseline;
this.lines[index].mask = data.mask;
callback(this.lines[index]);
}.bind(this))
.catch(function(error) {
console.log('couldnt update line', error)
});
},
bulkUpdateLines(lines, callback) {
let data = lines.map(function(l) {
let type = l.type && this.types.lines.find(t=>t.name==l.type)
return {
pk: l.pk,
document_part: this.pk,
baseline: l.baseline,
mask: l.mask,
region: l.region,
typology: type && type.pk || null
};
}.bind(this));
api.bulkUpdateLines(this.documentId, this.pk, {lines: data})
.then(function(response) {
let data = response.data;
let updatedLines = [];
let updatedBaselines = [];
for (let i=0; i<data.lines.length; i++) {
let lineData = data.lines[i];
let line = this.lines.find(function(l) {
return l.pk==lineData.pk;
});
if (line) {
if (!_.isEqual(line.baseline, lineData.baseline)) {
updatedBaselines.push(line)
}
line.baseline = lineData.baseline;
line.mask = lineData.mask;
line.region = lineData.region;
updatedLines.push(line);
}
}
if (this.hasMasks && updatedBaselines.length) {
this.recalculateMasks(updatedBaselines.map(l=>l.pk));
}
if (callback) callback(updatedLines);
}.bind(this))
.catch(function(error) {
console.log('couldnt update line', error)
});
},
deleteLine(linePk, callback) {
api.deleteLine(this.documentId, this.pk, linePk)
.then(function(response) {
let index = this.lines.findIndex(l=>l.pk==linePk);
Vue.delete(this.part.lines, index);
this.recalculateOrdering();
}.bind(this))
.catch(function(error) {
console.log('couldnt delete line #', linePk)
});
},
bulkDeleteLines(pks, callback) {
api.bulkDeleteLines(this.documentId, this.pk, {lines: pks})
.then(function(response) {
let deletedLines = [];
for (let i=0; i<pks.length; i++) {
let index = this.lines.findIndex(l=>l.pk==pks[i]);
if(index != -1) {
deletedLines.push(pks[i]);
Vue.delete(this.lines, index);