@osimatic/helpers-js 1.5.3 → 1.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/details_sub_array.js +45 -41
- package/form_helper.js +283 -232
- package/google_charts.js +154 -144
- package/google_maps.js +1 -1
- package/import_from_csv.js +166 -157
- package/multi_files_input.js +42 -34
- package/multiple_action_in_table.js +115 -105
- package/package.json +1 -1
- package/paging.js +103 -84
- package/select_all.js +65 -70
- package/sortable_list.js +12 -13
- package/tests/details_sub_array.test.js +211 -239
- package/tests/form_helper.test.js +553 -673
- package/tests/google_charts.test.js +338 -339
- package/tests/google_maps.test.js +3 -15
- package/tests/import_from_csv.test.js +391 -652
- package/tests/multi_files_input.test.js +292 -722
- package/tests/multiple_action_in_table.test.js +439 -417
- package/tests/paging.test.js +344 -475
- package/tests/select_all.test.js +232 -318
- package/tests/sortable_list.test.js +176 -500
- package/tests/user.test.js +163 -54
- package/user.js +35 -38
package/form_helper.js
CHANGED
|
@@ -1,62 +1,70 @@
|
|
|
1
1
|
class FormHelper {
|
|
2
2
|
static init(form, onSubmitCallback, submitButton=null) {
|
|
3
3
|
FormHelper.reset(form, submitButton);
|
|
4
|
-
submitButton = null != submitButton ? submitButton : form.
|
|
5
|
-
submitButton.
|
|
4
|
+
submitButton = null != submitButton ? submitButton : form.querySelector('button[name="validate"]');
|
|
5
|
+
submitButton.onclick = function(e) {
|
|
6
6
|
e.preventDefault();
|
|
7
|
-
FormHelper.buttonLoader(
|
|
7
|
+
FormHelper.buttonLoader(this, 'loading');
|
|
8
8
|
FormHelper.hideFormErrors(form);
|
|
9
9
|
if (typeof onSubmitCallback == 'function') {
|
|
10
10
|
onSubmitCallback(form, submitButton);
|
|
11
11
|
}
|
|
12
|
-
}
|
|
12
|
+
};
|
|
13
13
|
return form;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
static reset(form, submitButton=null) {
|
|
17
|
-
submitButton = null != submitButton ? submitButton : form.
|
|
18
|
-
form.
|
|
19
|
-
|
|
17
|
+
submitButton = null != submitButton ? submitButton : form.querySelector('button[name="validate"]');
|
|
18
|
+
form.querySelectorAll('input[name]:not([type="checkbox"]):not([type="radio"]), select:not(.selectpicker), textarea').forEach(el => {
|
|
19
|
+
el.value = '';
|
|
20
|
+
el.onchange = null;
|
|
21
|
+
});
|
|
22
|
+
form.querySelectorAll('select.selectpicker').forEach(el => el.value = '');
|
|
20
23
|
FormHelper.buttonLoader(submitButton, 'reset');
|
|
21
24
|
FormHelper.hideFormErrors(form);
|
|
22
25
|
return form;
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
static populateForm(form, data) {
|
|
26
|
-
form.
|
|
29
|
+
const employeesDisplayType = form.querySelector('[name="employees_display_type"][value="NONE"]');
|
|
30
|
+
if (employeesDisplayType) employeesDisplayType.checked = true; //todo à retirer
|
|
27
31
|
|
|
28
|
-
|
|
32
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
29
33
|
if (value == null) {
|
|
30
34
|
return;
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
if (typeof value == 'object') {
|
|
34
|
-
let select = form.
|
|
35
|
-
select
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
let select = form.querySelector('[name="'+key+'[]"]');
|
|
39
|
+
if (select) {
|
|
40
|
+
select.querySelectorAll('option').forEach(o => o.selected = false);
|
|
41
|
+
select.dataset.default_id = value.join(',');
|
|
42
|
+
value.forEach(val => {
|
|
43
|
+
const opt = select.querySelector('option[value="'+val+'"]');
|
|
44
|
+
if (opt) opt.selected = true;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
40
47
|
return;
|
|
41
48
|
}
|
|
42
49
|
|
|
43
|
-
|
|
50
|
+
const inputs = form.querySelectorAll('[name="'+key+'"]');
|
|
51
|
+
if (!inputs.length) return;
|
|
44
52
|
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
if (inputs[0].type === 'radio' || inputs[0].type === 'checkbox') {
|
|
54
|
+
inputs.forEach(i => i.checked = false);
|
|
55
|
+
const target = form.querySelector('[name="'+key+'"][value="'+value+'"]');
|
|
56
|
+
if (target) target.checked = true;
|
|
48
57
|
return;
|
|
49
58
|
}
|
|
50
59
|
|
|
51
|
-
|
|
52
|
-
// console.log(form.
|
|
60
|
+
inputs[0].value = value;
|
|
61
|
+
// console.log(form.querySelectorAll('[name="'+key+'"]').length);
|
|
53
62
|
});
|
|
54
63
|
}
|
|
55
64
|
|
|
56
65
|
|
|
57
66
|
static getFormData(form) {
|
|
58
|
-
|
|
59
|
-
return new FormData(form[0]);
|
|
67
|
+
return new FormData(form);
|
|
60
68
|
}
|
|
61
69
|
|
|
62
70
|
static getDataFromFormData(formData) {
|
|
@@ -69,14 +77,7 @@ class FormHelper {
|
|
|
69
77
|
}
|
|
70
78
|
|
|
71
79
|
static getFormDataQueryString(form) {
|
|
72
|
-
return form.
|
|
73
|
-
// cette soluce marche pas pour les clés sous forme de tableau : ids[]=1&ids[]=2
|
|
74
|
-
/*
|
|
75
|
-
return form.serializeArray().reduce(function(obj, item) {
|
|
76
|
-
obj[item.name] = item.value;
|
|
77
|
-
return obj;
|
|
78
|
-
}, {});
|
|
79
|
-
*/
|
|
80
|
+
return new URLSearchParams(new FormData(form)).toString();
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
|
|
@@ -86,10 +87,10 @@ class FormHelper {
|
|
|
86
87
|
// ------------------------------------------------------------
|
|
87
88
|
|
|
88
89
|
static getInputValue(input) {
|
|
89
|
-
if (typeof input == 'undefined') {
|
|
90
|
+
if (typeof input == 'undefined' || input == null) {
|
|
90
91
|
return null;
|
|
91
92
|
}
|
|
92
|
-
let value =
|
|
93
|
+
let value = input.value;
|
|
93
94
|
if (value === null || value === '') {
|
|
94
95
|
return null;
|
|
95
96
|
}
|
|
@@ -97,7 +98,7 @@ class FormHelper {
|
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
static getLinesOfTextarea(textarea) {
|
|
100
|
-
return textarea.
|
|
101
|
+
return textarea.value.replace(/(\r\n|\n|\r)/g, "\n").split("\n").filter(word => word.length > 0);
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
static setOnInputChange(input, callback, doneTypingInterval=700) {
|
|
@@ -105,18 +106,18 @@ class FormHelper {
|
|
|
105
106
|
let typingTimer; // timer identifier
|
|
106
107
|
|
|
107
108
|
// on keyup, start the countdown
|
|
108
|
-
input.
|
|
109
|
+
input.addEventListener('keyup', function () {
|
|
109
110
|
clearTimeout(typingTimer);
|
|
110
111
|
typingTimer = setTimeout(callback, doneTypingInterval); // time in ms
|
|
111
112
|
});
|
|
112
113
|
|
|
113
114
|
// on keydown, clear the countdown
|
|
114
|
-
input.
|
|
115
|
+
input.addEventListener('keydown', function () {
|
|
115
116
|
clearTimeout(typingTimer);
|
|
116
117
|
});
|
|
117
118
|
|
|
118
119
|
// on focusout, clear the countdown and call callback
|
|
119
|
-
input.
|
|
120
|
+
input.addEventListener('focusout', function () {
|
|
120
121
|
clearTimeout(typingTimer);
|
|
121
122
|
callback();
|
|
122
123
|
});
|
|
@@ -127,26 +128,27 @@ class FormHelper {
|
|
|
127
128
|
// ------------------------------------------------------------
|
|
128
129
|
|
|
129
130
|
static resetSelectOption(form, selectName) {
|
|
130
|
-
form.
|
|
131
|
+
form.querySelectorAll('select[name="'+selectName+'"] option').forEach(o => {
|
|
132
|
+
o.disabled = false;
|
|
133
|
+
o.selected = false;
|
|
134
|
+
});
|
|
131
135
|
}
|
|
132
136
|
static setSelectedSelectOption(form, selectName, optionValue) {
|
|
133
|
-
form.
|
|
137
|
+
const opt = form.querySelector('select[name="'+selectName+'"] option[value="'+optionValue+'"]');
|
|
138
|
+
if (opt) opt.selected = true;
|
|
134
139
|
}
|
|
135
140
|
static setSelectedSelectOptions(form, selectName, optionValues) {
|
|
136
|
-
|
|
137
|
-
FormHelper.setSelectedSelectOption(form, selectName, id);
|
|
138
|
-
});
|
|
141
|
+
optionValues.forEach(id => FormHelper.setSelectedSelectOption(form, selectName, id));
|
|
139
142
|
}
|
|
140
143
|
static disableSelectOption(form, selectName, optionValue) {
|
|
141
|
-
form.
|
|
144
|
+
const opt = form.querySelector('select[name="'+selectName+'"] option[value="'+optionValue+'"]');
|
|
145
|
+
if (opt) opt.disabled = true;
|
|
142
146
|
}
|
|
143
147
|
static disableSelectOptions(form, selectName, optionValues) {
|
|
144
|
-
|
|
145
|
-
FormHelper.disableSelectOption(form, selectName, id);
|
|
146
|
-
});
|
|
148
|
+
optionValues.forEach(id => FormHelper.disableSelectOption(form, selectName, id));
|
|
147
149
|
}
|
|
148
150
|
static countSelectOptions(form, selectName) {
|
|
149
|
-
return form.
|
|
151
|
+
return form.querySelectorAll('select[name="'+selectName+'"] option:not([disabled])').length;
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
|
|
@@ -155,23 +157,21 @@ class FormHelper {
|
|
|
155
157
|
// ------------------------------------------------------------
|
|
156
158
|
|
|
157
159
|
static getCheckedValues(inputs) {
|
|
158
|
-
return inputs.map(
|
|
159
|
-
if (this.checked) {
|
|
160
|
-
return this.value;
|
|
161
|
-
}
|
|
162
|
-
}).get();
|
|
160
|
+
return [...inputs].filter(i => i.checked).map(i => i.value);
|
|
163
161
|
}
|
|
164
162
|
|
|
165
163
|
static setCheckedValues(inputs, defaultValues) {
|
|
166
|
-
|
|
167
|
-
|
|
164
|
+
const parent = inputs[0]?.parentElement;
|
|
165
|
+
defaultValues.forEach(value => {
|
|
166
|
+
if (parent) {
|
|
167
|
+
const t = parent.querySelector('[value="'+value+'"]');
|
|
168
|
+
if (t) t.checked = true;
|
|
169
|
+
}
|
|
168
170
|
});
|
|
169
171
|
}
|
|
170
172
|
|
|
171
173
|
static getInputListValues(inputs) {
|
|
172
|
-
return inputs.map(
|
|
173
|
-
return this.value;
|
|
174
|
-
}).get().filter(word => word.length > 0);
|
|
174
|
+
return [...inputs].map(i => i.value).filter(word => word.length > 0);
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
|
|
@@ -180,54 +180,42 @@ class FormHelper {
|
|
|
180
180
|
// ------------------------------------------------------------
|
|
181
181
|
|
|
182
182
|
static initTypeFields(form) {
|
|
183
|
-
//if ( $('[type="date"]').prop('type') != 'date' ) {
|
|
184
|
-
// $('[type="date"]').datepicker();
|
|
185
|
-
//}
|
|
186
183
|
if (typeof Modernizr != 'undefined') {
|
|
187
184
|
if (!Modernizr.inputtypes.date) {
|
|
188
|
-
|
|
189
|
-
// $.datepicker.setDefaults( $.datepicker.regional["fr"]);
|
|
190
|
-
form.find('input[type="date"]')
|
|
191
|
-
.css('max-width', '120px')
|
|
192
|
-
// 28/06/2021 : désactivation du datepicker car safari le gere en natif
|
|
193
|
-
/*
|
|
194
|
-
.datepicker({
|
|
195
|
-
dateFormat: 'yy-mm-dd',
|
|
196
|
-
changeMonth: true,
|
|
197
|
-
changeYear: true,
|
|
198
|
-
showOn: "both",
|
|
199
|
-
buttonImage: ROOT_PATH+'images/icons/calendar-alt.png',
|
|
200
|
-
buttonImageOnly: true,
|
|
201
|
-
})
|
|
202
|
-
*/
|
|
203
|
-
;
|
|
204
|
-
//form.find('input[type="date"]').datepicker({dateFormat: 'yy-mm-dd', minDate: "-10Y", maxDate: "+3Y"});
|
|
205
|
-
// $("#date_conf").datepicker("option", $.datepicker.regional["fr"]);
|
|
206
|
-
// $("#date_conf").datepicker("option", "dateFormat", "yy-mm-dd");
|
|
185
|
+
form.querySelectorAll('input[type="date"]').forEach(el => el.style.maxWidth = '120px');
|
|
207
186
|
}
|
|
208
187
|
if (!Modernizr.inputtypes.time) {
|
|
209
|
-
form.
|
|
210
|
-
.
|
|
211
|
-
.
|
|
212
|
-
;
|
|
213
|
-
form.
|
|
188
|
+
form.querySelectorAll('input[type="time"]').forEach(el => {
|
|
189
|
+
el.style.maxWidth = '100px';
|
|
190
|
+
el.placeholder = 'hh:mm';
|
|
191
|
+
});
|
|
192
|
+
form.querySelectorAll('input[type="time"][step="1"]').forEach(el => el.placeholder = 'hh:mm:ss');
|
|
214
193
|
}
|
|
215
194
|
}
|
|
216
195
|
|
|
217
196
|
// Show/Hide password
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
197
|
+
form.querySelectorAll('input[type="password"]').forEach(inputEl => {
|
|
198
|
+
const wrapper = document.createElement('div');
|
|
199
|
+
wrapper.className = 'input-group password';
|
|
200
|
+
inputEl.parentNode.insertBefore(wrapper, inputEl);
|
|
201
|
+
wrapper.appendChild(inputEl);
|
|
202
|
+
const span = document.createElement('span');
|
|
203
|
+
span.className = 'input-group-text';
|
|
204
|
+
span.innerHTML = '<i class="fas fa-eye toggle_password"></i>';
|
|
205
|
+
span.querySelector('i').addEventListener('click', function(e) {
|
|
206
|
+
e.preventDefault();
|
|
207
|
+
const inp = this.closest('.input-group').querySelector('input');
|
|
208
|
+
const passwordHidden = inp.type === 'password';
|
|
209
|
+
inp.type = passwordHidden ? 'text' : 'password';
|
|
210
|
+
this.classList.remove('fa-eye', 'fa-eye-slash');
|
|
211
|
+
this.classList.add(passwordHidden ? 'fa-eye-slash' : 'fa-eye');
|
|
212
|
+
});
|
|
213
|
+
wrapper.appendChild(span);
|
|
225
214
|
});
|
|
226
|
-
form.find('input[type="password"]').wrap('<div class="input-group password"></div>').after(linkTogglePassword);
|
|
227
215
|
}
|
|
228
216
|
|
|
229
217
|
static hideField(inputOrSelect) {
|
|
230
|
-
inputOrSelect.closest('.form-group').
|
|
218
|
+
inputOrSelect.closest('.form-group')?.classList.add('hide');
|
|
231
219
|
}
|
|
232
220
|
|
|
233
221
|
// ------------------------------------------------------------
|
|
@@ -283,7 +271,7 @@ class FormHelper {
|
|
|
283
271
|
}
|
|
284
272
|
|
|
285
273
|
static hideFormErrors(form) {
|
|
286
|
-
form.
|
|
274
|
+
form.querySelectorAll('div.form_errors').forEach(el => el.remove());
|
|
287
275
|
return form;
|
|
288
276
|
}
|
|
289
277
|
|
|
@@ -311,11 +299,6 @@ class FormHelper {
|
|
|
311
299
|
this.displayFormErrorsFromText(form, this.getFormErrorText(errors), errorWrapperDiv);
|
|
312
300
|
if (btnSubmit != null) {
|
|
313
301
|
FormHelper.buttonLoader(btnSubmit, 'reset');
|
|
314
|
-
//if (btnSubmit.buttonLoader != null) {
|
|
315
|
-
// btnSubmit.buttonLoader('reset');
|
|
316
|
-
//} else {
|
|
317
|
-
// btnSubmit.attr('disabled', false).button('reset');
|
|
318
|
-
//}
|
|
319
302
|
}
|
|
320
303
|
}
|
|
321
304
|
|
|
@@ -323,32 +306,34 @@ class FormHelper {
|
|
|
323
306
|
let errorDiv = '<div class="alert alert-danger form_errors">'+errorLabels+'</div>';
|
|
324
307
|
|
|
325
308
|
if (null != errorWrapperDiv) {
|
|
326
|
-
errorWrapperDiv.
|
|
309
|
+
errorWrapperDiv.insertAdjacentHTML('beforeend', errorDiv);
|
|
327
310
|
return;
|
|
328
311
|
}
|
|
329
312
|
|
|
330
|
-
|
|
331
|
-
|
|
313
|
+
const formErrorsContent = form.querySelector('.form_errors_content');
|
|
314
|
+
if (formErrorsContent) {
|
|
315
|
+
formErrorsContent.insertAdjacentHTML('beforeend', errorDiv);
|
|
332
316
|
return;
|
|
333
317
|
}
|
|
334
318
|
|
|
335
319
|
let errorsParentDiv = form;
|
|
336
|
-
|
|
337
|
-
|
|
320
|
+
const modalBody = form.querySelector('.modal-body');
|
|
321
|
+
if (modalBody) {
|
|
322
|
+
errorsParentDiv = modalBody;
|
|
338
323
|
}
|
|
339
324
|
|
|
340
|
-
|
|
341
|
-
if (firstFormGroup
|
|
342
|
-
if (firstFormGroup.
|
|
343
|
-
firstFormGroup.
|
|
325
|
+
const firstFormGroup = errorsParentDiv.querySelector('.form-group');
|
|
326
|
+
if (firstFormGroup) {
|
|
327
|
+
if (firstFormGroup.parentElement?.parentElement?.classList.contains('row')) {
|
|
328
|
+
firstFormGroup.parentElement.parentElement.insertAdjacentHTML('beforebegin', errorDiv);
|
|
344
329
|
}
|
|
345
330
|
else {
|
|
346
|
-
|
|
331
|
+
firstFormGroup.insertAdjacentHTML('beforebegin', errorDiv);
|
|
347
332
|
}
|
|
348
333
|
return;
|
|
349
334
|
}
|
|
350
335
|
|
|
351
|
-
errorsParentDiv.
|
|
336
|
+
errorsParentDiv.insertAdjacentHTML('afterbegin', errorDiv);
|
|
352
337
|
}
|
|
353
338
|
|
|
354
339
|
|
|
@@ -357,33 +342,31 @@ class FormHelper {
|
|
|
357
342
|
// ------------------------------------------------------------
|
|
358
343
|
|
|
359
344
|
static buttonLoader(button, action) {
|
|
360
|
-
button = $(button);
|
|
361
345
|
if (action === 'start' || action === 'loading') {
|
|
362
|
-
if (button.
|
|
363
|
-
return
|
|
346
|
+
if (button.disabled) {
|
|
347
|
+
return button;
|
|
364
348
|
}
|
|
365
|
-
button.
|
|
366
|
-
button.
|
|
349
|
+
button.disabled = true;
|
|
350
|
+
button.dataset.btnText = button.innerHTML;
|
|
367
351
|
//let text = '<span class="spinner"><i class=\'fa fa-circle-notch fa-spin\'></i></span>Traitement en cours…';
|
|
368
352
|
let text = '<i class=\'fa fa-circle-notch fa-spin\'></i> Traitement en cours…';
|
|
369
|
-
if (button.
|
|
370
|
-
text = button.
|
|
353
|
+
if (button.dataset.loadText != null && button.dataset.loadText !== '') {
|
|
354
|
+
text = button.dataset.loadText;
|
|
371
355
|
}
|
|
372
|
-
if (button.
|
|
373
|
-
text = button.
|
|
356
|
+
if (button.dataset.loadingText != null && button.dataset.loadingText !== '') {
|
|
357
|
+
text = button.dataset.loadingText;
|
|
374
358
|
}
|
|
375
|
-
button.
|
|
376
|
-
button.
|
|
359
|
+
button.innerHTML = text;
|
|
360
|
+
button.classList.add('disabled');
|
|
377
361
|
}
|
|
378
362
|
if (action === 'stop' || action === 'reset') {
|
|
379
|
-
button.
|
|
380
|
-
button.
|
|
381
|
-
button.
|
|
382
|
-
//button.removeAttr("disabled");
|
|
363
|
+
button.innerHTML = button.dataset.btnText;
|
|
364
|
+
button.classList.remove('disabled');
|
|
365
|
+
button.disabled = false;
|
|
383
366
|
}
|
|
384
367
|
return button;
|
|
385
368
|
}
|
|
386
|
-
|
|
369
|
+
|
|
387
370
|
|
|
388
371
|
}
|
|
389
372
|
|
|
@@ -408,35 +391,44 @@ class ArrayField {
|
|
|
408
391
|
return typeof options[optionName] != 'undefined' && null !== options[optionName];
|
|
409
392
|
}
|
|
410
393
|
|
|
394
|
+
function createElement(html) {
|
|
395
|
+
const tmpDiv = document.createElement('div');
|
|
396
|
+
tmpDiv.innerHTML = html.trim();
|
|
397
|
+
return tmpDiv.firstElementChild;
|
|
398
|
+
}
|
|
399
|
+
|
|
411
400
|
let itemsList = defaultValues;
|
|
412
401
|
|
|
413
|
-
if (!formGroupDiv.
|
|
414
|
-
formGroupDiv.
|
|
402
|
+
if (!formGroupDiv.querySelector('table')) {
|
|
403
|
+
formGroupDiv.insertAdjacentHTML('beforeend', '<table class="table table-sm"><tbody></tbody></table>');
|
|
415
404
|
}
|
|
416
|
-
if (!formGroupDiv.
|
|
417
|
-
formGroupDiv.
|
|
405
|
+
if (!formGroupDiv.querySelector('.list_empty')) {
|
|
406
|
+
formGroupDiv.insertAdjacentHTML('beforeend', '<div class="list_empty">'+(isOptionDefined('list_empty_text') ? options['list_empty_text'] : '<em>aucun</em>')+'</div>');
|
|
418
407
|
}
|
|
419
|
-
if (!options['entering_field_in_table'] && !formGroupDiv.
|
|
420
|
-
let divLinks = formGroupDiv.
|
|
421
|
-
if (!divLinks
|
|
422
|
-
divLinks =
|
|
423
|
-
formGroupDiv.
|
|
408
|
+
if (!options['entering_field_in_table'] && !formGroupDiv.querySelector('.add_one, .add_multi')) {
|
|
409
|
+
let divLinks = formGroupDiv.querySelector('.links');
|
|
410
|
+
if (!divLinks) {
|
|
411
|
+
divLinks = createElement('<div class="links text-center"></div>');
|
|
412
|
+
formGroupDiv.appendChild(divLinks);
|
|
424
413
|
}
|
|
425
414
|
|
|
426
415
|
if (options['add_one_button_enabled']) {
|
|
427
|
-
divLinks.
|
|
416
|
+
divLinks.insertAdjacentHTML('beforeend', '<a href="#" class="add_one btn btn-sm btn-success">'+(isOptionDefined('add_one_button_label') ? options['add_one_button_label'] : 'Ajouter')+'</a>');
|
|
428
417
|
}
|
|
429
418
|
if (options['add_multi_button_enabled']) {
|
|
430
|
-
divLinks.
|
|
419
|
+
divLinks.insertAdjacentHTML('beforeend', '<a href="#" class="add_multi btn btn-sm btn-success">'+(isOptionDefined('add_multi_button_label') ? options['add_multi_button_label'] : 'Ajout multiple')+'</a>');
|
|
431
420
|
}
|
|
432
|
-
formGroupDiv.
|
|
421
|
+
formGroupDiv.appendChild(divLinks);
|
|
433
422
|
}
|
|
434
423
|
|
|
435
424
|
function addLine(item) {
|
|
436
|
-
const table = formGroupDiv.
|
|
425
|
+
const table = formGroupDiv.querySelector('table');
|
|
426
|
+
table.classList.remove('hide');
|
|
437
427
|
let tr;
|
|
438
|
-
|
|
439
|
-
|
|
428
|
+
const baseTr = table.querySelector('tbody tr.base');
|
|
429
|
+
if (baseTr) {
|
|
430
|
+
tr = baseTr.cloneNode(true);
|
|
431
|
+
tr.classList.remove('hide', 'base');
|
|
440
432
|
}
|
|
441
433
|
else {
|
|
442
434
|
let links = '';
|
|
@@ -445,7 +437,7 @@ class ArrayField {
|
|
|
445
437
|
}
|
|
446
438
|
links += '<a href="#" title="Supprimer" class="remove btn btn-sm btn-danger ms-1"><i class="fas fa-times"></i></a>';
|
|
447
439
|
|
|
448
|
-
tr =
|
|
440
|
+
tr = createElement(
|
|
449
441
|
'<tr>' +
|
|
450
442
|
'<td class="table-input" style="vertical-align: middle">' +
|
|
451
443
|
(options['entering_field_in_table'] ? '<input type="text" name="'+options['input_name']+'" class="form-control pt-1 pb-1">' : '<input type="hidden" name="'+options['input_name']+'"> <span class="value"></span>') +
|
|
@@ -455,62 +447,85 @@ class ArrayField {
|
|
|
455
447
|
);
|
|
456
448
|
}
|
|
457
449
|
|
|
458
|
-
tr.
|
|
459
|
-
|
|
460
|
-
|
|
450
|
+
const addLink = tr.querySelector('a.add');
|
|
451
|
+
if (addLink) {
|
|
452
|
+
addLink.onclick = function () {
|
|
453
|
+
const trEl = this.closest('tr');
|
|
454
|
+
const tableBody = trEl.closest('tbody');
|
|
461
455
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
return false;
|
|
468
|
-
});
|
|
469
|
-
tr.find('a.remove').click(function () {
|
|
470
|
-
const tr = $(this).closest('tr');
|
|
471
|
-
const tableBody = tr.closest('tbody');
|
|
472
|
-
if (options['entering_field_in_table'] && tableBody.find('tr').length <= 1) {
|
|
456
|
+
if (isOptionDefined('nb_max_lines') && tableBody.querySelectorAll('tr').length >= options['nb_max_lines']) {
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
addLine();
|
|
460
|
+
onUpdateList();
|
|
473
461
|
return false;
|
|
474
|
-
}
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
const removeLink = tr.querySelector('a.remove');
|
|
465
|
+
if (removeLink) {
|
|
466
|
+
removeLink.onclick = function () {
|
|
467
|
+
const trEl = this.closest('tr');
|
|
468
|
+
const tableBody = trEl.closest('tbody');
|
|
469
|
+
if (options['entering_field_in_table'] && tableBody.querySelectorAll('tr').length <= 1) {
|
|
470
|
+
return false;
|
|
471
|
+
}
|
|
475
472
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
473
|
+
if (!options['entering_field_in_table'] || '' !== trEl.dataset.item) {
|
|
474
|
+
itemsList.unsetVal(trEl.dataset.item);
|
|
475
|
+
}
|
|
479
476
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
477
|
+
trEl.remove();
|
|
478
|
+
onUpdateList();
|
|
479
|
+
return false;
|
|
480
|
+
};
|
|
481
|
+
}
|
|
484
482
|
|
|
485
483
|
if (typeof item != 'undefined' && null !== item) {
|
|
486
|
-
tr.
|
|
487
|
-
tr.
|
|
488
|
-
|
|
484
|
+
tr.dataset.item = item ?? '';
|
|
485
|
+
const inputEl = tr.querySelector('input');
|
|
486
|
+
if (inputEl) inputEl.value = item;
|
|
487
|
+
const spanEl = tr.querySelector('span.value');
|
|
488
|
+
if (spanEl) spanEl.textContent = item;
|
|
489
489
|
}
|
|
490
490
|
|
|
491
|
-
table.
|
|
491
|
+
table.querySelector('tbody').appendChild(tr);
|
|
492
492
|
return tr;
|
|
493
493
|
}
|
|
494
494
|
|
|
495
495
|
function onUpdateList() {
|
|
496
|
-
formGroupDiv.
|
|
496
|
+
formGroupDiv.querySelectorAll('.list_empty, table').forEach(el => el.classList.add('hide'));
|
|
497
497
|
|
|
498
498
|
// Maj tableau
|
|
499
|
-
let table = formGroupDiv.
|
|
500
|
-
const tableLines = table.
|
|
499
|
+
let table = formGroupDiv.querySelector('table');
|
|
500
|
+
const tableLines = [...table.querySelectorAll('tbody tr:not(.base)')];
|
|
501
501
|
if ((options['entering_field_in_table'] && tableLines.length ) || (!options['entering_field_in_table'] && itemsList.length)) {
|
|
502
|
-
table.
|
|
502
|
+
table.classList.remove('hide');
|
|
503
503
|
}
|
|
504
504
|
else {
|
|
505
|
-
formGroupDiv.
|
|
505
|
+
formGroupDiv.querySelector('.list_empty')?.classList.remove('hide');
|
|
506
506
|
}
|
|
507
507
|
|
|
508
|
-
tableLines.
|
|
508
|
+
tableLines.forEach(line => {
|
|
509
|
+
line.querySelectorAll('a').forEach(a => {
|
|
510
|
+
a.disabled = false;
|
|
511
|
+
a.classList.remove('disabled');
|
|
512
|
+
});
|
|
513
|
+
});
|
|
509
514
|
if (isOptionDefined('nb_max_lines') && tableLines.length >= options['nb_max_lines']) {
|
|
510
|
-
tableLines.
|
|
515
|
+
tableLines.forEach(line => {
|
|
516
|
+
line.querySelectorAll('a.add').forEach(a => {
|
|
517
|
+
a.disabled = true;
|
|
518
|
+
a.classList.add('disabled');
|
|
519
|
+
});
|
|
520
|
+
});
|
|
511
521
|
}
|
|
512
522
|
if (options['entering_field_in_table'] && tableLines.length <= 1) {
|
|
513
|
-
tableLines.
|
|
523
|
+
tableLines.forEach(line => {
|
|
524
|
+
line.querySelectorAll('a.remove').forEach(a => {
|
|
525
|
+
a.disabled = true;
|
|
526
|
+
a.classList.add('disabled');
|
|
527
|
+
});
|
|
528
|
+
});
|
|
514
529
|
}
|
|
515
530
|
|
|
516
531
|
if (typeof options['update_list_callback'] == 'function') {
|
|
@@ -521,14 +536,20 @@ class ArrayField {
|
|
|
521
536
|
}
|
|
522
537
|
|
|
523
538
|
function startAdd() {
|
|
524
|
-
formGroupDiv.
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
539
|
+
formGroupDiv.querySelectorAll('a.add_one, a.add_multi').forEach(el => {
|
|
540
|
+
el.classList.add('hide');
|
|
541
|
+
el.closest('.links')?.classList.add('hide');
|
|
542
|
+
});
|
|
543
|
+
formGroupDiv.querySelectorAll('.item_add_one, .item_add_multi').forEach(el => el.classList.add('hide'));
|
|
544
|
+
formGroupDiv.querySelectorAll('.item_add_one input[type="text"], .item_add_multi textarea').forEach(el => el.value = '');
|
|
545
|
+
formGroupDiv.querySelectorAll('.item_add_one .errors, .item_add_multi .errors').forEach(el => el.classList.add('hide'));
|
|
528
546
|
}
|
|
529
547
|
function cancelAdd() {
|
|
530
|
-
formGroupDiv.
|
|
531
|
-
|
|
548
|
+
formGroupDiv.querySelectorAll('a.add_one, a.add_multi').forEach(el => {
|
|
549
|
+
el.classList.remove('hide');
|
|
550
|
+
el.closest('.links')?.classList.remove('hide');
|
|
551
|
+
});
|
|
552
|
+
formGroupDiv.querySelectorAll('.item_add_one, .item_add_multi').forEach(el => el.classList.add('hide'));
|
|
532
553
|
}
|
|
533
554
|
|
|
534
555
|
function addItemsInList(items) {
|
|
@@ -568,17 +589,21 @@ class ArrayField {
|
|
|
568
589
|
if (!Array.isArray(errors)) {
|
|
569
590
|
errors = [errors];
|
|
570
591
|
}
|
|
571
|
-
divAdd.
|
|
592
|
+
const errorsEl = divAdd.querySelector('.errors');
|
|
593
|
+
if (errorsEl) {
|
|
594
|
+
errorsEl.textContent = errors.join('<br/>');
|
|
595
|
+
errorsEl.classList.remove('hide');
|
|
596
|
+
}
|
|
572
597
|
}
|
|
573
598
|
|
|
574
599
|
function initLinkAddOne() {
|
|
575
|
-
if (!formGroupDiv.
|
|
600
|
+
if (!formGroupDiv.querySelector('a.add_one') || !formGroupDiv.querySelector('a.add_one:not([disabled])')) {
|
|
576
601
|
return;
|
|
577
602
|
}
|
|
578
603
|
|
|
579
|
-
let divAdd = formGroupDiv.
|
|
580
|
-
if (!divAdd
|
|
581
|
-
divAdd =
|
|
604
|
+
let divAdd = formGroupDiv.querySelector('.item_add_one');
|
|
605
|
+
if (!divAdd) {
|
|
606
|
+
divAdd = createElement(
|
|
582
607
|
'<div class="item_add_one">' +
|
|
583
608
|
'<div class="alert alert-danger pt-1 pb-1 errors hide"></div>' +
|
|
584
609
|
'<div class="form-inline">' +
|
|
@@ -589,33 +614,33 @@ class ArrayField {
|
|
|
589
614
|
(isOptionDefined('form_desc')?'<br><span class="form-text">'+options['form_desc']+'</span>':'') +
|
|
590
615
|
'</div>'
|
|
591
616
|
);
|
|
592
|
-
formGroupDiv.
|
|
617
|
+
formGroupDiv.appendChild(divAdd);
|
|
593
618
|
}
|
|
594
619
|
|
|
595
|
-
divAdd.
|
|
620
|
+
divAdd.querySelector('a.cancel').onclick = function () {
|
|
596
621
|
cancelAdd();
|
|
597
622
|
return false;
|
|
598
|
-
}
|
|
599
|
-
divAdd.
|
|
600
|
-
submitAddNewItem(divAdd.
|
|
623
|
+
};
|
|
624
|
+
divAdd.querySelector('a.add').onclick = function () {
|
|
625
|
+
submitAddNewItem(divAdd.querySelector('input.form-control[type="text"]').value, divAdd);
|
|
601
626
|
return false;
|
|
602
|
-
}
|
|
627
|
+
};
|
|
603
628
|
|
|
604
|
-
formGroupDiv.
|
|
629
|
+
formGroupDiv.querySelector('a.add_one').onclick = function () {
|
|
605
630
|
startAdd();
|
|
606
|
-
formGroupDiv.
|
|
631
|
+
formGroupDiv.querySelector('.item_add_one').classList.remove('hide');
|
|
607
632
|
return false;
|
|
608
|
-
}
|
|
633
|
+
};
|
|
609
634
|
}
|
|
610
635
|
|
|
611
636
|
function initLinkAddMulti() {
|
|
612
|
-
if (!formGroupDiv.
|
|
637
|
+
if (!formGroupDiv.querySelector('a.add_multi') || !formGroupDiv.querySelector('a.add_multi:not([disabled])')) {
|
|
613
638
|
return;
|
|
614
639
|
}
|
|
615
640
|
|
|
616
|
-
let divAdd = formGroupDiv.
|
|
617
|
-
if (!divAdd
|
|
618
|
-
divAdd =
|
|
641
|
+
let divAdd = formGroupDiv.querySelector('.item_add_multi');
|
|
642
|
+
if (!divAdd) {
|
|
643
|
+
divAdd = createElement(
|
|
619
644
|
'<div class="item_add_multi">' +
|
|
620
645
|
'<div class="alert alert-danger pt-1 pb-1 errors hide"></div>' +
|
|
621
646
|
'<div class="form-group">' +
|
|
@@ -629,24 +654,24 @@ class ArrayField {
|
|
|
629
654
|
'</div>' +
|
|
630
655
|
'</div>'
|
|
631
656
|
);
|
|
632
|
-
formGroupDiv.
|
|
657
|
+
formGroupDiv.appendChild(divAdd);
|
|
633
658
|
}
|
|
634
659
|
|
|
635
|
-
divAdd.
|
|
660
|
+
divAdd.querySelector('a.cancel').onclick = function () {
|
|
636
661
|
cancelAdd();
|
|
637
662
|
return false;
|
|
638
|
-
}
|
|
639
|
-
divAdd.
|
|
640
|
-
const items = divAdd.
|
|
663
|
+
};
|
|
664
|
+
divAdd.querySelector('a.add').onclick = function () {
|
|
665
|
+
const items = divAdd.querySelector('textarea').value.normalizeBreaks("\n").split(/\n/ms).filter(value => value.length > 0);
|
|
641
666
|
submitAddNewItem(items, divAdd);
|
|
642
667
|
return false;
|
|
643
|
-
}
|
|
668
|
+
};
|
|
644
669
|
|
|
645
|
-
formGroupDiv.
|
|
670
|
+
formGroupDiv.querySelector('a.add_multi').onclick = function () {
|
|
646
671
|
startAdd();
|
|
647
|
-
formGroupDiv.
|
|
672
|
+
formGroupDiv.querySelector('.item_add_multi').classList.remove('hide');
|
|
648
673
|
return false;
|
|
649
|
-
}
|
|
674
|
+
};
|
|
650
675
|
}
|
|
651
676
|
|
|
652
677
|
initLinkAddOne();
|
|
@@ -669,44 +694,70 @@ class ArrayField {
|
|
|
669
694
|
|
|
670
695
|
class EditValue {
|
|
671
696
|
static init(valueDiv, onSubmitCallback, getInputCallback) {
|
|
672
|
-
|
|
673
|
-
|
|
697
|
+
const link = document.createElement('a');
|
|
698
|
+
link.href = '#';
|
|
699
|
+
link.className = 'text-warning';
|
|
700
|
+
link.innerHTML = '<i class="fas fa-pencil-alt"></i>';
|
|
701
|
+
valueDiv.parentElement.insertAdjacentHTML('beforeend', ' ');
|
|
702
|
+
valueDiv.parentElement.appendChild(link);
|
|
674
703
|
|
|
675
704
|
function cancelEdit(valueParentDiv) {
|
|
676
|
-
valueParentDiv.
|
|
677
|
-
valueParentDiv.
|
|
705
|
+
valueParentDiv.querySelectorAll('a, span').forEach(el => el.classList.remove('hide'));
|
|
706
|
+
const formEl = valueParentDiv.querySelector('form');
|
|
707
|
+
if (formEl) formEl.remove();
|
|
678
708
|
}
|
|
679
709
|
|
|
680
|
-
link.click
|
|
710
|
+
link.addEventListener('click', function (e) {
|
|
681
711
|
e.preventDefault();
|
|
682
712
|
|
|
683
|
-
let parent =
|
|
684
|
-
|
|
685
|
-
parent.
|
|
686
|
-
|
|
687
|
-
let form =
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
713
|
+
let parent = this.parentElement;
|
|
714
|
+
|
|
715
|
+
parent.querySelectorAll('a, span').forEach(el => el.classList.add('hide'));
|
|
716
|
+
|
|
717
|
+
let form = document.createElement('form');
|
|
718
|
+
form.className = 'form-inline';
|
|
719
|
+
|
|
720
|
+
const spanEl = parent.querySelector('span');
|
|
721
|
+
let value = spanEl?.dataset.value || spanEl?.textContent || '';
|
|
722
|
+
let inputEl;
|
|
723
|
+
if (typeof getInputCallback == 'function') {
|
|
724
|
+
const tmpDiv = document.createElement('div');
|
|
725
|
+
tmpDiv.innerHTML = getInputCallback(value).trim();
|
|
726
|
+
inputEl = tmpDiv.firstElementChild;
|
|
727
|
+
} else {
|
|
728
|
+
inputEl = document.createElement('input');
|
|
729
|
+
inputEl.type = 'text';
|
|
730
|
+
}
|
|
731
|
+
inputEl.classList.add('form-control');
|
|
732
|
+
inputEl.style.width = 'auto';
|
|
733
|
+
inputEl.value = value;
|
|
734
|
+
form.appendChild(inputEl);
|
|
735
|
+
|
|
736
|
+
let button = document.createElement('button');
|
|
737
|
+
button.type = 'submit';
|
|
738
|
+
button.className = 'btn btn-success ms-2';
|
|
739
|
+
button.dataset.loadingText = '<i class=\'fa fa-circle-notch fa-spin\'></i>';
|
|
740
|
+
button.style.verticalAlign = 'baseline';
|
|
741
|
+
button.innerHTML = '<i class="fas fa-check"></i>';
|
|
742
|
+
button.addEventListener('click', function (e) {
|
|
743
|
+
FormHelper.buttonLoader(parent.querySelector('button'), 'loading');
|
|
744
|
+
let newValue = parent.querySelector('input').value;
|
|
698
745
|
onSubmitCallback(newValue, parent,
|
|
699
746
|
(isSuccess, valueFormatCallback) => {
|
|
700
747
|
cancelEdit(parent);
|
|
701
748
|
if (isSuccess) {
|
|
702
|
-
parent.
|
|
749
|
+
const sp = parent.querySelector('span');
|
|
750
|
+
if (sp) {
|
|
751
|
+
sp.dataset.value = newValue;
|
|
752
|
+
sp.textContent = typeof valueFormatCallback == 'function' ? valueFormatCallback(newValue) : newValue;
|
|
753
|
+
}
|
|
703
754
|
}
|
|
704
755
|
}
|
|
705
756
|
);
|
|
706
757
|
});
|
|
707
|
-
form.
|
|
758
|
+
form.appendChild(button);
|
|
708
759
|
|
|
709
|
-
parent.
|
|
760
|
+
parent.appendChild(form);
|
|
710
761
|
return false;
|
|
711
762
|
});
|
|
712
763
|
}
|