New champs editor
This commit is contained in:
parent
e1a1a2b2ad
commit
0d35295d4e
9 changed files with 605 additions and 0 deletions
1
app/assets/images/icons/drag.svg
Normal file
1
app/assets/images/icons/drag.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20 9H4v2h16V9zM4 15h16v-2H4v2z"/></svg>
|
After Width: | Height: | Size: 132 B |
|
@ -107,6 +107,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type=checkbox] {
|
||||||
|
&.small-margin {
|
||||||
|
margin-bottom: $default-padding / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
input[type=text]:not([data-address='true']),
|
input[type=text]:not([data-address='true']),
|
||||||
input[type=email],
|
input[type=email],
|
||||||
input[type=password],
|
input[type=password],
|
||||||
|
|
137
app/assets/stylesheets/new_design/procedure_champs_editor.scss
Normal file
137
app/assets/stylesheets/new_design/procedure_champs_editor.scss
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
@import "colors";
|
||||||
|
|
||||||
|
#champs-editor {
|
||||||
|
.spinner {
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-top: 80px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggable-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
border: 1px solid $border-grey;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.handle {
|
||||||
|
cursor: ns-resize;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
text-align: center;
|
||||||
|
flex-grow: 1;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $light-grey;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-around;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
background-color: $medium-red;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.type-header-section {
|
||||||
|
background-color: $blue;
|
||||||
|
|
||||||
|
label {
|
||||||
|
color: $light-grey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.type-header-section) {
|
||||||
|
input.error {
|
||||||
|
border: 1px solid $medium-red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.column {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
&.shift-left {
|
||||||
|
margin-left: 35px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
&.section {
|
||||||
|
padding: 10px 10px 0 10px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.hr {
|
||||||
|
border-bottom: 1px solid $border-grey;
|
||||||
|
|
||||||
|
&.head {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.shift-left {
|
||||||
|
margin-left: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.head {
|
||||||
|
select {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.delete {
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell {
|
||||||
|
margin-right: 20px;
|
||||||
|
|
||||||
|
&.small {
|
||||||
|
width: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.libelle {
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.carte-options {
|
||||||
|
label {
|
||||||
|
font-weight: initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header,
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 30px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
131
app/javascript/new_design/administrateur/DraggableItem.js
Normal file
131
app/javascript/new_design/administrateur/DraggableItem.js
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
export default {
|
||||||
|
props: ['state', 'update', 'index', 'item', 'prefix'],
|
||||||
|
computed: {
|
||||||
|
isDirty() {
|
||||||
|
return (
|
||||||
|
this.state.version &&
|
||||||
|
this.state.unsavedInvalidItems.size > 0 &&
|
||||||
|
this.state.unsavedItems.has(this.itemId)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
isInvalid() {
|
||||||
|
if (this.deleted) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.libelle) {
|
||||||
|
return !this.libelle.trim();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
itemId() {
|
||||||
|
return this.item.id || this.clientId;
|
||||||
|
},
|
||||||
|
changeLog() {
|
||||||
|
return [this.itemId, !this.isInvalid];
|
||||||
|
},
|
||||||
|
itemClassName() {
|
||||||
|
const classNames = [`draggable-item-${this.index}`];
|
||||||
|
if (this.isHeaderSection) {
|
||||||
|
classNames.push('type-header-section');
|
||||||
|
}
|
||||||
|
if (this.isDirty) {
|
||||||
|
if (this.isInvalid) {
|
||||||
|
classNames.push('invalid');
|
||||||
|
} else {
|
||||||
|
classNames.push('dirty');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return classNames.join(' ');
|
||||||
|
},
|
||||||
|
isDropDown() {
|
||||||
|
return [
|
||||||
|
'drop_down_list',
|
||||||
|
'multiple_drop_down_list',
|
||||||
|
'linked_drop_down_list'
|
||||||
|
].includes(this.typeChamp);
|
||||||
|
},
|
||||||
|
isFile() {
|
||||||
|
return this.typeChamp === 'piece_justificative';
|
||||||
|
},
|
||||||
|
isCarte() {
|
||||||
|
return this.typeChamp === 'carte';
|
||||||
|
},
|
||||||
|
isExplication() {
|
||||||
|
return this.typeChamp === 'explication';
|
||||||
|
},
|
||||||
|
isHeaderSection() {
|
||||||
|
return this.typeChamp === 'header_section';
|
||||||
|
},
|
||||||
|
options() {
|
||||||
|
const options = this.item.options;
|
||||||
|
for (let key of Object.keys(options)) {
|
||||||
|
options[key] = castBoolean(options[key]);
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
},
|
||||||
|
attribute() {
|
||||||
|
if (this.state.isAnnotation) {
|
||||||
|
return 'types_de_champ_private_attributes';
|
||||||
|
} else {
|
||||||
|
return 'types_de_champ_attributes';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
typeChamp: this.item.type_champ,
|
||||||
|
libelle: this.item.libelle,
|
||||||
|
mandatory: this.item.mandatory,
|
||||||
|
description: this.item.description,
|
||||||
|
dropDownList: this.item.drop_down_list.value,
|
||||||
|
deleted: false,
|
||||||
|
clientId: `id-${clientIds++}`
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
for (let path of PATHS_TO_WATCH) {
|
||||||
|
this.$watch(path, () => this.update(this.changeLog));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.isInvalid) {
|
||||||
|
this.update(this.changeLog, false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
removeChamp(item) {
|
||||||
|
if (item.id) {
|
||||||
|
this.deleted = true;
|
||||||
|
} else {
|
||||||
|
const index = this.state.typesDeChamp.indexOf(item);
|
||||||
|
this.state.typesDeChamp.splice(index, 1);
|
||||||
|
this.update([this.itemId, true]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
nameFor(name) {
|
||||||
|
return `${this.prefix}[${this.attribute}][${this.index}][${name}]`;
|
||||||
|
},
|
||||||
|
elementIdFor(name) {
|
||||||
|
return `${this.prefix}_${this.attribute}_${this.index}_${name}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const PATHS_TO_WATCH = [
|
||||||
|
'typeChamp',
|
||||||
|
'libelle',
|
||||||
|
'mandatory',
|
||||||
|
'description',
|
||||||
|
'dropDownList',
|
||||||
|
'options.quartiers_prioritaires',
|
||||||
|
'options.cadastres',
|
||||||
|
'options.parcelles_agricoles',
|
||||||
|
'index',
|
||||||
|
'deleted'
|
||||||
|
];
|
||||||
|
|
||||||
|
function castBoolean(value) {
|
||||||
|
return value && value != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let clientIds = 0;
|
165
app/javascript/new_design/administrateur/DraggableItem.vue
Normal file
165
app/javascript/new_design/administrateur/DraggableItem.vue
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
<template>
|
||||||
|
<div class="deleted" v-if="deleted">
|
||||||
|
<input type="hidden" :name="nameFor('id')" :value="item.id">
|
||||||
|
<input type="hidden" :name="nameFor('_destroy')" value="true">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="draggable-item" v-else :class="itemClassName">
|
||||||
|
<div class="row section head" :class="{ hr: !isHeaderSection }">
|
||||||
|
<div class="handle">
|
||||||
|
<img :src="state.dragIconUrl" alt="">
|
||||||
|
</div>
|
||||||
|
<div class="cell">
|
||||||
|
<select :name="nameFor('type_champ')" v-model="typeChamp" class="small-margin small inline">
|
||||||
|
<option v-for="option in state.typesDeChampOptions" :key="option[1]" :value="option[1]">
|
||||||
|
{{ option[0] }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="row delete">
|
||||||
|
<div v-if="isDirty" class="error-message">
|
||||||
|
<span v-if="isInvalid" class="content">
|
||||||
|
Le libellé doit être rempli.
|
||||||
|
</span>
|
||||||
|
<span v-else class="content">
|
||||||
|
<template v-if="state.isAnnotation">
|
||||||
|
Modifications non sauvegardées. Le libellé doit être rempli sur tous les annotations.
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
Modifications non sauvegardées. Le libellé doit être rempli sur tous les champs.
|
||||||
|
</template>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="button danger" @click.prevent="removeChamp(item)">
|
||||||
|
Supprimer
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row section" :class="{ hr: isDropDown || isFile || isCarte }">
|
||||||
|
<div class="column shift-left">
|
||||||
|
<div class="cell libelle">
|
||||||
|
<label :for="elementIdFor('libelle')">
|
||||||
|
Libellé
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
:id="elementIdFor('libelle')"
|
||||||
|
:name="nameFor('libelle')"
|
||||||
|
v-model="libelle"
|
||||||
|
class="small-margin small"
|
||||||
|
:class="{ error: isDirty && isInvalid }">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cell" v-show="!isHeaderSection && !isExplication && !state.isAnnotation">
|
||||||
|
<label :for="elementIdFor('mandatory')">
|
||||||
|
Obligatoire
|
||||||
|
</label>
|
||||||
|
<input :name="nameFor('mandatory')" type="hidden" value="0">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
:id="elementIdFor('mandatory')"
|
||||||
|
:name="nameFor('mandatory')"
|
||||||
|
v-model="mandatory"
|
||||||
|
class="small-margin small"
|
||||||
|
value="1">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="cell" v-show="!isHeaderSection">
|
||||||
|
<label :for="elementIdFor('description')">
|
||||||
|
Description
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
:id="elementIdFor('description')"
|
||||||
|
:name="nameFor('description')"
|
||||||
|
v-model="description"
|
||||||
|
rows=3
|
||||||
|
cols=40
|
||||||
|
class="small-margin small">
|
||||||
|
</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row section shift-left" v-show="!isHeaderSection">
|
||||||
|
<div class="cell" v-show="isDropDown">
|
||||||
|
<label :for="elementIdFor('drop_down_list')">
|
||||||
|
Liste déroulante
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
:id="elementIdFor('drop_down_list')"
|
||||||
|
:name="nameFor('drop_down_list_attributes[value]')"
|
||||||
|
v-model="dropDownList"
|
||||||
|
rows=3
|
||||||
|
cols=40
|
||||||
|
placeholder="Ecrire une valeur par ligne et --valeur-- pour un séparateur."
|
||||||
|
class="small-margin small">
|
||||||
|
</textarea>
|
||||||
|
</div>
|
||||||
|
<div class="cell" v-show="isFile">
|
||||||
|
<label :for="elementIdFor('piece_justificative_template')">
|
||||||
|
Modèle
|
||||||
|
</label>
|
||||||
|
<template v-if="item.piece_justificative_template_url">
|
||||||
|
<a :href="item.piece_justificative_template_url" target="_blank">
|
||||||
|
{{item.piece_justificative_template_filename}}
|
||||||
|
</a>
|
||||||
|
<br> Modifier :
|
||||||
|
</template>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
:id="elementIdFor('piece_justificative_template')"
|
||||||
|
:name="nameFor('piece_justificative_template')"
|
||||||
|
:data-direct-upload-url="state.directUploadsUrl"
|
||||||
|
@change="update(changeLog)"
|
||||||
|
class="small-margin small">
|
||||||
|
</div>
|
||||||
|
<div class="cell" v-show="isCarte">
|
||||||
|
<label>
|
||||||
|
Utilisation de la cartographie
|
||||||
|
</label>
|
||||||
|
<div class="carte-options">
|
||||||
|
<label :for="elementIdFor('quartiers_prioritaires')">
|
||||||
|
<input :name="nameFor('quartiers_prioritaires')" type="hidden" value="0">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
:id="elementIdFor('quartiers_prioritaires')"
|
||||||
|
:name="nameFor('quartiers_prioritaires')"
|
||||||
|
v-model="options.quartiers_prioritaires"
|
||||||
|
class="small-margin small"
|
||||||
|
value="1">
|
||||||
|
Quartiers prioritaires
|
||||||
|
</label>
|
||||||
|
<label :for="elementIdFor('cadastres')">
|
||||||
|
<input :name="nameFor('cadastres')" type="hidden" value="0">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
:id="elementIdFor('cadastres')"
|
||||||
|
:name="nameFor('cadastres')"
|
||||||
|
v-model="options.cadastres"
|
||||||
|
class="small-margin small"
|
||||||
|
value="1">
|
||||||
|
Cadastres
|
||||||
|
</label>
|
||||||
|
<label :for="elementIdFor('parcelles_agricoles')">
|
||||||
|
<input :name="nameFor('parcelles_agricoles')" type="hidden" value="0">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
:id="elementIdFor('parcelles_agricoles')"
|
||||||
|
:name="nameFor('parcelles_agricoles')"
|
||||||
|
v-model="options.parcelles_agricoles"
|
||||||
|
class="small-margin small"
|
||||||
|
value="1">
|
||||||
|
Parcelles Agricoles
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="meta">
|
||||||
|
<input type="hidden" :name="nameFor('order_place')" :value="index">
|
||||||
|
<input type="hidden" :name="nameFor('id')" :value="item.id">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="./DraggableItem.js"></script>
|
12
app/javascript/new_design/administrateur/DraggableList.js
Normal file
12
app/javascript/new_design/administrateur/DraggableList.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
export default {
|
||||||
|
props: ['state', 'version', 'update', 'updateAll'],
|
||||||
|
methods: {
|
||||||
|
addChamp() {
|
||||||
|
this.state.typesDeChamp.push({
|
||||||
|
type_champ: 'text',
|
||||||
|
drop_down_list: {},
|
||||||
|
options: {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
42
app/javascript/new_design/administrateur/DraggableList.vue
Normal file
42
app/javascript/new_design/administrateur/DraggableList.vue
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<template>
|
||||||
|
<div class="champs-editor">
|
||||||
|
<div v-if="state.typesDeChamp.length > 3" class="header">
|
||||||
|
<button class="button" @click.prevent="addChamp">
|
||||||
|
<template v-if="state.isAnnotation">
|
||||||
|
Ajouter une annotation
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
Ajouter un champ
|
||||||
|
</template>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="button primary" @click.prevent="updateAll">Enregistrer</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Draggable :list="state.typesDeChamp" :options="{handle:'.handle'}">
|
||||||
|
<DraggableItem
|
||||||
|
v-for="(item, index) in state.typesDeChamp"
|
||||||
|
prefix="procedure"
|
||||||
|
:state="state"
|
||||||
|
:update="update"
|
||||||
|
:index="index"
|
||||||
|
:item="item"
|
||||||
|
:key="item.id" />
|
||||||
|
</Draggable>
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
<button class="button" @click.prevent="addChamp">
|
||||||
|
<template v-if="state.isAnnotation">
|
||||||
|
Ajouter une annotation
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
Ajouter un champ
|
||||||
|
</template>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="button primary" @click.prevent="updateAll">Enregistrer</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="./DraggableList.js"></script>
|
109
app/javascript/new_design/administrateur/champs-editor.js
Normal file
109
app/javascript/new_design/administrateur/champs-editor.js
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
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');
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,8 @@ import '../new_design/select2';
|
||||||
import '../new_design/champs/carte';
|
import '../new_design/champs/carte';
|
||||||
import '../new_design/champs/linked-drop-down-list';
|
import '../new_design/champs/linked-drop-down-list';
|
||||||
|
|
||||||
|
import '../new_design/administrateur/champs-editor';
|
||||||
|
|
||||||
import { toggleCondidentielExplanation } from '../new_design/avis';
|
import { toggleCondidentielExplanation } from '../new_design/avis';
|
||||||
import { scrollMessagerie } from '../new_design/messagerie';
|
import { scrollMessagerie } from '../new_design/messagerie';
|
||||||
import { showMotivation, motivationCancel } from '../new_design/state-button';
|
import { showMotivation, motivationCancel } from '../new_design/state-button';
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue