124 lines
3.1 KiB
JavaScript
124 lines
3.1 KiB
JavaScript
import Vue from 'vue';
|
|
import Draggable from 'vuedraggable';
|
|
import { fire, debounce } from '@utils';
|
|
|
|
import DraggableItem from './DraggableItem';
|
|
import DraggableList from './DraggableList';
|
|
|
|
Vue.component('Draggable', Draggable);
|
|
Vue.component('DraggableItem', DraggableItem);
|
|
|
|
addEventListener('DOMContentLoaded', () => {
|
|
const el = document.querySelector('#champs-editor');
|
|
if (el) {
|
|
initEditor(el);
|
|
}
|
|
});
|
|
|
|
function initEditor(el) {
|
|
const { directUploadsUrl, dragIconUrl } = el.dataset;
|
|
|
|
const state = {
|
|
typesDeChamp: JSON.parse(el.dataset.typesDeChamp),
|
|
typesDeChampOptions: JSON.parse(el.dataset.typesDeChampOptions),
|
|
directUploadsUrl,
|
|
dragIconUrl,
|
|
isAnnotation: el.dataset.type === 'annotation',
|
|
unsavedItems: new Set(),
|
|
unsavedInvalidItems: new Set(),
|
|
version: 1,
|
|
prefix: 'procedure'
|
|
};
|
|
|
|
new Vue({
|
|
el,
|
|
data: {
|
|
state,
|
|
update: null
|
|
},
|
|
render(h) {
|
|
return h(DraggableList, {
|
|
props: {
|
|
state: this.state,
|
|
update: this.update,
|
|
updateAll: this.updateAll
|
|
}
|
|
});
|
|
},
|
|
mounted() {
|
|
const [update, updateAll] = createUpdateFunctions(
|
|
this,
|
|
state.isAnnotation
|
|
);
|
|
|
|
this.update = update;
|
|
this.updateAll = updateAll;
|
|
|
|
// We add an initial type de champ here if form is empty
|
|
if (this.state.typesDeChamp.length === 0) {
|
|
this.state.typesDeChamp.push({
|
|
type_champ: 'text',
|
|
types_de_champ: []
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function createUpdateFunctions(app, isAnnotation) {
|
|
let isSaving = false;
|
|
const form = app.$el.closest('form');
|
|
|
|
const update = ([id, isValid], refresh = true) => {
|
|
app.state.unsavedItems.add(id);
|
|
if (isValid) {
|
|
app.state.unsavedInvalidItems.delete(id);
|
|
} else {
|
|
app.state.unsavedInvalidItems.add(id);
|
|
}
|
|
if (refresh) {
|
|
app.state.version += 1;
|
|
}
|
|
updateAll();
|
|
};
|
|
|
|
const updateAll = debounce(() => {
|
|
if (isSaving) {
|
|
updateAll();
|
|
} else if (
|
|
app.state.typesDeChamp.length > 0 &&
|
|
app.state.unsavedInvalidItems.size === 0
|
|
) {
|
|
isSaving = true;
|
|
app.state.unsavedItems.clear();
|
|
app.state.version += 1;
|
|
fire(form, 'submit');
|
|
}
|
|
}, 500);
|
|
|
|
addEventListener('ProcedureUpdated', event => {
|
|
const { types_de_champ, types_de_champ_private } = event.detail;
|
|
|
|
app.state.typesDeChamp = isAnnotation
|
|
? types_de_champ_private
|
|
: types_de_champ;
|
|
isSaving = false;
|
|
updateFileInputs();
|
|
});
|
|
|
|
return [update, updateAll];
|
|
}
|
|
|
|
// This is needed du to the way ActiveStorage javascript integration works.
|
|
// It is built to be used with traditional forms. Another way would be to not use
|
|
// high level ActiveStorage abstractions (and maybe this is what we should do in the future).
|
|
function updateFileInputs() {
|
|
for (let element of document.querySelectorAll('.direct-upload')) {
|
|
let hiddenInput = element.nextElementSibling;
|
|
let fileInput = hiddenInput.nextElementSibling;
|
|
element.remove();
|
|
hiddenInput.remove();
|
|
fileInput.value = '';
|
|
fileInput.removeAttribute('disabled');
|
|
}
|
|
}
|