PageSourceSearch

https://beechat.network/wp-content/plugins/wpc-composite-products/assets/js/frontend.js?ver=8.0.3

js beechat.network collected 2026-09-25 20:17:02 UTC 41,580 bytes, 1,102 lines download raw bytes

1'use strict';
2
3(function ($) {
4    var $gallery = null;
5    var gallery_loading = false;
6
7    $(function () {
8        if ($('.wooco-wrap').length) {
9            wooco_init_selector();
10
11            $('.wooco-wrap').each(function () {
12                wooco_init($(this), 'loaded');
13            });
14        }
15    });
16
17    $(document).on('woosq_loaded', function () {
18        // composite products in quick view popup
19        if ($('#woosq-popup .wooco-wrap').length) {
20            wooco_init_selector();
21            wooco_init($('#woosq-popup .wooco-wrap'), 'woosq_loaded');
22        }
23    });
24
25    $(document).on('wooco_save_ids', function (e, ids, $wrap, context, $selected) {
26        const block_ui_params = {
27            message: null, overlayCSS: {
28                background: '#fff', opacity: 0.6,
29            },
30        };
31
32        if ((wooco_vars.change_image === 'yes') && (context === 'loaded' || context === 'on_select' || context === 'on_click')) {
33            var product_id = $wrap.data('id');
34            var $all_gallery = $(wooco_vars.gallery_selector);
35            var $main_gallery = $(wooco_vars.main_gallery_selector);
36
37            if ($all_gallery.length && $main_gallery.length) {
38                if (!ids.length) {
39                    $(document).find('.woocommerce-product-gallery--wooco').unblock().hide();
40                    $main_gallery.unblock().show();
41                } else {
42                    var key = btoa(ids.toString()).replace(/[^a-zA-Z0-9]/g, '');
43                    var $key_gallery = $('.woocommerce-product-gallery--wooco-' + key);
44
45                    if ($key_gallery.length) {
46                        $all_gallery.unblock().hide();
47                        $key_gallery.unblock().show();
48
49                        // scroll to selected image
50                        if ($selected) {
51                            var selected_image = $selected.data('image_gallery');
52                            var $gallery_nav = $key_gallery.find('.flex-control-nav');
53
54                            if ($gallery_nav.length && (selected_image !== undefined) && (selected_image !== '')) {
55                                var $scroll_image = $gallery_nav.find('li img[src="' + selected_image + '"]');
56
57                                if ($scroll_image.length) {
58                                    window.setTimeout(function () {
59                                        $scroll_image.trigger('click');
60                                        $(window).trigger('resize');
61                                    }, 100);
62                                }
63                            }
64                        }
65                    } else {
66                        $all_gallery.block(block_ui_params);
67
68                        if (gallery_loading && ($gallery != null)) {
69                            $gallery.abort();
70                        }
71
72                        var data = {
73                            action: 'wooco_load_gallery',
74                            nonce: wooco_vars.nonce,
75                            product_id: product_id,
76                            key: key,
77                            ids: ids,
78                        };
79
80                        gallery_loading = true;
81
82                        $gallery = $.post(wooco_vars.wc_ajax_url.toString().replace('%%endpoint%%', 'wooco_load_gallery'), data, function (response) {
83                            if (response.gallery) {
84                                var $wooco_gallery = $(response.gallery);
85
86                                $all_gallery.unblock().hide();
87                                $wooco_gallery.insertAfter($main_gallery);
88                                $(document).trigger('wooco_gallery_loaded', product_id, key, ids);
89
90                                $wooco_gallery.imagesLoaded(function () {
91                                    $wooco_gallery.wc_product_gallery();
92
93                                    // scroll to selected image
94                                    if ($selected) {
95                                        var selected_image = $selected.data('image_gallery');
96                                        var $gallery_nav = $wooco_gallery.find('.flex-control-nav');
97
98                                        if ($gallery_nav.length && (selected_image !== undefined) && (selected_image !== '')) {
99                                            var $scroll_image = $gallery_nav.find('li img[src="' + selected_image + '"]');
100
101                                            if ($scroll_image.length) {
102                                                window.setTimeout(function () {
103                                                    $scroll_image.trigger('click');
104                                                    $(window).trigger('resize');
105                                                }, 100);
106                                            }
107                                        }
108                                    }
109
110                                    $(document).trigger('wooco_gallery_images_loaded', product_id, key, ids);
111                                });
112                            } else {
113                                $all_gallery.unblock();
114                            }
115
116                            gallery_loading = false;
117                        });
118                    }
119                }
120            }
121        }
122    });
123
124    $(document).on('click touch', '.single_add_to_cart_button', function (e) {
125        if ($(this).hasClass('wooco-disabled')) {
126            if (wooco_vars.show_alert === 'change') {
127                wooco_show_alert($(this).closest('.wooco-wrap'));
128            }
129
130            e.preventDefault();
131        }
132    });
133
134    $(document).on('click touch', '.wooco-plus, .wooco-minus', function () {
135        // get values
136        var $qty = $(this).closest('.wooco-qty-wrap').find('.wooco_qty').length ? $(this).closest('.wooco-qty-wrap').find('.wooco_qty') : $(this).closest('.wooco-qty-wrap').find('.qty'),
137            val = parseFloat($qty.val()), max = parseFloat($qty.attr('max')), min = parseFloat($qty.attr('min')),
138            step = $qty.attr('step');
139
140        // format values
141        if (!val || val === '' || val === 'NaN') {
142            val = 0;
143        }
144
145        if (max === '' || max === 'NaN') {
146            max = '';
147        }
148
149        if (min === '' || min === 'NaN') {
150            min = 0;
151        }
152
153        if (step === 'any' || step === '' || step === undefined || parseFloat(step) === 'NaN') {
154            step = 1;
155        } else {
156            step = parseFloat(step);
157        }
158
159        // change the value
160        if ($(this).is('.wooco-plus')) {
161            if (max && (val >= max)) {
162                $qty.val(max);
163            } else {
164                $qty.val((val + step).toFixed(wooco_decimal_places(step)));
165            }
166        } else {
167            if (min && (val <= min)) {
168                $qty.val(min);
169            } else if (val > 0) {
170                $qty.val((val - step).toFixed(wooco_decimal_places(step)));
171            }
172        }
173
174        // trigger change event
175        $qty.trigger('change');
176    });
177
178    $(document).on('keyup change', '.wooco_qty', function () {
179        var $this = $(this);
180        var $wrap = $this.closest('.wooco-wrap');
181        var val = parseFloat($this.val());
182        var min = parseFloat($this.attr('min'));
183        var max = parseFloat($this.attr('max'));
184
185        if ((val < min) || isNaN(val)) {
186            val = min;
187            $this.val(val);
188        }
189
190        if (val > max) {
191            val = max;
192            $this.val(val);
193        }
194
195        $this.closest('.wooco_component_product_selection_item').attr('data-qty', val);
196        $this.closest('.wooco_component_product').attr('data-qty', val);
197
198        wooco_init($wrap, 'update_qty');
199    });
200
201    $(document).on('change', '.wooco-checkbox', function () {
202        var $wrap = $(this).closest('.wooco-wrap');
203
204        wooco_init($wrap, 'checked');
205    });
206
207    $(document).on('change', '.wooco_component_product_select', function () {
208        // check on select
209        var $this = $(this);
210        var $selection = $this.closest('.wooco_component_product_selection');
211        var $component = $this.closest('.wooco_component_product');
212        var $wrap = $this.closest('.wooco-wrap');
213        var $selected = $('option:selected', this);
214
215        wooco_selected($selected, $selection, $component);
216        wooco_init($wrap, 'on_select', $selected);
217    });
218
219    $(document).on('click touch', '.wooco_component_product_selection_item', function (e) {
220        if ($(e.target).closest('.wooco_component_product_selection_item_qty').length === 0 && !$(e.target).is('a, a *')) {
221            // check on select
222            var $this = $(this);
223            var $selection = $this.closest('.wooco_component_product_selection');
224            var $component = $this.closest('.wooco_component_product');
225            var $wrap = $this.closest('.wooco-wrap');
226
227            if ($component.attr('data-multiple') === 'yes') {
228                // multiple selection
229                if ($this.hasClass('wooco_item_selected')) {
230                    $this.removeClass('wooco_item_selected');
231                    wooco_deselect($this, $selection, $component);
232                } else {
233                    $this.addClass('wooco_item_selected');
234                    wooco_selected($this, $selection, $component);
235                }
236            } else {
237                // single selection
238                if ($this.hasClass('wooco_item_selected')) {
239                    // remove
240                    $component.attr('data-id', '-1');
241                    $component.attr('data-price', '');
242                    $component.attr('data-price-html', '');
243                    $component.attr('data-regular-price', '');
244                    $this.removeClass('wooco_item_selected');
245                    wooco_deselect($this, $selection, $component);
246                } else {
247                    $selection.find('.wooco_component_product_selection_item').removeClass('wooco_item_selected');
248                    $this.addClass('wooco_item_selected');
249                    wooco_selected($this, $selection, $component);
250                }
251            }
252
253            wooco_init($wrap, 'on_click', $this);
254        }
255    });
256
257    $(document).on('select2:select', '.wooco_component_product_select', function (e) {
258        var $this = $(this);
259        var $selection = $this.closest('.wooco_component_product_selection');
260        var $component = $this.closest('.wooco_component_product');
261        var $wrap = $this.closest('.wooco-wrap');
262        var $selected = $(e.params.data.element);
263
264        wooco_selected($selected, $selection, $component);
265        wooco_init($wrap, 'on_select', $selected);
266    });
267})(jQuery);
268
269function wooco_init($wrap, context = null, $selected = null) {
270    if (context === 'loaded' || context === 'woosq_loaded') {
271        // update qty
272        if ($wrap.find('.wooco_qty').length) {
273            $wrap.find('.wooco_qty').trigger('change');
274        } else {
275            $wrap.find('.qty').trigger('change');
276        }
277    }
278
279    wooco_check_ready($wrap, context, $selected);
280    wooco_save_ids($wrap, context, $selected);
281
282    if (context === null || context === 'on_select' || context === wooco_vars.show_alert) {
283        wooco_show_alert($wrap, context, $selected);
284    }
285
286    // Update selected products summary when setting is enabled
287    if ((context === 'on_select' || context === 'on_click' || context === 'update_qty') && wooco_vars.show_selected === 'yes') {
288        wooco_step_update_selected($wrap);
289    }
290
291    // Refresh selected summary on initial load too
292    if ((context === 'loaded' || context === 'woosq_loaded' || context === 'selected') && wooco_vars.show_selected === 'yes') {
293        wooco_step_update_selected($wrap);
294    }
295
296    jQuery(document).trigger('wooco_init', [$wrap, context, $selected]);
297}
298
299function wooco_check_ready($wrap, context = null, $selected = null) {
300    var wid = $wrap.attr('data-id');
301    var $components = $wrap.find('.wooco-components');
302    var $ids = jQuery('.wooco-ids-' + wid);
303    var $btn = $ids.closest('form.cart').find('.single_add_to_cart_button');
304    var $alert = $wrap.find('.wooco-alert');
305    var is_selection = false;
306    var c_name = '';
307    var is_min = false;
308    var is_max = false;
309    var is_m_min = false;
310    var is_m_max = false;
311    var is_same = false;
312    var is_total_min = false;
313    var is_total_max = false;
314    var is_count = false;
315    var selected_products = [];
316    var allow_same = $components.attr('data-same');
317    var qty = 0;
318    var m_min = 0;
319    var m_max = 10000;
320    var qty_min = parseFloat($components.attr('data-min'));
321    var qty_max = parseFloat($components.attr('data-max'));
322    var total_min = parseFloat($components.attr('data-total-min'));
323    var total_max = parseFloat($components.attr('data-total-max'));
324    var $total = $wrap.find('.wooco-total');
325    var $count = $wrap.find('.wooco-count');
326    var $price = jQuery('.wooco-price-' + wid);
327    var $woobt = jQuery('.woobt-wrap-' + wid);
328    var pricing = $components.attr('data-pricing');
329    var price = wooco_format_number($components.attr('data-price'));
330    var regular_price = wooco_format_number($components.attr('data-regular-price'));
331    var percent = wooco_format_number($components.attr('data-percent'));
332    var total = 0;
333    var total_regular = 0;
334
335    if (!$components.length || !$components.find('.wooco_component_product').length) {
336        return;
337    }
338
339    // calculate price
340
341    if (pricing === 'only') {
342        total = price;
343        total_regular = regular_price;
344    } else {
345        // calc price
346        $components.find('.wooco_component_product').each(function () {
347            var $this = jQuery(this);
348            var $checkbox = $this.find('.wooco-checkbox');
349            var _price = wooco_format_number($this.attr('data-price'));
350            var _regular_price = wooco_format_number($this.attr('data-regular-price'));
351            var _qty = wooco_format_number($this.attr('data-qty'));
352            var _multiple = $this.attr('data-multiple');
353
354            if ($checkbox.length && !$checkbox.prop('checked')) {
355                return;
356            }
357
358            if (_multiple === 'yes') {
359                // multiple selection
360
361                $this.find('.wooco_item_selected').each(function () {
362                    var $_this = jQuery(this);
363                    var __price = wooco_format_number($_this.attr('data-price'));
364                    var __regular_price = wooco_format_number($_this.attr('data-regular-price'));
365                    var __qty = wooco_format_number($_this.attr('data-qty'));
366
367                    if ((__price > 0) && (__qty > 0)) {
368                        total += __price * __qty;
369                    }
370
371                    if ((__regular_price > 0) && (__qty > 0)) {
372                        total_regular += __regular_price * __qty;
373                    }
374                });
375            } else {
376                // single selection
377
378                if ((_price > 0) && (_qty > 0)) {
379                    total += _price * _qty;
380                }
381
382                if ((_regular_price > 0) && (_qty > 0)) {
383                    total_regular += _regular_price * _qty;
384                }
385            }
386        });
387
388        // discount
389        if ((percent > 0) && (percent < 100)) {
390            total = total * (100 - percent) / 100;
391        }
392
393        if (pricing === 'include') {
394            total += price;
395            total_regular += regular_price;
396        }
397    }
398
399    var total_html = wooco_price_html(total_regular, total);
400
401    if ((pricing !== 'only') && (percent > 0) && (percent < 100)) {
402        total_html += ' <small class="woocommerce-price-suffix">' + wooco_vars.saved_text.replace('[d]', percent + '%') + '</small>';
403    }
404
405    $total.html(wooco_vars.total_text + ' ' + total_html).slideDown();
406
407    if ((wooco_vars.change_price !== 'no') && (pricing !== 'only')) {
408        if ((wooco_vars.change_price === 'yes_custom') && (wooco_vars.price_selector !== null) && (wooco_vars.price_selector !== '')) {
409            $price = jQuery(wooco_vars.price_selector);
410        }
411
412        $price.html(total_html);
413    }
414
415    if ($woobt.length) {
416        $woobt.find('.woobt-products').attr('data-product-price-html', total_html);
417        $woobt.find('.woobt-product-this').attr('data-price', total).attr('data-regular-price', total_regular);
418
419        woobt_init($woobt);
420    }
421
422    jQuery(document).trigger('wooco_calc_price', [total, total_regular, total_html, $wrap, context, $selected]);
423
424    // check ready
425
426    $components.find('.wooco_component_product').each(function () {
427        var $this = jQuery(this);
428        var $checkbox = $this.find('.wooco-checkbox');
429        var _selected = false;
430        var _name = $this.attr('data-name');
431        var _id = parseInt($this.attr('data-id'));
432        var _qty = parseFloat($this.attr('data-qty'));
433        var _required = $this.attr('data-required');
434        var _multiple = $this.attr('data-multiple');
435        var _custom_qty = $this.attr('data-custom-qty');
436
437        if ($checkbox.length && !$checkbox.prop('checked')) {
438            return;
439        }
440
441        if (_custom_qty === 'yes' || _multiple === 'yes') {
442            is_count = true;
443        }
444
445        if (_multiple === 'yes') {
446            // multiple selection
447            var _m_qty = 0;
448            var _m_min = parseFloat($this.attr('data-m-min'));
449            var _m_max = parseFloat($this.attr('data-m-max'));
450
451            $this.find('.wooco_item_selected').each(function () {
452                var $_this = jQuery(this);
453                var __id = parseInt($_this.attr('data-id'));
454                var __qty = parseFloat($_this.attr('data-qty'));
455
456                if (__id > 0) {
457                    qty += __qty;
458                    _m_qty += __qty;
459                    _selected = true;
460                }
461
462                if (allow_same === 'no') {
463                    if (selected_products.includes(__id)) {
464                        is_same = true;
465                    } else {
466                        if (__id > 0) {
467                            selected_products.push(__id);
468                        }
469                    }
470                }
471            });
472
473            if (_m_qty < _m_min) {
474                is_m_min = true;
475                m_min = _m_min;
476
477                if (c_name === '') {
478                    c_name = _name;
479                }
480            }
481
482            if (_m_qty > _m_max) {
483                is_m_max = true;
484                m_max = _m_max;
485
486                if (c_name === '') {
487                    c_name = _name;
488                }
489            }
490        } else {
491            // single selection
492
493            if (_id > 0) {
494                qty += _qty;
495                _selected = true;
496            }
497
498            if (allow_same === 'no') {
499                if (selected_products.includes(_id)) {
500                    is_same = true;
501                } else {
502                    if (_id > 0) {
503                        selected_products.push(_id);
504                    }
505                }
506            }
507        }
508
509        if (!_selected && (_required === 'yes')) {
510            is_selection = true;
511
512            if (c_name === '') {
513                c_name = _name;
514            }
515        }
516    });
517
518    if (is_count) {
519        $count.html('<span class="wooco-count-label">' + wooco_vars.selected_text + '</span> <span class="wooco-count-value">' + qty + '</span>').slideDown();
520        jQuery(document).trigger('wooco_change_count', [$count, qty, qty_min, qty_max]);
521    }
522
523    if (qty < qty_min) {
524        is_min = true;
525    }
526
527    if (qty > qty_max) {
528        is_max = true;
529    }
530
531    if ((pricing !== 'only')) {
532        // check total min
533        if (total_min > 0 && total < total_min) {
534            is_total_min = true;
535        }
536
537        // check total max
538        if (total_max > 0 && total > total_max) {
539            is_total_max = true;
540        }
541    }
542
543    if (is_selection || is_min || is_max || is_m_min || is_m_max || is_same || is_total_min || is_total_max) {
544        $btn.addClass('wooco-disabled');
545        $alert.addClass('alert-active');
546
547        if (is_selection) {
548            $alert.addClass('alert-selection').html(wooco_vars.alert_selection.replace('[name]', '<strong>' + c_name + '</strong>'));
549        } else if (is_m_min) {
550            $alert.addClass('alert-min').html(wooco_vars.alert_m_min.replace('[min]', m_min).replace('[name]', '<strong>' + c_name + '</strong>'));
551        } else if (is_m_max) {
552            $alert.addClass('alert-max').html(wooco_vars.alert_m_max.replace('[max]', m_max).replace('[name]', '<strong>' + c_name + '</strong>'));
553        } else if (is_min) {
554            $alert.addClass('alert-min').html(wooco_vars.alert_min.replace('[min]', qty_min));
555        } else if (is_max) {
556            $alert.addClass('alert-max').html(wooco_vars.alert_max.replace('[max]', qty_max));
557        } else if (is_same) {
558            $alert.addClass('alert-same').html(wooco_vars.alert_same);
559        } else if (is_total_min) {
560            $alert.addClass('alert-total-min').html(wooco_vars.alert_total_min.replace('[min]', wooco_format_price(total_min)).replace('[total]', wo
560oco_format_price(total)));
561        } else if (is_total_max) {
562            $alert.addClass('alert-total-max').html(wooco_vars.alert_total_max.replace('[max]', wooco_format_price(total_max)).replace('[total]', wooco_format_price(total)));
563        }
564
565        $alert.slideDown();
566
567        jQuery(document).trigger('wooco_check_ready', [false, is_selection, is_same, is_min, is_max, $wrap, context, $selected]);
568    } else {
569        $alert.removeClass('alert-active alert-selection alert-min alert-max alert-total-min alert-total-max').slideUp(300, function () {
570            $alert.html('');
571        });
572        $btn.removeClass('wooco-disabled');
573
574        // ready
575        jQuery(document).trigger('wooco_check_ready', [true, is_selection, is_same, is_min, is_max, $wrap, context, $selected]);
576    }
577}
578
579function wooco_save_ids($wrap, context = null, $selected = null) {
580    var wid = $wrap.attr('data-id');
581    var $components = $wrap.find('.wooco-components');
582    var $ids = jQuery('.wooco-ids-' + wid);
583    var ids = Array();
584
585    $components.find('.wooco_component_product').each(function () {
586        var $this = jQuery(this);
587        var $checkbox = $this.find('.wooco-checkbox');
588        var key = $this.data('key');
589
590        if ($checkbox.length && !$checkbox.prop('checked')) {
591            return;
592        }
593
594        if ($this.attr('data-multiple') === 'yes') {
595            // multiple selection
596            $this.find('.wooco_item_selected').each(function () {
597                var $_this = jQuery(this);
598
599                if (($_this.attr('data-id') > 0) && ($_this.attr('data-qty') > 0)) {
600                    ids.push($_this.attr('data-id') + '/' + $_this.attr('data-qty') + '/' + key);
601                }
602            });
603        } else {
604            // single selection
605
606            if (($this.attr('data-id') > 0) && ($this.attr('data-qty') > 0)) {
607                ids.push($this.attr('data-id') + '/' + $this.attr('data-qty') + '/' + key);
608            }
609        }
610    });
611
612    $ids.val(ids.join(','));
613    jQuery(document).trigger('wooco_save_ids', [ids, $wrap, context, $selected]);
614}
615
616function wooco_show_alert($wrap, context = null, $selected = null) {
617    var $alert = $wrap.find('.wooco-alert');
618
619    if ($alert.hasClass('alert-active')) {
620        $alert.slideDown();
621    } else {
622        $alert.slideUp();
623    }
624
625    jQuery(document).trigger('wooco_show_alert', [$wrap, context, $selected]);
626}
627
628function wooco_init_selector() {
629    if (wooco_vars.selector === 'ddslick') {
630        jQuery('.wooco_component_product_select').each(function () {
631            var $this = jQuery(this);
632            var $selection = $this.closest('.wooco_component_product_selection');
633            var $component = $this.closest('.wooco_component_product');
634            var $wrap = $this.closest('.wooco-wrap');
635
636            $selection.data('select', 0);
637
638            $this.ddslick({
639                width: '100%', onSelected: function (data) {
640                    var _select = $selection.data('select');
641                    var $selected = jQuery(data.original[0].children[data.selectedIndex]);
642
643                    if (data.selectedData.value == '-1') {
644                        if (!$selection.find('.dd-selected .dd-desc').length) {
645                            $selection.find('.dd-selected').addClass('dd-option-without-desc');
646                            $selection.find('.dd-option-selected').addClass('dd-option-without-desc');
647                        } else {
648                            $selection.find('.dd-selected').removeClass('dd-option-without-desc');
649                            $selection.find('.dd-option-selected').removeClass('dd-option-without-desc');
650                        }
651                    }
652
653                    // check empty desc
654                    if (!$selection.hasClass('wooco-ddslick-checked-desc')) {
655                        $selection.find('.dd-selected, .dd-option').each(function () {
656                            if (!jQuery(this).find('.dd-desc').length) {
657                                jQuery(this).addClass('dd-option-without-desc');
658                            } else {
659                                jQuery(this).removeClass('dd-option-without-desc');
660                            }
661                        });
662
663                        $selection.addClass('wooco-ddslick-checked-desc');
664                    }
665
666                    // check disabled
667                    if (!$selection.hasClass('wooco-ddslick-checked-disabled')) {
668                        $selection.find('.dd-selected, .dd-option').each(function () {
669                            if (parseInt(jQuery(this).find('.dd-option-value').val()) === 0) {
670                                jQuery(this).addClass('dd-option-disabled');
671                            } else {
672                                jQuery(this).removeClass('dd-option-disabled');
673                            }
674                        });
675
676                        $selection.addClass('wooco-ddslick-checked-disabled');
677                    }
678
679                    wooco_selected($selected, $selection, $component);
680
681                    if (_select > 0) {
682                        wooco_init($wrap, 'on_select', $selected);
683                    } else {
684                        // selected on init_selector
685                        wooco_init($wrap, 'selected', $selected);
686                    }
687
688                    $selection.data('select', _select + 1);
689                },
690            });
691        });
692    } else if (wooco_vars.selector === 'select2') {
693        jQuery('.wooco_component_product_select').each(function () {
694            var $this = jQuery(this);
695            var $selection = $this.closest('.wooco_component_product_selection');
696            var $component = $this.closest('.wooco_component_product');
697            var $wrap = $this.closest('.wooco-wrap');
698
699            if ($this.val() !== '') {
700                var $default = jQuery('option:selected', this);
701
702                wooco_selected($default, $selection, $component);
703                wooco_init($wrap, 'selected', $default);
704            }
705
706            $this.select2({
707                templateResult: wooco_select2_state,
708                width: '100%',
709                containerCssClass: 'wpc-select2-container',
710                dropdownCssClass: 'wpc-select2-dropdown',
711            });
712        });
713    } else {
714        jQuery('.wooco_component_product_select').each(function () {
715            // check on start
716            var $this = jQuery(this);
717            var $selection = $this.closest('.wooco_component_product_selection');
718            var $component = $this.closest('.wooco_component_product');
719            var $wrap = $this.closest('.wooco-wrap');
720            var $selected = jQuery('option:selected', this);
721
722            wooco_selected($selected, $selection, $component);
723            wooco_init($wrap, 'selected', $selected);
724        });
725    }
726
727    jQuery('.wooco_component_product_selection_item.wooco_item_selected').each(function () {
728        var $this = jQuery(this);
729        var $selection = $this.closest('.wooco_component_product_selection');
730        var $component = $this.closest('.wooco_component_product');
731        var $wrap = $this.closest('.wooco-wrap');
732
733        wooco_selected($this, $selection, $component);
734        wooco_init($wrap, 'selected', $this);
735    });
736}
737
738function wooco_selected($selected, $selection, $component) {
739    var id = $selected.attr('data-id');
740    var pid = $selected.attr('data-pid');
741    var price = $selected.attr('data-price');
742    var purchasable = $selected.attr('data-purchasable');
743    var regular_price = $selected.attr('data-regular-price');
744    var link = $selected.attr('data-link');
745    var image = '<img src="' + $selected.attr('data-imagesrc') + '"/>';
746    var price_html = $selected.attr('data-price-html');
747    var availability = $selected.attr('data-availability');
748    var custom_qty = $component.attr('data-custom-qty');
749    var qid = id; // product ID for quick view
750
751    if (purchasable === 'yes') {
752        $component.attr('data-id', id);
753    } else {
754        $component.attr('data-id', 0);
755    }
756
757    // Store selected product display name for selected summary
758    var selectedName = jQuery.trim(
759        $selected.attr('data-name')
760        || $selected.text()
761        || ''
762    );
763    $component.attr('data-selected-name', selectedName);
764
765    $component.attr('data-price', price);
766    $component.attr('data-price-html', price_html);
767    $component.attr('data-regular-price', regular_price);
768
769    if (custom_qty === 'yes') {
770        if ($selected.find('.wooco_qty').length) {
771            $component.attr('data-qty', $selected.find('.wooco_qty').val());
772        } else if ($selected.find('.qty').length) {
773            $component.attr('data-qty', $selected.find('.qty').val());
774        }
775    }
776
777    if ((wooco_vars.quickview_variation === 'parent') && pid) {
778        qid = pid;
779    }
780
781    if (wooco_vars.product_link !== 'no') {
782        $selection.find('.wooco_component_product_link').remove();
783        if (link !== '') {
784            if (wooco_vars.product_link === 'yes_popup') {
785                $selection.append('<a class="wooco_component_product_link woosq-link" data-id="' + qid + '" data-context="wooco" href="' + link + '" target="_blank"> &nbsp; </a>');
786            } else {
787                $selection.append('<a class="wooco_component_product_link" href="' + link + '" target="_blank"> &nbsp; </a>');
788            }
789        }
790    }
791
792    $component.find('.wooco_component_product_image').html(image);
793    $component.find('.wooco_component_product_price').html(price_html);
794    $component.find('.wooco_component_product_availability').html(availability);
795
796    jQuery(document).trigger('wooco_selected', [$selected, $selection, $component]);
797}
798
799function wooco_deselect($selected, $selection, $component) {
800    jQuery(document).trigger('wooco_deselected', [$selected, $selection, $component]);
801}
802
803function wooco_select2_state(state) {
804    if (!state.id) {
805        return state.text;
806    }
807
808    var $state = {};
809
810    if (jQuery(state.element).attr('data-imagesrc') !== '') {
811        $state = jQuery('<span class="image"><img src="' + jQuery(state.element).attr('data-imagesrc') + '"/></span><span class="info"><span class="name">' + state.text + '</span> <span class="desc">' + jQuery(state.element).attr('data-description') + '</span></span>');
812    } else {
813        $state = jQuery('<span class="info"><span class="name">' + state.text + '</span> <span class="desc">' + jQuery(state.element).attr('data-description') + '</span></span>');
814    }
815
816    return $state;
817}
818
819function wooco_round(value) {
820    return Number(Math.round(value + 'e' + wooco_vars.price_decimals) + 'e-' + wooco_vars.price_decimals);
821}
822
823function wooco_decimal_places(num) {
824    var match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
825
826    if (!match) {
827        return 0;
828    }
829
830    return Math.max(0, // Number of digits right of decimal point.
831        (match[1] ? match[1].length : 0)
832        // Adjust for scientific notation.
833        - (match[2] ? +match[2] : 0));
834}
835
836function wooco_format_money(number, places, symbol, thousand, decimal) {
837    number = number || 0;
838    places = !isNaN(places = Math.abs(places)) ? places : 2;
839    symbol = symbol !== undefined ? symbol : '$';
840    thousand = thousand || '';
841    decimal = decimal || '';
842
843    var negative = number < 0 ? '-' : '', i = parseInt(number = Math.abs(+number || 0).toFixed(places), 10) + '', j = 0;
844
845    if (i.length > 3) {
846        j = i.length % 3;
847    }
848
849    if (wooco_vars.trim_zeros === '1') {
850        return symbol + negative + (j ? i.substr(0, j) + thousand : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand) + (places && (parseFloat(number) > parseFloat(i)) ? decimal + Math.abs(number - i).toFixed(places).slice(2).replace(/(\d*?[1-9])0+$/g, '$1') : '');
851    } else {
852        return symbol + negative + (j ? i.substr(0, j) + thousand : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand) + (places ? decimal + Math.abs(number - i).toFixed(places).slice(2) : '');
853    }
854}
855
856function wooco_format_number(number) {
857    return parseFloat(number.replace(/[^0-9.,]/g, '').replace(',', '.'));
858}
859
860function wooco_format_price(price) {
861    var price_html = '<span class="woocommerce-Price-amount amount">';
862    var price_formatted = wooco_format_money(price, wooco_vars.price_decimals, '', wooco_vars.price_thousand_separator, wooco_vars.price_decimal_separator);
863
864    switch (wooco_vars.price_format) {
865        case '%1$s%2$s':
866            //left
867            price_html += '<span class="woocommerce-Price-currencySymbol">' + wooco_vars.currency_symbol + '</span>' + price_formatted;
868            break;
869        case '%1$s %2$s':
870            //left with space
871            price_html += '<span class="woocommerce-Price-currencySymbol">' + wooco_vars.currency_symbol + '</span> ' + price_formatted;
872            break;
873        case '%2$s%1$s':
874            //right
875            price_html += price_formatted + '<span class="woocommerce-Price-currencySymbol">' + wooco_vars.currency_symbol + '</span>';
876            break;
877        case '%2$s %1$s':
878            //right with space
879            price_html += price_formatted + ' <span class="woocommerce-Price-currencySymbol">' + wooco_vars.currency_symbol + '</span>';
880            break;
881        default:
882            //default
883            price_html += '<span class="woocommerce-Price-currencySymbol">' + wooco_vars.currency_symbol + '</span> ' + price_formatted;
884    }
885
886    price_html += '</span>';
887
888    return price_html;
889}
890
891function wooco_price_html(regular_price, sale_price) {
892    var price_html = '';
893
894    if (wooco_round(sale_price) !== wooco_round(regular_price)) {
895        if (wooco_round(sale_price) < wooco_round(regular_price)) {
896            price_html = '<del>' + wooco_format_price(regular_price) + '</del> <ins>' + wooco_format_price(sale_price) + '</ins>';
897        } else {
898            price_html = wooco_format_price(sale_price);
899        }
900    } else {
901        price_html = wooco_format_price(regular_price);
902    }
903
904    return price_html;
905}
906
907/**
908 * Update the .wooco-selected summary div with a list of all selected products across steps.
909 * If the container doesn't exist yet (stale cache), it is injected before .wooco-total.
910 */
911function wooco_step_update_selected($wrap) {
912    var $container = $wrap.find('.wooco-selected');
913
914    // Inject container if PHP cache served old HTML without it
915    if (!$container.length) {
916        var $summary = $wrap.find('.wooco_summary, .wooco-summary').first();
917
918        if ($summary.length) {
919            $summary.before('<div class="wooco-selected"></div>');
920            $container = $wrap.find('.wooco-selected');
921        }
922
923        if (!$container.length) {
924            return;
925        }
926    }
927
928    var $steps = $wrap.find('.wooco-components').children('.wooco_component');
929
930    if (!$steps.length) {
931        $container.hide();
932        return;
933    }
934
935    var rows = [];
936
937    $steps.each(function () {
938        var $step     = jQuery(this);
939        var $product  = $step.find('.wooco_component_product').first();
940        var labelEl   = $step.find('.wooco_component_name').first().text().trim();
941        var name      = wooco_step_get_selected_name($product);
942
943        // Skip components with no selection
944        if (!name || !labelEl) {
945            return;
946        }
947
948        rows.push(
949            '<div class="wooco-selected-row">'
950            + '<span class="wooco-selected-label">' + labelEl + ':</span> '
951            + '<span class="wooco-selected-name">' + name + '</span>'
952            + '</div>'
953        );
954    });
955
956    if (rows.length === 0) {
957        $container.html('').hide();
958    } else {
959        $container.html(rows.join('')).show();
960    }
961}
962
963/**
964 * Get the display name of the currently selected product inside a .wooco_component_product element.
965 * Returns null when nothing is selected (id <= 0).
966 * Prepend quantity (qty × name) if custom quantity is enabled or qty > 1.
967 */
968function wooco_step_get_selected_name($product) {
969    var isMultiple = $product.attr('data-multiple') === 'yes';
970    var isCustomQty = $product.attr('data-custom-qty') === 'yes';
971
972    // --- Multiple selection: collect all selected item names ---
973    if (isMultiple) {
974        var names = [];
975
976        $product.find('.wooco_item_selected').each(function () {
977            var $item = jQuery(this);
978            var name  = jQuery.trim(
979                $item.find('.wooco_component_product_selection_list_item_name').first().text()
980                || $item.find('.wooco_component_product_selection_grid_item_name').first().text()
981                || $item.attr('data-name')
982                || ''
983            );
984
985            if (name) {
986                var itemQty = parseFloat($item.find('.wooco_qty, .qty').first().val())
987                    || parseFloat($item.attr('data-qty'))
988                    || parseFloat($product.attr('data-qty'))
989                    || 1;
990
991                if (isCustomQty || itemQty > 1) {
992                    name = itemQty + ' &times; ' + name;
993                }
994
995                names.push(name);
996            }
997        });
998
999        return names.length > 0 ? names.join('; ') : null;
1000    }
1001
1002    // --- Single selection ---
1003    var selectedId = parseInt($product.attr('data-id') || 0);
1004
1005    if (selectedId <= 0) {
1006        return null;
1007    }
1008
1009    var name = null;
1010
1011    // 1. Check cached name stored by wooco_selected()
1012    var cachedName = jQuery.trim($product.attr('data-selected-name') || '');
1013    if (cachedName) {
1014        name = cachedName;
1015    }
1016
1017    if (!name) {
1018        // --- Dropdown selectors (select / ddslick / select2) ---
1019        var $select = $product.find('.wooco_component_product_select');
1020
1021        if ($select.length) {
1022            // Option with matching value
1023            var $opt = $select.find('option[value="' + selectedId + '"]');
1024            if ($opt.length) {
1025                name = jQuery.trim($opt.text());
1026            }
1027
1028            if (!name) {
1029                // Option with matching data-id attribute
1030                $opt = $select.find('option').filter(function () {
1031                    return parseInt(jQuery(this).attr('data-id') || 0) === selectedId;
1032                });
1033                if ($opt.length) {
1034                    name = jQuery.trim($opt.first().text());
1035                }
1036            }
1037
1038            if (!name) {
1039                // Whatever option is marked :selected
1040                var $chosen = $select.find('option:selected');
1041                if ($chosen.length && parseInt($chosen.val()) > 0) {
1042                    name = jQuery.trim($chosen.text());
1043                }
1044            }
1045        }
1046    }
1047
1048    if (!name) {
1049        // ddslick selected label text
1050        var $ddText = $product.find('.dd-selected-text');
1051        if ($ddText.length) {
1052            var ddName = jQuery.trim($ddText.text());
1053            if (ddName) {
1054                name = ddName;
1055            }
1056        }
1057    }
1058
1059    if (!name) {
1060        // --- List layout ---
1061        var $listName = $product.find('.wooco_item_selected .wooco_component_product_selection_list_item_name').first();
1062        if ($listName.length) {
1063            name = jQuery.trim($listName.text());
1064        }
1065    }
1066
1067    if (!name) {
1068        // --- Grid layout ---
1069        var $gridName = $product.find('.wooco_item_selected .wooco_component_product_selection_grid_item_name').first();
1070        if ($gridName.length) {
1071            name = jQuery.trim($gridName.text());
1072        }
1073    }
1074
1075    if (!name) {
1076        // --- Generic fallback: data-name on any selected item ---
1077        var $anyItem = $product.find('.wooco_item_selected').first();
1078        if ($anyItem.length && $anyItem.attr('data-name')) {
1079            name = jQuery.trim($anyItem.attr('data-name'));
1080        }
1081    }
1082
1083    if (!name) {
1084        return null;
1085    }
1086
1087    // Prepend quantity for single selection
1088    var $selectedItem = $product.find('.wooco_item_selected').first();
1089    var $qtyInput = $selectedItem.length
1090        ? $selectedItem.find('.wooco_qty, .qty').first()
1091        : $product.find('.wooco_component_product_qty_input, .wooco_qty, .qty').first();
1092
1093    var qty = parseFloat($qtyInput.val())
1094        || parseFloat($product.attr('data-qty'))
1095        || 1;
1096
1097    if (isCustomQty || qty > 1) {
1098        name = qty + ' &times; ' + name;
1099    }
1100
1101    return name;
1102}

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.