PageSourceSearch

https://www.mmemed.com/wp-content/plugins/product-extras-for-woocommerce/assets/js/pewc.js?ver=4.3.15

js mmemed.com collected 2026-10-05 06:53:38 UTC 159,753 bytes, 3,584 lines download raw bytes

1(function($) {
2
3	var total_updated = false;
4
5	// Debounce timer for pewc_update_total_js: the function is called from multiple
6	// synchronous sources on a single click (form change, pewc_force_update_total_js,
7	// conditions chain). Debouncing collapses these into one call at the end of the
8	// event loop, removing the main-thread jank visible as click-to-selection lag.
9	var pewc_update_total_timer = null;
10	function pewc_update_total_js_debounced() {
11		clearTimeout( pewc_update_total_timer );
12		pewc_update_total_timer = setTimeout( pewc_update_total_js, 0 );
13	}
14
15	$( document ).ready( function() {
16
17		// $( 'body').find( '.dz-default.dz-message span' ).text( pewc_vars.drop_files_message );
18		// Init each select-box separately
19		$( '.pewc-select-box' ).each( function( index, element ) {
20			$( element ).ddslick({
21				onSelected: function( selectedData ) {
22					var original = selectedData.original[0];
23					var index = selectedData.selectedIndex;
24					var value = selectedData.selectedData.value;
25					var box_id = $( original ).attr( 'id' );
26					// Update field price
27					var hidden_option_id = box_id.replace( '_select_box', '' ) + '_' + index + '_hidden';
28					var price = $( '#' + hidden_option_id ).attr( 'data-option-cost' );
29					var wrapper = $( '#' + box_id ).closest( '.pewc-item' )
30						.attr( 'data-selected-option-price', price )
31						.attr( 'data-value', value )
32						.attr( 'data-field-value', value );
33					var hidden_select = $( '#' + box_id + '_' + index ).closest( '.pewc-item' ).find( '.pewc-select-box-hidden' ).attr( 'data-selected-option-price', price ).val( value );
34					//pewc_update_total_js(); // before 3.21.4
35
36					var select_box_wrapper = $( 'body' ).find( '.pewc-item-select-box .dd-container' );
37					$( 'body' ).find( '.dd-option label, .dd-selected label' ).each( function() {
38						$( this ).next( 'small' ).addBack().wrapAll( '<div class="dd-option-wrap"/>' );
39					});
40					// box_id = box_id.replace( '_select_box', '' );
41					box_id = $( '#' + box_id ).closest( '.pewc-item' ).attr( 'data-id' );
42					// Update the field attributes
43					$( 'body' ).find( '#' + box_id ).val( value ).trigger( 'change' );
44
45					var selected_option_price = $( '#' + box_id ).find( 'option:selected' ).attr( 'data-option-cost' );
46					$( wrapper ).attr( 'data-selected-option-price', selected_option_price );
47
48					$( 'body' ).find( '#' + box_id ).trigger( 'pewc_update_select_box' );
49					$( wrapper ).find( '.dd-selected-description' ).text( pewc_wc_price( selected_option_price, true ) );
50
51					// pewc_update_total_js() removed: trigger(change) above already fires pewc_update_total_js_debounced via .pewc-form-field change handler // since 3.21.4, moved here so that WCFAD can also update the price of the selected option
52
53				}
54			});
55		});
56
57		// Init each color-picker separately
58		$( '.pewc-color-picker-field' ).each( function ( index, element ) {
59			$(element).wpColorPicker({
60				defaultColor: $(element).data('color') ? $(element).data('color') : false,
61				change: function( event, ui ) {
62					// a callback to fire whenever the color changes to a valid color
63					$( 'body' ).trigger( 'pewc_trigger_calculations' );
64					$(element).trigger( 'pewc_trigger_color_picker_change' );
65					$(element).closest( '.pewc-item' ).attr( 'data-field-value', ui.color.toString() ); // 3.21.4
66				},
67				clear: function() {
68					// a callback to fire when the input is emptied or an invalid color
69					$( 'body' ).trigger( 'pewc_trigger_calculations' );
70					$(element).closest( '.pewc-item' ).attr( 'data-field-value', '' ); // 3.21.4
71				},
72				hide: !$(element).data('show'), // hide the color picker controls on load
73				palettes: !!$(element).data('palettes'), // show a group of common colors beneath the square
74				width: $(element).data('box-width') ? $(element).data('box-width') : 255,
75				mode: 'hsv',
76				type: 'full',
77				slider: 'horizontal'
78			});
79		});
80
81		$( 'body' ).find( '.dd-option label, .dd-selected label' ).each( function() {
82			$( this ).next( 'small' ).addBack().wrapAll( '<div class="dd-option-wrap"/>' );
83		});
84
85		// 3.24.5, for input type range, so that the slider will display the default value on page load
86		$( 'input.pewc-range-slider' ).each( function(){
87			if ( $(this).attr( 'value' ) > 0 ) {
88				$(this).trigger( 'change' );
89			}
90		});
91
92		// 3.26.7, force update totals when using the quantity selector +/- buttons
93		$( 'form.wp-block-add-to-cart-with-options .wc-block-components-quantity-selector' ).on( 'click', function( e ){
94			$( 'body' ).trigger( 'pewc_force_update_total_js' );
95		});
96
97		// 3.27.3, update max on child product independent quantities on page load
98		$( '.products-quantities-independent .pewc-child-select-field' ).each( function(){
99			var number_field = $( this ).closest( '.child-product-wrapper' ).find( '.pewc-child-quantity-field' );
100			pewc_update_independent_quantity_input_max( $( this ), number_field );
101		});
102	});
103
104	$('.require-depends li:first input').on('change',function() {
105		// Display asterisk on dependent required fields
106		if( $(this).val() != '' ) {
107			$(this).closest('.pewc-group').addClass('show-required');
108		} else {
109			$(this).closest('.pewc-group').removeClass('show-required');
110		}
111	});
112	$('.pewc-file-upload').on('change',function(){
113		readURL( this, $(this).attr('id') );
114	});
115	$('.pewc-remove-image').on('click',function(e){
116		e.preventDefault();
117		id = $(this).attr('data-id');
118		$('#'+id).val("");
119		$('#'+id+'-placeholder').css('display','none');
120		$('#'+id+'-placeholder img').attr('src', '#');
121		$('#'+id+'-wrapper').removeClass('image-loaded');
122	});
123	function readURL(input,id) {
124		if( input.files && input.files[0] ) {
125			var i = input.files.length;
126			var reader = new FileReader();
127			reader.onload = function (e) {
128				$('#'+id+'-wrapper').addClass('image-loaded');
129				$('#'+id+'-placeholder').fadeIn();
130				$('#'+id+'-placeholder img').attr('src', e.target.result);
131			}
132			reader.readAsDataURL(input.files[0]);
133		}
134	}
135	$('body').on('change input keyup','.pewc-has-maxchars input, .pewc-has-maxchars textarea',function(){
136		var maxchars = parseInt( $(this).attr('data-maxchars') );
137		var str = $(this).val();
138		var str_ex_spaces = $(this).val();
139		// Don't cost spaces
140		// str_ex_spaces = str_ex_spaces.replace(/\s/g, "");
141		if( pewc_vars.remove_spaces != 'no' ) {
142			str_ex_spaces = str.replace(/\s/g, "");
143			var num_spaces = str.split( " " ).length - 1;
144			maxchars += parseInt( num_spaces );
145		} else {
146			str_ex_spaces = str;
147
148		}
149		var str_len = str_ex_spaces.length;
150		if(str_len>maxchars){
151			var new_str = str_ex_spaces.substring(0, maxchars);
152			$(this).val(new_str);
153		}
154	});
155	$('body').on( 'change input', '.pewc-form-field', function() {
156		$form = $(this).closest( 'form' );
157		add_on_images.update_add_on_image( $( this ), $form );
158		// Debounced: this fires alongside the form.cart handler and pewc_force_update_total_js.
159		pewc_update_total_js_debounced();
160		if ( 'yes' == pewc_vars.enable_character_counter ) {
161			pewc_update_text_field_counter( $(this) );
162		}
163	});
164	$('body').on( 'change input', '.pewc-range-slider', function() {
165		$( this ).closest( '.pewc-item-field-wrapper' ).find( '.pewc-range-value' ).text( $( this ).val() );
166		$( this ).closest( '.pewc-item' ).attr( 'data-field-value', $( this ).val() ); // 3.24.5
167	});
168
169	// this updates all text field counters, called on first load
170	function pewc_update_text_field_counters() {
171		$( '.pewc-form-field' ).each( function(){
172			if ( $(this).closest( '.pewc-item' ).hasClass('pewc-item-text') || $(this).closest( '.pewc-item' ).hasClass('pewc-item-textarea') || $(this).closest( '.pewc-item' ).hasClass('pewc-item-advanced-preview') ) {
173				pewc_update_text_field_counter( $(this) );
174			}
175		});
176	}
177
178	function pewc_update_text_field_counter( field ) {
179		var wrapper = field.closest( '.pewc-item' );
180
181		if ( ! wrapper.hasClass('pewc-item-text') && ! wrapper.hasClass('pewc-item-textarea') && ! wrapper.hasClass('pewc-item-advanced-preview') ) {
182			return; // do nothing if not text fields
183		}
184
185		var val_length = field.val().length;
186		var field_id = field.attr( 'id' ).replace( '_clone', '' ); // 3.26.11, remove _clone so that the counter inside the lightbox works
187		//var current_count = $( '.pewc-text-counter-container.'+field.attr('id')+' .pewc-current-count' );
188		var current_count = field.closest( '.pewc-item' ).find( '.pewc-text-counter-container.' + field_id + ' .pewc-current-count' ); // 3.22.0, so that cloned text fields' counter works correctly
189		current_count.html( val_length );
190
191		current_count.removeClass( 'error' );
192		if ( parseInt( field.attr('data-minchars') ) > 0 && val_length < parseInt( field.attr('data-minchars') ) ) {
193			current_count.addClass( 'error' );
194		} else if ( parseInt( field.attr('data-maxchars') ) > 0 && val_length > parseInt( field.attr('data-maxchars') ) ) {
195			current_count.addClass( 'error' );
196		}
197	}
198
199	$('body').on('click','.pewc-remove-image',function(){
200		$form = $(this).closest('form');
201		// pewc_update_total( $form );
202		pewc_update_total_js();
203	});
204	// Bind to the show_variation event
205	// Update pewc-product-price field with variation price
206	// 3.20.1, changed .bind to .on, .bind is deprecated as of jQuery 3.0
207	$( document ).on( 'hide_variation', function( event, variation, purchasable ) {
208		$('#pewc-product-price').val( 0 );
209		$('#pewc-product-price-original').val( 0 ); // 3.21.7
210		pewc_update_total_js();
211		// hide all variation-dependent fields
212		$('.pewc-variation-dependent').each(function(){
213			if ($(this).hasClass( 'active' )) {
214				$(this).removeClass( 'active' );
215				// 3.20.1, run only if Optimised conditions is enabled
216				if ( pewc_vars.conditions_timer > 0 ) {
217					if( pewc_vars.reset_fields == 'yes' && ! $(this).hasClass( 'pewc-reset-me' ) ) {
218						$(this).addClass( 'pewc-reset-me' );
219					}
220					if ( $( this ).hasClass( 'pewc-field-triggers-condition' ) ) {
221						// 3.20.1, trigger the function trigger_field_condition_check() in pewc_conditions
222						if ( $( this ).find( 'input' ).length > 0 ) {
223							$( this ).find( 'input' ).trigger( 'change' );
224						} else if ( $( this ).find( 'select' ).length > 0 ) {
225							$( this ).find( 'select' ).trigger( 'change' );
226						}
227					}
228					if ( $( this ).hasClass( 'pewc-calculation-trigger' ) ) {
229						// sometimes the recalculate function is triggered too late, when the field is already hidden, so we trigger it manually
230						calculations.recalculate();
231					}
232				}
233				// 3.21.4
234				$( 'body' ).trigger( 'pewc_field_visibility_updated', [ $(this).attr('data-id'), 'hide' ] );
235			}
236		});
237		$( 'body' ).trigger( 'pewc_reset_fields' ); // 3.20.1
238	});
239	$( document ).on( 'show_variation', function( event, variation, purchasable ) {
240		$( '#pewc_calc_set_price' ).attr( 'data-calc-set', 0 );
241		pewc_update_total_js();
242		var var_price = variation.display_price;
243		$( '#pewc_variation_price' ).val( var_price );
244		$( '#pewc-product-price' ).val( var_price );
245		$( '#pewc-product-price-original' ).val( var_price ); // 3.21.7
246		// Update percentage prices
247		$( 'body' ).trigger( 'pewc_do_percentages' );
248		// Find any select options with percentage prices - these might not have a field price
249		$( this ).find( '.pewc-percentage.pewc-item-select select' ).each( function() {
250			pewc_update_select_percentage_field( $( this ), var_price );
251		});
252		$( this ).find( '.pewc-percentage.pewc-item-select-box' ).each( function() {
253			pewc_update_select_box_percentage_field( $( this ), var_price );
254		});
255		$( this ).find( '.pewc-percentage.pewc-item-image_swatch, .pewc-percentage.pewc-item-radio' ).each( function() {
256			pewc_update_radio_percentage_field( $( this ), var_price );
257		});
258		// Check for variation dependent fields
259		var variation_id = variation.variation_id;
260		$('.pewc-variation-dependent').each(function(){
261			var ids = $(this).attr('data-variations');
262			ids = ids.split( ',' );
263			ids = ids.map( function( x ) {
264				return parseInt( x, 10 );
265			});
266			if( ids.indexOf( variation_id ) != -1 ) {
267				$(this).addClass( 'active' );
268				// 3.20.1
269				if( pewc_vars.reset_fields == 'yes' && pewc_vars.conditions_timer > 0 ) {
270					$(this).removeClass( 'pewc-reset-me' );
271				}
272				// 3.21.4
273				$( 'body' ).trigger( 'pewc_field_visibility_updated', [ $(this).attr('data-id'), 'show' ] );
274			} else {
275				$(this).removeClass( 'active' );
276				// 3.20.1
277				if( pewc_vars.reset_fields == 'yes' && ! $(this).hasClass( 'pewc-reset-me' ) && pewc_vars.conditions_timer > 0 ) {
278					$(this).addClass( 'pewc-reset-me' );
279				}
280			}
281			// 3.20.1
282			if ( pewc_vars.conditions_timer > 0 ) {
283				if ( $( this ).hasClass( 'pewc-field-triggers-condition' ) ) {
284					// trigger trigger_field_condition_check() or trigger_condition_check() in pewc_conditions
285					if ( $( this ).find( 'input' ).length > 0 ) {
286						$( this ).find( 'input' ).trigger( 'change' );
287					} else if ( $( this ).find( 'select' ).length > 0 ) {
288						$( this ).find( 'select' ).trigger( 'change' );
289					}
290				}
291				if ( $( this ).hasClass( 'pewc-calculation-trigger' ) ) {
292					// sometimes the recalculate function is triggered too late, when the field is already hidden, so we trigger it manually
293					calculations.recalculate();
294				}
295			}
296		});
297		// Update product dimensions
298		$( '#pewc_product_length' ).val( variation.dimensions['length'] );
299		$( '#pewc_product_width' ).val( variation.dimensions['width'] );
300		$( '#pewc_product_height' ).val( variation.dimensions['height'] );
301		$( '#pewc_product_weight' ).val( variation.weight );
302		// Trigger recalculation
303		$( 'body' ).trigger( 'pewc_trigger_calculations' );
304		$( 'body' ).trigger( 'pewc_variations_updated' );
305		$( 'body' ).trigger( 'pewc_reset_fields' ); // 3.20.1
306		pewc_update_total_js();
307	});
308
309	$( 'body' ).on( 'pewc_do_percentages', function() {
310		$('.pewc-percentage').each(function() {
311			var var_price = $( '#pewc-product-price' ).val();
312			var new_price = ( var_price / 100 ) * parseFloat( $( this ).attr( 'data-percentage' ) );
313			if( isNaN( new_price ) ) {
314				new_price = 0;
315			}
316			$(this).attr( 'data-price', new_price );
317			var new_price_html = pewc_wc_price( new_price.toFixed(pewc_vars.decimals) );
318			$(this).find('.pewc-field-price').html(new_price_html);
319
320			// 3.21.4, for checkbox fields
321			if ( $(this).hasClass( 'pewc-item-checkbox' ) ) {
322				var new_price_currency_only = pewc_wc_price( new_price.toFixed( pewc_vars.decimals ), true );
323				$(this).find( '.pewc-checkbox-price' ).html( new_price_currency_only );
324				return;
325			}
326			// Find any options in this field - checkbox group
327			$(this).find( '.pewc-option-has-percentage' ).each(function() {
328				var option_price = ( var_price / 100 ) * $(this).attr('data-option-percentage');
329				$(this).attr('data-option-cost',option_price.toFixed(pewc_vars.decimals));
330				option_price = pewc_wc_price( option_price.toFixed(pewc_vars.decimals) );
331				$(this).closest('.pewc-checkbox-form-label').find('.pewc-option-cost-label').html(option_price);
332			});
333		});
334	});
335	$( 'body.pewc-variable-product' ).on( 'update change', '.pewc-percentage.pewc-item-select select', function( e ) {
336		// Only do this on variable products
337		pewc_update_select_percentage_field( $( this ), $( '#pewc_variation_price' ).val() );
338	});
339	// @param select is the select element itself
340	function pewc_update_select_percentage_field( select, var_price ) {
341		pewc_update_select_option_percentage( select, var_price );
342		// Trigger recalculation
343		$( 'body' ).trigger( 'pewc_trigger_calculations' );
344		pewc_update_total_js();
345	}
346	// @param selectbox is the wrapper element
347	// @param var_price the variation price
348	function pewc_update_select_box_percentage_field( selectbox, var_price ) {
349		var select = $( selectbox ).find( 'select' );
350		// Update the hidden select field
351		pewc_update_select_option_percentage( select, var_price );
352		// Now update the select box options
353		var box = $( selectbox ).find( '.dd-select' );
354		var box_options = $( selectbox ).find( '.dd-options' );
355		$( select ).find( 'option' ).each( function( i, v ) {
356			var new_price = ( var_price / 100 ) * $( this ).attr( 'data-option-percentage' );
357			var new_text = $( this ).val() + pewc_vars.separator + pewc_wc_price( new_price.toFixed( pewc_vars.decimals ), true );
358			var option = $( box_options ).find( 'li' ).eq( i );
359			$( option ).find( '.dd-option-description' ).text( new_text );
360		});
361		// Update the selected option price
362		var selected_price = $( select ).children( 'option:selected' ).attr( 'data-option-cost' );
363		selected_price = pewc_wc_price( selected_price, true );
364		$( selectbox ).find( '.dd-selected .dd-selected-description' ).text( selected_price );
365
366		// Trigger recalculation
367		$( 'body' ).trigger( 'pewc_trigger_calculations' );
368		pewc_update_total_js();
369	}
370	// Shared function for select and select box fields
371	function pewc_update_select_option_percentage( select, var_price ) {
372		var selected = $( select ).children( 'option:selected' );
373		var option_price = ( var_price / 100 ) * $( selected ).attr( 'data-option-percentage' );
374		var item = $( select ).closest( '.pewc-item' ).attr( 'data-selected-option-price', option_price );
375		$( selected ).attr( 'data-option-cost', option_price.toFixed( pewc_vars.decimals ) );
376		option_price = pewc_wc_price( option_price.toFixed( pewc_vars.decimals ) );
377		var data_price = $( select ).closest( '.pewc-item' ).attr( 'data-price' );
378		if( isNaN( data_price ) ) {
379			$( select ).closest( '.pewc-item' ).attr( 'data-price', 0 );
380		}
381		// Update all options prices
382		$( select ).find( 'option' ).each( function( i, v ) {
383			var new_price = ( var_price / 100 ) * $( this ).attr( 'data-option-percentage' );
384			$( this ).attr( 'data-option-cost', new_price.toFixed( pewc_vars.decimals ) );
385			if ( $( select ).closest( '.pewc-item' ).hasClass( 'pewc-hide-option-price' ) || $( this ).hasClass( 'pewc-first-option' ) ) {
386				return; // no need to proceed if option price is hidden for this field
387			}
388			var new_text = $( this ).val() + pewc_vars.separator + pewc_wc_price( new_price.toFixed( pewc_vars.decimals ), true );
389			$( this ).text( new_text );
390		});
391	}
392	// @param swatch is the swatch or radio group field wrapper
393	function pewc_update_radio_percentage_field( field, var_price ) {
394		// Iterate through each input element and update all options prices
395		$( field ).find( 'input' ).each( function( i, v ) {
396			var new_price = ( var_price / 100 ) * $( this ).attr( 'data-option-percentage' );
397			$( this ).attr( 'data-option-cost', new_price.toFixed( pewc_vars.decimals ) );
398			var new_text = $( this ).val() + pewc_vars.separator + pewc_wc_price( new_price.toFixed( pewc_vars.decimals ), true );
399			$( this ).closest( 'label' ).next().text( new_text );
400			if ( $( field ).hasClass( 'pewc-hide-option-price' ) ) {
401				return; // no need to proceed if option price is hidden for this field
402			}
403			// 3.21.4, added pewc-item-image-swatch-checkbox
404			if( ( $( field ).hasClass( 'pewc-item-radio' ) || $( field ).hasClass( 'pewc-item-image-swatch-checkbox' ) ) && $( field ).hasClass( 'pewc-item-image_swatch' ) ) {
405				// 3.21.4, added .pewc-radio-image-desc to avoid duplicates
406				$( this ).closest( 'label' ).find( '.pewc-radio-image-desc span' ).text( new_text );
407			} else if( $( field ).hasClass( 'pewc-item-radio' ) ) {
408				$( this ).closest( 'li' ).find( 'label span.pewc-radio-option-text' ).text( new_text );
409			}
410		});
411		// Trigger recalculation
412		$( 'body' ).trigger( 'pewc_trigger_calculations' );
413		pewc_update_total_js();
414	}
415	function pewc_update_total_js( $update=0 ) {
416
417		var flat_rate_total = 0;
418		var product_price = parseFloat( $('#pewc-product-price').val() );
419		var orig_product_price = parseFloat( $('#pewc-product-price-original').val() ); // 3.21.7
420		var total_price = 0; // Options running total
421		var orig_total_price = 0; // 3.21.7, stores add-on prices before getting adjusted by DPDR
422		var added_price = 0;
423		var repeatable_prices = 0; // 3.26.7, keeps track of repeatable field prices, in case we don't want them multiplied against the quantity
424		var field_value = [];
425		var field_label = [];
426
427		$('form.cart .pewc-form-field').each(function() {
428
429			added_price = 0;
430
431			var field_wrapper = $(this).closest('.pewc-group');
432			$( field_wrapper ).removeClass( 'pewc-active-field' );
433
434			// Ignore hidden variation dependent fields
435			if( ! $( field_wrapper ).hasClass( 'pewc-variation-dependent' ) || ( $( field_wrapper ).hasClass( 'pewc-variation-dependent' ) && $( field_wrapper ).hasClass( 'active' ) ) ) {
436
437				var group_wrap = $( field_wrapper ).closest( '.pewc-group-wrap' );
438				if ( group_wrap.hasClass( 'pewc-group-hidden' ) && ! group_wrap.hasClass( 'pewc-group-always-include' ) ) {
439					// 3.27.9, added condition to check for class .pewc-group-always-include. If it exists, include it in the totals, 
440					// since when added to the cart, the hidden field's cost are included. This makes it consistent on both the product page and 
441					// the cart page.
442					return; // this field is inside a hidden group, so ignore and return
443				}
444
445				// Check that the extra field is not flat rate
446				if( ! $(field_wrapper).hasClass('pewc-flatrate') ) {
447
448					if( $(field_wrapper).hasClass('pewc-group-checkbox') && ! $(field_wrapper).hasClass('pewc-hidden-field') ) {
449
450						if( $(field_wrapper).hasClass('pewc-per-unit-pricing') && $(this).prop('checked') ) {
451							// Bookings for WooCommerce
452							// Multiply option cost by number of booked units
453							// total_price += parseFloat( $('#num_units_int').val() ) * parseFloat( $(field_wrapper).attr('data-price') );
454							added_price = parseFloat( $('#num_units_int').val() ) * parseFloat( $(field_wrapper).attr('data-price') );
455							$( field_wrapper ).addClass( 'pewc-active-field' );
456						} else if( $(this).prop('checked') ) {
457							// total_price += parseFloat( $(field_wrapper).attr('data-price') );
458							added_price = parseFloat( $(field_wrapper).attr('data-price') );
459							$( field_wrapper ).addClass( 'pewc-active-field' );
460						} else {
461							$( field_wrapper ).removeClass( 'pewc-active-field' );
462						}
463
464					} else if( $(field_wrapper).hasClass('pewc-group-select' ) && ! $(field_wrapper).hasClass('pewc-hidden-field') ) {
465
466						// 3.24.8, added check for pewc-first-field-empty
467						if ( ! $( field_wrapper ).hasClass( 'pewc-first-field-empty' ) || $(this).find(':selected').val() != '' ) {
468							$( field_wrapper ).addClass( 'pewc-active-field' );
469							$( field_wrapper ).attr( 'data-field-value', $(this).find(':selected').val() );
470
471							// 'value' means use the price as value only, on calculation fields
472							// 3.25.6, moved here so that Select fields that have field price, but first element is instruction only, won't get added until an option is selected
473							if ( $(field_wrapper).attr( 'data-option-price-visibility' ) != 'value' ) {
474								// Add cost of selected option
475								added_price = parseFloat( $(this).find(':selected').attr('data-option-cost') );
476								// Add cost of select field
477								added_price += parseFloat( $(field_wrapper).attr('data-price') );
478								// Bookings for WooCommerce: multiply by number of booked units
479								if ( $(field_wrapper).hasClass('pewc-per-unit-pricing') ) {
480									added_price = parseFloat( $('#num_units_int').val() ) * added_price;
481								}
482							}
483						}
484
485					} else if( $(field_wrapper).hasClass('pewc-group-select-box' ) && ! $(field_wrapper).hasClass('pewc-hidden-field') ) {
486
487						// 3.24.8, added check for pewc-first-field-empty
488						if ( ! $( field_wrapper ).hasClass( 'pewc-first-field-empty' ) || $(this).find(':selected').val() != '' ) {
489							$( field_wrapper ).addClass( 'pewc-active-field' );
490							//$( field_wrapper ).attr( 'data-field-value', $(this).find('.pewc-select-box-hidden' ).val() ); // doesn't work as of 3.21.6
491							$( field_wrapper ).attr( 'data-field-value', $(this).find( ':selected' ).val() ); // 3.21.7
492
493							// 'value' means use the price as value only, on calculation fields
494							// 3.25.6, moved here, similar to Select field above
495							if ( $(field_wrapper).attr( 'data-option-price-visibility' ) != 'value' ) {
496								// Add cost of selected option
497								added_price = parseFloat( $( field_wrapper ).attr( 'data-selected-option-price') );
498								// Add cost of select field
499								added_price += parseFloat( $( field_wrapper ).attr( 'data-
499price' ) );
500								// Bookings for WooCommerce: multiply by number of booked units
501								if ( $(field_wrapper).hasClass('pewc-per-unit-pricing') ) {
502									added_price = parseFloat( $('#num_units_int').val() ) * added_price;
503								}
504							}
505						}
506
507					} else if( $(this).val() && ! $(field_wrapper).hasClass('pewc-hidden-field') ) {
508
509						if( $(field_wrapper).hasClass('pewc-per-character-pricing') && ( $(field_wrapper).hasClass('pewc-item-text') || $(field_wrapper).hasClass('pewc-item-textarea') || $(field_wrapper).hasClass( 'pewc-item-advanced-preview' ) ) ) {
510							var str_len = pewc_get_text_str_len( $(this).val(), field_wrapper );
511							added_price = str_len * parseFloat( $(field_wrapper).attr('data-price') );
512						} else if( $(field_wrapper).hasClass( 'pewc-multiply-pricing' ) ) {
513							var num_value = $(this).val();
514							added_price = num_value * parseFloat( $(field_wrapper).attr('data-price') );
515						} else if( $(field_wrapper).hasClass('pewc-group-name_price') ) {
516							added_price = parseFloat( $(this).val() );
517						} else {
518							added_price = parseFloat( $(field_wrapper).attr('data-price') );
519						}
520
521						// 3.27.11, moved here so that Price per booking unit can be used with Multiply Price
522						if( $(field_wrapper).hasClass( 'pewc-item-number' ) && $(field_wrapper).hasClass( 'pewc-per-unit-pricing' ) ) {
523								// Bookings for WooCommerce
524								// Multiply option cost by number of booked units
525								// total_price += parseFloat( $('#num_units_int').val() ) * parseFloat( $(field_wrapper).attr('data-price') );
526								// added_price = parseFloat( $('#num_units_int').val() ) * parseFloat( $(field_wrapper).attr('data-price') ) * parseFloat( $( this ).val() );
527								added_price = parseFloat( added_price ) * parseFloat( $('#num_units_int').val() ); // 3.27.11, use added_price so that this can be used with Multiply Price setting
528						}
529
530						if( $(this).val() ) {
531							$( field_wrapper ).addClass( 'pewc-active-field' );
532
533							if ( $(this).hasClass( 'pewc-range-slider' ) && $(this).attr( 'value' ) == '' ) {
534								// 3.24.5, input of type range always has a value, so if this is the first load, and we don't have a user-selected value, don't set data-field-value
535							} else {
536								$( field_wrapper ).attr( 'data-field-value', $(this).val() );
537							}
538						}
539
540					} else {
541
542						// blank text value falls here
543						$( field_wrapper ).attr( 'data-field-value', '' );
544
545					}
546
547					// 3.26.7, by default, add-on field prices are multiplied against the quantity. There are cases we don't want to do this for repeatable fields
548					if ( $( field_wrapper ).hasClass( 'pewc-repeatable-field' ) && ! $( field_wrapper ).hasClass( 'pewc-multiply-repeatable' ) ) {
549						repeatable_prices += added_price; // we don't add this field's price to the total price so that repeatable prices are not multiplied with quantity
550					} else {
551						total_price += added_price; // default behavior, later on total_price is multiplied against quantity
552					}
553
554					if( ! isNaN( added_price ) ) {
555						$( field_wrapper ).attr( 'data-field-price', added_price );
556					}
557
558				} else {
559
560					// Flat rate item
561					if( $(field_wrapper).hasClass('pewc-group-checkbox') && ! $(field_wrapper).hasClass('pewc-hidden-field') ) {
562						if( $(field_wrapper).hasClass('pewc-per-unit-pricing') && $(this).prop('checked') ) {
563							// Bookings for WooCommerce
564							// Multiply option cost by number of booked units
565							added_price = parseFloat( $('#num_units_int').val() ) * parseFloat( $(field_wrapper).attr('data-price') );
566							$( field_wrapper ).addClass( 'pewc-active-field' );
567						} else if( $(this).prop('checked') ) {
568							added_price = parseFloat( $(field_wrapper).attr('data-price') );
569							$( field_wrapper ).addClass( 'pewc-active-field' );
570						}
571					} else if( ( $(field_wrapper).hasClass('pewc-group-select') || $(field_wrapper).hasClass('pewc-group-select-box') ) && ! $(field_wrapper).hasClass('pewc-hidden-field') ) {
572						// Add cost of selected option
573						added_price = parseFloat( $(this).find(':selected').attr('data-option-cost') );
574						// Add cost of select field
575						added_price += parseFloat( $(field_wrapper).attr('data-price') );
576						// Bookings for WooCommerce: multiply by number of booked units
577						if ( $(field_wrapper).hasClass('pewc-per-unit-pricing') ) {
578							added_price = parseFloat( $('#num_units_int').val() ) * added_price;
579						}
580						$( field_wrapper ).addClass( 'pewc-active-field' );
581					} else if( $(this).val() && ! $(field_wrapper).hasClass('pewc-hidden-field') ) {
582						if( $(field_wrapper).hasClass('pewc-per-character-pricing') ) {
583							var str_len = pewc_get_text_str_len( $(this).val(), field_wrapper );
584							added_price = str_len * parseFloat( $(field_wrapper).attr('data-price') );
585							$( field_wrapper ).addClass( 'pewc-active-field' );
586						} else if( $(field_wrapper).hasClass('pewc-multiply-pricing') ) {
587							var num_value = $(this).val();
588							added_price = num_value * parseFloat( $(field_wrapper).attr('data-price') );
589							$( field_wrapper ).addClass( 'pewc-active-field' );
590						} else if( $(field_wrapper).hasClass('pewc-group-name_price') ) {
591							added_price = parseFloat( $(this).val() );
592						} else {
593							added_price = parseFloat( $(field_wrapper).attr('data-price') );
594							$( field_wrapper ).addClass( 'pewc-active-field' );
595						}
596					}
597
598					flat_rate_total += added_price;
599					$( field_wrapper ).attr( 'data-field-price', added_price );
600					$( field_wrapper ).attr( 'data-field-value', $(this).val() ); // 3.24.1, for JS validation
601
602				}
603
604			}
605
606			if( $( field_wrapper ).val() ) {
607				set_summary_panel_data( $( field_wrapper ), $( field_wrapper ).val(), added_price );
608			}
609
610		});
611
612		$( 'form.cart .pewc-item-radio, form.cart .pewc-item-image_swatch, form.cart .pewc-item-calendar-list' ).each(function() {
613
614			var field_value = [];
615
616			if( ! $( this ).hasClass( 'pewc-variation-dependent' ) || ( $( this ).hasClass( 'pewc-variation-dependent' ) && $( this ).hasClass( 'active' ) ) ) {
617
618				//var radio_group_id = $(this).attr( 'data-id' ); // 3.26.5, commented out
619				var group_wrap = $( this ).closest( '.pewc-group-wrap' );
620
621				if( ! $(this).hasClass('pewc-hidden-field') && ! group_wrap.hasClass( 'pewc-group-hidden' ) ) {
622
623					// 3.26.5, let's use a variable
624					var checked_radio = $( this ).find( 'input[type=radio]:checked' );
625
626					// 3.26.5, moved this condition outside of the 3 if/else
627					if( checked_radio.attr( 'data-option-cost' ) ) {
628						if ( $(this).attr('data-option-price-visibility') == 'value' ) {
629
630							// this option is only used for calculations, so don't add the price to the total
631							var selected_option_price = checked_radio.attr( 'data-option-cost' );
632							$( this ).attr( 'data-selected-option-price', selected_option_price );
633
634						} else if( ! $(this).hasClass( 'pewc-flatrate' ) ) {
635
636							added_price = parseFloat( $(this).attr( 'data-price' ) );
637							var selected_option_price = checked_radio.attr( 'data-option-cost' );
638							$( this ).attr( 'data-selected-option-price', selected_option_price );
639							added_price += parseFloat( selected_option_price );
640
641							// 3.26.7, by default, add-on field prices are multiplied against the quantity. There are cases we don't want to do this for repeatable fields
642							if ( $( this ).hasClass( 'pewc-repeatable-field' ) && ! $( this ).hasClass( 'pewc-multiply-repeatable' ) ) {
643								repeatable_prices += added_price; // we don't add this field's price to the total price so that repeatable prices are not multiplied with quantity
644							} else {
645								total_price += added_price;
646							}
647
648						} else {
649
650							flat_rate_total += parseFloat( $(this).attr( 'data-price' ) );
651							var selected_option_price = checked_radio.attr( 'data-option-cost' );
652							$( this ).attr( 'data-selected-option-price', selected_option_price );
653							flat_rate_total += parseFloat( selected_option_price );
654
655						}
656					} else {
657						$( this ).attr( 'data-selected-option-price', 0 );
658					}
659
660					if( checked_radio.val() ) {
661						set_summary_panel_data( $( this ), checked_radio.val(), added_price );
662					} else {
663						set_summary_panel_data( $( this ), '', 0 );
664						$( this ).removeClass( 'pewc-active-field' ); // 3.21.4, moved here because set_summary_panel_data adds the class pewc-active-field
665					}
666
667				}
668
669			}
670
671		});
672
673		$('form.cart .pewc-item-select').each(function() {
674			var selected_option_price = $( this ).find( 'option:selected' ).attr( 'data-option-cost' );
675			$( this ).attr( 'data-selected-option-price', selected_option_price );
676		});
677
678		$('form.cart .pewc-item-checkbox_group').each(function() {
679
680			var field_value = [];
681			var selected_counter = 0;
682
683			if( ! $( this ).hasClass( 'pewc-variation-dependent' ) || ( $( this ).hasClass( 'pewc-variation-dependent' ) && $( this ).hasClass( 'active' ) ) ) {
684
685				var checkbox_group_id = $(this).attr( 'data-id' );
686				var checkbox_group_price = 0;
687				var group_wrap = $( this ).closest( '.pewc-group-wrap' );
688
689				if( ! $(this).hasClass('pewc-hidden-field') && ! group_wrap.hasClass( 'pewc-group-hidden' ) ) {
690					var checkbox_value = [];
691					if( ! $(this).hasClass('pewc-flatrate') ) {
692						// Get the field price
693						if( $("input[name='" + checkbox_group_id + "[]']:checked" ).val() ) {
694							checkbox_group_price += parseFloat( $(this).attr('data-price') );
695						}
696						$('.'+checkbox_group_id).find( $('input[type=checkbox]:checked') ).each( function() {
697							checkbox_group_price += parseFloat( $(this).attr('data-option-cost') );
698							checkbox_value.push( $( this ).val() );
699							selected_counter++;
700						});
701						total_price += checkbox_group_price;
702
703						// Summary panel
704						if( $("input[name='" + checkbox_group_id + "[]']:checked" ).val() ) {
705							$( this ).attr( 'data-field-price', checkbox_group_price );
706							$( this ).addClass( 'pewc-active-field' );
707							$( this ).attr( 'data-field-value', checkbox_value.join( ', ' ) );
708						}
709						else {
710							// remove from summary panel
711							$( this ).attr( 'data-field-price', 0 );
712							$( this ).removeClass( 'pewc-active-field' );
713							$( this ).attr( 'data-field-value', '' );
714						}
715
716					} else {
717
718						// Flat rate
719						if( $("input[name='" + checkbox_group_id + "[]']:checked" ).val() ) {
720							flat_rate_total += parseFloat( $(this).attr('data-price') );
721						}
722						$('.'+checkbox_group_id).find( $('input[type=checkbox]:checked') ).each( function() {
723							flat_rate_total += parseFloat( $(this).attr('data-option-cost') );
724							checkbox_value.push( $( this ).val() );
725							selected_counter++;
726						});
727
728						if ( checkbox_value.length > 0 ) {
729							$( this ).attr( 'data-field-value', checkbox_value.join( ', ' ) );
730						} else {
731							$( this ).attr( 'data-field-value', '' );
732						}
733					}
734				}
735
736			}
737
738			pewc_update_checkbox_field_counter( $(this), selected_counter );
739
740		});
741		$('form.cart .pewc-item-image-swatch-checkbox').each(function() {
742
743			var field_value = [];
744			var selected_counter = 0;
745
746			if( ! $( this ).hasClass( 'pewc-variation-dependent' ) || ( $( this ).hasClass( 'pewc-variation-dependent' ) && $( this ).hasClass( 'active' ) ) ) {
747
748				var checkbox_group_id = $(this).attr( 'data-id' );
749				var checkbox_group_price = 0;
750				var group_wrap = $( this ).closest( '.pewc-group-wrap' );
751
752				if( ! $(this).hasClass('pewc-hidden-field') && ! group_wrap.hasClass( 'pewc-group-hidden' ) ) {
753					var field_value = [];
754					if( ! $(this).hasClass('pewc-flatrate') ) {
755						// Get the field price
756						if( $("input[name='" + checkbox_group_id + "[]']:checked" ).val() ) {
757							checkbox_group_price += parseFloat( $(this).attr('data-price') );
758						}
759						$('.'+checkbox_group_id).find( $('input[type=checkbox]:checked') ).each( function() {
760							field_value.push( $( this ).val() );
761							checkbox_group_price += parseFloat( $(this).attr('data-option-cost') );
762							selected_counter++;
763						});
764						total_price += checkbox_group_price;
765					} else {
766						// Flat rate
767						if( $("input[name='" + checkbox_group_id + "[]']:checked" ).val() ) {
768							flat_rate_total += parseFloat( $(this).attr('data-price') );
769						}
770						$('.'+checkbox_group_id).find( $('input[type=checkbox]:checked') ).each( function(){
771							field_value.push( $( this ).val() );
772							flat_rate_total += parseFloat( $(this).attr('data-option-cost') );
773							selected_counter++;
774						});
775					}
776				}
777
778				if( field_value.length > 0 ) {
779					set_summary_panel_data( $( this ), field_value.join( ', ' ), checkbox_group_price );
780				} else {
781					$( this ).removeClass( 'pewc-active-field' );
782					set_summary_panel_data( $( this ), '', 0 );
783				}
784
785			}
786
787			pewc_update_checkbox_field_counter( $(this), selected_counter );
788
789		});
790
791		// Check child products with select layout
792		var child_products_total = 0;
793		$('form.cart .pewc-child-select-field').each(function() {
794
795			var field_wrapper = $( this ).closest( '.pewc-item' );
796			var field_value = [];
797			var is_hidden = $( this ).closest( '.pewc-item' ).hasClass( 'pewc-hidden-field' );
798			var is_dependent = ( $( this ).closest( '.pewc-item' ).hasClass( 'pewc-variation-dependent' ) ) && ( ! $( this ).closest( '.pewc-item' ).hasClass( 'active' ) );
799			if( ! is_hidden && ! is_dependent ) {
800				// If the select field has a value
801				if( $(this).val() && $(this).val() != '' ) {
802					field_value.push( $(this).find(':selected').attr( 'data-field-value' ) );
803					var selected = $(this).find(':selected');
804					var child_product_price = selected.data( 'option-cost' );
805					// 3.21.4, compatibility with FD
806					if ( parseFloat( selected.attr('data-wcfad-price') ) > 0 ) {
807						child_product_price = parseFloat( selected.attr('data-wcfad-price') );
808					}
809					var qty = 0;
810					if( child_product_price > 0 ) {
811						var wrapper = $(this).closest('.child-product-wrapper');
812						var quantities = $(wrapper).data('products-quantities');
813						// Get the quantity
814						if( quantities == 'linked' ) {
815							//qty = $('form.cart .quantity .qty').val();
816							// 3.27.0
817							qty = pewc_get_quantity( qty, 'linked' );
818						} else if( quantities == 'independent' ) {
819							// Find the child_quantity field
820							qty = $(wrapper).find('.pewc-child-quantity-field').val();
821							if ( pewc_vars.multiply_independent == 'yes' /*&& $('form.cart .quantity .qty').val() !== undefined*/ ) {
822								// 3.27.0
823								var main_quantity = pewc_get_quantity();
824								qty = qty * parseFloat( main_quantity );
825							}
826						} else if( quantities == 'one-only' ) {
827							qty = pewc_get_quantity( 1, 'one-only' );
828						}
829					}
830
831					child_products_total += parseFloat( child_product_price ) * parseFloat( qty );
832					if( field_value.length > 0 ) {
833						$( this ).closest( '.pewc-item' ).attr( 'data-field-price', child_products_total );
834						set_summary_panel_data( $( this ).closest( '.pewc-item' ), field_value.join( ', ' ), parseFloat( child_product_price ) * parseFloat( qty ) );
835					} else {
836						$( this ).closest( '.pewc-item' ).removeClass( 'pewc-active-field' );
837					}
838
839				}
840			}
841		});
842		$('form.cart .pewc-radio-images-wrapper.child-product-wrapper').each(function() {
843			var field_value = [];
844			var is_hidden = $( this ).closest( '.pewc-item' ).hasClass( 'pewc-hidden-field' );
845			var is_dependent = ( $( this ).closest( '.pewc-item' ).hasClass( 'pewc-variation-dependent' ) ) && ( ! $( this ).closest( '.pewc-item' ).hasClass( 'active' ) );
846			if( ! is_hidden && ! is_dependent ) {
847				var quantities = $(this).data('products-quantities');
848				var checked_radio = $(this).find('.pewc-radio-form-field:checked');
849				var radio_val = checked_radio.val();
850				if( radio_val && radio_val != undefined ) {
851					var child_product_price = checked_radio.data('option-cost');
852					// 3.21.4, compatibility with FD
853					if ( parseFloat( checked_radio.attr('data-wcfad-price') ) > 0 ) {
854						child_product_price = parseFloat( checked_radio.attr('data-wcfad-price') );
855					}
856					var qty = 0;
857					// sometimes child_product_price is zero if it's discounted
858
859					// Get the quantity
860					if( quantities == 'linked' ) {
861						//qty = $('form.cart .quantity .qty').val();
862						// 3.27.0
863						qty = pewc_get_quantity( qty, 'linked' );
864					} else if( quantities == 'independent' ) {
865						// Find the child_quantity field
866						qty = $(this).closest('.pewc-item-field-wrapper').find('.pewc-child-quantity-field').val();
867						if ( pewc_vars.multiply_independent == 'yes' /*&& $('form.cart .quantity .qty').val() !== undefined*/ ) {
868							// 3.27.0
869							var main_quantity = pewc_get_quantity();
870							qty = qty * parseFloat( main_quantity );
871						}
872					} else if( quantities == 'one-only' ) {
873						qty = pewc_get_quantity( 1, 'one-only' );
874					}
875
876					child_products_total += parseFloat( child_product_price ) * parseFloat( qty );
877
878					if( child_products_total > 0 || qty > 0 ) {
879						$( this ).closest( '.pewc-item' ).attr( 'data-field-price', child_products_total );
880						set_summary_panel_data( $( this ).closest( '.pewc-item' ), checked_radio.attr( 'data-field-label' ), parseFloat( child_product_price ) * parseFloat( qty ) );
881					}
882
883				} else {
884					$( this ).closest( '.pewc-item' ).removeClass( 'pewc-active-field' );
885					$( this ).closest( '.pewc-item' )
886						.attr( 'data-field-price', 0 )
887						.attr( 'data-field-value', '' ); // 3.21.4, reset price and value
888				}
889
890			}
891		});
892
893		// 3.25.3, added form.cart .pewc-components-wrapper.child-product-wrapper
894		$( 'form.cart .pewc-checkboxes-images-wrapper.child-product-wrapper, form.cart .pewc-components-wrapper.child-product-wrapper' ).each(function() {
895
896			var this_child_total = 0;
897			var field_value = [];
898			var selected_counter = 0;
899			var is_hidden = $( this ).closest( '.pewc-item' ).hasClass( 'pewc-hidden-field' );
900			var is_dependent = ( $( this ).closest( '.pewc-item' ).hasClass( 'pewc-variation-dependent' ) ) && ( ! $( this ).closest( '.pewc-item' ).hasClass( 'active' ) );
901
902			if( ! is_hidden && ! is_dependent ) {
903				var quantities = $(this).data('products-quantities');
904				// Run through each selected checkbox
905
906				$( this ).closest( '.pewc-item' ).removeClass( 'pewc-active-field' );
907
908				$( this ).find('.pewc-checkbox-form-field:checkbox:checked').each(function() {
909					field_value.push( $( this ).attr( 'data-field-label' ) );
910					var child_product_price = $(this).data('option-cost');
911					// 3.21.4, compatibility with FD
912					if ( parseFloat( $(this).attr('data-wcfad-price') ) > 0 ) {
913						child_product_price = parseFloat( $(this).attr('data-wcfad-price') );
914					}
915					var qty = 0;
916
917					// Get the quantity
918					if( quantities == 'linked' ) {
919						//qty = $('form.cart .quantity .qty').val();
920						// 3.27.0
921						qty = pewc_get_quantity( qty, 'linked' );
922						selected_counter++;
923					} else if( quantities == 'independent' ) {
924						qty = $(this).closest('.pewc-checkbox-wrapper').find('.pewc-child-quantity-field').val();
925						selected_counter += parseInt( qty );
926						if ( pewc_vars.multiply_independent == 'yes' /*&& $('form.cart .quantity .qty').val() !== undefined*/ ) {
927							// 3.27.0
928							var main_quantity = pewc_get_quantity();
929							qty = qty * parseFloat( main_quantity );
930						}
931					} else if( quantities == 'one-only' ) {
932						qty = pewc_get_quantity( 1, 'one-only' );
933						selected_counter++;
934					}
935
936					if( child_product_price > 0 ) {
937						child_products_total += parseFloat( child_product_price ) * parseFloat( qty );
938						this_child_total += parseFloat( child_product_price ) * parseFloat( qty );
939					}
940
941				});
942
943				if( field_value.length > 0 ) {
944					$( this ).closest( '.pewc-item' ).attr( 'data-field-price', child_products_total );
945					set_summary_panel_data( $( this ).closest( '.pewc-item' ), field_value.join( ', ' ), this_child_total );
946				}
947
948			}
949
950			pewc_update_checkbox_field_counter( $( this ).closest( '.pewc-item' ), selected_counter );
951
952		});
953
954		// reset products column first
955		$('form.cart .pewc-item-products-column').each(function(){
956			$(this).removeClass('pewc-active-field');
957			$(this).attr('data-field-price', 0);
958			$(this).attr('data-field-value', '');
959			pewc_update_checkbox_field_counter( $(this), 0 );
960		});
961		$('form.cart .pewc-column-wrapper .pewc-variable-child-product-wrapper.checked').each(function() {
962			var field_value = [];
963			var field_wrapper = $( this ).closest( '.pewc-item' );
964			var parent_field_value = field_wrapper.attr('data-field-value');
965			if ( parent_field_value != 0 && parent_field_value != '') {
966				field_value = parent_field_value.split(', ');
967			}
968			var parent_field_price = parseFloat( field_wrapper.attr('data-field-price') );
969			var selected_counter = parseInt ( field_wrapper.attr( 'data-field-selected-counter' ) );
970			var is_hidden = field_wrapper.hasClass( 'pewc-hidden-field' );
971			var is_dependent = ( field_wrapper.hasClass( 'pewc-variation-dependent' ) ) && ( ! field_wrapper.hasClass( 'active' ) );
972
973			if( ! is_hidden && ! is_dependent ) {
974				var quantities = $(this).closest( '.pewc-column-wrapper' ).data('products-quantities');
975				// Run through each selected checkbox for variable child products
976
977				field_wrapper.removeClass( 'pewc-active-field' );
978
979				$(this).find('.pewc-variable-child-select').each(function() {
980					field_value.push( $( this ).find('option:selected').text() );
981					var child_product_price = $(this).find(':selected').data('option-cost');
982					// 3.21.4, compatibility with FD
983					if ( parseFloat( $(this).find(':selected').attr('data-wcfad-price') ) > 0 ) {
984						child_product_price = parseFloat( $(this).find(':selected').attr('data-wcfad-price') );
985					}
986					var qty = 0;
987
988					// Get the quantity
989					if( quantities == 'linked' ) {
990						//qty = $('form.cart .quantity .qty').val();
991						// 3.27.0
992						qty = pewc_get_quantity( qty, 'linked' );
993						selected_counter++;
994					} else if( quantities == 'independent' ) {
995						qty = $(this).closest('.pewc-checkbox-image-wrapper').find('.pewc-child-quantity-field').val();
996						selected_counter += parseInt( qty );
997						if ( pewc_vars.multiply_independent == 'yes' /*&& $('form.cart .quantity .qty').val() !== undefined*/ ) {
998							// 3.27.0
999							var main_quantity = pewc_get_quantity();
1000							qty = qty * parseFloat( main_quantity );
1001						}
1002					} else if( quantities == 'one-only' ) {
1003						qty = pewc_get_quantity( 1, 'one-only' );
1004						selected_counter++;
1005					}
1006
1007					if( child_product_price > 0 ) {
1008						child_products_total += parseFloat( child_product_price ) * parseFloat( qty );
1009						parent_field_price += parseFloat( child_product_price ) * parseFloat( qty );
1010					}
1011
1012					if( field_value.length > 0 ) {
1013						field_wrapper.attr( 'data-field-price', parent_field_price );
1014						set_summary_panel_data( field_wrapper, field_value.join( ', ' ), parent_field_price );
1015					}
1016
1017				});
1018
1019				// aou-products-column-new, for column layout with attributes select
1020				if ( $( this ).find( '.pewc-column-attributes-select' ).length > 0 ) {
1021					var child_id = $( this ).data( 'option-id' );
1022					var child_variant = $( this ).find( 'input[name="pewc_child_variants_' + child_id + '"]' );
1023					field_value.push( child_variant.attr( 'data-variation-name' ) );
1024					var child_product_price = child_variant.attr( 'data-option-cost' );
1025					// no
1025t yet supported, maybe add later
1026					//if ( parseFloat( $(this).find(':selected').attr('data-wcfad-price') ) > 0 ) {
1027					//	child_product_price = parseFloat( $(this).find(':selected').attr('data-wcfad-price') );
1028					//}
1029					var qty = 0;
1030
1031					// Get the quantity
1032					if( quantities == 'linked' ) {
1033						qty = pewc_get_quantity( qty, 'linked' );
1034						selected_counter++;
1035					} else if( quantities == 'independent' ) {
1036						qty = $(this).find( '.pewc-child-quantity-field' ).val();
1037						selected_counter += parseInt( qty );
1038						if ( pewc_vars.multiply_independent == 'yes' ) {
1039							var main_quantity = pewc_get_quantity();
1040							qty = qty * parseFloat( main_quantity );
1041						}
1042					} else if( quantities == 'one-only' ) {
1043						qty = pewc_get_quantity( 1, 'one-only' );
1044						selected_counter++;
1045					}
1046
1047					if( child_product_price > 0 ) {
1048						child_products_total += parseFloat( child_product_price ) * parseFloat( qty );
1049						parent_field_price += parseFloat( child_product_price ) * parseFloat( qty );
1050					}
1051
1052					if( field_value.length > 0 ) {
1053						field_wrapper.attr( 'data-field-price', parent_field_price );
1054						set_summary_panel_data( field_wrapper, field_value.join( ', ' ), parent_field_price );
1055					}
1056				}
1057
1058			}
1059
1060			pewc_update_checkbox_field_counter( field_wrapper, selected_counter );
1061
1062		});
1063		$('form.cart .pewc-column-wrapper .pewc-simple-child-product-wrapper.checked').each(function() {
1064			var field_value = [];
1065			var field_wrapper = $( this ).closest( '.pewc-item' );
1066			var parent_field_value = field_wrapper.attr('data-field-value');
1067			if ( parent_field_value != 0 && parent_field_value != '') {
1068				field_value = parent_field_value.split(', ');
1069			}
1070			var parent_field_price = parseFloat( field_wrapper.attr('data-field-price') );
1071			var selected_counter = parseInt ( field_wrapper.attr( 'data-field-selected-counter' ) );
1072			var is_hidden = field_wrapper.hasClass( 'pewc-hidden-field' );
1073			var is_dependent = ( field_wrapper.hasClass( 'pewc-variation-dependent' ) ) && ( ! field_wrapper.hasClass( 'active' ) );
1074
1075			if( ! is_hidden && ! is_dependent ) {
1076				var quantities = $(this).closest( '.pewc-column-wrapper' ).data('products-quantities');
1077
1078				field_wrapper.removeClass( 'pewc-active-field' );
1079
1080				// Run through each selected checkbox
1081				$(this).find('.pewc-checkbox-form-field').each(function(){
1082					field_value.push( $( this ).attr( 'data-field-label' ) );
1083					var child_product_price = $(this).data('option-cost');
1084					// 3.21.4, compatibility with FD
1085					if ( parseFloat( $(this).attr('data-wcfad-price') ) > 0 ) {
1086						child_product_price = parseFloat( $(this).attr('data-wcfad-price') );
1087					}
1088					var qty = 0;
1089
1090					// Get the quantity
1091					if( quantities == 'linked' ) {
1092						//qty = $('form.cart .quantity .qty').val();
1093						// 3.27.0
1094						qty = pewc_get_quantity( qty, 'linked' );
1095						selected_counter++;
1096					} else if( quantities == 'independent' ) {
1097						qty = $(this).closest('.pewc-simple-child-product-wrapper').find('.pewc-child-quantity-field').val();
1098						selected_counter += parseInt( qty );
1099						if ( pewc_vars.multiply_independent == 'yes' /*&& $('form.cart .quantity .qty').val() !== undefined*/ ) {
1100							// 3.27.0
1101							var main_quantity = pewc_get_quantity();
1102							qty = qty * parseFloat( main_quantity );
1103						}
1104					} else if( quantities == 'one-only' ) {
1105						qty = pewc_get_quantity( 1, 'one-only' );
1106						selected_counter++;
1107					}
1108
1109					if( child_product_price > 0 ) {
1110						child_products_total += parseFloat( child_product_price ) * parseFloat( qty );
1111						parent_field_price += parseFloat( child_product_price ) * parseFloat( qty );
1112					}
1113
1114					if( field_value.length > 0 ) {
1115						field_wrapper.attr( 'data-field-price', parent_field_price );
1116						set_summary_panel_data( field_wrapper, field_value.join( ', ' ), parent_field_price );
1117					}
1118
1119				});
1120
1121			}
1122
1123			pewc_update_checkbox_field_counter( field_wrapper, selected_counter );
1124
1125		});
1126
1127		// reset products swatches first
1128		$('form.cart .pewc-item-products-swatches').each(function(){
1129			$(this).removeClass('pewc-active-field');
1130			$(this).attr('data-field-price', 0);
1131			$(this).attr('data-field-value', '');
1132		});
1133		$('form.cart .pewc-swatches-wrapper .pewc-child-variation-main').each(function() {
1134			var field_value = [];
1135			var parent_field_value = $( this ).closest( '.pewc-item' ).attr('data-field-value');
1136			if ( parent_field_value != 0 && parent_field_value != '') {
1137				field_value = parent_field_value.split(', ');
1138			}
1139			var parent_field_price = parseFloat( $( this ).closest( '.pewc-item' ).attr('data-field-price') );
1140			var is_hidden = $( this ).closest( '.pewc-item' ).hasClass( 'pewc-hidden-field' );
1141			var is_dependent = ( $( this ).closest( '.pewc-item' ).hasClass( 'pewc-variation-dependent' ) ) && ( ! $( this ).closest( '.pewc-item' ).hasClass( 'active' ) );
1142			if( ! is_hidden && ! is_dependent ) {
1143
1144				var quantities = $(this).closest( '.pewc-swatches-wrapper' ).data('products-quantities');
1145
1146				// Run through each selected variation product
1147				$(this).find('.pewc-child-name input').each(function() {
1148					var child_product_price = parseFloat( $(this).attr( 'data-option-cost' ) );
1149					// 3.21.4, compatibility with FD
1150					if ( parseFloat( $(this).attr('data-wcfad-price') ) > 0 ) {
1151						child_product_price = parseFloat( $(this).attr('data-wcfad-price') );
1152					}
1153					var qty = 0;
1154					if( child_product_price > 0 && $(this).is( ':checked' ) ) {
1155						// Get the quantity
1156						// 3.21.4, added is :checked, only consider selected child product
1157						if( quantities == 'linked' ) {
1158							//qty = $('form.cart .quantity .qty').val();
1159							// 3.27.0
1160							qty = pewc_get_quantity( qty, 'linked' );
1161						} else if( quantities == 'independent' ) {
1162							qty = $(this).closest('.pewc-child-variation-main').find('.pewc-child-quantity-field').val();
1163							if ( pewc_vars.multiply_independent == 'yes' /*&& $('form.cart .quantity .qty').val() !== undefined*/ ) {
1164								// 3.27.0
1165								var main_quantity = pewc_get_quantity();
1166								qty = qty * parseFloat( main_quantity );
1167							}
1168						} else if( quantities == 'one-only' ) {
1169							qty = pewc_get_quantity( 1, 'one-only' );
1170						}
1171					}
1172					if ( qty < 1 ) {
1173						return; // quantity is zero, so ignore this field
1174					}
1175					field_value.push( $( this ).attr( 'data-field-label' ) );
1176					child_products_total += parseFloat( child_product_price ) * parseFloat( qty );
1177					parent_field_price += parseFloat( child_product_price ) * parseFloat( qty );
1178
1179					if( field_value.length > 0 ) {
1180						$( this ).closest( '.pewc-item' ).attr( 'data-field-price', parent_field_price );
1181						set_summary_panel_data( $( this ).closest( '.pewc-item' ), field_value.join( ', ' ), parent_field_price );
1182					}
1183				});
1184
1185			}
1186
1187		});
1188		$('form.cart .grid-layout').each( function() {
1189
1190			var is_hidden = $( this ).closest( '.pewc-item' ).hasClass( 'pewc-hidden-field' );
1191			var is_hidden_group = $( this ).closest( '.pewc-group-wrap' ).hasClass( 'pewc-group-hidden' );
1192			var is_dependent = ( $( this ).closest( '.pewc-item' ).hasClass( 'pewc-variation-dependent' ) ) && ( ! $( this ).closest( '.pewc-item' ).hasClass( 'active' ) );
1193			if( ! is_hidden && ! is_hidden_group && ! is_dependent ) {
1194				var child_product_price = parseFloat( $( this ).closest( '.pewc-item' ).attr( 'data-
1194price' ) );
1195				child_products_total += parseFloat( child_product_price );
1196			}
1197
1198		});
1199
1200		if( product_price < 0 ) product_price = 0;
1201
1202		// Summary panel rows
1203
1204		// Summary panel for add-on groups
1205		$( '.pewc-summary-panel-group-row' ).addClass( 'pewc-summary-panel-field-row-inactive' );
1206
1207		$( '.pewc-group-wrap' ).not( '.pewc-group-hidden' ).each( function() {
1208			var group_id = $( this ).attr( 'data-group-id' );
1209			$( '.pewc-summary-panel-group-'+group_id ).removeClass( 'pewc-summary-panel-field-row-inactive' );
1210		});
1211
1212		// Summary panel for add-on fields
1213		$( '.pewc-summary-panel-field-row' ).addClass( 'pewc-summary-panel-field-row-inactive' );
1214
1215		// 3.26.14, added .pewc-hidden-calculation to the not() selector so that hidden Calculation fields are not displayed on the Summary panel
1216		$( '.pewc-active-field' ).not( '.pewc-hidden-field, .pewc-hidden-calculation' ).each( function() {
1217			var field_id = $( this ).attr( 'data-field-id' );
1218			var field_type = $( '.pewc-field-' + field_id ).attr( 'data-field-type' );
1219			$( '#pewc-summary-row-' + field_id ).removeClass( 'pewc-summary-panel-field-row-inactive' ).addClass( 'pewc-field-' + field_type );
1220			var field_price = parseFloat( $( this ).attr( 'data-field-price' ) );
1221			if( field_price ) {
1222				field_price = field_price.toFixed( pewc_vars.decimals );
1223			}
1224
1225			var field_label = $( this ).attr( 'data-field-label' );
1226			var field_value;
1227			if( $( this ).attr( 'data-field-type') != 'checkbox' ) {
1228				field_value = $( this ).attr( 'data-field-value' );
1229			}
1230			$( '#pewc-summary-row-' + field_id ).find( '.pewc-summary-panel-product-name' ).text( field_label );
1231			$( '#pewc-summary-row-' + field_id ).find( '.pewc-summary-panel-product-value' ).text( field_value );
1232			$( '#pewc-summary-row-' + field_id ).find( '.pewc-summary-panel-price' ).html( pewc_wc_price( field_price ) );
1233		});
1234
1235		var qty = 1;
1236		// 3.27.0, we use 'linked' so that add-ons are multiplied per day and per num_bookings (quantity)?
1237		qty = pewc_get_quantity( qty, 'linked' );
1238
1239		// See if we need to apply a discount to the add-ons care of Dynamic Pricing and Discount Rules
1240		// Updated on 3.21.4
1241		orig_total_price = total_price; // 3.21.7, for DPDR
1242		if ( pewc_wcfad_apply_discount() ) {
1243			total_price = pewc_wcfad.adjust_price( total_price );
1244			if ( repeatable_prices > 0 ) {
1245				repeatable_prices = pewc_wcfad.adjust_price( repeatable_prices ); // 3.26.7
1246			}
1247		}
1248
1249		// Summary panel subtotal (3.9.8)
1250		var subtotal = parseFloat( child_products_total ) + parseFloat( total_price ) + parseFloat( qty * product_price );
1251		if( ! isNaN( subtotal ) ) {
1252			$( '#pewc-summary-panel-subtotal' ).html( pewc_wc_price( subtotal.toFixed(pewc_vars.decimals) ) );
1253		}
1254
1255		var total_grid_variations = $( '#pewc-grid-total-variations' ).val();
1256
1257		// 3.27.0, for Booking products, product_price already includes "qty" (num_units), no need to multiply again
1258		// 4.1.1, also skip for variable products using Better Variations grid mode
1259		if ( ! pewc_is_booking_product() && ! pewc_wcbvp_variation_grid() ) {
1260			var product_price = qty * product_price;
1261		}
1262
1263		var grand_total = product_price;
1264		var orig_grand_total = qty * orig_product_price; // 3.21.7, for DPDR
1265		base_price = product_price;
1266		product_price = product_price.toFixed(pewc_vars.decimals);
1267		product_price = pewc_wc_price( product_price );
1268		product_price = add_price_suffix( product_price, base_price );
1269		$('#pewc-per-product-total').html( product_price );
1270
1271		total_price = qty * total_price;
1272		orig_total_price = qty * orig_total_price; // 3.21.7, for DPDR
1273
1274		// 3.26.7, we have a separate variable for repeatable field prices in case we dont want them multiplied with quantity
1275		if ( repeatable_prices > 0 ) {
1276			total_price += repeatable_prices;
1277			orig_total_price += repeatable_prices;
1278		}
1279
1280		// Multiply add-ons by number of variations in bulk grid
1281		// 2.7.1, added > 0 to the condition so that option total doesn't become 0 if no variations are selected
1282		if( total_grid_variations > 0 ) {
1283			total_price = total_grid_variations * total_price;
1284		}
1285		total_price += child_products_total;
1286		grand_total += total_price;
1287		orig_grand_total += orig_total_price; // 3.21.7, for DPDR
1288
1289		if( ! isNaN( total_price ) ) {
1290			var base_total_price = total_price;
1291			total_price = total_price.toFixed(pewc_vars.decimals);
1292			total_price = pewc_wc_price( total_price );
1293			total_price = add_price_suffix( total_price, base_total_price );
1294			$('#pewc-options-total').html( total_price );
1295		}
1296
1297		if( flat_rate_total < 0 ) flat_rate_total = 0;
1298		base_flat_rate_total = flat_rate_total;
1299		grand_total += flat_rate_total;
1300		flat_rate_total = flat_rate_total.toFixed(pewc_vars.decimals);
1301		flat_rate_total = pewc_wc_price( flat_rate_total );
1302		flat_rate_total = add_price_suffix( flat_rate_total, base_flat_rate_total );
1303		$('#pewc-flat-rate-total').html( flat_rate_total );
1304
1305		// Set the product price using a calculation field
1306		// 3.13.3 added 2nd condition to apply only calculated price if at least 1 calculation field is not hidden
1307		if( ( $( '#pewc_calc_set_price').attr( 'data-calc-set' ) == 1 || $('input[name="pewc_calc_set_price"]').length > 1 ) && $( '.pewc-product-extra-groups-wrap .pewc-item-calculation' ).not( '.pewc-hidden-field' ).length > 0 ) {
1308			if ( $('input[name="pewc_calc_set_price"]').length > 1 ) {
1309				// 3.17.2, compatibility with Product Table Ultimate
1310				// find the first non-hidden total
1311				var new_grand_total = 0;
1312				$('input[name="pewc_calc_set_price"]').each(function(){
1313					if ( $(this).attr( 'data-calc-set' ) == 1 && $(this).closest( '.pewc-product-extra-groups-wrap' ).is( ':visible' ) ) {
1314						new_grand_total = parseFloat( $(this).closest( '.pewc-product-extra-groups-wrap' ).find('input[name="pewc_calc_set_price"][data-calc-set="1"]').val() );
1315					}
1316				});
1317				if ( new_grand_total > 0 ) {
1318					grand_total = new_grand_total;
1319				}
1320			} else {
1321				// single product page
1322				grand_total = parseFloat( $( '#pewc_calc_set_price').val() );
1323			}
1324
1325			// 4.3.2. In DPDR if a product has a regular price, a strikethrough is added to it if the final calculated price is less than the regular price
1326			// we copy it here before the possible DPDR discount below
1327			orig_grand_total = grand_total;
1328
1329			if ( $('form.cart .quantity .qty').length > 0 ) {
1330
1331				// 3.12.0, apply dynamic pricing if it exists
1332				if ( pewc_wcfad_apply_discount() ) {
1333					grand_total = pewc_wcfad.adjust_price( grand_total );
1334				}
1335
1336				// 3.11.6 multiply product price by quantity
1337				grand_total = grand_total * parseFloat( $('form.cart .quantity .qty').val() );
1338				// 4.3.2, for DPDR
1339				orig_grand_total = orig_grand_total * parseFloat( $('form.cart .quantity .qty').val() );
1340
1341			}
1342		}
1343
1344		if( ! isNaN( grand_total ) ) {
1345			if ( isNaN( orig_grand_total ) || orig_grand_total == grand_total ) {
1346				orig_grand_total = ''; // 3.21.7, let's clear this so that we know we don't need it
1347			}
1348			var base_price = grand_total;
1349			grand_total = grand_total.toFixed( pewc_vars.decimals );
1350			grand_total = pewc_wc_price( grand_total );
1351			if( pewc_vars.update_price == 'yes' ) {
1352				update_product_price( grand_total, base_price, orig_grand_total );
1353			}
1354			grand_total = add_price_suffix( grand_total, base_price );
1355			$('#pewc-grand-total').html( grand_total );
1356			if ( $( '#pewc-grand-total_clone' ).length > 0 ) {
1357				// 3.26.11, also update the grand total inside the lightbox
1358				$( '#pewc-grand-total_clone' ).html( grand_total );
1359			}
1360		}
1361
1362		// Re-run this because some browsers are too quick
1363		// This won't run if we're using the optimised condition option
1364		if( $update == 0 && pewc_vars.conditions_timer < 1 ) {
1365			var interval = setTimeout( function() {
1366				pewc_update_total_js( 1 );
1367				if( ! total_updated ) {
1368					// Check any calculations before input fields are updated
1369					$( 'body' ).trigger( 'pewc_trigger_calculations' );
1370					total_updated = true;
1371				}
1372			},
1373			250 );
1374		}
1375
1376		// 3.15.0, let other plugins hook into this
1377		$( 'body' ).trigger( 'pewc_after_update_total_js', [ base_total_price, base_price, grand_total ] );
1378	}
1379
1380	/*
1381	 * Counts selected checkboxes, swatches, or products
1382	 */
1383	function pewc_update_checkbox_field_counter( field_wrapper, counter ) {
1384
1385		var current_count = field_wrapper.attr( 'data-field-selected-counter' );
1386
1387		// hopefully this prevents this process from being run multiple times
1388		if ( current_count != counter ) {
1389			field_wrapper.attr( 'data-field-selected-counter', counter );
1390			// Optimised validation will hook into the trigger below
1391			$( 'body' ).trigger( 'pewc_field_selected_counter_updated', [ field_wrapper, counter ] );
1392		}
1393	}
1394
1395	function add_price_suffix( price, base_price ) {
1396		if( pewc_vars.show_suffix == 'yes' ) {
1397			var price_suffix_setting = pewc_vars.price_suffix_setting;
1398			if( price_suffix_setting.indexOf( '{price_excluding_tax}' ) > -1 ) {
1399				var price_ex_tax = base_price * ( pewc_vars.percent_exc_tax / 100 );
1400				suffix = price_suffix_setting.replace( '{price_excluding_tax}', pewc_wc_price( price_ex_tax.toFixed( pewc_vars.decimals ), false, false ) );
1401			} else if( price_suffix_setting.indexOf( '{price_including_tax}' ) > -1 ) {
1402				var price_inc_tax = base_price * ( pewc_vars.percent_inc_tax / 100 );
1403				suffix = price_suffix_setting.replace( '{price_including_tax}', pewc_wc_price( price_inc_tax.toFixed( pewc_vars.decimals ), false, false ) );
1404			} else {
1405				suffix = pewc_vars.price_suffix;
1406			}
1407			price = price + ' <small class="woocommerce-price-suffix">' + suffix + '</small>';
1408		}
1409		return price;
1410	}
1411
1412	function update_product_price( grand_total, base_price, orig_grand_total ) {
1413		var price_suffix_setting = pewc_vars.price_suffix_setting;
1414		// We can rebuild him
1415		// 3.27.5, Related Products could also have pewc-main-price, so we assume the first one to be the correct main one
1416		// This fixes an issue where if a Related Product has a hidden price, that it affects all prices on the product page
1417		// Let's also exclude main price from QuickView here instead of later in the function
1418		var main_price = $( '.pewc-main-price' ).not( '.pewc-quickview-product-wrapper .pewc-main-price' );
1419		if ( main_price.length > 1 ) {
1420			// get only the first?
1421			main_price.each(function( index, element){
1422				// add a special class to the first main price, we assume that's the real main price
1423				if ( index < 1 ) {
1424					$( this ).addClass( 'pewc-main-main-price' );
1425					return false;
1426				};
1427			});
1428			main_price = $( '.pewc-main-price.pewc-main-main-price' );
1429		}
1430		var suffix = main_price.find( '.woocommerce-price-suffix' ).html();
1431		var label = main_price.find( '.wcfad-rule-label' ).html();
1432		var before = main_price.find( '.pewc-label-before' ).html();
1433		var after = main_price.find( '.pewc-label-after' ).html();
1434		var hide = main_price.find( '.pewc-label-hidden' );
1435		var new_total = '';
1436
1437		if( hide.length > 0 ) {
1438			new_total = '<span class="pewc-label-hidden">' + hide.html() + '</span>';
1439		} else {
1440			if( before ) {
1441				new_total += '<span class="pewc-label-before">' + before + ' </span>';
1442			}
1443
1444			// 3.21.7
1445			if ( orig_grand_total != '' && pewc_vars.disable_wcfad_label != 'yes' ) {
1446				orig_grand_total.toFixed( pewc_vars.decimals );
1447				orig_grand_total = pewc_wc_price( orig_grand_total );
1448				new_total += ' <s>' + orig_grand_total + '</s> ';
1449			}
1450
1451			new_total += grand_total;
1452
1453			if( after ) {
1454				new_total += '<span class="pewc-label-after"> ' + after + '</span>';
1455			}
1456			if( suffix ) {
1457				if( price_suffix_setting.indexOf( '{price_excluding_tax}' ) > -1 ) {
1458					var price_ex_tax = base_price * ( pewc_vars.percent_exc_tax / 100 );
1459					suffix = price_suffix_setting.replace( '{price_excluding_tax}', pewc_wc_price( price_ex_tax.toFixed( pewc_vars.decimals ), false, false ) );
1460				} else if( price_suffix_setting.indexOf( '{price_including_tax}' ) > -1 ) {
1461					var price_inc_tax = base_price * ( pewc_vars.percent_inc_tax / 100 );
1462					suffix = price_suffix_setting.replace( '{price_including_tax}', pewc_wc_price( price_inc_tax.toFixed( pewc_vars.decimals ), false, false ) );
1463				}
1464				if( label && suffix.indexOf( 'wcfad-rule-label' ) < 0 ) {
1465					suffix += '<br><span class="wcfad-rule-label">' + label + '</span>';
1466				}
1467				new_total += '&nbsp;<small class="woocommerce-price-suffix">' + suffix + '</small>';
1468			}
1469		}
1470
1471		// 3.22.1, retain DPDR label even if Update pricing label is enabled
1472		//var main_price = $( '.pewc-main-price').not( '.pewc-quickview-product-wrapper .pewc-main-price' ); // 3.27.5, commented out, maybe no longer needed?
1473		if ( main_price.find( '.wcfad-rule-label' ).length > 0 && new_total.indexOf( 'wcfad-rule-label' ) == -1 ) {
1474			// this has a DPDR discount label, add it to the new_total
1475			var dpdr_label = main_price.find( '.wcfad-rule-label' );
1476			new_total += '<br>' + dpdr_label[0].outerHTML;
1477		}
1478		main_price.html( new_total );
1479	}
1480
1481	function set_summary_panel_data( field, value, added_price ) {
1482		$( field ).attr( 'data-field-value', value );
1483		$( field ).attr( 'data-field-price', added_price );
1484		$( field ).addClass( 'pewc-active-field' );
1485	}
1486
1487	// old position of pewc_wc_price_without_currency and pewc_wc_price, moved outside of this container since 3.21.4
1488
1489	function format_separator( num ) {
1490	  return num.toString().replace( /(\d)(?=(\d{3})+(?!\d))/g, '$1,' );
1491	}
1492	// var interval = setInterval(function(){
1493	// 	pewc_update_total_js();
1494	// },
1495	// 500);
1496
1497	// 3.24.7, add a trigger event so that other plugins like PTU can re-trigger the form.cart input changes
1498	$( 'body' ).on( 'pewc_attach_form_cart_input_change', function() {
1499		$( 'form.cart' ).on('keyup input change paste', 'input:not(.pewc-grid-quantity-field), select, textarea.pewc-has-field-price', function(){
1500			// Debounced: batches rapid keyup/input events and redundant change events.
1501			pewc_update_total_js_debounced();
1502			$( 'body' ).trigger( 'pewc_updated_total_js' );
1503		});
1504	});
1505	$( 'body' ).trigger( 'pewc_attach_form_cart_input_change' );
1506
1507	var interval = setTimeout( function() {
1508		pewc_update_total_js();
1509		if ( 'yes' == pewc_vars.enable_character_counter ) {
1510			pewc_update_text_field_counters();
1511		}
1512	},
1513	250 );
1514	$( 'body' ).on( 'pewc_add_button_clicked', function() {
1515		pewc_update_total_js();
1516	});
1517	$( 'body' ).on( 'pewc_force_update_total_js', function() {
1518		// Debounced: this event fires multiple times per user action from conditions.js.
1519		pewc_update_total_js_debounced();
1520	});
1521
1522	// Accordion and tabs
1523	// 4.3.3, created a function for the click so that repeatable groups can use it. Moved the function out of the container
1524	$( '.pewc-groups-accordion h3' ).on( 'click', function( e ){
1525		pewc_accordion_click( $( this ) );
1526	});
1527
1528	if( pewc_vars.accordion_toggle == 'open' ) {
1529		$('.pewc-group-wrap').addClass('group-active');
1530	} else if( pewc_vars.accordion_toggle == 'closed' ) {
1531		$('.pewc-group-wrap').removeClass('group-active');
1532	} else {
1533		$('.first-group').addClass('group-active');
1534	}
1535
1536	$('.pewc-tab').on('click',function(e) {
1537		// 3.13.7
1538		if ( $(this).hasClass( 'pewc-disabled-group') ) {
1539			return;
1540		}
1541
1542		e.preventDefault();
1543		var tab_id = $(this).attr('data-group-id');
1544		$('.pewc-tab').removeClass('active-tab tab-failed');
1545		$( '.pewc-group-js-validation-notice' ).hide();
1546		$(this).addClass('active-tab');
1547		$('.pewc-group-wrap').removeClass('group-active');
1548		$('.pewc-group-wrap-'+tab_id).addClass('group-active');
1549	});
1550	$('.pewc-next-step-button').on('click',function(e) {
1551		e.preventDefault();
1552		// 3.13.7
1553		if ( $(this).hasClass( 'pewc-disabled-group') ) {
1554			return;
1555		}
1556
1557		var tab_id = $( this ).attr( 'data-group-id' );
1558		var tab_index = $( this ).closest( '.pewc-group-wrap' ).attr( 'data-group-index' );
1559		var direction = $( this ).attr( 'data-direction' );
1560		$( '.pewc-tab' ).removeClass( 'active-tab tab-failed' );
1561		$( '.pewc-group-js-validation-notice' ).hide();
1562		// Check if the next group is visible
1563		if( $( '.pewc-group-wrap-' + tab_id ).hasClass( 'pewc-group-hidden' ) ) {
1564			// Count the total tabs
1565			var total_tabs = $( '.pewc-group-wrap' ).length;
1566			if( direction == 'next' ) {
1567				// Find the next group ID
1568				for( var i = parseInt( tab_index ) + 1; i < total_tabs; i++ ) {
1569					if( ! $( '.pewc-group-index-' + i ).hasClass( 'pewc-group-hidden' ) ) {
1570						tab_id = $( '.pewc-group-index-' + i ).attr( 'data-group-id' );
1571						break;
1572					}
1573				}
1574			} else {
1575				// Find the previous group ID
1576				for( var i = parseInt( tab_index ) - 1; i >= 0; i-- ) {
1577					if( ! $( '.pewc-group-index-' + i ).hasClass( 'pewc-group-hidden' ) ) {
1578						tab_id = $( '.pewc-group-index-' + i ).attr( 'data-group-id' );
1579						break;
1580					}
1581				}
1582			}
1583		}
1584		$( '#pewc-tab-' + tab_id ).addClass( 'active-tab' );
1585		$( '.pewc-group-wrap' ).removeClass( 'group-active' );
1586		$( '.pewc-group-wrap-' + tab_id ).addClass( 'group-active' );
1587
1588		// Scroll to top
1589		if ( pewc_vars.steps_group_disable_scroll_to_top != 'yes' ) {
1590			if( $( '.pewc-steps-wrapper' ).length > 0 ) {
1591				$([document.documentElement, document.body]).animate({
1592					scrollTop: $( '.pewc-steps-wrapper' ).offset().top
1593	    		}, 150);
1594			}
1595		}
1596	});
1597
1598	function pewc_get_text_str_len( str, wrapper ) {
1599		var new_str, str_ex_spaces ;
1600		var field = $(wrapper).find('.pewc-form-field');
1601		// Don't include spaces
1602		if( pewc_vars.remove_spaces != 'yes' ) {
1603			str_ex_spaces = str.replace(/\s/g, "");
1604		} else {
1605			str_ex_spaces = str;
1606		}
1607
1608		var str_len = str_ex_spaces.length;
1609		// Exclude alphanumerics if selected
1610		if( $(field).attr('data-alphanumeric') == 1 ) {
1611			str_ex_spaces = str_ex_spaces.replace(/\W/g, '');
1612			$(field).val(str_ex_spaces);
1613			str_len = str_ex_spaces.length;
1614		}
1615		// Allow alphanumerics but don't charge if selected
1616		if( $(field).attr('data-alphanumeric-charge') == 1 ) {
1617			str_ex_spaces = str_ex_spaces.replace(/\W/g, '');
1618			// $(field).val(str_ex_spaces);
1619			str_len = str_ex_spaces.length;
1620		}
1621		// If free characters are allowed
1622		var freechars = $(field).attr('data-freechars');
1623		str_len -= freechars;
1624		str_len = Math.max(0,str_len);
1625		return str_len;
1626	}
1627
1628	function pewc_disable_child_product_quantities() {
1629		$( '.woocommerce-cart-form__cart-item.pewc-child-product' ).each( function() {
1630			if( pewc_vars.disable_qty || pewc_vars.multiply_independent == 'yes' ) {
1631				$(this).find('.product-quantity input').attr('disabled',true);
1632			}
1633		});
1634	}
1635
1636	// Disable quantity fields in Barn2 Fast Cart
1637	$('body').on('click', 'a.wfc-open-cart-button', function( e ) {
1638		var timeout = setTimeout(
1639			function() {
1640				$( '.wfc-cart-form__cart-item.pewc-child-product' ).each( function() {
1641					if( pewc_vars.disable_qty || pewc_vars.multiply_independent == 'yes' ) {
1642						$(this).find('.product-quantity input').attr('disabled',true);
1643					}
1644				});
1645			},
1646			250
1647		);
1648	} );
1649
1650	// only do this if there are actually child products
1651	if ( $('.woocommerce-cart-form__cart-item.pewc-child-product').length > 0 ) {
1652		// call function on page load
1653		pewc_disable_child_product_quantities();
1654		// when cart is updated, disable quantities again
1655		$('body').on('updated_cart_totals', pewc_disable_child_product_quantities);
1656	}
1657
1658	// If child product is selected, manage allowable purchase quantity
1659	// Applies to radio and select
1660	$('body').on('change','.products-quantities-independent .pewc-child-select-field',function(){
1661		var number_field = $(this).closest('.child-product-wrapper').find('.pewc-child-quantity-field');
1662		if ( $( this ).val() != '') {
1663			// select field is not blank, update quantity
1664			if( $(number_field).val() == 0 ) {
1665				// Automatically enter a quantity when a product is selected
1666				$(number_field).val(1);
1667			};
1668		} else {
1669			// reset number field
1670			$( number_field ).val(0);
1671		}
1672		//var available_stock = $(this).find(':selected').data('stock');
1673		//if( available_stock ) {
1674		//	var number = $(number_field).attr('max',available_stock);
1675		//	if( $(number).val() > available_stock ) {
1676		//		$(number_field).val(available_stock);
1677		//	}
1678		//} else {
1679		//	$(number_field).removeAttr('max');
1680		//}
1681		// 3.27.3
1682		pewc_update_independent_quantity_input_max( $( this ), number_field );
1683	});
1684
1685	// 3.27.3, created a separate function so that we can call this on page load
1686	function pewc_update_independent_quantity_input_max( select_field, number_field) {
1687
1688		var available_stock = $( select_field ).find( ':selected' ).data( 'stock' );
1689		if( available_stock ) {
1690			var number = $( number_field ).attr( 'max', available_stock );
1691			if( $( number ).val() > available_stock ) {
1692				$( number_field ).val( available_stock );
1693			}
1694		} else {
1695			$( number_field ).removeAttr( 'max' );
1696		}
1697
1698	}
1699
1700	$('body').on('change input keyup paste click','.products-quantities-independent .pewc-child-quantity-field',function( e ) {
1701		e.stopPropagation(); // this prevents the click event from bubbling up to the event attached to the layer
1702		if ( $( this ).closest( '.pewc-item' ).hasClass( 'pewc-item-products-select' ) ) {
1703			// this is a Products select field
1704			var selIndex = 0;
1705			if( $(this).val() > 0 ) {
1706				var selField = $( this ).closest( '.pewc-item' ).find( 'select.pewc-child-select-field' );
1707				// find first select option with value if not already selected
1708				selIndex = selField.prop( 'selectedIndex' );
1709				if ( selIndex < 1 && selField.val() == '' ) {
1710					$( this ).closest( '.pewc-item' ).find( 'select.pewc-child-select-field option' ).each( function( index, element ) {
1711						if ( $(this).val() != '' && selIndex < 1 ) {
1712							selIndex = index;
1713							return;
1714						}
1715					});
1716				}
1717			}
1718			$( this ).closest( '.pewc-item' ).find( 'select.pewc-child-select-field' ).prop( 'selectedIndex', selIndex );
1719		} else {
1720			// Ensure this child product is selected
1721			// for checkbox images
1722			if( $(this).val() > 0 ) {
1723				var checkbox = $(this).closest('.pewc-checkbox-wrapper').find('input[type=checkbox]').prop('checked',true).trigger( 'change' );
1724			} else {
1725				var checkbox = $(this).closest('.pewc-checkbox-wrapper').find('input[type=checkbox]').prop('checked',fal
1725se).trigger( 'change' );
1726			}
1727		}
1728		var available_stock = $(this).find(':selected').data('stock');
1729		// $( 'body' ).trigger( 'pewc_update_child_quantity', [ $(this).closest('.pewc-checkbox-image-wrapper').find('input[type=checkbox]') ] );
1730		$( 'body' ).trigger( 'pewc_update_child_quantity', [ $(this).closest('.pewc-checkbox-wrapper').find('input[type=checkbox]') ] );
1731		pewc_update_total_js();
1732	});
1733
1734	// 3.24.8, Products and Product Categories fields, Radio Images/Radio List layout, independent quantity. Since the quantity input is now outside .products-quantities-independent, the script above doesn't get triggered.
1735	$( 'body' ).on( 'change input keyup paste click', '.pewc-item-products-radio.pewc-item-products-independent .pewc-child-quantity-field, .pewc-item-products-radio-list.pewc-item-products-independent .pewc-child-quantity-field', function( e ){
1736		var item_field_wrapper = $( this ).closest( '.pewc-item-field-wrapper' );
1737		var pewc_item_wrapper = item_field_wrapper.closest( '.pewc-item' );
1738		var radio_type = '';
1739		var number_checked = 0;
1740
1741		if ( pewc_item_wrapper.hasClass( 'pewc-item-products-radio' ) ) {
1742			radio_type = 'radio images';
1743			number_checked = item_field_wrapper.find( '.pewc-radio-images-wrapper .pewc-radio-image-wrapper.checked' ).length;
1744		} else {
1745			radio_type = 'radio list';
1746			number_checked = item_field_wrapper.find( '.pewc-radio-wrapper input.pewc-radio-form-field:checked' ).length;
1747		}
1748
1749		var number_value = $( this ).val();
1750		if ( number_value > 0 && number_checked < 1 ) {
1751			// we don't have a product selected, select the first one?
1752			if ( radio_type == 'radio images' ) {
1753				item_field_wrapper.find( '.pewc-radio-images-wrapper .pewc-radio-image-wrapper' ).each( function(){
1754					if ( ! $( this ).hasClass( 'checked' ) ) {
1755						$( this ).addClass( 'checked' );
1756					}
1757					$( this ).find( 'input.pewc-radio-form-field' ).prop( 'checked', true );
1758					return false; // break the loop since we only want to select the first one
1759				});
1760			} else {
1761				// radio list
1762				item_field_wrapper.find( '.pewc-radio-list-wrapper .pewc-radio-wrapper input.pewc-radio-form-field' ).each( function(){
1763					$( this ).prop( 'checked', true );
1764					return false; // break the loop since we only want to select the first one
1765				});
1766			}
1767		} else if ( number_value < 1 && number_checked > 0 ) {
1768			// de-select all products
1769			if ( radio_type == 'radio images' ) {
1770				item_field_wrapper.find( '.pewc-radio-images-wrapper .pewc-radio-image-wrapper.checked' ).each( function(){
1771					$( this ).removeClass( 'checked' );
1772					$( this ).find( 'input.pewc-radio-form-field' ).prop( 'checked', false );
1773				});
1774			} else {
1775				// radio list
1776				item_field_wrapper.find( '.pewc-radio-list-wrapper .pewc-radio-wrapper input.pewc-radio-form-field:checked' ).each( function(){
1777					$( this ).prop( 'checked', false );
1778				});
1779			}
1780		}
1781	});
1782
1783	$('body').on('change input keyup paste','.pewc-item-products-independent.pewc-child-qty-target .pewc-child-quantity-field',function() {
1784		// This runs when the user manually updates a child product quantity that has been set by a calculation field (independent quantities, radio items only)
1785		// If the calculation field has a reverse formula, use the result to set the source field value
1786		var wrapper = $( this ).closest( '.pewc-item' );
1787		// This is the ID of the calculation field that triggers this quantity update
1788		var triggered_by = $( wrapper ).attr( 'data-child-qty-triggered-by' );
1789		// Get the "reverse formula" - i.e. the method to calculate how to update the source input field
1790		var reverse_field_id = $( '.pewc-field-' + triggered_by ).attr( 'data-reverse-formula-field' );
1791		var reverse_formula = calculations.get_formula_by_id( reverse_field_id );
1792		// Do this calc "live" to avoid any race conditions with other fields getting updated
1793		calc_field = $( '.pewc-field-' + reverse_field_id );
1794		calc_field_id = $( calc_field ).attr( 'data-field-id' );
1795		price_wrapper = $( calc_field ).find( '.pewc-calculation-price-wrapper' );
1796		calc_field_id = $( calc_field ).attr( 'data-field-id' );
1797		formula = $( price_wrapper ).find( '.pewc-data-formula' ).val();
1798		fields = $( price_wrapper ).find( '.pewc-data-fields' ).val();
1799		round = $( price_wrapper ).find( '.pewc-formula-round' ).val();
1800		decimals = $( price_wrapper ).find( '.pewc-decimal-places' ).val();
1801		if( fields ) {
1802			fields = JSON.parse( fields );
1803		}
1804		var reverse_result = calculations.evaluate_formula( fields, reverse_formula, round, decimals, calc_field_id );
1805		// Update the "source" input field with the result of the reverse calculation
1806		// The source input is the number field used in the main calculation field
1807		var source_field_id = $( '.pewc-field-' + triggered_by ).attr( 'data-reverse-input-field' );
1808		$( '.pewc-field-' + source_field_id ).find( 'input' ).val( reverse_result );
1809
1810		// Check if the calculation can be overridden by manual quantity updates
1811		if( $( '.pewc-field-' + triggered_by ).hasClass( 'pewc-quantity-overrides' ) ) {
1812			// Only set the quantity of this field with the result of the calculation once - to allow users to override the calculation by updating the quantity manually
1813			$( wrapper ).addClass( 'pewc-quantity-updated' );
1814		}
1815		
1816	});
1817	$( 'body' ).on( 'pewc_update_child_quantity', function( e, el ) {
1818		// This is triggered when the quantity field for a child product is updated
1819		var child_qty = $( el ).closest('.pewc-checkbox-wrapper').find('input[type=number]').val();
1820		if( child_qty > 0 ) {
1821			$( el ).closest('.pewc-checkbox-image-wrapper').addClass('checked');
1822		} else {
1823			$( el ).closest('.pewc-checkbox-image-wrapper').removeClass('checked');
1824		}
1825	});
1826	$( 'body' ).on( 'click', '.products-quantities-independent .pewc-checkbox-form-field', function( e ) {
1827		// aou-products-column-new, added 2nd condition
1828		if( $( this ).closest( '.pewc-checkbox-images-wrapper' ).hasClass( 'pewc-force-quantity' ) || $( this ).closest( '.pewc-checkbox-image-wrapper' ).find( '.pewc-column-attributes-select' ).length > 0 ) {
1829			e.stopPropagation();
1830			e.preventDefault(); // 3.25.7, prevent the hidden input checkbox from being unchecked and deselected
1831			return;
1832		}
1833		// this is triggered when clicking the child product's image
1834		if( $(this).is(':checked') ){
1835			var number = $(this).closest('.pewc-checkbox-wrapper').find('input[type=number]').val();
1836			if( number==0 ) {
1837				var default_quantity = $(this).closest( '.pewc-checkbox-wrapper' ).find( 'input[type=number]' ).attr( 'data-default-quantity' );
1838				if( default_quantity == undefined || pewc_vars.set_child_quantity_default != 'yes' ) {
1839					default_quantity = 1;
1840				}
1841				$(this).closest('.pewc-checkbox-wrapper').find('input[type=number]').val( default_quantity );
1842				//$(this).closest('.pewc-checkbox-image-wrapper').addClass('checked'); // commented out in 3.13.2, this is handled when the wrapper itself is clicked
1843			}
1844		} else {
1845			var number = $(this).closest('.pewc-checkbox-wrapper').find('input[type=number]').val(0);
1846			//$(this).closest('.pewc-checkbox-image-wrapper').removeClass('checked'); // commented out in 3.13.2
1847		}
1848		e.stopPropagation(); // added in 3.13.2. this may be triggered when the wrapper is clicked. Prevents infinite loop
1849	});
1850	$( 'body' ).on( 'click', '.products-quantities-linked .pewc-checkbox-form-field, .products-quantities-one-only .pe
1850wc-checkbox-form-field', function( e ) {
1851		e.stopPropagation(); // 3.13.3, prevents infinite loop
1852		if( $(this).is(':checked') ){
1853			$(this).closest('.pewc-checkbox-image-wrapper').addClass('checked');
1854		} else {
1855			$(this).closest('.pewc-checkbox-image-wrapper').removeClass('checked');
1856		}
1857	});
1858
1859	// Toggle class on label when text swatch element is updated
1860	$( 'body' ).on( 'change', '.pewc-text-swatch input', function( e ) {
1861		var field_type = $( this ).closest( '.pewc-item' ).attr( 'data-field-type' );
1862		if( field_type == 'radio' ) {
1863			$( this ).closest( 'ul' ).find( 'label' ).removeClass( 'active-swatch' );
1864		}
1865
1866		if( $( this ).prop( 'checked' ) == true ) {
1867			$( this ).closest( 'label' ).addClass( 'active-swatch' );
1868		} else {
1869			$( this ).closest( 'label' ).removeClass( 'active-swatch' );
1870		}
1871	});
1872
1873	$( 'body' ).on( 'click', '.pewc-radio-image-wrapper, .pewc-checkbox-image-wrapper', function( e ) {
1874		var wrapper = $( this );
1875		if( $( wrapper ).hasClass( 'pewc-checkbox-disabled' ) ) {
1876			return;
1877		}
1878		if( $( wrapper ).closest( '.pewc-components-wrapper' ).hasClass( 'pewc-force-quantity' ) ) {
1879			return;
1880		}
1881
1882		// aou-products-column-new, disable the click event for Column layout with attributes selection
1883		if ( $( wrapper ).find( '.pewc-column-attributes-select' ).length > 0 ) {
1884			return;
1885		}
1886
1887		// 
1888		var radio;
1889		var is_image_swatch_checkbox = $( wrapper ).closest( '.pewc-item' ).hasClass( 'pewc-item-image-swatch-checkbox' );
1890		var is_checkbox = $( wrapper ).hasClass( 'pewc-checkbox-image-wrapper' );
1891		// Remove all checked for radio button
1892		if( ! is_image_swatch_checkbox && ! is_checkbox ) {
1893			var checked = $( wrapper ).find( '.pewc-radio-form-field' ).prop( 'checked' );
1894			var group = $( wrapper ).closest( '.pewc-radio-images-wrapper' ).find( '.pewc-radio-image-wrapper' ).removeClass( 'checked' );
1895			if( ! checked ) {
1896				$( wrapper ).addClass( 'checked' );
1897				//radio = $( wrapper ).find( '.pewc-radio-form-field' ).trigger( 'click' );
1898			}
1899			// Defer the heavy synchronous chain (conditions, price update) so the browser can
1900			// paint the checked class before running the condition check / price recalculation.
1901			radio = $( wrapper ).find( '.pewc-radio-form-field' );
1902			setTimeout( function() { radio.trigger( 'click' ); }, 0 ); // moved here 3.9.5 for lightbox
1903		} else {
1904			// Checkbox
1905			if ( is_checkbox ) {
1906				// added in 3.13.2 for Products checkbox images
1907				e.preventDefault(); // this helps avoid the conflict with clicking the child product image
1908				radio = $( wrapper ).find( '.pewc-checkbox-form-field' );
1909				$( wrapper ).toggleClass( 'checked' );
1910				if ( is_image_swatch_checkbox ) {
1911					// 4.3.1, Swatch fields with Allow multiple enable wasn't getting added. trigger( 'click' ) below also causes infinite loop with the new Swatch template
1912					var checked = $( radio ).prop( 'checked' );
1913					var new_checked = ! checked;
1914					setTimeout( function() { $( radio ).prop( 'checked', new_checked ).trigger( 'change' ); }, 0 );
1915				} else {
1916					// keeping this here in case Products field need this
1917					setTimeout( function() { $( radio ).trigger( 'click' ); }, 0 ); // this triggers the click event attached to .products-quantities-independent .pewc-checkbox-form-field
1918				}
1919				e.stopPropagation();
1920			} else {
1921				radio = $( wrapper ).find( '.pewc-radio-form-field' );
1922				var checked = $( radio ).prop( 'checked' );
1923				$( wrapper ).toggleClass( 'checked' );
1924				var new_checked = ! checked;
1925				setTimeout( function() { $( radio ).prop( 'checked', new_checked ).trigger( 'click' ); }, 0 ); // click added 3.9.5
1926			}
1927		}
1928
1929	}).on( 'click', '.pewc-radio-image-wrapper .pewc-radio-form-field', function( e ) {
1930		// aou-products-column-new, disable the click event for Column layout with attributes selection
1931		var wrapper = $( this ).closest( '.pewc-radio-image-wrapper' );
1932		if ( $( wrapper ).find( '.pewc-column-attributes-select' ).length > 0 ) {
1933			return;
1934		}
1935		var is_image_swatch_checkbox = $( this ).closest( '.pewc-item' ).hasClass( 'pewc-item-image-swatch-checkbox' );
1936		if( ! is_image_swatch_checkbox ) {
1937			// Stop propagation for radio buttons
1938			e.stopPropagation();
1939			// Deselect the radio button
1940			var checked = $( this ).closest( '.pewc-radio-image-wrapper' ).hasClass( 'checked' );
1941			if( ! checked ) {
1942				$( this ).prop( 'checked', false ).trigger( 'change' ); // added on 3.9.5 for lightbox
1943				// pewc_update_total_js() removed: trigger(change) above fires pewc_update_total_js_debounced via .pe
1943wc-form-field handler
1944			}
1945		} else {
1946			e.stopPropagation(); // added on 3.9.5, for checkbox in lightbox
1947			$( this ).closest( '.pewc-radio-image-wrapper' ).toggleClass( 'checked' ); // originally here before 3.9.5
1948		}
1949		$form = $( this ).closest( 'form' );
1950		add_on_images.update_add_on_image( $( this ), $form );
1951	});
1952
1953	$( 'body' ).on( 'click' , '.products-quantities-independent .pewc-radio-form-field', function() {
1954		if($(this).is(':checked')) {
1955			var number_field = $(this).closest('.pewc-item-field-wrapper').find('input[type=number]');
1956			var number = $(number_field).val();
1957			if( number == 0 ) {
1958				$( number_field ).val( 1 );
1959			}
1960			if( $(this).attr('data-stock') > 0 ) {
1961				// Ensure the quantity field doesn't display more than the available stock
1962				$(number_field).attr( 'max', $(this).attr('data-stock') );
1963				if( $(number_field).val() > $(this).attr('data-stock') ) {
1964					$(number_field).val( $(this).attr('data-stock') );
1965				}
1966			}
1967		} else {
1968			//var number = $(this).closest( '.pewc-radio-images-wrapper' ).find( 'input[type=number]' ).val( 0 );
1969			var number = $(this).closest( '.pewc-item-field-wrapper' ).find( 'input[type=number]' ).val( 0 ); // 3.24.8, change quantity to 0 for Products and Product Categories field, Radio Images layout, independent quantity
1970		}
1971	});
1972
1973	// 3.12.0, handler for enabling/disabling the add-to-cart button
1974	function pewc_toggle_add_to_cart_button( eventType, disabled, caller ) {
1975
1976		var button = $( 'body' ).find( 'form.cart .single_add_to_cart_button' );
1977		var disable_class = 'pewc-disabled-by-'+caller;
1978
1979		if ( button.length < 1 ) return; // do nothing
1980
1981		// 4.3.14, it is possible to have more than one button e.g. Add to Quote button
1982		button.each( function(){
1983			var curr_button = $( this );
1984			if ( disabled ) {
1985				// always disable button
1986				curr_button.attr( 'disabled', true );
1987				if ( ! curr_button.hasClass( disable_class ) ) {
1988					curr_button.addClass( disable_class );
1989
1990					// 3.21.5
1991					var button_text = pewc_vars.calculating_text;
1992					if ( caller === 'upload' ) {
1993						button_text = pewc_vars.uploading_text;
1994					}
1995					pewc_update_add_to_cart_button_text( curr_button, button_text, disabled );
1996				}
1997			} else {
1998				// remove the disable_class added by the caller when it enabled it previously
1999				curr_button.removeClass( disable_class );
2000				// if we're trying to enable the add-to-cart button, check first if it hasn't been disabled by other plugins (example, by the calculation table)
2001				if ( curr_button.attr( 'class' ).indexOf( 'pewc-disabled-by' ) == -1 ) {
2002					// our special class was not found, safe to enable again
2003					curr_button.attr( 'disabled', false );
2004					var default_text = pewc_vars.default_add_to_cart_text;
2005					if ( curr_button.attr( 'data-pewc-orig-button-text' ) ) {
2006						default_text = curr_button.attr( 'data-pewc-orig-button-text' );
2007					}
2008					pewc_update_add_to_cart_button_text( curr_button, default_text );
2009				}
2010			}
2011		});
2012
2013	}
2014	$( 'body' ).on( 'pewc_toggle_add_to_cart_button', pewc_toggle_add_to_cart_button );
2015
2016	function pewc_update_add_to_cart_button_text( button, button_text, disabled=false ) {
2017		if ( button.is( 'button' ) ) {
2018			if ( disabled && ! button.attr( 'data-pewc-orig-button-text' ) ) {
2019				// 4.3.14, save first the original text e.g. could be Add to Quote
2020				button.attr( 'data-pewc-orig-button-text', button.text() );
2021			}
2022			button.text( button_text );
2023		} else {
2024			if ( disabled && ! button.attr( 'data-pewc-orig-button-text' ) ) {
2025				// 4.3.14, save first the original text
2026				button.attr( 'data-pewc-orig-button-text', button.val() );
2027			}
2028			button.val( button_text ); // maybe an input type submit button
2029		}
2030	}
2031
2032	var calculations = {
2033
2034		init: function() {
2035
2036			if( pewc_vars.calculations_timer > 0 ) {
2037				if ( pewc_vars.event_driven_conditions === 'yes' ) {
2038					// 4.3.5: bind recalculate to field change events instead of polling every 500ms.
2039					// These are the same triggers used by the non-optimised path but run within the
2040					// optimised context so we don't fall back to legacy condition-checking behaviour.
2041					$( 'body' ).on( 'keyup input change paste', 'form.cart .qty', this.recalculate );
2042					$( 'body' ).on( 'keyup input change paste', 'form.cart .pewc-item.pewc-calculation-trigger, .pewc-form-field.pewc-calculation-trigger, .pewc-field-triggers-condition .pewc-form-field, .pewc-field-triggers-condition .pewc-radio-form-field', this.recalculate );
2043					$( 'body' ).on( 'keyup input change paste', '.pewc-number-uploads', this.recalculate );
2044					$( 'body' ).on( 'pewc_trigger_calculations', this.recalculate );
2045					$( 'body' ).on( 'pewc_conditions_checked', this.recalculate );
2046					$( 'body' ).one( 'pewc_after_update_total_js', this.recalculate );
2047				} else {
2048					var interval = setInterval(
2049						this.recalculate,
2050						pewc_vars.calculations_timer
2051					);
2052				}
2053
2054				// since 3.12.0, disable add-to-cart button while recalculating
2055				if ( pewc_vars.disable_button_recalculate == 'yes' ) {
2056					$( 'body' ).on( 'keyup input change paste', 'form.cart .qty', this.disable_add_to_cart_button );
2057					$( 'body' ).on( 'keyup input change paste', 'form.cart .pewc-item.pewc-calculation-trigger, .pewc-form-field.pewc-calculation-trigger, .pewc-field-triggers-condition .pewc-form-field, .pewc-field-triggers-condition .pewc-radio-form-field', this.disable_add_to_cart_button );
2058					$( 'body' ).on( 'keyup input change paste', '.pewc-number-uploads', this.disable_add_to_cart_button );
2059					$( 'body' ).on( 'pewc_trigger_calculations', this.disable_add_to_cart_button );
2060					$( 'body' ).on( 'pewc_conditions_checked', this.disable_add_to_cart_button );
2061				}
2062			} else {
2063				// $( 'body' ).one( 'keyup input change paste', '.pewc-number-field.pewc-calculation-trigger, .pewc-field-triggers-condition .pewc-number-field', this.recalculate );
2064				$( 'body' ).on( 'keyup input change paste', 'form.cart .qty', this.recalculate );
2065				$( 'body' ).on( 'keyup input change paste', 'form.cart .pewc-item.pewc-calculation-trigger, .pewc-form-field.pewc-calculation-trigger, .pewc-field-triggers-condition .pewc-form-field, .pewc-field-triggers-condition .pewc-radio-form-field', this.recalculate );
2066				$( 'body' ).on( 'keyup input change paste', '.pewc-number-uploads', this.recalculate );
2067				$( 'body' ).on( 'pewc_trigger_calculations', this.recalculate );
2068				$( 'body' ).on( 'pewc_conditions_checked', this.recalculate );
2069			}
2070
2071		},
2072
2073		// 3.12.0
2074		disable_add_to_cart_button: function( e ) {
2075			// 3.12.2. Only disable if product has calculation fields
2076			var num_calcs = $( '.pewc-product-extra-groups-wrap .pewc-item-calculation' ).not( '.pewc-hidden-field' ).length;
2077
2078			if( parseFloat( num_calcs ) < 1 ) {
2079				return;
2080			}
2081			pewc_toggle_add_to_cart_button( e, true, 'calculation_recalculate' );
2082		},
2083
2084		recalculate: function( e ) {
2085
2086			// If we don't have any calculation fields, just bounce
2087			var num_calcs = parseInt( $( '.pewc-product-extra-groups-wrap .pewc-item-calculation' ).not( '.pewc-hidden-field' ).length );
2088			var num_formulas_in_field_prices = parseInt( $( '.pewc-product-extra-groups-wrap .pewc-field-price-has-formula' ).not( '.pewc-hidden-field' ).length );
2089			var num_formulas_in_option_prices = parseInt( $( '.pewc-product-extra-groups-wrap .pewc-field-option-price-has-formula' ).not( '.pewc-hidden-field' ).length );
2090
2091			if( num_calcs < 1 && num_formulas_in_field_prices < 1 && num_formulas_in_option_prices < 1 ) {
2092				return;
2093			}
2094
2095			var calc_field, price_wrapper, dimensions_wrapper, formula, tags, calc_formula, replace, calc_field_id, calc_value, prev_calc_value;
2096
2097			var calc_fields = [];
2098
2099			var update = 0;
2100
2101			if ( pewc_vars.calculations_timer > 0 && pewc_vars.disable_button_recalculate == 'yes' ) {
2102				// 3.12.0, we use this to determine if we have to enable or disable the add-to-cart button
2103				var pewc_total_calc_price_start = $( '#pewc_total_calc_price' ).val();
2104			}
2105
2106			// Find any calculation fields
2107			$( 'body' ).find( 'form.cart .pewc-item-calculation' ).not( '.pewc-hidden-field' ).each( function() {
2108
2109				if( $( this ).hasClass( 'pewc-variation-dependent' ) && ! $( this ).hasClass( 'active' ) ) {
2110					return;
2111				}
2112
2113				var group = $( this ).closest( '.pewc-group-wrap' );
2114				if( $( group ).hasClass( 'pewc-group-hidden' ) ) {
2115					return;
2116				}
2117
2118				var group_id = $( group ).attr( 'data-group-id' );
2119
2120				calc_field = $( this );
2121				var field_id = $( calc_field ).attr( 'data-id' );
2122				calc_field_id = $( calc_field ).attr( 'data-field-id' );
2123				price_wrapper = $( calc_field ).find( '.pewc-calculation-price-wrapper' );
2124				formula = $( price_wrapper ).find( '.pewc-data-formula' ).val();
2125				fields = $( price_wrapper ).find( '.pewc-data-fields' ).val();
2126				tags = $( price_wrapper ).find( '.pewc-data-tag' ).val();
2127				action = $( price_wrapper ).find( '.pewc-action' ).val();
2128				round = $( price_wrapper ).find( '.pewc-formula-round' ).val();
2129				decimals = $( price_wrapper ).find( '.pewc-decimal-places' ).val();
2130				calc_value = $( price_wrapper ).find( '.pewc-calculation-value' );
2131				prev_calc_value = calc_value.val();
2132
2133				if( fields ) {
2134					fields = JSON.parse( fields );
2135				}
2136
2137				var result = calculations.evaluate_formula( fields, formula, round, decimals, calc_field_id );
2138
2139				if( result == '*' ) {
2140					$( calc_field ).closest( '.pewc-item-calculation' ).attr( 'data-price', 0 );
2141					$( price_wrapper ).find( 'span' ).html( pewc_vars.null_signifier );
2142					calc_value.val( 0 );
2143					if ( prev_calc_value != 0 ) {
2144						// 3.12.2. Trigger only if the value changed to avoid infinite loop
2145						calc_value.trigger( 'calculation_field_updated' )
2146					}
2147					if( pewc_vars.disable_button_calcs == 'yes' ) {
2148						calc_fields.push( calc_field_id );
2149						//$( 'body' ).find( 'form.cart .single_add_to_cart_button' ).attr( 'disabled', true );
2150						$( 'body' ).trigger( 'pewc_toggle_add_to_cart_button', [ true, 'calculation' ] ); // since 3.12.0
2151					}
2152				} else if( ! result || ! isNaN( result ) ) {
2153					if( pewc_vars.disable_button_calcs == 'yes' ) {
2154						calc_fields = calc_fields.filter( function( item ) {
2155							return item !== calc_field_id;
2156						});
2157						if( calc_fields.length < 1 ) {
2158							//$( 'body' ).find( 'form.cart .single_add_to_cart_button' ).attr( 'disabled', false );
2159							$( 'body' ).trigger( 'pewc_toggle_add_to_cart_button', [ false, 'calculation' ] ); // since 3.12.0
2160						}
2161					}
2162					$( price_wrapper ).find( 'span' ).html( result );
2163
2164					if( action == 'cost' || action == 'price' ) {
2165						$( calc_field ).closest( '.pewc-item-calculation' ).attr( 'data-price', result );
2166						$( price_wrapper ).find( 'span' ).html( pewc_wc_price( result ) );
2167					} else if( action == 'qty' ) {
2168						$( 'form.cart' ).find( '.quantity .qty' ).val( result ).trigger( 'pewc_qty_changed' );
2169					} else if( action == 'child-qty' ) {
2170						// When a calculation updates, check if it should update a child product quantity field (independent, radio buttons only)
2171						// If it does, we update the quantity field						
2172						// This is the product field that will have its quantity set
2173						var product_field_id = $( calc_field ).closest( '.pewc-item-calculation' ).find( '.pewc-calculation-price-wrapper' ).attr( 'data-product-field-id' );
2174						// This is the ID of the child product that will be selected
2175						var child_qty_product_id = $( calc_field ).closest( '.pewc-item-calculation' ).find( '.pewc-calculation-price-wrapper' ).attr( 'data-child-product-id' );
2176						// Only set the result of this calculation once - don't update quantity if the user has updated it manually themselves
2177						if( ! $( '.pewc-field-' + product_field_id ).hasClass( 'pewc-quantity-updated' ) ) {
2178							$( '.pewc-field-' + product_field_id ).find( '.pewc-child-quantity-field' ).val( result ).trigger( 'pewc_update_child_quantity' );
2179							var group_name = 'pewc_group_' + group_id + '_' + product_field_id;
2180							// Auto select item (provided an item is not already selected)
2181							if( $( "input[name='" + group_name + "_child_product[]']:checked" ).length < 1 ) {
2182								$( '#' + group_name + '_' + child_qty_product_id ).prop( 'checked', true );
2183								$( '#' + group_name + '_' + child_qty_product_id ).closest( '.pewc-radio-image-wrapper' ).addClass( 'checked' );
2184							}
2185						}						
2186					} else if ( ! $( calc_field ).hasClass( 'pewc-hidden-calculation' ) ) {
2187						// no-action falls here, don't bother if calc field is hidden
2188						// pewc-result-format is filterable
2189						var result_format = $( price_wrapper ).find( '.pewc-result-format' ).val();
2190						if ( result_format == 'price' ) {
2191							$( price_wrapper ).find( 'span' ).html( pewc_wc_price( result ) );
2192						} else if ( result_format == 'price without currency' ) {
2193							$( price_wrapper ).find( 'span' ).html( pewc_wc_price_without_currency( result ) );
2194						}
2195					}
2196
2197					if( action == 'price' ) {
2198						$( calc_field ).closest( '.pewc-product-extra-groups-wrap' ).find( '#pewc_calc_set_price' ).val( result ).attr( 'data-calc-set', 1 ); // 3.17.2, compatibility with Product Table Ultimate
2199						//$( '#pewc_calc_set_price' ).val( result ).attr( 'data-calc-set', 1 ); // before 3.17.2
2200					}
2201
2202					calc_value.val( result );
2203					if ( prev_calc_value != result ) {
2204						// 3.12.2. Trigger only if the value changed to avoid infinite loop
2205						calc_value.trigger( 'calculation_field_updated' );
2206						calc_value.trigger( 'change' ); // 3.17.2, makes this field more responsive to changes by typing
2207					}
2208				} else if( result && isNaN( result ) && result != 'error' ) {
2209					allow_text_calcs_fields = pewc_vars.allow_text_calcs_fields;
2210					if( pewc_vars.allow_text_calcs ) {
2211						$( price_wrapper ).find( 'span' ).html( result );
2212						calc_value.val( result );
2213					} else if( allow_text_calcs_fields.includes( parseInt( calc_field_id ) ) ) {
2214						$( price_wrapper ).find( 'span' ).html( result );
2215						calc_value.val( result );
2216					}
2217				}
2218
2219				update++;
2220
2221			});
2222
2223			// 3.26.0
2224			if ( num_formulas_in_field_prices > 0 ) {
2225				calculations.evaluate_field_prices();
2226			}
2227			if ( num_formulas_in_option_prices > 0 ) {
2228				calculations.evaluate_option_prices();
2229			}
2230
2231			// Update the totals
2232			if( update > 0 ) {
2233				update = 0;
2234				pewc_update_total_js();
2235			}
2236
2237			if ( pewc_vars.calculations_timer > 0 && pewc_vars.disable_button_recalculate == 'yes' ) {
2238				// 3.12.0, we use this to determine if we have to enable or disable the add-to-cart button
2239				var pewc_total_calc_price_end = $( '#pewc_total_calc_price' ).val();
2240				var d = new Date();
2241				var time = d.getTime();
2242
2243				if ( pewc_total_calc_price_start != pewc_total_calc_price_end ) {
2244					// maybe we're not done calculating, disable the add-to-cart button
2245					$( 'body' ).trigger( 'pewc_toggle_add_to_cart_button', [ true, 'calculation_recalculate' ] );
2246					// record the last time there was a change
2247					$( '#pewc_total_calc_price' ).attr( 'data-last-calc-time', time );
2248				} else {
2249					// maybe we're done calculating, let's wait a second?
2250					if ( isNaN( $( '#pewc_total_calc_price' ).attr( 'data-last-calc-time') ) ) {
2251						// maybe this is not yet created, save a value
2252						$( '#pewc_total_calc_price' ).attr( 'data-last-calc-time', time );
2253					} else {
2254						var diff = parseFloat( time ) - parseFloat( $( '#pewc_total_calc_price' ).attr( 'data-last-calc-time') );
2255						if ( isNaN( diff ) || diff < pewc_vars.recalculate_waiting_time ) {
2256							// do nothing if not a number, or less than waiting time (default 0.7 seconds)
2257						} else {
2258							//enable the add-to-cart button
2259							$( 'body' ).trigger( 'pewc_toggle_add_to_cart_button', [ false, 'calculation_recalculate' ] );
2260						}
2261					}
2262				}
2263
2264			}
2265
2266		},
2267
2268		evaluate_look_up_table: function( calc_field_id ) {
2269
2270			var result = false;
2271
2272			if( pewc_look_up_fields == undefined ) return false;
2273
2274			var look_up_field = pewc_look_up_fields[calc_field_id];
2275
2276			var table = look_up_field[0];
2277			var x_field = look_up_field[1];
2278			var y_field = look_up_field[2];
2279
2280			var x_value = this.get_field_value( x_field );
2281			var y_value = this.get_field_value( y_field );
2282
2283			var tables = pewc_look_up_tables[table];
2284			if( tables == undefined ) {
2285				return false;
2286			}
2287
2288			var x_axis = tables[x_value];
2289
2290			// If there's not an element in the tables array for our x value, find the next one
2291			if( x_axis == undefined && x_value && x_value != undefined ) {
2292				if ( this.exact_match( calc_field_id, 'x' ) ) {
2293					return '*'; // 3.13.0, let's use the null signifier
2294				} else {
2295					x_value = calculations.find_nearest_index( x_value, tables );
2296					x_axis = tables[x_value];
2297				}
2298			} else if( x_axis == undefined && x_value==0 && x_value != undefined ) {
2299				x_axis = tables[Object.keys(tables)[0]];
2300			}
2301
2302			if( x_axis != undefined ) {
2303
2304				var y_axis = tables[y_value];
2305
2306				// if( y_axis == undefined && y_value && y_value != undefined ) {
2307				if( y_value && y_value != undefined ) {
2308					if ( ! this.exact_match( calc_field_id, 'y' ) ) {
2309						y_value = calculations.find_nearest_index( y_value, x_axis );
2310					}
2311				}
2312				if( y_value == 'max' ) {
2313					// Get last value in x_axis
2314					result = x_axis[Object.keys(x_axis)[Object.keys(x_axis).length - 1]];
2315				} else {
2316					result = x_axis[y_value];
2317				}
2318
2319				if ( this.exact_match( calc_field_id, 'y' ) && result == undefined ) {
2320					result = '*'; // 3.13.0
2321				}
2322			} else {
2323
2324				return false;
2325
2326			}
2327
2328			return result;
2329
2330		},
2331
2332		get_field_value: function( field_id ) {
2333
2334			var value = 0;
2335
2336			if( $( '.pewc-field-' + field_id ).find( 'input.pewc-number-field' ).length > 0 ) {
2337				return $( '.pewc-field-' + field_id ).find( 'input.pewc-number-field' ).val();
2338			} else if( $( '.pewc-field-' + field_id ).find( 'select' ).length > 0 ) {
2339				if( ! isNaN( $( '.pewc-field-' + field_id ).find( 'select option:selected' ).attr( 'value' ) ) ) {
2340					// Return the option 'label' if it's numeric
2341					return $( '.pewc-field-' + field_id ).find( 'select option:selected' ).attr( 'value' );
2342				} else {
2343					// Return the option's 'price'
2344					return $( '.pewc-field-' + field_id ).find( 'select option:selected' ).attr( 'data-option-cost' );
2345				}
2346				
2347			} else if( $( '.pewc-field-' + field_id ).find( 'input.pewc-radio-form-field[type="radio"]:checked' ).length > 0 ) {
2348				return $( '.pewc-field-' + field_id ).find( 'input.pewc-radio-form-field[type="radio"]:checked' ).attr( 'data-option-cost' );
2349			}
2350
2351			return value;
2352		},
2353
2354		find_nearest_index: function( value, axis ) {
2355
2356			var keys = Object.keys( axis ); // Just the keys
2357			keys.sort( (a,b) => a-b ); // sort the keys numerically. This is needed if keys have decimals
2358
2359			if( parseFloat( value ) <= parseFloat( keys[0] ) ) {
2360				return keys[0];
2361			}
2362
2363			// If first element is empty, replace with 0
2364			if( pewc_vars.set_initial_key == 'yes' ) {
2365				if( isNaN( keys[0] ) || keys[0] == '' ) {
2366					keys[0] = 0;
2367				}
2368			}
2369
2370			for( var i=0; i < keys.length; i++ ) {
2371				if( ( parseFloat( value ) > parseFloat( keys[i] ) ) && keys[i+1] !=undefined && ( parseFloat( value ) <= parseFloat( keys[i+1] ) ) ) { // Find the first key that is greater than the value passed in
2372					return keys[i+1];
2373				}
2374			}
2375
2376			if( keys[( keys.length ) - 1] == 'max' ) {
2377				return 'max';
2378			}
2379
2380			// Return this as a fallback in case we've gone over the last index
2381			return keys[i];
2382
2383		},
2384
2385		exact_match: function( calc_field_id, axis ) {
2386			// since 3.13.0
2387			if ( $( '.pewc-item-calculation.pewc-field-' + calc_field_id ).attr( 'data-exact-match-' + axis ) == 'yes' ) {
2388				return true;
2389			} else {
2390				return false;
2391			}
2392		},
2393
2394		evaluate_formula: function( fields, formula, round, decimals, calc_field_id ) {
2395
2396			var calc_formula = formula;
2397
2398			if( fields ) {
2399
2400				// Replace any field tags with values
2401				for( var i in fields ) {
2402
2403					// Look for any price values
2404					if( fields[i].indexOf( '_option_price' ) > -1 ) {
2405						var field_id = fields[i].replace( '_option_price', '' );
2406						// We want the price of the selected option in this field, not its value
2407						var o_price = parseFloat( $( 'form.cart .pewc-field-' + field_id ).attr( 'data-selected-option-price' ) );
2408						if( isNaN( o_price ) || ( $( 'form.cart .pewc-field-' + field_id ).length == 0 && pewc_vars.zero_missing_field == 'yes' ) ) {
2409							o_price = 0;
2410						}
2411						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2412						calc_formula = calc_formula.replace( replace, o_price );
2413					} else if ( fields[i].indexOf( '_option_value' ) > -1 ) {
2414						var field_id = fields[i].replace( '_option_value', '' );
2415						// We want the value of the selected option in this field
2416						var o_value = parseFloat( $( 'form.cart .pewc-field-' + field_id ).attr('data-field-value') );
2417						if( ( $( 'form.cart .pewc-field-' + field_id ).length == 0 && pewc_vars.zero_missing_field == 'yes' ) || isNaN( o_value ) ) {
2418							o_value = 0;
2419						}
2420						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2421						calc_formula = calc_formula.replace( replace, o_value );
2422					} else if( fields[i].indexOf( '_field_price' ) > -1 ) {
2423						// We want the price of the field
2424						var field_id = fields[i].replace( '_field_price', '' );
2425						var f_price = parseFloat( $( 'form.cart .pewc-field-' + field_id ).attr( 'data-field-price' ) );
2426						if( $( 'form.cart .pewc-field-' + field_id ).length == 0 && pewc_vars.zero_missing_field == 'yes' ) {
2427							f_price = 0;
2428						}
2429						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2430						calc_formula = calc_formula.replace( replace, f_price );
2431					} else if( fields[i].indexOf( '_number_uploads' ) > -1 ) {
2432						// We want the number of uploads
2433						var field_id = fields[i].replace( '_number_uploads', '' );
2434						var num_uploads = parseFloat( $( 'form.cart .pewc-field-' + field_id ).find( '.pewc-number-uploads' ).val() );
2435						if( $( 'form.cart .pewc-field-' + field_id ).length == 0 && pewc_vars.zero_missing_field == 'yes' ) {
2436							num_uploads = 0;
2437						}
2438						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2439						calc_formula = calc_formula.replace( replace, num_uploads );
2440					} else if( fields[i].indexOf( '_pdf_count' ) > -1 ) {
2441						// Get the number of pages for this uploaded PDF
2442						var field_id = fields[i].replace( '_pdf_count', '' );
2443						var pdf_count = parseFloat( $( '#field_' + field_id + "_pdf_count" ).val() );
2444						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2445						calc_formula = calc_formula.replace( replace, pdf_count );
2446					} else if( fields[i].indexOf( '_weight' ) > -1 ) {
2447						// Get the weight of child products selected in specified field
2448						var field_id = fields[i].replace( '_weight', '' );
2449						// Find the selected item in the field and get the weight
2450						var weight = $( 'form.cart .pewc-field-' + field_id ).find( 'input:checked').closest( '.pewc-radio-wrapper' ).attr( 'data-
2450product-weight' );
2451						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2452						calc_formula = calc_formula.replace( replace, weight );
2453					} else if( fields[i].indexOf( '_length' ) > -1 ) {
2454						// Get the length of child products selected in specified field
2455						var field_id = fields[i].replace( '_length', '' );
2456						// Find the selected item in the field and get the length
2457						var length = $( 'form.cart .pewc-field-' + field_id ).find( 'input:checked').closest( '.pewc-radio-wrapper' ).attr( 'data-product-length' );
2458						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2459						calc_formula = calc_formula.replace( replace, length );
2460					} else if( fields[i].indexOf( '_width' ) > -1 ) {
2461						// Get the width of child products selected in specified field
2462						var field_id = fields[i].replace( '_width', '' );
2463						// Find the selected item in the field and get the width
2464						var width = $( 'form.cart .pewc-field-' + field_id ).find( 'input:checked').closest( '.pewc-radio-wrapper' ).attr( 'data-product-width' );
2465						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2466						calc_formula = calc_formula.replace( replace, width );
2467					} else if( fields[i].indexOf( '_height' ) > -1 ) {
2468						// Get the height of child products selected in specified field
2469						var field_id = fields[i].replace( '_height', '' );
2470						// Find the selected item in the field and get the height
2471						var height = $( 'form.cart .pewc-field-' + field_id ).find( 'input:checked').closest( '.pewc-radio-wrapper' ).attr( 'data-product-height' );
2472						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2473						calc_formula = calc_formula.replace( replace, height );
2474					} else if( fields[i].indexOf( '_quantity' ) > -1 ) {
2475						// Get the quantity of child products in specified field - independent quantities, radio list / images only
2476						var field_id = fields[i].replace( '_quantity', '' );
2477						// Find the selected item in the field and get the quantity
2478						var quantity = $( 'form.cart .pewc-field-' + field_id ).find( '.pewc-independent-quantity-field').val();
2479						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2480						calc_formula = calc_formula.replace( replace, quantity );
2481					} else {
2482						// Look for the value of number fields
2483						var f_val = parseFloat( $( 'form.cart .pewc-number-field-' + fields[i] ).val() );
2484						if( ! f_val && pewc_vars.zero_missing_field == 'yes' ) {
2485							f_val = 0;
2486						}
2487						if( ! isNaN( f_val ) ) {
2488							if( $( 'form.cart .pewc-field-' + fields[i] ).length == 0 && pewc_vars.zero_missing_field == 'yes' ) {
2489								f_val = 0;
2490							}
2491							replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2492							calc_formula = calc_formula.replace( replace, f_val );
2493						}
2494					}
2495
2496				}
2497
2498			}
2499
2500			if( formula === undefined ) {
2501				console.log( 'formula not defined: ' + calc_field_id );
2502				return false;
2503			}
2504
2505			var product_price = parseFloat( $('#pewc-product-price').val() );
2506			// 3.12.0, if action of calculation field is Set Product Price, and if product has an FD bulk discount, use the original product price in the calculation, so that we can then set the discounted price later
2507			if ( typeof pewc_wcfad !== 'undefined' && pewc_wcfad.reset_product_price( formula, calc_field_id ) ) {
2508				product_price = parseFloat( $('#pewc-product-price-original').val() );
2509			}
2510			var quantity = parseFloat( $( 'form.cart .quantity' ).find( '.qty' ).val() );
2511			if( formula.includes( "{look_up_table}" ) ) {
2512				calc_formula = calculations.evaluate_look_up_table( calc_field_id );
2513			}
2514			if( formula.includes( "{product_weight}" ) ) {
2515				var product_weight = parseFloat( $( '#pewc_product_weight' ).val() );
2516				calc_formula = calc_formula.replace( /{product_weight}/g, parseFloat( product_weight ) );
2517			}
2518			if( formula.includes( "{product_height}" ) ) {
2519				var product_height = parseFloat( $( '#pewc_product_height' ).val() );
2520				calc_formula = calc_formula.replace( /{product_height}/g, parseFloat( product_height ) );
2521			}
2522			if( formula.includes( "{product_length}" ) ) {
2523				var product_length = parseFloat( $( '#pewc_product_length' ).val() );
2524				calc_formula = calc_formula.replace( /{product_length}/g, parseFloat( product_length ) );
2525			}
2526			if( formula.includes( "{product_width}" ) ) {
2527				var product_width = parseFloat( $( '#pewc_product_width' ).val() );
2528				calc_formula = calc_formula.replace( /{product_width}/g, parseFloat( product_width ) );
2529			}
2530			if( formula.includes( "{product_price}" ) && product_price ) {
2531				calc_formula = calc_formula.replace( /{product_price}/g, parseFloat( product_price ) );
2532			}
2533			if( formula.includes( "{quantity}" ) && quantity ) {
2534				calc_formula = calc_formula.replace( /{quantity}/g, parseFloat( quantity ) );
2535			}
2536			if( formula.includes( "{variable_1}" ) && pewc_vars.variable_1 ) {
2537				calc_formula = calc_formula.replace( /{variable_1}/g, parseFloat( pewc_vars.variable_1 ) );
2538			}
2539			if( formula.includes( "{variable_2}" ) && pewc_vars.variable_2 ) {
2540				calc_formula = calc_formula.replace( /{variable_2}/g, parseFloat( pewc_vars.variable_2 ) );
2541			}
2542			if( formula.includes( "{variable_3}" ) && pewc_vars.variable_3 ) {
2543				calc_formula = calc_formula.replace( /{variable_3}/g, parseFloat( pewc_vars.variable_3 ) );
2544			}
2545			if( formula.includes( "{calculated_booking_cost}" ) ) {
2546				var calculated_booking_cost = parseFloat( $( '#calculated_booking_cost' ).val() );
2547				calc_formula = calc_formula.replace( /{calculated_booking_cost}/g, parseFloat( calculated_booking_cost ) );
2548			}
2549			if( formula.includes( "{num_units_int}" ) ) {
2550				var num_units_int = parseFloat( $( '#num_units_int' ).val() );
2551				calc_formula = calc_formula.replace( /{num_units_int}/g, parseFloat( num_units_int ) );
2552			}
2553			if( formula.includes( "{num_bookings}" ) ) {
2554				var num_units_int = parseFloat( $( '#num_bookings' ).val() );
2555				calc_formula = calc_formula.replace( /{num_bookings}/g, parseFloat( num_units_int ) );
2556			}
2557			if( formula.includes( "{total_variations}" ) ) {
2558				var total_variations = parseFloat( $( '#wcbvp_total_variations' ).val() );
2559				calc_formula = calc_formula.replace( /{total_variations}/g, parseFloat( total_variations ) );
2560			}
2561			if( formula.includes( "{pa_" ) ) {
2562				var attribute = formula.replace( "{", "" );
2563				var attribute = attribute.replace( "}", "" );
2564				var attribute_data = pewc_vars.attribute_data;
2565				calc_formula = parseFloat( attribute_data[attribute] );
2566			}
2567
2568			if( pewc_vars.global_calc_vars ) {
2569				var global_calc_vars = pewc_vars.global_calc_vars;
2570				// Iterate through our global vars
2571				for( var key in global_calc_vars ) {
2572					if( formula.includes( "{" + key + "}" ) ) {
2573						var global_var = "{" + key + "}";
2574						var global_var_regex = new RegExp( global_var, 'g' );
2575						calc_formula = calc_formula.replace( global_var_regex, global_calc_vars[key] );
2576					}
2577				}
2578			}
2579
2580			// Check for ACF fields
2581			if( typeof pewc_acf_fields != 'undefined' ) {
2582				for( var key in pewc_acf_fields ) {
2583					if( formula.includes( "{acf_" + key + "}" ) ) {
2584						var acf_field = "{acf_" + key + "}";
2585						// Find all instances
2586						var acf_field_regex = new RegExp( acf_field, 'g' );
2587						calc_formula = calc_formula.replace( acf_field_regex, pewc_acf_fields[key] );
2588					}
2589				}
2590			}
2591
2592			var result;
2593
2594			if( calc_formula == '*' ) return calc_formula;
2595
2596			if( pewc_vars.allow_text_calcs ) {
2597				return calc_formula;
2598			}
2599			
2600			allow_text_calcs_fields = pewc_vars.allow_text_calcs_fields;
2601			if( allow_text_calcs_fields.includes( parseInt( calc_field_id ) ) ) {
2602				return calc_formula;
2603			}
2604
2605			try {
2606				result = math.eval( calc_formula );
2607
2608				if( round == 'ceil' ) {
2609					result = math.ceil( result );
2610				} else if( round == 'floor' ) {
2611					result = math.floor( result );
2612				}
2613				if( pewc_vars.math_round == 'yes' ) {
2614					result = Math.round( result * 100 ) / 100;
2615				}
2616				return result.toFixed( parseFloat( decimals ) );
2617			} catch( err ) {
2618				// Check all tags have been replaced
2619				return 'error';
2620			}
2621
2622		},
2623
2624		get_formula_by_id: function( reverse_field_id ) {
2625
2626			var formula = $( '.pewc-field-' + reverse_field_id ).find( '.pewc-data-formula' ).val();
2627			return formula;
2628
2629		},
2630
2631		evaluate_field_prices: function() {
2632
2633			$( 'body' ).find( 'form.cart .pewc-field-price-has-formula' ).not( '.pewc-hidden-field' ).each( function() {
2634				if( $( this ).hasClass( 'pewc-variation-dependent' ) && ! $( this ).hasClass( 'active' ) ) {
2635					return;
2636				}
2637
2638				var group = $( this ).closest( '.pewc-group-wrap' );
2639				if( $( group ).hasClass( 'pewc-group-hidden' ) ) {
2640					return;
2641				}
2642
2643				var group_id = $( group ).attr( 'data-group-id' );
2644
2645				var pewc_item = $( this );
2646				var field_id = $( pewc_item ).attr( 'data-id' );
2647				var data_field_id = $( pewc_item ).attr( 'data-field-id' );
2648				//var price_wrapper = $( pewc_item ).find( '.pewc-calculation-price-wrapper' );
2649				var formula = $( pewc_item ).attr( 'data-field-price-formula' );
2650				if ( formula == undefined ) {
2651					return;
2652				}
2653				var fields = $( pewc_item ).attr( 'data-field-price-formula-fields' );
2654				var tags = $( pewc_item ).attr( 'data-field-price-formula-tags' );
2655				//var action = $( price_wrapper ).find( '.pewc-action' ).val();
2656				var round = $( pewc_item ).attr( 'data-field-price-formula-round' );
2657				var decimals = $( pewc_item ).attr( 'data-field-price-formula-decimals' );
2658				//var calc_value = $( price_wrapper ).find( '.pewc-calculation-value' );
2659				//var prev_calc_value = calc_value.val();
2660
2661				if( fields ) {
2662					fields = JSON.parse( fields );
2663				}
2664
2665				var result = calculations.evaluate_formula( fields, formula, round, decimals, data_field_id );
2666				if ( isNaN( result ) ) {
2667					result = 0;
2668				}
2669				$( pewc_item ).attr( 'data-price', result ); // data-field-price is field price (data-price) + option-price
2670				if ( 'checkbox' === $( pewc_item ).attr( 'data-field-type' ) ) {
2671					$( pewc_item ).find( '.pewc-checkbox-price' ).html( pewc_wc_price( result, true ) );
2672				} else {
2673					$( pewc_item ).find( '.pewc-field-price' ).html( pewc_wc_price( result, true ) );
2674				}
2675				$( pewc_item ).find( 'input[name="' + field_id + '_field_price_calculated"]' ).val( result );
2676			});
2677
2678		},
2679
2680		evaluate_option_prices: function() {
2681
2682			$( 'body' ).find( 'form.cart .pewc-field-option-price-has-formula' ).not( '.pewc-hidden-field' ).each( function() {
2683				if( $( this ).hasClass( 'pewc-variation-dependent' ) && ! $( this ).hasClass( 'active' ) ) {
2684					return;
2685				}
2686
2687				var group = $( this ).closest( '.pewc-group-wrap' );
2688				if( $( group ).hasClass( 'pewc-group-hidden' ) ) {
2689					return;
2690				}
2691
2692				var group_id = $( group ).attr( 'data-group-id' );
2693
2694				var pewc_item = $( this );
2695				var field_id = $( pewc_item ).attr( 'data-id' );
2696				var data_field_id = $( pewc_item ).attr( 'data-field-id' );
2697				var round = $( pewc_item ).attr( 'data-field-price-formula-round' );
2698				var decimals = $( pewc_item ).attr( 'data-field-price-formula-decimals' );
2699
2700				$( this ).find( '.pewc-option-price-has-formula' ).each( function(){
2701					var opt = $( this );
2702					var formula = $( opt ).attr( 'data-option-cost-formula' );
2703					if ( formula == undefined ) {
2704						return;
2705					}
2706					var fields = $( opt ).attr( 'data-option-price-formula-fields' );
2707					var tags = $( opt ).attr( 'data-option-price-formula-tags' );
2708					var index = $( opt ).attr( 'data-option-index' );
2709
2710					if( fields ) {
2711						fields = JSON.parse( fields );
2712					}
2713
2714					var result = calculations.evaluate_formula( fields, formula, round, decimals, data_field_id );
2715					if ( isNaN( result ) ) {
2716						result = 0;
2717					}
2718					if ( $( opt ).attr( 'data-option-cost' ) == result && 'select' === $( pewc_item ).attr( 'data-field-type' ) ) {
2719						return; // no need to update, prevents Select fields from blinking
2720					}
2721					$( opt ).attr( 'data-option-cost', result );
2722					$( opt ).closest( 'label' ).find( '.pewc-option-cost-label' ).html( pewc_wc_price( result ) );
2723					if ( 'select' === $( pewc_item ).attr( 'data-field-type' ) ) {
2724						var new_text = $( opt ).val() + pewc_vars.separator + pewc_wc_price( result, true );
2725						$( this ).text( new_text );
2726					} else if ( 'select-box' === $( pewc_item ).attr( 'data-field-type' ) ) {
2727						var selectbox = $( '#' + field_id + '_select_box' );
2728						if ( selectbox.length > 0 ) {
2729							var optprice = 0;
2730							selectbox.find( '.dd-option' ).each( function( index, element ){
2731								optprice = parseFloat( $( 'input[name="' + field_id + '_option_' + index + '_price_calculated"]' ).val() );
2732								if ( ! isNaN( optprice ) ) {
2733									$( element ).find( '.dd-option-description' ).html( pewc_wc_price( optprice, true ) );
2734								}
2735							});
2736							var selected_value = $( pewc_item ).find( '.dd-selected-value' ).val();
2737							var select_option_index = 0;
2738							select_option_index = $( 'select#' + field_id + ' option[value="' + selected_value.replace( /"/g, '\\"' ) + '"]').index();
2739							optprice = parseFloat( $( 'input[name="' + field_id + '_option_' + select_option_index + '_price_calculated"]' ).val() );
2740							if ( ! isNaN( optprice ) ) {
2741								$( pewc_item ).find( '.dd-selected-description' ).html( pewc_wc_price( optprice, true ) );
2742								$( pewc_item ).attr( 'data-selected-option-price', optprice );
2743							}
2744						}
2745					}
2746					$( pewc_item ).find( 'input[name="' + field_id  + '_option_' + index + '_price_calculated"]' ).val( result );
2747				});
2748			});
2749
2750		}
2751
2752	}
2753
2754	calculations.init();
2755
2756	var hidden_groups = {
2757
2758		init: function() {
2759			$( 'body' ).on( 'pewc_conditions_checked', this.check_group_visibility );
2760		},
2761
2762		/**
2763		 * Check whether to hide or display groups
2764		 */
2765		check_group_visibility: function() {
2766
2767			// Check each group
2768			$( 'body' ).find( '.pewc-group-wrap' ).each( function() {
2769				var all_hidden = true;
2770				var group = $( this );
2771				$( group ).find( '.pewc-item' ).each( function() {
2772					if( ! $( this ).hasClass( 'pewc-hidden-field' ) ) {
2773						all_hidden = false;
2774					}
2775				});
2776				if( all_hidden ) {
2777					$( group ).addClass( 'pewc-hidden-group' );
2778				} else {
2779					$( group ).removeClass( 'pewc-hidden-group' );
2780				}
2781			});
2782
2783		}
2784
2785	}
2786
2787	hidden_groups.init();
2788
2789	var summary_panel = {
2790
2791		init: function() {
2792			$( '.pewc-form-field' ).on( 'change update keyup', this.update_panel );
2793		},
2794
2795		update_panel: function( e ) {
2796			var field_id = $( this ).closest( '.pewc-item' ).attr( 'data-field-id' );
2797			var field_value = $( this ).val();
2798		},
2799
2800	}
2801
2802	summary_panel.init();
2803
2804	/**
2805	 * Sets product images for the chosen add-on
2806	 */
2807	var add_on_images = {
2808
2809		init: function() {
2810
2811			var $product        = $( 'form.cart' ).closest( '.product' ),
2812				$product_gallery  = $product.find( pewc_vars.product_gallery ),
2813				$gallery_nav      = $product.find( '.flex-control-nav' ),
2814				$gallery_img      = $gallery_nav.find( 'li:eq(0) img' ),
2815				$product_img_wrap = $product_gallery.find( pewc_vars.product_img_wrap ).eq( 0 ),
2816				$product_img      = $product_img_wrap.find( 'img' ).eq( 0 ),
2817				$product_link     = $product_img_wrap.find( 'a' ).eq( 0 );
2818
2819			if( add_on_images.replace_image() ) {
2820				// create an attribute where we can track where a replaced image came from
2821				$product_img.attr( 'data-pewc-from-field', '' );
2822
2823				// 3.17.2, find the first field that has a default value and not hidden, then auto replace main image with the selected swatch. if multiple are selected, pick the first one?
2824				$( document ).ready( function() {
2825					// we need to delay this so that the main image container takes the size of the original product image
2826					add_on_images.replace_main_with_default();
2827				});
2828
2829				// when Optimised conditions is enabled, update_add_on_image is run first before a group is hidden, so we do this to reset a main image if the field is inside a group that becomes hidden
2830				$( 'body' ).on( 'pewc_group_visibility_updated', function( e, id, action ) {
2831					add_on_images.check_if_src_hidden( $product_img );
2832				});
2833
2834				// 3.21.4, trigger replace main image if field is initially hidden by a condition
2835				$( 'body' ).on( 'pewc_field_visibility_updated', function( e, id, action ) {
2836					var pewc_item = $( '.pewc-item.' + id );
2837					// 3.26.6, changed condition from data-default-value to data-field-value to accommodate Edit Options
2838					if ( pewc_item.attr( 'data-field-value' ) != '' ) {
2839						// only do this if field has selected value that needs to replace the main image
2840						if ( pewc_item.data( 'field-type' ) === 'image_swatch' ) {
2841							// 3.24.6, find the first checked/selected element
2842							var field = pewc_item.find( 'input[name="' + id + '[]"]:checked' )[0];
2843						} else {
2844							var field = pewc_item.find( 'input[name="' + id + '[]"]' )[0];
2845						}
2846						var $form = pewc_item.closest( 'form' );
2847						add_on_images.update_add_on_image( $( field ), $form );
2848					}
2849				});
2850
2851			}
2852
2853			// If we've got parent/child swatches, then hide/show the correct child swatch
2854			$( '.pewc-swatch-parent .pewc-radio-form-field' ).on( 'change', this.change_child );
2855
2856			// If we've got parent/child swatches, then ensure that all the child swatches are in sync
2857			$( '.pewc-swatch-child .pewc-radio-form-field' ).on( 'change', this.sync_children );
2858
2859		},
2860
2861		replace_image: function( field ) {
2862			// 3.17.2
2863			if( pewc_vars.replace_image ) {
2864				// global Replace main image, or the filter pewc_get_add_on_image_action, is used
2865				return pewc_vars.replace_image;
2866			} else if ( field ) {
2867				if ( field.hasClass( 'pewc-replace-main-image' ) ) {
2868					return true;
2869				}
2870			} else {
2871				// if we have just one field that has enabled Replace main image, activate
2872				if ( $( document ).find( '.pewc-replace-main-image' ).length > 0 ) {
2873					return true;
2874				}
2875			}
2876			return false;
2877		},
2878
2879		save_original_src: function( $product_img ) {
2880			if ( $product_img.attr( 'data-pewc-old-src' ) ) {
2881				return; // already set, do nothing
2882			}
2883			// Set original src values
2884			$product_img.attr( 'data-pewc-old-src', $product_img.attr( 'src' ) );
2885			// 3.13.3, data-src is used by WooCommerce zoom image
2886			if ( $product_img.attr( 'data-src' ) ) {
2887				$product_img.attr( 'data-pewc-old-data-src', $product_img.attr( 'data-src' ) );
2888			} else {
2889				$product_img.attr( 'data-pewc-old-data-src', '' );
2890			}
2891			if ( $product_img.attr( 'srcset' ) ) {
2892				$product_img.attr( 'data-pewc-old-srcset', $product_img.attr( 'srcset' ) );
2893			} else {
2894				$product_img.attr( 'data-pewc-old-srcset', '' );
2895			}
2896			// photoswipe gallery
2897			if ( $product_img.attr( 'data-large_image' ) ) {
2898				$product_img.attr( 'data-pewc-old-data-large_image', $product_img.attr( 'data-large_image' ) );
2899			} else {
2900				$product_img.attr( 'data-pewc-old-data-large_image', '' );
2901			}
2902			if ( $product_img.attr( 'data-large_image_width' ) ) {
2903				$product_img.attr( 'data-pewc-old-data-large_image_width', $product_img.attr( 'data-large_image_width' ) );
2904			} else {
2905				$product_img.attr( 'data-pewc-old-data-large_image_width', '' );
2906			}
2907			if ( $product_img.attr( 'data-large_image_height' ) ) {
2908				$product_img.attr( 'data-pewc-old-data-large_image_height', $product_img.attr( 'data-large_image_height' ) );
2909			} else {
2910				$product_img.attr( 'data-pewc-old-data-large_image_height', '' );
2911			}
2912
2913		},
2914
2915		// 4.3.13, created a separate function outside of save_original_src()
2916		save_original_zoom_src: function( $product_img ) {
2917
2918			if ( $product_img.attr( 'data-pewc-old-zoom' ) ) {
2919				return; // already set, do nothing
2920			}
2921
2922			var zoomImg = $product_img.closest( pewc_vars.product_img_wrap ).find( pewc_vars.product_img_zoom ).eq(0);
2923			if ( zoomImg.length ) {
2924				$product_img.attr( 'data-pewc-old-zoom', zoomImg.attr( pewc_vars.product_img_zoom_src ) );
2925			} else {
2926				// zoomImg not yet in DOM (e.g. Enfold theme) — fall back to data-src, which jquery.zoom uses to populate zoomImg
2927				$product_img.attr( 'data-pewc-old-zoom', $product_img.attr( 'data-src' ) || $product_img.attr( 'src' ) );
2928			}
2929
2930		},
2931
2932		update_add_on_image: function( field, $form ) {
2933			
2934			var field_wrapper = $( field ).closest( '.pewc-item' );
2935			var is_layered = $( field_wrapper ).attr( 'data-field-layered' );
2936
2937			if( ! add_on_images.replace_image( field_wrapper ) && is_layered != 'yes' ) {
2938				return;
2939			}
2940
2941			var field_type = $( field_wrapper ).attr( 'data-field-type' );
2942
2943			var $product        	= $form.closest( '.product' ),
2944				$product_gallery  	= $product.find( pewc_vars.product_gallery ),
2945				$layer_parent 		= pewc_vars.layer_parent,
2946				$gallery_nav      	= $product.find( '.flex-control-nav' ),
2947				$gallery_img      	= $gallery_nav.find( 'li:eq(0) img' ),
2948				$product_img_wrap 	= $product_gallery.find( pewc_vars.product_img_wrap ).eq( 0 ),
2949				$product_img      	= $product_img_wrap.find( 'img' ).eq( 0 ),
2950				$product_link     	= $product_img_wrap.find( 'a' ).eq( 0 );
2951
2952			if( ! $( field_wrapper ).hasClass( 'pewc-has-field-image' ) && field_type != 'image_swatch' && field_type != 'select-box' ) {
2953				// the clicked field is not an image swatch, select box, or does not have a field image, but let's check if we need to replace the main image with the original one
2954				add_on_images.check_if_src_hidden( $product_img );
2955				return;
2956			}
2957
2958			// 3.21.4, Ignore fields in hidden groups
2959			if ( $( field_wrapper ).closest( '.pewc-group-wrap' ).hasClass( 'pewc-group-hidden' ) ) {
2960				add_on_images.check_if_src_hidden( $product_img );
2961				return; 
2962			}
2963
2964			// 3.21.4, Ignore hidden variation-dependent fields and hidden fields
2965			if( ( $( field_wrapper ).hasClass( 'pewc-variation-dependent' ) && ! $( field_wrapper ).hasClass( 'active' ) ) || $( field_wrapper ).hasClass( 'pewc-hidden-field' ) ) {
2966				add_on_images.check_if_src_hidden( $product_img );
2967				return;
2968			}
2969
2970			var add_on_image_wrapper;
2971			var add_on_image_src;
2972			var add_on_image_large_image, add_on_image_large_image_width, add_on_image_large_image_height;
2973			var turn = 'off';
2974
2975			var add_on_image_field = '', add_on_image_option = '';
2976
2977			if( field_type == 'checkbox' && $( field ).prop( 'checked' ) && add_on_images.replace_image( field_wrapper ) != 'replace_image_swatch_only' ) {
2978				turn = 'on';
2979				add_on_image_wrapper = $( field_wrapper ).find( '.pewc-item-field-image-wrapper' );
2980				add_on_image_src = $( add_on_image_wrapper ).attr( 'data-image-full-size' );
2981				add_on_image_srcset = add_on_image_src;
2982				// photoswipe gallery
2983				add_on_image_large_image = $( add_on_image_wrapper ).attr( 'data-image-full-size' );
2984				add_on_image_large_image_width = $( add_on_image_wrapper ).attr( 'data-large_image_width' );
2985				add_on_image_large_image_height = $( add_on_image_wrapper ).attr( 'data-large_image_height' );
2986				// 3.27.4, for Checkbox field, maybe we only need to detect this class to know it's checked?
2987				add_on_image_field = 'pewc-add-on-image-' + $( field_wrapper ).attr( 'data-field-id' );
2988			}
2989			if( field_type == 'image_swatch') {
2990				add_on_image_wrapper = field.closest( '.pewc-radio-image-wrapper' );
2991
2992				if ( add_on_image_wrapper.hasClass( 'checked' ) ) {
2993					add_on_image_src = add_on_image_wrapper.find( 'img' ).attr( 'data-src' );
2994					add_on_image_srcset = add_on_image_src;
2995					// photoswipe gallery
2996					add_on_image_large_image = add_on_image_wrapper.find( 'img' ).attr( 'data-large_image' );
2997					add_on_image_large_image_width = add_on_image_wrapper.find( 'img' ).attr( 'data-large_image_width' );
2998					add_on_image_large_image_height = add_on_image_wrapper.find( 'img' ).attr( 'data-large_image_height' );
2999
3000					if (add_on_image_src != undefined) {
3001						turn = 'on';
3002						// 3.27.5
3003						if ( $( field_wrapper ).hasClass( 'pewc-item-radio' ) ) {
3004							$product_img.closest( '.' + pewc_vars.layer_parent ).removeClass(function(index, className) {
3005								return (className.match(/(^|\s)pewc\-add\-on\-image\-\S+/g) || []).join(' ');
3006							});
3007						}
3008						// 3.27.4
3009						add_on_image_field = 'pewc-add-on-image-' + $( field_wrapper ).attr( 'data-field-id' );
3010						add_on_image_option = add_on_image_field + '-' + $( field ).attr( 'id' ).replace( $( field_wrapper ).attr( 'data-id' ) + '_', '' );
3011					}
3012				}
3013			} else if ( field_type == 'select-box' && add_on_images.replace_image( field_wrapper ) != 'replace_image_swatch_only' ) {
3014				// 3.13.7
3015				if ( field_wrapper.find( 'input.dd-selected-value' ).val() != '' ) {
3016					// check if the full image exists
3017					var src_image = field_wrapper.find( 'input.dd-selected-image-full' );
3018					if ( src_image.length > 0 ) {
3019						add_on_image_src = src_image.val();
3020					} else {
3021						src_image = field_wrapper.find( 'img.dd-selected-image' );
3022						add_on_image_src = src_image.attr( 'src' );
3023					}
3024					add_on_image_srcset = add_on_image_src;
3025					// photoswipe gallery
3026					add_on_image_large_image = add_on_image_src;
3027					add_on_image_large_image_width = src_image.attr( 'data-imgsrc-width' );
3028					add_on_image_large_image_height = src_image.attr( 'data-imgsrc-height' );
3029
3030					if ( add_on_image_src != undefined) {
3031						turn = 'on';
3032						// 3.27.4, always remove first for Select Box, so that the previous option selected is removed first
3033						$product_img.closest( '.' + pewc_vars.layer_parent ).removeClass(function(index, className) {
3034							return (className.match(/(^|\s)pewc\-add\-on\-image\-\S+/g) || []).join(' ');
3035						});
3036						add_on_image_field = 'pewc-add-on-image-' + $( field_wrapper ).attr( 'data-field-id' );
3037						add_on_image_option = add_on_image_field + '-index-' + $( field_wrapper ).find( 'select' ).prop( 'selectedIndex' );
3038					}
3039				}
3040			}
3041
3042			if( is_layered == 'yes' ) {
3043				// This is a layered image so we are going to create/update layers
3044				var field_id = $( field_wrapper ).attr( 'data-field-id' );
3045				var layer_id = 'pewc-layer-' + field_id;
3046				var layer_index = $( field_wrapper ).attr( 'data-field-index' );
3047				// This is the wrapper, e.g. woocommerce-product-gallery__wrapper
3048				// Add our cloned image into a div within this wrapper
3049				// The wrapper can be absolutely positioned over the main image
3050				var swatch_src = $( add_on_image_wrapper ).find( 'img' ).attr( 'data-large_image' );
3051				// Check for an alternative image to replace the main image
3052				if( $( add_on_image_wrapper ).find( 'img' ).attr( 'data-alt_image' ).length > 0 ) {
3053					swatch_src = $( add_on_image_wrapper ).find( 'img' ).attr( 'data-alt_image' );
3054				}
3055				if( $( '.' + layer_id ).length === 0 && $( add_on_image_wrapper ).hasClass( 'checked' ) ) {
3056					// Get the selected swatch image src
3057					var layer_image = '<img class="pewc-layer-image" src="' + swatch_src + '">';
3058					// Make the layer
3059					// var layer = $product_img.clone().insertAfter( $product_img ).addClass( layer_id );
3060					$( $( '.' + $layer_parent ) ).append( '<div class="pewc-image-layer ' + layer_id + '" style="z-index:' + ( layer_index + 1 ) * 10 + '">' + layer_image + '</div>' );
3061				} else if( $( '.' + layer_id ).length !== 0 && $( add_on_image_wrapper ).hasClass( 'checked' ) ) {
3062					// Layer exists but need to update the image inside
3063					// swatch_src = $( add_on_image_wrapper ).find( 'img' ).attr( 'data-large_image' );
3064					$( '.' + layer_id ).find( 'img' ).attr( 'src', swatch_src );
3065				} else if( ! $( add_on_image_wrapper ).hasClass( 'checked' ) ) {
3066					$( '.' + layer_id ).remove();
3067				}
3068
3069				// 3.27.8, add special classes
3070				if ( add_on_image_field != '' && ! $( '.' + pewc_vars.layer_parent ).hasClass( add_on_image_field ) ) {
3071					$product_img.closest( '.' + pewc_vars.layer_parent ).addClass( add_on_image_field );
3072				}
3073				if ( add_on_image_option != '' && ! $( '.' + pewc_vars.layer_parent ).hasClass( add_on_image_option ) ) {
3074					$product_img.closest( '.' + pewc_vars.layer_parent ).addClass( add_on_image_option );
3075				}
3076
3077			} else if ( add_on_image_src && turn == 'on' ) {
3078
3079				// maybe save original
3080				add_on_images.save_original_src( $product_img );
3081				add_on_images.save_original_zoom_src( $product_img );
3082
3083				$product_img.attr( 'data-pewc-from-field', $( field_wrapper ).attr( 'data-id' ) );
3084				$product_img.attr( 'src', add_on_image_src );
3085				$product_img.attr( 'srcset', add_on_image_srcset );
3086				$product_img.attr( 'data-src', add_on_image_src ); // 3.13.3, used by WC zoomImg
3087				// replace photoswipe gallery
3088				$product_img.attr( 'data-large_image', add_on_image_large_image );
3089				$product_img.attr( 'data-large_image_width', add_on_image_large_image_width );
3090				$product_img.attr( 'data-large_image_height', add_on_image_large_image_height );
3091
3092				// replace zoom image
3093				//var zoomImg = $product_img.closest( pewc_vars.product_img_wrap ).find( pewc_vars.product_img_zoom ).eq(0);
3094				//if ( zoomImg ) {
3095				//	zoomImg.attr( pewc_vars.product_img_zoom_src, add_on_image_src );
3096				//}
3097
3098				// 4.3.13, newer version, waits for zoomImg to be ready
3099				var $wrap   = $product_img.closest( pewc_vars.product_img_wrap );
3100				var zoomImg = $wrap.find( pewc_vars.product_img_zoom ).eq(0);
3101
3102				if ( zoomImg.length ) {
3103					add_on_images.save_original_zoom_src( $product_img );
3104					zoomImg.attr( pewc_vars.product_img_zoom_src, add_on_image_src );
3105				} else if ( $wrap[0] ) {
3106					var _src = add_on_image_src;
3107					var zoomObserver = new MutationObserver( function() {
3108						var $z = $wrap.find( pewc_vars.product_img_zoom ).eq(0);
3109						if ( $z.length ) {
3110							zoomObserver.disconnect();
3111							add_on_images.save_original_zoom_src( $product_img );
3112							$z.attr( pewc_vars.product_img_zoom_src, _src );
3113						}
3114					} );
3115					zoomObserver.observe( $wrap[0], { childList: true, subtree: true } );
3116				}
3117
3118				// 3.27.4, add special classes
3119				if ( add_on_image_field != '' && ! $( '.' + pewc_vars.layer_parent ).hasClass( add_on_image_field ) ) {
3120					$product_img.closest( '.' + pewc_vars.layer_parent ).addClass( add_on_image_field );
3121				}
3122				if ( add_on_image_option != '' && ! $( '.' + pewc_vars.layer_parent ).hasClass( add_on_image_option ) ) {
3123					$product_img.closest( '.' + pewc_vars.layer_parent ).addClass( add_on_image_option );
3124				}
3125			} else {
3126				// 3.27.4, remove all our special classes, it will be added back if we still have a swatch selected
3127				$product_img.closest( '.' + pewc_vars.layer_parent ).removeClass(function(index, className) {
3128					return (className.match (/(^|\s)pewc\-add\-on\-image\-\S+/g) || []).join(' ');
3129				});
3130				add_on_images.replace_main_with_default( $product_img, false ); // 3.24.7, let's try to find an active swatch first before resetting the main image
3131			}
3132
3133			// 3.13.2 bring back the focus on the main image to see the selected image swatch
3134			if ( pewc_vars.replace_image_focus == 'yes' ) {
3135				var control_list_selector = '.' + pewc_vars.control_container + ' ' + pewc_vars.control_list;
3136				$( control_list_selector ).first().find( pewc_vars.control_element ).trigger( 'click' ); // 3.25.6, changed from click() to trigger('click') because click() is deprecated
3137				$( 'body' ).trigger( 'pewc_update_add_on_image_focus_on_main_image' ); // 3.23.1, for other sliders that have a different way of focusing on the first image e.g. Flickity
3138			}
3139		},
3140
3141		// If we are using secondary images, then hide/show the correct child swatch field
3142		change_child: function( e ) {
3143			
3144			var parent_swatch = e.target;
3145			var parent_index = $( parent_swatch ).closest( '.pewc-item' ).find( '.pewc-radio-image-wrapper.checked input' ).attr( 'data-option-index' );
3146			if( ! isNaN( parent_index ) ) {
3147				$( '.pewc-swatch-child' ).addClass( 'pewc-visibility-hidden' );
3148				$( '.pewc-swatch-child-' + parent_index ).removeClass( 'pewc-visibility-hidden' );
3149				var active_layer_id = $( '.pewc-swatch-child-' + parent_index ).attr( 'data-field-id' );
3150				// Get the selected child index
3151				var selected_input = $( '.pewc-swatch-child' ).not( '.pewc-visibility-hidden' ).closest( '.pewc-item' ).find( '.pewc-radio-image-wrapper.checked input' );
3152				var index = $( selected_input ).attr( 'data-option-index' );
3153				// Trigger the child swatch
3154				// var selected = $( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' ).prop( 'checked' );
3155
3156				$( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper.pewc-radio-form-field' ).prop('checked', false);
3157
3158				// When we change the child, we need to hide unwanted image layers on the main image
3159				$( '.pewc-layer-' + active_layer_id ).show();
3160				// Hide the other child swatch layers
3161				var child_swatch_ids = JSON.parse( pewc_vars.child_swatch_ids );
3162				for( var i in child_swatch_ids ) {
3163					if( child_swatch_ids[i] != active_layer_id ) {
3164						$( '.pewc-layer-' + child_swatch_ids[i] ).fadeOut( 150 );
3165					} 
3166				}
3167				// Find any layers that we need to hide
3168				// $( '.pewc-show-for' ).each( function( layer_index, element ) {
3169				// 	// This layer only shows when a specific field is visible
3170				// 	var show_for = $( this ).attr( 'data-show-for' );
3171				// 	var layer_id = $( this ).attr( 'data-field-id' );
3172				// 	if( show_for != active_layer_id ) {
3173				// 		$( '.pewc-layer-' + layer_id ).fadeOut( 150 );
3174				// 	} else {
3175				// 		$( '.pewc-layer-' + layer_id ).fadeIn( 150 );
3176				// 	}
3177				// });
3178				// $( '.pewc-image-layer' ).not( '.pewc-layer-' + active_layer_id ).fadeOut( 250 );
3179				
3180
3181				// if( ! selected ) {
3182					$( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' ).addClass( 'here-' + parent_index + '-' + index ).trigger( 'click' );
3183					// selected = $( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' ).prop( 'checked' );
3184					$( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' ).trigger( 'change' );
3185					// if( selected ) {
3186						// $( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' ).prop( 'checked', false ).trigger( 'change' );
3187						// selected = $( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' ).prop( 'checked' );
3188						// $( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' ).addClass( 'here-' + parent_index + '-' + index ).trigger( 'click' );
3189						// selected = $( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' ).prop( 'checked' );
3190					// }
3191
3192				// }
3193				
3194			}
3195
3196		},
3197
3198		// If we've updated a child swatch, we need to ensure that other child swatches have the same value
3199		sync_children: function( e ) {
3200
3201			// Get the active parent index
3202			var parent_index = $( '.pewc-swatch-parent' ).find( '.pewc-radio-image-wrapper.checked input' ).attr( 'data-option-index' );
3203			var child_swatch = e.target;
3204			// Get the index of the selected child swatch
3205			var index = $( child_swatch ).closest( '.pewc-item' ).find( '.pewc-radio-image-wrapper.checked input' ).attr( 'data-option-index' );
3206			if( ! isNaN( index ) ) {
3207				// Ensure that all other child swatch fields have the same item selected
3208				$( '.pewc-swatch-child' ).find( '.pewc-radio-image-wrapper' ).removeClass( 'checked' );
3209				$( '.pewc-swatch-child' ).find( '.pewc-radio-image-wrapper-' + index ).addClass( 'checked' ).find( 'input' );
3210				// Need to ensure that the correct main image is displayed
3211				// Trigger a click on the currently visible selected swatch
3212				var input = $( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' );
3213				$( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' ).trigger( 'click' );
3214			}
3215
3216		},
3217
3218		check_if_src_hidden: function( $product_img ) {
3219			if ( $product_img.attr('data-pewc-from-field') != '' ) {
3220
3221				// main image is using an image from a field, check if the field where it came from is currently hidden. if so, put back the original main image
3222				var pewc_from_field = $( ".pewc-item."+$product_img.attr('data-pewc-from-field') );
3223
3224				if ( pewc_from_field.hasClass( 'pewc-hidden-field') || pewc_from_field.closest( '.pewc-group-wrap' ).hasClass( 'pewc-group-hidden') || ( pewc_from_field.hasClass( 'pewc-variation-dependent' ) && ! pewc_from_field.hasClass( 'active' ) ) ) {
3225					// field is hidden, reset image
3226					// 3.21.4, added variation-dependent fields
3227					//add_on_images.reset_main_image( $product_img );
3228					add_on_images.replace_main_with_default( $product_img ); // 3.24.7, let's try to find an active swatch first before resetting the main image
3229				}
3230			}
3231		},
3232
3233		reset_main_image: function ( $product_img ) {
3234			$product_img.attr( 'data-pewc-from-field', '' );
3235			$product_img.attr( 'src', $product_img.attr( 'data-pewc-old-src' ) );
3236			$product_img.attr( 'srcset', $product_img.attr( 'data-pewc-old-srcset' ) );
3237			$product_img.attr( 'data-src', $product_img.attr( 'data-pewc-old-data-src' ) ); // 3.13.3
3238			// photoswipe gallery
3239			$product_img.attr( 'data-large_image', $product_img.attr( 'data-pewc-old-data-large_image' ) );
3240			$product_img.attr( 'data-large_image_width', $product_img.attr( 'data-pewc-old-data-large_image_width' ) );
3241			$product_img.attr( 'data-large_image_height', $product_img.attr( 'data-pewc-old-data-large_image_height' ) );
3242			// zoom image
3243			var zoomImg = $product_img.closest( pewc_vars.product_img_wrap ).find( pewc_vars.product_img_zoom ).eq(0);
3244			if ( zoomImg ) {
3245				zoomImg.attr( pewc_vars.product_img_zoom_src, $product_img.attr( 'data-pewc-old-zoom' ) );
3246			}
3247		},
3248
3249		replace_main_with_default: function( $product_img='', is_layered=true ) {
3250			// 3.17.2
3251			var replace_fields = [ 'image_swatch', 'select-box', 'checkbox' ];
3252			var replaced = false;
3253
3254			$( '.pewc-item' ).each( function( index, element ) {
3255				// 3.20.1
3256				var layered_image = $(this).hasClass( 'pewc-layered-image' );
3257
3258				// Replace main image is not active for this field, skip
3259				// 3.27.2, added ! layered_image condition, so that layer images work even if they don't enable Replace main image on the field setting
3260				if ( ! add_on_images.replace_image( $(this) ) && ! layered_image ) {
3261					return;
3262				}
3263
3264				// 3.25.4, skip layered images when resetting normal swatch fields?
3265				if ( layered_image && ! is_layered ) {
3266					return;
3267				}
3268
3269				// Main image has been replaced, we can skip
3270				// 3.20.1, don't skip if this is a layered image
3271				if ( replaced && ! layered_image ) {
3272					return;
3273				}
3274
3275				// Ignore fields in hidden groups
3276				if ( $( this ).closest( '.pewc-group-wrap' ).hasClass( 'pewc-group-hidden' ) ) {
3277					return; 
3278				}
3279
3280				// Ignore hidden variation-dependent fields and hidden fields
3281				if( ( $( this ).hasClass( 'pewc-variation-dependent' ) && ! $( this ).hasClass( 'active' ) ) || $( this ).hasClass( 'pewc-hidden-field' ) ) {
3282					return;
3283				}
3284
3285				if ( replace_fields.indexOf( $( this ).attr( 'data-field-type' ) ) > -1 && $( this ).attr( 'data-field-value' ) != '' ) {
3286					// 3.22.1, replaced data-default value with data-field-value in the condition so that the main image is also replaced when editing add-ons via Edit options on the cart
3287					var field_type = $( this ).attr( 'data-field-type' );
3288					if ( field_type  == 'image_swatch' ) {
3289						// find the first checked input, that must be the default
3290						$( this ).find( '.pewc-radio-form-field' ).each( function( index, element ){
3291							// 3.20.1, allow multiple layered images with default values
3292							if ( $( this ).is( ':checked' ) && ( ! replaced || layered_image ) ) {
3293								// 3.26.15, only replace if option has an image
3294								if ( $( this ).closest( '.pewc-radio-image-wrapper' ).find( 'img' ).attr( 'data-src' ) ) {
3295									add_on_images.update_add_on_image( $( this ), $(this).closest( 'form' ) );
3296									replaced = true;
3297									return;
3298								}
3299							}
3300						});
3301					} else if ( field_type == 'checkbox' ) {
3302						if ( $( this ).find( '.pewc-form-field' ).is( ':checked' ) && $( this ).find( '.pewc-item-field-image-wrapper' ).length > 0 ) {
3303							// 4.3.0, only do this if checkbox has an image, prevent an infinite loop
3304							add_on_images.update_add_on_image( $( this ).find( '.pewc-form-field' ), $(this).closest( 'form' ) );
3305							replaced = true;
3306							return;
3307						}
3308					} else if ( field_type == 'select-box' ) {
3309						add_on_images.update_add_on_image( $( this ).find( 'select.pewc-form-field' ), $(this).closest( 'form' ) );
3310						replaced = true;
3311						return;
3312					}
3313				}
3314			});
3315
3316			// 3.24.7, if we didn't find a swatch, reset the main image
3317			if ( ! replaced && $product_img != '' ) {
3318				add_on_images.reset_main_image( $product_img );
3319			}
3320		},
3321
3322	}
3323
3324	add_on_images.init();
3325
3326	var tooltips = {
3327
3328		init: function() {
3329
3330			if( pewc_vars.enable_tooltips == 'yes' && ! pewc_vars.dequeue_tooltips ) {
3331				$( '.tooltip' ).tooltipster(
3332					{
3333						theme: 'tooltipster-shadow',
3334		        		side: 'right',
3335						contentAsHTML: pewc_vars.contentAsHTML,
3336						autoClose : pewc_vars.autoClose,
3337						interactive : pewc_vars.interactive,
3338						hideOnClick : pewc_vars.hideOnClick,
3339						trigger : pewc_vars.trigger,
3340						triggerOpen : pewc_vars.triggerOpen,
3341						triggerClose: pewc_vars.triggerClose
3342					}
3343				);
3344			}
3345
3346		}
3347
3348	}
3349
3350	tooltips.init();
3351
3352	var quickview = {
3353
3354		init: function() {
3355			$( 'body' ).on( 'click', '.pewc-show-quickview', this.show_quickview );
3356			$( 'body' ).on( 'click', '#pewc-quickview-background, .pewc-close-quickview', this.hide_quickview );
3357		},
3358
3359		show_quickview: function( e ) {
3360			e.stopPropagation();
3361			if( pewc_vars.quickview == 'yes' ) {
3362				// Open the link in a new tab
3363				e.preventDefault();
3364				$( 'body' ).addClass( 'pewc-quickview-active' );
3365			}
3366			
3367			// $( '.pewc-quickview-product-wrapper' ).hide();
3368			$( '#pewc-quickview-' + $(this).closest( 'li.pewc-item' ).attr( 'data-id' ) + '_' + $( this ).attr( 'data-child-product-id' ) ).css( 'left', '50%' );
3369		},
3370
3371		hide_quickview: function( e ) {
3372			 e.preventDefault();
3373			 $( 'body' ).removeClass( 'pewc-quickview-active' );
3374			 $( '.pewc-quickview-product-wrapper' ).css( 'left', '-5000px' );
3375		}
3376
3377	}
3378
3379	quickview.init();
3380
3381	var check_time = {
3382
3383		interval_id: null,
3384
3385		init: function() {
3386			var today = new Date();
3387			var loaded = $( '.pewc-cl-wrapper' ).first().attr( 'data-today' );
3388			today.setHours(0,0,0,0);
3389			if( today > loaded ) {
3390				$( '.pewc-cl-wrapper' ).addClass( 'disabled' );
3391				$( '.pewc-cl-wrapper' ).find( '.pewc-radio-form-field' ).prop( 'disabled', true );
3392			}
3393			// check_time.check();
3394			check_time.interval_id = setInterval(
3395				function() {
3396					check_time.check();
3397				},
3398				5000
3399			);
3400			$( '.pewc-cl-wrapper' ).find( 'input' ).on( 'change', this.update_date );
3401
3402			// Auto-select the default option in each calendar list field so that
3403			// calculations using {field_XXX_option_price} have a value on page load.
3404			// data-default-value holds the day offset (e.g. "6"), matching data-offset on each radio.
3405			$( 'form.cart .pewc-item-calendar-list' ).each( function() {
3406				var $field = $( this );
3407				if ( $field.find( 'input[type=radio]:checked' ).length === 0 ) {
3408					var default_val = $field.attr( 'data-default-value' );
3409					var $enabled = $field.find( '.pewc-cl-wrapper:not(.disabled) input[type=radio]:enabled' );
3410					var $target = ( default_val !== '' && default_val !== undefined )
3411						? $enabled.filter( '[data-offset="' + default_val + '"]' )
3412						: $();
3413					if ( ! $target.length ) {
3414						$target = $enabled.first();
3415					}
3416					if ( $target.length ) {
3417						$target.prop( 'checked', true ).trigger( 'change' );
3418					}
3419				}
3420			} );
3421		},
3422
3423		check: function() {
3424			$( '.pewc-cl-has-time' ).each( function() {
3425				var hour = $( this ).attr( 'data-hour' );
3426				var min = $( this ).attr( 'data-minute' );
3427				if( ! hour || ! min ) {
3428					return;
3429				}
3430				if( check_time.is_after( hour, min ) ) {
3431					clearInterval( check_time.interval_id );
3432					var now = new Date();
3433					var client_minutes = now.getHours() * 60 + now.getMinutes();
3434					var url = new URL( window.location.href );
3435					url.searchParams.set( 'pewc_client_minutes', client_minutes );
3436					window.location.replace( url.toString() );
3437					return false; // Break out of .each()
3438				}
3439			});
3440		},
3441
3442		is_after: function( hour, min ) {
3443			let ms_today = Date.now() - new Date().setHours(0,0,0,0);
3444			return ms_today > (hour*3.6e6 + min*6e4);
3445		},
3446
3447		update_date: function() {
3448			var field_id = $( this ).closest( '.pewc-item' ).attr( 'data-field-id' );
3449			var id = $( this ).closest( '.pewc-item' ).attr( 'data-id' );
3450			$( '#pewc_cl_' + field_id ).val( $( this ).attr( 'data-date' ) );
3451			$( '#pewc_cl_price_' + field_id ).val( $( this ).closest( '.pewc-item' ).attr( 'data-field-price' ) );
3452			$( '#pewc_cl_offset_' + id ).val( $( this ).attr( 'data-offset' ) );
3453		}
3454
3455	}
3456
3457	check_time.init();
3458
3459
3460})(jQuery);
3461
3462// 3.21.4, moved outside so that other scripts can use this function
3463function pewc_wc_price_without_currency( price ) {
3464
3465	var price_settings = {
3466		decimal: pewc_vars.decimal_separator,
3467		thousand: pewc_vars.thousand_separator,
3468		precision: pewc_vars.decimals,
3469		format: '%v'
3470	};
3471
3472	if ( pewc_vars.price_trim_zeros == 'yes' && price == parseInt( price ) ) {
3473		// 3.21.3, trim zeros if filter is active
3474		price_settings.precision = 0;
3475	}
3476
3477	// since 3.12.0
3478	price = accounting.formatMoney( price, price_settings );
3479
3480	return price;
3481
3482}
3483
3484// 3.21.4, moved outside so that other scripts can use this function
3485function pewc_wc_price( price, price_only=false, update_pewc_total_calc_price=true ) {
3486
3487	if ( update_pewc_total_calc_price ) {
3488		jQuery( '#pewc_total_calc_price' ).val( price ); // Used in Bookings for WooCommerce
3489	}
3490
3491	// since 3.12.0
3492	var currency_html = '<span class="woocommerce-Price-currencySymbol">%s</span>';
3493	var currency_format = '';
3494	if ( price_only ) {
3495		currency_html = '%s';
3496	}
3497
3498	if( pewc_vars.currency_pos == 'left' ) {
3499		currency_format = currency_html+'%v';
3500	} else if( pewc_vars.currency_pos == 'right' ) {
3501		currency_format = '%v'+currency_html;
3502	} else if( pewc_vars.currency_pos == 'left_space' ) {
3503		currency_format = currency_html+' %v';
3504	} else if( pewc_vars.currency_pos == 'right_space' ) {
3505		currency_format = '%v '+currency_html;
3506	}
3507
3508	var price_settings = {
3509		symbol: pewc_vars.currency_symbol,
3510		decimal: pewc_vars.decimal_separator,
3511		thousand: pewc_vars.thousand_separator,
3512		precision: pewc_vars.decimals,
3513		format: currency_format
3514	};
3515
3516	if ( pewc_vars.price_trim_zeros == 'yes' && price == parseInt( price ) ) {
3517		// 3.21.3, trim zeros if filter is active
3518		price_settings.precision = 0;
3519	}
3520
3521	price = accounting.formatMoney( price, price_settings );
3522
3523	if ( ! price_only ) {
3524		return '<span class="woocommerce-Price-amount amount"><bdi>' + price + '</bdi></span>';
3525	}
3526
3527	return price;
3528
3529}
3530
3531// 3.21.7
3532function pewc_wcfad_apply_discount() {
3533	return typeof pewc_wcfad !== 'undefined' && pewc_wcfad.apply_discount();
3534}
3535
3536// 3.27.0
3537function pewc_is_booking_product() {
3538
3539	return ( jQuery( '#num_units_int' ).length > 0 );
3540
3541}
3542
3543// 3.27.0, for compatibility with Bookings for WooCommerce
3544function pewc_get_quantity( qty=1, type='' ) {
3545
3546	if ( pewc_wcbvp_variation_grid() ) {
3547		// 4.1.1, return the total variations selected when using Better Variations grid mode
3548		qty = jQuery( '#wcbvp_total_variations' ).val();
3549		if ( qty < 1 ) qty = 1; // so that the add-on price updates even if no variations have been selected yet
3550	} else if( jQuery( 'form.cart .quantity .qty' ).val() && 'one-only' !== type ) {
3551		qty = jQuery( 'form.cart .quantity .qty' ).val();
3552	} else if ( pewc_is_booking_product() ) {
3553		// for Booking products, where the quantity field is not available
3554		qty = 1; // 3.27.11, changed to 1 so that "Price per booking unit" setting is respected. Previously jQuery( '#num_units_int' ).val();
3555		if ( jQuery( '#num_bookings' ).length > 0 && ! isNaN( jQuery( '#num_bookings' ).val() ) && 'linked' === type ) {
3556			// also multiply by quantity?
3557			qty = qty * jQuery( '#num_bookings' ).val();
3558		}
3559	}
3560
3561	return qty;
3562
3563}
3564
3565// 4.1.1, Better Variations grid mode
3566function pewc_wcbvp_variation_grid() {
3567	return ( jQuery( 'body' ).find( '.wcbvp-grid-quantity-field' ).length > 0 );
3568}
3569
3570// 4.3.3, separated into a function and moved here so that repeatable groups can access it
3571function pewc_accordion_click( header ){
3572	var is_open = jQuery( header ).closest( '.pewc-group-wrap' ).hasClass( 'group-active' );
3573
3574	if ( jQuery( header ).closest( '.pewc-group-wrap' ).hasClass( 'pewc-disabled-group') ) {
3575		return;
3576	}
3577	if( pewc_vars.close_accordion == 'yes' ) {
3578		jQuery( '.pewc-group-wrap' ).removeClass( 'group-active' );
3579	}
3580	// Don't reopen group if we've just closed it, only if close_accordion snippet is active
3581	if( ! is_open || pewc_vars.close_accordion != 'yes' ) {
3582		jQuery( header ).closest('.pewc-group-wrap').toggleClass('group-active');
3583	}
3584}

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.