@osimatic/helpers-js 1.1.77 → 1.2.0

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/form_helper.js CHANGED
@@ -1,411 +1,692 @@
1
- class FormHelper {
2
- static init(form, onSubmitCallback, submitButton=null) {
3
- FormHelper.reset(form, submitButton);
4
- submitButton = null != submitButton ? submitButton : form.find('button[name="validate"]');
5
- submitButton.off('click').click(function(e) {
6
- e.preventDefault();
7
- FormHelper.buttonLoader($(this), 'loading');
8
- FormHelper.hideFormErrors(form);
9
- if (typeof onSubmitCallback == 'function') {
10
- onSubmitCallback(form, submitButton);
11
- }
12
- });
13
- return form;
14
- }
15
-
16
- static reset(form, submitButton=null) {
17
- submitButton = null != submitButton ? submitButton : form.find('button[name="validate"]');
18
- form.find('input[name]:not([type="checkbox"], [type="radio"]), select:not(.selectpicker), textarea').each((idx, el) => $(el).val('')).off('change');
19
- form.find('select.selectpicker').each((idx, el) => $(el).val(''));
20
- FormHelper.buttonLoader(submitButton, 'reset');
21
- FormHelper.hideFormErrors(form);
22
- return form;
23
- }
24
-
25
- static populateForm(form, data) {
26
- form.find('[name="employees_display_type"][value="NONE"]').prop('checked', true); //todo à retirer
27
-
28
- $.each(data, function(key, value) {
29
- if (value == null) {
30
- return;
31
- }
32
-
33
- if (typeof value == 'object') {
34
- let select = form.find('[name="'+key+'[]"]');
35
- select.find('option').prop('selected', false);
36
- select.data('default_id', value.join(','));
37
- $.each(value, function(key, val) {
38
- select.find('option[value="'+val+'"]').prop('selected', true);
39
- });
40
- return;
41
- }
42
-
43
- let input = form.find('[name="'+key+'"]');
44
-
45
- if (input.prop('type') === 'radio' || input.prop('type') === 'checkbox') {
46
- input.prop('checked', false);
47
- input.filter('[value="'+value+'"]').prop('checked', true);
48
- return;
49
- }
50
-
51
- input.val(value);
52
- // console.log(form.find('[name="'+key+'"]').length);
53
- });
54
- }
55
-
56
-
57
- static getFormData(form) {
58
- // var formElement = document.getElementById("myFormElement");
59
- return new FormData(form[0]);
60
- }
61
-
62
- static getDataFromFormData(formData) {
63
- let data = {};
64
- for(let pair of formData.entries()) {
65
- //console.log(pair[0]+ ', '+ pair[1]);
66
- data[pair[0]] = pair[1];
67
- }
68
- return data;
69
- }
70
-
71
- static getFormDataQueryString(form) {
72
- return form.serialize();
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
- }
81
-
82
-
83
-
84
- // ------------------------------------------------------------
85
- // Input text
86
- // ------------------------------------------------------------
87
-
88
- static getInputValue(input) {
89
- if (typeof input == 'undefined') {
90
- return null;
91
- }
92
- let value = $(input).val();
93
- if (value === null || value === '') {
94
- return null;
95
- }
96
- return value;
97
- }
98
-
99
- static getLinesOfTextarea(textarea) {
100
- return textarea.val().replace(/(\r\n|\n|\r)/g, "\n").split("\n").filter(word => word.length > 0);
101
- }
102
-
103
- static setOnInputChange(input, callback, doneTypingInterval=700) {
104
- // setup before functions
105
- let typingTimer; // timer identifier
106
-
107
- // on keyup, start the countdown
108
- input.on('keyup', function () {
109
- clearTimeout(typingTimer);
110
- typingTimer = setTimeout(callback, doneTypingInterval); // time in ms
111
- });
112
-
113
- // on keydown, clear the countdown
114
- input.on('keydown', function () {
115
- clearTimeout(typingTimer);
116
- });
117
-
118
- // on focusout, clear the countdown and call callback
119
- input.on('focusout', function () {
120
- clearTimeout(typingTimer);
121
- callback();
122
- });
123
- }
124
-
125
- // ------------------------------------------------------------
126
- // Select
127
- // ------------------------------------------------------------
128
-
129
- static resetSelectOption(form, selectName) {
130
- form.find('select[name="'+selectName+'"] option').prop('disabled', false).prop('selected', false);
131
- }
132
- static setSelectedSelectOption(form, selectName, optionValue) {
133
- form.find('select[name="'+selectName+'"] option[value="'+optionValue+'"]').prop('selected', true);
134
- }
135
- static setSelectedSelectOptions(form, selectName, optionValues) {
136
- $.each(optionValues, function(idx, id) {
137
- FormHelper.setSelectedSelectOption(form, selectName, id);
138
- });
139
- }
140
- static disableSelectOption(form, selectName, optionValue) {
141
- form.find('select[name="'+selectName+'"] option[value="'+optionValue+'"]').prop('disabled', true);
142
- }
143
- static disableSelectOptions(form, selectName, optionValues) {
144
- $.each(optionValues, function(idx, id) {
145
- FormHelper.disableSelectOption(form, selectName, id);
146
- });
147
- }
148
- static countSelectOptions(form, selectName) {
149
- return form.find('select[name="'+selectName+'"] option:not([disabled])').length;
150
- }
151
-
152
-
153
- // ------------------------------------------------------------
154
- // Checkbox
155
- // ------------------------------------------------------------
156
-
157
- static getCheckedValues(inputs) {
158
- return inputs.map(function() {
159
- if (this.checked) {
160
- return this.value;
161
- }
162
- }).get();
163
- }
164
-
165
- static setCheckedValues(inputs, defaultValues) {
166
- $.each(defaultValues, function(idx, value) {
167
- inputs.parent().find('[value="'+value+'"]').prop('checked', true);
168
- });
169
- }
170
-
171
- static getInputListValues(inputs) {
172
- return inputs.map(function() {
173
- return this.value;
174
- }).get().filter(word => word.length > 0);
175
- }
176
-
177
-
178
- // ------------------------------------------------------------
179
- // Champs
180
- // ------------------------------------------------------------
181
-
182
- static initTypeFields(form) {
183
- //if ( $('[type="date"]').prop('type') != 'date' ) {
184
- // $('[type="date"]').datepicker();
185
- //}
186
- if (typeof Modernizr != 'undefined') {
187
- if (!Modernizr.inputtypes.date) {
188
- // $.fn.datepicker.defaults.language = 'fr';
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");
207
- }
208
- if (!Modernizr.inputtypes.time) {
209
- form.find('input[type="time"]')
210
- .css('max-width', '100px')
211
- .attr('placeholder', 'hh:mm')
212
- ;
213
- form.find('input[type="time"][step="1"]').attr('placeholder', 'hh:mm:ss');
214
- }
215
- }
216
-
217
- // Show/Hide password
218
- let linkTogglePassword = $('<span class="input-group-text"><i class="fas fa-eye toggle_password"></i></span>');
219
- linkTogglePassword.find('i').click(function(e) {
220
- e.preventDefault();
221
- let input = $(this).closest('.input-group').find('input');
222
- let passwordHidden = input.attr('type') === 'password';
223
- input.attr('type', passwordHidden ? 'text' : 'password');
224
- $(this).removeClass('fa-eye fa-eye-slash').addClass(passwordHidden ? 'fa-eye-slash' : 'fa-eye');
225
- });
226
- form.find('input[type="password"]').wrap('<div class="input-group password"></div>').after(linkTogglePassword);
227
- }
228
-
229
- static hideField(inputOrSelect) {
230
- inputOrSelect.closest('.form-group').addClass('hide');
231
- }
232
-
233
- // ------------------------------------------------------------
234
- // Messages erreur
235
- // ------------------------------------------------------------
236
-
237
- static extractErrorKeyOfJson(json, onlyIfUniqueError=false) {
238
- if (typeof json == 'undefined' || json == null) {
239
- return null;
240
- }
241
-
242
- if (typeof json.error != 'undefined') {
243
- return json.error;
244
- }
245
-
246
- if (onlyIfUniqueError && !json.length || json.length > 1) {
247
- return null;
248
- }
249
-
250
- if (typeof json[0] != 'undefined' && typeof json[0].error != 'undefined') {
251
- return json[0].error;
252
- }
253
-
254
- if (typeof json[0] != 'undefined' && Array.isArray(json[0]) && json[0].length === 2) {
255
- return json[0][0];
256
- }
257
-
258
- return null;
259
- }
260
-
261
- static hideFormErrors(form) {
262
- form.find('div.form_errors').remove();
263
- return form;
264
- }
265
-
266
- static getFormErrorText(errors) {
267
- let errorLabels = [];
268
- for (let property in errors) {
269
- // console.log(property);
270
- if (typeof errors[property] == 'function') {
271
- continue;
272
- }
273
- if (typeof errors[property]['error_description'] !== 'undefined') {
274
- errorLabels.push(errors[property]['error_description']);
275
- continue;
276
- }
277
- if (Array.isArray(errors[property]) && errors[property].length === 2) {
278
- errorLabels.push(errors[property][1]);
279
- continue;
280
- }
281
- errorLabels.push(errors[property]);
282
- }
283
- return errorLabels.removeEmptyValues().map(errorLabel => '<span>' + errorLabel + '</span>').join('<br/>');
284
- }
285
-
286
- static displayFormErrors(form, btnSubmit, errors, errorWrapperDiv=null) {
287
- this.displayFormErrorsFromText(form, this.getFormErrorText(errors), errorWrapperDiv);
288
- if (btnSubmit != null) {
289
- FormHelper.buttonLoader(btnSubmit, 'reset');
290
- //if (btnSubmit.buttonLoader != null) {
291
- // btnSubmit.buttonLoader('reset');
292
- //} else {
293
- // btnSubmit.attr('disabled', false).button('reset');
294
- //}
295
- }
296
- }
297
-
298
- static displayFormErrorsFromText(form, errorLabels, errorWrapperDiv=null) {
299
- let errorDiv = '<div class="alert alert-danger form_errors">'+errorLabels+'</div>';
300
-
301
- if (null != errorWrapperDiv) {
302
- errorWrapperDiv.append(errorDiv);
303
- return;
304
- }
305
-
306
- if (form.find('.form_errors_content').length) {
307
- form.find('.form_errors_content').append(errorDiv);
308
- return;
309
- }
310
-
311
- let errorsParentDiv = form;
312
- if (form.find('.modal-body').length) {
313
- errorsParentDiv = form.find('.modal-body');
314
- }
315
-
316
- let firstFormGroup = errorsParentDiv.find('.form-group:first');
317
- if (firstFormGroup.length) {
318
- if (firstFormGroup.parent().parent().hasClass('row')) {
319
- firstFormGroup.parent().parent().before(errorDiv);
320
- }
321
- else {
322
- errorsParentDiv.find('.form-group:first').before(errorDiv);
323
- }
324
- return;
325
- }
326
-
327
- errorsParentDiv.prepend(errorDiv);
328
- }
329
-
330
-
331
- // ------------------------------------------------------------
332
- // Bouton valider
333
- // ------------------------------------------------------------
334
-
335
- static buttonLoader(button, action) {
336
- button = $(button);
337
- if (action === 'start' || action === 'loading') {
338
- if (button.attr('disabled')) {
339
- return self;
340
- }
341
- button.attr('disabled', true);
342
- button.data('btn-text', button.html());
343
- //let text = '<span class="spinner"><i class=\'fa fa-circle-notch fa-spin\'></i></span>Traitement en cours…';
344
- let text = '<i class=\'fa fa-circle-notch fa-spin\'></i> Traitement en cours…';
345
- if (button.data('load-text') != null && button.data('load-text') !== '') {
346
- text = button.data('load-text');
347
- }
348
- if (button.data('loading-text') != null && button.data('loading-text') !== '') {
349
- text = button.data('loading-text');
350
- }
351
- button.html(text);
352
- button.addClass('disabled');
353
- }
354
- if (action === 'stop' || action === 'reset') {
355
- button.html(button.data('btn-text'));
356
- button.removeClass('disabled');
357
- button.attr('disabled', false);
358
- //button.removeAttr("disabled");
359
- }
360
- return button;
361
- }
362
-
363
-
364
- }
365
-
366
- class EditValue {
367
- static init(valueDiv, onSubmitCallback, getInputCallback) {
368
- let link = $('<a href="#" class="text-warning"><i class="fas fa-pencil-alt"></i></a>');
369
- valueDiv.parent().append('&nbsp;').append(link);
370
-
371
- function cancelEdit(valueParentDiv) {
372
- valueParentDiv.find('a, span').removeClass('hide');
373
- valueParentDiv.find('form').remove();
374
- }
375
-
376
- link.click(function (e) {
377
- e.preventDefault();
378
-
379
- let parent = $(this).parent();
380
-
381
- parent.find('a, span').addClass('hide');
382
-
383
- let form = $('<form class="form-inline"></form>');
384
-
385
- let value = parent.find('span').data('value') || parent.find('span').text();
386
- let input = $( typeof getInputCallback == 'function' ? getInputCallback(value) : '<input type="text" />');
387
- form.append(input);
388
- form.find('input').addClass('form-control').css('width', 'auto').val(value);
389
-
390
- let button = $('<button type="submit" class="btn btn-success ms-2" data-loading-text="<i class=\'fa fa-circle-notch fa-spin\'></i>" style="vertical-align: baseline;"><i class="fas fa-check"></i></button>');
391
- button.click(function (e) {
392
- FormHelper.buttonLoader(parent.find('button'), 'loading');
393
- let newValue = parent.find('input').val();
394
- onSubmitCallback(newValue, parent,
395
- (isSuccess, valueFormatCallback) => {
396
- cancelEdit(parent);
397
- if (isSuccess) {
398
- parent.find('span').data('value', newValue).text(typeof valueFormatCallback == 'function' ? valueFormatCallback(newValue) : newValue);
399
- }
400
- }
401
- );
402
- });
403
- form.append(button);
404
-
405
- parent.append(form);
406
- return false;
407
- });
408
- }
409
- }
410
-
411
- module.exports = { FormHelper, EditValue };
1
+ class FormHelper {
2
+ static init(form, onSubmitCallback, submitButton=null) {
3
+ FormHelper.reset(form, submitButton);
4
+ submitButton = null != submitButton ? submitButton : form.find('button[name="validate"]');
5
+ submitButton.off('click').click(function(e) {
6
+ e.preventDefault();
7
+ FormHelper.buttonLoader($(this), 'loading');
8
+ FormHelper.hideFormErrors(form);
9
+ if (typeof onSubmitCallback == 'function') {
10
+ onSubmitCallback(form, submitButton);
11
+ }
12
+ });
13
+ return form;
14
+ }
15
+
16
+ static reset(form, submitButton=null) {
17
+ submitButton = null != submitButton ? submitButton : form.find('button[name="validate"]');
18
+ form.find('input[name]:not([type="checkbox"], [type="radio"]), select:not(.selectpicker), textarea').each((idx, el) => $(el).val('')).off('change');
19
+ form.find('select.selectpicker').each((idx, el) => $(el).val(''));
20
+ FormHelper.buttonLoader(submitButton, 'reset');
21
+ FormHelper.hideFormErrors(form);
22
+ return form;
23
+ }
24
+
25
+ static populateForm(form, data) {
26
+ form.find('[name="employees_display_type"][value="NONE"]').prop('checked', true); //todo à retirer
27
+
28
+ $.each(data, function(key, value) {
29
+ if (value == null) {
30
+ return;
31
+ }
32
+
33
+ if (typeof value == 'object') {
34
+ let select = form.find('[name="'+key+'[]"]');
35
+ select.find('option').prop('selected', false);
36
+ select.data('default_id', value.join(','));
37
+ $.each(value, function(key, val) {
38
+ select.find('option[value="'+val+'"]').prop('selected', true);
39
+ });
40
+ return;
41
+ }
42
+
43
+ let input = form.find('[name="'+key+'"]');
44
+
45
+ if (input.prop('type') === 'radio' || input.prop('type') === 'checkbox') {
46
+ input.prop('checked', false);
47
+ input.filter('[value="'+value+'"]').prop('checked', true);
48
+ return;
49
+ }
50
+
51
+ input.val(value);
52
+ // console.log(form.find('[name="'+key+'"]').length);
53
+ });
54
+ }
55
+
56
+
57
+ static getFormData(form) {
58
+ // var formElement = document.getElementById("myFormElement");
59
+ return new FormData(form[0]);
60
+ }
61
+
62
+ static getDataFromFormData(formData) {
63
+ let data = {};
64
+ for(let pair of formData.entries()) {
65
+ //console.log(pair[0]+ ', '+ pair[1]);
66
+ data[pair[0]] = pair[1];
67
+ }
68
+ return data;
69
+ }
70
+
71
+ static getFormDataQueryString(form) {
72
+ return form.serialize();
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
+ }
81
+
82
+
83
+
84
+ // ------------------------------------------------------------
85
+ // Input text
86
+ // ------------------------------------------------------------
87
+
88
+ static getInputValue(input) {
89
+ if (typeof input == 'undefined') {
90
+ return null;
91
+ }
92
+ let value = $(input).val();
93
+ if (value === null || value === '') {
94
+ return null;
95
+ }
96
+ return value;
97
+ }
98
+
99
+ static getLinesOfTextarea(textarea) {
100
+ return textarea.val().replace(/(\r\n|\n|\r)/g, "\n").split("\n").filter(word => word.length > 0);
101
+ }
102
+
103
+ static setOnInputChange(input, callback, doneTypingInterval=700) {
104
+ // setup before functions
105
+ let typingTimer; // timer identifier
106
+
107
+ // on keyup, start the countdown
108
+ input.on('keyup', function () {
109
+ clearTimeout(typingTimer);
110
+ typingTimer = setTimeout(callback, doneTypingInterval); // time in ms
111
+ });
112
+
113
+ // on keydown, clear the countdown
114
+ input.on('keydown', function () {
115
+ clearTimeout(typingTimer);
116
+ });
117
+
118
+ // on focusout, clear the countdown and call callback
119
+ input.on('focusout', function () {
120
+ clearTimeout(typingTimer);
121
+ callback();
122
+ });
123
+ }
124
+
125
+ // ------------------------------------------------------------
126
+ // Select
127
+ // ------------------------------------------------------------
128
+
129
+ static resetSelectOption(form, selectName) {
130
+ form.find('select[name="'+selectName+'"] option').prop('disabled', false).prop('selected', false);
131
+ }
132
+ static setSelectedSelectOption(form, selectName, optionValue) {
133
+ form.find('select[name="'+selectName+'"] option[value="'+optionValue+'"]').prop('selected', true);
134
+ }
135
+ static setSelectedSelectOptions(form, selectName, optionValues) {
136
+ $.each(optionValues, function(idx, id) {
137
+ FormHelper.setSelectedSelectOption(form, selectName, id);
138
+ });
139
+ }
140
+ static disableSelectOption(form, selectName, optionValue) {
141
+ form.find('select[name="'+selectName+'"] option[value="'+optionValue+'"]').prop('disabled', true);
142
+ }
143
+ static disableSelectOptions(form, selectName, optionValues) {
144
+ $.each(optionValues, function(idx, id) {
145
+ FormHelper.disableSelectOption(form, selectName, id);
146
+ });
147
+ }
148
+ static countSelectOptions(form, selectName) {
149
+ return form.find('select[name="'+selectName+'"] option:not([disabled])').length;
150
+ }
151
+
152
+
153
+ // ------------------------------------------------------------
154
+ // Checkbox
155
+ // ------------------------------------------------------------
156
+
157
+ static getCheckedValues(inputs) {
158
+ return inputs.map(function() {
159
+ if (this.checked) {
160
+ return this.value;
161
+ }
162
+ }).get();
163
+ }
164
+
165
+ static setCheckedValues(inputs, defaultValues) {
166
+ $.each(defaultValues, function(idx, value) {
167
+ inputs.parent().find('[value="'+value+'"]').prop('checked', true);
168
+ });
169
+ }
170
+
171
+ static getInputListValues(inputs) {
172
+ return inputs.map(function() {
173
+ return this.value;
174
+ }).get().filter(word => word.length > 0);
175
+ }
176
+
177
+
178
+ // ------------------------------------------------------------
179
+ // Champs
180
+ // ------------------------------------------------------------
181
+
182
+ static initTypeFields(form) {
183
+ //if ( $('[type="date"]').prop('type') != 'date' ) {
184
+ // $('[type="date"]').datepicker();
185
+ //}
186
+ if (typeof Modernizr != 'undefined') {
187
+ if (!Modernizr.inputtypes.date) {
188
+ // $.fn.datepicker.defaults.language = 'fr';
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");
207
+ }
208
+ if (!Modernizr.inputtypes.time) {
209
+ form.find('input[type="time"]')
210
+ .css('max-width', '100px')
211
+ .attr('placeholder', 'hh:mm')
212
+ ;
213
+ form.find('input[type="time"][step="1"]').attr('placeholder', 'hh:mm:ss');
214
+ }
215
+ }
216
+
217
+ // Show/Hide password
218
+ let linkTogglePassword = $('<span class="input-group-text"><i class="fas fa-eye toggle_password"></i></span>');
219
+ linkTogglePassword.find('i').click(function(e) {
220
+ e.preventDefault();
221
+ let input = $(this).closest('.input-group').find('input');
222
+ let passwordHidden = input.attr('type') === 'password';
223
+ input.attr('type', passwordHidden ? 'text' : 'password');
224
+ $(this).removeClass('fa-eye fa-eye-slash').addClass(passwordHidden ? 'fa-eye-slash' : 'fa-eye');
225
+ });
226
+ form.find('input[type="password"]').wrap('<div class="input-group password"></div>').after(linkTogglePassword);
227
+ }
228
+
229
+ static hideField(inputOrSelect) {
230
+ inputOrSelect.closest('.form-group').addClass('hide');
231
+ }
232
+
233
+ // ------------------------------------------------------------
234
+ // Messages erreur
235
+ // ------------------------------------------------------------
236
+
237
+ static extractErrorKeyOfJson(json, onlyIfUniqueError=false) {
238
+ if (typeof json == 'undefined' || json == null) {
239
+ return null;
240
+ }
241
+
242
+ if (typeof json.error != 'undefined') {
243
+ return json.error;
244
+ }
245
+
246
+ if (onlyIfUniqueError && !json.length || json.length > 1) {
247
+ return null;
248
+ }
249
+
250
+ if (typeof json[0] != 'undefined' && typeof json[0].error != 'undefined') {
251
+ return json[0].error;
252
+ }
253
+
254
+ if (typeof json[0] != 'undefined' && Array.isArray(json[0]) && json[0].length === 2) {
255
+ return json[0][0];
256
+ }
257
+
258
+ return null;
259
+ }
260
+
261
+ static hideFormErrors(form) {
262
+ form.find('div.form_errors').remove();
263
+ return form;
264
+ }
265
+
266
+ static getFormErrorText(errors) {
267
+ let errorLabels = [];
268
+ for (let property in errors) {
269
+ // console.log(property);
270
+ if (typeof errors[property] == 'function') {
271
+ continue;
272
+ }
273
+ if (typeof errors[property]['error_description'] !== 'undefined') {
274
+ errorLabels.push(errors[property]['error_description']);
275
+ continue;
276
+ }
277
+ if (Array.isArray(errors[property]) && errors[property].length === 2) {
278
+ errorLabels.push(errors[property][1]);
279
+ continue;
280
+ }
281
+ errorLabels.push(errors[property]);
282
+ }
283
+ return errorLabels.removeEmptyValues().map(errorLabel => '<span>' + errorLabel + '</span>').join('<br/>');
284
+ }
285
+
286
+ static displayFormErrors(form, btnSubmit, errors, errorWrapperDiv=null) {
287
+ this.displayFormErrorsFromText(form, this.getFormErrorText(errors), errorWrapperDiv);
288
+ if (btnSubmit != null) {
289
+ FormHelper.buttonLoader(btnSubmit, 'reset');
290
+ //if (btnSubmit.buttonLoader != null) {
291
+ // btnSubmit.buttonLoader('reset');
292
+ //} else {
293
+ // btnSubmit.attr('disabled', false).button('reset');
294
+ //}
295
+ }
296
+ }
297
+
298
+ static displayFormErrorsFromText(form, errorLabels, errorWrapperDiv=null) {
299
+ let errorDiv = '<div class="alert alert-danger form_errors">'+errorLabels+'</div>';
300
+
301
+ if (null != errorWrapperDiv) {
302
+ errorWrapperDiv.append(errorDiv);
303
+ return;
304
+ }
305
+
306
+ if (form.find('.form_errors_content').length) {
307
+ form.find('.form_errors_content').append(errorDiv);
308
+ return;
309
+ }
310
+
311
+ let errorsParentDiv = form;
312
+ if (form.find('.modal-body').length) {
313
+ errorsParentDiv = form.find('.modal-body');
314
+ }
315
+
316
+ let firstFormGroup = errorsParentDiv.find('.form-group:first');
317
+ if (firstFormGroup.length) {
318
+ if (firstFormGroup.parent().parent().hasClass('row')) {
319
+ firstFormGroup.parent().parent().before(errorDiv);
320
+ }
321
+ else {
322
+ errorsParentDiv.find('.form-group:first').before(errorDiv);
323
+ }
324
+ return;
325
+ }
326
+
327
+ errorsParentDiv.prepend(errorDiv);
328
+ }
329
+
330
+
331
+ // ------------------------------------------------------------
332
+ // Bouton valider
333
+ // ------------------------------------------------------------
334
+
335
+ static buttonLoader(button, action) {
336
+ button = $(button);
337
+ if (action === 'start' || action === 'loading') {
338
+ if (button.attr('disabled')) {
339
+ return self;
340
+ }
341
+ button.attr('disabled', true);
342
+ button.data('btn-text', button.html());
343
+ //let text = '<span class="spinner"><i class=\'fa fa-circle-notch fa-spin\'></i></span>Traitement en cours…';
344
+ let text = '<i class=\'fa fa-circle-notch fa-spin\'></i> Traitement en cours…';
345
+ if (button.data('load-text') != null && button.data('load-text') !== '') {
346
+ text = button.data('load-text');
347
+ }
348
+ if (button.data('loading-text') != null && button.data('loading-text') !== '') {
349
+ text = button.data('loading-text');
350
+ }
351
+ button.html(text);
352
+ button.addClass('disabled');
353
+ }
354
+ if (action === 'stop' || action === 'reset') {
355
+ button.html(button.data('btn-text'));
356
+ button.removeClass('disabled');
357
+ button.attr('disabled', false);
358
+ //button.removeAttr("disabled");
359
+ }
360
+ return button;
361
+ }
362
+
363
+
364
+ }
365
+
366
+ class ArrayField {
367
+ static init(formGroupDiv, defaultValues=[], options = {
368
+ entering_field_in_table: true,
369
+ item_name: null,
370
+ nb_min_lines: 5,
371
+ nb_max_lines: null,
372
+ list_empty_text: null,
373
+ add_one_button_enabled: true,
374
+ add_one_button_label: null,
375
+ add_multi_button_enabled: false,
376
+ add_multi_button_label: null,
377
+ input_name: null,
378
+ init_callback: null,
379
+ update_list_callback: null,
380
+ get_errors_callback: null,
381
+
382
+ }) {
383
+ function isOptionDefined(optionName) {
384
+ return typeof options[optionName] != 'undefined' && null !== options[optionName];
385
+ }
386
+
387
+ let itemsList = defaultValues;
388
+
389
+ if (!formGroupDiv.find('table').length) {
390
+ formGroupDiv.append($('<table class="table table-sm"><tbody></tbody></table>'));
391
+ }
392
+ if (!formGroupDiv.find('.list_empty').length) {
393
+ formGroupDiv.append($('<div class="list_empty">'+(isOptionDefined('list_empty_text') ? options['list_empty_text'] : '<em>aucun</em>')+'</div>'));
394
+ }
395
+ if (!options['entering_field_in_table'] && !formGroupDiv.find('.add_one, .add_multi').length) {
396
+ let divLinks = formGroupDiv.find('.links');
397
+ if (!divLinks.length) {
398
+ divLinks = $('<div class="links text-center"></div>');
399
+ formGroupDiv.append(divLinks);
400
+ }
401
+
402
+ if (options['add_one_button_enabled']) {
403
+ divLinks.append($('<a href="#" class="add_one btn btn-sm btn-success">'+(isOptionDefined('add_one_button_label') ? options['add_one_button_label'] : 'Ajouter')+'</a>'));
404
+ }
405
+ if (options['add_multi_button_enabled']) {
406
+ divLinks.append($('<a href="#" class="add_multi btn btn-sm btn-success">'+(isOptionDefined('add_multi_button_label') ? options['add_multi_button_label'] : 'Ajout multiple')+'</a>'));
407
+ }
408
+ formGroupDiv.append(divLinks);
409
+ }
410
+
411
+ function addLine(item) {
412
+ const table = formGroupDiv.find('table').removeClass('hide');
413
+ let tr;
414
+ if (table.find('tbody tr.base').length) {
415
+ tr = table.find('tbody tr.base').clone().removeClass('hide').removeClass('base');
416
+ }
417
+ else {
418
+ let links = '';
419
+ if (options['entering_field_in_table']) {
420
+ links += '<a href="#" title="Ajouter" class="add btn btn-sm btn-success ms-1"><i class="fas fa-plus"></i></a>';
421
+ }
422
+ links += '<a href="#" title="Supprimer" class="remove btn btn-sm btn-danger ms-1"><i class="fas fa-times"></i></a>';
423
+
424
+ tr = $(
425
+ '<tr>' +
426
+ '<td class="table-input" style="vertical-align: middle">' +
427
+ (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>') +
428
+ '</td>' +
429
+ '<td class="table-links text-end" style="vertical-align: middle">'+links+'</td>' +
430
+ '</tr>'
431
+ );
432
+ }
433
+
434
+ tr.find('a.add').click(function () {
435
+ const tr = $(this).closest('tr');
436
+ const tableBody = tr.closest('tbody');
437
+
438
+ if (isOptionDefined('nb_max_lines') && tableBody.find('tr').length >= options['nb_max_lines']) {
439
+ return false;
440
+ }
441
+ addLine();
442
+ onUpdateList();
443
+ return false;
444
+ });
445
+ tr.find('a.remove').click(function () {
446
+ const tr = $(this).closest('tr');
447
+ const tableBody = tr.closest('tbody');
448
+ if (options['entering_field_in_table'] && tableBody.find('tr').length <= 1) {
449
+ return false;
450
+ }
451
+
452
+ if (!options['entering_field_in_table'] || '' !== tr.data('item')) {
453
+ itemsList.unsetVal(tr.data('item'));
454
+ }
455
+
456
+ tr.remove();
457
+ onUpdateList();
458
+ return false;
459
+ });
460
+
461
+ if (typeof item != 'undefined' && null !== item) {
462
+ tr.data('item', item);
463
+ tr.find('input').val(item);
464
+ tr.find('span.value').text(item);
465
+ }
466
+
467
+ table.find('tbody').append(tr);
468
+ return tr;
469
+ }
470
+
471
+ function onUpdateList() {
472
+ formGroupDiv.find('.list_empty, table').addClass('hide');
473
+
474
+ // Maj tableau
475
+ let table = formGroupDiv.find('table');
476
+ const tableLines = table.find('tbody tr:not(.base)');
477
+ if ((options['entering_field_in_table'] && tableLines.length ) || (!options['entering_field_in_table'] && itemsList.length)) {
478
+ table.removeClass('hide');
479
+ }
480
+ else {
481
+ formGroupDiv.find('.list_empty').removeClass('hide');
482
+ }
483
+
484
+ tableLines.find('a').prop('disabled', false).removeClass('disabled');
485
+ if (isOptionDefined('nb_max_lines') && tableLines.length >= options['nb_max_lines']) {
486
+ tableLines.find('a.add').prop('disabled', true).addClass('disabled');
487
+ }
488
+ if (options['entering_field_in_table'] && tableLines.length <= 1) {
489
+ tableLines.find('a.remove').prop('disabled', true).addClass('disabled');
490
+ }
491
+
492
+ if (typeof options['update_list_callback'] == 'function') {
493
+ options['update_list_callback'](itemsList);
494
+ }
495
+
496
+ cancelAdd();
497
+ }
498
+
499
+ function startAdd() {
500
+ formGroupDiv.find('a.add_one, a.add_multi').addClass('hide').closest('.links').addClass('hide');
501
+ formGroupDiv.find('.item_add_one, .item_add_multi').addClass('hide');
502
+ formGroupDiv.find('.item_add_one, .item_add_multi').find('input[type="text"], textarea').val('');
503
+ }
504
+ function cancelAdd() {
505
+ formGroupDiv.find('a.add_one, a.add_multi').removeClass('hide').closest('.links').removeClass('hide');
506
+ formGroupDiv.find('.item_add_one, .item_add_multi').addClass('hide');
507
+ }
508
+
509
+ function addItemsInList(items) {
510
+ if (!Array.isArray(items)) {
511
+ items = [items];
512
+ }
513
+
514
+ for (let i = 0; i < items.length; i++) {
515
+ if (itemsList.indexOf(items[i]) === -1) {
516
+ itemsList.push(items[i]);
517
+ addLine(items[i]);
518
+ }
519
+ }
520
+
521
+ onUpdateList();
522
+ }
523
+
524
+ function submitAddNewItem(item, divAdd) {
525
+ const items = Array.isArray(item) ? item : [item];
526
+
527
+ divAdd.find('.errors').addClass('hide');
528
+
529
+ if (typeof options['format_entered_value_callback'] == 'function') {
530
+ items.map(item => options['format_entered_value_callback'](item, divAdd));
531
+ }
532
+
533
+ if (typeof options['get_errors_callback'] == 'function') {
534
+ const errors = options['get_errors_callback'](items, itemsList, divAdd);
535
+ if (null !== errors && errors.length) {
536
+ displayErrors(divAdd, errors);
537
+ return;
538
+ }
539
+ }
540
+
541
+ addItemsInList(items);
542
+ }
543
+
544
+ function displayErrors(divAdd, errors) {
545
+ if (!Array.isArray(errors)) {
546
+ errors = [errors];
547
+ }
548
+ divAdd.find('.errors').text(errors.join('<br/>')).removeClass('hide');
549
+ }
550
+
551
+ function initLinkAddOne() {
552
+ if (!formGroupDiv.find('a.add_one').length || !formGroupDiv.find('a.add_one:not([disabled])').length) {
553
+ return;
554
+ }
555
+
556
+ let divAdd = formGroupDiv.find('.item_add_one');
557
+ if (!divAdd.length) {
558
+ divAdd = $(
559
+ '<div class="item_add_one">' +
560
+ '<div class="alert alert-danger pt-1 pb-1 errors hide"></div>' +
561
+ '<div class="form-inline">' +
562
+ '<input type="text" class="form-control" placeholder="'+options['item_name']+'" value="" /> &nbsp;' +
563
+ '<a href="#" title="Ajouter" class="add btn btn-success"><i class="fas fa-plus"></i></a> &nbsp;' +
564
+ '<a href="#" class="cancel">Annuler</a>' +
565
+ '</div>' +
566
+ (isOptionDefined('form_desc')?'<br><span class="form-text">'+options['form_desc']+'</span>':'') +
567
+ '</div>'
568
+ );
569
+ formGroupDiv.append(divAdd);
570
+ }
571
+
572
+ divAdd.find('a.cancel').off('click').click(function () {
573
+ cancelAdd();
574
+ return false;
575
+ });
576
+ divAdd.find('a.add').off('click').click(function () {
577
+ submitAddNewItem(divAdd.find('input[type="text"]').val(), divAdd);
578
+ return false;
579
+ });
580
+
581
+ formGroupDiv.find('a.add_one').off('click').click(function () {
582
+ startAdd();
583
+ formGroupDiv.find('.item_add_one').removeClass('hide');
584
+ return false;
585
+ });
586
+ }
587
+
588
+ function initLinkAddMulti() {
589
+ if (!formGroupDiv.find('a.add_multi').length || !formGroupDiv.find('a.add_multi:not([disabled])').length) {
590
+ return;
591
+ }
592
+
593
+ let divAdd = formGroupDiv.find('.item_add_multi');
594
+ if (!divAdd.length) {
595
+ divAdd = $(
596
+ '<div class="item_add_multi">' +
597
+ '<div class="alert alert-danger pt-1 pb-1 errors hide"></div>' +
598
+ '<div class="form-group">' +
599
+ '<label>Liste à ajouter :</label>' +
600
+ '<textarea name="emails" class="form-control" rows="10"></textarea>' +
601
+ '<span class="form-text">Un élément par ligne.</span>' +
602
+ '</div>' +
603
+ '<div class="form-inline">' +
604
+ '<a href="#" title="Ajouter" class="add btn btn-success"><i class="fas fa-plus"></i></a> &nbsp;' +
605
+ '<a href="#" class="cancel">Annuler</a>' +
606
+ '</div>' +
607
+ '</div>'
608
+ );
609
+ formGroupDiv.append(divAdd);
610
+ }
611
+
612
+ divAdd.find('a.cancel').off('click').click(function () {
613
+ cancelAdd();
614
+ return false;
615
+ });
616
+ divAdd.find('a.add').off('click').click(function () {
617
+ const items = divAdd.find('textarea').val().normalizeBreaks("\n").split(/\n/ms).filter(value => value.length > 0);
618
+ submitAddNewItem(items, divAdd);
619
+ return false;
620
+ });
621
+
622
+ formGroupDiv.find('a.add_multi').off('click').click(function () {
623
+ startAdd();
624
+ formGroupDiv.find('.item_add_multi').removeClass('hide');
625
+ return false;
626
+ });
627
+ }
628
+
629
+ initLinkAddOne();
630
+ initLinkAddMulti();
631
+
632
+ itemsList.forEach(item => addLine(item));
633
+ if (options['entering_field_in_table']) {
634
+ for (let i=itemsList.length; i <= options['nb_min_lines']; i++) {
635
+ addLine();
636
+ }
637
+ }
638
+
639
+ onUpdateList();
640
+
641
+ if (typeof options['init_callback'] == 'function') {
642
+ options['init_callback'](formGroupDiv, onUpdateList, addItemsInList);
643
+ }
644
+ }
645
+ }
646
+
647
+ class EditValue {
648
+ static init(valueDiv, onSubmitCallback, getInputCallback) {
649
+ let link = $('<a href="#" class="text-warning"><i class="fas fa-pencil-alt"></i></a>');
650
+ valueDiv.parent().append('&nbsp;').append(link);
651
+
652
+ function cancelEdit(valueParentDiv) {
653
+ valueParentDiv.find('a, span').removeClass('hide');
654
+ valueParentDiv.find('form').remove();
655
+ }
656
+
657
+ link.click(function (e) {
658
+ e.preventDefault();
659
+
660
+ let parent = $(this).parent();
661
+
662
+ parent.find('a, span').addClass('hide');
663
+
664
+ let form = $('<form class="form-inline"></form>');
665
+
666
+ let value = parent.find('span').data('value') || parent.find('span').text();
667
+ let input = $( typeof getInputCallback == 'function' ? getInputCallback(value) : '<input type="text" />');
668
+ form.append(input);
669
+ form.find('input').addClass('form-control').css('width', 'auto').val(value);
670
+
671
+ let button = $('<button type="submit" class="btn btn-success ms-2" data-loading-text="<i class=\'fa fa-circle-notch fa-spin\'></i>" style="vertical-align: baseline;"><i class="fas fa-check"></i></button>');
672
+ button.click(function (e) {
673
+ FormHelper.buttonLoader(parent.find('button'), 'loading');
674
+ let newValue = parent.find('input').val();
675
+ onSubmitCallback(newValue, parent,
676
+ (isSuccess, valueFormatCallback) => {
677
+ cancelEdit(parent);
678
+ if (isSuccess) {
679
+ parent.find('span').data('value', newValue).text(typeof valueFormatCallback == 'function' ? valueFormatCallback(newValue) : newValue);
680
+ }
681
+ }
682
+ );
683
+ });
684
+ form.append(button);
685
+
686
+ parent.append(form);
687
+ return false;
688
+ });
689
+ }
690
+ }
691
+
692
+ module.exports = { FormHelper, ArrayField, EditValue };