1(function () { 2 'use strict'; 3 4 // Check if required global localization array exists 5 if (typeof data_arr === 'undefined') { 6 return; 7 } 8 9 // Map to keep track of initial form field values for resetting 10 const initialFormValues = new Map(); 11 12 /** 13 * Resets form to its initial state using stored initial values. 14 */ 15 const resetForm = function(formElm) { 16 const initial = initialFormValues.get(formElm); 17 if (!initial) return; 18 19 initial.forEach(field => { 20 if (field.type === 'checkbox' || field.type === 'radio') { 21 field.element.checked = field.checked; 22 } else { 23 field.element.value = field.value; 24 } 25 }); 26 27 // Reset file inputs explicitly 28 formElm.querySelectorAll('input[type="file"]').forEach(file => { 29 file.value = ''; 30 }); 31 }; 32 33 /** 34 * Sanitizes values and converts newlines to HTML breaks. 35 */ 36 const sanitizeText = function(textVal) { 37 if (!textVal) return ''; 38 return textVal 39 .replace(/&/g, '&') 40 .replace(/</g, '<') 41 .replace(/>/g, '>') 42 .replace(/"/g, '"') 43 .replace(/'/g, ''') 44 .replace(/`/g, '`') 45 .replace(/\r?\n/g, '<br>'); 46 }; 47 48 /** 49 * Extracts text templates wrapped in special layout classes. 50 */ 51 const getTextSet = function(inputObj) { 52 const textSetObj = inputObj.closest('.text-set-contactform7'); 53 if (!textSetObj) { 54 return null; 55 } 56 const clone = textSetObj.cloneNode(true); 57 const inputToReplaces = clone.querySelectorAll('input, select'); 58 inputToReplaces.forEach(input => { 59 const name = input.getAttribute('name'); 60 if (name) { 61 const cleanName = name.replace('[]', ''); 62 const placeholder = document.createTextNode(`{%${cleanName}%}
62`); 63 if (input.parentNode) { 64 input.parentNode.replaceChild(placeholder, input); 65 } 66 } 67 }); 68 return clone.textContent; 69 }; 70 71 const splitter = ', '; 72 73 /** 74 * Closes confirmation window and restores form visibility. 75 */ 76 const wpcf7cp_edit = function(formElm) { 77 if (!formElm) return; 78 formElm.classList.remove('wpcf7cp-form-hide'); 79 const container = formElm.closest('div.wpcf7'); 80 if (container) { 81 const cnf = container.querySelector('#wpcf7cpcnf'); 82 if (cnf) cnf.remove(); 83 } 84 }; 85 86 /** 87 * Sends form submit action from the confirmation screen. 88 */ 89 const wpcf7cp_mail_send = function(formElm) { 90 if (!formElm) return; 91 const submitButton = formElm.querySelector('input.wpcf7-submit, button.wpcf7-submit'); 92 const responseOutput = formElm.querySelector('div.wpcf7-response-output'); 93 94 const onSubmitComplete = function(event) { 95 if (event.target === formElm) { 96 // Remove progress spinner 97 formElm.querySelectorAll('.wpcf7cp-progress-cover, .wpcf7cp-progress-content').forEach(p => p.remove()); 98 99 // Restore validation/result message visibility 100 if (responseOutput) { 101 responseOutput.classList.remove('wpcf7cp-force-hide'); 102 } 103 104 // Reset form values to initial state 105 resetForm(formElm); 106 107 // Update status flag back to input state 108 const statusInput = formElm.querySelector('input[name="_wpcf7cp"]'); 109 if (statusInput) statusInput.value = 'status_input'; 110 111 // Close confirmation box 112 wpcf7cp_edit(formElm); 113 114 // Scroll to submission message 115 if (responseOutput) { 116 setTimeout(() => { 117 const rect = responseOutput.getBoundingClientRect(); 118 const scrollToPosi = window.pageYOffset + rect.top - (window.innerHeight / 2); 119 window.scrollTo({ 120 top: scrollToPosi, 121 behavior: 'smooth' 122 }); 123 }, 100); 124 } 125 126 // Clean up listeners 127 window.removeEventListener('wpcf7submit', onSubmitComplete); 128 window.removeEventListener('wpcf7mailfailed', onSubmitComplete); 129 } 130 }; 131 132 window.addEventListener('wpcf7submit', onSubmitComplete); 133 window.addEventListener('wpcf7mailfailed', onSubmitComplete); 134 135 // Render progress overlay 136 const cover = document.createElement('div'); 137 cover.className = 'wpcf7cp-progress-cover'; 138 const content = document.createElement('div'); 139 content.className = 'wpcf7cp-progress-content'; 140 const p = document.createElement('p'); 141 p.textContent = 'Progress...'; 142 content.appendChild(p); 143 144 formElm.appendChild(cover); 145 formElm.appendChild(content); 146 147 // Trigger native submission click 148 if (submitButton) { 149 submitButton.click(); 150 } 151 }; 152 153 /** 154 * Resolves display label (title) for a given form element. 155 */ 156 const wpcf7cp_get_title = function(element) { 157 let title = null; 158 159 const makeTitle = function(titleObj) { 160 if (!titleObj) return ''; 161 const clone = titleObj.cloneNode(true); 162 clone.querySelectorAll('.avoid-confirm').forEach(elm => elm.remove()); 163 // Exclude input elements, selects, textareas, and option items from group label text 164 clone.querySelectorAll('.wpcf7-list-item, input, select, textarea').forEach(elm => elm.remove()); 165 return clone.textContent.trim(); 166 }; 167 168 const thisObj = element; 169 const inputType = thisObj.getAttribute('type'); 170 const tagName = thisObj.tagName; 171 172 // Check for fieldset legend first for check/radio inputs 173 if (inputType === 'checkbox' || inputType === 'radio') { 174 const fieldset = thisObj.closest('fieldset'); 175 if (fieldset) { 176 const legend = fieldset.querySelector('legend'); 177 if (legend) { 178 title = makeTitle(legend); 179 } 180 } 181 182 // Fallback for classic checkbox/radio: Find the outer label wrapping the group 183 if (!title) { 184 let ancestor = thisObj.parentElement; 185 const ancestorLabels = []; 186 while (ancestor && ancestor.tagName !== 'FORM') { 187 if (ancestor.tagName === 'LABEL') { 188 ancestorLabels.push(ancestor); 189 } 190 ancestor = ancestor.parentElement; 191 } 192 if (ancestorLabels.length > 1) { 193 title = makeTitle(ancestorLabels[ancestorLabels.length - 1]); 194 } 195 } 196 } 197 198 if (!title) { 199 const nameAttr = thisObj.getAttribute('name'); 200 if (!nameAttr) return null; 201 const nameVal = nameAttr.replace(/\[\]$/, ''); 202 203 const formElm = thisObj.closest('form'); 204 const root = formElm || document; 205 206 // Specification (2): Check label with matching 'for' attribute 207 if (inputType !== 'radio') { 208 const labelObjWithForAttr = root.querySelector(`label[for="${nameVal}"]`); 209 if (labelObjWithForAttr) { 210 title = makeTitle(labelObjWithForAttr); 211 } 212 213 // Specification (1): Check parent label tag wrapper (except for checkbox) 214 if (!title && inputType !== 'checkbox') { 215 const closestLabel = thisObj.closest('label'); 216 if (closestLabel) { 217 if (tagName === 'SELECT') { 218 const clone = closestLabel.cloneNode(true); 219 clone.querySelectorAll('option').forEach(opt => opt.remove()); 220 title = makeTitle(clone); 221 } else { 222 title = makeTitle(closestLabel); 223 } 224 } 225 } 226 } 227 228 // Specification (4): Explicit class mapping (.title-contactform7.for-name) 229 if (!title) { 230 const classLabel = root.querySelector(`.title-contactform7.for-${nameVal}`); 231 if (classLabel) { 232 title = makeTitle(classLabel); 233 } 234 } 235 236 // Specification (3): Adjacent table cells matching via .title-contactform7 237 if (!title) { 238 const closestTr = thisObj.closest('tr'); 239 if (closestTr) { 240 const labelInSameTr = closestTr.querySelector('.title-contactform7'); 241 if (labelInSameTr) { 242 title = makeTitle(labelInSameTr); 243 } 244 } 245 } 246 247 // Specification (1) Fallback: Parent label tag for single checkboxes (e.g. policy acceptance) 248 if (!title && inputType === 'checkbox') { 249 const closestLabel = thisObj.closest('label'); 250 if (closestLabel) { 251 title = makeTitle(closestLabel); 252 } 253 } 254 } 255 256 return title; 257 }; 258 259 /** 260 * Builds and displays the confirmation page on event trigger. 261 */ 262 const wpcf7cp_confirm = function(unit_tag) { 263 const PATH_CODE = /[\\\/]/; 264 265 // Query the specific form matching the active unit_tag 266 const unitTagInput = document.querySelector(`form.wpcf7-form input[name="_wpcf7_unit_tag"][value="${unit_tag}"]`); 267 if (!unitTagInput) return; 268 const formElm = unitTagInput.closest('form'); 269 if (!formElm) return; 270 const wpcf7Container = formElm.closest('div.wpcf7'); 271 if (!wpcf7Container) return; 272 273 // Change status input to confirm state 274 const statusInput = formElm.querySelector('input[name="_wpcf7cp"]'); 275 if (statusInput) statusInput.value = 'status_confirm'; 276 277 // Hide CF7 feedback box temporarily 278 const responseOutput = formElm.querySelector('div.wpcf7-response-output'); 279 if (responseOutput) responseOutput.classList.add('wpcf7cp-force-hide'); 280 281 const noTitleDammyStr = 'CF7CfmPlsNoTitle'; 282 const noTitleOuterHTMLs = []; 283 const dispList = {}; 284 285 // Parse all input fields in this form 286 const inputs = formElm.querySelectorAll('input, select, textarea');
287 inputs.forEach(elm => { 288 // Skip hidden elements, custom avoids, and buttons 289 const style = window.getComputedStyle(elm); 290 const isVisible = !!(elm.offsetWidth || elm.offsetHeight || elm.getClientRects().length); 291 if (!isVisible || style.visibility === 'hidden' || elm.classList.contains('avoid-confirm')) { 292 return; 293 } 294 295 const tagName = elm.tagName; 296 const type = elm.type; 297 const name = elm.getAttribute('name'); 298 if (!name) return; 299 const cleanName = name.replace('[]', ''); 300 301 let title = null; 302 let val = null; 303 304 if (tagName === 'INPUT') { 305 if (['submit', 'button', 'hidden', 'image'].includes(type)) { 306 return; 307 } 308 if (type === 'radio' || type === 'checkbox') { 309 if (!elm.checked) return; 310 title = wpcf7cp_get_title(elm); 311 val = elm.value; 312 313 // Translate piped values if defined in localized CF7 pipes map 314 if (val && typeof wpcf7cp_pipes !== 'undefined' && wpcf7cp_pipes[cleanName] && typeof wpcf7cp_pipes[cleanName][val] !== 'undefined') { 315 val = wpcf7cp_pipes[cleanName][val]; 316 } 317 318 // Use the localized check message (configurable site-wide via PHP filter) 319 const checkedMsg = data_arr.checked_msg; 320 321 if (val === '1' || val === 'on') { 322 val = checkedMsg; 323 } else if (type === 'checkbox') { 324 // Collapse value to checkedMsg if it's a single checkbox (e.g. policy acceptance) 325 // and the value text matches or overlaps the label/title text 326 const siblings = formElm.querySelectorAll(`input[type="checkbox"][name="${elm.name}"]`); 327 if (siblings.length === 1 && title && (title.indexOf(val) !== -1 || val.indexOf(title) !== -1)) { 328 val = checkedMsg; 329 } 330 } 331 } else if (type === 'file') { 332 title = wpcf7cp_get_title(elm); 333 val = elm.value.split(PATH_CODE).pop(); 334 } else { 335 if (elm.classList.contains('wpcf7-quiz')) { 336 return; 337 } 338 title = wpcf7cp_get_title(elm); 339 val = sanitizeText(elm.value); 340 341 // Translate piped values if defined in localized CF7 pipes map 342 if (val && typeof wpcf7cp_pipes !== 'undefined' && wpcf7cp_pipes[cleanName] && typeof wpcf7cp_pipes[cleanName][val] !== 'undefined') { 343 val = wpcf7cp_pipes[cleanName][val]; 344 } 345 } 346 } else if (tagName === 'TEXTAREA') { 347 title = wpcf7cp_get_title(elm); 348 val = sanitizeText(elm.value); 349 350 // Translate piped values if defined in localized CF7 pipes map 351 if (val && typeof wpcf7cp_pipes !== 'undefined' && wpcf7cp_pipes[cleanName] && typeof wpcf7cp_pipes[cleanName][val] !== 'undefined') { 352 val = wpcf7cp_pipes[cleanName][val]; 353 } 354 } else if (tagName === 'SELECT') { 355 title = wpcf7cp_get_title(elm); 356 if (elm.multiple) { 357 val = Array.from(elm.selectedOptions).map(opt => opt.value); 358 } else { 359 val = elm.value; 360 } 361 362 // Translate piped values if defined in localized CF7 pipes map 363 if (val && typeof wpcf7cp_pipes !== 'undefined' && wpcf7cp_pipes[cleanName]) { 364 if (Array.isArray(val)) { 365 val = val.map(v => typeof wpcf7cp_pipes[cleanName][v] !== 'undefined' ? wpcf7cp_pipes[cleanName][v] : v); 366 } else if (typeof wpcf7cp_pipes[cleanName][val] !== 'undefined') { 367 val = wpcf7cp_pipes[cleanName][val]; 368 } 369 } 370 } 371 372 // Fallback for unlabeled elements 373 if (!title) { 374 const parentP = elm.closest('p'); 375 const outerHTML = parentP ? parentP.outerHTML : ''; 376 let k = noTitleOuterHTMLs.indexOf(outerHTML); 377 if (k === -1 && outerHTML) { 378 noTitleOuterHTMLs.push(outerHTML); 379 k = noTitleOuterHTMLs.length - 1; 380 } 381 title = noTitleDammyStr + (k !== -1 ? k : 0); 382 } 383 384 if (title !== null && val !== null) { 385 if (!dispList[title]) { 386 dispList[title] = { 387 values: {}, 388 textSet: getTextSet(elm) 389 }; 390 } 391 if (typeof dispList[title]['values'][cleanName] === 'undefined') { 392 dispList[title]['values'][cleanName] = ''; 393 } else { 394 dispList[title]['values'][cleanName] += splitter; 395 } 396 dispList[title]['values'][cleanName] += (Array.isArray(val) ? val.join(splitter) : val); 397 } 398 }); 399 400 // Hide input fields form 401 formElm.classList.add('wpcf7cp-form-hide'); 402 403 // Clear existing confirmation container if any 404 const existingCnf = wpcf7Container.querySelector('#wpcf7cpcnf'); 405 if (existingCnf) existingCnf.remove(); 406 407 // Build confirmation layout 408 const wrapperDiv = document.createElement('div'); 409 wrapperDiv.id = 'wpcf7cpcnf'; 410 411 const table = document.createElement('table'); 412 wrapperDiv.appendChild(table); 413 414 for (const key in dispList) { 415 let keyToShow = key; 416 if (new RegExp('^' + noTitleDammyStr + '[0-9]+$').test(keyToShow)) { 417 keyToShow = ''; 418 } 419 420 const tr = document.createElement('tr'); 421 const th = document.createElement('th'); 422 const pTitle = document.createElement('p'); 423 pTitle.textContent = keyToShow; 424 th.appendChild(pTitle); 425 tr.appendChild(th); 426 427 const td = document.createElement('td'); 428 let innerHTML = ''; 429 if (!dispList[key]['textSet']) { 430 let mergedVal = ''; 431 for (const k in dispList[key]['values']) { 432 if (mergedVal !== '') { 433 mergedVal += splitter; 434 } 435 mergedVal += dispList[key]['values'][k]; 436 } 437 innerHTML = '<p>' + mergedVal + '</p>'; 438 } else { 439 innerHTML = dispList[key]['textSet']; 440 for (const k in dispList[key]['values']) { 441 innerHTML = innerHTML.replace(new RegExp('\{%' + k + '%\}', 'g'), String(dispList[key]['values'][k])); 442 } 443 } 444 td.innerHTML = innerHTML; 445 tr.appendChild(td); 446 table.appendChild(tr); 447 } 448
449 // Render back & submit controls 450 const btnsDiv = document.createElement('div'); 451 btnsDiv.className = 'wpcf7cp-btns'; 452 453 const editBtn = document.createElement('button'); 454 editBtn.type = 'button'; 455 editBtn.className = 'wpcf7-form-control wpcf7cp-cfm-edit-btn'; 456 editBtn.textContent = data_arr.cfm_btn_edit; 457 editBtn.addEventListener('click', () => { 458 wpcf7cp_edit(formElm); 459 if (statusInput) statusInput.value = 'status_input'; 460 }); 461 462 const submitBtn = document.createElement('button'); 463 submitBtn.type = 'button'; 464 submitBtn.className = 'wpcf7-form-control wpcf7-submit wpcf7cp-cfm-submit-btn'; 465 submitBtn.textContent = data_arr.cfm_btn_mail_send; 466 submitBtn.addEventListener('click', () => { 467 wpcf7cp_mail_send(formElm); 468 }); 469 470 btnsDiv.appendChild(editBtn); 471 btnsDiv.appendChild(submitBtn); 472 wrapperDiv.appendChild(btnsDiv); 473 wpcf7Container.appendChild(wrapperDiv); 474 475 // Smooth scroll to top of confirmation box 476 const rect = wpcf7Container.getBoundingClientRect(); 477 const absoluteTop = window.pageYOffset + rect.top; 478 const popupHeight = wrapperDiv.offsetHeight; 479 const windowHeight = document.documentElement.clientHeight; 480 481 let topOffset = 50; 482 if (popupHeight < windowHeight) { 483 topOffset = Math.round((windowHeight - popupHeight) / 2); 484 } 485 486 window.scrollTo({ 487 top: absoluteTop - topOffset, 488 behavior: 'smooth' 489 }); 490 }; 491 492 /** 493 * Initializes configuration fields, labels and states. 494 */ 495 const init = function() { 496 // Append hidden status parameter if missing 497 document.querySelectorAll('input[name="_wpcf7"]').forEach(input => { 498 const form = input.closest('form'); 499 if (form && !form.querySelector('input[name="_wpcf7cp"]')) { 500 const hidden = document.createElement('input'); 501 hidden.type = 'hidden'; 502 hidden.name = '_wpcf7cp'; 503 hidden.value = 'status_input'; 504 if (input.parentNode) { 505 input.parentNode.insertBefore(hidden, input.nextSibling); 506 } 507 } 508 }); 509 510 // Set custom confirmation button labels 511 document.querySelectorAll('form.wpcf7-form input.wpcf7-submit').forEach(btn => { 512 btn.value = data_arr.cfm_btn; 513 }); 514 document.querySelectorAll('form.wpcf7-form button.wpcf7-submit').forEach(btn => { 515 btn.textContent = data_arr.cfm_btn; 516 }); 517 518 // Store initial form values for resetting later 519 document.querySelectorAll('form.wpcf7-form').forEach(form => { 520 if (!initialFormValues.has(form)) { 521 const values = []; 522 form.querySelectorAll('input, select, textarea').forEach(elm => { 523 const name = elm.getAttribute('name'); 524 if (name) { 525 if (elm.type === 'checkbox' || elm.type === 'radio') { 526 values.push({ element: elm, checked: elm.checked, type: elm.type }); 527 } else { 528 values.push({ element: elm, value: elm.value, type: elm.type }); 529 } 530 } 531 }); 532 initialFormValues.set(form, values); 533 } 534 }); 535 }; 536 537 // Safely trigger initiation on document load 538 if (document.readyState === 'loading') { 539 document.addEventListener('DOMContentLoaded', init); 540 } else { 541 init(); 542 } 543 544 // Monitor CF7 submissions globally 545 document.addEventListener('wpcf7submit', function(event) { 546 if ('wpcf7cp_confirm' === event.detail.status) { 547 wpcf7cp_confirm(event.detail.unitTag); 548 } 549 }, false); 550 551})();
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.