|
1 /** |
|
2 * MyAMS forms management |
|
3 */ |
|
4 (function($, globals) { |
|
5 |
|
6 var ams = globals.MyAMS; |
|
7 |
|
8 ams.form = { |
|
9 |
|
10 /** |
|
11 * Init forms to activate form change listeners |
|
12 * |
|
13 * @param element: the parent element |
|
14 */ |
|
15 init: function(element) { |
|
16 |
|
17 $('FORM', element).each(function() { |
|
18 var form = $(this); |
|
19 // Store value of hidden inputs |
|
20 $('INPUT.select2[type="hidden"]', form).each(function() { |
|
21 var input = $(this); |
|
22 input.data('ams-select2-input-value', input.val()); |
|
23 }); |
|
24 }); |
|
25 |
|
26 // Activate form changes if required |
|
27 var forms; |
|
28 if (ams.warnOnFormChange) { |
|
29 forms = $('FORM[data-ams-warn-on-change!="false"]', element); |
|
30 } else { |
|
31 forms = $('FORM[data-ams-warn-on-change="true"]', element); |
|
32 } |
|
33 forms.each(function() { |
|
34 var form = $(this), |
|
35 formChangedCallback = form.data('ams-form-changed-callback') || |
|
36 ams.formChangedCallback; |
|
37 $('INPUT[type="text"], ' + |
|
38 'INPUT[type="checkbox"], ' + |
|
39 'INPUT[type="radio"], ' + |
|
40 'SELECT, ' + |
|
41 'TEXTAREA, ' + |
|
42 '[data-ams-changed-event]', form).each(function() { |
|
43 var source = $(this); |
|
44 if (source.data('ams-ignore-change') !== true) { |
|
45 var event = source.data('ams-changed-event') || 'change'; |
|
46 source.on(event, function () { |
|
47 ams.form.setChanged(form); |
|
48 ams.executeFunctionByName(formChangedCallback, form, source); |
|
49 }); |
|
50 } |
|
51 }); |
|
52 form.on('reset', function() { |
|
53 ams.form.resetChanged($(this)); |
|
54 }); |
|
55 }); |
|
56 }, |
|
57 |
|
58 /** |
|
59 * Set focus to first container input |
|
60 */ |
|
61 setFocus: function(container) { |
|
62 var focused = $('[data-ams-focus-target]', container).first(); |
|
63 if (!focused.exists()) { |
|
64 focused = $('input, select', container).first(); |
|
65 } |
|
66 if (focused.exists()) { |
|
67 if (focused.hasClass('select2-input')) { |
|
68 focused = focused.parents('.select2'); |
|
69 } |
|
70 if (focused.hasClass('select2')) { |
|
71 setTimeout(function() { |
|
72 focused.select2('focus'); |
|
73 if (focused.data('ams-focus-open') === true) { |
|
74 focused.select2('open'); |
|
75 } |
|
76 }, 100); |
|
77 } else { |
|
78 focused.focus(); |
|
79 } |
|
80 } |
|
81 }, |
|
82 |
|
83 /** |
|
84 * Check for modified forms before exiting |
|
85 */ |
|
86 checkBeforeUnload: function() { |
|
87 var forms = $('FORM[data-ams-form-changed="true"]'); |
|
88 if (forms.exists()) { |
|
89 return ams.i18n.FORM_CHANGED_WARNING; |
|
90 } |
|
91 }, |
|
92 |
|
93 /** |
|
94 * Check for modified forms before loading new inner content |
|
95 */ |
|
96 confirmChangedForm: function(element, callback, cancelCallback) { |
|
97 if (typeof(element) === 'function') { |
|
98 callback = element; |
|
99 element = undefined; |
|
100 } |
|
101 var forms = $('FORM[data-ams-form-changed="true"]', element); |
|
102 if (forms.exists()) { |
|
103 if (cancelCallback) { |
|
104 if (globals.confirm(ams.i18n.FORM_CHANGED_WARNING, ams.i18n.WARNING)) { |
|
105 callback.call(element); |
|
106 } else { |
|
107 cancelCallback.call(element); |
|
108 } |
|
109 } else { |
|
110 ams.skin && ams.skin.bigBox({ |
|
111 title: ams.i18n.WARNING, |
|
112 content: '<i class="text-danger fa fa-2x fa-bell shake animated"></i> ' + ams.i18n.FORM_CHANGED_WARNING, |
|
113 buttons: ams.i18n.BTN_OK_CANCEL |
|
114 }, function(button) { |
|
115 if (button === ams.i18n.BTN_OK) { |
|
116 callback.call(element); |
|
117 } |
|
118 }); |
|
119 } |
|
120 } else { |
|
121 callback.call(element); |
|
122 } |
|
123 }, |
|
124 |
|
125 /** |
|
126 * Update form "chenged" status flag |
|
127 */ |
|
128 setChanged: function(form) { |
|
129 form.attr('data-ams-form-changed', true); |
|
130 }, |
|
131 |
|
132 /** |
|
133 * Reset form changed flag |
|
134 */ |
|
135 resetChanged: function(form) { |
|
136 if (form !== undefined) { |
|
137 $(form).removeAttr('data-ams-form-changed'); |
|
138 } |
|
139 }, |
|
140 |
|
141 /** |
|
142 * Submit given form |
|
143 */ |
|
144 submit: function(form, handler, submitOptions) { |
|
145 // Check params |
|
146 form = $(form); |
|
147 if (!form.exists()) { |
|
148 return false; |
|
149 } |
|
150 if (typeof(handler) === 'object') { |
|
151 submitOptions = handler; |
|
152 handler = undefined; |
|
153 } |
|
154 // Prevent multiple submits of the same form |
|
155 if (form.data('submitted')) { |
|
156 if (!form.data('ams-form-hide-submitted')) { |
|
157 ams.skin && ams.skin.messageBox('warning', { |
|
158 title: ams.i18n.WAIT, |
|
159 content: ams.i18n.FORM_SUBMITTED, |
|
160 icon: 'fa fa-save shake animated', |
|
161 timeout: form.data('ams-form-alert-timeout') || 5000 |
|
162 }); |
|
163 } |
|
164 return false; |
|
165 } |
|
166 // Check submit validators |
|
167 if (ams.form && !ams.form._checkSubmitValidators(form)) { |
|
168 return false; |
|
169 } |
|
170 // Remove remaining status messages |
|
171 $('.alert-danger, SPAN.state-error', form).not('.persistent').remove(); |
|
172 $('.state-error', form).removeClassPrefix('state-'); |
|
173 // Check submit button |
|
174 var button = $(form.data('ams-submit-button')); |
|
175 if (button && !button.data('ams-form-hide-loading')) { |
|
176 button.data('ams-progress-content', button.html()); |
|
177 button.button('loading'); |
|
178 } |
|
179 ams.ajax && ams.ajax.check($.fn.ajaxSubmit, |
|
180 ams.baseURL + 'ext/jquery-form-3.49' + ams.devext + '.js', |
|
181 function() { |
|
182 |
|
183 function _submitAjaxForm(form, options) { |
|
184 |
|
185 var button, |
|
186 buttonData, |
|
187 buttonTarget, |
|
188 data = form.data(), |
|
189 formOptions = data.amsFormOptions, |
|
190 formData, |
|
191 formDataCallback; |
|
192 |
|
193 var progressHandler, |
|
194 progressInterval, |
|
195 progressCallback, |
|
196 progressEndCallback; |
|
197 |
|
198 // Inner progress status handler |
|
199 function _getProgress(handler, progress_id) { |
|
200 |
|
201 var timeout; |
|
202 |
|
203 function _clearProgressStatus() { |
|
204 clearTimeout(timeout); |
|
205 ams.form.resetAfterSubmit(form, button); |
|
206 button.html(button.data('ams-progress-content')); |
|
207 ams.executeFunctionByName(progressEndCallback, form, button); |
|
208 ams.form.resetChanged(form); |
|
209 } |
|
210 |
|
211 function _getProgressStatus() { |
|
212 ams.ajax && ams.ajax.post(handler, |
|
213 {progress_id: progress_id}, |
|
214 {error: _clearProgressStatus}, |
|
215 ams.getFunctionByName(progressCallback) || function(result, status) { |
|
216 if (status === 'success') { |
|
217 if (result.status === 'running') { |
|
218 if (result.message) { |
|
219 button.text(result.message); |
|
220 } else { |
|
221 var text = button.data('ams-progress-text') || ams.i18n.PROGRESS; |
|
222 if (result.current) { |
|
223 text += ': ' + result.current + '/ ' + (result.length || 100); |
|
224 } else { |
|
225 text += '...'; |
|
226 } |
|
227 button.text(text); |
|
228 } |
|
229 timeout = setTimeout(_getProgressStatus, progressInterval); |
|
230 } else if (result.status === 'finished') { |
|
231 _clearProgressStatus(); |
|
232 } |
|
233 } else { |
|
234 _clearProgressStatus(); |
|
235 } |
|
236 }); |
|
237 } |
|
238 |
|
239 button.button('loading'); |
|
240 timeout = setTimeout(_getProgressStatus, progressInterval); |
|
241 } |
|
242 |
|
243 // Initialize form data |
|
244 if (submitOptions) { |
|
245 formDataCallback = submitOptions.formDataInitCallback; |
|
246 } |
|
247 if (formDataCallback) { |
|
248 delete submitOptions.formDataInitCallback; |
|
249 } else { |
|
250 formDataCallback = data.amsFormDataInitCallback; |
|
251 } |
|
252 if (formDataCallback) { |
|
253 var veto = {}; |
|
254 formData = ams.executeFunctionByName(formDataCallback, form, veto); |
|
255 if (veto.veto) { |
|
256 button = form.data('ams-submit-button'); |
|
257 if (button) { |
|
258 button.button('reset'); |
|
259 } |
|
260 ams.form.finalizeSubmitFooter.call(form); |
|
261 return false; |
|
262 } |
|
263 } else { |
|
264 formData = data.amsFormData || {}; |
|
265 } |
|
266 |
|
267 // Check submit button for custom action handler and target |
|
268 button = $(form.data('ams-submit-button')); |
|
269 if (button && button.exists()) { |
|
270 buttonData = button.data(); |
|
271 buttonTarget = buttonData.amsFormSubmitTarget; |
|
272 } else { |
|
273 buttonData = {}; |
|
274 } |
|
275 |
|
276 // Check action URL |
|
277 var url; |
|
278 var formHandler = handler || buttonData.amsFormHandler || data.amsFormHandler || ''; |
|
279 if (formHandler.startsWith(window.location.protocol)) { |
|
280 url = formHandler; |
|
281 } else { |
|
282 var action = buttonData.amsFormAction || form.attr('action').replace(/#/, ''); |
|
283 if (action.startsWith(window.location.protocol)) { |
|
284 url = action; |
|
285 } else { |
|
286 url = ams.ajax && (ams.ajax.getAddr() + action); |
|
287 } |
|
288 url += formHandler; |
|
289 } |
|
290 progressHandler = buttonData.amsProgressHandler || data.amsProgressHandler || ''; |
|
291 progressInterval = buttonData.amsProgressInterval || data.amsProgressInterval || 1000; |
|
292 progressCallback = buttonData.amsProgressCallback || data.amsProgressCallback; |
|
293 progressEndCallback = buttonData.amsProgressEndCallback || data.amsProgressEndCallback; |
|
294 |
|
295 // Initialize submit target with AJAX indicator |
|
296 var target = null; |
|
297 if (submitOptions && submitOptions.initSubmitTarget) { |
|
298 ams.executeFunctionByName(submitOptions.initSubmitTarget, form); |
|
299 } else { |
|
300 if (data.amsFormInitSubmitTarget) { |
|
301 target = $(buttonTarget || data.amsFormSubmitTarget || '#content'); |
|
302 ams.executeFunctionByName(data.amsFormInitSubmit || 'MyAMS.form.initSubmit', form, target); |
|
303 } else if (!data.amsFormHideSubmitFooter) { |
|
304 ams.executeFunctionByName(data.amsFormInitSubmit || 'MyAMS.form.initSubmitFooter', form); |
|
305 } |
|
306 } |
|
307 |
|
308 // Complete form data |
|
309 if (submitOptions) { |
|
310 formData = $.extend({}, formData, submitOptions.form_data); |
|
311 } |
|
312 |
|
313 // Check progress handler |
|
314 var hasUpload; |
|
315 if (progressHandler) { |
|
316 formData.progress_id = ams.generateUUID(); |
|
317 } else { |
|
318 // Check progress meter via Apache progress module |
|
319 hasUpload = typeof (options.uuid) !== 'undefined'; |
|
320 if (hasUpload) { |
|
321 if (url.indexOf('X-Progress-ID') < 0) { |
|
322 url += "?X-Progress-ID=" + options.uuid; |
|
323 } |
|
324 delete options.uuid; |
|
325 } |
|
326 } |
|
327 |
|
328 // Initialize default AJAX settings |
|
329 var defaults = { |
|
330 url: url, |
|
331 type: 'post', |
|
332 cache: false, |
|
333 data: formData, |
|
334 dataType: data.amsFormDatatype, |
|
335 beforeSerialize: function(/*form, options*/) { |
|
336 form.trigger('myams.form.before-serialize'); |
|
337 if (typeof (globals.tinyMCE) !== 'undefined') { |
|
338 globals.tinyMCE.triggerSave(); |
|
339 } |
|
340 }, |
|
341 beforeSubmit: function(data, form /*, options*/) { |
|
342 form.trigger('myams.form.before-submit', [data]); |
|
343 form.data('submitted', true); |
|
344 if (form.data('ams-form-reset-before-submit')) { |
|
345 setTimeout(function() { |
|
346 ams.form.resetAfterSubmit(form); |
|
347 }, 250); |
|
348 } |
|
349 }, |
|
350 error: function(request, status, error, form) { |
|
351 form.trigger('myams.form.submit-error', [request, status, error]); |
|
352 if (target) { |
|
353 ams.executeFunctionByName(data.amsFormSubmitError || 'MyAMS.form.finalizeSubmitOnError', form, target); |
|
354 } |
|
355 ams.form.resetAfterSubmit(form); |
|
356 }, |
|
357 iframe: hasUpload |
|
358 }; |
|
359 |
|
360 // Initialize IFrame for custom download target |
|
361 var downloadTarget = (submitOptions && submitOptions.downloadTarget) || data.amsFormDownloadTarget; |
|
362 if (downloadTarget) { |
|
363 var iframe = $('iframe[name="' + downloadTarget + '"]'); |
|
364 if (!iframe.exists()) { |
|
365 iframe = $('<iframe></iframe>').hide() |
|
366 .attr('name', downloadTarget) |
|
367 .appendTo($('body')); |
|
368 } |
|
369 defaults = $.extend({}, defaults, { |
|
370 iframe: true, |
|
371 iframeTarget: iframe, |
|
372 success: function(result, status, request, form) { |
|
373 form.trigger('myams.form.after-submit', [result, status, request]); |
|
374 var modal = $(form).parents('.modal-dialog'); |
|
375 if (modal.exists()) { |
|
376 ams.dialog && ams.dialog.close(form); |
|
377 } else { |
|
378 var callback, |
|
379 button = form.data('ams-submit-button'); |
|
380 if (button) { |
|
381 callback = button.data('ams-form-submit-callback'); |
|
382 } |
|
383 if (!callback) { |
|
384 callback = ams.getFunctionByName(data.amsFormSubmitCallback) || ams.form._submitCallback; |
|
385 } |
|
386 try { |
|
387 callback.call(form, result, status, request, form); |
|
388 } finally { |
|
389 ams.form.resetAfterSubmit(form); |
|
390 ams.form.resetChanged(form); |
|
391 } |
|
392 } |
|
393 } |
|
394 }); |
|
395 } else { |
|
396 defaults = $.extend({}, defaults, { |
|
397 error: function(request, status, error, form) { |
|
398 if (target) { |
|
399 ams.executeFunctionByName(data.amsFormSubmitError || 'MyAMS.form.finalizeSubmitOnError', form, target); |
|
400 } |
|
401 ams.form.resetAfterSubmit(form); |
|
402 }, |
|
403 success: function(result, status, request, form) { |
|
404 form.trigger('myams.form.after-submit', [result, status, request]); |
|
405 var callback, |
|
406 button = form.data('ams-submit-button'); |
|
407 if (button) { |
|
408 callback = button.data('ams-form-submit-callback'); |
|
409 } |
|
410 if (!callback) { |
|
411 callback = ams.getFunctionByName(data.amsFormSubmitCallback) || ams.form._submitCallback; |
|
412 } |
|
413 try { |
|
414 callback.call(form, result, status, request, form); |
|
415 } finally { |
|
416 ams.form.resetAfterSubmit(form); |
|
417 ams.form.resetChanged(form); |
|
418 } |
|
419 }, |
|
420 iframe: hasUpload |
|
421 }); |
|
422 } |
|
423 var settings = $.extend({}, defaults, options, formOptions, submitOptions); |
|
424 |
|
425 // Initialize progress handler |
|
426 if (progressHandler) { |
|
427 _getProgress(progressHandler, formData.progress_id); |
|
428 } |
|
429 |
|
430 // Submit form |
|
431 $(form).ajaxSubmit(settings); |
|
432 |
|
433 // If external download target is specified, reset form submit button and footer |
|
434 if (downloadTarget) { |
|
435 var modal = $(form).parents('.modal-dialog'); |
|
436 var keepModal = modal.exists() && button.exists() && button.data('ams-keep-modal'); |
|
437 if (modal.exists() && (keepModal !== true)) { |
|
438 ams.dialog && ams.dialog.close(form); |
|
439 } else { |
|
440 if (!progressHandler) { |
|
441 setTimeout(function() { |
|
442 ams.form.resetAfterSubmit(form, button); |
|
443 ams.form.resetChanged(form); |
|
444 }, button.data('ams-form-reset-timeout') || 2000); |
|
445 } |
|
446 } |
|
447 } |
|
448 } |
|
449 |
|
450 var hasUpload = (form.data('ams-form-ignore-uploads') !== true) && |
|
451 ($('INPUT[type="file"]', form).length > 0); |
|
452 if (hasUpload) { |
|
453 // JQuery-progressbar plug-in must be loaded synchronously!! |
|
454 // Otherwise, hidden input fields created by jquery-validate plug-in |
|
455 // and matching named buttons will be deleted (on first form submit) |
|
456 // before JQuery-form plug-in can get them when submitting the form... |
|
457 ams.ajax && ams.ajax.check($.progressBar, |
|
458 ams.baseURL + 'ext/jquery-progressbar' + ams.devext + '.js'); |
|
459 var settings = $.extend({}, { |
|
460 uuid: $.progressBar.submit(form) |
|
461 }); |
|
462 _submitAjaxForm(form, settings); |
|
463 } else { |
|
464 _submitAjaxForm(form, {}); |
|
465 } |
|
466 }); |
|
467 return false; |
|
468 }, |
|
469 |
|
470 /** |
|
471 * Initialize AJAX submit call |
|
472 * |
|
473 * @param this: the submitted form |
|
474 * @param target: the form submit container target |
|
475 * @param message: the optional message |
|
476 */ |
|
477 initSubmit: function(target, message) { |
|
478 var form = $(this), |
|
479 spin = '<i class="fa fa-3x fa-gear fa-spin"></i>'; |
|
480 if (!message) { |
|
481 message = form.data('ams-form-submit-message'); |
|
482 } |
|
483 if (message) { |
|
484 spin += '<strong>' + message + '</strong>'; |
|
485 } |
|
486 $(target).html('<div class="row margin-20"><div class="text-center">' + spin + '</div></div>'); |
|
487 $(target).parents('.hidden').removeClass('hidden'); |
|
488 }, |
|
489 |
|
490 /** |
|
491 * Reset form status after submit |
|
492 * |
|
493 * @param form: the submitted form |
|
494 */ |
|
495 resetAfterSubmit: function(form) { |
|
496 if (form.data('submitted')) { |
|
497 if (form.is(':visible')) { |
|
498 var button = form.data('ams-submit-button'); |
|
499 if (button) { |
|
500 button.button('reset'); |
|
501 } |
|
502 ams.form.finalizeSubmitFooter.call(form); |
|
503 } |
|
504 form.data('submitted', false); |
|
505 form.removeData('ams-submit-button'); |
|
506 form.trigger('myams.form.after-reset'); |
|
507 } |
|
508 }, |
|
509 |
|
510 /** |
|
511 * Finalize AJAX submit call |
|
512 * |
|
513 * @param target: the form submit container target |
|
514 */ |
|
515 finalizeSubmitOnError: function(target) { |
|
516 $('i', target).removeClass('fa-spin') |
|
517 .removeClass('fa-gear') |
|
518 .addClass('fa-ambulance'); |
|
519 }, |
|
520 |
|
521 /** |
|
522 * Initialize AJAX submit call in form footer |
|
523 * |
|
524 * @param this: the submitted form |
|
525 * @param message: the optional submit message |
|
526 */ |
|
527 initSubmitFooter: function(message) { |
|
528 var form = $(this), |
|
529 spin = '<i class="fa fa-3x fa-gear fa-spin"></i>'; |
|
530 if (!message) { |
|
531 message = $(this).data('ams-form-submit-message'); |
|
532 } |
|
533 if (message) { |
|
534 spin += '<strong class="submit-message align-top padding-left-10 margin-top-10">' + message + '</strong>'; |
|
535 } |
|
536 var footer = $('footer', form); |
|
537 $('button', footer).hide(); |
|
538 footer.append('<div class="row"><div class="text-center">' + spin + '</div></div>'); |
|
539 }, |
|
540 |
|
541 /** |
|
542 * Finalize AJAX submit call |
|
543 * |
|
544 * @param this: the submitted form |
|
545 * @param target: the form submit container target |
|
546 */ |
|
547 finalizeSubmitFooter: function(/*target*/) { |
|
548 var form = $(this), |
|
549 footer = $('footer', form); |
|
550 if (footer) { |
|
551 $('.row', footer).remove(); |
|
552 $('button', footer).show(); |
|
553 } |
|
554 }, |
|
555 |
|
556 /** |
|
557 * Handle AJAX submit results |
|
558 * |
|
559 * Submit results are auto-detected via response content type, except when this content type |
|
560 * is specified into form's data attributes. |
|
561 * Submit response can be of several content types: |
|
562 * - html or text: the response is directly included into a "target" container (#content by default) |
|
563 * - json: a "status" attribute indicates how the request was handled and how the response should be |
|
564 * treated: |
|
565 * - error: indicates that an error occured; other response attributes indicate error messages |
|
566 * - success: basic success, no other action is requested |
|
567 * - callback: only call given function to handle the result |
|
568 * - callbacks: only call given set of functions to handle the result |
|
569 * - reload: page's body should be reloaded from a given URL |
|
570 * - redirect: redirect browser to given URL |
|
571 * Each JSON response can also specify an HTML content, a message and a callback ( |
|
572 */ |
|
573 _submitCallback: function(result, status, request, form) { |
|
574 |
|
575 var button; |
|
576 if (form.is(':visible')) { |
|
577 ams.form.finalizeSubmitFooter.call(form); |
|
578 button = form.data('ams-submit-button'); |
|
579 if (button) { |
|
580 button.button('reset'); |
|
581 } |
|
582 } |
|
583 |
|
584 var data = form.data(), |
|
585 dataType; |
|
586 if (data.amsFormDatatype) { |
|
587 dataType = data.amsFormDatatype; |
|
588 } else { |
|
589 var response = ams.ajax && ams.ajax.getResponse(request); |
|
590 if (response) { |
|
591 dataType = response.contentType; |
|
592 result = response.data; |
|
593 } |
|
594 } |
|
595 |
|
596 var target; |
|
597 if (button) { |
|
598 target = $(button.data('ams-form-submit-target') || data.amsFormSubmitTarget || '#content'); |
|
599 } else { |
|
600 target = $(data.amsFormSubmitTarget || '#content'); |
|
601 } |
|
602 |
|
603 switch (dataType) { |
|
604 case 'json': |
|
605 ams.ajax && ams.ajax.handleJSON(result, form, target); |
|
606 break; |
|
607 case 'script': |
|
608 break; |
|
609 case 'xml': |
|
610 break; |
|
611 case 'html': |
|
612 /* falls through */ |
|
613 case 'text': |
|
614 /* falls through */ |
|
615 default: |
|
616 ams.form.resetChanged(form); |
|
617 if (button && (button.data('ams-keep-modal') !== true)) { |
|
618 ams.dialog && ams.dialog.close(form); |
|
619 } |
|
620 if (!target.exists()) { |
|
621 target = $('body'); |
|
622 } |
|
623 target.parents('.hidden').removeClass('hidden'); |
|
624 $('.alert', target.parents('.alerts-container')).remove(); |
|
625 target.css({opacity: '0.0'}) |
|
626 .html(result) |
|
627 .delay(50) |
|
628 .animate({opacity: '1.0'}, 300); |
|
629 ams.initContent && ams.initContent(target); |
|
630 ams.form.setFocus(target); |
|
631 } |
|
632 var callback = request.getResponseHeader('X-AMS-Callback'); |
|
633 if (callback) { |
|
634 var options = request.getResponseHeader('X-AMS-Callback-Options'); |
|
635 ams.executeFunctionByName(callback, form, options === undefined ? {} : JSON.parse(options), request); |
|
636 } |
|
637 }, |
|
638 |
|
639 /** |
|
640 * Get list of custom validators called before submit |
|
641 */ |
|
642 _getSubmitValidators: function(form) { |
|
643 var validators = []; |
|
644 var formValidator = form.data('ams-form-validator'); |
|
645 if (formValidator) { |
|
646 validators.push([form, formValidator]); |
|
647 } |
|
648 $('[data-ams-form-validator]', form).each(function() { |
|
649 var source = $(this); |
|
650 validators.push([source, source.data('ams-form-validator')]); |
|
651 }); |
|
652 return validators; |
|
653 }, |
|
654 |
|
655 /** |
|
656 * Call list of custom validators before submit |
|
657 * |
|
658 * Each validator can return: |
|
659 * - a boolean 'false' value to just specify that an error occured |
|
660 * - a string value containing an error message |
|
661 * - an array containing a list of string error messages |
|
662 * Any other value (undefined, null, True...) will lead to a successful submit. |
|
663 */ |
|
664 _checkSubmitValidators: function(form) { |
|
665 var validators = ams.form._getSubmitValidators(form); |
|
666 if (!validators.length) { |
|
667 return true; |
|
668 } |
|
669 var output = [], |
|
670 result = true; |
|
671 for (var index=0; index < validators.length; index++) { |
|
672 var validator = validators[index], |
|
673 source = validator[0], |
|
674 handler = validator[1], |
|
675 validatorResult = ams.executeFunctionByName(handler, form, source); |
|
676 if (validatorResult === false) { |
|
677 result = false; |
|
678 } else if (typeof(validatorResult) === 'string') { |
|
679 output.push(validatorResult); |
|
680 } else if (result.length && (result.length > 0)) { |
|
681 output = output.concat(result); |
|
682 } |
|
683 } |
|
684 if (output.length > 0) { |
|
685 var header = output.length === 1 ? ams.i18n.ERROR_OCCURED : ams.i18n.ERRORS_OCCURED; |
|
686 ams.skin && ams.skin.alert(form, 'danger', header, output); |
|
687 return false; |
|
688 } else { |
|
689 return result; |
|
690 } |
|
691 }, |
|
692 |
|
693 /** |
|
694 * Display JSON errors |
|
695 * JSON errors should be defined in an object as is: |
|
696 * {status: 'error', |
|
697 * error_message: "Main error message", |
|
698 * messages: ["Message 1", "Message 2",...] |
|
699 * widgets: [{label: "First widget name", |
|
700 * name: "field-name-1", |
|
701 * message: "Error message"}, |
|
702 * {label: "Second widget name", |
|
703 * name: "field-name-2", |
|
704 * message: "Second error message"},...]} |
|
705 */ |
|
706 showErrors: function(form, errors) { |
|
707 var header; |
|
708 if (typeof(errors) === 'string') { |
|
709 ams.skin && ams.skin.alert(form, 'error', ams.i18n.ERROR_OCCURED, errors); |
|
710 } else if (errors instanceof Array) { |
|
711 header = errors.length === 1 ? ams.i18n.ERROR_OCCURED : ams.i18n.ERRORS_OCCURED; |
|
712 ams.skin && ams.skin.alert(form, 'error', header, errors); |
|
713 } else { |
|
714 $('.state-error', form).removeClass('state-error'); |
|
715 header = errors.error_header || |
|
716 (errors.widgets && (errors.widgets.length > 1) ? ams.i18n.ERRORS_OCCURED : ams.i18n.ERROR_OCCURED); |
|
717 var message = []; |
|
718 var index; |
|
719 if (errors.messages) { |
|
720 for (index = 0; index < errors.messages.length; index++) { |
|
721 var msg = errors.messages[index]; |
|
722 if (msg.header) { |
|
723 message.push('<strong>' + msg.header + '</strong><br />' + msg.message); |
|
724 } else { |
|
725 message.push(msg.message || msg); |
|
726 } |
|
727 } |
|
728 } |
|
729 if (errors.widgets) { |
|
730 for (index = 0; index < errors.widgets.length; index++) { |
|
731 // set widget status message |
|
732 var widgetData = errors.widgets[index]; |
|
733 var widget = $('[name="' + widgetData.name + '"]', form); |
|
734 if (!widget.exists()) { |
|
735 widget = $('[name="' + widgetData.name + ':list"]', form); |
|
736 } |
|
737 if (widget.exists()) { |
|
738 // Update widget state |
|
739 widget.parents('label, .input') |
|
740 .first() |
|
741 .removeClassPrefix('state-') |
|
742 .addClass('state-error') |
|
743 .after('<span for="name" class="state-error">' + widgetData.message + '</span>'); |
|
744 } else { |
|
745 // complete form alert message |
|
746 if (widgetData.label) { |
|
747 message.push(widgetData.label + ' : ' + widgetData.message); |
|
748 } |
|
749 } |
|
750 // mark parent tab (if any) with error status |
|
751 var tabIndex = widget.parents('.tab-pane').index() + 1; |
|
752 if (tabIndex > 0) { |
|
753 var navTabs = $('.nav-tabs', $(widget).parents('.tabforms')); |
|
754 $('li:nth-child(' + tabIndex + ')', navTabs).removeClassPrefix('state-') |
|
755 .addClass('state-error'); |
|
756 $('li.state-error:first a', form).click(); |
|
757 } |
|
758 } |
|
759 } |
|
760 ams.skin && ams.skin.alert($('.form-group:first', form), errors.error_level || 'error', header, message, errors.error_message); |
|
761 } |
|
762 } |
|
763 }; |
|
764 |
|
765 })(jQuery, this); |