PageSourceSearch

https://bagebixen.dk/wp-content/themes/bagebixen/woocommerce/asset…/frontend/add-to-cart-variation.js?ver=1.0

js bagebixen.dk collected 2026-09-26 13:27:36 UTC 28,364 bytes, 781 lines download raw bytes

1/*global wc_add_to_cart_variation_params */
2;(function ( $, window, document, undefined ) {
3	/**
4	 * VariationForm class which handles variation forms and attributes.
5	 */
6	var VariationForm = function( $form ) {
7		var self = this;
8
9		self.$form                = $form;
10		self.$attributeFields     = $form.find( '.variations select' );
11		self.$singleVariation     = $form.find( '.single_variation' );
12		self.$singleVariationWrap = $form.find( '.single_variation_wrap' );
13		self.$resetVariations     = $form.find( '.reset_variations' );
14		self.$product             = $form.closest( '.product' );
15		self.variationData        = $form.data( 'product_variations' );
16		self.useAjax              = false === self.variationData;
17		self.xhr                  = false;
18		self.loading              = true;
19
20		// Initial state.
21		self.$singleVariationWrap.show();
22		self.$form.off( '.wc-variation-form' );
23
24		// Methods.
25		self.getChosenAttributes    = self.getChosenAttributes.bind( self );
26		self.findMatchingVariations = self.findMatchingVariations.bind( self );
27		self.isMatch                = self.isMatch.bind( self );
28		self.toggleResetLink        = self.toggleResetLink.bind( self );
29
30		// Events.
31		$form.on( 'click.wc-variation-form', '.reset_variations', { variationForm: self }, self.onReset );
32		$form.on( 'reload_product_variations', { variationForm: self }, self.onReload );
33		$form.on( 'hide_variation', { variationForm: self }, self.onHide );
34		$form.on( 'show_variation', { variationForm: self }, self.onShow );
35		$form.on( 'click', '.single_add_to_cart_button', { variationForm: self }, self.onAddToCart );
36		$form.on( 'reset_data', { variationForm: self }, self.onResetDisplayedVariation );
37		$form.on( 'reset_image', { variationForm: self }, self.onResetImage );
38		$form.on( 'change.wc-variation-form', '.variations select', { variationForm: self }, self.onChange );
39		$form.on( 'found_variation.wc-variation-form', { variationForm: self }, self.onFoundVariation );
40		$form.on( 'check_variations.wc-variation-form', { variationForm: self }, self.onFindVariation );
41		$form.on( 'update_variation_values.wc-variation-form', { variationForm: self }, self.onUpdateAttributes );
42
43		// Init after gallery.
44		setTimeout( function() {
45			$form.trigger( 'check_variations' );
46			$form.trigger( 'wc_variation_form' );
47			self.loading = false;
48		}, 100 );
49	};
50
51	/**
52	 * Reset all fields.
53	 */
54	VariationForm.prototype.onReset = function( event ) {
55		event.preventDefault();
56		event.data.variationForm.$attributeFields.val( '' ).change();
57		event.data.variationForm.$form.trigger( 'reset_data' );
58	};
59
60	/**
61	 * Reload variation data from the DOM.
62	 */
63	VariationForm.prototype.onReload = function( event ) {
64		var form           = event.data.variationForm;
65		form.variationData = form.$form.data( 'product_variations' );
66		form.useAjax       = false === form.variationData;
67		form.$form.trigger( 'check_variations' );
68	};
69
70	/**
71	 * When a variation is hidden.
72	 */
73	VariationForm.prototype.onHide = function( event ) {
74		event.preventDefault();
75		event.data.variationForm.$form.find( '.single_add_to_cart_button' ).removeClass( 'wc-variation-is-unavailable' ).addClass( 'disabled-variation-needed wc-variation-selection-needed' );
76		event.data.variationForm.$form.find( '.woocommerce-variation-add-to-cart' ).removeClass( 'woocommerce-variation-add-to-cart-enabled' ).addClass( 'woocommerce-variation-add-to-cart-disabled' );
77	};
78
79	/**
80	 * When a variation is shown.
81	 */
82	VariationForm.prototype.onShow = function( event, variation, purchasable ) {
83		event.preventDefault();
84		if ( purchasable ) {
85			event.data.variationForm.$form.find( '.single_add_to_cart_button' ).removeClass( 'disabled-variation-needed wc-variation-selection-needed wc-variation-is-unavailable' );
86			event.data.variationForm.$form.find( '.woocommerce-variation-add-to-cart' ).removeClass( 'woocommerce-variation-add-to-cart-disabled' ).addClass( 'woocommerce-variation-add-to-cart-enabled' );
87		} else {
88			event.data.variationForm.$form.find( '.single_add_to_cart_button' ).removeClass( 'wc-variation-selection-needed' ).addClass( 'disabled wc-variation-is-unavailable' );
89			event.data.variationForm.$form.find( '.woocommerce-variation-add-to-cart' ).removeClass( 'woocommerce-variation-add-to-cart-enabled' ).addClass( 'woocommerce-variation-add-to-cart-disabled' );
90		}
91
92		// If present, the media element library needs initialized on the variation description.
93		if ( wp.mediaelement ) {
94			event.data.variationForm.$form.find( '.wp-audio-shortcode, .wp-video-shortcode' )
95				.not( '.mejs-container' )
96				.filter(
97					function () {
98						return ! $( this ).parent().hasClass( 'mejs-mediaelement' );
99					}
100				)
101				.mediaelementplayer( wp.mediaelement.settings );
102		}
103	};
104
105	/**
106	 * When the cart button is pressed.
107	 */
108	VariationForm.prototype.onAddToCart = function( event ) {
109		if ( $( this ).is('.disabled') ) {
110			event.preventDefault();
111
112			if ( $( this ).is('.wc-variation-is-unavailable') ) {
113				window.alert( wc_add_to_cart_variation_params.i18n_unavailable_text );
114			} else if ( $( this ).is('.wc-variation-selection-needed') ) {
115				window.alert( wc_add_to_cart_variation_params.i18n_make_a_selection_text );
116			}
117		}
118
119		if ( $( this ).is('.disabled-variation-needed') ) {
120			event.preventDefault();
121			var variation = $( 'table.variations select' ); 
122
123			if ( $( this ).is('.wc-variation-selection-needed') ) {
124				if ( variation.val() == '' ) {
125					$( '.variations select' ).addClass( 'empty-variation-field' )
126					$(".empty-variation-wrap").css('display', 'block')
127				} else {
128					$(".empty-variation-wrap").css('display', 'none')
129					$( '.variations select' ).removeClass( 'empty-variation-field' )
130				}
131
132				variation.prop('required',true);
133			} else {
134				variation.prop('required',false);
135			}
136		}
137	};
138
139	/**
140	 * When displayed variation data is reset.
141	 */
142	VariationForm.prototype.onResetDisplayedVariation = function( event ) {
143		var form = event.data.variationForm;
144		form.$product.find( '.product_meta' ).find( '.sku' ).wc_reset_content();
145		form.$product.find( '.product_weight, .woocommerce-product-attributes-item--weight .woocommerce-product-attributes-item__value' ).wc_reset_content();
146		form.$product.find( '.product_dimensions, .woocommerce-product-attributes-item--dimensions .woocommerce-product-attributes-item__value' ).wc_reset_content();
147		form.$form.trigger( 'reset_image' );
148		form.$singleVariation.slideUp( 200 ).trigger( 'hide_variation' );
149	};
150
151	/**
152	 * When the product image is reset.
153	 */
154	VariationForm.prototype.onResetImage = function( event ) {
155		event.data.variationForm.$form.wc_variations_image_update( false );
156	};
157
158	/**
159	 * Looks for matching variations for current selected attributes.
160	 */
161	VariationForm.prototype.onFindVariation = function( event ) {
162		var form              = event.data.variationForm,
163			attributes        = form.getChosenAttributes(),
164			currentAttributes = attributes.data;
165
166		if ( attributes.count === attributes.chosenCount ) {
167			if ( form.useAjax ) {
168				if ( form.xhr ) {
169					form.xhr.abort();
170				}
171				form.$form.block( { message: null, overlayCSS: { background: '#fff', opacity: 0.6 } } );
172				currentAttributes.product_id  = parseInt( form.$form.data( 'product_id' ), 10 );
173				currentAttributes.custom_data = form.$form.data( 'custom_data' );
174				form.xhr                      = $.ajax( {
175					url: wc_add_to_cart_variation_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'get_variation' ),
176					type: 'POST',
177					data: currentAttributes,
178					success: function( variation ) {
179						if ( variation ) {
180							form.$form.trigger( 'found_variation', [ variation ] );
181						} else {
182							form.$form.trigger( 'reset_data' );
183							attributes.chosenCount = 0;
184
185							if ( ! form.loading ) {
186								form.$form.find( '.single_variation' ).after( '<p class="wc-no-matching-variations woocommerce-info">' + wc_add_to_cart_variation_params.i18n_no_matching_variations_text + '</p>' );
187								form.$form.find( '.wc-no-matching-variations' ).slideDown( 200 );
188							}
189						}
190					},
191					complete: function() {
192						form.$form.unblock();
193					}
194				} );
195			} else {
196				form.$form.trigger( 'update_variation_values' );
197
198				var matching_variations = form.findMatchingVariations( form.variationData, currentAttributes ),
199					variation           = matching_variations.shift();
200
201				if ( variation ) {
202					form.$form.trigger( 'found_variation', [ variation ] );
203				} else {
204					form.$form.trigger( 'reset_data' );
205					attributes.chosenCount = 0;
206
207					if ( ! form.loading ) {
208						form.$form.find( '.single_variation' ).after( '<p class="wc-no-matching-variations woocommerce-info">' + wc_add_to_cart_variation_params.i18n_no_matching_variations_text + '</p>' );
209						form.$form.find( '.wc-no-matching-variations' ).slideDown( 200 );
210					}
211				}
212			}
213		} else {
214			form.$form.trigger( 'update_variation_values' );
215			form.$form.trigger( 'reset_data' );
216		}
217
218		// Show reset link.
219		form.toggleResetLink( attributes.chosenCount > 0 );
220	};
221
222	/**
223	 * Triggered when a variation has been found which matches all attributes.
224	 */
225	VariationForm.prototype.onFoundVariation = function( event, variation ) {
226		var form           = event.data.variationForm,
227			$sku           = form.$product.find( '.product_meta' ).find( '.sku' ),
228			$weight        = form.$product.find( '.product_weight, .woocommerce-product-attributes-item--weight .woocommerce-product-attributes-item__value' ),
229			$dimensions    = form.$product.find( '.product_dimensions, .woocommerce-product-attributes-item--dimensions .woocommerce-product-attributes-item__value' ),
230			$qty           = form.$singleVariationWrap.find( '.quantity' ),
231			purchasable    = true,
232			variation_id   = '',
233			template       = false,
234			$template_html = '';
235
236		if ( variation.sku ) {
237			$sku.wc_set_content( variation.sku );
238		} else {
239			$sku.wc_reset_content();
240		}
241
242		if ( variation.weight ) {
243			$weight.wc_set_content( variation.weight_html );
244		} else {
245			$weight.wc_reset_content();
246		}
247
248		if ( variation.dimensions ) {
249			// Decode HTML entities.
250			$dimensions.wc_set_content( $.parseHTML( variation.dimensions_html )[0].data );
251		} else {
252			$dimensions.wc_reset_content();
253		}
254
255		form.$form.wc_variations_image_update( variation );
256
257		if ( ! variation.variation_is_visible ) {
258			template = wp_template( 'unavailable-variation-template' );
259		} else {
260			template     = wp_template( 'variation-template' );
261			variation_id = variation.variation_id;
262		}
263
264		$template_html = template( {
265			variation: variation
266		} );
267		$template_html = $template_html.replace( '/*<![CDATA[*/', '' );
268		$template_html = $template_html.replace( '/*]]>*/', '' );
269
270		form.$singleVariation.html( $template_html );
271		form.$form.find( 'input[name="variation_id"], input.variation_id' ).val( variation.variation_id ).change();
272
273		// Hide or show qty input
274		if ( variation.is_sold_individually === 'yes' ) {
275			$qty.find( 'input.qty' ).val( '1' ).attr( 'min', '1' ).attr( 'max', '' );
276			$qty.hide();
277		} else {
278			$qty.find( 'input.qty' ).attr( 'min', variation.min_qty ).attr( 'max', variation.max_qty );
279			$qty.show();
280		}
281
282		// Enable or disable the add to cart button
283		if ( ! variation.is_purchasable || ! variation.is_in_stock || ! variation.variation_is_visible ) {
284			purchasable = false;
285		}
286
287		// Reveal
288		if ( $.trim( form.$singleVariation.text() ) ) {
289			form.$singleVariation.slideDown( 200 ).trigger( 'show_variation', [ variation, purchasable ] );
290		} else {
291			form.$singleVariation.show().trigger( 'show_variation', [ variation, purchasable ] );
292		}
293	};
294
295	/**
296	 * Triggered when an attribute field changes.
297	 */
298	VariationForm.prototype.onChange = function( event ) {
299		var form = event.data.variationForm;
300
301		form.$form.find( 'input[name="variation_id"], input.variation_id' ).val( '' ).change();
302		form.$form.find( '.wc-no-matching-variations' ).remove();
303
304		if ( form.useAjax ) {
305			form.$form.trigger( 'check_variations' );
306		} else {
307			form.$form.trigger( 'woocommerce_variation_select_change' );
308			form.$form.trigger( 'check_variations' );
309		}
310
311		// Custom event for when variation selection has been changed
312		form.$form.trigger( 'woocommerce_variation_has_changed' );
313	};
314
315	/**
316	 * Escape quotes in a string.
317	 * @param {string} string
318	 * @return {string}
319	 */
320	VariationForm.prototype.addSlashes = function( string ) {
321		string = string.replace( /'/g, '\\\'' );
322		string = string.replace( /"/g, '\\\"' );
323		return string;
324	};
325
326	/**
327	 * Updates attributes in the DOM to show valid values.
328	 */
329	VariationForm.prototype.onUpdateAttributes = function( event ) {
330		var form              = event.data.variationForm,
331			attributes        = form.getChosenAttributes(),
332			currentAttributes = attributes.data;
333
334		if ( form.useAjax ) {
335			return;
336		}
337
338		// Loop through selects and disable/enable options based on selections.
339		form.$attributeFields.each( function( index, el ) {
340			var current_attr_select     = $( el ),
341				current_attr_name       = current_attr_select.data( 'attribute_name' ) || current_attr_select.attr( 'name' ),
342				show_option_none        = $( el ).data( 'show_option_none' ),
343				option_gt_filter        = ':gt(0)',
344				attached_options_count  = 0,
345				new_attr_select         = $( '<select/>' ),
346				selected_attr_val       = current_attr_select.val() || '',
347				selected_attr_val_valid = true;
348
349			// Reference options set at first.
350			if ( ! current_attr_select.data( 'attribute_html' ) ) {
351				var refSelect = current_attr_select.clone();
352
353				refSelect.find( 'option' ).removeAttr( 'disabled attached' ).removeAttr( 'selected' );
354
355				current_attr_select.data( 'attribute_options', refSelect.find( 'option' + option_gt_filter ).get() ); // Legacy data attribute.
356				current_attr_select.data( 'attribute_html', refSelect.html() );
357			}
358
359			new_attr_select.html( current_attr_select.data( 'attribute_html' ) );
360
361			// The attribute of this select field should not be taken into account when calculating its matching variations:
362			// The constraints of this attribute are shaped by the values of the other attributes.
363			var checkAttributes = $.extend( true, {}, currentAttributes );
364
365			checkAttributes[ current_attr_name ] = '';
366
367			var variations = form.findMatchingVariations( form.variationData, checkAttributes );
368
369			// Loop through variations.
370			for ( var num in variations ) {
371				if ( typeof( variations[ num ] ) !== 'undefined' ) {
372					var variationAttributes = variations[ num ].attributes;
373
374					for ( var attr_name in variationAttributes ) {
375						if ( variationAttributes.hasOwnProperty( attr_name ) ) {
376							var attr_val         = variationAttributes[ attr_name ],
377								variation_active = '';
378
379							if ( attr_name === current_attr_name ) {
380								if ( variations[ num ].variation_is_active ) {
381									variation_active = 'enabled';
382								}
383
384								if ( attr_val ) {
385									// Decode entities.
386									attr_val = $( '<div/>' ).html( attr_val ).text();
387
388									// Attach to matching options by value. This is done to compare
389									// TEXT values rather than any HTML entities.
390									var $option_elements = new_attr_select.find( 'option' );
391									if ( $option_elements.length ) {
392										for (var i = 0, len = $option_elements.length; i < len; i++) {
393											var $option_element = $( $option_elements[i] ),
394												option_value = $option_element.val();
395
396											if ( attr_val === option_value ) {
397												$option_element.addClass( 'attached ' + variation_active );
398												break;
399											}
400										}
401									}
402								} else {
403									// Attach all apart from placeholder.
404									new_attr_select.find( 'option:gt(0)' ).addClass( 'attached ' + variation_active );
405								}
406							}
407						}
408					}
409				}
410			}
411
412			// Count available options.
413			attached_options_count = new_attr_select.find( 'option.attached' ).length;
414
415			// Check if current selection is in attached options.
416			if ( selected_attr_val ) {
417				selected_attr_val_valid = false;
418
419				if ( 0 !== attached_options_count ) {
420					new_attr_select.find( 'option.attached.enabled' ).each( function() {
421						var option_value = $( this ).val();
422
423						if ( selected_attr_val === option_value ) {
424							selected_attr_val_valid = true;
425							return false; // break.
426						}
427					});
428				}
429			}
430
431			// Detach the placeholder if:
432			// - Valid options exist.
433			// - The current selection is non-empty.
434			// - The current selection is valid.
435			// - Placeholders are not set to be permanently visible.
436			if ( attached_options_count > 0 && selected_attr_val && selected_attr_val_valid && ( 'no' === show_option_none ) ) {
437				new_attr_select.find( 'option:first' ).remove();
438				option_gt_filter = '';
439			}
440
441			// Detach unattached.
442			new_attr_select.find( 'option' + option_gt_filter + ':not(.attached)' ).remove();
443
444			// Finally, copy to DOM and set value.
445			current_attr_select.html( new_attr_select.html() );
446			current_attr_select.find( 'option' + option_gt_filter + ':not(.enabled)' ).prop( 'disabled', true );
447
448			// Choose selected value.
449			if ( selected_attr_val ) {
450				// If the previously selected value is no longer available, fall back to the placeholder (it's going to be there).
451				if ( selected_attr_val_valid ) {
452					current_attr_select.val( selected_attr_val );
453				} else {
454					current_attr_select.val( '' ).change();
455				}
456			} else {
457				current_attr_select.val( '' ); // No change event to prevent infinite loop.
458			}
459		});
460
461		// Custom event for when variations have been updated.
462		form.$form.trigger( 'woocommerce_update_variation_values' );
463	};
464
465	/**
466	 * Get chosen attributes from form.
467	 * @return array
468	 */
469	VariationForm.prototype.getChosenAttributes = function() {
470		var data   = {};
471		var count  = 0;
472		var chosen = 0;
473
474		this.$attributeFields.each( function() {
475			var attribute_name = $( this ).data( 'attribute_name' ) || $( this ).attr( 'name' );
476			var value          = $( this ).val() || '';
477
478			if ( value.length > 0 ) {
479				chosen ++;
480			}
481
482			count ++;
483			data[ attribute_name ] = value;
484		});
485
486		return {
487			'count'      : count,
488			'chosenCount': chosen,
489			'data'       : data
490		};
491	};
492
493	/**
494	 * Find matching variations for attributes.
495	 */
496	VariationForm.prototype.findMatchingVariations = function( variations, attributes ) {
497		var matching = [];
498		for ( var i = 0; i < variations.length; i++ ) {
499			var variation = variations[i];
500
501			if ( this.isMatch( variation.attributes, attributes ) ) {
502				matching.push( variation );
503			}
504		}
505		return matching;
506	};
507
508	/**
509	 * See if attributes match.
510	 * @return {Boolean}
511	 */
512	VariationForm.prototype.isMatch = function( variation_attributes, attributes ) {
513		var match = true;
514		for ( var attr_name in variation_attributes ) {
515			if ( variation_attributes.hasOwnProperty( attr_name ) ) {
516				var val1 = variation_attributes[ attr_name ];
517				var val2 = attributes[ attr_name ];
518				if ( val1 !== undefined && val2 !== undefined && val1.length !== 0 && val2.length !== 0 && val1 !== val2 ) {
519					match = false;
520				}
521			}
522		}
523		return match;
524	};
525
526	/**
527	 * Show or hide the reset link.
528	 */
529	VariationForm.prototype.toggleResetLink = function( on ) {
530		if ( on ) {
531			if ( this.$resetVariations.css( 'visibility' ) === 'hidden' ) {
532				this.$resetVariations.css( 'visibility', 'visible' ).hide().fadeIn();
533			}
534		} else {
535			this.$resetVariations.css( 'visibility', 'hidden' );
536		}
537	};
538
539	/**
540	 * Function to call wc_variation_form on jquery selector.
541	 */
542	$.fn.wc_variation_form = function() {
543		new VariationForm( this );
544		return this;
545	};
546
547	/**
548	 * Stores the default text for an element so it can be reset later
549	 */
550	$.fn.wc_set_content = function( content ) {
551		if ( undefined === this.attr( 'data-o_content' ) ) {
552			this.attr( 'data-o_content', this.text() );
553		}
554		this.text( content );
555	};
556
557	/**
558	 * Stores the default text for an element so it can be reset later
559	 */
560	$.fn.wc_reset_content = function() {
561		if ( undefined !== this.attr( 'data-o_content' ) ) {
562			this.text( this.attr( 'data-o_content' ) );
563		}
564	};
565
566	/**
567	 * Stores a default attribute for an element so it can be reset later
568	 */
569	$.fn.wc_set_variation_attr = function( attr, value ) {
570		if ( undefined === this.attr( 'data-o_' + attr ) ) {
571			this.attr( 'data-o_' + attr, ( ! this.attr( attr ) ) ? '' : this.attr( attr ) );
572		}
573		if ( false === value ) {
574			this.removeAttr( attr );
575		} else {
576			this.attr( attr, value );
577		}
578	};
579
580	/**
581	 * Reset a default attribute for an element so it can be reset later
582	 */
583	$.fn.wc_reset_variation_attr = function( attr ) {
584		if ( undefined !== this.attr( 'data-o_' + attr ) ) {
585			this.attr( attr, this.attr( 'data-o_' + attr ) );
586		}
587	};
588
589	/**
590	 * Reset the slide position if the variation has a different image than the current one
591	 */
592	$.fn.wc_maybe_trigger_slide_position_reset = function( variation ) {
593		var $form                = $( this ),
594			$product             = $form.closest( '.product' ),
595			$product_gallery     = $product.find( '.images' ),
596			reset_slide_position = false,
597			new_image_id         = ( variation && variation.image_id ) ? variation.image_id : '';
598
599		if ( $form.attr( 'current-image' ) !== new_image_id ) {
600			reset_slide_position = true;
601		}
602
603		$form.attr( 'current-image', new_image_id );
604
605		if ( reset_slide_position ) {
606			$product_gallery.trigger( 'woocommerce_gallery_reset_slide_position' );
607		}
608	};
609
610	/**
611	 * Sets product images for the chosen variation
612	 */
613	$.fn.wc_variations_image_update = function( variation ) {
614		var $form             = this,
615			$product          = $form.closest( '.product' ),
616			$product_gallery  = $product.find( '.images' ),
617			$gallery_nav      = $product.find( '.flex-control-nav' ),
618			$gallery_img      = $gallery_nav.find( 'li:eq(0) img' ),
619			$product_img_wrap = $product_gallery.find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ).eq( 0 ),
620			$product_img      = $product_img_wrap.find( '.wp-post-image' ),
621			$product_link     = $product_img_wrap.find( 'a' ).eq( 0 );
622
623		if ( variation && variation.image && variation.image.src && variation.image.src.length > 1 ) {
624			// See if the gallery has an image with the same original src as the image we want to switch to.
625			var galleryHasImage = $gallery_nav.find( 'li img[data-o_src="' + variation.image.gallery_thumbnail_src + '"]' ).length > 0;
626
627			// If the gallery has the image, reset the images. We'll scroll to the correct one.
628			if ( galleryHasImage ) {
629				$form.wc_variations_image_reset();
630			}
631
632			// See if gallery has a matching image we can slide to.
633			var slideToImage = $gallery_nav.find( 'li img[src="' + variation.image.gallery_thumbnail_src + '"]' );
634
635			if ( slideToImage.length > 0 ) {
636				slideToImage.trigger( 'click' );
637				$form.attr( 'current-image', variation.image_id );
638				window.setTimeout( function() {
639					$( window ).trigger( 'resize' );
640					$product_gallery.trigger( 'woocommerce_gallery_init_zoom' );
641				}, 20 );
642				return;
643			}
644
645			$product_img.wc_set_variation_attr( 'src', variation.image.src );
646			$product_img.wc_set_variation_attr( 'height', variation.image.src_h );
647			$product_img.wc_set_variation_attr( 'width', variation.image.src_w );
648			$product_img.wc_set_variation_attr( 'srcset', variation.image.srcset );
649			$product_img.wc_set_variation_attr( 'sizes', variation.image.sizes );
650			$product_img.wc_set_variation_attr( 'title', variation.image.title );
651			$product_img.wc_set_variation_attr( 'data-caption', variation.image.caption );
652			$product_img.wc_set_variation_attr( 'alt', variation.image.alt );
653			$product_img.wc_set_variation_attr( 'data-src', variation.image.full_src );
654			$product_img.wc_set_variation_attr( 'data-large_image', variation.image.full_src );
655			$product_img.wc_set_variation_attr( 'data-large_image_width', variation.image.full_src_w );
656			$product_img.wc_set_variation_attr( 'data-large_image_height', variation.image.full_src_h );
657			$product_img_wrap.wc_set_variation_attr( 'data-thumb', variation.image.src );
658			$gallery_img.wc_set_variation_attr( 'src', variation.image.gallery_thumbnail_src );
659			$product_link.wc_set_variation_attr( 'href', variation.image.full_src );
660		} else {
661			$form.wc_variations_image_reset();
662		}
663
664		window.setTimeout( function() {
665			$( window ).trigger( 'resize' );
666			$form.wc_maybe_trigger_slide_position_reset( variation );
667			$product_gallery.trigger( 'woocommerce_gallery_init_zoom' );
668		}, 20 );
669	};
670
671	/**
672	 * Reset main image to defaults.
673	 */
674	$.fn.wc_variations_image_reset = function() {
675		var $form             = this,
676			$product          = $form.closest( '.product' ),
677			$product_gallery  = $product.find( '.images' ),
678			$gallery_nav      = $product.find( '.flex-control-nav' ),
679			$gallery_img      = $gallery_nav.find( 'li:eq(0) img' ),
680			$product_img_wrap = $product_gallery.find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ).eq( 0 ),
681			$product_img      = $product_img_wrap.find( '.wp-post-image' ),
682			$product_link     = $product_img_wrap.find( 'a' ).eq( 0 );
683
684		$product_img.wc_reset_variation_attr( 'src' );
685		$product_img.wc_reset_variation_attr( 'width' );
686		$product_img.wc_reset_variation_attr( 'height' );
687		$product_img.wc_reset_variation_attr( 'srcset' );
688		$product_img.wc_reset_variation_attr( 'sizes' );
689		$product_img.wc_reset_variation_attr( 'title' );
690		$product_img.wc_reset_variation_attr( 'data-caption' );
691		$product_img.wc_reset_variation_attr( 'alt' );
692		$product_img.wc_reset_variation_attr( 'data-src' );
693		$product_img.wc_reset_variation_attr( 'data-large_image' );
694		$product_img.wc_reset_variation_attr( 'data-large_image_width' );
695		$product_img.wc_reset_variation_attr( 'data-large_image_height' );
696		$product_img_wrap.wc_reset_variation_attr( 'data-thumb' );
697		$gallery_img.wc_reset_variation_attr( 'src' );
698		$product_link.wc_reset_variation_attr( 'href' );
699	};
700
701	$(function() {
702		if ( typeof wc_add_to_cart_variation_params !== 'undefined' ) {
703			$( '.variations_form' ).each( function() {
704				$( this ).wc_variation_form();
705			});
706		}
707	});
708
709	/**
710	 * Matches inline variation objects to chosen attributes
711	 * @deprecated 2.6.9
712	 * @type {Object}
713	 */
714	var wc_variation_form_matcher = {
715		find_matching_variations: function( product_variations, settings ) {
716			var matching = [];
717			for ( var i = 0; i < product_variations.length; i++ ) {
718				var variation    = product_variations[i];
719
720				if ( wc_variation_form_matcher.variations_match( variation.attributes, settings ) ) {
721					matching.push( variation );
722				}
723			}
724			return matching;
725		},
726		variations_match: function( attrs1, attrs2 ) {
727			var match = true;
728			for ( var attr_name in attrs1 ) {
729				if ( attrs1.hasOwnProperty( attr_name ) ) {
730					var val1 = attrs1[ attr_name ];
731					var val2 = attrs2[ attr_name ];
732					if ( val1 !== undefined && val2 !== undefined && val1.length !== 0 && val2.length !== 0 && val1 !== val2 ) {
733						match = false;
734					}
735				}
736			}
737			return match;
738		}
739	};
740
741	/**
742	 * Avoids using wp.template where possible in order to be CSP compliant.
743	 * wp.template uses internally eval().
744	 * @param {string} templateId
745	 * @return {Function}
746	 */
747	var wp_template = function( templateId ) {
748		var html = document.getElementById( 'tmpl-' + templateId ).textContent;
749		var hard = false;
750		// any <# #> interpolate (evaluate).
751		hard = hard || /<#\s?data\./.test( html );
752		// any data that is NOT data.variation.
753		hard = hard || /{{{?\s?data\.(?!variation\.).+}}}?/.test( html );
754		// any data access deeper than 1 level e.g.
755		// data.variation.object.item
756		// data.variation.object['item']
757		// data.variation.array[0]
758		hard = hard || /{{{?\s?data\.variation\.[\w-]*[^\s}]/.test ( html );
759		if ( hard ) {
760			return wp.template( templateId );
761		}
762		return function template ( data ) {
763			var variation = data.variation || {};
764			return html.replace( /({{{?)\s?data\.variation\.([\w-]*)\s?(}}}?)/g, function( _, open, key, close ) {
765				// Error in the format, ignore.
766				if ( open.length !== close.length ) {
767					return '';
768				}
769				var replacement = variation[ key ] || '';
770				// {{{ }}} => interpolate (unescaped).
771				// {{  }}  => interpolate (escaped).
772				// https://codex.wordpress.org/Javascript_Reference/wp.template
773				if ( open.length === 2 ) {
774					return window.escape( replacement );
775				}
776				return replacement;
777			});
778		};
779	};
780
781})( 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.