PageSourceSearch

https://tinyvoice.com/wp-content/plugins/confirm-plus-contact-form-7/assets/js/scripts.js?ver=2.0.3.1

js tinyvoice.com collected 2026-10-02 19:10:09 UTC 21,918 bytes, 551 lines download raw bytes

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, '&lt;')
41            .replace(/>/g, '&gt;')
42            .replace(/"/g, '&quot;')
43            .replace(/'/g, '&#39;')
44            .replace(/`/g, '&#x60;')
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.