1window.kentico = window.kentico || {}; 2 3window.kentico.updatableFormHelper = (function () { 4 5 // Duration for which user must not type anything in order for the form to be submitted. 6 var KEY_UP_DEBOUNCE_DURATION = 800; 7 8 /** 9 * Registers event listeners and updates the form upon changes of the form data. 10 * @param {object} config Configuration object. 11 * @param {string} config.formId ID of the form element. 12 * @param {string} config.targetAttributeName Data attribute of element that is used to be replaced by HTML received from the server. 13 * @param {string} config.unobservedAttributeName Data attribute which marks an input as not being observed for changes. 14 */ 15 function registerEventListeners(config) { 16 if (!config || !config.formId || !config.targetAttributeName || !config.unobservedAttributeName) { 17 throw new Error("Invalid configuration passed."); 18 } 19 20 var writeableTypes = ["email", "number", "password", "search", "tel", "text", "time"]; 21 22 var observedForm = document.getElementById(config.formId); 23 if (!(observedForm && observedForm.getAttribute(config.targetAttributeName))) { 24 return; 25 } 26 27 for (i = 0; i < observedForm.length; i++) { 28 var observedFormElement = observedForm.elements[i]; 29 var handleElement = !observedFormElement.hasAttribute(config.unobservedAttributeName) && 30 observedFormElement.type !== "submit"; 31 32 if (handleElement) { 33 var isWriteableElement = (observedFormElement.tagName === "INPUT" && writeableTypes.indexOf(observedFormElement.type) !== -1) || observedFormElement.tagName === "TEXTAREA"; 34 35 if (isWriteableElement) { 36 observedFormElement.previousValue = observedFormElement.value; 37 38 observedFormElement.addEventListener("keyup", debounce(function (e) { 39 setTimeout(function () { 40 if (!observedForm.updating && e.target.previousValue !== e.target.value) { 41 observedForm.keyupUpdate = true; 42 updateForm(observedForm, e.target); 43 } 44 }, 0); 45 }, KEY_UP_DEBOUNCE_DURATION)); 46 47 observedFormElement.addEventListener("blur", function (e) { 48 setTimeout(function () { 49 if (!observedForm.updating && e.target.previousValue !== e.target.value) { 50 updateForm(observedForm, e.relatedTarget); 51 } 52 }, 0); 53 }); 54 } 55 56 observedFormElement.addEventListener("change", function (e) { 57 setTimeout(function () { 58 if (!observedForm.updating) { 59 updateForm(observedForm); 60 } 61 }, 0); 62 }); 63 } 64 } 65 } 66 67 /** 68 * Updates the form markup. 69 * @param {HTMLElement} form Element of the form to update. 70 * @param {Element} nextFocusElement Element which shout get focus after update. 71 */ 72 function updateForm(form, nextFocusElement) { 73 if (!form) { 74 return; 75 } 76 77 // If form is not updatable then do nothing 78 var elementIdSelector = form.getAttribute("data-ktc-ajax-update"); 79 if (!elementIdSelector) { 80 return; 81 } 82 83 $(form).find("input[type='submit']").attr("onclick", "return false;"); 84 form.updating = true; 85 86 var formData = new FormData(form); 87 formData.append("kentico_update_form", "true"); 88 89 var focus = nextFocusElement || document.activeElement; 90 91 var onResponse = function (event) { 92 if (!event.target.response.data) { 93 var selectionStart = selectionEnd = null; 94 if (focus && (focus.type === "text" || focus.type === "search" || focus.type === "password" || focus.type === "tel" || focus.type === "url")) { 95 selectionStart = focus.selectionStart;
96 selectionEnd = focus.selectionEnd; 97 } 98 99 var currentScrollPosition = $(window).scrollTop(); 100 $(elementIdSelector).replaceWith(event.target.responseText); 101 $(window).scrollTop(currentScrollPosition); 102 103 if (focus.id) { 104 var newInput = document.getElementById(focus.id); 105 if (newInput) { 106 newInput.focus(); 107 setCaretPosition(newInput, selectionStart, selectionEnd); 108 } 109 } 110 } 111 }; 112 113 createRequest(form, formData, onResponse); 114 } 115 116 function submitForm(event) { 117 event.preventDefault(); 118 var form = event.target; 119 var formData = new FormData(form); 120 121 var onResponse = function (event) { 122 var contentType = event.target.getResponseHeader("Content-Type"); 123 124 if (contentType.indexOf("application/json") === -1) { 125 var currentScrollPosition = $(window).scrollTop(); 126 var replaceTarget = form.getAttribute("data-ktc-ajax-update"); 127 128 const $replaceTarget = $(replaceTarget); 129 130 eventReservationRedirect(event.target.response) 131 132 $replaceTarget.replaceWith(event.target.response); 133 134 $(window).scrollTop(currentScrollPosition); 135 } else { 136 var json = JSON.parse(event.target.response); 137 138 location.href = json.redirectTo; 139 } 140 }; 141 142 createRequest(form, formData, onResponse); 143 } 144 145 function createRequest(form, formData, onResponse) { 146 var xhr = new XMLHttpRequest(); 147 148 xhr.addEventListener("load", onResponse); 149 150 xhr.open("POST", form.action); 151 xhr.send(formData); 152 } 153 154 /** 155 * Sets the caret position. 156 * @param {HTMLInputElement} input Input element in which the caret position should be set. 157 * @param {number} selectionStart Selection start position. 158 * @param {number} selectionEnd Selection end position. 159 */ 160 function setCaretPosition(input, selectionStart, selectionEnd) { 161 if (selectionStart === null && selectionEnd === null) { 162 return; 163 } 164 165 if (input.setSelectionRange) { 166 input.setSelectionRange(selectionStart, selectionEnd); 167 } 168 } 169 170 function debounce(func, wait, immediate) { 171 var timeout; 172 173 return function () { 174 var context = this, 175 args = arguments; 176 177 var later = function () { 178 timeout = null; 179 180 if (!immediate) { 181 func.apply(context, args); 182 } 183 }; 184 185 var callNow = immediate && !timeout; 186 clearTimeout(timeout); 187 timeout = setTimeout(later, wait || 200); 188 189 if (callNow) { 190 func.apply(context, args); 191 } 192 }; 193 } 194 195 function eventReservationRedirect(response) { 196 const virtualDOM = document.createElement("div") 197 virtualDOM.innerHTML = response 198 const dataElement = virtualDOM.querySelector("[data-event-reservation-data]") 199 200 if (!dataElement) { 201 return 202 } 203 204 const url = dataElement.getAttribute("data-url") 205 206 if (!url) { 207 return 208 } 209 210 const redirectUrl = new URL(url, window.location.origin) 211 212 window.location.href = redirectUrl.href 213 } 214 215 return { 216 registerEventListeners: registerEventListeners, 217 updateForm: updateForm, 218 submitForm: submitForm 219 }; 220}());
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.