PageSourceSearch

https://danishfuel.com/wp-content/plugins/woocommerce/assets/js/frontend/add-to-cart-variation.js?ver=9.6.4

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