PageSourceSearch

https://www.silex.co.uk/wp-content/plugins/yith-woocommerce-color-…/assets/js/yith-wccl.js?ver=3.21.0

js silex.co.uk collected 2026-10-04 13:29:40 UTC 46,109 bytes, 1,126 lines download raw bytes

1/**
2 * Frontend
3 *
4 * @author YITH <[email protected]>
5 * @package YITH WooCommerce Colors and Labels Variations Premium
6 * @version 1.0.0
7 */
8
9;(function( $, window, document ){
10
11    if ( typeof yith_wccl_general === 'undefined' )
12        return false;
13
14    /**
15     * Matches inline variation objects to chosen attributes and return variation
16     * @type {Object}
17     */
18    var variations_match = function( form, value, current_attribute_name ) {
19        var match = false,
20            product_variations = form.data( 'product_variations' ),
21            all_select = form.find( '.variations select' ),
22            show_specific_attr = true;
23            settings = [];
24
25        // current selected values
26        $.each( all_select, function(){
27            var attribute_name = $( this ).data( 'attribute_name' ) || $( this ).attr( 'name' );
28            if( current_attribute_name == attribute_name ) {
29                settings[attribute_name] = value;
30            }
31            else {
32                if( $(this).val() !== '' ) {
33                    settings[attribute_name] = $(this).val();
34                }
35            }
36        });
37
38        for ( var i = 0; i < product_variations.length; i++ ) {
39            var variation    = product_variations[i];
40
41            // if found matching variation exit
42            if( match ) {
43                break;
44            }
45            var attr = ( show_specific_attr ) ? settings : variation.attributes;
46            if( Object.keys(attr).length >= 1 ) {
47                match = variation;
48                for (var attr_name in attr) {
49                    if (variation.attributes.hasOwnProperty(attr_name) ) {
50                        var val1 = variation.attributes[attr_name],
51                            val2 = settings[attr_name];
52                        if (val1 != val2 && attr[attr_name] != '' && val1 !='') {
53                            match = false;
54                        }
55                    }
56                }
57            }
58        }
59        return match;
60    };
61
62    /**
63     * Add to cart variation loop
64     * @param event
65     */
66    var yith_wccl_add_cart = function( event ){
67
68        event.preventDefault();
69
70        var b          = $( this ),
71            product_id = b.data( 'product_id' ),
72            quantity   = b.data( 'quantity' ),
73            attr = [],
74            data = {};
75
76        $.each( b.data(), function( key, value ) {
77            data[ key ] = value;
78        });
79
80        // get select value
81        event.data.select.each( function(index){
82            attr[ index ] = this.name + '=' + this.value;
83        });
84
85        // Trigger event.
86        $( document.body ).trigger( 'adding_to_cart', [ b, data ] );
87
88        $.ajax({
89            url: yith_wccl_general.ajaxurl.toString().replace( '%%endpoint%%', yith_wccl_general.actionAddCart ),
90            type: 'POST',
91            data: {
92                action: yith_wccl_general.actionAddCart,
93                product_id : product_id,
94                variation_id : event.data.variation,
95                attr: attr.join('&'),
96                quantity: quantity,
97                context: 'frontend'
98            },
99            beforeSend: function(){
100                b.addClass( 'loading').removeClass( 'added' );
101            },
102            success: function( res ){
103
104                // redirect to product page if some error occurred
105                if ( res.error && res.product_url ) {
106                    window.location = res.product_url;
107                    return;
108                }
109                // redirect to cart
110                if ( yith_wccl_general.cart_redirect ) {
111                    window.location = yith_wccl_general.cart_url;
112                    return;
113                }
114
115                // change button
116                b.removeClass('loading').addClass('added');
117
118                if( ! b.next('.added_to_cart').length ) {
119                    b.after(' <a href="' + yith_wccl_general.cart_url + '" class="added_to_cart wc-forward" title="' + yith_wccl_general.view_cart + '">' + yith_wccl_general.view_cart + '</a>');
120                }
121
122                $( document.body ).trigger( 'wc_fragment_refresh' );
123                // trigger refresh also cart page
124                $( document ).trigger( 'wc_update_cart' );
125
126                // added to cart
127                $( document.body ).trigger( 'added_to_cart', [ res.fragments, res.cart_hash, b ] );
128            }
129        });
130    }
131
132    var yith_wccl_change_label = function (label, t) {
133
134        t.closest('tr').find('th label').text(label);
135    };
136
137    /**
138     *
139     * @param $form
140     * @param attr
141     * @constructor
142     */
143    var WCCL = function( $form, attr ) {
144
145        this.$form              = $form;
146        this.$attr              = ( typeof yith_wccl != 'undefined' ) ? JSON.parse( yith_wccl.attributes ) : attr;
147        this.$select            = this.$form.find( '.variations select' );
148        this.$use_ajax          = this.$form.data( 'product_variations' ) === false;
149        this.$attr_number        = this.$form.data('number-variation-attributes');
150        // variables for loop
151        this.$is_loop           = this.$form.hasClass('in_loop');
152        this.$wrapper           = this.$form.closest( yith_wccl_general.wrapper_container_shop ).length ? this.$form.closest( yith_wccl_general.wrapper_container_shop ) : this.$form.closest('.product-add-to-cart' );
153        this.$image             = this.$wrapper.find( yith_wccl_general.image_selector ).first();
154        this.$def_image_src     = ( this.$image.data('lazy-src') ) ? this.$image.data('lazy-src') : this.$image.attr( 'src' );
155        this.$def_image_srcset  = ( this.$image.data('lazy-srcset') ) ? this.$image.data('lazy-srcset') : this.$image.attr( 'srcset' );
156        this.$price_html        = this.$wrapper.find( yith_wccl_general.wrapper_price_shop ).clone().wrap('<p>').parent().html();
157        this.$button            = this.$wrapper.find( yith_wccl_general.add_to_cart_selector_loop );
158        this.$button_html       = this.$button.html();
159        this.$input_qty         = this.$wrapper.find('input.thumbnail-quantity');
160        this.$xhr               = null;
161        this.variations_gallery = []; // store variations gallery to improve performace
162
163        // prevent undefined attr error
164        if( typeof this.$attr == 'undefined' ) {
165            this.$attr = [];
166        }
167
168        $form.on( 'yith_wccl_form_initialized', { obj: this }, this.init );
169
170        // get default value
171        this.$select.each( function() {
172            this.setAttribute( 'data-default_value', this.value );
173        });
174
175        // reset form and select
176        this.resetForm( this );
177
178        if( this.$is_loop ) {
179            $form.parent().on( 'change', function(e) { e.stopPropagation(); });
180        }
181
182        // hide input qty if present
183        if( this.$input_qty.length )
184            this.$input_qty.hide();
185
186        if( ! this.$form.hasClass( 'initialized' ) ) {
187            this.$form.addClass('initialized').fadeIn().trigger( 'yith_wccl_form_initialized' );
188        }
189    };
190
191    WCCL.prototype.styleOption = function( obj, option, type, value ) {
192
193        const regExp = /^(ftp|http|https):\/\/[^ "]+$/;
194
195        if( regExp.test(value ) && 'image' !== type ) {
196            type = 'image';
197        }
198
199        switch ( type ) {
200
201            case 'colorpicker':
202                value = value.split(',');
203
204                if( value.length == 1 ) {
205                    /*option.append($('<span/>', {
206                        'class': 'yith_wccl_value',
207                        'css': {
208                            'background': value
209                        }
210                    }));*/
211                    option.append($('<div class="yith_wccl_value_wrapper"><span class="yith_wccl_value"></span></div>'));
212                    option.find('.yith_wccl_value').css({
213                        'background': value,
214                    });
215                } else {
216                    option.append($('<div class="yith_wccl_value_wrapper"><span class="yith_wccl_value"><span class="yith-wccl-bicolor"/></span></div>'));
217                    option.find('.yith-wccl-bicolor').css({
218                        'background-color': value[0],
219                        'border-color': value[1]
220                    });
221
222                }
223                break;
224            case 'image' :
225                /*option.append($('<img/>', {
226                    'class': 'yith_wccl_value',
227                    'src': value,
228                    'alt':type
229                }));*/
230                option.append($('<div class="yith_wccl_value_wrapper"><img class="yith_wccl_value"/></div>'));
231                option.find('.yith_wccl_value').attr('src',value).attr('alt',type);
232                break;
233
234            case 'label' :
235                /*option.append($('<span/>', {
236                    'class': 'yith_wccl_value',
237                    'text': value
238                }));*/
239                option.append($('<div class="yith_wccl_value_wrapper"><span class="yith_wccl_value"></span></div>'));
240                option.find('.yith_wccl_value').text(value);
241                break;
242
243        }
244    };
245
246    WCCL.prototype.addTooltip = function( obj, tooltip, option, type, value, tooltip_image = '' ) {
247
248        var tooltip_wrapper = $('<span class="yith_wccl_tooltip"></span>'),
249            classes         = yith_wccl_general.tooltip_pos + ' ' + yith_wccl_general.tooltip_ani;
250
251        if( ! yith_wccl_general.tooltip || typeof tooltip == 'undefined' || ( ! tooltip && tooltip_image === '' ) || option.find( '.yith_wccl_tooltip' ).length ) {
252            return;
253        }
254
255        if( type == 'image' ) {
256            tooltip = tooltip.toString().replace('{show_image}', '<img src="' + value + '" />');
257        }
258        if(  tooltip_image !== '' ) {
259            color_image = '<img src="' + tooltip_image + '" />';
260            tooltip = color_image + tooltip.toString();
261        }
262
263        tooltip_wrapper.addClass( classes );
264        option.append( tooltip_wrapper.html( '<span class="yith-wccl-tooltip-image">' + tooltip + '</span>' ) );
265    };
266
267    WCCL.prototype.handleSelect = function( event ) {
268
269        var obj = event.data.obj;
270        var chosenAttributes= {};
271
272        // First loop selectors for know the current chosen attributes.
273        obj.$select.each( function() {
274            var p = $(this);
275            chosenAttributes[this.name] = p.val();
276        });
277        //Display C&L attributes.
278        obj.$select.each( function() {
279        var t               = $(this),
280            current_attr    = obj.$attr[ this.name ],
281            decoded_name    = decodeURIComponent( this.name ),
282            select_box      = t.parent().find( '.select_box' ),
283            current_option  = [],
284            default_label = t.closest('tr').find('th label').data('default-label'),
285            selectParent;
286
287        // Set select parent.
288        selectParent = t.closest('.select-wrapper');
289        if ( ! selectParent.length ) {
290            selectParent = t.closest('td');
291            if ( ! selectParent.length ) {
292                selectParent = t.parent();
293            }
294        }
295
296        if( typeof current_attr == 'undefined' ) {
297            current_attr = obj.$attr[ decoded_name ];
298        }
299        // Add description
300        if ( yith_wccl_general.description && ! obj.$is_loop && ! obj.$wrapper.length && ! obj.$form.find( '.description_' + decoded_name ).length
301             && typeof current_attr != 'undefined' && current_attr.descr ) {
302            if( t.closest('tr').length ) {
303                t.closest('tr').after( '<tr class="description_' + decoded_name + '"><td colspan="2">' + current_attr.descr + '</td></tr>' );
304            } else {
305                selectParent.append( '<p class="description_' + decoded_name + '">' + current_attr.descr + '</p>' );
306            }
307        }
308        var type    = ( typeof current_attr != 'undefined' ) ? current_attr.type : t.data('type'),
309            opt     = ( typeof current_attr != 'undefined' ) ? current_attr.terms : false;
310
311            selectParent.addClass('yith_wccl_layout_'+yith_wccl_general.variation_layout);
312            selectParent.siblings( ".label" ).addClass('yith_wccl_layout_'+yith_wccl_general.variation_layout);
313
314        // exit if is not a custom attr
315        if ( ( ! obj.$is_loop && ( typeof current_attr == 'undefined' || ! current_attr.terms ) ) || typeof type == 'undefined' || ! type ) {
316
317            // Show option selected on th label.
318            t.on('change', function (e) {
319                var label = $(this).closest('tr').find('th label').data('default-label');
320                var actual_val = $(this).val();
321
322                if( actual_val ) {
323                    label = label + yith_wccl_general.attribute_separator + actual_val;
324                }
325                if( yith_wccl_general.change_label_on_selected_attribute ) {
326                    yith_wccl_change_label(label, $(this));
327                }
328
329            });
330          return;
331        }
332
333        t.addClass('yith_wccl_custom').hide();
334            selectParent.addClass('yith_wccl_is_custom');
335
336        if( ! select_box.length || ! yith_wccl_general.grey_out ) {
337            select_box.remove();
338            select_box = $('<div />', {
339                'class': 'select_box_' + type + ' select_box ' + t.attr('name')
340            }).insertAfter(t);
341        }
342        t.find('option').each(function () {
343            var option_val = $(this).val();
344            if( ( opt && typeof opt[option_val] != 'undefined') || ( typeof $(this).data('value') !== 'undefined' && $(this).data('value') !== '' ) ) {
345                current_option.push( option_val );
346
347                var o           = $(this),
348                    classes     = 'select_option_' + type + ' select_option',
349                    value       = opt && typeof opt[option_val] != 'undefined' ? opt[option_val].value : $(this).data('value'),
350                    tooltip     = opt && typeof opt[option_val] != 'undefined' ? opt[option_val].tooltip : $(this).data('tooltip'),
351                    tooltip_image     = opt && typeof opt[option_val] != 'undefined' ? opt[option_val].tooltip_image : $(this).data('tooltip_image'),
352                    option      = select_box.find('[data-value="' + option_val + '"]'),
353                    attr_type   = opt && typeof opt[option_val] != 'undefined' ? opt[option_val].type : $(this).data('type');
354
355                type       =  attr_type ? attr_type : type;
356                // add options if missing
357                if( ! option.length ) {
358                    // add selected class if is default
359                    if( option_val == t.val() || option_val == t.attr( 'data-default_value' ) ) {
360                        classes += ' selected';
361                        if( yith_wccl_general.change_label_on_selected_attribute && default_label !== undefined ) {
362                                yith_wccl_change_label( default_label + yith_wccl_general.attribute_separator+o[0].label, t );
363                        }
364                    }
365
366                    option = $('<div/>', {
367                        'class': classes,
368                        'data-value': option_val,
369                        'data-label': o[0].label,
370                        'data-tooltip_image': tooltip_image,
371                        'data-attr_name': decoded_name,
372                    }).appendTo(select_box);
373
374                    // event
375                    option.off('click').on('click', function (e) {
376
377                        var inactive = $(this).hasClass('inactive'),
378                            selected = $(this).hasClass('selected');
379
380                        if( inactive ) {
381
382                            var current_attribute_name = t.data('attribute_name') || t.attr('name');
383
384                            if( variations_match( obj.$form, $(this).data('value'), current_attribute_name ) ) {
385                                t.val('').change();
386                            }
387                        }
388
389                        if( selected ) {
390                            t.val('').change();
391                            if( yith_wccl_general.change_label_on_selected_attribute ) {
392                                yith_wccl_change_label(default_label, t);
393                            }
394                        } else {
395                            t.val( o.val() ).change();
396                            var label = $(this).data('label');
397                            if( yith_wccl_general.change_label_on_selected_attribute ) {
398                                yith_wccl_change_label(default_label + yith_wccl_general.attribute_separator + label, t);
399                            }
400                        }
401
402                        $(this).toggleClass( 'selected' );
403                        $(this).siblings().removeClass( 'selected' );
404                    });
405
406                    // style option
407                    obj.styleOption( obj, option, type, value );
408                    // add tooltip if any
409                    obj.addTooltip( obj, tooltip, option, type, value, tooltip_image );
410                }
411            }
412        });
413
414        var variationData = obj.$form.data('product_variations');
415
416        //TODO Try to save the actual variations in order to know if they are available or not
417        select_box.children().each(function () {
418            var val = $(this).data('value') + '';
419            var opt_attr_name = $(this).closest( '.yith_wccl_is_custom' ).find( 'select.yith_wccl_custom' ).attr( 'name' );
420            let chosenAttr = Object.assign({}, chosenAttributes); //Copy original selected attributes.
421            var in_stock = true;
422
423            if ( $.inArray( val, current_option ) == '-1' ) {
424                $(this).addClass('yith-wccl-remove');
425            } else {
426                $(this).removeClass('yith-wccl-remove');
427            }
428
429            if( !obj.$use_ajax ) {
430                // Add inactive cross on out-of-stock attributes.
431                chosenAttr[opt_attr_name] = val;
432                var variations = obj.findMatchingVariations(variationData, chosenAttr);
433                in_stock = variations.find(variation => variation.is_in_stock === true) ? true : false;
434                if (!in_stock) {
435                    $(this).addClass('inactive');
436                    switch (yith_wccl_general.attribute_style) {
437                        case 'blur_cross' :
438                            $(this).addClass('inactive_cross');
439                            break;
440                        case 'hide':
441                            $(this).addClass('yith-wccl-remove');
442                            break;
443                    }
444                } else {
445                    $(this).removeClass('inactive');
446                    switch (yith_wccl_general.attribute_style) {
447                        case 'blur_cross' :
448                            $(this).removeClass('inactive_cross');
449                            break;
450                        case 'hide':
451                            $(this).removeClass('yith-wccl-remove');
452                            break;
453                    }
454                }
455            }
456        });
457
458        obj.$form.trigger( 'yith_wccl_select_initialized', [ t, current_attr ] );
459    });
460    };
461
462    WCCL.prototype.setDefaultValue = function( event ) {
463        var obj = event.data.obj;
464
465        obj.$select.each( function () {
466            $(this).val( $(this).attr( 'data-default_value' ) );
467        });
468
469        obj.$select.first().change();
470    }
471
472    WCCL.prototype.changeLoopImage = function( obj, variation ){
473        if( ! variation ) {
474            obj.$image.attr( 'src', obj.$def_image_src );
475            if( obj.$def_image_srcset ) {
476                obj.$image.attr( 'srcset', obj.$def_image_srcset ); // restore srcset if any
477            }
478        } else {
479
480            var var_image           = ( typeof variation.image != 'undefined' && variation.image.thumb_src ) ? variation.image.thumb_src : '',
481                var_image_srcset    = ( typeof variation.image != 'undefined' && variation.image.srcset ) ? variation.image.srcset : '';
482
483            if( var_image && var_image.length ) {
484                obj.$image.attr('src', var_image );
485                obj.$image.attr('data-lazy-src', var_image );
486            }
487            if( yith_wccl_general.set_srcset_on_loop_image && var_image_srcset && var_image_srcset.length && obj.$def_image_srcset ) {
488                obj.$image.attr( 'srcset', var_image_srcset );
489                obj.$image.attr( 'data-lazy-srcset', var_image_srcset );
490            }
491        }
492    };
493
494    WCCL.prototype.changeSingleImage = function( obj, variation ) {
495        var $product_gallery  = obj.$form.closest( '.product' ).find( '.images' ),
496            $product_img_wrap = $product_gallery.find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ).eq( 0 ),
497            $product_img      = $product_img_wrap.find( '.wp-post-image' ),
498            $product_link     = $product_img_wrap.find( 'a' ).eq( 0 );
499
500        $product_img.wc_set_variation_attr( 'src', variation.image.src );
501        $product_img.wc_set_variation_attr( 'height', variation.image.src_h );
502        $product_img.wc_set_variation_attr( 'width', variation.image.src_w );
503        $product_img.wc_set_variation_attr( 'srcset', variation.image.srcset );
504        $product_img.wc_set_variation_attr( 'sizes', variation.image.sizes );
505        $product_img.wc_set_variation_attr( 'title', variation.image.title );
506        $product_img.wc_set_variation_attr( 'alt', variation.image.alt );
507        $product_img.wc_set_variation_attr( 'data-src', variation.image.full_src );
508        $product_img.wc_set_variation_attr( 'data-large_image', variation.image.full_src );
509        $product_img.wc_set_variation_attr( 'data-large_image_width', variation.image.full_src_w );
510        $product_img.wc_set_variation_attr( 'data-large_image_height', variation.image.full_src_h );
511        $product_img_wrap.wc_set_variation_attr( 'data-thumb', variation.image.src );
512        $product_link.wc_set_variation_attr( 'href', variation.image.full_src );
513    };
514
515    WCCL.prototype.changeImageOnHover = function( event ) {
516
517        var obj = event.data.obj;
518
519        if( /*obj.$select.length != 1 ||*/ ! yith_wccl_general.image_hover ) {
520            return;
521        }
522
523        obj.$form.on('mouseenter', '.select_option', function() {
524            var value       = $(this).attr("data-value"),
525                //attr_name   = //obj.$select.attr('name'),
526                attr_name   = $(this).attr('data-attr_name'),
527                variation   = variations_match( obj.$form, value, attr_name ); // find variation
528
529            if( ! yith_wccl_general.image_hover_even_selected && ( $(this).hasClass('selected') || $(this).siblings().hasClass('selected') ) ){
530                return;
531            }
532
533            if( variation && ( ( variation.image && variation.image.src ) || variation.image_src ) ) {
534                if( obj.$form.hasClass('in_loop') ) {
535                    obj.changeLoopImage( obj, variation );
536                } else {
537                    obj.changeSingleImage( obj, variation );
538                }
539            }
540        }).on('mouseleave', '.select_option', function() {
541
542            var variation   = variations_match( obj.$form, '', false ); // find variation
543
544            if( variation && ( ( variation.image && variation.image.src ) || variation.image_src ) ) {
545                if( obj.$form.hasClass('in_loop') ) {
546                    obj.changeLoopImage( obj, variation );
547                } else {
548                    obj.changeSingleImage( obj, variation );
549                }
550            } else {
551                if( obj.$form.hasClass('in_loop') ) {
552                    obj.changeLoopImage( obj, false );
553                } else {
554                    obj.$form.wc_variations_image_update( false );
555                }
556            }
557        });
558
559    };
560
561    WCCL.prototype.handleCheckVariations = function( event, data, focus ) {
562        var obj = event.data.obj;
563        if ( ! focus ) {
564            if( obj.$found ) {
565                event.data.obj.$found = false;
566                if( ! obj.$use_ajax ) return;
567            }
568            if( obj.$changed ) {
569                event.data.obj.$changed = false;
570                // reset
571                obj.resetLoopForm( obj );
572            }
573        }
574    }
575
576    WCCL.prototype.handleFoundVariation = function( event, variation ) {
577        var obj = event.data.obj;
578
579        if( obj.$use_ajax ) {
580            obj.handleSelect( event );
581        } else {
582            obj.$select.last().trigger('focusin');
583        }
584
585        if ( obj.$is_loop ) {
586
587            if( obj.$changed ) {
588                obj.resetLoopForm( obj );
589            }
590
591            // found it!
592            event.data.obj.$changed = true;
593            event.data.obj.$found = true;
594
595            // change image
596            obj.changeLoopImage( obj, variation );
597
598            let selectLength = obj.$select.length;
599
600            if( selectLength === obj.$attr_number ) { //Prevent to change if the attribute number showed are less than the registered.
601
602                if (variation.is_purchasable) {
603                    // change price
604                    if (variation.price_html) {
605                        obj.$wrapper.find(yith_wccl_general.wrapper_price_shop).replaceWith(variation.price_html);
606                    }
607
608                    // show qty input
609                    if (obj.$input_qty.length) {
610                        obj.$input_qty.show();
611                    }
612                    // change button and add event add to cart
613
614                    if (variation.is_in_stock) {
615
616                        obj.$button.html(yith_wccl_general.add_cart);
617
618                        obj.$button.off('click').on('click', {
619                            variation: variation.variation_id,
620                            select: obj.$select
621                        }, yith_wccl_add_cart);
622                    }
623                }
624
625                // add availability
626                //span.price
627                obj.$wrapper.find('.variations_form').after($(variation.availability_html).addClass('ywccl_stock'));
628
629                // set active variation
630                obj.$form.data('active_variation', variation.variation_id);
631
632                $(document).trigger('ywccl_found_variation_in_loop', [variation, obj.$button, yith_wccl_general.add_cart]);
633            } else {
634                //No variation is selected, we'll update only the button link.
635                let all_select = obj.$form.find( '.variations select' ),
636                    settings = [];
637
638                $.each( all_select, function(){
639                    var attribute_name = $( this ).data( 'attribute_name' ) || $( this ).attr( 'name' );
640                    if( $(this).val() !== '' ) {
641                        settings[attribute_name] = $(this).val();
642                    }
643                });
644                var newURL = new URL(obj.$button.attr('href'));
645
646                for (var key in settings) {
647                    var value = settings[key];
648                    if (value) {
649                        newURL.searchParams.set(key, value); //newURL.searchParams.append(key, value);
650                    }
651                }
652                obj.$button.attr('href',newURL);
653            }
654        }
655        $(document).trigger('ywccl_after_found_variation', [variation, obj.$button, yith_wccl_general.add_cart]);
656    };
657
658    WCCL.prototype.handleVariationGallery = function( event, variation ) {
659
660        var obj             = event.data.obj,
661            gallery_wrap    = $( yith_wccl_general.single_gallery_selector ),
662            id;
663
664        if( obj.$is_loop || ! gallery_wrap.length ) {
665            return;
666        }
667
668        if( obj.$xhr !== null ) {
669            obj.$xhr.abort();
670        }
671
672        id = typeof variation != 'undefined' ? variation.variation_id : obj.$form.find( '
672input[name="product_id"]' ).val();
673        if( ! id || typeof id == 'undefined' ) {
674            return;
675        }
676
677        if ( undefined !== obj.variations_gallery[ id ] ) {
678            obj.loadVariationGallery( obj.variations_gallery[ id ], gallery_wrap, variation );
679        }
680        else {
681            obj.$xhr = $.ajax({
682                url: yith_wccl_general.ajaxurl.toString().replace( '%%endpoint%%', yith_wccl_general.actionVariationGallery ),
683                data: {
684                    action: yith_wccl_general.actionVariationGallery,
685                    id : id,
686                    context: 'frontend'
687                },
688                type: 'POST',
689                dataType: 'html',
690                beforeSend: function(){
691                    gallery_wrap.addClass( 'loading-gallery' );
692                },
693                success: function( html ){
694                    gallery_wrap.removeClass( 'loading-gallery' );
695                    obj.$xhr = null;
696                    if( html ) {
697                        // store variation gallery to improve performance
698                        obj.variations_gallery[ id ] = html;
699                        obj.loadVariationGallery( html, gallery_wrap, variation );
700                    }
701
702                    // Support for Avda custom gallery
703                    if( typeof initAvadaWoocommerProductGallery === "function" ){
704                        initAvadaWoocommerProductGallery();
705                    }
706                }
707            });
708        }
709    }
710
711    WCCL.prototype.loadVariationGallery = function( html, gallery_wrap, variation ) {
712        gallery_wrap.replaceWith( html ).fadeIn();
713        if ( typeof wc_single_product_params !== 'undefined' ) {
714            // reload gallery
715            $( yith_wccl_general.single_gallery_selector ).wc_product_gallery( wc_single_product_params );
716        }
717
718        this.$form.wc_variations_image_update( variation );
719
720        $(document).trigger( 'yith_wccl_product_gallery_loaded' );
721        // uncode theme compatibility
722        $(document).trigger( 'uncode-quick-view-loaded' );
723        // woodmart theme compatibility
724        $(document).trigger('wdReplaceMainGallery');
725        $(document).trigger('wdResetVariation');
726        if( typeof woodmartThemeModule !== 'undefined' ){
727            woodmartThemeModule.productImages();
728        }
729    }
730
731    WCCL.prototype.resetLoopForm = function( obj ){
732        // reset image
733        obj.changeLoopImage( obj, false );
734        obj.$wrapper.find( yith_wccl_general.wrapper_price_shop ).replaceWith( obj.$price_html );
735        obj.$wrapper.find('.ywccl_stock').remove();
736
737        if( obj.$input_qty.length ){
738            obj.$input_qty.hide();
739        }
740
741        obj.$button.html( obj.$button_html )
742            .off( 'click', yith_wccl_add_cart )
743            .removeClass( 'added' )
744            .next('.added_to_cart').remove();
745
746        // set active variation
747        obj.$form.data('active_variation', '' );
748
749        $(document).trigger( 'yith_wccl_reset_loop_form',[obj.$button] );
750    }
751
752    WCCL.prototype.resetForm = function( obj ) {
753        obj.$form.find( 'div.select_option' ).removeClass( 'selected inactive' );
754        obj.$select.val('').change();
755        obj.$form.trigger( 'reset_data' );
756    };
757
758    WCCL.prototype.onReset = function( event ) {
759        event.data.obj.$form.find('.select_option.selected').removeClass('selected inactive');
760    };
761
762    WCCL.prototype.onAddToCart = function ( event ) {
763
764       if ( $( this ).is('.wc-variation-selection-needed') ) {
765
766           event.data.obj.$select.each(function (){
767               $(this).closest('tr').find('th').removeClass('yith-wccl-no-selected');
768               if( !$(this).val()  ) {
769                   $(this).closest('tr').find('th').addClass('yith-wccl-no-selected');
770               }
771           });
772       }
773    };
774
775    WCCL.prototype.findMatchingVariations = function( variations, attributes ) {
776        var matching = [];
777        for (var i = 0; i < variations.length; i++) {
778            var variation = variations[i];
779            if (this.isMatch(variation.attributes, attributes)) {
780                matching.push(variation);
781            }
782        }
783        return matching;
784    };
785
786    /**
787     * See if attributes match.
788     * @return {Boolean}
789     */
790    WCCL.prototype.isMatch = function( variation_attributes, attributes ) {
791        var match = true;
792        for ( var attr_name in variation_attributes ) {
793            if ( variation_attributes.hasOwnProperty( attr_name ) ) {
794                var val1 = variation_attributes[ attr_name ];
795                var val2 = attributes[ attr_name ];
796                if ( val1 !== undefined && val2 !== undefined && typeof val2 === "string" && val1.length !== 0 && val2.length !== 0 && val1 !== val2 ) {
797                    match = false;
798                }
799            }
800        }
801        return match;
802    };
803
804    WCCL.prototype.getChosenAttributes = function(form) {
805        var data   = {};
806        var count  = 0;
807        var chosen = 0;
808
809        if ( form.$use_ajax ) {
810            return;
811        }
812
813        this.$select.each( function() {
814            var attribute_name = $( this ).data( 'attribute_name' ) || $( this ).attr( 'name' );
815            var value          = $( this ).val() || '';
816
817            if ( value.length > 0 ) {
818                chosen ++;
819            }
820
821            count ++;
822            data[ attribute_name ] = value;
823        });
824
825        return {
826            'count'      : count,
827            'chosenCount': chosen,
828            'data'       : data
829        };
830    };
831
832    WCCL.prototype.onUpdateAttributes = function(event) {
833        var form              = event.data.obj;
834
835        if ( form.$use_ajax ) {
836            return;
837        }
838
839        var attributes        = form.getChosenAttributes(form),
840            currentAttributes = attributes.data;
841
842
843
844        // Loop through selects and disable/enable options based on selections.
845        form.$select.each( function( index, el ) {
846            var current_attr_select     = $( el ),
847                current_attr_name       = current_attr_select.data( 'attribute_name' ) || current_attr_select.attr( 'name' ),
848                show_option_none        = $( el ).data( 'show_option_none' ),
849                option_gt_filter        = ':gt(0)',
850                attached_options_count  = 0,
851                new_attr_select         = $( '<select/>' ),
852                selected_attr_val       = current_attr_select.val() || '',
853                selected_attr_val_valid = true;
854
855            // Reference options set at first.
856            if ( ! current_attr_select.data( 'attribute_html' ) ) {
857                var refSelect = current_attr_select.clone();
858
859                refSelect.find( 'option' ).removeAttr( 'attached' ).prop( 'disabled', false ).prop( 'selected', false );
860
861                // Legacy data attribute.
862                current_attr_select.data(
863                    'attribute_options',
864                    refSelect.find( 'option' + option_gt_filter ).get()
865                );
866                current_attr_select.data( 'attribute_html', refSelect.html() );
867            }
868
869            new_attr_select.html( current_attr_select.data( 'attribute_html' ) );
870
871            // The attribute of this select field should not be taken into account when calculating its matching variations:
872            // The constraints of this attribute are shaped by the values of the other attributes.
873            var checkAttributes = $.extend( true, {}, currentAttributes );
874
875            checkAttributes[ current_attr_name ] = '';
876            var variations = form.findMatchingVariations( event.data.obj.$form.data('product_variations'), checkAttributes );
877
878            // Loop through variations.
879            for ( var num in variations ) {
880                if ( typeof( variations[ num ] ) !== 'undefined' ) {
881                    var variationAttributes = variations[ num ].attributes;
882
883                    for ( var attr_name in variationAttributes ) {
884                        if ( variationAttributes.hasOwnProperty( attr_name ) ) {
885                            var attr_val         = variationAttributes[ attr_name ],
886                                variation_active = '';
887
888                            if ( attr_name === current_attr_name ) {
889                                if ( variations[ num ].variation_is_active ) {
890                                    variation_active = 'enabled';
891                                }
892
893                                if ( attr_val ) {
894                                    // Decode entities.
895                                    attr_val = $( '<div/>' ).html( attr_val ).text();
896
897                                    // Attach to matching options by value. This is done to compare
898                                    // TEXT values rather than any HTML entities.
899                                    var $option_elements = new_attr_select.find( 'option' );
900                                    if ( $option_elements.length ) {
901                                        for (var i = 0, len = $option_elements.length; i < len; i++) {
902                                            var $option_element = $( $option_elements[i] ),
903                                                option_value = $option_element.val();
904
905                                            if ( attr_val === option_value ) {
906                                                $option_element.addClass( 'attached ' + variation_active );
907                                                break;
908                                            }
909                                        }
910                                    }
911                                } else {
912                                    // Attach all apart from placeholder.
913                                    new_attr_select.find( 'option:gt(0)' ).addClass( 'attached ' + variation_active );
914                                }
915                            }
916                        }
917                    }
918                }
919            }
920
921            // Count available options.
922            attached_options_count = new_attr_select.find( 'option.attached' ).length;
923
924            // Check if current selection is in attached options.
925            if ( selected_attr_val ) {
926                selected_attr_val_valid = false;
927
928                if ( 0 !== attached_options_count ) {
929                    new_attr_select.find( 'option.attached.enabled' ).each( function() {
930                        var option_value = $( this ).val();
931
932                        if ( selected_attr_val === option_value ) {
933                            selected_attr_val_valid = true;
934                            return false; // break.
935                        }
936                    });
937                }
938            }
939
940            // Detach the placeholder if:
941            // - Valid options exist.
942            // - The current selection is non-empty.
943            // - The current selection is valid.
944            // - Placeholders are not set to be permanently visible.
945            if ( attached_options_count > 0 && selected_attr_val && selected_attr_val_valid && ( 'no' === show_option_none ) ) {
946                new_attr_select.find( 'option:first' ).remove();
947                option_gt_filter = '';
948            }
949
950            // Detach unattached.
951            new_attr_select.find( 'option' + option_gt_filter + ':not(.attached)' ).remove();
952
953            // Finally, copy to DOM and set value.
954            current_attr_select.html( new_attr_select.html() );
955            current_attr_select.find( 'option' + option_gt_filter + ':not(.enabled)' ).prop( 'disabled', true );
956
957            // Choose selected value.
958            if ( selected_attr_val ) {
959                // If the previously selected value is no longer available, fall back to the placeholder (it's going to be there).
960                if ( selected_attr_val_valid ) {
961                    current_attr_select.val( selected_attr_val );
962                } else {
963                    current_attr_select.val( '' ).trigger( 'change' );
964                }
965            } else {
966                current_attr_select.val( '' ); // No change event to prevent infinite loop.
967            }
968        });
969
970        // Custom event for when variations have been updated.
971        form.$form.trigger( 'woocommerce_update_variation_values' );
972    };
973
974    WCCL.prototype.init = function( event ) {
975
976        var obj = event.data.obj;
977
978        obj.$form.on( 'click.wc-variation-form', '.reset_variations', { obj: obj }, obj.onReset );
979        obj.$form.on( 'woocommerce_update_variation_values', { obj: obj }, obj.handleSelect );
980        obj.$form.one( 'yith_wccl_select_initialized', { obj: obj }, obj.changeImageOnHover );
981        obj.$form.on( 'check_variations', { obj: obj }, obj.handleCheckVariations );
982        obj.$form.on( 'found_variation', { obj: obj }, obj.handleFoundVariation );
983        if( yith_wccl_general.enable_handle_variation_gallery ){
984            obj.$form.on( 'found_variation', {obj: obj}, obj.handleVariationGallery );
985            obj.$form.on( 'reset_image', {obj: obj}, obj.handleVariationGallery );
986        }
987        obj.$form.on( 'click', '.single_add_to_cart_button', { obj: obj }, obj.onAddToCart );
988
989        obj.$select.each( function(){
990
991            // Fix compatibility to avoid conflict with Product Bundles - Variation Bundles
992            if( $(this).parents( '.bundled_product' ).length ){
993                return;
994            }
995
996            var val = $(this).attr( 'data-default_value' );
997            $(this).removeAttr( 'data-default_value' );
998            $(this).val( val );
999
1000            //set label.
1001            $(this).closest('tr').find('th label').attr('data-default-label', $(this).closest('tr').find('th label').text() );
1002
1003        });
1004        obj.$form.on( 'update_variation_values.wc-variation-form', { obj: obj }, obj.onUpdateAttributes );
1005
1006        // force start select
1007        obj.handleSelect( event );
1008
1009    }
1010
1011    // retrocompatibility
1012    $.yith_wccl = function( attr ) {
1013        forms = $( '.variations_form.cart:not(.initialized), .owl-item.cloned .variations_form, form.cart.ywcp_form_loaded' );
1014        // prevent undefined attr error
1015        if( typeof attr == 'undefined' ) {
1016            attr = [];
1017        }
1018
1019        forms.each(function (){
1020            new WCCL( $(this), attr );
1021        });
1022    };
1023
1024    // plugin compatibility
1025    $(document).on( yith_wccl_general.plugin_compatibility_selectors, function() {
1026
1027        if( typeof $.yith_wccl != 'undefined' && typeof $.fn.wc_variation_form != 'undefined' ) {
1028            // not initialized
1029            $(document).find( '.variations_form:not(.initialized), .owl-item.cloned .variations_form' ).each( function() {
1030                $(this).wc_variation_form();
1031            });
1032
1033            // prevent undefined attr error
1034            if( typeof attr == 'undefined' ) {
1035                attr = [];
1036            }
1037
1038            $.yith_wccl(attr);
1039        }
1040    });
1041
1042    // Astra infinite scrolling. Facetwp load more
1043    $(window).on('astWooCommerceAjaxPostsAdded facetwp-loaded', function() {
1044        if( typeof $.yith_wccl != 'undefined' && typeof $.fn.wc_variation_form != 'undefined' ) {
1045            // not initialized
1046            $(document).find( '.variations_form:not(.initialized)' ).each( function() {
1047                $(this).wc_variation_form();
1048            });
1049
1050            $.yith_wccl([]);
1051        }
1052    })
1053
1054    // reinit for woocommerce quick view
1055    $( 'body' ).on( 'quick-view-displayed', function() {
1056        var attr_qv = $('.pp_woocommerce_quick_view').find('.yith-wccl-data').data('attr');
1057        if( attr_qv ) {
1058            $.yith_wccl(attr_qv);
1059        }
1060    });
1061
1062    // Fix for Flatsome Infinite Scrolling
1063    $('.shop-container > .products').on('append.infiniteScroll',function(){
1064        $(document).find( '.variations_form:not(.initialized), .owl-item.cloned .variations_form' ).each( function() {
1065            $(this).wc_variation_form();
1066        });
1067
1068        // prevent undefined attr error
1069        if( typeof attr == 'undefined' ) {
1070            attr = [];
1071        }
1072
1073        $.yith_wccl(attr);
1074
1075    });
1076
1077    // Re-init scripts on gallery loaded
1078    $(document).on( 'yith_wccl_product_gallery_loaded', function(){
1079        if( typeof mkdf != 'undefined' && typeof mkdf.modules.common.mkdfPrettyPhoto === "function" ) {
1080            var item = $('.mkdf-woo-single-page.mkdf-woo-single-has-pretty-photo .images .woocommerce-product-gallery__image');
1081            if( item.length ) {
1082                item.children('a').attr('data-rel', 'prettyPhoto[woo_single_pretty_photo]');
1083                mkdf.modules.common.mkdfPrettyPhoto();
1084            }
1085        }
1086
1087        if( typeof Flatsome != 'undefined' ){
1088            Flatsome.attach( $( '.product-gallery' ) );
1089            // foce zoom button to work
1090            $( '.zoom-button' ).click( function ( ev ) {
1091                ev.preventDefault();
1092                $( '.product-gallery-slider' ) .find( '.is-selected a' ).click();
1093            });
1094        }
1095    });
1096
1097    //Prevent windows.
1098    $('.single_add_to_cart_button').on('click',function(e){
1099        if ( $( this ).is('.disabled') ) {
1100            e.preventDefault();
1101            if ( $( this ).is('.wc-variation-selection-needed') ) {
1102                let form = $('.variations_form.cart');
1103                let selects = form.find( '.variations select' );
1104
1105                selects.each(function (){
1106                    $(this).closest('tr').find('th').removeClass('yith-wccl-no-selected');
1107                    $(this).closest('tr').find('.yith-wccl-no-selected-msg').remove();
1108                    if( !$(this).val()  ) {
1109                        $(this).closest('tr').find('th').addClass('yith-wccl-no-selected');
1110                        $(this).closest('td').append('<div class="yith-wccl-no-selected-msg"><small>'+yith_wccl_general.error_no_selected+'</small></div>');
1111
1112                    }
1113                });
1114
1115                return false;
1116            }
1117        }
1118    });
1119
1120    // START
1121    $(document).ready( function(){
1122        $.yith_wccl();
1123    });
1124
1125
1126})( jQuery, window, document );

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.