PageSourceSearch

https://www.zwolsetheaters.nl/assets/forms/umbracoforms-custom-13.…T8Q12d7qj4FlngZCG6OtCUPcUn0btDGMJ4n562eA0nQ

js zwolsetheaters.nl collected 2026-09-24 20:46:13 UTC 44,579 bytes, 1,242 lines download raw bytes

1// The only change in this file is the change of listening to DOMContentLoaded to BaselineLoaded.
2// In the future, please make sure this file is updated and then listen to the correct event.
3// Get a new version of this file at:
4// https://localhost:44389/App_Plugins/UmbracoForms/Assets/themes/default/umbracoforms.js?v=13.5.0 (update the version number)
5
6(function () {
7  // polyfill for matches and closest
8  if (!Element.prototype.matches)
9    Element.prototype.matches = Element.prototype.msMatchesSelector;
10  if (!Element.prototype.closest)
11    Element.prototype.closest = function (selector) {
12      var el = this;
13      while (el) {
14        if (el.matches(selector)) {
15          return el;
16        }
17        el = el.parentElement;
18      }
19    };
20
21  //execute init() on document ready
22  document.addEventListener("BaselineLoaded", listen);
23
24  function listen() {
25    // Inline script setting umbracoFormsCollection was removed in 8.11/9.3, and replaced by config elements.
26    // So if we have them, use it, otherwise fall-back to legacy method.
27    var configElements = document.getElementsByClassName(
28      "umbraco-forms-form-config"
29    );
30    if (configElements.length > 0) {
31      var umbracoFormsCollectionFromConfig = [];
32      for (var i = 0; i < configElements.length; i++) {
33        var configElement = configElements[i];
34        var form = {
35          formId: configElement.dataset.id,
36          pageButtonConditions: JSON.parse(
37            configElement.dataset.serializedPageButtonConditions
38          ),
39          fieldSetConditions: JSON.parse(
40            configElement.dataset.serializedFieldsetConditions
41          ),
42          fieldConditions: JSON.parse(
43            configElement.dataset.serializedFieldConditions
44          ),
45          triggerConditionsCheckOn:
46            configElement.dataset.triggerConditionsCheckOn,
47          disableValidationDependencyCheck:
48            configElement.dataset.disableValidationDependencyCheck === "true",
49          recordValues: JSON.parse(
50            configElement.dataset.serializedFieldsNotDisplayed
51          ),
52          formElementHtmlIdPrefix:
53            configElement.dataset.formElementHtmlIdPrefix,
54          validationRules: configElement.dataset.serializedValidationRules
55            ? JSON.parse(configElement.dataset.serializedValidationRules)
56            : [],
57        };
58        umbracoFormsCollectionFromConfig.push(form);
59      }
60      initCollection(umbracoFormsCollectionFromConfig, true); // Set the 'jsonParsed' flag, indicating that we already have a JSON structure, which we don't have with the legacy, inline script method.
61    } else {
62      if (typeof umbracoFormsCollection === "undefined") {
63        //this will occur if this js file is loaded before the inline scripts, in which case
64        //we'll listen for the inline scripts to execute a custom event.
65        document.addEventListener("umbracoFormLoaded", init);
66      } else {
67        initCollection(umbracoFormsCollection);
68      }
69    }
70
71    // Scrolling to the submitted form was also moved from an inline script in 8.11/9.3.
72    var submittedFormElement = document.getElementById(
73      "umbraco-forms-form-submitted"
74    );
75    if (submittedFormElement) {
76      var formClientId = submittedFormElement.dataset.formClientId;
77      scrollToSubmittedForm(formClientId);
78    }
79  }
80
81  function initCollection(formsCollection, jsonParsed) {
82    configureUmbracoFormsValidation(formsCollection);
83
84    for (var i = 0; i < formsCollection.length; i++) {
85      init({ form: formsCollection[i] }, jsonParsed);
86    }
87  }
88
89  function init(e, jsonParsed) {
90    var formItem = jsonParsed ? e.form : JSON.parse(decodeURI(e.form));
91
92    var forms = document.querySelectorAll(".umbraco-forms-form");
93
94    for (var i = 0; i < forms.length; i++) {
95      var form = forms[i];
96
97      if (!formItem.disableValidationDependencyCheck) {
98        dependencyCheck(form);
99      }
100
101      var page = form.querySelector(".umbraco-forms-page");
102      var conditions = new UmbracoFormsConditions(
103        page,
104        formItem.pageButtonConditions,
105        formItem.fieldSetConditions,
106        formItem.fieldConditions,
107        formItem.triggerConditionsCheckOn &&
108        formItem.triggerConditionsCheckOn.length > 0
109          ? formItem.triggerConditionsCheckOn
110          : "change",
111        formItem.recordValues,
112        formItem.formElementHtmlIdPrefix
113      );
114      conditions.watch();
115
116      applyFormAccessibility(form);
117    }
118  }
119
120  function scrollToSubmittedForm(formClientId) {
121    document.onreadystatechange = function () {
122      if (document.readyState == "complete") {
123        // We have various cases where we want to scroll to the form rendered on the page.
124        // - When we have a server-side validation error, we should scroll to the first error element (which class 'field-validation-error').
125        // - When the form has been submitted, we should scroll to the displayed message (which will have class 'umbraco-forms-submitmessage' or 'umbraco-forms-submitmessage-html').
126        // - When navigating back and forth on a multi-page form, we should scroll to the start of the form page (which will have an id of #umbraco_form_[form client id]).
127        var validationsMessageElements = document.querySelectorAll(
128          ".field-validation-error"
129        );
130        var messageOnSubmitElement = document.querySelectorAll(
131          ".umbraco-forms-submitmessage"
132        );
133        var messageOnSubmitHtmlElement = document.querySelectorAll(
134          ".umbraco-forms-submitmessage-html"
135        );
136        var submittedFormElement = document.getElementById(
137          "umbraco_form_" + formClientId
138        );
139        if (validationsMessageElements.length > 0) {
140          scrollToFirstFieldWithValidationError(validationsMessageElements);
141        } else if (messageOnSubmitElement.length > 0) {
142          scrollElementIntoView(messageOnSubmitElement[0].parentElement);
143        } else if (messageOnSubmitHtmlElement.length > 0) {
144          scrollElementIntoView(messageOnSubmitHtmlElement[0]);
145        } else if (submittedFormElement) {
146          scrollElementIntoView(submittedFormElement);
147        }
148      }
149    };
150
151    function scrollToFirstFieldWithValidationError(validationsMessageElements) {
152      var scrollY = 0;
153      for (var i = 0; i < validationsMessageElements.length; i++) {
154        var node = getFormFieldElement(validationsMessageElements[i]);
155        var offset = node.getBoundingClientRect().top;
156        if (0 < offset && (offset < scrollY || scrollY === 0)) {
157          scrollY = offset;
158        }
159      }
160
161      if (scrollY > 0) {
162        window.scrollTo(0, scrollY);
163      }
164    }
165
166    function scrollElementIntoView(element) {
167      element.scrollIntoView({
168        behavior: "auto",
169        block: "start",
170      });
171    }
172
173    function getFormFieldElement(node) {
174      var runner = node;
175      while (runner.tagName !== "BODY") {
176        if (runner.classList.contains("umbraco-forms-field")) {
177          return runner;
178        }
179
180        runner = runner.parentNode;
181      }
182
183      return node;
184    }
185  }
186
187  /** Configures the jquery validation for Umbraco forms */
188  function configureUmbracoFormsValidation(formsCollection) {
189    var submitInputs, input;
190
191    if (window.aspnetValidation !== undefined) {
192      // Asp-net validation setup:
193
194      var validationService = new aspnetValidation.ValidationService();
195      var required = function (value, element) {
196        // Handle single and multiple checkboxes:
197        if (
198          element.type.toLowerCase() === "checkbox" ||
199          element.type.toLowerCase() === "radio"
200        ) {
201          var allCheckboxesOfThisName = element.form.querySelectorAll(
202            "input[name='" + element.name + "']"
203          );
204          for (var i = 0; i < allCheckboxesOfThisName.length; i++) {
205            if (allCheckboxesOfThisName[i].checked === true) {
206              return true;
207            }
208          }
209          return false;
210        }
211        return Boolean(value);
212      };
213      validationService.addProvider("requiredcb", required);
214      validationService.addProvider("required", required); // this will go instead of the build-in required.
215
216      var umbracoforms_regex = function (value, element, params) {
217        if (!value || !params.pattern) {
218          return true;
219        }
220
221        var r = new RegExp(params.pattern);
222        return r.test(value);
223      };
224      validationService.addProvider("umbracoforms_regex", umbracoforms_regex);
225
226      var wrapProviderWithIgnorerBehaviour = function (provider) {
227        return function (value, element, params) {
228          // If field is hidden we ignore the validation.
229          if (element.offsetParent === null) {
230            return true;
231          }
232
233          return provider(value, element, params);
234        };
235      };
236
237      // we can only incept with default validator if we do it after bootstrapping but before window load event triggers validationservice.
238      window.addEventListener("load", function () {
239        // Wrap all providers with ignorer hidden fields logic:
240        for (var key in validationService.providers) {
241          validationService.providers[key] = wrapProviderWithIgnorerBehaviour(
242            validationService.providers[key]
243          );
244        }
245      });
246
247      // bootstrap validation service.
248      validationService.bootstrap();
249
250      // make validation service availalble globally for custom client-side code.
251      window.umbracoFormsValidationService = validationService;
252
253      // Without jquery validation, the previous page submit button click isn't sent with it's name,
254      // so can't be used server-side to determine whether to go forward or back.
255      // Hence we'll use an alternate method, setting a hidden field that's also used in the check.
256      var handlePreviousClicked = function () {
257        this.form.elements["PreviousClicked"].value = "clicked";
258      };
259
260      // - previous buttons are indicated by a data attribute of data-umb="prev-forms-form", introduced in 8.12/9.4.
261      var previousButtonElements = document.querySelectorAll(
262        "[data-umb='prev-forms-form']"
263      );
264
265      // - prior to that classes were used to identify them, so for compatibility with custom themes, we'll check for those too
266      //   if we haven't found any via the data attribute.
267      if (previousButtonElements.length === 0) {
268        previousButtonElements = document.getElementsByClassName("prev cancel");
269      }
270
271      for (var i = 0; i < previousButtonElements.length; i++) {
272        previousButtonElements[i].form.elements["PreviousClicked"].value = "";
273        previousButtonElements[i].addEventListener(
274          "click",
275          handlePreviousClicked,
276          false
277        );
278      }
279
280      // Apply protection for multiple form submissions using the aspnet validation validator.
281      submitInputs = getSubmitInputs();
282      for (let i = 0; i < submitInputs.length; i++) {
283        input = submitInputs[i];
284        input.addEventListener("click", function (e) {
285          e.preventDefault();
286          var frm = e.currentTarget.form;
287          var validationRules = getValidationRulesForForm(frm, formsCollection);
288          validationService.validateForm(frm, (valid) => {
289            var formRulesValid = validateFormRules(
290              frm,
291              validationRules,
292              "aspnet-client-validation",
293              validationService
294            );
295            valid = valid && formRulesValid;
296            if (valid) {
297              submitValidatedForm(frm);
298              var submitInputsForForm = frm.querySelectorAll(
299                "[type=submit]:not(.cancel)"
300              );
301              for (let j = 0; j < submitInputsForForm.length; j++) {
302                submitInputsForForm[j].setAttribute("disabled", "disabled");
303              }
304            }
305          });
306        });
307      }
308    } else if (
309      typeof jQuery === "function" &&
310      $.validator &&
311      $.validator.unobtrusive
312    ) {
313      //Jquery validation setup
314
315      $.validator.setDefaults({
316        ignore: ":hidden",
317      });
318
319      $.validator.unobtrusive.adapters.addBool("requiredcb", "required");
320
321      $.validator.addMethod("umbracoforms_regex", function (value, element) {
322        var regex = $(element).attr("data-regex");
323        var val = $(element).val();
324        if (val.length === 0) {
325          return true;
326        }
327        return val.match(regex);
328      });
329
330      $.validator.unobtrusive.adapters.addBool("regex", "umbracoforms_regex");
331
332      // Apply protection for multiple form submissions using the jquery validator.
333      submitInputs = getSubmitInputs();
334      for (let i = 0; i < submitInputs.length; i++) {
335        input = submitInputs[i];
336        input.addEventListener(
337          "click",
338          function (evt) {
339            evt.preventDefault();
340            var frm = $(this).closest("form");
341            resetValidationMessages(frm[0]);
342            var validator = frm.validate();
343            var validationRules = getValidationRulesForForm(
344              frm[0],
345              formsCollection
346            );
347            var formValid = frm.valid();
348            var formRulesValid = validateFormRules(
349              frm[0],
350              validationRules,
351              "jquery",
352              validator
353            );
354            if (formValid && formRulesValid) {
355              submitValidatedForm(frm);
356              this.setAttribute("disabled", "disabled");
357            }
358          }.bind(input)
359        );
360      }
361    }
362  }
363
364  function getSubmitInputs() {
365    return document.querySelectorAll(
366      ".umbraco-forms-form [type=submit]:not(.cancel)"
367    );
368  }
369
370  function getValidationRulesForForm(formElement, formsCollection) {
371    var filteredForms = formsCollection.filter(
372      (f) => f.formId === formElement["FormId"].value.replaceAll("-", "")
373    );
374    if (filteredForms.length > 0 && filteredForms[0].validationRules) {
375      // Work on a clone of the rules, so we don't modify in the originals and can still access the definitions that refer to
376      // field names.
377      var clonedRules = structuredClone(filteredForms[0].validationRules);
378      var formData = new FormData(formElement);
379      return clonedRules.map((r) => getRuleWithFieldValues(r, formData));
380    }
381
382    return [];
383  }
384
385  function getRuleWithFieldValues(validationRule, formData) {
386    var replacedRule = validationRule.rule;
387    for (var item of formData) {
388      replacedRule = replacedRule.replaceAll("{" + item[0] + "}", item[1]);
389    }
390    validationRule.rule = replacedRule;
391    return validationRule;
392  }
393
394  function validateFormRules(
395    formElement,
396    validationRules,
397    validationLibrary,
398    validator
399  ) {
400    if (typeof jsonLogic === "undefined") {
401      // If we don't have the dependency, form rules aren't validated.
402      return true;
403    }
404
405    var rulesResult = true;
406    for (var i = 0; i < validationRules.length; i++) {
407      var validationRule = validationRules[i];
408
409      // Skip if the rule contains unresolved field references.
410      var re = /{({*[\w]*}*)}/;
411      if (validationRule.rule.match(re)) {
412        continue;
413      }
414
415      var ruleAsJson;
416      try {
417        ruleAsJson = JSON.parse(validationRule.rule);
418      } catch (e) {
419        continue; // Skip also on invalid JSON.
420      }
421
422      var ruleResult = jsonLogic.apply(ruleAsJson);
423      indicateFormRuleValidation(
424        formElement,
425        validationLibrary,
426        validator,
427        ruleResult,
428        validationRule
429      );
430      rulesResult = rulesResult && ruleResult;
431    }
432
433    return rulesResult;
434  }
435
436  function indicateFormRuleValidation(
437    formElement,
438    validationLibrary,
439    validator,
440    result,
441    validationRule
442  ) {
443    if (validationRule.fieldId) {
444      // Show or hide field error dependending on result.
445      var inputElement = formElement[validationRule.fieldId];
446
447      // If we have more than one element, e.g. for the date picker, use the one also matching the id.
448      if (inputElement.length && inputElement.length > 0) {
449        inputElement = Array.from(inputElement).filter(
450          (e) => e.id === validationRule.fieldId
451        )[0];
452      }
453
454      if (validationLibrary === "aspnet-client-validation") {
455        if (result) {
456          // Only remove if it's the same message that we've added (could be other validation rules on the field we would want to keep).
457          var validationFieldMessageElement = getValidationFieldMessageElement(
458            inputElement,
459            "error"
460          );
461          if (
462            validationFieldMessageElement &&
463            validationFieldMessageElement.innerText ===
464              validationRule.errorMessage
465          ) {
466            validator.removeError(inputElement);
467          }
468        } else {
469          validator.addError(inputElement, validationRule.errorMessage);
470        }
471      }
471 else if (validationLibrary === "jquery") {
472        var validationSummaryElement = formElement.querySelector(
473          ".validation-summary-errors ul"
474        );
475        if (result) {
476          var validationFieldMessageElement = getValidationFieldMessageElement(
477            inputElement,
478            "error"
479          );
480
481          // Only remove if it's the same message that we've added (could be other validation rules on the field we would want to keep).
482          if (
483            validationFieldMessageElement &&
484            validationFieldMessageElement.innerText ===
485              validationRule.errorMessage
486          ) {
487            validationFieldMessageElement.classList.remove(
488              "field-validation-error"
489            );
490            validationFieldMessageElement.classList.add(
491              "field-validation-valid"
492            );
493            validationFieldMessageElement.innerText = "";
494          }
495
496          removeValidationSummaryMessage(
497            validationSummaryElement,
498            validationRule.errorMessage
499          );
500        } else {
501          var validationFieldMessageElement = getValidationFieldMessageElement(
502            inputElement,
503            "valid"
504          );
505          if (validationFieldMessageElement) {
506            validationFieldMessageElement.classList.remove(
507              "field-validation-valid"
508            );
509            validationFieldMessageElement.classList.add(
510              "field-validation-error"
511            );
512            validationFieldMessageElement.innerText =
513              validationRule.errorMessage;
514          }
515
516          addValidationSummaryMessage(
517            validationSummaryElement,
518            validationRule.errorMessage
519          );
520        }
521      }
522    }
523  }
524
525  function getValidationFieldMessageElement(inputElement, state) {
526    return inputElement
527      .closest(".umbraco-forms-field-wrapper")
528      .querySelector(".field-validation-" + state);
529  }
530
531  function removeValidationSummaryMessage(
532    validationSummaryElement,
533    errorMessage
534  ) {
535    if (validationSummaryElement) {
536      validationSummaryElement.querySelectorAll("li").forEach((li) => {
537        if (li.innerText === errorMessage) {
538          li.remove();
539        }
540      });
541    }
542  }
543
544  function addValidationSummaryMessage(validationSummaryElement, errorMessage) {
545    removeValidationSummaryMessage(validationSummaryElement, errorMessage);
546    if (validationSummaryElement) {
547      var validationSummaryItemElement = document.createElement("li");
548      validationSummaryItemElement.appendChild(
549        document.createTextNode(validationRule.errorMessage)
550      );
551      validationSummaryElement.appendChild(validationSummaryItemElement);
552    }
553  }
554
555  function submitValidatedForm(form) {
556    // Use requestSubmit if available (see: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit#usage_notes)
557    if (form.requestSubmit) {
558      form.requestSubmit();
559    } else {
560      form.submit();
561    }
562  }
563
564  /**
565   * method to determine if Umbraco Forms can run and has the required dependencies loaded
566   * @param {Form Element} formEl the element of the form
567   */
568  function dependencyCheck(formEl) {
569    // Only perform check if the global 'Umbraco.Sys' is null/undefined.
570    // If present means we are in backoffice & that this is being rendered as a macro preview and we do not need to perform this check here.
571    // Similarly we need a check for if running in a rich text editor.
572    var isBackOffice = function () {
573      return (
574        typeof Umbraco !== "undefined" && typeof Umbraco.Sys !== "undefined"
575      );
576    };
577    var isBackOfficeRte = function () {
578      return document.body.id === "tinymce";
579    };
580
581    if (isBackOffice() || isBackOfficeRte()) {
582      return;
583    }
584
585    var errorElement = document.createElement("div");
586    errorElement.className = "umbraco-forms missing-library";
587    errorElement.style.color = "#fff";
588    errorElement.style.backgroundColor = "#9d261d";
589    errorElement.style.padding = "15px";
590    errorElement.style.margin = "10px 0";
591    var errorMessage = "";
592
593    //Ensure umbracoForm is not null
594    if (formEl) {
595      //Check to see if the message for the form has been inserted already
596      var checkForExistinhgErr = formEl.getElementsByClassName(
597        "umbraco-forms missing-library"
598      );
599      if (checkForExistinhgErr.length > 0) {
600        return;
601      }
602
603      var hasValidationFramework = false;
604
605      if (window.jQuery && $ && $.validator !== undefined) {
606        hasValidationFramework = true;
607      } else if (window.aspnetValidation !== undefined) {
608        hasValidationFramework = true;
609      }
610
611      if (hasValidationFramework === false) {
612        errorMessage =
613          errorMessage +
614          "Umbraco Forms requires a validation framework to run, please read documentation for posible options.";
615      }
616
617      if (errorMessage !== "") {
618        errorElement.innerHTML =
619          errorMessage +
620          '<br/> <a href="https://docs.umbraco.com/umbraco-forms/developer/prepping-frontend" target="_blank" style="text-decoration:underline;
620 color:#fff;">See Umbraco Forms Documentation</a>';
621
622        formEl.insertBefore(errorElement, formEl.childNodes[0]);
623      }
624    }
625  }
626
627  /**
628   * Applies form accessibility improvements.
629   * @param {Element} formEl the element of the form.
630   */
631  function applyFormAccessibility(formEl) {
632    setFocusToFirstElementOnValidationError(formEl);
633  }
634
635  /**
636   * Monitors for validation errors and when found sets the focus to the first field with an error.
637   * @param {Element} formEl the element of the form.
638   */
639  function setFocusToFirstElementOnValidationError(formEl) {
640    if ("MutationObserver" in window === false) {
641      return;
642    }
643
644    // To implement this, we are relying on on monitoring for validation message elements, which only fires when there are changes.
645    // So if you have two errors, and fix the first one, it wouldn't then highlight the second one on re-submitting the form.
646    // Unless we reset the validation messages on submit, so they get changed back on errors.
647    if (window.aspnetValidation !== undefined) {
648      var form = formEl.getElementsByTagName("form")[0];
649      var handleResetValidationMessages = function () {
650        resetValidationMessages(form);
651      };
652      form.addEventListener("submit", handleResetValidationMessages, false);
653    } else {
654      // For jquery.validate, we need to hook this in as part of the submit handler coded in configureUmbracoFormsValidation();
655    }
656
657    // Watch for changes to the validation error messages in the DOM tree using a MutationObserver.
658    // See: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
659    var observer = new MutationObserver(function (mutationRecords) {
660      for (var i = 0; i < mutationRecords.length; i++) {
661        var mutationRecord = mutationRecords[i];
662        if (mutationRecord.target.className === "field-validation-error") {
663          setFocusOnFormField(mutationRecord.target);
664          break;
665        }
666      }
667    });
668
669    observer.observe(formEl, {
670      attributes: true,
671      attributeFilter: ["class"],
672      childList: false,
673      characterData: false,
674      subtree: true,
675    });
676  }
677
678  /**
679   * Resets the validation messages for a form.
680   * @param {Element} formEl the element of the form.
681   */
682  function resetValidationMessages(formEl) {
683    var validationErrorMessageElements = formEl.getElementsByClassName(
684      "field-validation-error"
685    );
686    for (var i = 0; i < validationErrorMessageElements.length; i++) {
687      validationErrorMessageElements[i].className = "field-validation-valid";
688    }
689  }
690
691  /**
692   * Sets the focus to the form field input element associated with the provided validation message element.
693   * @param {Element} validationErrorEl the element of the validation error.
694   */
695  function setFocusOnFormField(validationErrorEl) {
696    var formFieldElement = validationErrorEl.previousElementSibling;
697    while (formFieldElement) {
698      if (
699        formFieldElement.tagName.toLowerCase() === "input" ||
700        formFieldElement.tagName.toLowerCase() === "textarea" ||
701        formFieldElement.tagName.toLowerCase() === "select"
702      ) {
703        formFieldElement.focus();
704        break;
705      }
706
707      if (
708        formFieldElement.classList.contains("radiobuttonlist") ||
709        formFieldElement.classList.contains("checkboxlist")
710      ) {
711        for (var i = 0; i < formFieldElement.children.length; i++) {
712          var formFieldChildElement = formFieldElement.children[i];
713          if (formFieldChildElement.tagName.toLowerCase() === "input") {
714            formFieldChildElement.focus();
715            break;
716          }
717        }
718
719        break;
720      }
721
722      formFieldElement = formFieldElement.previousElementSibling;
723    }
724  }
725
726  /**
727   * Class to handle Umbraco Forms conditional statements
728   * @param {any} form a reference to the form
729   * @param {any} pageButtonConditions a reference to the page button conditions
730   * @param {any} fieldsetConditions a reference to the fieldset conditions
731   * @param {any} fieldConditions a reference to the field conditions
732   * @param {any} triggerConditionsCheckOn the client-side event on which condition checks should be triggered
733   * @param {any} values the form values
734   * @param {any} formElementHtmlIdPrefix the HTML ID prefix used when rendering the form
735   * @return {Object} reference to the created class
736   */
737  function UmbracoFormsConditions(
738    form,
739    pageButtonConditions,
740    fieldsetConditions,
741    fieldConditions,
742    triggerConditionsCheckOn,
743    values,
744    formElementHtmlIdPrefix
745  ) {
746    //our conditions "class" - must always be newed to work as it uses a form instance to operate on
747    //load all the information from the dom and serverside info and then the class will take care of the rest
748
749    var self = {};
750    self.form = form;
751    self.pageButtonConditions = pageButtonConditions;
752    self.fieldsetConditions = fieldsetConditions;
753    self.fieldConditions = fieldConditions;
754    self.triggerConditionsCheckOn = triggerConditionsCheckOn;
755    self.values = values;
756    self.formElementHtmlIdPrefix = formElementHtmlIdPrefix;
757    self.dataTypes = {};
758
759    //Iterates through all the form elements found on the page to update the registered value
760    function populateFieldValues(page, formValues, dataTypes) {
761      var selectFields = page.querySelectorAll("select");
762      for (let i = 0; i < selectFields.length; i++) {
763        const field = selectFields[i];
764        formValues[field.getAttribute("id")] = field.value;
765        dataTypes[field.getAttribute("id")] = "select";
766      }
767
768      var textareaFields = page.querySelectorAll("textarea");
769      for (let i = 0; i < textareaFields.length; i++) {
770        const field = textareaFields[i];
771        formValues[field.getAttribute("id")] = field.value;
772        dataTypes[field.getAttribute("id")] = "textarea";
773      }
774
775      var getKeyForRadioOrCheckBoxListElement = function (field) {
776        const idParts = field.getAttribute("id").split("_");
777        return idParts.slice(0, idParts.length - 1).join("_");
778      };
779
780      // clear out all saved checkbox values to we can safely append
781      var checkboxFields = page.querySelectorAll("input[type=checkbox]");
782      for (let i = 0; i < checkboxFields.length; i++) {
783        const field = checkboxFields[i];
784
785        // Need to handle both a single checkbox, and a checkbox list. We can distinguish by comparing the field's
786        // id and name attributes. If they are the same, accounting for a custom prefix, then we have a single checkbox.
787        if (
788          field.getAttribute("id") !==
789          self.formElementHtmlIdPrefix + field.getAttribute("name")
790        ) {
791          // Handle checkbox list.
792          // For a checkbox in a list we need to remove the suffix from the Id (which will be '_0', '_1' etc.).
793          const checkboxKey = getKeyForRadioOrCheckBoxListElement(field);
794          formValues[checkboxKey] = null;
795          dataTypes[checkboxKey] = "checkbox";
796        } else {
797          // Handle single checkbox.
798          formValues[field.getAttribute("id")] = null;
799          dataTypes[field.getAttribute("id")] = "checkbox";
800        }
801      }
802
803      var inputFields = page.querySelectorAll("input");
804      for (let i = 0; i < inputFields.length; i++) {
805        const field = inputFields[i];
806
807        if (
808          field.getAttribute("type") === "text" ||
809          field.getAttribute("type") === "number" ||
810          field.getAttribute("type") === "email" ||
811          field.getAttribute("type") === "url" ||
812          field.getAttribute("type") === "tel" ||
813          field.getAttribute("type") === "time" ||
814          field.getAttribute("type") === "date" ||
815          field.getAttribute("type") === "datetime-local" ||
816          field.getAttribute("type") === "hidden"
817        ) {
818          formValues[field.getAttribute("id")] = field.value;
819          dataTypes[field.getAttribute("id")] = "text";
820        }
821
822        if (field.getAttribute("type") === "radio") {
823          if (field.matches(":checked")) {
824            // For a radio button in a list we need to remove the suffix from the Id (which will be '_0', '_1' etc.).
825            const radioKey = getKeyForRadioOrCheckBoxListElement(field);
826            formValues[radioKey] = field.value;
827            dataTypes[radioKey] = "radio";
828          }
829        }
830
831        if (field.getAttribute("type") === "checkbox") {
832          // Again, need to handle both a single checkbox, and a checkbox list.
833          if (
834            field.getAttribute("id") !==
835            self.formElementHtmlIdPrefix + field.getAttribute("name")
836          ) {
837            // Handle checkbox list.
838            // For a checkbox in a list we need to remove the suffix from the Id (which will be '_0', '_1' etc.).
839            const checkboxKey = getKeyForRadioOrCheckBoxListElement(field);
840            if (field.matches(":checked")) {
841              if (formValues[checkboxKey] === null) {
842                formValues[checkboxKey] = field.value;
843              } else {
844                formValues[checkboxKey] += ";;" + field.value;
845              }
846            }
847          } else {
848            // Handle single checkbox.
849            formValues[field.getAttribute("id")] = field.matches(":checked")
850              ? "true"
851              : "false";
852          }
853        }
854      }
855    }
856
857    /* Public api */
858
859    self.operators = {
860      Is: function (value, expected) {
861        if ((value || "") === expected) {
862          return true;
863        }
864        if (value == null) {
865          return expected == value;
866        }
867
868        // Handle special cases where we case insensitively compare for expected values of "true" and "on", which we
869        // expect to have come from checkbox conditions.
870        if (
871          expected.toUpperCase() === "TRUE" ||
872          expected.toUpperCase() === "ON"
873        ) {
874          expected = "true";
875        } else if (
876          expected.toUpperCase() === "FALSE" ||
877          expected.toUpperCase() === "OFF"
878        ) {
879          expected = "false";
880        }
881
882        // Handle single checked checkbox, where we'll get two values provided.
883        if (value === "true;;false") {
884          value = "true";
885        }
886
887        var values = value.split(";;");
888
889        var matchingExpected = values.filter(function (o) {
890          return o === expected;
891        });
892        return matchingExpected.length === values.length; // If there are multiple values (e.g. for a checkbox list), "is" only matches if
893        // a single value only matches the expected. Contains should be used if matching any value.
894      },
895      IsNot: function (value, unexpected, dataType) {
896        if (value == null) {
897          return unexpected != value;
898        }
899
900        // Handle single checked checkbox, where we'll get two values provided.
901        if (value === "true;;false") {
902          value = "true";
903        }
904
905        var values = value.split(";;");
906        var matchingUnexpected = values.filter(function (o) {
907          return o === unexpected;
908        });
909
910        if (dataType === "checkbox") {
911          if (
912            unexpected.toUpperCase() === "TRUE" ||
913            unexpected.toUpperCase() === "ON"
914          ) {
915            unexpected = "true";
916          } else if (
917            unexpected.toUpperCase() === "FALSE" ||
918            unexpected.toUpperCase() === "OFF"
919          ) {
920            unexpected = "false";
921          }
922        }
923        return (
924          (value || "") !== unexpected &&
925          matchingUnexpected.length != values.length
926        );
927      },
928      GreaterThen: function (value, limit) {
929        if (isNaN(value) || isNaN(limit)) {
930          return value > limit;
931        }
932
933        return parseInt(value) > parseInt(limit);
934      },
935      LessThen: function (value, limit) {
936        if (isNaN(value) || isNaN(limit)) {
937          return value < limit;
938        }
939
940        return parseInt(value) < parseInt(limit);
941      },
942      StartsWith: function (value, criteria) {
943        return value && value.startsWith(criteria);
944      },
945      EndsWith: function (value, criteria) {
946        return value && value.endsWith(criteria);
947      },
948      Contains: function (value, criteria) {
949        return value && value.indexOf(criteria) > -1;
950      },
951      ContainsIgnoreCase: function (value, criteria) {
952        return (
953          value &&
954          criteria &&
955          value.toUpperCase().indexOf(criteria.toUpperCase()) >= 0
956        );
957      },
958      StartsWithIgnoreCase: function (value, criteria) {
959        return (
960          value &&
961          criteria &&
962          value.toUpperCase().startsWith(criteria.toUpperCase())
963        );
964      },
965      EndsWithIgnoreCase: function (value, criteria) {
966        return (
967          value &&
968          criteria &&
969          value.toUpperCase().endsWith(criteria.toUpperCase())
970        );
971      },
972      NotContains: function (value, criteria) {
973        return !value || (criteria && value.indexOf(criteria) < 0);
974      },
975      NotStartsWith: function (value, criteria) {
976        return !value || (criteria && !value.startsWith(criteria));
977      },
978      NotEndsWith: function (value, criteria) {
979        return !value || (criteria && !value.endsWith(criteria));
980      },
981      NotContainsIgnoreCase: function (value, criteria) {
982        return (
983          !value ||
984          (criteria && value.toUpperCase().indexOf(criteria.toUpperCase()) < 0)
985        );
986      },
987      NotStartsWithIgnoreCase: function (value, criteria) {
988        return (
989          !value ||
990          (criteria && !value.toUpperCase().startsWith(criteria.toUpperCase()))
991        );
992      },
993      NotEndsWithIgnoreCase: function (value, criteria) {
994        return (
995          !value ||
996          (criteria && !value.toUpperCase().endsWith(criteria.toUpperCase()))
997        );
998      },
999    };
1000
1001    self.watch = function () {
1002      // This is a special case for pikaday
1003      // The only way around to pickup the value, for now, is to
1004      // subscribe to blur events
1005      var datepickerfields = self.form.querySelectorAll(".datepickerfield");
1006      for (let i = 0; i < datepickerfields.length; i++) {
1007        const field = datepickerfields[i];
1008        field.addEventListener(
1009          "blur",
1010          function () {
1011            if (this.value === "") {
1012              // Here comes the hack
1013              // Force the hidden datepicker field the datepicker field
1014              var id = this.getAttribute("id");
1015              var hiddenDatePickerField = id + "_1";
1016              self.values[hiddenDatePickerField] = "";
1017              document.getElementById(hiddenDatePickerField).value = ""; // sadly we cant use querySelector with current mark-up (would need to prefix IDs)
1018            }
1019
1020            populateFieldValues(self.form, self.values, self.dataTypes);
1021            //process the conditions
1022            self.run();
1023          }.bind(field)
1024        );
1025      }
1026      //subscribe to change or input event as per configuration
1027      var changeablefields = self.form.querySelectorAll(
1028        "input, textarea, select"
1029      );
1030      for (let i = 0; i < changeablefields.length; i++) {
1031        const field = changeablefields[i];
1032        field.addEventListener(
1033          self.triggerConditionsCheckOn,
1034          function () {
1035            populateFieldValues(self.form, self.values, self.dataTypes);
1036            //process the conditions
1037            self.run();
1038          }.bind(field)
1039        );
1040      }
1041
1042      //register all values from the current fields on the page
1043      populateFieldValues(self.form, self.values, self.dataTypes);
1044
1045      //the initial run-through of all the conditions
1046      self.run();
1047    };
1048
1049    self.run = function () {
1050      var pageId,
1051        htmlFieldId,
1052        fsId,
1053        fieldId,
1054        /*
1055                fsConditions = params.fsConditions || {},
1056                fieldConditions = params.fieldConditions || {},
1057                values = params.values || {},*/
1058
1059        cachedResults = {};
1060
1061      function evaluateRuleInstance(rule) {
1062        var value = self.values[self.formElementHtmlIdPrefix + rule.field],
1063          func = self.operators[rule.operator],
1064          result = value !== null && func(value, rule.value);
1065        return result;
1066      }
1067
1068      function evaluateRule(rule) {
1069        var dependencyIsVisible = true;
1070
1071        if (self.fieldConditions[rule.field]) {
1072          dependencyIsVisible = isVisible(
1073            rule.field,
1074            self.fieldConditions[rule.field]
1075          );
1076        }
1077
1078        if (dependencyIsVisible) {
1079          return evaluateRuleInstance(rule);
1080        } else {
1081          return false;
1082        }
1083      }
1084
1085      function evaluateCondition(id, condition) {
1086        // This was once pretty. Now it needs refactoring again. :)
1087
1088        var any = condition.logicType === "Any",
1089          all = condition.logicType === "All",
1090          fieldsetVisibilities = {},
1091          hasHiddenFieldset = false,
1092          success = true,
1093          rule,
1094          i;
1095
1096        // If we don't have any rules defined, we must return false (as neither 'any' nor 'all' of the conditions
1097        // can be considered passing).
1098        if (condition.rules.length === 0) {
1099          return false;
1100        }
1101
1102        for (i = 0; i < condition.rules.length; i++) {
1103          rule = condition.rules[i];
1104
1105          if (id === rule.field || id === rule.fieldsetId) {
1106            throw new Error(
1107              "Field or fieldset " + id + " has a condition on itself."
1108            );
1109          }
1110
1111          if (fieldsetVisibilities[rule.fieldsetId] !== undefined) {
1112            continue;
1113          }
1114
1115          if (self.fieldsetConditions[rule.fieldsetId]) {
1116            fieldsetVisibilities[rule.fieldsetId] = isVisible(
1117              rule.fieldsetId,
1118              self.fieldsetConditions[rule.fieldsetId]
1119            );
1120
1121            if (!fieldsetVisibilities[rule.fieldsetId]) {
1122              hasHiddenFieldset = true;
1123            }
1124          } else {
1125            fieldsetVisibilities[rule.fieldsetId] = true;
1126          }
1127        }
1128
1129        if (all && hasHiddenFieldset) {
1130          return false;
1131        }
1132
1133        for (i = 0; i < condition.rules.length; i++) {
1134          rule = condition.rules[i];
1135
1136          if (fieldsetVisibilities[rule.fieldsetId]) {
1137            success = evaluateRule(condition.rules[i]);
1138          } else {
1139            success = false;
1140          }
1141
1142          if (any && success) {
1143            break;
1144          }
1145          if (all && !success) {
1146            break;
1147          }
1148        }
1149        return success;
1150      }
1151
1152      function evaluateConditionVisibility(id, condition) {
1153        var show = condition.actionType === "Show",
1154          cachedResult = cachedResults[id];
1155
1156        var success;
1157        if (cachedResult === undefined) {
1158          cachedResults[id] = show; // set default value to avoid circular issues
1159          success = cachedResults[id] = evaluateCondition(id, condition);
1160        } else {
1161          success = cachedResult;
1162        }
1163
1164        var visible = !(success ^ show);
1165        return visible;
1166      }
1167
1168      function isVisible(id, condition) {
1169        if (condition) {
1170          return evaluateConditionVisibility(id, condition);
1171        }
1172        return true;
1173      }
1174
1175      function handleCondition(element, id, condition) {
1176        var shouldShow = isVisible(id, condition);
1177        if (element) {
1178          if (shouldShow) {
1179            element.classList.remove("umbraco-forms-hidden");
1180          } else {
1181            element.classList.add("umbraco-forms-hidden");
1182          }
1183        }
1184      }
1185
1186      for (pageId in self.pageButtonConditions) {
1187        if (
1188          Object.prototype.hasOwnProperty.call(
1189            self.pageButtonConditions,
1190            pageId
1191          )
1192        ) {
1193          var pageElem = document.getElementById(pageId);
1194          if (pageElem) {
1195            handleCondition(
1196              pageElem.querySelector(
1197                "input[name='__next'], button[name='__next'], input[data-form-navigate='next'], button[data-form-navigate='next']"
1198              ),
1199              pageId,
1200              self.pageButtonConditions[pageId],
1201              "Page"
1202            );
1203          }
1204        }
1205      }
1206
1207      for (fsId in self.fieldsetConditions) {
1208        if (
1209          Object.prototype.hasOwnProperty.call(self.fieldsetConditions, fsId)
1210        ) {
1211          htmlFieldId = self.formElementHtmlIdPrefix + fsId;
1212          handleCondition(
1213            document.getElementById(htmlFieldId),
1214            fsId,
1215            self.fieldsetConditions[fsId],
1216            "Fieldset"
1217          ); // sadly we cant use querySelector with current mark-up (would need to prefix IDs)
1218        }
1219      }
1220
1221      for (fieldId in self.fieldConditions) {
1222        if (
1223          Object.prototype.hasOwnProperty.call(self.fieldConditions, fieldId)
1224        ) {
1225          htmlFieldId = self.formElementHtmlIdPrefix + fieldId;
1226          if (document.getElementById(htmlFieldId)) {
1227            handleCondition(
1228              document
1229                .getElementById(htmlFieldId)
1230                .closest(".umbraco-forms-field"), // sadly we cant use querySelector with current mark-up (would need to prefix IDs)
1231              fieldId,
1232              self.fieldConditions[fieldId],
1233              "Field"
1234            );
1235          }
1236        }
1237      }
1238    };
1239
1240    return self;
1241  }
1242})();

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.