PageSourceSearch

https://selfmanagementresource.com/wp-content/plugins/pn-cookies-m…/pn-cookies-manager-selector.js?ver=1.0.45

js selfmanagementresource.com collected 2026-10-01 12:10:00 UTC 16,247 bytes, 382 lines download raw bytes

1(function($) {
2    'use strict';
3
4    class PN_COOKIES_MANAGER_Selector {
5        constructor(element, options = {}) {
6            this.element = element;
7            this.options = {
8                multiple: $(element).prop('multiple'),
9                searchable: true,
10                placeholder: 'Select an option...',
11                searchThreshold: 5,
12                ...options
13            };
14            
15            this.selectedValues = [];
16            this.isOpen = false;
17            // Get placeholder from attribute or empty option
18            this.placeholder = $(this.element).attr('placeholder') || $(this.element).find('option[value=""]').text() || '';
19            this.init();
20        }
21
22        init() {
23            // Create the selector structure
24            this.createStructure();
25            this.bindEvents();
26            // Only on initialization, sync visual with original select
27            this.updateDisplay();
28        }
29
30        createStructure() {
31            const wrapper = $('<div class="pn-cookies-manager-selector"></div>');
32            const control = $('<div class="pn-cookies-manager-selector__control"></div>');
33            const valueContainer = $('<div class="pn-cookies-manager-selector__value-container"></div>');
34            const input = $('<input type="text" class="pn-cookies-manager-selector__input" />');
35            const indicator = $('<span class="pn-cookies-manager-selector__indicator"><i class="material-icons-outlined pn-cookies-manager-selector__indicator-icon">keyboard_arrow_down</i></span>');
36            
37            valueContainer.append(input);
38            control.append(valueContainer, indicator);
39            wrapper.append(control);
40            
41            this.menu = $('<div class="pn-cookies-manager-selector__menu" style="display: none;"></div>');
42            
43            if (this.options.searchable) {
44                const searchContainer = $('<div class="pn-cookies-manager-selector__search"></div>');
45                const searchInput = $('<input type="text" placeholder="Search..." />');
46                searchContainer.append(searchInput);
47                this.menu.append(searchContainer);
48                this.searchInput = searchInput;
49            }
50            
51            this.optionsContainer = $('<div class="pn-cookies-manager-selector__options"></div>');
52            this.menu.append(this.optionsContainer);
53            
54            wrapper.append(this.menu);
55            $(this.element)
56                .css({
57                    position: 'absolute',
58                    opacity: 0.01,
59                    height: '1px',
60                    width: '1px',
61                    padding: 0,
62                    margin: '-1px',
63                    overflow: 'hidden',
64                    clip: 'rect(0,0,0,0)',
65                    whiteSpace: 'nowrap',
66                    border: 0
67                })
68                .after(wrapper);
69            
70            this.wrapper = wrapper;
71            this.control = control;
72            this.valueContainer = valueContainer;
73            this.input = input;
74        }
75
76        bindEvents() {
77            // Toggle menu
78            this.control.on('click', (e) => {
79                e.stopPropagation();
80                this.toggleMenu();
81            });
82
83            // Close menu when clicking outside
84            $(document).on('click', (e) => {
85                if (!this.wrapper.has(e.target).length) {
86                    this.closeMenu();
87                }
88            });
89
90            // Handle option selection
91            this.menu.on('click', '.pn-cookies-manager-selector__option', (e) => {
92                const option = $(e.currentTarget);
93                const value = option.data('value');
94                const label = option.text();
95
96                const wasSelected = this.selectedValues.includes(value);
97
98                if (this.options.multiple) {
99                    this.toggleValue(value, label);
100                } else {
101                    this.setValue(value, label);
102                    this.closeMenu();
103                }
104
105                // Update class according to new state
106                if (this.options.multiple) {
107                    if (wasSelected) {
108                        option.removeClass('-selector__option--is-selected');
109                    } else {
110                        option.addClass('-selector__option--is-selected');
111                    }
112                }
113            });
114
115            // Handle search
116            if (this.options.searchable) {
117                this.searchInput.on('input', (e) => {
118                    this.filterOptions(e.target.value);
119                });
120            }
121
122            // Handle keyboard navigation
123            this.input.on('keydown', (e) => {
124                switch(e.key) {
125                    case 'Enter':
126                        e.preventDefault();
127                        this.toggleMenu();
128                        break;
129                    case 'Escape':
130                        this.closeMenu();
131                        break;
132                }
133            });
134        }
135
136        toggleMenu() {
137            if (this.isOpen) {
138                this.closeMenu();
139            } else {
140                this.openMenu();
141            }
142        }
143
144        openMenu() {
145            this.isOpen = true;
146            this.control.addClass('-selector__control--is-open');
147            this.menu.show();
148            this.updateOptions();
149            // Change icon to arrow up
150            this.wrapper.find('.pn-cookies-manager-selector__indicator-icon').text('keyboard_arrow_up');
151
152            // Auto-focus on search input if it's visible
153            if (this.options.searchable && this.searchInput && this.searchInput.parent().is(':visible')) {
154                // Use setTimeout to ensure the menu is fully rendered before focusing
155                setTimeout(() => {
156                    this.searchInput.focus();
157                }, 10);
158            }
159        }
160
161        closeMenu() {
162            this.isOpen = false;
163            this.control.removeClass('-selector__control--is-open');
164            this.menu.hide();
165            // Change icon to arrow down
166            this.wrapper.find('.pn-cookies-manager-selector__indicator-icon').text('keyboard_arrow_down');
167        }
168
169        updateOptions() {
170            const options = $(this.element).find('option');
171            this.optionsContainer.empty();
172
173            options.each((_, option) => {
174                const $option = $(option);
175                const value = $option.val();
176                const label = $option.text();
177
178                // Do not show empty option
179                if (value === '') return;
180
181                const isSelected = this.selectedValues.includes(value);
182
183                const optionElement = $('<div class="pn-cookies-manager-selector__option"></div>')
184                    .text(label)
185                    .data('value', value);
186
187                if (isSelected) {
188                    optionElement.addClass('-selector__option--is-selected');
189                }
190
191                this.optionsContainer.append(optionElement);
192            });
193
194            // Show search if options exceed threshold
195            if (this.options.searchable && options.length > this.options.searchThreshold) {
196                this.searchInput.parent().show();
197            } else {
198                this.searchInput.parent().hide();
199            }
200        }
201
202        filterOptions(searchTerm) {
203            const options = this.optionsContainer.find('.pn-cookies-manager-selector__option');
204            const term = searchTerm.toLowerCase();
205
206            // Function to normalize text by removing accents
207            const normalizeText = (text) => {
208                return text.normalize('NFD')
209                          .replace(/[\u0300-\u036f]/g, '') // Remove diacritics (accents)
210                          .toLowerCase();
211            };
212
213            options.each((_, option) => {
214                const $option = $(option);
215                const text = $option.text();
216                const normalizedText = normalizeText(text);
217                const normalizedTerm = normalizeText(term);
218                $option.toggle(normalizedText.includes(normalizedTerm));
219            });
220        }
221
222        toggleValue(value, label) {
223            if (value === '') return;
224            if (this.selectedValues.includes(value)) {
225                this.removeAllSelectedValue(value);
226                return;
227            }
228            this.selectedValues.push(value);
229            this.addSelectedValue(value, label);
230            this.updateOriginalSelect();
231        }
232
233        setValue(value, label) {
234            this.selectedValues = [value];
235            this.valueContainer.empty();
236            this.addSelectedValue(value, label);
237            this.updateOriginalSelect();
238        }
239
240        addSelectedValue(value, label) {
241            // Remove placeholder if exists
242            this.valueContainer.find('.pn-cookies-manager-selector__placeholder').remove();
243            if (this.options.multiple) {
244                const valueElement = $('<div class="pn-cookies-manager-selector__multi-value"></div>');
245                const labelElement = $('<span class="pn-cookies-manager-selector__multi-value__label"></span>').text(label);
246                const removeButton = $('<span class="pn-cookies-manager-selector__multi-value__remove"><i class="material-icons-outlined pn-cookies-manager-icon-close">close</i></span>');
247
248                valueElement.attr('data-value', value);
249
250                removeButton.on('click', (e) => {
251                    e.stopPropagation();
252                    this.removeAllSelectedValue(value);
253                    // Also remove selected class from the option in the dropdown menu
254                    this.optionsContainer.find('.pn-cookies-manager-selector__option').each(function() {
255                        if ($(this).data('value') == value) {
256                            $(this).removeClass('-selector__option--is-selected');
257                        }
258                    });
259                });
260
261                valueElement.append(labelElement, removeButton);
262                this.valueContainer.append(valueElement);
263            } else {
264                // Single select: text + x to remove
265                const valueElement = $('<span class="pn-cookies-manager-selector__single-value"></span>');
266                const labelElement = $('<span class="pn-cookies-manager-selector__single-value__label"></span>').text(label);
267                const removeButton = $('<span class="pn-cookies-manager-selector__single-value__remove"><i class="material-icons-outlined pn-cookies-manager-icon-close">close</i></span>');
268                removeButton.on('click', (e) => {
269                    e.stopPropagation();
270                    // Clear selection
271                    this.selectedValues = [];
272                    this.valueContainer.empty();
273                    this.valueContainer.find('.pn-cookies-manager-selector__placeholder').remove();
274                    this.updateOriginalSelect();
275                    if (this.placeholder) {
276                        this.input.hide();
277                        this.valueContainer.append('<span class="pn-cookies-manager-selector__placeholder">' + this.placeholder + '</span>');
278                    }
279                });
280                valueElement.append(labelElement, removeButton);
281                this.valueContainer.append(valueElement);
282            }
283        }
284
285        removeAllSelectedValue(value) {
286            // Remove all occurrences from the array
287            this.selectedValues = this.selectedValues.filter(v => v !== value);
288            // Remove all visual elements
289            this.valueContainer.find(`[data-value="${value}"]`).remove();
290            this.updateOriginalSelect();
291            // If there are no selected values, show the placeholder and hide the input
292            if (this.selectedValues.length === 0 && this.placeholder) {
293                this.input.hide();
294                this.valueContainer.find('.pn-cookies-manager-selector__placeholder').remove();
295                this.valueContainer.append('<span class="pn-cookies-manager-selector__placeholder">' + this.placeholder + '</span>');
296            } else {
297                this.input.show();
298            }
299        }
300
301        updateOriginalSelect() {
302            const $select = $(this.element);
303            
304            if (this.options.multiple) {
305                $select.find('option').prop('selected', false);
306                this.selectedValues.forEach(value => {
307                    $select.find(`option[value="${value}"]`).prop('selected', true);
308                });
309            } else {
310                $select.val(this.selectedValues[0]);
311            }
312
313            $select.trigger('change');
314        }
315
316        updateDisplay() {
317            const $select = $(this.element);
318            const selectedOptions = $select.find('option:selected');
319            this.selectedValues = [];
320            this.valueContainer.empty();
321            this.valueContainer.find('.pn-cookies-manager-selector__placeholder').remove();
322
323            // For single select: if only the empty value is selected, show only the placeholder
324            if (
325                !this.options.multiple &&
326                selectedOptions.length === 1 &&
327                selectedOptions[0].value === '' &&
328                (selectedOptions.length === 0 && this.placeholder) ||
329                (selectedOptions.length === 1 && selectedOptions[0].value === '' && this.placeholder)
330            ) {
331                this.input.hide();
332                this.valueContainer.append('<span class="pn-cookies-manager-selector__placeholder">' + this.placeholder + '</span>');
333                return;
334            } else {
335                this.input.show();
336            }
337
338            selectedOptions.each((_, option) => {
339                const $option = $(option);
340                const value = $option.val();
341                const label = $option.text();
342                if (value === '') return; // Skip empty value (placeholder)
343                this.selectedValues.push(value);
344                this.addSelectedValue(value, label);
345            });
346        }
347    }
348
349    // jQuery plugin initialization
350    $.fn.PN_COOKIES_MANAGER_Selector = function(options) {
351        return this.each(function() {
352            if (!$(this).data('-selector')) {
353                $(this).data('-selector', new PN_COOKIES_MANAGER_Selector(this, options));
354            }
355        });
356    };
357
358    // Global handlers outside of class: close selector when clicking outside or pressing ESC
359    $(document).on('mousedown touchstart', function(e) {
360        var $target = $(e.target);
361        if (!$target.closest('.pn-cookies-manager-selector').length) {
362            $('.pn-cookies-manager-selector__menu:visible').each(function() {
363                var $menu = $(this);
364                $menu.hide();
365                $menu.closest('.pn-cookies-manager-selector').find('.pn-cookies-manager-selector__control').removeClass('-selector__control--is-open');
366                $menu.closest('.pn-cookies-manager-selector').find('.pn-cookies-manager-selector__indicator-icon').text('keyboard_arrow_down');
367            });
368        }
369    });
370
371    $(document).on('keyup', function(e) {
372        if (e.key === 'Escape') {
373            $('.pn-cookies-manager-selector__menu:visible').each(function() {
374                var $menu = $(this);
375                $menu.hide();
376                $menu.closest('.pn-cookies-manager-selector').find('.pn-cookies-manager-selector__control').removeClass('-selector__control--is-open');
377                $menu.closest('.pn-cookies-manager-selector').find('.pn-cookies-manager-selector__indicator-icon').text('keyboard_arrow_down');
378            });
379        }
380    });
381
382})(jQuery); 

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.