PageSourceSearch

https://instituto-camoes.pt/media/com_visforms/js/visforms.js?e2ebdd

js instituto-camoes.pt collected 2026-10-01 10:27:48 UTC 79,709 bytes, 1,454 lines download raw bytes

1(function($) {
2    $.extend($.fn, {
3        // public plugin functions
4        displayChanger : function (options) {
5            // Attach onchange event handler to displayChanger Element
6            $(".displayChanger").on('change', function (e) {
7                $(".conditional").trigger("checkConditionalState");
8            });
9        },
10        // perform the code which is necessary to toggle the display state of one form element
11        toggleDisplay : function (options) {
12            const defaults = {
13                // just an example of adding translated texts, stepAlert is not used
14                texts: {
15                    stepAlert: "Es wurde ein bedingtes Feld in einem anderen Schritt aktiviert. Eventuell funktioniert das Formular nicht mehr."
16                }
17            };
18            const settings = jQuery.extend(true, {}, defaults, options);
19            const data = options.restricts;
20            const userinputs = $.data($(this).closest("form").get(0), 'userinputs');
21            if ((!userinputs) || typeof userinputs === "undefined") {
22                return;
23            }
24            // el is a div class="conditional"
25            const el = $(this);
26            // data is a list of all conditional fields
27            // index is id of field
28            // value is a comma separated string of all field IDs and values the command the conditional field to be visible
29            $.each(data, function (index, value) {
30                // a conditional field may have different other fields that make it visible
31                // we will not hide it, when at least one condition is true
32                let hide = true;
33                // find the right set of conditions for the div conditional that is actually processed
34                let elId;
35                if (el.hasClass(index)) {
36                    if (elId = el.attr('class').match(index)) {
37                        // split the condition string
38                        const showWhens = value.split(', ');
39                        $.each(showWhens, function (i, v) {
40                            // split the condition into a field id and a value that, if selected , will command the field to be visible
41                            const showWhen = v.split('__');
42                            if (showWhen.length >= 2) {
43                                const fieldId = showWhen[0];
44                                const conditionalValue = showWhen[1];
45                                // Restrictor elements that determine whether field is shown or hidden
46                                // we first look if we have a single control with a matching ID
47                                let restrictors = $('#' + fieldId);
48                                // if not, we deal with a radio or a multi checkbox. Id's are there followed by _n
49                                if (restrictors.length < 1) {
50                                    restrictors = $("[id^='" + fieldId + "_']");
51                                }
52                                // rel is restrictor element
53                                // check if we have a value in a restrictor element that will command field to be shown
54                                $.each(restrictors, function (ri, rel) {
55                                    // only use values of elements that are enabled
56                                    if ($(rel).is(':enabled')) {
57                                        const tagname = rel.tagName.toLowerCase();
58                                        switch (tagname) {
59                                            case "input" :
60                                                // selected values have checked=checked set
61                                                if ($(rel).is(':checked')) {
62                                                    if ($(rel).val() == conditionalValue) {
63                                                        hide = false;
64                                                        return hide;
65                                                    }
66                                                }
67                                                break;
68                                            case "select" :
69                                                const vals = $(rel).find(':selected');
70                                                $.each(vals, function (valindex, selectedValue) {
71                                                    if ($(selectedValue).val() == conditionalValue) {
72                                                        hide = false;
73                                                    }
74                                                    return hide;
75                                                });
76                                                break;
77                                            default :
78                                                break;
79                                        }
80                                    }
81                                    return hide;
82                                });
83
84                                return hide;
85                            }
86                        })
87                    }
88
89                    // controls of element to be shown or hidden
90                    // we first look for a control with matching id
91                    // _code is field for email verification code
92                    let controls = $("#" + index + ", #" + index + "_code");
93                    // if not, we deal with a radio or a multi checkbox. Id's are there followed by _n. Or a location Id' are followed by _lat and _lng
94                    if (controls.length < 1) {
95                        // data-disabled: Unique values validation: Use to mark options, which are already used up
96                        controls = el.find("[id^='" + index + "_']:not([data-disabled])");
97                    }
98                    let ctagname = '';
99                    if (controls.get(0)) {
100                        ctagname = controls.get(0).tagName.toLowerCase();
101                    }
102                    if (hide === false) {
103                        if ($(controls).is(':disabled') || ((ctagname == 'hr') && $(controls).hasClass('ignore'))) {
104                            // enable controls, remove class ignore and disabled, show div conditional
105                            showControls(controls, settings);
106                            // check if control is displayChanger
107                            if (controls.hasClass('displayChanger')) {
108                                // check if depending fields must be displayed too
109                                toggleChild(data, index);
110                            }
111                            // use custom event; #index does not exist, if field is radio or multicheckbox, which is ok, because the cannot be used in calculations
112                            $('#' + index).trigger('recalculate');
113                            return false;
114                        }
115                    } else {
116                        // data-disabled: Unique values validation: Use to mark options, which are already used up
117                        if (($(controls).is(':enabled') || (($(controls).is(':disabled')) && ($(controls).attr('data-disabled') != undefined))) || ((ctagname == 'hr') && $(controls).hasClass('ignore') == false)) {
118                            // disable controls, set class ignore, hide div conditional
119                            hideControls(controls);
120                            // check if control is displayChanger
121                            if (controls.hasClass('displayChanger')) {
122                                // check if depending fields must be hidden too
123                                toggleChild(data, index);
124                            }
125                            // use custom event; #index does not exist, if field is radio or multicheckbox, which is ok, because the cannot be used in calculations
126                            $('#' + index).trigger('recalculate');
127                            return false;
128                        }
129                    }
130                }
131            });
132            
133            // additional protected class variables can be declared here.
134            
135            // protected helper functions for toggleDisplay
136            
137            /**
138             * Methode to enable controls, remove class ignore and disabled, show div conditional
139             * @param {jQuery selection} controls
140             * @returns {Boolean}
141             */
142            function showControls (controls, settings) {
143                if (controls.length < 1) {
144                    // no controls found, do nothing
145                    return false;
146                }
147                $.each(controls, function (cindex, control) {
148                    let elid;
149                    // only enable multicheckbox option that have no data-disabled attribute
150                    // data-disabled: Unique values validation: Use to mark options, which are already used up
151                    // for some like disabled adding or removing the content attribute disabled="disabled" always toggles the js property
152                    // so using removeAttr('disabled'); is completely okay!
153                    if ($(control).attr('data-disabled') == undefined) {
154                        $(control).removeAttr('disabled');
155                        $(control).removeClass('ignore');
156                        elid = $(control).get(0).id;
157                    }
158                    // no radio or checkbox group
159                    if (cindex === 0) {
160                        $.each(userinputs, function (i, obj) {
161                            // set to user input values
162                            switch (obj.type) {
163                                case "select":
164                                case "selectsql":
165                                    if (obj.label === elid) {
166                                        if ($.isPlainObject(obj.value)) {
167                                            const seloptions = $(control).find('option');
168                                            $.each(seloptions, function (i, el) {
169                                                $.each(obj.value, function (i, val) {
170                                                    if ($(el).attr('value') === val) {
171                                                        $(el).prop('selected', true);
172                                                        // you have to return false to break from an each loop
173                                                        return false;
174                                                    }
175                                                    $(el).prop('selected', false);
176                                                    return;
177                                                });
178                                            });
179                                        }
180                                    }
181                                    break;
182                                case "multicheckbox":
183                                case "multicheckboxsql":
184                                    // control is a single input. It's id (elid) has a additional counter _1....)
185                                    // we cannot use the control to set a checked property of each inputs but have to go one level up and then find each input element and set the property
186                                    if ($(control).parents("div.conditional").hasClass(obj.label)) {
187                                        if ($.isPlainObject(obj.value)) {
188                                            const boxes = $(control).parents("div.conditional").find('input');
189                                            $.each(boxes, function (i, el) {
190                                                $.each(obj.value, function (ix, val) {
191                                                    if ($(el).attr('value') === val) {
192                                                        $(el).prop('checked', true);
193                                                        // you have to return false to break from an each loop
194                                                        return false;
195                                                    }
196                                                    $(el).prop('checked', false);
197                                                    return;
198                                                });
199                                            });
200                                        }
201                                    }
202                                    break;
203                                case "radio":
204                                case "radiosql":
205                                    // control is a single input. It's id (elid) has a additional counter _1....)
206                                    // we cannot use the control to set a checked property of each inputs but have to go one level up and then find each input element and set the property
207                                    if ($(control).parents("div.conditional").hasClass(obj.label)) {
208                                        const radios = $(control).parents("div.conditional").find('input');
209                                        $.each(radios, function (i, el) {
210                                            if ($(el).attr('value') === obj.value) {
211                                                $(el).prop('checked', true);
212                                            }
213                                            else {
214                                                $(el).prop('checked', false);
215                                            }
216                                        });
217                                    }
218                                    break;
219                                case "checkbox":
220                                    if (obj.label === elid) {
221                                        $("#" + obj.label).prop("checked", obj.value);
222                                        return;
223                                    }
224                                    break;
225                                case "signature" :
226                                    // value in text-input was already reset to defaultValue in hideControls
227                                    // the canvas content is only replaced when the field is displayed again (showControls)
228                                    if (obj.label === elid){
229                                        let canvasContainer = document.getElementById(obj.label + "_sig");
230                                        const {api} = canvasContainer.dataset;
231                                        // jSignature
232                                        if (!api) {
233                                            $("#" + obj.label).val(obj.value);
234                                            if (obj.value === "") {
235                                                $("#" + obj.label + "_sig").jSignature("reset");
236                                            }
237                                            else {
238                                                $("#" + obj.label + "_sig").jSignature("setData", "data:" + obj.value);
239                                            }
240                                        }
241                                        // signaturePad
242                                        else if (api === "1") {
243                                            // create custom event and trigger it on the canvas element
244                                            let canvas = document.querySelector("#" + obj.label + "_sig canvas")
245                                            const event =  new CustomEvent('replaceCanvasImage', {bubbles: true, detail : obj.value});
246                                            canvas.dispatchEvent(event);
247                                        }
248                                    }
249                                    break;
250                                default:
251                                    if (obj.label === elid) {
252                                        // used to prevent email cloaking in form used in content (plg or module)
253                                        $("#" + obj.label).val(obj.value.replace(/&#64/g, '@'));
254                                        return ;
255                                    }
256                                    break;
257                            }
258                        });
259                        if ($(control).is('[readonly]') == false) {
260                            $(control).parents("div.conditional").find("button").removeClass('vishidden');
261                        }
262                        $(control).parents("div.conditional").removeClass('vishidden');
263                        // fix bug in google maps: Map in hidden field not displayed properly.
264                        $(control).parents("div.conditional").trigger('reloadVfMap');
265                    }
266                });
267            }
268            
269            /**
270             * Methode to disable controls, set class ignore, hide div conditional
271             * @param {jquery selection} controls
272             * @returns {Boolean}
273             */
274            function hideControls (controls) {
275                if (controls.length < 1) {
276                    // no controls found, do nothing
277                    return false;
278                }
279                $.each(controls, function (cindex, control) {
280                    $(control).attr('disabled', 'disabled');
281                    $(control).addClass('ignore');
282                    const isCal = $(control).hasClass('isCal');
283                    const isLocation = $(control).hasClass('locationinput');
284                    const isSearchSelect = $(control).hasClass('select2-hidden-accessible');
285                    // do not empty location field value and cal field value
286                    if (!(isCal === true) && !(isLocation === true)) {
287                        $(control).val(function () {
288                            return this.defaultValue;
289                        });
290                    }
291                    $(control).prop('checked', function() {
292                        return this.defaultChecked;
293                    });
294                    const elid = $(control).get(0).id;
295                    $('#' + elid + ' option').prop('selected', function() {
296                        return this.defaultSelected;
297                    });
298                    if (isSearchSelect) {
299                        const seloptions = $(control).find('option');
300                        $.each(seloptions, function (i, el) {
301                            if ($(el).prop('selected') === true) {
302                                $('#select2-' + elid + '-container').html($(el).html());
303                                return false;
304                            }
305                        });
306                    }
307                    // no radio or checkbox group
308                    if (cindex === 0) {
309                        // if it is a file upload field we reset the delete file checkbox to unchecked
310                        $(control).parents("div.conditional").addClass('vishidden');
311                        $(control).parents("div.conditional").find(".deleteFile").prop("checked", false);
312                    }
313                });
314            }
315            
316            /**
317             * Basically we use the data object to find all conditional fields, who's display state depends on the state of the control with the id, given as param.
318             * We then find the parent html element with class=conditional for each conditional field and trigger the checkConditionalState event on it
319             * The toggleDisplay function is then performed once again for the conditional field
320             * @param {string} restricts list of all conditionla fields and the field__values that trigger there display
321             * @param {string} id id/class name of parent control
322             * @returns {undefined}
323             */
324            function toggleChild (restricts, id) {
325                $.each(restricts, function (index, list) {
326                    // split the restriction string
327                    const showWhens = list.split(', ');
328                    $.each(showWhens, function (i, v) {
329                        // split the restriction into a field id and a value that, if selected , will command the field to be visible
330                        const showWhen = v.split('__');
331                        if (showWhen.length >= 2) {
332                            // we have a depending child
333                            if (showWhen[0] == id) {
334                                // find parent element with class=conditional
335                                const conditional = $('.' + index);
336                                // check the child
337                                conditional.trigger('checkConditionalState');
338                            }
339                        }
340                    });
341                });
342            }
343        }
344    });
345}(jQuery));
346
347// mend missing placeholder support in some browsers
348(function ($) {
349    $.support.placeholder = ('placeholder' in document.createElement('input'));
350})(jQuery);
351
352const visForm = {
353    version : '5.4.0',
354    // used for both
355    // reload option list (listbox)
356    // reload field value (input)
357    reloadOptionList : function (event) {
358        event.preventDefault();
359        const formElement = jQuery(this).closest('form');
360        const fid = jQuery(formElement).attr('id');
361        const data = event.data;
362        const formData = jQuery(formElement).serializeArray();
363        const reloadId = data.reloadId;
364        const baseurl = data.baseurl;
365        const cid = data.cid;
366        const phpTask = data.task;
367        formData.push({name: 'reloadId', value: data.reloadId});
368        jQuery.ajax({
369            type: 'POST',
370            url: baseurl + '/index.php?option=com_visforms&task=visforms.'+phpTask+'&id=' + fid + '&cid=' + cid,
371            data: formData,
372            success: function(data, textStatus, jqXHR) {
373                let elId = '#' + fid + ' #field' + reloadId;
374                if (phpTask === 'reloadOptionList') {
375                    jQuery(elId).empty().append(data);
376                    // set any possible default values given by user inputs (edit value or url parameter) in reloaded options
377                    visForm.setDefaultValues(fid, reloadId);
378                    // perform preSelection of a solitary option if set in field configuration
379                    visForm.preSelectSolitaryOption(reloadId);
380                    jQuery(elId).trigger('change');
381                    visForm.hideSqlOptionList(fid);
382                    visForm.hideSqlDataList(fid);
383                }
384                else if (phpTask === 'reloadValue') {
385                    // Set value in reloaded field
386                    jQuery(elId).val(data.replace(/&#64/g, '@'));
387                    // Fieldtype date needs special treatment
388                    // all Calender fields are accessible through JoomlaCalendar.getCalObject(element)._joomlaCalendar;
389                    // where element is the HTML Input field
390                    // the _joomlaCalendar is attached to the parent ('.field-calender') element and can be called directly
391                    // if there is no _joomlaCalendar for a field, this getCalObject() returns false
392                    // change the data-alt-value
393                    // call checkInputs() on the _joomlaCalendar to properly set the value in a date field
394                    if (jQuery(elId)[0].hasAttribute('data-alt-value')) {
395                        jQuery(elId).attr('data-alt-value', data.replace(/&#64/g, '@'));
396                        let calObj = JoomlaCalendar.getCalObject(jQuery(elId)[0]);
397                        if (calObj) {
398                            let calendar = calObj._joomlaCalendar;
399                            calendar.checkInputs();
400                        }
401                    }
402                    jQuery(elId).trigger("recalculate");
403                    jQuery(elId).trigger('change');
404                }
405            },
406            error: function(jqXHR, textStatus, errorThrown) {
407                // give error feedback
408                visForm.showAjaxError(jqXHR.responseText, errorThrown);
409            },
410            dataType: 'html',
411            async: true
412        });
413    },
414    setDefaultValues : function (formId, fieldId) {
415        const userinputs = jQuery.data(jQuery("#" + formId).get(0), 'userinputs');
416        if ((!userinputs) || typeof userinputs === "undefined") {
417            return;
418        }
419        jQuery.each(userinputs, function (i, obj) {
420            if (obj.label !== "field" + fieldId) {
421                return;
422            }
423            if (obj.value === "undefined") {
424                return;
425            }
426            if (obj.isDisabled === true && obj.isForbidden !== true) {
427                // these fields stay with there configuration default
428                return;
429            }
430            if (jQuery.isPlainObject(obj.value)) {
431                const seloptions = jQuery("#" + obj.label).find('option');
432                jQuery.each(seloptions, function (i, el) {
433                    jQuery.each(obj.value, function (i, val) {
434                        if (jQuery(el).attr('value') === val) {
435                            jQuery(el).prop('selected', true);
436                            // you have to return false to break from an each loop
437                            return false;
438                        }
439                        jQuery(el).prop('selected', false);
440                        return;
441                    });
442                });
443            }
444            return false;
445        });
446    },
447    preSelectSolitaryOption : function (fieldId) {
448        const field = jQuery('#field' + fieldId);
449        if (field.hasClass('preSelectedSolitaryOption')) {
450            let options = field.find('option');
451            let optionsCount = options.length;
452            if (optionsCount === 1 && jQuery(options[0]).prop('disabled') === false) {
453                jQuery(options[0]).prop('selected', true);
454            }
455            else if (optionsCount === 2) {
456                if (options[0].value === '' && jQuery(options[1]).prop('disabled') === false) {
457                    jQuery(options[0]).prop('selected', false);
458                    jQuery(options[1]).prop('selected', true);
459                }
460            }
461        }
462    },
463    hideSqlOptionList : function (formId) {
464        let hideEmpty = 1, hidePrselect = 2, hideBoth = 3, state = 0;
465        jQuery('#' + formId + ' select.hideOnEmptyOptionList, #' + formId + ' select.hideOnPreSelectedSolitaryOption').each(function() {
466            // Do not hide field with php Errors
467            if (jQuery(this).hasClass('error')) {
468                return true;
469            }
470            let fieldId = jQuery(this).attr('id');
471            let controlGroup = jQuery(this).parents('.' + fieldId);
472            let optionsCount = jQuery(this).find('option').length;
473            if (jQuery(this).hasClass('hideOnEmptyOptionList') && jQuery(this).hasClass('hideOnPreSelectedSolitaryOption')) {
474                state = hideBoth;
475            }
476            else if (jQuery(this).hasClass('hideOnEmptyOptionList')) {
477                state = hideEmpty;
478            }
479            else if (jQuery(this).hasClass('hideOnPreSelectedSolitaryOption')) {
480                state = hidePrselect;
481            }
482            if (optionsCount === 0) {
483                // hide if not option is given and hideEmpty is set
484                if (state === hideEmpty) {
485                    jQuery(controlGroup).addClass('vishidden');
486                }
487                else {
488                    jQuery(controlGroup).removeClass('vishidden');
489                }
490            }
491            else if (optionsCount === 1) {
492                // if only one option is given and it's value is '' this is the 'select a value' default option
493                if (this.options[0].value === '') {
494                    if (state === hideEmpty || state === hideBoth) {
495                        jQuery(controlGroup).addClass('vishidden');
496                    }
497                    else {
498                        jQuery(controlGroup).removeClass('vishidden');
499                    }
500                }
501                // if only one option is given and it's value is not '' it is a real option (happens, if for example if size attribute is set)
502                else {
503                    if (this.selectedIndex === 0 && (state === hideBoth || state === hidePrselect)) {
504                        jQuery(controlGroup).addClass('vishidden');
505                    }
506                    else {
507                        jQuery(controlGroup).removeClass('vishidden');
508                    }
509                }
510            }
511            // select an option plus one real option
512            else if (optionsCount === 2) {
513                if (this.selectedIndex === 1 && (state === hideBoth || state === hidePrselect)) {
514                    jQuery(controlGroup).addClass('vishidden');
515                }
516                else {
517                    jQuery(controlGroup).removeClass('vishidden');
518                }
519            }
520            else {
521                jQuery(controlGroup).removeClass('vishidden');
522            }
523        });
524    },
525    hideSqlDataList : function (formId) {
526        const hideEmpty = 1;
527        let state = 0;
528        jQuery('#' + formId + ' table.hideOnEmptyOptionList, #' + formId).each(function() {
529            const fieldId = jQuery(this).attr('id');
530            const controlGroup = jQuery(this).parents('.' + fieldId);
531            const rowCount = jQuery(this).find('tr').length;
532            if (jQuery(this).hasClass('hideOnEmptyOptionList')) {
533                state = hideEmpty;
534            }
535            if (rowCount === 0) {
536                // hide if not option is given and hideEmpty is set
537                if (state === hideEmpty) {
538                    jQuery(controlGroup).addClass('vishidden');
539                }
540                else {
541                    jQuery(controlGroup).removeClass('vishidden');
542                }
543            }
544            else {
545                jQuery(controlGroup).removeClass('vishidden');
546            }
547        });
548    },
549    showAjaxError : function (responseText, errorThrown) {
550        if (responseText === undefined || responseText === null) {
551            return;
552        }
553        if (responseText.startsWith('<!DOC')) {
554            alert(errorThrown);
555        }
556        else {
557            alert(responseText);
558        }
559    },
560    showProcessFormMsg : function (parentFormId) {
561        // show form processing message
562        // div _processform does only exist, if showformprocessmessage is enabled!
563        let div = jQuery("#"+parentFormId+"_processform");
564        if (div.length) {
565            jQuery("#vispoweredby").addClass('vishidden');
566            jQuery("#"+parentFormId).addClass('vishidden');
567            div.removeClass('vishidden');
568            this.focusjQueryElementTop(div);
569        }
570    },
571    // expects div to be a jQuery object of an HTML element
572    focusjQueryElementTop : function (div) {
573        let elOffset = div.offset().top;
574        let elHeight = div.height();
575        let windowHeight = jQuery(window).height();
576        let offset;
577        // focus div with form processing message in the middle of the view port
578        if (elHeight < windowHeight) {
579            offset = elOffset - ((windowHeight / 2) - (elHeight / 2));
580        }
581        else {
582            offset = elOffset;
583        }
584        let speed = 700;
585        jQuery('html, body').animate({scrollTop: offset}, speed);
586    },
587    onNextButtonClick: function (button) {
588        const visform = jQuery(button).closest('form');
589        const isValid = jQuery(visform).valid();
590        const isPending = jQuery(visform).validate().pendingRequest !== 0;
591        if (isPending) {
592            if (typeof validPendingTimeout !== "undefined") {
593                clearTimeout(validPendingTimeout);
594            }
595            validPendingTimeout = setTimeout(function () {
596                visForm.onNextButtonClick(button);
597            }, 200);
598        }
599        if (jQuery(visform).valid() && !isPending) {
600            let fieldset = jQuery(button).closest('[class^="fieldset-"]').next();
601            jQuery(button).closest('[class^="fieldset-"]').next().removeClass("vishidden").addClass("active");
602            jQuery(button).closest('[class^="fieldset-"]').next().trigger("reloadVfMap");
603            jQuery(button).closest('[class^="fieldset-"]').addClass("vishidden").removeClass("active");
604            // trigger after active was removed from current fieldset
605            jQuery(button).closest('[class^="fieldset-"]').next().trigger('setFocusOnClassChange',["
605next"]);
606            const activeBadge = jQuery(visform).find('.visprogress .badge.badge-important');
607            jQuery(activeBadge).removeClass("badge-important").addClass("badge-success");
608            jQuery(activeBadge).closest('.stepCont').next().find('.badge').addClass("badge-important");
609            // we have to remove class ignore from controls on next page, because the submit button could be on that page
610            // and we cannot remove class ignore when click event is on submit button (due to validator)
611            jQuery(button).closest('[class^="fieldset-"]').next().find('input, textarea, select').not(":disabled").removeClass("ignore");
612        }
613    },
614    onSummaryButtonClick: function (button) {
615        const formid = jQuery(button).closest("form").get(0).id;
616        const isValid = jQuery("#" + formid).valid();
617        const isPending = jQuery("#" + formid).validate().pendingRequest !== 0;
618        if (isPending) {
619            if (typeof validPendingTimeout !== "undefined") {
620                clearTimeout(validPendingTimeout);
621            }
622            validPendingTimeout = setTimeout(function () {
623                visForm.onSummaryButtonClick(button);
624            }, 200);
625        }
626        if (jQuery("#" + formid).valid() && !isPending) {
627            visForm.createSummaryHtml(formid);
628            jQuery(button).closest('[class^="fieldset-"]').next().removeClass("vishidden").addClass("active");
629            jQuery(button).closest('[class^="fieldset-"]').addClass("vishidden").removeClass("active");
630            // trigger after active was removed from current fieldset
631            jQuery(button).closest('[class^="fieldset-"]').next().trigger('setFocusOnClassChange',["next"]);
632            const activeBadge = jQuery('#' + formid + ' .visprogress .badge.badge-important');
633            jQuery(activeBadge).removeClass("badge-important").addClass("badge-success");
634            jQuery(activeBadge).closest('.stepCont').next().find('.badge').addClass("badge-important");
635            // force validation of captcha input on summary page
636            jQuery(button).closest('[class^="fieldset-"]').next().find('input').not(":disabled").removeClass("ignore");
637            // force validation of hCaptcha input on summary page
638            jQuery(button).closest('[class^="fieldset-"]').next().find('textarea').not(":disabled").removeClass("ignore");
639        }
640        // recaptcha must be reloaded in order to be checked for required properly
641        if (typeof grecaptcha !== "undefined") {
642            grecaptcha.reset();
643        }
644    },
645    createSummaryHtml : function(formid) {
646        let htmlsummary;
647        const visform = jQuery.data(jQuery("#" + formid).get(0), 'visform');
648        const fields = visform.fields;
649        const summary = [];
650        jQuery.each(fields, function (i, o) {
651            let tmp;
652            let selected;
653            let value;
654            if (jQuery.inArray(o.type, ['image', 'submit', 'reset', 'fieldsep', 'hidden', 'pagebreak']) > -1) {
655                return true;
656            }
657            const label = visform.oSummaryFirstElementLayout + '' + o.label + ': ' + visform.cSummaryFirstElementLayout;
658            switch (o.type) {
659                case "select":
660                case "selectsql":
661                    if (!jQuery("#" + formid + " #field" + o.id).prop("disabled")) {
662                        value = [];
663                        selected = jQuery("#" + formid + " .field" + o.id + " :selected");
664                        if (selected.length > 0) {
665                            selected.each(function () {
666                                if (jQuery(this).val() != "") {
667                                    value.push(jQuery(this).text());
668                                }
669                            });
670                        }
671                        tmp = value.join(", ");
672                        if ((!visform.hideemptyfieldsinsummary) || (tmp != "")) {
673                            summary.push(label + visform.oSummarySecondElementLayout + tmp + visform.cSummarySecondElementLayout);
674                        }
675                    }
676                    return;
677                case 'multicheckbox' :
678                case 'radio' :
679                case 'multicheckboxsql' :
680                case 'radiosql' :
681                    // Unique Values property sets used inputs to disabled and adds attribute data-disabled=disabled.
682                    // Therefore prop disabled cannot be used as only means to detect, whether a multicheckbox or radio is conditianal or simply disabled as because it is used
683                    // Search for a disabled input which does not have a data-disabled attribute
684                    const senabled = jQuery("#" + formid + " .field" + o.id + " :input:disabled:not([data-disabled])");
685                    if (!(senabled.length > 0)) {
686                        value = [];
687                        selected = (jQuery("#" + formid + " .field" + o.id + " :input:checked"));
688
689                        if (selected.length > 0) {
690                            selected.each(function (i) {
691                                sid = jQuery(this).attr("id");
692                                value.push(jQuery(this).closest(".field" + o.id).find("label[for=\'" + sid + "\']").text());
693                            });
694                        }
695                        tmp = value.join(", ");
696                        if ((!visform.hideemptyfieldsinsummary) || (tmp != "")) {
697                            summary.push(label + visform.oSummarySecondElementLayout + tmp + visform.cSummarySecondElementLayout);
698                        }
699                    }
700                    return;
701                case 'checkbox' :
702                    if (!jQuery("#" + formid + " #field" + o.id).prop("disabled")) {
703                        value = "";
704                        if ((jQuery("#" + formid + " #field" + o.id).prop("checked"))) {
705                            value = jQuery("#" + formid + " #field" + o.id).val();
706
707                        }
708                        if ((!visform.hideemptyfieldsinsummary) || (value != "")) {
709                            summary.push(label + visform.oSummarySecondElementLayout + value + visform.cSummarySecondElementLayout);
710                        }
711                    }
712                    return;
713                case 'calculation' :
714                    if (!jQuery("#" + formid + " #field" + o.id).prop("disabled")) {
715                        value = jQuery("#" + formid + " #field" + o.id).val();
716                        if ((!visform.hideemptyfieldsinsummary) || (value != "")) {
717                            if ((!visform.summaryemptycaliszero) || (!(0 == value.replace(",", ".")))) {
718                                summary.push(label + visform.oSummarySecondElementLayout + value + visform.cSummarySecondElementLayout);
719                            }
720                        }
721                    }
722                    return;
723                case 'location' :
724                    const lat = jQuery("#" + formid + " #field" + o.id + "_lat");
725                    const lng = jQuery("#" + formid + " #field" + o.id + "_lng");
726                    if (!lat.prop("disabled") && !lng.prop("disabled")) {
727                        const value_lat = lat.val();
728                        const value_lng = lng.val();
729                        if ((!visform.hideemptyfieldsinsummary) || ((value_lat != "") && (value_lng != ""))) {
730                            value = ((value_lat != "") && (value_lng != "")) ? value_lat + ", " + value_lng: "";
731                            summary.push(label + visform.oSummarySecondElementLayout + value + visform.cSummarySecondElementLayout);
732                        }
733                    }
734                    return;
735                case 'signature' :
736                    if (!jQuery("#" + formid + " #field" + o.id).prop("disabled") && !jQuery("#" + formid + " #field" + o.id).hasClass('noSummary')) {
737                        const imgData = visForm.getVfSignatureImgFromCanvas({sigFieldId: "#" + formid + " #field" + o.id + "_sig", formid: formid});
738                        if ((!visform.hideemptyfieldsinsummary) || (imgData != "")) {
739                            if (imgData.substring(0, 4) !== "data") {
740                                value = imgData;
741                            }
742                            else {
743                                value = '<img src="' + imgData + '" />';
744                            }
745                            summary.push(label + visform.oSummarySecondElementLayout + value + visform.cSummarySecondElementLayout);
746                        }
747                    }
748                    return;
749                case 'file' :
750                    if (!jQuery("#" + formid + " #field" + o.id).prop("disabled")) {
751                        value = jQuery("#" + formid + " #field" + o.id).val();
752                        // input element of upload field is not always displayed in form
753                        if (typeof  value === "undefined") {
754                            return;
755                        }
756                        if ((!visform.hideemptyfieldsinsummary) || (value != "")) {
757                            value = value.replace(/^.+(?=[\\\/])\\/, "");
758                            summary.push(label + visform.oSummarySecondElementLayout + value + visform.cSummarySecondElementLayout);
759                        }
760                    }
761                    return;
762                default :
763                    if (!jQuery("#" + formid + " #field" + o.id).prop("disabled")) {
764                        value = jQuery("#" + formid + " #field" + o.id).val();
765                        if ((!visform.hideemptyfieldsinsummary) || (value != "")) {
766                            summary.push(label + visform.oSummarySecondElementLayout + value + visform.cSummarySecondElementLayout);
767                        }
768                    }
769                    return;
770            }
771        })
772        if (visform.summaryRowLayout) {
773            htmlsummary = summary.join("</"+ visform.summaryRowLayout+"><"+ visform.summaryRowLayout +">");
774            htmlsummary = "<"+ visform.summaryRowLayout +">" + htmlsummary + "</"+ visform.summaryRowLayout+">";
775        }
776        else {
777            htmlsummary = summary.join("");
778        }
779        if (htmlsummary !== "") {
780            htmlsummary = '<' + visform.summaryLayout + ' id="'+formid+'_summary" class="'+ visform.summaryLayoutClass+' visforms_summary">' + htmlsummary + '</' +  visform.summaryLayout + '>';
781            jQuery("#" + formid + "_summarypage").prepend(htmlsummary);
782        }
783    },
784    verifyMail: function (event) {
785        let item = event.target;
786        if (item.nodeName === 'SPAN' && ['A', 'BUTTON'].includes(item.parentNode.nodeName)) {
787            item = item.parentNode;
788        }
789        if (item.nodeName === 'A') {
790            event.preventDefault();
791        }
792        if (item.hasAttribute('disabled') || !item.hasAttribute('data-fieldid') || !item.hasAttribute('data-fid') || !item.hasAttribute('data-token')|| !item.hasAttribute('data-baseurl')) {
793            return;
794        }
795        const {
796            fieldid
797        } = item.dataset;
798        const {
799            fid
800        } = item.dataset;
801        const {
802            token
803        } = item.dataset;
804        const {
805            baseurl
806        } = item.dataset;
807        const adr = jQuery("#" + fieldid).val();
808        const pData = {};
809        pData[token] = 1;
810        pData['verificationAddr'] = adr;
811        pData['fid'] = fid;
812        jQuery.ajax({
813            type: 'POST',
814            url: baseurl + '/index.php?option=com_visforms&task=visforms.sendVerficationMail',
815            data : pData,
816            dataType: 'text',
817            success: function (data, textStatus, jqXHR) {
818                alert(data);
819            },
820            error: function(jqXHR, textStatus, errorThrown) {
821                visForm.showAjaxError(jqXHR.responseText, errorThrown);
822            }
823        });
824    },
825    validateDateOnUpdate : function (event) {
826        let input = event.target;
827        jQuery(input).valid();
828        jQuery(".isCal").trigger("update");
829        return true;
830    },
831    getVfSignatureImgFromCanvas : function (sigFieldOptions) {
832        sigFieldOptions = sigFieldOptions || {};
833        if (!sigFieldOptions.sigFieldId) {
834            return false;
835        }
836        if (!sigFieldOptions.formid) {
837            return false;
838        }
839        let canvasContainer = document.querySelector(sigFieldOptions.sigFieldId);
840        const {api} = canvasContainer.dataset;
841        const settings = jQuery.data(jQuery("#" + sigFieldOptions.formid).get(0), 'visformsettings');
842        let errorMsg = settings.texts.txtCantCreateSigImage;
843        let data, src;
844        // jSignature
845        if (!api) {
846            // translated texts can be found in the visformsetting data of the form
847            // always returns true in modern browsers. Returns true or false as expected in old browsers
848            let supportsSvg = document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Shape", "1.0");
849            let dataFormat = (supportsSvg) ? "image/svg+xml;base64" : "image";
850            let imgFormat = (supportsSvg) ? "image/svg+xml;base64" : "image/png;base64";
851            try {
852                data = jQuery(sigFieldOptions.sigFieldId).jSignature("getData", dataFormat);
853                src = "data:" + imgFormat + "," + data[1];
854                return src;
855            } catch (ex) {
856                return errorMsg;
857            }
858        }
859        // signaturePad
860        else if (api === "1") {
861            let canvas = document.querySelector(sigFieldOptions.sigFieldId + " canvas");
862            const {
863                fieldid
864            } = canvas.dataset;
865            return jQuery("#field" + fieldid).val();
866        }
867        return errorMsg;
868    },
869    initVfSignature : function (fieldOptions) {
870        fieldOptions = fieldOptions || {} ;
871        if (!fieldOptions.fieldId) {return false;}
872        let resetText = fieldOptions.texts.resetText;
873        let unlockText = fieldOptions.texts.unlockText;
874        let lockText = fieldOptions.texts.lockText;
875        this.fieldId = fieldOptions.fieldId; // ToDo sets field id in visForm object; not really necessary because it is only used inside the initVfSignature; could use let fieldId instead as a shorthand or simply fieldOptions.fieldId
876        jQuery("#field" + this.fieldId + "_sig").jSignature({cssclass:"visCanvas",width:fieldOptions.width, height:fieldOptions.height});
877        jQuery('<input type="button" value="'+resetText+'" class="vfSigReset">').on("click", {field: this.fieldId}, function(e){
878            jQuery("#field" + e.data.field + "_sig").jSignature("reset");
879            jQuery("#field" + e.data.field).val("");
880        }).appendTo(jQuery("#field" + this.fieldId + "_sigtools"));
881        jQuery("#field" + this.fieldId + "_sig canvas").attr('tabindex', '0');
882        jQuery("#field" + this.fieldId + "_sig canvas").attr('aria-label', fieldOptions.label);
883        jQuery("#field" + this.fieldId + "_sig canvas").attr('aria-labelledby', fieldOptions.fieldName + "_siglbl");
884        // prevent unintentional writing on mobiles on scroll
885        if (("ontouchstart" in window) || navigator.maxTouchPoints || (fieldOptions.lockCanvas && !(jQuery("#field" + this.fieldId + "_sig").hasClass("isForbidden")))) {
886            jQuery('<input type="button" value="'+unlockText+'" class="vfUnlockC">').on("click", {field: this.fieldId}, function(e){
887                visForm.enableJSignature({field: e.data.field});
888            }).appendTo(jQuery("#field" + this.fieldId + "_sigtools"));
889            jQuery('<input type="button" value="'+lockText+'" class="vfLockC">').on("click", {field: this.fieldId}, function(e){
890                visForm.disableJSignature({field: e.data.field});
891            }).appendTo(jQuery("#field" + this.fieldId + "_sigtools"));
892            this.disableJSignature({field: this.fieldId});
893        }
894        jQuery("#field" + this.fieldId + "_sig").on("change", {field: this.fieldId}, function (e) {
895            var data = jQuery("#field" + e.data.field + "_sig").jSignature("getData", "base30");
896            if(jQuery.isArray(data) && (data.length === 2) && (data[1] !== "")){
897                jQuery("#field" + e.data.field).val(data.join(","))
898            }
899            else {
900                jQuery("#field" + e.data.field).val("");
901            }
902            jQuery("#field" + e.data.field).valid();
903        });
904        jQuery("#field" + this.fieldId + "_sig").closest("form").on("reset", {field: this.fieldId}, function(e) {
905            // jSignature("reset") empties the canvas and existing data and triggers a change event, which results in setting the value in the text-input to ''
906            jQuery("#field" + e.data.field + "_sig").jSignature("reset");
907        });
908        if (jQuery("#field" + this.fieldId + "_sig").hasClass("isForbidden")) {
909            visForm.disableJSignature({field: this.fieldId});
910        }
911    },
912    // lock canvas, used in edit view and on mobile
913    disableJSignature : function(data){
914        jQuery("#field" + data.field + "_sig").jSignature("disable");
915        visForm.hideDisableSignatureControls(data);
916    },
917    // unlock canvas, used in edit view and on mobile
918    enableJSignature : function(data){
919        jQuery("#field" + data.field + "_sig").jSignature("enable");
920        visForm.hideEnableSignatureControls(data);
921    },
922    initVfSignaturePad : function (fieldOptions) {
923        fieldOptions = fieldOptions || {} ;
924        if (!fieldOptions.fieldId) {return false;}
925        const resetText = fieldOptions.texts.resetText;
926        const unlockText = fieldOptions.texts.unlockText;
927        const lockText = fieldOptions.texts.lockText;
928        const fieldId = fieldOptions.fieldId;
929        const canvasContainer = document.getElementById("field" + fieldId + "_sig");
930        const canvas = document.querySelector("#field" + fieldId + "_sig canvas");
931        const signaturePad = new SignaturePad(canvas);
932        jQuery('<input type="button" value="' + resetText + '" class="vfSigReset">').on("click", {field: fieldId}, function (e) {
933            signaturePad.clear();
934            jQuery("#field" + e.data.field).val("");
935        }).appendTo(jQuery("#field" + fieldId + "_sigtools"));
936        // Add lock/unlock buttons if lockCanvas is set or we are on a device with ontouchstart and canvas container has not isForbidden
937        // isForbidden set on control group div = user has no permission to edit the data
938        // isForbidden set on canvas container div = field is set to 'readonly' in field configuration
939        // we look for isForbidden on canvas container div here!
940        if (("ontouchstart" in window) || navigator.maxTouchPoints || (fieldOptions.lockCanvas && !(jQuery("#field" + fieldId + "_sig").hasClass("isForbidden")))) {
941            jQuery('<input type="button" value="' + unlockText + '" class="vfUnlockC">').on("click", {field: fieldId}, function (e) {
942                signaturePad.on();
943                visForm.hideEnableSignatureControls({field: e.data.field});
944            }).appendTo(jQuery("#field" + fieldId + "_sigtools"));
945            jQuery('<input type="button" value="' + lockText + '" class="vfLockC">').on("click", {field: fieldId}, function (e) {
946                signaturePad.off();
947                visForm.hideDisableSignatureControls({field: e.data.field});
948            }).appendTo(jQuery("#field" + fieldId + "_sigtools"));
949            signaturePad.off();
950            visForm.hideDisableSignatureControls({field: fieldId});
951        }
952        // store stroke data in text-input
953        signaturePad.addEventListener("endStroke", () => {
954            const data = signaturePad.toDataURL();
955            const {
956                fieldid
957            } = signaturePad.canvas.dataset;
958            jQuery("#field" + fieldid).val(data);
959        });
960        // handle reset on form (form view only)
961        jQuery("#field" + fieldId + "_sig").closest("form").on("reset",  function (e) {
962            visForm.resetSignaturePadCanvasDataToEmpty(fieldId, signaturePad);
963        });
964        // after value is set in text-input, make sure, that the correct data are displayed on canvas
965        // add event handler for visforms event visfieldInitialised
966        jQuery("#field" + fieldId + "_sig").closest("form").on('visfieldInitialized', function() {
967            // get value in text-input
968            let data = jQuery("#field" + fieldId).val();
969            visForm.setImageOnCanvas(signaturePad, data);
970        });
971        // handle data displayed on canvas for conditional signature field
972        // custom event displatched in showControl()
973        // add event handler
974        canvasContainer.addEventListener('replaceCanvasImage', (event) => {
975            event.stopPropagation();
976            visForm.setImageOnCanvas(signaturePad, event.detail);
977        });
978        if (jQuery("#field" + fieldId + "_sig").hasClass("isForbidden")) {
979            signaturePad.off();
980        }
981    },
982    resetSignaturePadCanvasDataToEmpty : function(fieldId, canvas) {
983        // set text-input to empty
984        jQuery("#field" + fieldId).val('');
985        // clear canvas
986        canvas.clear();
987    },
988    setImageOnCanvas: function (signaturePad, data) {
989        if (data) {
990            signaturePad.clear();
991            signaturePad.fromDataURL(data);
992        }
993        else {
994            signaturePad.clear();
995        }
996    },
997    // toggle visibility of signature controls
998    hideDisableSignatureControls : function (data) {
999        jQuery("#field" + data.field + "_sigtools .vfSigReset").addClass('vishidden');
1000        jQuery("#field" + data.field + "_sigtools .vfLockC").addClass('vishidden');
1001        jQuery("#field" + data.field + "_sigtools .vfUnlockC").removeClass('vishidden');
1002    },
1003    hideEnableSignatureControls: function(data) {
1004        jQuery("#field" + data.field + "_sigtools .vfSigReset").removeClass('vishidden');
1005        jQuery("#field" + data.field + "_sigtools .vfLockC").removeClass('vishidden');
1006        jQuery("#field" + data.field + "_sigtools .vfUnlockC").addClass('vishidden');
1007    }
1008};
1009(function($) {
1010    $.extend($.fn, {
1011        initVisform : function (options) {
1012            const defaults = {
1013                // adding translated texts
1014                texts: {
1015                    txtCantCreateSigImage: "Problems to display signature as image."
1016                }
1017            };
1018            const settings = jQuery.extend(true, {}, defaults, options);
1019            // store form information with the form object in javascript
1020            const visform = $.data(this[0], "visform");
1021            if ((!visform) || typeof visform === "undefined") {
1022                $.data( this[0], "visform", options.visform );
1023                $.data( this[0], "visformsettings", settings );
1024            }
1025            // store user input information with the form object in javascript
1026            const userinputs = $.data(this[0], "userinputs");
1027            if ((!userinputs) || typeof userinputs === "undefined") {
1028                if (!options.visform.useSession && options.userInputs) {
1029                    $.data( this[0], "userinputs", options.userInputs );
1030                }
1031                else {
1032                    this.setUserInputs(options.visform);
1033                }
1034            }
1035
1036            jQuery("#" + options.visform.parentFormId + "_processform").addClass('vishidden');
1037            this.initFields(options.visform);
1038            jQuery(".conditional").on("checkConditionalState", {
1039                restricts: options.restrictData,
1040                userInputs: options.userInputs
1041            }, function (e) {
1042                jQuery(this).toggleDisplay(e.data);
1043            });
1044            // uikit
1045            jQuery(this).closest("form").on("shown", function () {
1046                jQuery(this).trigger('reloadVfMap');
1047                jQuery(this).children("fieldset.active").trigger('setFocusOnClassChange');
1048            });
1049            // Bootstrap 5
1050            jQuery(this).closest("form").on("shown.bs.collapse", function () {
1051                jQuery(this).trigger('reloadVfMap');
1052                jQuery(this).children("fieldset.active").trigger('setFocusOnClassChange');
1053            });
1054            jQuery("#" + options.visform.parentFormId).trigger('visformsInitialised');
1055            this.focusInvalidForm(options.visform);
1056        },
1057        initFields : function (visform) {
1058            const userinputs = $.data($("#" + visform.parentFormId).get(0), 'userinputs');
1059            if ((!userinputs) || typeof userinputs === "undefined") {
1060                return;
1061            }
1062            jQuery.each(userinputs, function (i, obj) {
1063                if (obj.value === "undefined") {
1064                    return;
1065                }
1066                if (obj.isDisabled === true && obj.isForbidden !== true) {
1067                    // these fields stay with there configuration default
1068                    return;
1069                }
1070                // HTML Controls are set with attributes value, selected and checked according to the settings in the field configuration
1071                // This ensures that the js properties defaultValue, defaultSelected and defaultChecked are true the default values
1072                // So that we can use these js properties to reset disabled fields
1073                // And so that 'reset'-Button will have the expected result (even if we are in a redisplay task after php validation of user inputs failed)
1074                // if we have a Redisplay Task (php validation of user inputs failed) we want to set the valid user inputs, which were already made, in the form
1075                // set to user input values
1076                // if a field is readonly the configuration default and the user input are the same (except, when the field value was set with an url param)
1077                switch (obj.type) {
1078                    case "select":
1079                    case "selectsql":
1080                        if (jQuery.isPlainObject(obj.value)) {
1081                            jQuery(this).setSelectedOptions(obj);
1082                        }
1083                        break;
1084                    case "multicheckbox":
1085                    case "multicheckboxsql":
1086                        if (jQuery.isPlainObject(obj.value)) {
1087                            const boxes = jQuery("#" + visform.parentFormId + " ." + obj.label).find('input');
1088                            jQuery.each(boxes, function (i, el) {
1089                                jQuery.each(obj.value, function (ix, val) {
1090                                    if (jQuery(el).attr('value') === val) {
1091                                        jQuery(el).prop('checked', true);
1092                                        // you have to return false to break from an each loop
1093                                        return false;
1094                                    }
1095                                    jQuery(el).prop('checked', false);
1096                                    return;
1097                                });
1098                            });
1099                        }
1100                        break;
1101                    case "radio":
1102                    case "radiosql":
1103                        const radios = jQuery("#" + visform.parentFormId + " ." + obj.label).find('input');
1104                        jQuery.each(radios, function (i, el) {
1105                            if (jQuery(el).attr('value') === obj.value) {
1106                                jQuery(el).prop('checked', true);
1107                            }
1108                            else {
1109                                jQuery(el).prop('checked', false);
1110                            }
1111                        });
1112                        break;
1113                    case "checkbox":
1114                        jQuery("#" + obj.label).prop("checked", obj.value);
1115                        jQuery("#" + obj.label).trigger("recalculate");
1116                        break;
1117                    case "signature" :
1118                        jQuery("#" + obj.label).val(obj.value);
1119                        if (obj.value) {
1120                            if (obj.value.startsWith('image/jsignature;base30')) {
1121                                jQuery("#" + obj.label + "_sig").jSignature("setData", "data:" + obj.value);
1122                            }
1123                            else {
1124                                // signaturePad can only be populated by using an event handler, which is implemented on initialisation
1125                            }
1126                        }
1127                        break;
1128                    case "date" :
1129                        // Calendar field needs special treatment
1130                        // all Calender fields are accessible through JoomlaCalendar.getCalObject(element)._joomlaCalendar;
1131                        // where element is the HTML Input field
1132                        // the _joomlaCalendar is attached to the parent ('.field-calender') element and can be called directly
1133                        // if there is no _joomlaCalendar for a field, this getCalObject() returns false
1134                        // change the data-alt-value
1135                        // call checkInputs() on the _joomlaCalendar to properly set the value in a date field
1136                        jQuery("#" + obj.label).attr('value', obj.value);
1137                        jQuery("#" + obj.label).attr('data-alt-value', obj.value);
1138                        // calObj = jQuery("#" + obj.label).closest('.field-calendar')[0]._joomlaCalendar;
1139                        let calObj = JoomlaCalendar.getCalObject(jQuery("#" + obj.label)[0]);
1140                        if (calObj) {
1141                            let calendar = calObj._joomlaCalendar;
1142                            calendar.checkInputs();
1143                        }
1144                        jQuery("#" + obj.label).trigger("recalculate");
1145                        break;
1146                    case "textarea" :
1147                        // set value in textarea
1148                        let text = obj.value.replace(/&#64/g, '@');
1149                        jQuery("#" + obj.label).val(text);
1150                        // console.log('textarea ' + obj.label + ': content set = ' + text);
1151                        break;
1152                    default:
1153                        // replace used to prevent email cloaking in form used in content (plg or module)
1154                        if (typeof obj.value.replace !== 'undefined') {
1155                            jQuery("#" + obj.label).val(obj.value.replace(/&#64/g, '@'));
1156                            jQuery("#" + obj.label).trigger("recalculate");
1157                        }
1158                        break;
1159                }
1160            });
1161            // ToDo consider if yo want to do this
1162            // enable the buttons only if there is no javascript error on the page
1163            jQuery("#" + visform.parentFormId + ' input[type="submit"]').prop('disabled', false);
1164            jQuery("#" + visform.parentFormId + ' input[type="image"]').prop('disabled', false);
1165            jQuery("#" + visform.parentFormId + ' input[type="reset"]').prop('disabled', false);
1166            // Select a solitary option in selectSQL Field, if option is enabled
1167            jQuery("#" + visform.parentFormId + ' .preSelectedSolitaryOption').each( function (i, el) {
1168                visForm.preSelectSolitaryOption(jQuery(el).attr('id'))
1169            });
1170            // necessary in edit view
1171            jQuery("#" + visform.parentFormId + ' input[type="radio"]').trigger('reloadsqloptions');
1172            jQuery("#" + visform.parentFormId + ' input[type="checkbox"]').trigger('reloadsqloptions');
1173            jQuery("#" + visform.parentFormId + ' select').trigger('reloadsqloptions');
1174            jQuery("#" + visform.parentFormId + ' input[type="text"]').trigger('reloadsqloptions');
1175            jQuery("#" + visform.parentFormId + ' input[type="email"]').trigger('reloadsqloptions');
1176            jQuery("#" + visform.parentFormId + ' input[type="date"]').trigger('reloadsqloptions');
1177            jQuery("#" + visform.parentFormId + ' input[type="url"]').trigger('reloadsqloptions');
1178            jQuery("#" + visform.parentFormId + ' input[type="number"]').trigger('reloadsqloptions');
1179            jQuery("#" + visform.parentFormId + ' input[type="hidden"]').trigger('reloadsqloptions');
1180            jQuery("#" + visform.parentFormId + ' input[type="tel"]').trigger('reloadsqloptions');
1181            jQuery("#" + visform.parentFormId + ' input[type="password"]').trigger('reloadsqloptions');
1182            visForm.hideSqlOptionList(visform.parentFormId);
1183            visForm.hideSqlDataList(visform.parentFormId);
1184            jQuery("#" + visform.parentFormId).trigger('visfieldInitialized');
1185            // initialize tinymce editor if present and function is defined: must be done after the text was set to the textarea
1186            if (typeof tinyMCE !== 'undefined' && typeof initTinyMCE 
1186=== 'function') {
1187                initTinyMCE();
1188            }
1189            // pseudo readonly for non mutable html controls
1190            // native JS implementation using data-Attribute
1191            let pseudoReadonlyElments = document.querySelectorAll("#" + visform.parentFormId + ' [data-readonly="1"]');
1192            pseudoReadonlyElments.forEach(readonlyElement => {
1193                readonlyElement.style.pointerEvents = 'none';
1194                if (readonlyElement.type === "checkbox" || readonlyElement.type === "radio") {
1195                    readonlyElement.addEventListener('click', e => {
1196                        e.preventDefault();
1197                        return false;
1198                    });
1199                    return true;
1200                }
1201                if (readonlyElement.nodeName === "SELECT") {
1202                    readonlyElement.addEventListener('change', e => {
1203                        jQuery.each(userinputs, function (i, obj) {
1204                            if (obj.label === readonlyElement.id) {
1205                                if (obj.value === "undefined") {
1206                                    return;
1207                                }
1208                                if (obj.isDisabled === true && obj.isForbidden !== true) {
1209                                    // these fields stay with there configuration default
1210                                    return;
1211                                }
1212                                jQuery(this).setSelectedOptions(obj);
1213                            }
1214                        })
1215                        jQuery('#'+readonlyElement.id).trigger("change");
1216                    });
1217                    return true;
1218                }
1219            });
1220        },
1221        setSelectedOptions : function (obj) {
1222            if (jQuery.isPlainObject(obj.value)) {
1223                const seloptions = jQuery("#" + obj.label).find('option');
1224                const isSearchSelect = $("#" + obj.label).hasClass('select2-hidden-accessible');
1225                jQuery.each(seloptions, function (i, el) {
1226                    jQuery.each(obj.value, function (i, val) {
1227                        if (jQuery(el).attr('value') === val) {
1228                            jQuery(el).prop('selected', true);
1229                            if (isSearchSelect) {
1230                                $('#select2-' + obj.label + '-container').html($(el).html());
1231                                $("#" + obj.label).trigger('change');
1232                            }
1233                            // you have to return false to break from an each loop
1234                            return false;
1235                        }
1236                        jQuery(el).prop('selected', false);
1237                        return;
1238                    });
1239                });
1240                // preselect solitary option and hide option list according to field configuration
1241                if (obj.type === "selectsql") {
1242                    visForm.preSelectSolitaryOption(obj.label.replace('field',''));
1243                }
1244                if (obj.type === "select") {
1245                    jQuery("#" + obj.label).trigger("recalculate");
1246                }
1247            }
1248        },
1249        focusInvalidForm : function (visform) {
1250            if (jQuery('#' + visform.parentFormId).parent('.visforms.php-error')) {
1251                // php error
1252                // focus message error message block
1253                let errorContainer = jQuery('#' + visform.parentFormId).parent('.visforms.php-error').find('#form-error-container');
1254                if (errorContainer.length) {
1255                    visForm.focusjQueryElementTop(errorContainer);
1256                }
1257            }
1258        },
1259        setUserInputs: function (visform) {
1260            const formElement = jQuery('#' + visform.parentFormId)
1261            const formData = jQuery(formElement).serializeArray();
1262            let baseUrl = visform.baseUrl;
1263            jQuery.ajax({
1264                type: 'POST',
1265                url: baseUrl + '/index.php?option=com_visforms&task=visforms.getUserInputs&id=' + visform.fid,
1266                data: formData,
1267                success: function(data, textStatus, jqXHR) {
1268                    $.data($("#" + visform.parentFormId).get(0),  "userinputs", data)
1269                },
1270                error: function(jqXHR, textStatus, errorThrown) {
1271                    // give error feedback
1272                    visForm.showAjaxError(jqXHR.responseText, errorThrown);
1273                },
1274                dataType: 'json',
1275                async: false
1276            });
1277        }
1278    });
1279}(jQuery));
1280
1281jQuery(document).ready(function () {
1282    // "static" scripts which should only be included once
1283
1284    // fix placeholder for IE7, IE8, IE9
1285    if (!jQuery.support.placeholder) {
1286        jQuery("[placeholder]").focus(function () {
1287            if (jQuery(this).val() == jQuery(this).attr("placeholder")) jQuery(this).val("");
1288        }).blur(function () {
1289            if (jQuery(this).val() == "") jQuery(this).val(jQuery(this).attr("placeholder"));
1290        }).blur();
1291
1292        jQuery("[placeholder]").parents("form").submit(function () {
1293            jQuery(this).find('[placeholder]').each(function () {
1294                if (jQuery(this).val() == jQuery(this).attr("placeholder")) {
1295                    jQuery(this).val("");
1296                }
1297            });
1298        });
1299    }
1300
1301    // keyup event triggers validation if element is marked as invali
1301d
1302    jQuery("input[type='number']").on("input mouseup", function () {
1303        jQuery(this).trigger("keyup");
1304    });
1305    jQuery("input[type='file']").on("change", function () {
1306        jQuery(this).trigger("keyup").trigger("focus");
1307    })
1308    jQuery("input[type='file']").on("blur", function () {
1309        if (!(jQuery(this).get(0).files.length == 0)) {
1310            const id = jQuery(this).attr('id');
1311            jQuery('[data-clear-target="'+id+'"]').removeClass("vishidden").addClass("active");
1312        }
1313    });
1314    jQuery("a.clear-selection").addClass('vishidden');
1315    jQuery("a.clear-selection").on("click", function(e) {
1316        const uploadid = jQuery(this).attr('data-clear-target');
1317        let el = jQuery('#' + uploadid);
1318        el.replaceWith(el.val('').clone(true));
1319        // get the new jQuery object of el
1320        el = jQuery('#' + uploadid);
1321        el.trigger('keyup');
1322        jQuery(this).removeClass("active").addClass('vishidden');
1323        e.preventDefault();
1324        return false;
1325    });
1326    const successMessageClose = jQuery(".visforms-form joomla-alert[type=\"success\"] .joomla-alert--close");
1327    if (successMessageClose) {
1328        const form = successMessageClose.parents(".visforms-form").find("form");
1329        const description = successMessageClose.parents(".visforms-form").find(".category-desc");
1330        form.addClass('vishidden');
1331        description.addClass('vishidden');
1332        successMessageClose.on("click", function() {
1333            jQuery(this).parents(".visforms-form").find("form").removeClass('vishidden');
1334            jQuery(this).parents(".visforms-form").find(".category-desc").removeClass('vishidden');
1335            jQuery(this).parents(".visforms-form").find("form").trigger("reloadVfMap");
1336        });
1337    }
1338
1339    // multi step forms
1340    jQuery('.visform .next_btn').on('click', function (){
1341        jQuery(this).closest('[class^="fieldset-"]').find('input, textarea, select').not(":disabled").removeClass("ignore");
1342        jQuery(this).closest('[class^="fieldset-"]').siblings('[class^="fieldset-"]').find('input, textarea, select').not(":disabled, .btn, .uk-button").addClass("ignore");
1343        visForm.onNextButtonClick(this);
1344    });
1345
1346    jQuery('.visform .summary_btn').on('click', function (){
1347        jQuery(this).closest('[class^="fieldset-"]').find('input, textarea, select').not(":disabled").removeClass("ignore");
1348        jQuery(this).closest('[class^="fieldset-"]').siblings('[class^="fieldset-"]').find('input, textarea, select').not(":disabled, .btn, .uk-button").addClass("ignore");
1349        visForm.onSummaryButtonClick(this)
1350    });
1351
1352    jQuery(".visform .back_btn").on('click', function () {
1353        const visform = jQuery(this).closest('form');
1354        jQuery(this).closest("[class^='fieldset-']").prev().removeClass("vishidden").addClass('active');
1355        jQuery(this).closest("[class^='fieldset-']").prev().trigger("reloadVfMap");
1356        jQuery(this).closest("[class^='fieldset-']").addClass("vishidden").removeClass('active');
1357        // trigger after active was removed from current fieldset
1358        jQuery(this).closest("[class^='fieldset-']").prev().trigger('setFocusOnClassChange',["back"]);
1359        const activeBadge = jQuery(visform).find('.visprogress .badge.badge-important');
1360        jQuery(activeBadge).removeClass("badge-important");
1361        jQuery(activeBadge).closest('.stepCont').prev().find('.badge').removeClass("badge-success").addClass("badge-important");
1362    });
1363
1364    jQuery(".visform .fieldset-1 :reset").on('click', function (e) {
1365        e.preventDefault();
1366        jQuery(this).closest('form').get(0).reset();
1367        // set userinputs of this form to empty array; We can do this, because the edit views do not have a reset button.
1368        // So the stored user inputs which are in the userinputs array and which must not get lost, are not deleted by this call
1369        jQuery.data(jQuery((this).closest('form')).get(0), 'userinputs', []);
1370        jQuery(".conditional").trigger("checkConditionalState");
1371        // Trigger change event is needed to recalculate
1372        jQuery(this).closest('form').find('input').trigger("change");
1373        jQuery(this).closest('form').find('select').trigger("change");
1374    });
1375
1376    // action for reset button on summary page
1377    jQuery(".visform fieldset:not(.fieldset-1) :reset").on('click', function (e) {
1378        e.preventDefault();
1379        jQuery(this).closest('form').get(0).reset();
1380        // set userinputs of this form to empty array;
1380 We can do this, because the edit views do not have a reset button.
1381        // So the stored user inputs which are in the userinputs array and which must not get lost, are not deleted by this call
1382        jQuery.data(jQuery((this).closest('form')).get(0), 'userinputs', []);
1383        jQuery(".conditional").trigger("checkConditionalState");
1384        // Trigger change event is needed to recalculate
1385        jQuery(this).closest('form').find('input').trigger("change");
1386        jQuery(this).closest('form').find('select').trigger("change");
1387        const formid = jQuery(this).closest("form").get(0).id;
1388        jQuery("#" + formid + "_summary").remove();
1389        jQuery(this).closest("[class^='fieldset-']").parent().find("[class^='fieldset-']").first().removeClass("vishidden").addClass('active');
1390        jQuery(this).closest("[class^='fieldset-']").parent().find("[class^='fieldset-']").first().trigger("reloadVfMap");
1391        jQuery(this).closest("[class^='fieldset-']").addClass("vishidden").removeClass('active');
1392        jQuery("#" + formid + " .visprogress .stepCont .badge").removeClass("badge-important badge-success");
1393        jQuery("#" + formid + " .visprogress .stepCont:first .badge").addClass("badge-important");
1394    });
1395
1396    // correct button on summary page
1397    jQuery(".visform .correct_btn").on('click',function () {
1398        const formid = jQuery(this).closest("form").get(0).id;
1399        jQuery("#" + formid + "_summary").remove();
1400        jQuery(this).closest("[class^='fieldset-']").prev().removeClass("vishidden").addClass('active');
1401        jQuery(this).closest("[class^='fieldset-']").prev().trigger("reloadVfMap");
1402        jQuery(this).closest("[class^='fieldset-']").addClass("vishidden").removeClass('active');
1403        jQuery(this).closest("[class^='fieldset-']").prev().trigger('setFocusOnClassChange',["back"]);
1404        jQuery("#" + formid + " .visprogress .stepCont:last .badge").removeClass("badge-important");
1405        jQuery("#" + formid + " .visprogress .stepCont:nth-last-child(2) .badge").removeClass("badge-success").addClass("badge-important");
1406    });
1407
1408    jQuery(".noEnterSubmit").keypress(function (event) {
1409        const key = event.keyCode;
1410        if (key === 13) {
1411            event.preventDefault();
1412            event.stopPropagation();
1413            return false;
1414        }
1415    });
1416
1417    jQuery("fieldset.mpfocustop, fieldset.mpfocusbottom").on('setFocusOnClassChange', function (e, direction) {
1418        // direction not used yet, could be used to have different focus settings on backwards and forwards
1419        let fieldset = e.target;
1420        if (fieldset) {
1421            fieldset = jQuery(fieldset);
1422            let windowHeight = jQuery(window).height();
1423            // top of fieldset relative to document
1424            let elOffset = fieldset.offset().top;
1425            // height of fieldset
1426            let elHeight = fieldset.prop("scrollHeight");// fieldset.height();
1427            let focusTarget = (jQuery(fieldset).hasClass('mpfocusbottom')) ? 'bottom' : 'top';
1428            let offset;
1429            if (focusTarget === 'top') {
1430                offset = elOffset;
1431            }
1432            else {
1433                offset = elOffset  + elHeight - (windowHeight / 4);
1434            }
1435            let speed = 700;
1436            jQuery('html, body').animate({scrollTop: offset}, speed);
1437        }
1438    });
1439    setupVfFormViewTasks({
1440        target: document
1441    });
1442
1443    jQuery(document).displayChanger();
1444
1445});
1446
1447const setupVfFormViewTasks = ({target}) => {
1448    target.querySelectorAll('.verifyMailBtn').forEach(
1449        element => element.addEventListener('click', visForm.verifyMail)
1450    );
1451    target.querySelectorAll('.viscalendar-input').forEach(
1452        element => element.addEventListener('click', visForm.validateDateOnUpdate)
1453    );
1454};

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.