PageSourceSearch

https://www.touchstonetonewoods.co.uk/common/js/forms.js

js touchstonetonewoods.co.uk collected 2026-10-04 03:08:15 UTC 13,963 bytes, 346 lines download raw bytes

1$(document).ready(function () {
2    forms.init(false);
3});
4
5// Vertical Pack forms
6var forms = {
7    init: function (vpb) {
8        this.vpTextInput();
9        this.vpSelectInput(vpb);
10        this.vpSearchBoxInput();
11        this.vpToggleInput(vpb);
12        this.vpImageInput(vpb);
13        this.vpButton(vpb);
14    },
15    vpTextInput: function () {
16        $('.vp-form-input-js').each(function () {
17            $(this).on('blur', function () {
18                const id = $(this).attr('id');
19                if (!$(this).val()) {
20                    $(`label[for='${id}']`).first().removeClass('vp-form__label--active')
21                }
22            })
23            $(this).on('focus', function () {
24                const id = $(this).attr('id');
25                $(`label[for='${id}']`).addClass('vp-form__label--active')
26            });
27        })
28    },
29    vpImageInput: function (vpb) {
30        if (vpb) {
31            const elms = document.getElementsByClassName('vp-form-remove-image-js');
32            for (const elm of elms) {
33                elm.addEventListener('click', function (e) {
34                    e.stopPropagation();
35                    const attr = this.getAttribute('data-checkbox-name');
36                    const checkbox = document.querySelector(`input[name="${attr}"]`);
37                    checkbox.checked = true;
38                    const event = new CustomEvent("vpb-update", {
39                        bubbles: true
40                    });
41                    checkbox.dispatchEvent(event);
42                })
43            }
44
45
46            $('.vp-form-file-input-js').each(function () {
47                $(this).on('click', function () {
48                    const id = $(this).attr('data-id');
49                    document.getElementById(id).click();
50                })
51            })
52        }
53    },
54    vpSelectInput: function (vpb) {
55        // update label position
56        $('.vp-form-select-js').each(function () {
57            $(this).on('blur', function () {
58                const id = $(this).attr('button-id');
59                if ($(this).find('a.vp-form-select-label-js').text() === '') {
60                    $(`label[for='${id}']`).removeClass('vp-form__label--active')
61                }
62            })
63            $(this).on('focus', function () {
64                const id = $(this).attr('button-id');
65                $(`label[for='${id}']`).addClass('vp-form__label--active')
66            });
67        })
68
69        // set the value of the hidden update and trigger change event
70        const assignListenersForDropdownOptions = () => {
71            // single select
72            $('.dropdown-menu .vp-form-option-value-js').on('click', function () {
73                const id = $(this).attr('data-id');
74                const val = $(this).attr('data-value');
75
76                // need to use vanilla here to allow for id's like frm-extended[banner]
77                const input = document.getElementById(id);
78
79                input.value = val;
80
81                // Manually trigger a change event on the input
82                const event = vpb ? new CustomEvent("vpb-update", {
83                    bubbles: true
84                }) : new Event('change');
85                input.dispatchEvent(event);
86
87                $(`[toggle-id='${id}']`).text($(this).text());
88            })
89
90            multiSelect.init(vpb);
91
92
93        };
94        assignListenersForDropdownOptions();
95
96
97        // searchable dropdown
98        $('.dropdown-menu .vp-form-dropdown-search-input-js').each(function () {
99            $(this).on('click', function (e) {
100                e.stopPropagation();
101            })
102            $(this).on('keyup', function () {
103                const search = $(this).val().toLowerCase();
104
105                $(this).parent().parent().find('.vp-form-option-value-js').each(function () {
106                    const optionLabel = $(this).text().toLowerCase();
107                    if (optionLabel.includes(search)) $(this).parent().removeClass('disappear');
108                    if (!optionLabel.includes(search)) $(this).parent().addClass('disappear');
109                })
110
111                multiSelect.runSearch(this, search);
112            })
113        })
114
115        // searchable ajax dropdown
116        $('.dropdown-menu .vp-form-dropdown-search-ajax-input-js').each(function () {
117            $(this).on('click', function (e) {
118                e.stopPropagation();
119            })
120
121            const getResults = (url, term, dropdownId, wrapper) => $.ajax({
122                url: url,
123                data: { term: term },
124                success: function (data) {
125                    let html = "";
126                    $.each(data.data, function (key, value) {
127                        html += `<li>
128                            <div class="vp-form__select-button__menu__standard-option vp-form-option-value-js" data-id="${dropdownId}" data-value="${key}">${value}</div>
129                        </li>`
130                    });
131
132                    wrapper.html(html);
133                    assignListenersForDropdownOptions();
134                }
135            });
136
137            const debounce = debounceRequest(getResults, 500);
138
139            $(this).on('keyup', function () {
140                const url = $(this).attr('data-url');
141                const term = $(this).val();
142                const dropdownId = $(this).attr('data-id');
143                const wrapper = $(this).parent().parent().find('.ajax-response-results').first();
144                debounce(url, term, dropdownId, wrapper);
145            })
146        })
147    },
148    vpSearchBoxInput: function () {
149        $('#product-search').on('focus', function () {
150            $('.search-box-js').addClass('tb-header-middle__search__form--focus');
151        });
152
153        $('#product-search').on('blur', function () {
154            $('.search-box-js').removeClass('tb-header-middle__search__form--focus');
155        });
156    },
157    vpToggleInput: function (vpb) {
158        $('.vp-form-toggle-input').each(function () {
159            $(this).on('click', function () {
160                $(this).find('.vp-form-toggle').first().toggleClass('vp-form__toggle--active');
161                const checkboxInput = $(this).find('input[type="checkbox"]').first();
162                const radioInputs = $(this).find('input[type="radio"]');
163                const isCheckBoxToggle = checkboxInput.length;
164
165
166                if (isCheckBoxToggle) {
167                    checkboxInput.prop('checked', !checkboxInput.is(':checked'));
168                } else {
169                    let radioInputToSetActive = $(radioInputs[0]).prop('checked') ? 1 : 0;
170                    radioInputs.each(function () {
171                        $(this).prop('checked', false)
172                    })
173                    $(radioInputs[radioInputToSetActive]).prop('checked', true);
174                }
175
176                const sendChangeEvtElmId = isCheckBoxToggle ? checkboxInput.attr('id') : radioInputs.first().attr('id');
177                const sendChangeEvtElm = document.getElementById(sendChangeEvtElmId);
178
179                const event = vpb ? new CustomEvent("vpb-update", {
180                    bubbles: true
181                }) : new Event('change');
182                sendChangeEvtElm.dispatchEvent(event);
183            });
184        })
185    },
186    vpButton: function (vpb) {
187        if (vpb) {
188            $('.add-extended-group-js').each(function () {
189                $(this).on('click', function () {
190                    const groupId = $(this).attr('group-id');
191                    const count = +$(this).attr('data-count');
192                    const newGroupRow = $(`#extended-extra-${groupId}`).children().clone();
193                    const appendTo = $(`[extended-group-list-id=${groupId}]`);
194
195                    const inputIndex = count - 1;
196                    newGroupRow.html(function (index, html) {
197                        return html.replace(/extignore/g, inputIndex).replace(/exitgnorecount/g, count);
198                    }).appendTo(appendTo);
199
200                    forms.vpSelectInput(true);
201                    $(this).attr('data-count', count + 1);
202                    forms.destroy();
203                    forms.init(true);
204                })
205            })
206        }
207    },
208    destroy: function () {
209        $('.vp-form-toggle-input').each(function () {
210            $(this).off('click')
211        })
212
213        $('.add-extended-group-js').each(function () {
214            $(this).off('click')
215        })
216
217        $('.vp-form-option-value-js').each(function () {
218            $(this).off('click')
219        })
220    }
221}
222
223const multiSelect = {
224    vpb: false,
225    init: function (vpb = false) {
226        this.vpb = vpb;
227        $('.dropdown-menu .vp-form-multi-option-value-js').on('click', function (e) {
228            e.stopPropagation();
229        });
230
231        $('.dropdown-menu .vp-form-multi-option-value-js input').on('change', function (e) {
232            const addInput = $(this).prop('checked');
233
234            const val = $(this).attr('value');
235            const name = $(this).attr('name');
236            const label = $(this).parent().find('label').first().text();
237
238            if (addInput) {
239                $(this).parent().addClass('vp-form__multi__dropdown-item-active');
240                $(`.vp-form__multi-wrapper[multi-id="${name}"] .vpb-js-selected-container`).append(multiSelect.addButton(name, val, label));
241                multiSelect.destroy();
242                multiSelect.init(true);
243            } else {
244                $(this).parent().removeClass('vp-form__multi__dropdown-item-active');
245                $(`.vp-form__multi-wrapper[multi-id="${name}"] [button-container-id="${val}"]`).remove();
246            }
247
248            if (!$(`.vp-form__multi-wrapper[multi-id="${name}"] .vpb-js-selected-container`).children().length) {
249                multiSelect.removeLastItem(name);
250            }
251        });
252
253        $('.multi-icon-remove').on('click', function () {
254            const value = $(this).attr('input-value');
255            const name = $(this).attr('input-name');
256
257            multiSelect.clearOption(name, value);
258
259            !$(`.vp-form__multi-wrapper[multi-id="${name}"] .vpb-js-selected-container`).children().length ? multiSelect.removeLastItem(name) : multiSelect.sendEvent(name, value)
260        });
261
262        // multi select - clear all options
263        $('.multi-clear-options').on('click', function () {
264            const name = $(this).attr('input-name');
265            multiSelect.clearAllOptions(name);
266        })
267    },
268    clearAllOptions: function (name) {
269        $(`.vp-form__multi-wrapper[multi-id="${name}"] input[name="${name}"]:checked`).each(function () {
270            const val = $(this).val();
271            $(`.vp-form__multi-wrapper[multi-id="${name}"] [button-container-id="${val}"]`).remove();
272            $(this).prop('checked', false);
273            $(this).parent().removeClass('vp-form__multi__dropdown-item-active')
274        });
275        this.removeLastItem(name);
276    },
277    clearOption: function (name, value) {
278        $(`.vp-form__multi-wrapper[multi-id="${name}"] [button-container-id="${value}"]`).remove();
279        const checkBoxInput = $(`input[value="${value}"]`);
280        checkBoxInput.prop('checked', false);
281        checkBoxInput.parent().removeClass('vp-form__multi__dropdown-item-active')
282    },
283    // we need to send an event on rm-NAMEOFINPUT in order to successfully remove the very last item
284    removeLastItem: function (name) {
285        const event = this.vpb ? new CustomEvent("vpb-update", {
286            bubbles: true
287        }) : new Event('change');
288
289        const removeAllInput = document.querySelector(`input[name="rm-${name.replace('[]', '')}"]`);
290        removeAllInput.checked = true;
291        removeAllInput.dispatchEvent(event);
292        removeAllInput.checked = false;
293    },
294    addButton: function (name, val, label) {
295        return `<div class="vp-form__button-container" button-container-id="${val}">
296        <button type="button" class="vp-form__button vp-form__button--icon-close">
297            <span class="vp-form__button__text">${label}</span>
298            <span class=" multi-icon-remove vp-form__button__icon" input-value="${val}" input-name="${name}">
299                <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
300                    <path d="M12 2C6.47 2 2 6.47 2 12C2 17.53 6.47 22 12 22C17.53 22 22 17.53 22 12C22 6.47 17.53 2 12 2ZM17 15.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59Z" fill="rgba(0, 0, 0, 0.26)"></path>
301                </svg>
302            </span>
303        </button>
304    </div>`
305    },
306    sendEvent: function (name, inputValue) {
307        const event = this.vpb ? new CustomEvent("vpb-update", {
308            bubbles: true
309        }) : new Event('change');
310
311        const input = document.querySelector(`.vp-form__multi-wrapper[multi-id="${name}"] input[value="${inputValue}"]`);
312        input.dispatchEvent(event);
313    },
314    runSearch: function (elm, search) {
315        $(elm).parent().parent().find('.vp-form-multi-option-value-js label').each(function () {
316            const optionLabel = $(this).text().toLowerCase();
317            if (optionLabel.includes(search)) $(this).parent().removeClass('disappear');
318            if (!optionLabel.includes(search)) $(this).parent().addClass('disappear');
319        })
320    },
321    destroy: function () {
322        $('.dropdown-menu .vp-form-multi-option-value-js input').each(function () {
323            $(this).off('change')
324        })
325    },
326}
327
328function debounceRequest(callback, delay, immediate = false) {
329    let timerID;
330
331    return function (...args) {
332        clearTimeout(timerID);
333
334        const shouldCallImmediately = timerID == null && immediate;
335        if (shouldCallImmediately) {
336            callback.apply(this, args);
337        }
338
339        timerID = setTimeout(() => {
340            if (!immediate) {
341                callback.apply(this, args);
342            }
343            timerID = null;
344        }, delay)
345    }
346}

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.