PageSourceSearch

https://www.chargeamps.com/app/plugins/controller-fields-for-conta…/controllable-fields.js?ver=1787139603

js chargeamps.com collected 2026-10-02 05:32:28 UTC 24,942 bytes, 448 lines download raw bytes

1/*
2    Name: controllable-fields.js
3    Author: AuRise Creative | https://aurisecreative.com
4    Last Modified: August 31, 2024 @ 22:32
5
6    To use this feature...
7
8    1. Add a "au-cf7-controller" class to the radio, checkbox, select, or number/range HTML elements that will be controlling others
9        - Checkbox: displays the controlled fields when checked and hides when unchecked.
10        - Radio:    displays the controlled fields when checked and hides the rest.
11        - Select:   displays the controlled fields when they match the value that is selected and hides the rest.
12        - Number:   displays the controlled fields based on number ranges set in the controlled element's values.
13    2. Controlled fields should have a data-controller attribute on its wrapping element set to the ID attribute of its controller
14        within the same form. It can have multiple controllers, with ID using pipes (|) to separate them.
15    3. Controlled fields should have a "au-cf7-hidden-by-controller" class added to its wrapping element to hide it by default. This
16        feature simply toggles that class on/off, so you'll need CSS to actually hide it based on that class.
17    4. Controlled fields controlled by a radio button, select field, or number field, should have a `data-values` attribute set to a
18        pipe separated list of the values used to display it on the wrapping element. Values can include operations such as >, >=,
19        <, <=, !=, or *. The operation = is assumed when no comparison is found.
20    5. If it has multiple controllers, then there should be a `data-{controller ID}-values` attribute that sets the values for that
21        specific controller.
22    5. If the controlled field should be required when displayed, instead of adding the required attribute to the input/select field,
23        add the "required-when-visible" to the class attribute.
24    6. It is possible to nest controllers.
25    7. Controlled fields with multiple controllers are only hidden if all controllers evaluate to no matches. Otherwise, it will
26        remain visible. Multiple controllers are treated as an OR comparison, meaning at least one controller must be active for
27        the controlled field to display. Nest them to treat them as an AND operation.
28*/
29window['$'] = window['$'] || jQuery.noConflict();
30const aurise_controllable_fields_cf7 = {
31    version: '2024.04.27.10.41',
32    init: function() {
33        // Controllable fields
34        let click_controllers = '.wpcf7 form input[type=checkbox].au-cf7-controller,.wpcf7 form input[type=radio].au-cf7-controller',
35            select_controllers = '.wpcf7 form select.au-cf7-controller',
36            text_controllers = '.wpcf7 form input[type=text].au-cf7-controller,.wpcf7 form input[type=email].au-cf7-controller,.wpcf7 form input[type=hidden].au-cf7-controller,.wpcf7 form input[type=password].au-cf7-controller,.wpcf7 form input[type=search].au-cf7-controller,.wpcf7 form input[type=tel].au-cf7-controller,.wpcf7 form input[type=url].au-cf7-controller',
37            interactive_controllers = '.wpcf7 form input[type=number].au-cf7-controller,.wpcf7 form input[type=range].au-cf7-controller',
38            controllers = $(click_controllers + ',' + select_controllers + ',' + interactive_controllers + ',' + text_controllers); // All controllers
39        if (controllers.length) {
40
41            //Add controllable field listeners
42            $(click_controllers).on('click', aurise_controllable_fields_cf7.toggleHandler);
43            $(select_controllers).on('change', aurise_controllable_fields_cf7.toggleHandler);
44            $(text_controllers).on('change keyup blur', aurise_controllable_fields_cf7.toggleHandler);
45            $(interactive_controllers).on('change keyup blur mousemove mousedown mouseup', aurise_controllable_fields_cf7.toggleHandler);
46
47            // Initialize default states
48            let c1 = 1;
49            controllers.each(function() {
50                let $controller = $(this),
51                    controller_name = $controller.attr('name');
52
53                // If this controller does not have an ID attribute, add a temporary one
54                let temp_id = false;
55                if ($controller.attr('id') === undefined) {
56                    temp_id = 'aurise-cf7-cf-temp-controller-id-' 
56+ controller_name + '-' + c1;
57                    $controller.attr('id', temp_id);
58                }
59
60                let id = $controller.attr('id'),
61                    cid = aurise_controllable_fields_cf7.getControllerId(this),
62                    $controlled = $('[data-controller*="' + (temp_id ? controller_name : cid) + '"]');
63                if ($controlled.length) {
64                    if (temp_id) {
65                        $controlled.attr('data-controller', $controlled.attr('data-controller').replace(controller_name, id));
66                    }
67                    let controlled_value = $controller.is('input[type=checkbox]') ? aurise_controllable_fields_cf7.getCheckbox($controller) : $controller.val(),
68                        ariaControls = [];
69                    aurise_controllable_fields_cf7.toggleControlledFields(cid, id, controlled_value);
70                    // Update aria attributes
71                    $controlled.each(function() {
72                        let c2 = 1,
73                            $thisControlled = $(this),
74                            thisControlledId = $thisControlled.attr('id'),
75                            thisLabel = $thisControlled.attr('aria-labelledby');
76                        if (!thisControlledId) {
77                            // Generate a random ID
78                            thisControlledId = 'aurise-cf7-cf-temp-controlled-id-' + cid + '-' + c1 + '-' + c2;
79                            $thisControlled.attr('id', thisControlledId);
80                        }
81                        ariaControls.push(thisControlledId);
82                        if (!thisLabel) {
83                            thisLabel = id;
84                        } else {
85                            thisLabel += ' ' + id;
86                        }
87                        $thisControlled.attr({ 'role': 'group', 'aria-labelledby': thisLabel });
88                        c2++;
89                    });
90                    ariaControls = ariaControls.join(' ');
91                    $controller.attr({ 'aria-controls': ariaControls, 'aria-owns': ariaControls });
92                } else {
93                    console.warn('No controlled elements found for controller: ' + cid);
94                    // If I am a checkbox or radio button, look for my name object instead
95                }
96                $controller.trigger('controller_init');
97                c1++;
98            });
99        }
100    },
101    getControllerId: function(input) {
102        let $controller = $(input),
103            id = $controller.attr('id'),
104            id2 = $controller.attr('data-id');
105        // If there is a data-id attribute, return that
106        if (id2) {
107            return id2;
108        }
109        // If I don't have an id attribute, return my name attribute
110        if (!id || $controller.is('[type=radio]') || $controller.is('[type=checkbox]')) {
111            return $controller.attr('name').replace('[]', '');
112        }
113        return id; // Return my id attribute
114    },
115    getControllerById: function(cid) {
116        // The cid could be the id attribute or data-id attribute
117        let $controller = $('[data-id="' + cid + '"].au-cf7-controller');
118        if ($controller.length) {
119            return $controller;
120        }
121        $controller = $('#' + cid + '.au-cf7-controller');
122        if ($controller.length) {
123            return $controller;
124        }
125        return false;
126    },
127    getCheckbox: function(input) {
128        //Returns a true/false boolean value based on whether the checkbox is checked
129        let $input = $(input);
130        return ($input.is(':checked') || $input.prop('checked'));
131    },
132    toggleCheckbox: function(input, passedValue) {
133        //Changes a checkbox input to be checked or unchecked based on boolean parameter (or toggles if not included)
134        //Only changes it visually - it does not change any data in any objects
135        let $input = $(input),
136            value = passedValue;
137        if (typeof(value) != 'boolean' || value === undefined) {
138            value = !aurise_controllable_fields_cf7.getCheckbox($input);
139        }
140        if (value) {
141            $input.attr('checked', 'checked');
142            $input.prop('checked', true);
143        } else {
144            $input.removeAttr('checked');
145            $input.prop('checked', false);
146        }
147        input.trigger('toggled_checkbox');
148    },
149    number: {
150        changing: false,
151        check: false
152    },
153    toggleHandler: function(e) {
154        // Handle the number spinbox and ranged slider
155        if (typeof(e) == 'object') {
156            if (e.type == 'mousedown') {
157                // Mouse is being clicked down, turn it on
158                aurise_controllable_fields_cf7.number.changing = true;
159                aurise_controllable_fields_cf7.number.check = setInterval(function() {
160                    if (aurise_controllable_fields_cf7.number.changing) {
161                        aurise_controllable_fields_cf7.toggleHandler($(e.target).attr('id'));
162                    }
163                }, 500);
164            } else if (e.type == 'mouseup' && aurise_controllable_fields_cf7.number.changing) {
165                // Mouse was released after changing the number, turn it all off
166                aurise_controllable_fields_cf7.number.changing = false;
167                clearInterval(aurise_controllable_fields_cf7.number.check);
168                return;
169            } else if ((e.type == 'mousemove' && !aurise_controllable_fields_cf7.number.changing) || e.type == 'mouseup') {
170                // If mouse is moving but numbers aren't changing, or mouse was released but we don't care, bail
171                return;
172            }
173        }
174        let $controller = typeof(e) == 'string' ? $('#' + e) : $(e.target),
175            id = $controller.attr('id'),
176            cid = aurise_controllable_fields_cf7.getControllerId($controller);
177        aurise_controllable_fields_cf7.toggleControlledFields(cid, id, null);
178    },
179    toggleControlledFields: function(cid, id, forcedToggle) {
180        let $controller = $('#' + id);
181        if ($controller.length < 1) { console.warn('Controller #' + id + '" does not exist!'); return; }
182        let is_checkbox = $controller.is('[type=checkbox]'),
183            is_radio = $controller.is('[type=radio]'),
184            is_select = $controller.is('select'),
185            is_toggle = is_checkbox || is_radio,
186            toggle_value = is_toggle ? aurise_controllable_fields_cf7.getCheckbox($controller) : null,
187            is_expanded = false,
188            //is_number = $controller.is('[type=number]'),
189            $controlledObjs = $('[data-controller*="' + cid + '"]'),
190            $empty_controlled = false;
191        if ($controlledObjs.length < 1) { console.warn('No controlled elements found for controller: ' + cid); return; }
192        let controlled_value = forcedToggle === null || forcedToggle === undefined ? $controller.val() : forcedToggle,
193            count_displayed = 0;
194
195        // Loop through each controlled element; the value must match that of the input to display it
196        $controlledObjs.each(function(co, controlled) {
197            let $controlled = $(controlled),
198                // If I have multiple controllers, get the values for this specific controller
199                multiControllers = $controlled.attr('data-controller').indexOf('|') >= 0,
200                acceptedValues = multiControllers ? $controlled.attr('data-' + cid + '-values') : $controlled.attr('data-values'),
201                matches = 0,
202                displayMe = false;
203
204            //console.log(acceptedValues, toggle_value);
205            if (acceptedValues === '' || acceptedValues === undefined) {
206                $empty_controlled = $controlled;
207
208            }
209            matches += aurise_controllable_fields_cf7.compareLoop(acceptedValues, controlled_value, is_toggle, toggle_value);
210            if (matches > 0) {
211                // This controlled element's value matches what was selected, display it
212                count_displayed++;
213                $controlled.removeClass('au-cf7-hidden-by-controller');
214                displayMe = true;
215            } else {
216                // Before hiding, we need to check if I have multiple controllers and if I do, if any of them say I should still be shown
217                if (multiControllers) {
218                    matches = 0;
219                    let controllers = $controlled.attr('data-controller').split('|');
220                    $.each(controllers, function(c, other_cid) {
221                        // Skip checking the controller this is for, just check the other ones
222                        if (other_cid !== cid) {
223                            let $other_controller = aurise_controllable_fields_cf7.getControllerById(other_cid),
224                                other_controlled_value = $other_
224controller.val(),
225                                is_other_toggle = $other_controller.is('[type=checkbox]') || $other_controller.is('[type=radio]'),
226                                otherAcceptedValues = $other_controller.attr('data-' + other_cid + '-values');
227                            matches += aurise_controllable_fields_cf7.compareLoop(
228                                otherAcceptedValues,
229                                other_controlled_value,
230                                is_other_toggle,
231                                is_other_toggle ? aurise_controllable_fields_cf7.getCheckbox($other_controller) : null
232                            );
233                        }
234                    });
235                    if (matches > 0) {
236                        // This controlled element's value matches what was selected, display it
237                        count_displayed++;
238                        $controlled.removeClass('au-cf7-hidden-by-controller');
239                        displayMe = true;
240                    } else {
241                        // This controlled element's value DOES NOT match what was selected, hide it
242                        $controlled.addClass('au-cf7-hidden-by-controller');
243                    }
244                } else {
245                    // Before hiding, we need to check if the checkbox value is still checked because we could just be checking/unchecking a different box of the same group
246                    if (is_toggle) {
247                        if (is_checkbox) {
248                            // Skip checking the controller this is for, just check the other checked checkboxes in the set
249                            let controllers = $controller.closest('form').find('input[type=checkbox][name="' + $controller.attr('name') + '"]:checked:not(#' + $controller.attr('id') + ')');
250                            if (controllers.length) {
251                                $.each(controllers, function(c, other_controller) {
252                                    let $other_controller = $(other_controller);
253                                    is_other_toggle = $other_controller.is('[type=checkbox]') || $other_controller.is('[type=radio]');
254                                    matches += aurise_controllable_fields_cf7.compareLoop(
255                                        acceptedValues,
256                                        $other_controller.val(),
257                                        is_other_toggle, is_other_toggle ? aurise_controllable_fields_cf7.getCheckbox(other_controller) : null
258                                    );
259                                });
260                            }
261                        }
262                    }
263
264                    if (matches > 0) {
265                        // This controlled element's value matches what was selected, display it
266                        count_displayed++;
267                        $controlled.removeClass('au-cf7-hidden-by-controller');
268                        displayMe = true;
269                    } else {
270                        // This controlled element's value DOES NOT match what was selected, hide it
271                        $controlled.addClass('au-cf7-hidden-by-controller');
272                    }
273                }
274            }
275
276            // Handle nested required fields: TO-DO: filter out nested-requireds?
277            let $required_fields = displayMe ? $controlled.find('.required-when-visible') : $controlled.find('[required]')
278            if ($required_fields.length > 0) {
279                if (displayMe) {
280                    // Add the required attributes because they are now visible
281                    $required_fields.each(function(rf, required_field) {
282                        $(required_field).attr({ 'required': 'required', 'aria-required': 'true' });
283                    });
284                } else {
285                    // Remove the required attributes because they are being hidden
286                    $required_fields.each(function(rf, required_field) {
287                        let $thisRequiredField = $(required_field);
288                        if (!$thisRequiredField.hasClass('required-when-visible')) {
289                            $thisRequiredField.addClass('required-when-visible');
290                        }
291                        $thisRequiredField.attr('aria-required', 'false').removeAttr('required');
292                    });
293                }
294            }
295
296            // Hide nested controllers
297            if (!displayMe) {
298                let $nested_controllers = $controlled.find('.au-cf7-controller');
299                if ($nested_controllers.length) {
300                    $nested_controllers.each(function(nc, nested_controller) {
301                        let $nested_controller = $(nested_controller);
302                        aurise_controllable_fields_cf7.toggleCheckbox($nested_controller, false);
303                        aurise_controllable_fields_cf7.toggleControlledFields(aurise_controllable_fields_cf7.getControllerId($nested_controller), $nested_controller.attr('id'), false);
304                    });
305                }
306            } else if (!is_expanded) {
307                is_expanded = true;
308            }
309        });
310
311        // Update ARIA flag on controller
312        if (is_expanded) {
313            $controller.attr('aria-expanded', 'true');
314            $controller.trigger('displayed_controlled');
315        } else if (is_toggle && $empty_controlled !== false && !$('input[name="' + $controller.attr('name') + '"]:checked').length) {
316            // If they're all unchecked and there is a "default" to display, display it
317            $controller.attr('aria-expanded', 'true');
318            $empty_controlled.removeClass('au-cf7-hidden-by-controller');
319            $controller.trigger('default_controlled');
320        } else {
321            $controller.attr('aria-expanded', 'false');
322            $controller.trigger('hide_controlled');
323        }
324        $controller.trigger('toggled_controlled');
325    },
326    compareLoop: function(acceptedValues, controlled_value, is_toggle, toggle_value) {
327        let matches = 0;
328        if (acceptedValues.indexOf('|') >= 0) {
329            acceptedValues = acceptedValues.split('|');
330        } else {
331            acceptedValues = [acceptedValues];
332        }
333        $.each(acceptedValues, function(i, acceptedValue) {
334            if (!is_toggle || (is_toggle && toggle_value)) {
335                // If neither a checkbox nor select field, continue to check for matches
336                // For checkboxes and radios to possibly match at all, it must also be checked
337                matches += aurise_controllable_fields_cf7.compareValues(acceptedValue, controlled_value, is_toggle);
338            }
339        });
340        return matches;
341    },
342    compareValues: function(value, controlled_value, is_toggle) {
343        /**
344         * value = the controller's value that it should match to be true, set by the user
345         * controlled_value = the controlled element's value that is being tested, an option
346         */
347        if (controlled_value === true) {
348            // Treat boolean true as 1
349            controlled_value = '1';
350        } else if (controlled_value === null || controlled_value === undefined || typeof(controlled_value) != 'string') {
351            // Treat null and undefined values as empty strings
352            controlled_value = '';
353        }
354        controlled_value = controlled_value.trim();
355        if (value === true) {
356            // Treat boolean true as 1
357            value = '1';
358        } else if (value === null || value === undefined || typeof(value) != 'string') {
359            value = '';
360        }
361        value = value.trim();
362
363        // Global value checks
364        if (value == '' || value == 'BLANK' || value == 'EMPTY') {
365            // Match only empty/blank
366            if (controlled_value == '') {
367                return 1;
368            }
369            return 0;
370        } else if (value == 'EMPTY_OR_ZERO' || value == 'FALSEY') {
371            // Match falsey values
372            if (!controlled_value || controlled_value == 0 || controlled_value == 'false') {
373                return 1;
374            }
375            return 0;
376        } else if (value == '*') {
377            // Match anything that isn't falsy
378            if (!controlled_value || controlled_value == 0 || controlled_value == 'false') {
379                return 0;
380            }
381            return 1;
382        }
383
384        // If controlled value is a number, do numerical checks
385        if (controlled_value != '' && value != '' && !isNaN(controlled_value)) {
386            controlled_value = parseFloat(controlled_value);
387
388            // If the value isn't a number, then there's probably operations involved
389            if (isNaN(value) || value.startsWith('--')) {
390                // Check for a range, e.g. 10-20, -10 (less than 10) or 50- (greater than 50)
391                if (value.indexOf('-') > -1) {
392                    if (value.startsWith('--')) {
393                        // If the value is -10, then the controlled value is less than or equal to 10
394                        value = value.replace('--', '<='); // Replace with the appropriate operation
395                    } else if (value.endsWith('--')) {
396                        // If the value is 10-, then the controlled value is greater than or equal to 10
397                        value = '>=' + value.replace('--', ''); // Replace with the appropriate operation
398                    } else {
399                        // Do a "between" comparison
400                        let values = value.split('-');
401                        if (values.length > 1) {
402
403                            let min = parseFloat(values[0]),
404                                max = parseFloat(values[1]);
405                            if (min <= controlled_value && controlled_value <= max) {
406                                return 1;
407                            }
408                        }
409                        return 0;
410                    }
411                }
412
413                // Single numeric comparisons
414                if (value.startsWith('!=')) {
415                    // Match everything else except this value
416                    if (controlled_value != value.replace('!=', '')) {
417                        return 1;
418                    }
419                    return 0;
420                } else if (value.startsWith('<=')) {
421                    if (controlled_value <= parseFloat(value.replace('<=', ''))) {
422                        return 1;
423                    }
424                    return 0;
425                } else if (value.startsWith('<')) {
426                    if (controlled_value < parseFloat(value.replace('<', ''))) {
427                        return 1;
428                    }
429                    return 0;
430                } else if (value.startsWith('>=')) {
431                    if (controlled_value >= parseFloat(value.replace('>=', ''))) {
432                        return 1;
433                    }
434                    return 0;
435                } else if (value.startsWith('>')) {
436                    if (controlled_value > parseFloat(value.replace('>', ''))) {
437                        return 1;
438                    }
439                    return 0;
440                }
441            } else {
442                value = parseFloat(value);
443            }
444        }
445        return controlled_value == value ? 1 : 0;
446    }
447};
448$(document).ready(aurise_controllable_fields_cf7.init);

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.