PageSourceSearch

https://zuomod.com/wp-content/mu-plugins/custom-cf7-tags/product-a…/js/product-attributes.js?ver=3aa79bdb

js zuomod.com collected 2026-10-03 21:26:56 UTC 32,553 bytes, 745 lines download raw bytes

1(function($) {
2    'use strict';
3
4    var instances_map = new Map();
5    var max_visible_values = 3;
6
7    function ProductAttributesField($wrapper_element) {
8        this.$wrapper = $wrapper_element;
9        this.$loading_element = $wrapper_element.find('.cf7-pa-loading');
10        this.$content_element = $wrapper_element.find('.cf7-pa-content');
11        this.$options_list_element = $wrapper_element.find('.cf7-pa-options-list');
12        this.$selected_list_element = $wrapper_element.find('.cf7-pa-selected-list');
13        this.$hidden_input_element = $wrapper_element.find('.cf7-pa-hidden-input');
14        this.$modal_element = $wrapper_element.find('.cf7-pa-modal-overlay');
15        this.$search_options_input = $wrapper_element.find('.cf7-pa-search-options');
16        this.$search_selected_input = $wrapper_element.find('.cf7-pa-search-selected');
17        
18        this.attributes_list = [];
19        this.selected_attributes_list = [];
20        this.current_attribute_data = null;
21        this.current_editing_index = -1;
22        this.expanded_items_set = new Set();
23        this.modal_values_list = [];
24        this.modal_values_expanded = false;
25        
26        var types_attribute = $wrapper_element.attr('data-types') || '';
27        this.allowed_types_list = types_attribute ? types_attribute.split(',').map(function(type) { 
28            return type.trim().toLowerCase(); 
29        }).filter(function(type) { return type; }) : [];
30
31        this.is_multiselect_enabled = $wrapper_element.attr('data-multiselect') === 'true';
32
33        var defaults_attribute = $wrapper_element.attr('data-defaults') || '[]';
34        try {
35            this.default_values_list = JSON.parse(defaults_attribute);
36        } catch (parse_error) {
37            this.default_values_list = [];
38        }
39
40        this.initialize();
41    }
42
43    ProductAttributesField.prototype.initialize = function() {
44        this.bind_event_handlers();
45        this.load_attributes_data();
46    };
47
48    ProductAttributesField.prototype.bind_event_handlers = function() {
49        var self = this;
50
51        this.$options_list_element.on('click', '.cf7-pa-option-item', function(click_event) {
52            self.toggle_option_selection($(click_event.currentTarget));
53        });
54
55        this.$selected_list_element.on('click', '.cf7-pa-selected-item', function(click_event) {
56            if (!$(click_event.target).closest('.cf7-pa-item-remove').length) {
57                var item_index = $(click_event.currentTarget).data('index');
58                self.open_values_modal(item_index);
59            }
60        });
61
62        this.$selected_list_element.on('click', '.cf7-pa-item-remove', function(click_event) {
63            click_event.stopPropagation();
64            self.remove_selected_attribute($(click_event.currentTarget).closest('.cf7-pa-selected-item'));
65        });
66
67        this.$selected_list_element.on('click', '.cf7-pa-value-more', function(click_event) {
68            click_event.stopPropagation();
69            var item_index = $(click_event.currentTarget).data('index');
70            self.expanded_items_set.add(item_index);
71            self.render_selected_attributes_list();
72        });
73
74        this.$selected_list_element.on('click', '.cf7-pa-value-less', function(click_event) {
75            click_event.stopPropagation();
76            var item_index = $(click_event.currentTarget).data('index');
77            self.expanded_items_set.delete(item_index);
78            self.render_selected_attributes_list();
79        });
80
81        this.$search_options_input.on('input', function(input_event) {
82            self.filter_options_list($(input_event.target).val());
83        });
84
85        this.$search_selected_input.on('input', function(input_event) {
86            self.filter_selected_list($(input_event.target).val());
87        });
88
89        this.$wrapper.find('.cf7-pa-select-all-checkbox').on('change', function() {
90            var is_checked = $(this).is(':checked');
91            if (is_checked) {
92                self.select_all_attributes();
93            } else {
94                self.deselect_all_attributes();
95            }
96        });
97
98        this.$modal_element.on('click', '.cf7-pa-modal-close', function(click_event) {
99            click_event.preventDefault();
100            self.close_values_modal();
101        });
102
103        this.$modal_element.on('click', '.cf7-pa-modal-cancel', function(click_event) {
104            click_event.preventDefault();
105            self.close_values_modal();
106        });
107
108        this.$modal_element.on('click', '.cf7-pa-modal-save', function(click_event) {
109            click_event.preventDefault();
110            self.save_attribute_values();
111        });
112
113        this.$modal_element.on('click', function(click_event) {
114            if ($(click_event.target).hasClass('cf7-pa-modal-overlay')) {
115                self.close_values_modal();
116            }
117        });
118
119        this.$modal_element.on('keypress', '.cf7-pa-single-mode input[name="value"]', function(keypress_event) {
120            if (keypress_event.which === 13) {
121                keypress_event.preventDefault();
122                self.save_attribute_values();
123            }
124        });
125
126        this.$modal_element.on('keypress', '.cf7-pa-multi-mode input[name="value"]', function(keypress_event) {
127            if (keypress_event.which === 13) {
128                keypress_event.preventDefault();
129                self.add_value_to_modal_list();
130            }
131        });
132
133        this.$modal_element.on('input', '.cf7-pa-multi-mode input[name="value"]', function() {
134            self.update_save_button_state();
135        });
136
137        this.$modal_element.on('click', '.cf7-pa-add-value-btn', function(click_event) {
138            click_event.preventDefault();
139            self.add_value_to_modal_list();
140        });
141
142        this.$modal_element.on('click', '.cf7-pa-value-remove', function(click_event) {
143            click_event.preventDefault();
144            var $value_item = $(click_event.currentTarget).closest('.cf7-pa-value-item');
145            var value_text = $value_item.data('value');
146            
147            self.modal_values_list = self.modal_values_list.filter(function(item) {
148                return item.value !== value_text;
149            });
150            
151            self.render_modal_values_list();
152        });
153
154        this.$modal_element.on('click', '.cf7-pa-modal-value-more', function(click_event) {
155            click_event.preventDefault();
156            self.modal_values_expanded = true;
157            self.render_modal_values_list();
158        });
159
160        this.$modal_element.on('click', '.cf7-pa-modal-value-less', function(click_event) {
161            click_event.preventDefault();
162            self.modal_values_expanded = false;
163            self.render_modal_values_list();
164        });
165    };
166
167    ProductAttributesField.prototype.load_attributes_data = function() {
168        var self = this;
169        
170        this.$loading_element.show();
171        this.$content_element.hide();
172
173        if (typeof window.product_attributes !== 'undefined' && 
174            Array.isArray(window.product_attributes) && 
175            window.product_attributes.length > 0) {
176            this.attributes_list = this.normalize_attributes_data(window.product_attributes);
177            this.render_options_list();
178            this.render_selected_attributes_list();
179            this.update_select_all_checkbox();
180            this.$loading_element.hide();
181            this.$content_element.show();
182            return;
183        }
184
185        $.ajax({
186            url: cf7ProductAttributesConfig.ajaxurl,
187            type: 'POST',
188            data: {
189                action: 'cf7_get_product_attributes',
190                nonce: cf7ProductAttributesConfig.nonce
191            },
192            success: function(ajax_response) {
193                if (ajax_response.success) {
194                    var attributes_data = ajax_response.data?.attributes || ajax_response.data || [];
195                    
196                    if (typeof attributes_data === 'string') {
197                        try {
198                            attributes_data = JSON.parse(attributes_data);
199                        } catch (parse_error) {}
200                    }
201                    
202                    if (attributes_data && attributes_data.data && Array.isArray(attributes_data.data)) {
203                        attributes_data = attributes_data.data;
204                    }
205                    
206                    if (Array.isArray(attributes_data) && attributes_data.length > 0) {
207                        self.attributes_list = self.normalize_attributes_data(attributes_data);
208                        self.render_options_list();
209                        self.render_selected_attributes_list();
210                        self.update_select_all_checkbox();
211                        self.$loading_element.hide();
212                        self.$content_element.show();
213                    } else {
214                        self.show_error_message('No attributes found');
215                    }
216                } else {
217                    self.show_error_message(ajax_response.data?.message || 'Failed to load');
218                }
219            },
220            error: function() {
221                self.show_error_message('Failed to load attributes');
222            }
223        });
224    };
225
226    ProductAttributesField.prototype.normalize_attributes_data = function(raw_attributes_data) {
227        var self = this;
228        
229        if (!Array.isArray(raw_attributes_data)) return [];
230        
231        var normalized_attributes = raw_attributes_data.map(function(attribute_item) {
232            return {
233                id: attribute_item.id || attribute_item.attribute_id || '',
234                name: attribute_item.name || '',
235                display_name: attribute_item.name || attribute_item.display_name || attribute_item.label || '',
236                type: (attribute_item.data_type || attribute_item.type || 'text').trim().toLowerCase(),
237                options: attribute_item.options || []
238            };
239        }).filter(function(attribute_item) {
240            return attribute_item.id && attribute_item.display_name;
241        });
242        
243        if (self.allowed_types_list.length > 0) {
244            normalized_attributes = normalized_attributes.filter(function(attribute_item) {
245                return self.allowed_types_list.includes(attribute_item.type.toLowerCase().trim());
246            });
247        }
248        
249        return normalized_attributes;
250    };
251
252    ProductAttributesField.prototype.get_default_value_for_attribute = function(attribute_id, attribute_name) {
253        if (!this.default_values_list || this.default_values_list.length === 0) return null;
254        
255        var matching_default = this.default_values_list.find(function(default_item) {
256            return default_item.attribute_id === attribute_id || 
257                (default_item.attribute_name && attribute_name && 
258                 default_item.attribute_name.toLowerCase() === attribute_name.toLowerCase());
259        });
260        
261        return matching_default ? matching_default.value : null;
262    };
263
264    ProductAttributesField.prototype.render_options_list = function() {
265        var self = this;
266        
267        this.$options_list_element.empty();
268        
269        this.attributes_list.forEach(function(attribute_item) {
270            var is_selected = self.selected_attributes_list.some(function(selected_item) {
271                return selected_item.id === attribute_item.id;
272            });
273            
274            var default_value = self.get_default_value_for_attribute(attribute_item.id, attribute_item.name);
275            var default_label_html = default_value ? 
276                '<span class="cf7-pa-option-default" title="' + self.escape_attribute(default_value) + '">
276' + self.escape_html_string(default_value) + '</span>' : '';
277            
278            var selected_class = is_selected ? 'cf7-pa-option-selected' : '';
279            
280            var option_item_html = '<div class="cf7-pa-option-item ' + selected_class + '" ' +
281                'data-id="' + self.escape_html_string(attribute_item.id) + '" ' +
282                'data-name="' + self.escape_html_string(attribute_item.display_name) + '">' +
283                '<div class="cf7-pa-option-checkbox">' +
284                '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3">' +
285                '<polyline points="20 6 9 17 4 12"></polyline></svg></div>' +
286                '<span class="cf7-pa-option-name" title="' + self.escape_attribute(attribute_item.display_name) + '">' + self.escape_html_string(attribute_item.display_name) + '</span>' +
287                default_label_html + '</div>';
288            
289            self.$options_list_element.append(option_item_html);
290        });
291    };
292
293    ProductAttributesField.prototype.toggle_option_selection = function($option_item_element) {
294        var self = this;
295        var attribute_id = $option_item_element.data('id');
296        var is_currently_selected = $option_item_element.hasClass('cf7-pa-option-selected');
297        
298        if (is_currently_selected) {
299            this.selected_attributes_list = this.selected_attributes_list.filter(function(selected_item) {
300                return selected_item.id !== attribute_id;
301            });
302            $option_item_element.removeClass('cf7-pa-option-selected');
303        } else {
304            var attribute_data = this.attributes_list.find(function(attribute_item) {
305                return attribute_item.id === attribute_id;
306            });
307            
308            if (attribute_data) {
309                var default_value = this.get_default_value_for_attribute(attribute_data.id, attribute_data.name);
310                var initial_values = default_value ? [default_value] : [];
311                
312                this.selected_attributes_list.push({
313                    id: attribute_data.id,
314                    name: attribute_data.name,
315                    display_name: attribute_data.display_name,
316                    type: attribute_data.type,
317                    values: initial_values
318                });
319                $option_item_element.addClass('cf7-pa-option-selected');
320            }
321        }
322        
323            this.render_selected_attributes_list();
324            this.update_hidden_input_value();
325            this.update_select_all_checkbox();
326    };
327
328    ProductAttributesField.prototype.render_selected_attributes_list = function() {
329        var self = this;
330        
331        this.$selected_list_element.empty();
332
333        if (this.selected_attributes_list.length === 0) {
334            this.$selected_list_element.html('<div class="cf7-pa-empty-state"><span>No attributes selected</span></div>');
335            return;
336        }
337
338        this.selected_attributes_list.forEach(function(attribute_item, item_index) {
339            var default_value = self.get_default_value_for_attribute(attribute_item.id, attribute_item.name);
340            var is_expanded = self.expanded_items_set.has(item_index);
341            var values_array = attribute_item.values || [];
342            var total_values_count = values_array.length;
343            var remaining_values_count = total_values_count - max_visible_values;
344            
345            var values_html = '';
346            
347            if (total_values_count === 0) {
348                values_html = '<span class="cf7-pa-item-no-values">Click to add values</span>';
349            } else {
350                var visible_values = is_expanded ? values_array : values_array.slice(0, max_visible_values);
351                
352                values_html = visible_values.map(function(value_item) {
353                    var is_default = value_item === default_value;
354                    var default_class = is_default ? 'cf7-pa-value-default' : '';
355                    return '<span class="cf7-pa-item-value-tag ' + default_class + '" title="' + self.escape_attribute(value_item) + '">' + 
356                        self.escape_html_string(value_item) + '</span>';
357                }).join('');
358                
359                if (remaining_values_count > 0 && !is_expanded) {
360                    values_html += '<span class="cf7-pa-item-value-tag cf7-pa-value-more" data-index="' + 
361                        item_index + '">+' + remaining_values_count + '</span>';
362                }
363                
364                if (is_expanded && total_values_count > max_visible_values) {
365                    values_html += '<span class="cf7-pa-item-value-tag cf7-pa-value-less" data-index="' + 
366                        item_index + '">Show less</span>';
367                }
368            }
369
370            var expanded_class = is_expanded ? ' cf7-pa-values-expanded' : '';
371            
372            var selected_item_html = '<div class="cf7-pa-selected-item" data-index="' + item_index + '">' +
373                '<div class="cf7-pa-drag-handle"><span></span><span></span></div>' +
374                '<div class="cf7-pa-item-content">' +
375                '<div class="cf7-pa-item-name" title="' + self.escape_attribute(attribute_item.display_name) + '">' + self.escape_html_string(attribute_item.display_name) + '</div>' +
376                '<div class="cf7-pa-item-values' + expanded_class + '">' + values_html + '</div></div>' +
377                '<button type="button" class="cf7-pa-item-remove" title="Remove">' +
378                '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">' +
379                '<line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button></div>';
380            
381            self.$selected_list_element.append(selected_item_html);
382        });
383    };
384
385    ProductAttributesField.prototype.filter_options_list = function(search_query) {
386        var lower_query = search_query.toLowerCase();
387        var visible_count = 0;
388        
389        this.$options_list_element.find('.cf7-pa-option-item').each(function() {
390            var option_name = $(this).data('name').toLowerCase();
391            var is_visible = option_name.includes(lower_query);
392            $(this).toggle(is_visible);
393            if (is_visible) visible_count++;
394        });
395        
396        this.$options_list_element.find('.cf7-pa-no-results').remove();
397        if (visible_count === 0 && search_query.length > 0) {
398            this.$options_list_element.append('<div class="cf7-pa-no-results">No attributes found</div>');
399        }
400    };
401
402    ProductAttributesField.prototype.filter_selected_list = function(search_query) {
403        var lower_query = search_query.toLowerCase();
404        var visible_count = 0;
405        
406        this.$selected_list_element.find('.cf7-pa-selected-item').each(function() {
407            var item_name = $(this).find('.cf7-pa-item-name').text().toLowerCase();
408            var is_visible = item_name.includes(lower_query);
409            $(this).toggle(is_visible);
410            if (is_visible) visible_count++;
411        });
412        
413        this.$selected_list_element.find('.cf7-pa-no-results').remove();
414        if (visible_count === 0 && search_query.length > 0) {
415            this.$selected_list_element.append('<div class="cf7-pa-no-results">No attributes found</div>');
416        }
417    };
418
419    ProductAttributesField.prototype.select_all_attributes = function() {
420        var self = this;
421        
422        this.attributes_list.forEach(function(attribute_item) {
423            var is_already_selected = self.selected_attributes_list.some(function(selected_item) {
424                return selected_item.id === attribute_item.id;
425            });
426            
427            if (!is_already_selected) {
428                var default_value = self.get_default_value_for_attribute(attribute_item.id, attribute_item.name);
429                var initial_values = default_value ? [default_value] : [];
430                
431                self.selected_attributes_list.push({
432                    id: attribute_item.id,
433                    name: attribute_item.name,
434                    display_name: attribute_item.display_name,
435                    type: attribute_item.type,
436                    values: initial_values
437                });
438            }
439        });
440        
441        this.render_options_list();
442        this.render_selected_attributes_list();
443        this.update_hidden_input_value();
444    };
445
446    ProductAttributesField.prototype.deselect_all_attributes = function() {
447        this.selected_attributes_list = [];
448        this.expanded_items_set.clear();
449        
450        this.render_options_list();
451        this.render_selected_attributes_list();
452        this.update_hidden_input_value();
453    };
454
455    ProductAttributesField.prototype.update_select_all_checkbox = function() {
456        var total_count = this.attributes_list.length;
457        var selected_count = this.selected_attributes_list.length;
458        var $checkbox = this.$wrapper.find('.cf7-pa-select-all-checkbox');
459        
460        if (selected_count === 0) {
461            $checkbox.prop('checked', false);
462            $checkbox.prop('indeterminate', false);
463        } else if (selected_count === total_count) {
464            $checkbox.prop('checked', true);
465            $checkbox.prop('indeterminate', false);
466        } else {
467            $checkbox.prop('checked', false);
468            $checkbox.prop('indeterminate', true);
469        }
470    };
471
472    ProductAttributesField.prototype.remove_selected_attribute = function($selected_item_element) {
473        var item_index = $selected_item_element.data('index');
474        var attribute_data = this.selected_attributes_list[item_index];
475        
476        if (attribute_data) {
477            this.$options_list_element.find('.cf7-pa-option-item[data-id="' + attribute_data.id + '"]')
478                .removeClass('cf7-pa-option-selected');
479        }
480        
481        this.selected_attributes_list.splice(item_index, 1);
482        this.render_selected_attributes_list();
483        this.update_hidden_input_value();
484        this.update_select_all_checkbox();
485    };
486
487    ProductAttributesField.prototype.open_values_modal = function(edit_index) {
488        var attribute_data = this.selected_attributes_list[edit_index];
489        if (!attribute_data) return;
490
491        this.current_editing_index = edit_index;
492        this.current_attribute_data = attribute_data;
493
494        this.$modal_element.find('.cf7-pa-error-message').removeClass('visible');
495
496        this.$modal_element.find('.cf7-pa-modal-attr-name')
497            .text(attribute_data.display_name)
498            .attr('title', attribute_data.display_name);
499        this.$modal_element.find('.cf7-pa-modal-attribute-name').hide();
500
501        var existing_values = attribute_data.values || [];
502        var default_value = this.get_default_value_for_attribute(attribute_data.id, attribute_data.name);
503
504        if (this.is_multiselect_enabled) {
505            this.$modal_element.find('.cf7-pa-single-mode').hide();
506            this.$modal_element.find('.cf7-pa-multi-mode').show();
507            
508            this.modal_values_list = [];
509            this.modal_values_expanded = false;
510            
511            var self = this;
512            
513            if (existing_values.length > 0) {
514                existing_values.forEach(function(value_item) {
515                    var is_default = value_item === default_value;
516                    self.modal_values_list.push({ value: value_item, is_default: is_default });
517                });
518            } else if (default_value) {
519                this.modal_values_list.push({ value: default_value, is_default: true });
520            }
521            
522            this.render_modal_values_list();
523            
524            var $multi_input_element = this.$modal_element.find('.cf7-pa-multi-mode input[name="value"]');
525            $multi_input_element.val('');
526            
527            if (window.cf7_pa_multi_value) {
528                window.cf7_pa_multi_value.data = { value: '' };
529            }
530        } else {
531            this.$modal_element.find('.cf7-pa-single-mode').show();
532            this.$modal_element.find('.cf7-pa-multi-mode').hide();
533            
534            var existing_value = existing_values.length > 0 ? existing_values[0] : (default_value || '');
535            var $single_input_element = this.$modal_element.find('.cf7-pa-single-mode input[name="value"]');
536            $single_input_element.val(existing_value);
537            
538            if (window.cf7_pa_single_value) {
539                window.cf7_pa_single_value.data = { value: existing_value };
540            }
541        }
542
543        this.$modal_element.addClass('active');
544        
545        var self = this;
546        
547        if (this.is_multiselect_enabled) {
548            setTimeout(function() { 
549                self.$modal_element.find('.cf7-pa-multi-mode input[name="value"]').focus(); 
550            }, 100);
551        } else {
552            setTimeout(function() {
553                self.$modal_element.find('.cf7-pa-single-mode input[name="value"]').focus();
554            }, 100);
555        }
556
557        $('body').addClass('cf7-pa-modal-open');
558        this.update_save_button_state();
559    };
560
561    ProductAttributesField.prototype.add_value_to_modal_list = function() {
562        var $input_element = this.$modal_element.find('.cf7-pa-multi-mode input[name="value"]');
563        var input_value = '';
564        
565        if (window.cf7_pa_multi_value && window.cf7_pa_multi_value.data) {
566            input_value = (window.cf7_pa_multi_value.data.value || '').trim();
567        } else {
568            input_value = $input_element.val().trim();
569        }
570
571        if (!input_value) {
572            return;
573        }
574
575        this.modal_values_list.push({ value: input_value, is_default: false });
576        this.render_modal_values_list();
577        
578        $input_element.val('');
579        
580        if (window.cf7_pa_multi_value) {
581            window.cf7_pa_multi_value.data = { value: '' };
582        }
583
584        $input_element.focus();
585        this.update_save_button_state();
586    };
587
588    ProductAttributesField.prototype.render_modal_values_list = function() {
589        var self = this;
590        var $values_list_element = this.$modal_element.find('.cf7-pa-values-list');
591        $values_list_element.empty();
592        
593        var total_count = this.modal_values_list.length;
594        var remaining_count = total_count - max_visible_values;
595        var visible_values = this.modal_values_expanded 
596            ? this.modal_values_list 
597            : this.modal_values_list.slice(0, max_visible_values);
598        
599        visible_values.forEach(function(item) {
600            var default_class = item.is_default ? 'cf7-pa-value-default' : '';
601            
602            var value_item_html = '<div class="cf7-pa-value-item ' + default_class + '" title="' + self.escape_attribute(item.value) + '">' +
603                '<span class="cf7-pa-value-text">' + self.escape_html_string(item.value) + '</span>' +
604                '<button type="button" class="cf7-pa-value-remove" title="Remove">' +
605                '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">' +
606                '<line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button></div>';
607            
608            var $value_item = $(value_item_html);
609            $value_item.data('value', item.value);
610            $values_list_element.append($value_item);
611        });
612        
613        if (remaining_count > 0 && !this.modal_values_expanded) {
614            var more_chip_html = '<div class="cf7-pa-value-item cf7-pa-modal-value-more">' +
615                '<span class="cf7-pa-value-text">+' + remaining_count + '</span></div>';
616            $values_list_element.append(more_chip_html);
617        }
618        
619        if (this.modal_values_expanded && total_count > max_visible_values) {
620            var less_chip_html = '<div class="cf7-pa-value-item cf7-pa-modal-value-less">' +
621                '<span class="cf7-pa-value-text">Show less</span></div>';
622            $values_list_element.append(less_chip_html);
623        }
624    };
625
626    ProductAttributesField.prototype.close_values_modal = function() {
627        this.$modal_element.removeClass('active');
628        this.current_editing_index = -1;
629        $('body').removeClass('cf7-pa-modal-open');
630    };
631
632    ProductAttributesField.prototype.update_save_button_state = function() {
633        if (!this.is_multiselect_enabled) {
634            this.$modal_element.find('.cf7-pa-modal-save').prop('disabled', false);
635            return;
636        }
637        
638        var $input_element = this.$modal_element.find('.cf7-pa-multi-mode input[name="value"]');
639        var input_value = $input_element.val().trim();
640        var has_unsaved_input = input_value.length > 0;
641        
642        this.$modal_element.find('.cf7-pa-modal-save').prop('disabled', has_unsaved_input);
643    };
644
645    ProductAttributesField.prototype.save_attribute_values = function() {
646        var values_array = [];
647
648        this.$modal_element.find('.cf7-pa-error-message').removeClass('visible');
649
650        if (this.is_multiselect_enabled) {
651            values_array = this.modal_values_list.map(function(item) {
652                return item.value;
653            });
654
655            if (values_array.length === 0) {
656                this.$modal_element.find('.cf7-pa-multi-error').addClass('visible');
657                return;
658            }
659        } else {
660            var $input_element = this.$modal_element.find('.cf7-pa-single-mode input[name="value"]');
661            var input_value = '';
662            
663            if (window.cf7_pa_single_value && window.cf7_pa_single_value.data) {
664                input_value = (window.cf7_pa_single_value.data.value || '').trim();
665            } else {
666                input_value = $input_element.val().trim();
667            }
668
669            if (!input_value) {
670                if (typeof window.handleValidate === 'function') {
671                    var validations = $input_element.data('validations');
672                    window.handleValidate(validations, '', $input_element, true);
673                }
674                return;
675            }
676            
677            values_array = [input_value];
678        }
679
680        if (this.current_editing_index >= 0) {
681            this.selected_attributes_list[this.current_editing_index].values = values_array;
682        }
683
684        this.render_selected_attributes_list();
685        this.render_options_list();
686        this.update_hidden_input_value();
687        this.close_values_modal();
688    };
689
690    ProductAttributesField.prototype.update_hidden_input_value = function() {
691        var serialized_data = this.selected_attributes_list.map(function(attribute_item) {
692            return {
693                attribute_id: attribute_item.id,
694                attribute_name: attribute_item.name,
695                display_name: attribute_item.display_name,
696                type: attribute_item.type,
697                values: attribute_item.values
698            };
699        });
700
701        this.$hidden_input_element.val(JSON.stringify(serialized_data));
702        
703        window.selected_product_attributes = serialized_data;
704    };
705
706    ProductAttributesField.prototype.show_error_message = function(error_message) {
707        this.$loading_element.html(
708            '<div class="cf7-pa-error">' +
709            '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">' +
710            '<circle cx="12" cy="12" r="10"></circle>' +
711            '<line x1="12" y1="8" x2="12" y2="12"></line>' +
712            '<line x1="12" y1="16" x2="12.01" y2="16"></line></svg>' +
713            '<span>' + error_message + '</span></div>'
714        );
715    };
716
717    ProductAttributesField.prototype.escape_html_string = function(text_content) {
718        var temp_div = document.createElement('div');
719        temp_div.textContent = text_content;
720        return temp_div.innerHTML;
721    };
722
723    ProductAttributesField.prototype.escape_attribute = function(text_content) {
724        if (!text_content) return '';
725        return String(text_content)
726            .replace(/&/g, '&amp;')
727            .replace(/"/g, '&quot;')
728            .replace(/'/g, '&#39;')
729            .replace(/</g, '&lt;')
730            .replace(/>/g, '&gt;');
731    };
732
733    function initialize_product_attributes_fields() {
734        $('.cf7-product-attributes-wrapper').each(function() {
735            var $wrapper_element = $(this);
736            if (!instances_map.has(this)) {
737                instances_map.set(this, new ProductAttributesField($wrapper_element));
738            }
739        });
740    }
741
742    $(document).ready(initialize_product_attributes_fields);
743    $(document).on('wpcf7initform', initialize_product_attributes_fields);
744
745})(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.