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.querySelectorAll("input[type='submit']").forEach((item) => { 84 item.setAttribute("onclick", "return false;"); 85 }); 86 87 form.updating = true; 88 89 var formData = new FormData(form); 90 formData.append("kentico_update_form", "true"); 91 92 var focus = nextFocusElement || document.activeElement; 93 94 var onResponse = function (event) { 95 if (!event.target.response.data) { 96 var selectionStart = selectionEnd = null; 97 if (focus && (focus.type === "text" || focus.type === "search" || focus.type === "password" || focus.type === "tel" || focus.type === "url")) { 98 selectionStart = focus.selectionStart;
99 selectionEnd = focus.selectionEnd; 100 } 101 102 var currentScrollPosition = window.scrollY; 103 var element = document.getElementById(elementIdSelector); 104 105 if (useJQuery()) { 106 $(element).replaceWith(event.target.responseText); 107 } else { 108 renderMarkup(event.target.responseText, element); 109 } 110 window.scrollTo(0, currentScrollPosition); 111 112 if (focus.id) { 113 var newInput = document.getElementById(focus.id); 114 if (newInput) { 115 newInput.focus(); 116 setCaretPosition(newInput, selectionStart, selectionEnd); 117 } 118 } 119 } 120 }; 121 122 createRequest(form, formData, onResponse); 123 } 124 125 function submitForm(event) { 126 event.preventDefault(); 127 var form = event.target; 128 var formData = new FormData(form); 129 130 var onResponse = function(event) { 131 var contentType = event.target.getResponseHeader("Content-Type"); 132 133 if (contentType.indexOf("application/json") === -1) { 134 var currentScrollPosition = window.scrollY; 135 var replaceTargetId = form.getAttribute("data-ktc-ajax-update"); 136 137 var element = document.getElementById(replaceTargetId); 138 139 if (useJQuery()) { 140 $(element).replaceWith(event.target.response); 141 } else { 142 renderMarkup(event.target.response, element) 143 } 144 145 window.scrollTo(0, currentScrollPosition); 146 } else { 147 var json = JSON.parse(event.target.response); 148 149 location.href = json.redirectTo; 150 } 151 }; 152 153 createRequest(form, formData, onResponse); 154 } 155 156 const renderMarkup = (markup, targetElement) => { 157 var elementFromMarkup = createElementFromMarkup(markup); 158 159 targetElement.parentNode.replaceChild(elementFromMarkup, targetElement); 160 const scripts = elementFromMarkup.querySelectorAll("script"); 161 Array.prototype.forEach.call(scripts, (scriptElement) => { 162 const parent = scriptElement.parentNode; 163 const temp = document.createElement("script"); 164 [...scriptElement.attributes].forEach((attr) => { 165 temp.setAttribute(attr.name, attr.value); 166 }); 167 168 temp.innerHTML = scriptElement.innerHTML; 169 parent.replaceChild(temp, scriptElement); 170 scriptElement.remove(); 171 }); 172 }; 173 174 function createElementFromMarkup(markup) { 175 var element = document.createElement("div"); 176 177 element.innerHTML = markup; 178 179 return element.firstElementChild; 180 } 181 182 function createRequest(form, formData, onResponse) { 183 var xhr = new XMLHttpRequest(); 184 185 xhr.addEventListener("load", onResponse); 186 187 xhr.open("POST", form.action); 188 xhr.send(formData); 189 } 190 191 /** 192 * Sets the caret position. 193 * @param {HTMLInputElement} input Input element in which the caret position should be set. 194 * @param {number} selectionStart Selection start position. 195 * @param {number} selectionEnd Selection end position. 196 */ 197 function setCaretPosition(input, selectionStart, selectionEnd) { 198 if (selectionStart === null && selectionEnd === null) { 199 return; 200 } 201 202 if (input.setSelectionRange) { 203 input.setSelectionRange(selectionStart, selectionEnd); 204 } 205 } 206 207 function debounce(func, wait, immediate) { 208 var timeout; 209 210 return function () { 211 var context = this, 212 args = arguments; 213 214 var later = function () { 215 timeout = null; 216 217 if (!immediate) { 218 func.apply(context, args); 219 } 220 }; 221 222 var callNow = immediate && !timeout; 223 clearTimeout(timeout); 224 timeout = setTimeout(later, wait || 200); 225 226 if (callNow) {
227 func.apply(context, args); 228 } 229 }; 230 } 231 232 function useJQuery() { 233 return window.kentico.hasOwnProperty("builder") ? window.kentico.builder.useJQuery : false; 234 } 235 236 return { 237 registerEventListeners: registerEventListeners, 238 updateForm: updateForm, 239 submitForm: submitForm 240 }; 241}());
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.