PageSourceSearch

https://www.st-cyr-ardeche.fr/packages/formidable/blocks/formidabl…=115d54aadcabbac4aa256e42739ed7d07ea22412

js st-cyr-ardeche.fr collected 2026-09-25 10:48:27 UTC 55,402 bytes, 1,414 lines download raw bytes

1if (typeof formidable_dropzone === "undefined") var formidable_dropzone = [];
2
3(function ($) {
4
5    if ($.fn.Dropzone) {
6        Dropzone.autoDiscover = false;
7    }
8
9    "use strict";
10
11    $.fn.tagName = function() {
12        return this.prop('tagName').toLowerCase();
13    };
14
15    $.fn.formidable = function (settings) {
16
17        var timeout = '';
18        var formidable = this;
19        var dropzone = 0;
20        var debug = false;
21
22        $.extend(formidable, {
23
24            settings: $.extend({
25
26                // Do callback on load
27                // Vars: method|function
28                onloadCallback: function() {},
29
30                // Set locale
31                // Vars: string --> 'en', 'fr', 'nl', ...
32                locale: 'en',
33
34                // Show errors on top of form or underneath each element
35                // Vars: string -> 'form', 'element'
36                errors: 'element',
37
38                // Add additional classes to each error message
39                // Vars: string
40                errorsAdditionalClass: '',
41
42                // Do callback on errors
43                // Vars: method|function
44                errorsCallback: function() {},
45
46                // Hide form on successful submission
47                // Vars: bolean
48                successHideForm: false,
49
50                // Add additional classes to each error message
51                // Vars: string
52                successAdditionalClass: '',
53
54                // Scroll to top on success
55                // Vars: bolean
56                scrollToTop: true,
57
58                // Scroll animation time
59                // Vars: int
60                scrollTime: 200,
61
62                // Scroll offset from top
63                // Vars: int
64                scrollOffset: 0,
65
66                // Do callback on success
67                // Vars: method|function
68                successCallback: function() {},
69
70                // Dependencies for the form.
71                // Should be loaded through the controller
72                // Vars: json string
73                dependencies: '',
74
75                // Step variables
76                // Vars: array
77                steps: {
78                    /* Appearance */
79                    headerTag: "h3",
80                    bodyTag: "section",
81                    contentContainerTag: "div",
82                    actionContainerTag: "div",
83                    stepsContainerTag: "div",
84                    cssClass: "has-steps",
85                    stepsOrientation: 0,
86
87                    /* Templates */
88                    titleTemplate: '<span class="number">#index#.</span> #title#',
89                    loadingTemplate: '<span class="spinner"></span> #text#',
90
91                    /* Behaviour */
92                    autoFocus: false,
93                    enableAllSteps: false,
94                    enableKeyNavigation: false,
95                    enablePagination: false,
96                    suppressPaginationOnFocus: true,
97                    enableContentCache: true,
98                    enableCancelButton: false,
99                    enableFinishButton: false,
100                    preloadContent: false,
101                    showFinishButtonAlways: false,
102                    forceMoveForward: false,
103                    saveState: false,
104                    startIndex: 0,
105
106                    /* Transition Effects */
107                    transitionEffect: 'fade',
108                    transitionEffectSpeed: 200,
109
110                    /* Events */
111                    onStepChanging: function (event, currentIndex, newIndex) { return true; },
112                    onStepChanged: function (event, currentIndex, priorIndex) { }},
113                    onCanceled: function (event) { },
114                    onFinishing: function (event, currentIndex) { return true; },
115                    onFinished: function (event, currentIndex) { },
116
117                    /* Labels */
118                    labels: {
119                        cancel: "Cancel",
120                        current: "current step:",
121                        pagination: "Pagination",
122                        finish: "Finish",
123                        next: "Next",
124                        previous: "Previous",
125                        loading: "Loading ..."
126                    }
127
128            }, settings),
129
130            init: function()
131            {
132                // initialize formObj
133                this.formObj = $('form', this);
134
135                // set locale
136                this.setLocale();
137
138                // add honeypot
139                this.addHoneypot();
140
141                // add resolution
142                this.setResolution();
143
144                // enable steps
145                this.enableSteps();
146
147                // enable masking
148                this.enableMasking();
149
150                // enable counter
151                this.enableCounter();
152
153                // enable ranges
154                this.enableRanges();
155
156                // enable sigantures
157                this.enableSignatures();
158
159                // enable others for options
160                this.enableOthers();
161
162                // enable dropzones
163                this.enableDropzones();
164
165                // load dependencies
166                this.loadDependencies();
167
168                // do callback
169                this.doCallbackOnload();
170
171                // on submit!
172                this.formObj.off('submit').on('submit', this.formSubmit.bind(this));
173            },
174
175            formSubmit: function(e)
176            {
177                // stop form from submitting
178                e.preventDefault();
179
180                // capture data
181                var formData = this.captureData();
182
183                // disable fields
184                this.startProcess();
185
186                return $.ajax({
187                    url: this.formObj.attr('action'),
188                    data: formData,
189                    method: 'post',
190                    dataType: 'json',
191
192                    // when using formdata
193                    contentType: false,
194                    processData: false,
195                    cache: false,
196
197                    beforeSend: this.beforeFormSend.bind(this),
198                    error: this.formSubmitError.bind(this),
199                    success: this.formSubmitSuccess.bind(this),
200                    complete: this.formSubmitComplete.bind(this)
201                });
202            },
203
204            beforeFormSend: function()
205            {
206                formidable.removeClass('was-validated');
207                formidable.find(':input').removeClass('is-invalid is-valid');
208                formidable.find('.invalid-feedback, .valid-feedback').remove();
209                formidable.find('[data-formidable-message]').empty().hide();
210            },
211
212            formSubmitError: function(response)
213            {
214                var data = response.responseJSON;
215
216                if (data.message) {
217                    this.formMessage(data.message);
218                }
219
220                if (data.errors) {
221                    var self = this;
222                    var formMessages = [];
223
224                    // support both error formats:
225                    //   keyed:     { field_handle: ["message", ...] }
226                    //   ErrorList: [ { field: { element: "field_handle" }, message: "message" } ]
227                    $.each(data.errors, function(key, err) {
228                        var handle = null;
229                        var message = null;
230
231                        if (err !== null && typeof err === 'object' && typeof err.message !== 'undefined') {
232                            message = err.message;
233                            if (err.field && err.field.element) {
234                                handle = err.field.element;
235                            }
236                        } else {
237                            handle = key;
238                            message = $.isArray(err) ? err.join('<br />') : err;
239                        }
240
241                        if (self.settings.errors == 'form' || !handle || handle == 'form') {
242                            formMessages.push(message);
243
244                            if (handle) {
245                                var holder = $('[data-formidable-handle="'+handle+'"]', formidable);
246                                if (typeof handle === 'object') {
247                                    holder = handle;
248                                }
249                                holder.find(':input:not(.no-valid)').addClass('is-invalid');
250                            }
251
252                        } else {
253                            self.elementMessage(handle, message);
254                        }
255                    });
256
257                    if (formMessages.length) {
258                        self.formMessage({type: 'error', message: formMessages});
259                    }
260                }
261            },
262
263            formSubmitSuccess: function(data)
264            {
265
266                if (data.redirect) {
267
268                    // make sure to start process
269                    this.startProcess();
270
271                    window.location.href = data.redirect;
272                    return;
273                }
274
275                if (data.message) {
276                    this.formMessage({type: 'success', message: data.message});
277                }
278            },
279
280            formSubmitSuccessStep: function(data)
281            {
282                // set as validated
283                this.setFormValidated(data.step);
284
285                // reload ccm_token
286                this.resetToken(data.ccm_token);
287
288                // refresh elements
289                this.resetRecaptcha();
290
291                // enable fields
292                this.stopProcess();
293
294                // scroll to top of form
295                this.scrollToTop();
296            },
297
298            formValidateCurrentStep: function(noError)
299            {
300                // capture data
301                var formData = this.captureData();
302
303                // add current step data
304                formData.append('validate_formidable_step', $('[data-formidable-step].current', formidable).data('formidable-step'));
305
306                // disable fields
307                this.startProcess();
308
309                return $.ajax({
310                    url: this.formObj.attr('action'),
311                    data: formData,
312                    method: 'post',
313                    dataType: 'json',
314                    // make sure this isn't async.
315                    async: false,
316
317                    // when using formdata
318                    contentType: false,
319                    processData: false,
320                    cache: false,
321
322                    beforeSend: this.beforeFormSend.bind(this),
323                    error: !!noError?function(){}:this.formSubmitError.bind(this),
324                    success: this.formSubmitSuccessStep.bind(this),
325                    complete: this.stopProcess.bind(this),
326                });
327            },
328
329            formClearCurrentStep: function()
330            {
331                $(':input', $('[data-formidable-step].current', formidable)).each(function(i, field) {
332                    $(field).removeClass('is-valid no-valid is-invalid is-invalid');
333                    if ($(field).attr('type') == 'radio' || $(field).attr('type') == 'checkbox') {
334                        $(field).prop('checked', false);
335                        $(field).closest('label').removeClass('active');
336                    }
337                    else $(field).val('');
338                });
339                this.formValidateCurrentStep(true); // true for no errors
340            },
341
342            formSubmitComplete: function(response, status)
343            {
344                var data = response.responseJSON;
345
346                // set as validated
347                this.setFormValidated();
348
349                // reload ccm_token
350                this.resetToken(data.ccm_token);
351
352                // refresh elements
353                this.resetRecaptcha();
354
355                // enable fields
356                this.stopProcess();
357
358                // scroll to top of form
359                this.scrollToTop();
360
361                // reload dependencies
362                this.reloadDependencies();
363
364                // do callback
365                if (status == 'error') {
366                    this.doCallbackError(response);
367                }
368                if (status == 'success') {
369
370                    // clear form
371                    this.resetForm();
372
373                    // hide form
374                    this.hideForm();
375
376                    // data layer (enhanced)
377                    this.doEnhancedConversion(response);
378
379                    // do callback
380                    this.doCallbackSuccess(response);
381                }
382            },
383
384            captureData: function()
385            {
386                // before we capture all data, we need to process the textarea (wysiwyg)
387                if (typeof(CKEDITOR) != 'undefined') {
388                    for(var i in CKEDITOR.instances) {
389                        CKEDITOR.instances[i].updateElement();
390                    }
391                }
392                // now grab all the data.
393                var formData = new FormData(this.formObj[0]);
394                return formData;
395            },
396
397            setLocale: function()
398            {
399                // set locale for moment.js
400                if (window.moment) {
401                    moment.locale(this.settings.locale.substr(0, 2));
402                }
403            },
404
405            setResolution: function()
406            {
407                var resolution = $('<input>').attr({
408                    'type': 'hidden',
409                    'name': 'resolution',
410                    'id': 'resolution',
411                    'value': screen.width + 'x' + screen.height
412                });
413                this.formObj.prepend(resolution);
414            },
415
416            addHoneypot: function()
417            {
418                var website_url = $('<input>').attr({
419                    'type': 'text',
420                    'name': 'website_url',
421                    'id': 'website_url',
422                    'value': ''
423                }).attr('style', 'display:none');
424                this.formObj.prepend(website_url);
425
426                var homepage = $('<input>').attr({
427                    'type': 'text',
428                    'name': 'homepage',
429                    'id': 'homepage',
430                    'value': ''
431                }).attr('style', 'display:none');
432                this.formObj.prepend(homepage);
433            },
434
435            enableSteps: function()
436            {
437                if ($.fn.steps) {
438                    if (this.formObj.find('[data-formidable-step]').length <= 0) {
439                        return;
440                    }
441
442                    this.settings.steps.onStepChanging = function (e, currentStep, newStep)
443                    {
444                        // Always allow previous action even if the current form is not val
444id!
445                        if (newStep < currentStep) {
446                            this.formClearCurrentStep();
447                            this.scrollToTop(1);
448                            return true;
449                        }
450
451                        // now handle the next step!
452                        var promise = this.formValidateCurrentStep();
453                        if (promise.responseJSON.success) {
454                            this.stopProcess();
455                            this.scrollToTop(1);
456                            return true;
457                        }
458                        return false;
459
460                    }.bind(this);
461
462                    this.settings.steps.onFinishing = function (e, currentStep)
463                    {
464                        // now handle the next step!
465                        var promise = this.formValidateCurrentStep();
466                        if (promise.responseJSON.success) {
467                            this.formSubmitSuccess(promise.responseJSON);
468                            this.formSubmitComplete(promise, 'success');
469                            return true;
470                        }
471                        return false;
472
473                    }.bind(this);
474
475                    var steps = this.formObj.steps(this.settings.steps);
476
477                    this.formObj.find('[data-formidable-step-buttons] [data-formidable-step-previous]').on('click', function() {
478                        steps.steps('previous');
479                    });
480                    this.formObj.find('[data-formidable-step-buttons] [data-formidable-step-next]').on('click', function() {
481                        if ($('section[data-formidable-step]:last').data('formidable-step') != $(this).closest('section[data-formidable-step]').data('formidable-step')) {
482                            return steps.steps('next');
483                        }
484                        steps.steps('finish');
485                    });
486                }
487            },
488
489            enableMasking: function()
490            {
491                // mask for "normal" fields
492                if ($.fn.mask) {
493                    $('[data-mask]').each(function(i, f)  {
494                        $(f).mask($(f).attr('data-mask'));
495                    });
496                }
497                // mask / placeholder for selectboxes
498                $('[data-placeholder]').each(function(i, f) {
499                    var attr = {disabled: true, hidden: true, selected: true};
500                    if ($(f).attr('multiple')) {
501                        attr = {disabled: true, selected: false};
502                    }
503                    $(f).find('option:first').prop(attr);
504                })
505            },
506
507            enableCounter: function()
508            {
509                $('[data-range-type]', formidable).each(function(i, f)  {
510                    var typ = $(f).attr('data-range-type');
511                    var min = parseFloat($(f).attr('data-range-min'));
512                    var max = parseFloat($(f).attr('data-range-max'));
513                    var range = '<div data-range><span data-count></span>/<span data-max>'+max+'</span></div>';
514                    $(f).wrapAll('<div data-formidable-countable>').after(range);
515                    var tag = $(f).tagName().toLowerCase();
516                    // for select, checkbox and radio...
517                    if ($.inArray(tag, ['select']) > -1 || $.inArray($(f).attr('type'), ['radio', 'checkbox']) > -1) {
518                        $(f).on('change', function() {
519                            var range = $(f).closest('[data-formidable-countable]').find('[data-count]');
520                            var checked = parseFloat($(":selected", $(f)).length);
521                            range.text(checked);
522                            $(f).find(':not(:selected)').prop('disabled', false);
523                            if (checked >= max) {
524                                $(f).find(':not(:selected)').prop('disabled', true);
525                            }
526                        }).trigger('change');
527                    }
528                    // for number field
529                    else if ($.inArray($(f).attr('type'), ['number']) > -1) {
530                        var range = $(f).closest('[data-formidable-countable]').find('[data-count]');
531                        range.text(min);
532                    }
533                    // for file field
534                    else if ($.inArray(typ, ['files']) > -1) {
535                        $('[data-additional-file]', $(f)).on('click', function() {
536                            $('.file.hide:first', $(f)).removeClass('hide');
537                            if ($('.file.hide', $(f)).length <= 0) {
538                                $('[data-additional-file]', $(f)).prop('disabled', true);
539                            }
540                        });
541                    }
542                    // for others
543                    else {
544                        if ($.fn.simplyCountable) {
545                            $(f).simplyCountable({counter: $('[data-count]', $(f).closest('[data-formidable-countable]')), countType: typ, maxCount: max});
546                        }
547                    }
548                });
549            },
550
551            enableRanges: function()
552            {
553                $('input[type="range"]', formidable).each(function(i, f) {
554                    var span = $('[data-range-value="'+$(this).attr('id')+'"]');
555                    span.html($(f).val());
556
557                    $(f).on('input', function() {
558                        span.html($(f).val());
559                    });
560                });
561            },
562
563            enableSignatures: function()
564            {
565                $('[data-signature-type]', formidable).each(function(i, f) {
566                    var container = $(f);
567                    var signature = $('div.signature', container);
568                    var textarea = $('textarea', container);
569
570                    var options = $.extend({
571                        'width': 'ratio',
572                        'height': 'ratio',
573                        'sizeRatio': 2, // only used when height = 'ratio',
574                        'color': '#000',
575                        'background-color': '#fff',
576                        'decor-color': '#eee',
577                        'lineWidth': 0,
578                        'minFatFingerCompensation': -10,
579                        'showUndoButton': false,
580                        'readOnly': false,
581                        'data': [],
582                        'signatureLine': false,
583                        'afterload': function() {}
584                    }, JSON.parse('{'+container.data('options').replace(/\'/g, '"')+'}'));
585
586                    var signature = signature.jSignature(options).on('change', function() {
587                        textarea.text("data:" + $(this).jSignature("getData", "svgbase64").join(",") );
588                    });
589
590                    // Add image if already there!
591                    // Disabled for now. It's not nice to edit a signature...
592                    // if (textarea.text().length > 0)	signature.jSignature("setData", textarea.text());
593
594                    $('[data-signature="clear"]', container).on('click', function (e) {
595                        if (!container.is(':disabled')) {
596                            signature.jSignature('reset');
597                            textarea.text('');
598                        }
599                    });
600                });
601            },
602
603            // enable dropzones
604            enableDropzones: function()
605            {
606                $('.formidable-dropzone', formidable).each(function(i, e) {
607                    $('div.dropzone-box', $(e)).formidableDropzone(this);
608                }.bind(this));
609            },
610
611            enableOthers: function()
612            {
613                $('[data-option-other]', formidable).each(function(i, f) {
614                    var element = $(f).find('[type="checkbox"], [type="radio"], select');
615                    element.on('change', function() {
616                        var value = element.val();
617                        if ($.inArray(element.attr('type'), ['radio', 'checkbox']) > -1) {
618                            value = [];
619                            $(f).find(':is(:checked)').each(function(i, e) {
620                                value.push($(e).val());
621                            });
622                        }
623                        var other = $(f).find('div.option-other');
624                        if ($.inArray('other_value', $.isArray(value)?value:[value]) > -1) {
625                            other.addClass('enabled').find(':input').prop({disabled: false});
626                        }
627                        else {
628                            other.removeClass('enabled').find(':input').val('').prop({disabled: true});
629                        }
630                    }).trigger('change');
631                })
632            },
633
634            // run dependencies
635            loadDependencies: function()
636            {
637                $.each(this.settings.dependencies.selectors, function(d, dependency) {
638                    $(dependency.selector, formidable).on('change keyup', function() {
639                        clearTimeout(timeout);
640                        timeout = setTimeout(formidable.checkDependencyRule(dependency.id), 200);
641                    }).trigger('change');
642                });
643            },
644
645            // reload dependencies
646            reloadDependencies: function()
647            {
648                this.settings.dependencies.reload = true;
649                $.each(this.settings.dependencies.selectors, function(d, dependency) {
650                    formidable.checkDependencyRule(dependency.id);
651                });
652                this.settings.dependencies.reload = false;
653            },
654
655            // resolve a dependency selector to the actual :input element(s),
656            // also when the handle is on a wrapper (e.g. checkbox/Accept elements)
657            getDependencyInput: function(handle)
658            {
659                var elements = $(handle, formidable);
660                var input = elements.filter(':input');
661                elements.not(':input').each(function(i, element) {
662                    input = input.add($(element).find(':input'));
663                });
664                return input;
665            },
666
667            checkDependencyRule: function(id)
668            {
669                for (let rs = 0; rs < this.settings.dependencies.rules.length; rs++) {
670
671                    var rules = this.settings.dependencies.rules[rs];
672
673                    // skip rules...
674                    if ($.inArray(rules.id, id) <= -1) {
675                        continue;
676                    }
677
678                    var selector = $(rules.selector, formidable);
679
680                    var inverse = false;
681
682                    // first go back to basics to it's "default" state.
683                    // example: if show is action, default is hidden.
684                    for (let r = 0; r < rules.rules.length; r++) {
685                        var rule = rules.rules[r];
686                        for (let a = 0; a < rule.actions.length; a++) {
687                            var action = rule.actions[a];
688                            if (this.settings.dependencies.reload && $.inArray(action[0], ['disable']) <= -1) {
689                                continue;
690                            }
691                            switch (action[0]) {
692                                case 'show':
693                                    selector.prop('disabled', true).closest('[data-formidable-handle]').hide();
694                                break;
695                                case 'hide':
696                                    selector.prop('disabled', false).closest('[data-formidable-handle]').show();
697                                    inverse = true;
698                                break;
699                                case 'disable':
700                                    selector.prop('disabled', false);
701                                break;
702                                case 'enable':
703                                    selector.prop('disabled', true);
704                                    inverse = true;
705                                break;
706                                case 'class':
707                                    formidable.removeElementClass(selector, action[1]);
708                                break;
709                                case 'value':
710                                    formidable.setElementValue(selector, '');
711                                break;
712                            }
713                        }
714                    }
715
716                    for (let r = 0; r < rules.rules.length; r++) {
717
718                        var rule = rules.rules[r];
719
720                        if (debug) console.log('---- RuleNo: '+r+' ----');
721                        if (debug) console.log('Selector: '+rules.selector);
722
723                        var match = true;
724
725                        for (let s = 0; s < rule.selectors.length; s++) {
726
727                            var line = rule.selectors[s];
728
729                            var input = formidable.getDependencyInput(line.handle);
730                            if (!input.length) {
731                                continue;
732                            }
733
734                            var type = input.eq(0).tagName();
735                            if (type == 'input') {
736                                type = input.eq(0).attr('type');
737                            }
738
739                            var value = [];
740                            switch (type) {
741                                case 'select':
742                                    input.each(function(i, field) {
743                                        var fieldValue = $(field).val();
744                                        if ($.isArray(fieldValue)) {
745                                            $.each(fieldValue, function(v, item) {
746                                                if (item) {
747                                                    value.push(String(item).toLowerCase());
748                                                }
749                                            });
750                                        }
751                                        else if (fieldValue) {
752                                            value.push(String(fieldValue).toLowerCase());
753                                        }
754                                    });
755                                break;
756                                case 'checkbox':
757                                case 'radio':
758                                    $.each(input.filter(':checked'), function(c, check) {
759                                        value[c] = String($(check).val()).toLowerCase();
760                                    });
761                                break;
762                                default:
763                                    if (input.eq(0).val()) {
764                                        value[0] = String(input.eq(0).val()).toLowerCase();
765                                    }
766                                break;
767                            }
768
769                            if (debug) console.log('Rule selector: '+line.handle);
770                            if (debug) console.log('Value: '+(value.length?value:'(empty)')+' ('+value.length+')');
771
772                            for (let c = 0; c < line.conditions.length; c++) {
773
774                                var cond = line.conditions[c];
775                                var compare_value = cond.value?cond.value.toLowerCase():'';
776
777                                if (debug) console.log('---- ConditionRuleNo: '+c+' ----');
778
779                                // change comparison to empty / not empty for any and non;
780                                if (compare_value == 'any') cond.comparison = 'not_empty';
781                                if (compare_value == 'non') cond.comparison = 'empty';
782
783                                if (debug) console.log('Condition: '+cond.c
783omparison);
784                                if (debug) console.log('Compare to: '+compare_value);
785
786                                switch (cond.comparison) {
787                                    case 'empty':
788                                        // not empty is false
789                                        if (value.length > 0) match = false;
790                                    break;
791                                    case 'not_empty':
792                                        // empty is false
793                                        if (value.length <= 0) match = false;
794                                    break;
795                                    case 'equals':
796                                        // not equals is false
797                                        if (compare_value == 'any' && value.length <= 0) match = false;
798                                        else if (compare_value == 'non' && value.length > 0) match = false;
799                                        else if ($.inArray(compare_value, value) <= -1) match = false;
800                                    break;
801                                    case 'not_equals':
802                                        // equals is false
803                                        if ($.inArray(compare_value, value) > -1) match = false;
804                                    break;
805                                    case 'contains':
806                                        // not contains is false
807                                        for (let i = 0; i < value.length; i++) {
808                                            if (value[i].search(compare_value) <= -1) {
809                                                match = false;
810                                                break;
811                                            }
812                                        }
813                                    break;
814                                    case 'not_contains':
815                                        // contains is false
816                                        for (let i = 0; i < value.length; i++) {
817                                            if (value[i].search(compare_value) >= -1) {
818                                                match = false;
819                                                break;
820                                            }
821                                        }
822                                    break;
823                                }
824                            }
825                        }
826
827                        if (debug) console.log('Match: '+(match?'yes':'no'));
828
829                        if (inverse) {
830                            if (debug) console.log('Inversed?: '+(inverse?'yes':'no'));
831                            match = !match;
832                        }
833
834                        if (!match) {
835                            continue;
836                        }
837
838                        for (let a = 0; a < rule.actions.length; a++) {
839                            var action = rule.actions[a];
840                            if (this.settings.dependencies.reload && $.inArray(action[0], ['disable']) <= -1) {
841                                continue;
842                            }
843                            if (debug) console.log('Action '+action[0]);
844                            switch (action[0]) {
845                                case 'show':
846                                    if (inverse) {
847                                        selector.prop('disabled', true).closest('[data-formidable-handle]').hide();
848                                        break;
849                                    }
850                                    selector.prop('disabled', false).closest('[data-formidable-handle]').show();
851                                break;
852                                case 'hide':
853                                    if (inverse) {
854                                        selector.prop('disabled', false).closest('[data-formidable-handle]').show();
855                                        break;
856                                    }
857                                    selector.prop('disabled', true).closest('[data-formidable-handle]').hide();
858                                break;
859                                case 'disable':
860                                    if (inverse) {
861                                        selector.prop('disabled', false);
862                                        break;
863                                    }
864                                    selector.prop('disabled', true);
865                                break;
866                                case 'enable':
867                                    if (inverse) {
868                                        selector.prop('disabled', true);
869                                        break;
870                                    }
871                                    selector.prop('disabled', false);
872                                break;
873                                case 'class':
874                                    formidable.addElementClass(selector, action[1]);
875                                    if (debug) console.log('Class: '+action[1]);
876                                break;
877                                case 'value':
878                                    formidable.setElementValue(selector, action[1]);
879                                    if (debug) console.log('Value: '+action[1]);
880                                break;
881                                case 'clear':
882                                    formidable.setElementValue(selector);
883                                break;
884                            }
885                        }
886                        if (debug) console.log('------------------');
887                    }
888                }
889            },
890
891            // set field value
892            setElementValue: function(selector, value)
893            {
894                var type = selector.tagName();
895                if (type == 'input') {
896                    type = selector.attr('type');
897                }
898                switch (type) {
899                    case 'select':
900                        selector.prop('selectedIndex', 0);
901                        if (value.length) {
902                            selector.val(value);
903                        }
904                    break;
905                    case 'checkbox':
906                    case 'radio':
907                        selector.prop('checked', false);
908                        if (value.length) {
909                            for (let i = 0; i < selector.length; i++) {
910                                var s = selector[i];
911                                $(s).prop('checked', false);
912                                if ($(s).val() == value) $(s).prop('checked', true);
913                            };
914                        }
915                    break;
916                    default:
917                        selector.val(value);
918                    break;
919                }
920                selector.trigger('change');
921            },
922
923            // add field class
924            addElementClass: function(selector, className, todo)
925            {
926                selector.addClass(className);
927            },
928
929            // remove field class
930            removeElementClass: function(selector, className, todo)
931            {
932                selector.removeClass(className);
933            },
934
935            // if form is validated
936            setFormValidated: function(step)
937            {
938                // Disabled for now because i don't want to use :valid or :invalid
939                // formidable.addClass('was-validated');
940                if (!!step) {
941                    $('[data-formidable-step="' + step + '"]', formidable).find(':input:not(.is-invalid):not(.no-valid)').addClass('is-valid');
942                    return;
943                }
944                $('[data-formidable-type]', formidable).find(':input:not(.is-invalid):not(.no-valid)').addClass('is-valid');
945            },
946
947            // start 'busy' process
948            startProcess: function()
949            {
950                formidable.addClass('processing').find(':input').attr('disabled', true);
951            },
952
953            // stop 'busy' process
954            stopProcess: function()
955            {
956                formidable.removeClass('processing').find(':input').attr('disabled', false);
957            },
958
959            setSendable: function(sendable)
960            {
961                this.sendable = sendable;
962            },
963
964            getSendable: function()
965            {
966                return this.sendable;
967            },
968
969            // hide form
970            hideForm: function()
971            {
972                if (!!this.settings.successHideForm) {
973                    this.formObj.remove();
974                }
975            },
976
977            resetForm: function()
978            {
979                $('[data-formidable-type]', formidable).find(':input').removeClass('is-valid no-valid is-invalid is-invalid');
980                $('div.invalid-feedback, div.valid-feedback', formidable).remove();
981
982                // reset signatures canvasses
983                $('[data-signature-type]', formidable).each(function(i, f) {
984                    $('div.signature', $(f)).jSignature('reset');
985                });
986
987                this.formObj.trigger('reset');
988            },
989
990            resetRecaptcha: function()
991            {
992                // reset recaptcha
993                if (typeof refresh_recaptcha !== "undefined") {
994                    refresh_recaptcha();
995                }
996            },
997
998            // callback called onload of the form
999            doCallbackOnload: function()
1000            {
1001                if (!!this.settings.onloadCallback && $.isFunction(this.settings.onloadCallback)) {
1002                    this.settings.onloadCallback.call(this, formidable);
1003                }
1004            },
1005
1006            // callback called when errors occure on submit
1007            doCallbackError: function(response)
1008            {
1009                if (this.settings.errorsCallback && $.isFunction(this.settings.errorsCallback)) {
1010                    this.settings.errorsCallback.call(this, this, response);
1011                }
1012            },
1013
1014            // callback called when form is successfully submitted
1015            doCallbackSuccess: function(response)
1016            {
1017                if (this.settings.successCallback && $.isFunction(this.settings.successCallback)) {
1018                    this.settings.successCallback.call(this, this, response);
1019                }
1020            },
1021
1022            doEnhancedConversion: function(response)
1023            {
1024                var data = response.responseJSON;
1025                if (data.enhanced_conversion) {
1026			        window.dataLayer = window.dataLayer || [];
1027                    dataLayer.push($.parseJSON(data.enhanced_conversion));
1028                }
1029            },
1030
1031            // reload token data in form
1032            resetToken: function(ccm_token)
1033            {
1034                $('[id="ccm_token"]', formidable).val(ccm_token);
1035            },
1036
1037            // move to top
1038            scrollToTop: function()
1039            {
1040                if (!!this.settings.scrollToTop) {
1041                    $('html, body').animate({
1042                        scrollTop: formidable.offset().top + this.settings.scrollOffset
1043                    }, this.settings.scrollTime);
1044                }
1045            },
1046
1047            // show message (notifications and errors) on top of form
1048            formMessage: function(message)
1049            {
1050                var type = 'error';
1051                if (!!message.type) {
1052                    type = message.type;
1053                }
1054                if (!!message.message) {
1055                    message = message.message;
1056                }
1057                if ($.isArray(message)) {
1058                    message = message.join('<br />');
1059                }
1060
1061                var holder = $('[data-formidable-message]', formidable);
1062                holder.attr('class', '').html(message);
1063                if (type == 'error') {
1064                    holder.addClass('alert alert-danger');
1065                    if (this.settings.errorsAdditionalClass) {
1066                        holder.addClass(this.settings.errorsAdditionalClass);
1067                    }
1068                }
1069                if (type == 'info') {
1070                    holder.addClass('alert alert-info');
1071                }
1072                if (type == 'success') {
1073                    holder.addClass('alert alert-success');
1074                    if (this.settings.successAdditionalClass) {
1075                        holder.addClass(this.settings.successAdditionalClass);
1076                    }
1077                }
1078                holder.show();
1079            },
1080
1081            // show message (erros) after the specific element
1082            elementMessage: function(handle, message)
1083            {
1084                var type = 'error';
1085                if (!!message.type) {
1086                    type = message.type;
1087                }
1088                if (!!message.message) {
1089                    message = message.message;
1090                }
1091                if ($.isArray(message)) {
1092                    message = message.join('<br />');
1093                }
1094
1095                var holder = $('[data-formidable-handle="'+handle+'"]', formidable);
1096                if (typeof handle === 'object') {
1097                    holder = handle;
1098                }
1099
1100                var elements = holder.find(':input:not(.no-valid)');
1101                if (type == 'error') {
1102                    elements.addClass('is-invalid');
1103                    if (this.settings.errorsAdditionalClass) {
1104                        elements.addClass(this.settings.errorsAdditionalClass);
1105                    }
1106                }
1107                else {
1108                    elements.addClass('is-valid');
1109                    if (this.settings.successAdditionalClass) {
1110                        elements.addClass(this.settings.successAdditionalClass);
1111                    }
1112                }
1113
1114                // show message with element
1115                if (this.settings.errors == 'element') {
1116                    if (message.length > 0) {
1117                        var msg = $('<div>');
1118                        msg.html(message);
1119                        if (type == 'error') {
1120                            msg.addClass('invalid-feedback');
1121                            if (this.settings.errorsAdditionalClass) {
1122                                msg.addClass(this.settings.errorsAdditionalClass);
1123                            }
1124                        }
1125                        else {
1126                            msg.addClass('valid-feedback');
1127                            if (this.settings.successAdditionalClass) {
1128                                msg.addClass(this.settings.successAdditionalClass);
1129                            }
1130                        }
1131                        holder.append(msg);
1132                    }
1133                }
1134            },
1135
1136            getFormObject: function()
1137            {
1138                return this.formObj;
1139            },
1140
1141            addDropzoneUpload: function()
1142            {
1143                dropzone++;
1144                this.startProcess();
1145            },
1146
1147            removeDropzoneUpload: function()
1148            {
1149                dropzone--;
1150                if (dropzone <= 0) {
1151                    this.stopProcess();
1152                }
1153            }
1154
1155        });
1156
1157        formidable.init();
1158
1159        return formidable;
1160    };
1161
1162
1163    $.fn.formidableDropzone = function (formidable) {
1164
1165        var dropzone = this;
1166
1167        $.extend(dropzone, {
1168
1169            settings: $.extend({
1170
1171                // set max uploaded files
1172                maxFiles: 10,
1173
1174                // set accepted extensions
1175                acceptedFiles: '.jpg,.jpeg,.png,.doc,.docx,.xls,.xlsx,.pdf',
1176
1177                // set max uploaded filesize
1178                maxFilesize: 5 // MB
1179
1180            }),
1181
1182            formidable: formidable,
1183            dropzoneObj: null,
1184
1185            init: function()
1186            {
1187                this.dropzoneDiv = $(this);
1188                this.formObj = this.formidable.getFormObject();
1189
1190                this.settings.action = this.formObj.attr('action');;
1191
1192                if (this.dropzoneDiv.data('range-max')) {
1193                    this.settings.maxFiles = this.dropzoneDiv.data('range-max');
1194                }
1195                if (this.dropzoneDiv.data('extensions')) {
1196                    this.settings.acceptedFiles = this.dropzoneDiv.data('extensions');
1197                }
1198                if (this.dropzoneDiv.data('filesize')) {
1199                   this.settings.maxFilesize = this.dropzoneDiv.data('filesize');
1200                }
1201
1202                // do callback
1203                this.doDropzone();
1204            },
1205
1206            doDropzone: function()
1207            {
1208                this.dropzoneDiv.dropzone({
1209                    url: this.settings.action.replace(/submit/, 'upload'),
1210                    maxFiles: this.settings.maxFiles,
1211                    acceptedFiles: this.settings.acceptedFiles,
1212                    maxFilesize: this.settings.maxFilesize,
1213                    createImageThumbnails: true,
1214                    autoProcessQueue: true,
1215                    uploadMultiple: false,
1216                    addRemoveLinks: false,
1217                    previewTemplate: this.dropzoneDiv.next('[id^="dropzoneTemplate"]').html(),
1218                    init: this.initialize.bind(this),
1219                    sending: this.sending.bind(this),
1220                    addedfiles: this.add.bind(this),
1221                    removedfile: this.removeFile.bind(this),
1222                    processing: this.processing.bind(this),
1223                    error: this.error.bind(this),
1224                    success: this.success.bind(this),
1225                    complete: this.complete.bind(this)
1226                });
1227                this.dropzoneObj = this.dropzoneDiv.get(0).dropzone;
1228
1229                this.mocks();
1230            },
1231
1232            initialize: function()
1233            {
1234
1235            },
1236
1237            sending: function(file, json, formData)
1238            {
1239                formData.append('formID', $('[id="formID"]', this.formidable.getFormObject()).val());
1240                formData.append('bID', $('[id="bID"]', this.formidable.getFormObject()).val());
1241                formData.append('ccm_token', $('[id="ccm_token"]', this.formidable.getFormObject()).val());
1242                formData.append('handle', this.dropzoneDiv.data('element-handle'));
1243            },
1244
1245            add: function(file)
1246            {
1247                this.removeErrors();
1248            },
1249
1250            processing: function(file)
1251            {
1252                this.formidable.addDropzoneUpload();
1253                this.removeErrors();
1254            },
1255
1256            error:  function(file, message)
1257            {
1258                this.formidable.stopProcess();
1259                this.dropzoneObj.removeFile(file);
1260                this.formidable.elementMessage(this.dropzoneDiv.parent(), message);
1261            },
1262
1263            removeFile: function(file)
1264            {
1265                var response = false;
1266
1267                if (file.xhr && file.xhr.responseText.length > 0) {
1268                    response = $.parseJSON(file.xhr.responseText);
1269			    }
1270
1271                if (!!response) {
1272
1273                    this.doRemoveFile(response.file);
1274                }
1275
1276                // do native dropzone remove
1277                file.previewElement.remove();
1278
1279                if ($('.dropzone-item', this.dropzoneDiv).length <= 0) {
1280                    this.dropzoneDiv.removeClass('dz-started');
1281                }
1282            },
1283
1284            doRemoveFile: function(file)
1285            {
1286                var formData = new FormData();
1287
1288                formData.append('formID', $('[id="formID"]', this.formidable.getFormObject()).val());
1289                formData.append('bID', $('[id="bID"]', this.formidable.getFormObject()).val());
1290                formData.append('ccm_token', $('[id="ccm_token"]', this.formidable.getFormObject()).val());
1291                formData.append('handle', this.dropzoneDiv.data('element-handle'));
1292                formData.append('file', file);
1293
1294                $.ajax({
1295                    url: this.settings.action.replace(/submit/, 'delete'),
1296                    data: formData,
1297                    method: 'post',
1298                    dataType: 'json',
1299
1300                    // when using formdata
1301                    contentType: false,
1302                    processData: false,
1303                    cache: false,
1304
1305                    error: this.removeFileError.bind(this),
1306                    success: this.removeFileComplete.bind(this)
1307                });
1308            },
1309
1310            removeFileComplete: function(response)
1311            {
1312                $('[type="hidden"][value="'+response.file+'"]', this.dropzoneDiv).remove();
1313            },
1314
1315            removeFileError: function(response)
1316            {
1317                var data = response.responseJSON;
1318
1319                if (data.errors) {
1320                    // set all errors
1321                    if (this.settings.errors == 'form') {
1322                        var errors = [];
1323                        $.each(data.errors, function(handle, err) {
1324                            if ($.isArray(err)) {
1325                                err = err.join('<br />');
1326                            }
1327                            errors.push(err);
1328                        });
1329                        this.formidable.formMessage({type: 'error', message: errors});
1330                    }
1331                    else {
1332                        $.each(data.errors, function(handle, message) {
1333                            this.formidable.elementMessage(this.dropzoneDiv.parent(), message);
1334                        }.bind(this));
1335                    }
1336                }
1337            },
1338
1339            removeErrors: function()
1340            {
1341                $('.invalid-feedback:not(:last-child)', this.dropzoneDiv.parent()).remove();
1342            },
1343
1344            removeAllErrors: function()
1345            {
1346                $('.invalid-feedback', this.dropzoneDiv.parent()).remove();
1347            },
1348
1349            removeNonExistingThumbnail: function()
1350            {
1351                $('[data-dz-thumbnail]', this.dropzoneDiv).each(function(i, row) {
1352                    if (!$(row).attr('href') || $(row).attr('href').length <= 0) {
1353                        $(row).parent().remove();
1354                    }
1355                });
1356            },
1357
1358            success: function(file, json)
1359            {
1360                this.removeNonExistingThumbnail();
1361
1362                /* append to object */
1363                var input = $('<input>').attr({
1364                    'type': 'hidden',
1365                    'name': this.dropzoneDiv.data('element-handle')+'[]',
1366                    'value': json.file
1367                });
1368                $('.dropzone-item:last-child', this.dropzoneDiv).prepend(input);
1369            },
1370
1371            complete: function(file)
1372            {
1373                this.formidable.removeDropzoneUpload();
1374            },
1375
1376            mocks: function()
1377            {
1378                var files = this.dropzoneDiv.data('files') || [];
1379                $.each(files, function(i, file) {
1380
1381                    var mock = {
1382                        name: file.name,
1383                        size: file.size,
1384                        accepted: true,
1385                        status: Dropzone.ADDED,
1386                    }
1387                    this.dropzoneObj.files.push(mock);
1388                    // resizeThumbnail = false (5th arg) so Dropzone does not build/load a preview image
1389                    this.dropzoneObj.displayExistingFile(mock, null, null, null, false);
1390
1391                    this.removeNonExistingThumbnail();
1392
1393                    var input = $('<input>').attr({
1394                        'type': 'hidden',
1395                        'name': this.dropzoneDiv.data('element-handle')+'[]',
1396                        'value': mock.name
1397                    });
1398
1399                    $('.dropzone-item:last-child', this.dropzoneDiv).prepend(input);
1400                    $('.dropzone-item:last-child', this.dropzoneDiv).find('[data-dz-remove]').on('click', function() {
1401                        this.doRemoveFile(mock.name);
1402                    }.bind(this));
1403
1404                }.bind(this));
1405            }
1406
1407        });
1408
1409        dropzone.init();
1410
1411        return dropzone;
1412    };
1413
1414}(jQuery));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.