PageSourceSearch

https://store.faithalone.org/wp-content/plugins/product-extras-for-woocommerce/assets/js/pewc.js?ver=4.5.2

js faithalone.org collected 2026-10-02 03:03:49 UTC 170,152 bytes, 3,856 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							// 4.3.19, per unit pricing (Bookings)
642							if ( $( this ).hasClass( 'pewc-per-unit-pricing' ) ) {
643								added_price = parseFloat( $('#num_units_int').val() ) * added_price;
644							}
645
646							// 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
647							if ( $( this ).hasClass( 'pewc-repeatable-field' ) && ! $( this ).hasClass( 'pewc-multiply-repeatable' ) ) {
648								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
649							} else {
650								total_price += added_price;
651							}
652
653						} else {
654
655							flat_rate_total += parseFloat( $(this).attr( 'data-price' ) );
656							var selected_option_price = checked_radio.attr( 'data-option-cost' );
657							$( this ).attr( 'data-selected-option-price', selected_option_price );
658							flat_rate_total += parseFloat( selected_option_price );
659
660						}
661					} else {
662						$( this ).attr( 'data-selected-option-price', 0 );
663					}
664
665					if( checked_radio.val() ) {
666						set_summary_panel_data( $( this ), checked_radio.val(), added_price );
667					} else {
668						set_summary_panel_data( $( this ), '', 0 );
669						$( this ).removeClass( 'pewc-active-field' ); // 3.21.4, moved here because set_summary_panel_data adds the class pewc-active-field
670					}
671
672				}
673
674			}
675
676		});
677
678		$('form.cart .pewc-item-select').each(function() {
679			var selected_option_price = $( this ).find( 'option:selected' ).attr( 'data-option-cost' );
680			$( this ).attr( 'data-selected-option-price', selected_option_price );
681		});
682
683		$('form.cart .pewc-item-checkbox_group').each(function() {
684
685			var field_value = [];
686			var selected_counter = 0;
687
688			if( ! $( this ).hasClass( 'pewc-variation-dependent' ) || ( $( this ).hasClass( 'pewc-variation-dependent' ) && $( this ).hasClass( 'active' ) ) ) {
689
690				var checkbox_group_id = $(this).attr( 'data-id' );
691				var checkbox_group_price = 0;
692				var group_wrap = $( this ).closest( '.pewc-group-wrap' );
693
694				if( ! $(this).hasClass('pewc-hidden-field') && ! group_wrap.hasClass( 'pewc-group-hidden' ) ) {
695					var checkbox_value = [];
696					if( ! $(this).hasClass('pewc-flatrate') ) {
697						// Get the field price
698						if( $("input[name='" + checkbox_group_id + "[]']:checked" ).val() ) {
699							checkbox_group_price += parseFloat( $(this).attr('data-price') );
700						}
701						$('.'+checkbox_group_id).find( $('input[type=checkbox]:checked') ).each( function() {
702							checkbox_group_price += parseFloat( $(this).attr('data-option-cost') );
703							checkbox_value.push( $( this ).val() );
704							selected_counter++;
705						});
706
707						// 4.3.19, per unit pricing (Bookings)
708						if ( $( this ).hasClass( 'pewc-per-unit-pricing' ) ) {
709							checkbox_group_price = parseFloat( $('#num_units_int').val() ) * checkbox_group_price;
710						}
711
712						total_price += checkbox_group_price;
713
714						// Summary panel
715						if( $("input[name='" + checkbox_group_id + "[]']:checked" ).val() ) {
716							$( this ).attr( 'data-field-price', checkbox_group_price );
717							$( this ).addClass( 'pewc-active-field' );
718							$( this ).attr( 'data-field-value', checkbox_value.join( ', ' ) );
719						}
720						else {
721							// remove from summary panel
722							$( this ).attr( 'data-field-price', 0 );
723							$( this ).removeClass( 'pewc-active-field' );
724							$( this ).attr( 'data-field-value', '' );
725						}
726
727					} else {
728
729						// Flat rate
730						if( $("input[name='" + checkbox_group_id + "[]']:checked" ).val() ) {
731							flat_rate_total += parseFloat( $(this).attr('data-price') );
732						}
733						$('.'+checkbox_group_id).find( $('input[type=checkbox]:checked') ).each( function() {
734							flat_rate_total += parseFloat( $(this).attr('data-option-cost') );
735							checkbox_value.push( $( this ).val() );
736							selected_counter++;
737						});
738
739						if ( checkbox_value.length > 0 ) {
740							$( this ).attr( 'data-field-value', checkbox_value.join( ', ' ) );
741						} else {
742							$( this ).attr( 'data-field-value', '' );
743						}
744					}
745				}
746
747			}
748
749			pewc_update_checkbox_field_counter( $(this), selected_counter );
750
751		});
752		$('form.cart .pewc-item-image-swatch-checkbox').each(function() {
753
754			var field_value = [];
755			var selected_counter = 0;
756
757			if( ! $( this ).hasClass( 'pewc-variation-dependent' ) || ( $( this ).hasClass( 'pewc-variation-dependent' ) && $( this ).hasClass( 'active' ) ) ) {
758
759				var checkbox_group_id = $(this).attr( 'data-id' );
760				var checkbox_group_price = 0;
761				var group_wrap = $( this ).closest( '.pewc-group-wrap' );
762
763				if( ! $(this).hasClass('pewc-hidden-field') && ! group_wrap.hasClass( 'pewc-group-hidden' ) ) {
764					var field_value = [];
765					if( ! $(this).hasClass('pewc-flatrate') ) {
766						// Get the field price
767						if( $("input[name='" + checkbox_group_id + "[]']:checked" ).val() ) {
768							checkbox_group_price += parseFloat( $(this).attr('data-price') );
769						}
770						$('.'+checkbox_group_id).find( $('input[type=checkbox]:checked') ).each( function() {
771							field_value.push( $( this ).val() );
772							checkbox_group_price += parseFloat( $(this).attr('data-option-cost') );
773							selected_counter++;
774						});
775						total_price += checkbox_group_price;
776					} else {
777						// Flat rate
778						if( $("input[name='" + checkbox_group_id + "[]']:checked" ).val() ) {
779							flat_rate_total += parseFloat( $(this).attr('data-price') );
780						}
781						$('.'+checkbox_group_id).find( $('input[type=checkbox]:checked') ).each( function(){
782							field_value.push( $( this ).val() );
783							flat_rate_total += parseFloat( $(this).attr('data-option-cost') );
784							selected_counter++;
785						});
786					}
787				}
788
789				if( field_value.length > 0 ) {
790					set_summary_panel_data( $( this ), field_value.join( ', ' ), checkbox_group_price );
791				} else {
792					$( this ).removeClass( 'pewc-active-field' );
793					set_summary_panel_data( $( this ), '', 0 );
794				}
795
796			}
797
798			pewc_update_checkbox_field_counter( $(this), selected_counter );
799
800		});
801
802		// Check child products with select layout
803		var child_products_total = 0;
804		$('form.cart .pewc-child-select-field').each(function() {
805
806			var field_wrapper = $( this ).closest( '.pewc-item' );
807			var field_value = [];
808			var is_hidden = $( this ).closest( '.pewc-item' ).hasClass( 'pewc-hidden-field' );
809			var is_dependent = ( $( this ).closest( '.pewc-item' ).hasClass( 'pewc-variation-dependent' ) ) && ( ! $( this ).closest( '.pewc-item' ).hasClass( 'active' ) );
810			if( ! is_hidden && ! is_dependent ) {
811				// If the select field has a value
812				if( $(this).val() && $(this).val() != '' ) {
813					field_value.push( $(this).find(':selected').attr( 'data-field-value' ) );
814					var selected = $(this).find(':selected');
815					var child_product_price = selected.data( 'option-cost' );
816					// 3.21.4, compatibility with FD
817					if ( parseFloat( selected.attr('data-wcfad-price') ) > 0 ) {
818						child_product_price = parseFloat( selected.attr('data-wcfad-price') );
819					}
820					var qty = 0;
821					if( child_product_price > 0 ) {
822						var wrapper = $(this).closest('.child-product-wrapper');
823						var quantities = $(wrapper).data('products-quantities');
824						// Get the quantity
825						if( quantities == 'linked' ) {
826							//qty = $('form.cart .quantity .qty').val();
827							// 3.27.0
828							qty = pewc_get_quantity( qty, 'linked' );
829						} else if( quantities == 'independent' ) {
830							// Find the child_quantity field
831							qty = $(wrapper).find('.pewc-child-quantity-field').val();
832							if ( pewc_vars.multiply_independent == 'yes' /*&& $('form.cart .quantity .qty').val() !== undefined*/ ) {
833								// 3.27.0
834								var main_quantity = pewc_get_quantity();
835								qty = qty * parseFloat( main_quantity );
836							}
837						} else if( quantities == 'one-only' ) {
838							qty = pewc_get_quantity( 1, 'one-only' );
839						}
840					}
841
842					child_products_total += parseFloat( child_product_price ) * parseFloat( qty );
843					if( field_value.length > 0 ) {
844						$( this ).closest( '.pewc-item' ).attr( 'data-field-price', child_products_total );
845						set_summary_panel_data( $( this ).closest( '.pewc-item' ), field_value.join( ', ' ), parseFloat( child_product_price ) * parseFloat( qty ) );
846					} else {
847						$( this ).closest( '.pewc-item' ).removeClass( 'pewc-active-field' );
848					}
849
850				}
851			}
852		});
853		$('form.cart .pewc-radio-images-wrapper.child-product-wrapper').each(function() {
854			var field_value = [];
855			var is_hidden = $( this ).closest( '.pewc-item' ).hasClass( 'pewc-hidden-field' );
856			var is_dependent = ( $( this ).closest( '.pewc-item' ).hasClass( 'pewc-variation-dependent' ) ) && ( ! $( this ).closest( '.pewc-item' ).hasClass( 'active' ) );
857			if( ! is_hidden && ! is_dependent ) {
858				var quantities = $(this).data('products-quantities');
859				var checked_radio = $(this).find('.pewc-radio-form-field:checked');
860				var radio_val = checked_radio.val();
861				if( radio_val && radio_val != undefined ) {
862					var child_product_price = checked_radio.data('option-cost');
863					// 3.21.4, compatibility with FD
864					if ( parseFloat( checked_radio.attr('data-wcfad-price') ) > 0 ) {
865						child_product_price = parseFloat( checked_radio.attr('data-wcfad-price') );
866					}
867					var qty = 0;
868					// sometimes child_product_price is zero if it's discounted
869
870					// Get the quantity
871					if( quantities == 'linked' ) {
872						//qty = $('form.cart .quantity .qty').val();
873						// 3.27.0
874						qty = pewc_get_quantity( qty, 'linked' );
875					} else if( quantities == 'independent' ) {
876						// Find the child_quantity field
877						qty = $(this).closest('.pewc-item-field-wrapper').find('.pewc-child-quantity-field').val();
878						if ( pewc_vars.multiply_independent == 'yes' /*&& $('form.cart .quantity .qty').val() !== undefined*/ ) {
879							// 3.27.0
880							var main_quantity = pewc_get_quantity();
881							qty = qty * parseFloat( main_quantity );
882						}
883					} else if( quantities == 'one-only' ) {
884						qty = pewc_get_quantity( 1, 'one-only' );
885					}
886
887					child_products_total += parseFloat( child_product_price ) * parseFloat( qty );
888
889					if( child_products_total > 0 || qty > 0 ) {
890						$( this ).closest( '.pewc-item' ).attr( 'data-field-price', child_products_total );
891						set_summary_panel_data( $( this ).closest( '.pewc-item' ), checked_radio.attr( 'data-field-label' ), parseFloat( child_product_price ) * parseFloat( qty ) );
892					}
893
894				} else {
895					$( this ).closest( '.pewc-item' ).removeClass( 'pewc-active-field' );
896					$( this ).closest( '.pewc-item' )
897						.attr( 'data-field-price', 0 )
898						.attr( 'data-field-value', '' ); // 3.21.4, reset price and value
899				}
900
901			}
902		});
903
904		// 3.25.3, added form.cart .pewc-components-wrapper.child-product-wrapper
905		$( 'form.cart .pewc-checkboxes-images-wrapper.child-product-wrapper, form.cart .pewc-components-wrapper.child-product-wrapper' ).each(function() {
906
907			var this_child_total = 0;
908			var field_value = [];
909			var selected_counter = 0;
910			var is_hidden = $( this ).closest( '.pewc-item' ).hasClass( 'pewc-hidden-field' );
911			var is_dependent = ( $( this ).closest( '.pewc-item' ).hasClass( 'pewc-variation-dependent' ) ) && ( ! $( this ).closest( '.pewc-item' ).hasClass( 'active' ) );
912
913			if( ! is_hidden && ! is_dependent ) {
914				var quantities = $(this).data('products-quantities');
915				// Run through each selected checkbox
916
917				$( this ).closest( '.pewc-item' ).removeClass( 'pewc-active-field' );
918
919				// 4.5.0, 'Select All' option: use the flat Select All price instead of summing individual checkboxes
920				var select_all_field = $( this ).find( '.pewc-select-all-form-field:checked' );
921
922				if( select_all_field.length > 0 ) {
923
924					var select_all_price = parseFloat( select_all_field.data( 'select-all-price' ) ) || 0;
925					var qty = 0;
926
927					if( quantities == 'linked' ) {
928						qty = pewc_get_quantity( qty, 'linked' );
929					} else if( quantities == 'one-only' ) {
930						qty = pewc_get_quantity( 1, 'one-only' );
931					}
932
933					child_products_total += select_all_price * parseFloat( qty );
934					this_child_total += select_all_price * parseFloat( qty );
935					field_value.push( select_all_field.attr( 'data-field-label' ) );
936
937					selected_counter = $( this ).find('.pewc-checkbox-form-field:checkbox').length;
938
939				} else {
940
941					$( this ).find('.pewc-checkbox-form-field:checkbox:checked').each(function() {
942						field_value.push( $( this ).attr( 'data-field-label' ) );
943						var child_product_price = $(this).data('option-cost');
944						// 3.21.4, compatibility with FD
945						if ( parseFloat( $(this).attr('data-wcfad-price') ) > 0 ) {
946							child_product_price = parseFloat( $(this).attr('data-wcfad-price') );
947						}
948						var qty = 0;
949
950						// Get the quantity
951						if( quantities == 'linked' ) {
952							//qty = $('form.cart .quantity .qty').val();
953							// 3.27.0
954							qty = pewc_get_quantity( qty, 'linked' );
955							selected_counter++;
956						} else if( quantities == 'independent' ) {
957							qty = $(this).closest('.pewc-checkbox-wrapper').find('.pewc-child-quantity-field').val();
958							selected_counter += parseInt( qty );
959							if ( pewc_vars.multiply_independent == 'yes' /*&& $('form.cart .quantity .qty').val() !== undefined*/ ) {
960								// 3.27.0
961								var main_quantity = pewc_get_quantity();
962								qty = qty * parseFloat( main_quantity );
963							}
964						} else if( quantities == 'one-only' ) {
965							qty = pewc_get_quantity( 1, 'one-only' );
966							selected_counter++;
967						}
968
969						if( child_product_price > 0 ) {
970							child_products_total += parseFloat( child_product_price ) * parseFloat( qty );
971							this_child_total += parseFloat( child_product_price ) * parseFloat( qty );
972						}
973
974					});
975
976				}
977
978				if( field_value.length > 0 ) {
979					$( this ).closest( '.pewc-item' ).attr( 'data-field-price', child_products_total );
980					set_summary_panel_data( $( this ).closest( '.pewc-item' ), field_value.join( ', ' ), this_child_total );
981				}
982
983			}
984
985			pewc_update_checkbox_field_counter( $( this ).closest( '.pewc-item' ), selected_counter );
986
987		});
988
989		// reset products column first
990		$('form.cart .pewc-item-products-column').each(function(){
991			$(this).removeClass('pewc-active-field');
992			$(this).attr('data-field-price', 0);
993			$(this).attr('data-field-value', '');
994			pewc_update_checkbox_field_counter( $(this), 0 );
995		});
996		$('form.cart .pewc-column-wrapper .pewc-variable-child-product-wrapper.checked').each(function() {
997			var field_value = [];
998			var field_wrapper = $( this ).closest( '.pewc-item' );
999			var parent_field_value = field_wrapper.attr('data-field-value');
1000			if ( parent_field_value != 0 && parent_field_value != '') {
1001				field_value = parent_field_value.split(', ');
1002			}
1003			var parent_field_price = parseFloat( field_wrapper.attr('data-field-price') );
1004			var selected_counter = parseInt ( field_wrapper.attr( 'data-field-selected-counter' ) );
1005			var is_hidden = field_wrapper.hasClass( 'pewc-hidden-field' );
1006			var is_dependent = ( field_wrapper.hasClass( 'pewc-variation-dependent' ) ) && ( ! field_wrapper.hasClass( 'active' ) );
1007
1008			if( ! is_hidden && ! is_dependent ) {
1009				var quantities = $(this).closest( '.pewc-column-wrapper' ).data('products-quantities');
1010				// Run through each selected checkbox for variable child products
1011
1012				field_wrapper.removeClass( 'pewc-active-field' );
1013
1014				$(this).find('.pewc-variable-child-select').each(function() {
1015					field_value.push( $( this ).find('option:selected').text() );
1016					var child_product_price = $(this).find(':selected').data('option-cost');
1017					// 3.21.4, compatibility with FD
1018					if ( parseFloat( $(this).find(':selected').attr('data-wcfad-price') ) > 0 ) {
1019						child_product_price = parseFloat( $(this).find(':selected').attr('data-wcfad-price') );
1020					}
1021					var qty = 0;
1022
1023					// Get the quantity
1024					if( quantities == 'linked' ) {
1025						//qty = $('form.cart .quantity .qty').val();
1026						// 3.27.0
1027						qty = pewc_get_quantity( qty, 'linked' );
1028						selected_counter++;
1029					} else if( quantities == 'independent' ) {
1030						qty = $(this).closest('.pewc-checkbox-image-wrapper').find('.pewc-child-quantity-field').val();
1031						s
1031elected_counter += parseInt( qty );
1032						if ( pewc_vars.multiply_independent == 'yes' /*&& $('form.cart .quantity .qty').val() !== undefined*/ ) {
1033							// 3.27.0
1034							var main_quantity = pewc_get_quantity();
1035							qty = qty * parseFloat( main_quantity );
1036						}
1037					} else if( quantities == 'one-only' ) {
1038						qty = pewc_get_quantity( 1, 'one-only' );
1039						selected_counter++;
1040					}
1041
1042					if( child_product_price > 0 ) {
1043						child_products_total += parseFloat( child_product_price ) * parseFloat( qty );
1044						parent_field_price += parseFloat( child_product_price ) * parseFloat( qty );
1045					}
1046
1047					if( field_value.length > 0 ) {
1048						field_wrapper.attr( 'data-field-price', parent_field_price );
1049						set_summary_panel_data( field_wrapper, field_value.join( ', ' ), parent_field_price );
1050					}
1051
1052				});
1053
1054				// 4.3.5, for column layout with attributes select
1055				if ( $( this ).find( '.pewc-column-attributes-select' ).length > 0 ) {
1056					var child_id = $( this ).data( 'option-id' );
1057					var child_variant = $( this ).find( 'input[name="pewc_child_variants_' + child_id + '"]' );
1058					field_value.push( child_variant.attr( 'data-variation-name' ) );
1059					var child_product_price = child_variant.attr( 'data-option-cost' );
1060					// not yet supported, maybe add later
1061					//if ( parseFloat( $(this).find(':selected').attr('data-wcfad-price') ) > 0 ) {
1062					//	child_product_price = parseFloat( $(this).find(':selected').attr('data-wcfad-price') );
1063					//}
1064					var qty = 0;
1065
1066					// Get the quantity
1067					if( quantities == 'linked' ) {
1068						qty = pewc_get_quantity( qty, 'linked' );
1069						selected_counter++;
1070					} else if( quantities == 'independent' ) {
1071						qty = $(this).find( '.pewc-child-quantity-field' ).val();
1072						selected_counter += parseInt( qty );
1073						if ( pewc_vars.multiply_independent == 'yes' ) {
1074							var main_quantity = pewc_get_quantity();
1075							qty = qty * parseFloat( main_quantity );
1076						}
1077					} else if( quantities == 'one-only' ) {
1078						qty = pewc_get_quantity( 1, 'one-only' );
1079						selected_counter++;
1080					}
1081
1082					if( child_product_price > 0 ) {
1083						child_products_total += parseFloat( child_product_price ) * parseFloat( qty );
1084						parent_field_price += parseFloat( child_product_price ) * parseFloat( qty );
1085					}
1086
1087					if( field_value.length > 0 ) {
1088						field_wrapper.attr( 'data-field-price', parent_field_price );
1089						set_summary_panel_data( field_wrapper, field_value.join( ', ' ), parent_field_price );
1090					}
1091				}
1092
1093			}
1094
1095			pewc_update_checkbox_field_counter( field_wrapper, selected_counter );
1096
1097		});
1098		$('form.cart .pewc-column-wrapper .pewc-simple-child-product-wrapper.checked').each(function() {
1099			var field_value = [];
1100			var field_wrapper = $( this ).closest( '.pewc-item' );
1101			var parent_field_value = field_wrapper.attr('data-field-value');
1102			if ( parent_field_value != 0 && parent_field_value != '') {
1103				field_value = parent_field_value.split(', ');
1104			}
1105			var parent_field_price = parseFloat( field_wrapper.attr('data-field-price') );
1106			var selected_counter = parseInt ( field_wrapper.attr( 'data-field-selected-counter' ) );
1107			var is_hidden = field_wrapper.hasClass( 'pewc-hidden-field' );
1108			var is_dependent = ( field_wrapper.hasClass( 'pewc-variation-dependent' ) ) && ( ! field_wrapper.hasClass( 'active' ) );
1109
1110			if( ! is_hidden && ! is_dependent ) {
1111				var quantities = $(this).closest( '.pewc-column-wrapper' ).data('products-quantities');
1112
1113				field_wrapper.removeClass( 'pewc-active-field' );
1114
1115				// Run through each selected checkbox
1116				$(this).find('.pewc-checkbox-form-field').each(function(){
1117					field_value.push( $( this ).attr( 'data-field-label' ) );
1118					var child_product_price = $(this).data('option-cost');
1119					// 3.21.4, compatibility with FD
1120					if ( parseFloat( $(this).attr('data-wcfad-price') ) > 0 ) {
1121						child_product_price = parseFloat( $(this).attr('data-wcfad-price') );
1122					}
1123					var qty = 0;
1124
1125					// Get the quantity
1126					if( quantities == 'linked' ) {
1127						//qty = $('form.cart .quantity .qty').val();
1128						// 3.27.0
1129						qty = pewc_get_quantity( qty, 'linked' );
1130						selected_counter++;
1131					} else if( quantities == 'independent' ) {
1132						qty = $(this).closest('.pewc-simple-child-product-wrapper').find('.pewc-child-quantity-field').val();
1133						selected_counter += parseInt( qty );
1134						if ( pewc_vars.multiply_independent == 'yes' /*&& $('form.cart .quantity .qty').val() !== undefined*/ ) {
1135							// 3.27.0
1136							var main_quantity = pewc_get_quantity();
1137							qty = qty * parseFloat( main_quantity );
1138						}
1139					} else if( quantities == 'one-only' ) {
1140						qty = pewc_get_quantity( 1, 'one-only' );
1141						selected_counter++;
1142					}
1143
1144					if( child_product_price > 0 ) {
1145						child_products_total += parseFloat( child_product_price ) * parseFloat( qty );
1146						parent_field_price += parseFloat( child_product_price ) * parseFloat( qty );
1147					}
1148
1149					if( field_value.length > 0 ) {
1150						field_wrapper.attr( 'data-field-price', parent_field_price );
1151						set_summary_panel_data( field_wrapper, field_value.join( ', ' ), parent_field_price );
1152					}
1153
1154				});
1155
1156			}
1157
1158			pewc_update_checkbox_field_counter( field_wrapper, selected_counter );
1159
1160		});
1161
1162		// reset products swatches first
1163		$('form.cart .pewc-item-products-swatches').each(function(){
1164			$(this).removeClass('pewc-active-field');
1165			$(this).attr('data-field-price', 0);
1166			$(this).attr('data-field-value', '');
1167		});
1168		$('form.cart .pewc-swatches-wrapper .pewc-child-variation-main').each(function() {
1169			var field_value = [];
1170			var parent_field_value = $( this ).closest( '.pewc-item' ).attr('data-field-value');
1171			if ( parent_field_value != 0 && parent_field_value != '') {
1172				field_value = parent_field_value.split(', ');
1173			}
1174			var parent_field_price = parseFloat( $( this ).closest( '.pewc-item' ).attr('data-field-price') );
1175			var is_hidden = $( this ).closest( '.pewc-item' ).hasClass( 'pewc-hidden-field' );
1176			var is_dependent = ( $( this ).closest( '.pewc-item' ).hasClass( 'pewc-variation-dependent' ) ) && ( ! $( this ).closest( '.pewc-item' ).hasClass( 'active' ) );
1177			if( ! is_hidden && ! is_dependent ) {
1178
1179				var quantities = $(this).closest( '.pewc-swatches-wrapper' ).data('products-quantities');
1180
1181				// Run through each selected variation product
1182				$(this).find('.pewc-child-name input').each(function() {
1183					var child_product_price = parseFloat( $(this).attr( 'data-option-cost' ) );
1184					// 3.21.4, compatibility with FD
1185					if ( parseFloat( $(this).attr('data-wcfad-price') ) > 0 ) {
1186						child_product_price = parseFloat( $(this).attr('data-wcfad-price') );
1187					}
1188					var qty = 0;
1189					if( child_product_price > 0 && $(this).is( ':checked' ) ) {
1190						// Get the quantity
1191						// 3.21.4, added is :checked, only consider selected child product
1192						if( quantities == 'linked' ) {
1193							//qty = $('form.cart .quantity .qty').val();
1194							// 3.27.0
1195							qty = pewc_get_quantity( qty, 'linked' );
1196						} else if( quantities == 'independent' ) {
1197							qty = $(this).closest('.pewc-child-variation-main').find('.pewc-child-quantity-field').val();
1198							if ( pewc_vars.multiply_independent == 'yes' /*&& $('form.cart .quantity .qty').val() !== undefined*/ ) {
1199								// 3.27.0
1200								var main_quantity = pewc_get_quantity();
1201								qty = qty * parseFloat( main_quantity );
1202							}
1203						} else if( quantities == 'one-only' ) {
1204							qty = pewc_get_quantity( 1, 'one-only' );
1205						}
1206					}
1207					if ( qty < 1 ) {
1208						return; // quantity is zero, so ignore this field
1209					}
1210					field_value.push( $( this ).attr( 'data-field-label' ) );
1211					child_products_total += parseFloat( child_product_price ) * parseFloat( qty );
1212					parent_field_price += parseFloat( child_product_price ) * parseFloat( qty );
1213
1214					if( field_value.length > 0 ) {
1215						$( this ).closest( '.pewc-item' ).attr( 'data-field-price', parent_field_price );
1216						set_summary_panel_data( $( this ).closest( '.pewc-item' ), field_value.join( ', ' ), parent_field_price );
1217					}
1218				});
1219
1220			}
1221
1222		});
1223		$('form.cart .grid-layout').each( function() {
1224
1225			var is_hidden = $( this ).closest( '.pewc-item' ).hasClass( 'pewc-hidden-field' );
1226			var is_hidden_group = $( this ).closest( '.pewc-group-wrap' ).hasClass( 'pewc-group-hidden' );
1227			var is_dependent = ( $( this ).closest( '.pewc-item' ).hasClass( 'pewc-variation-dependent' ) ) && ( ! $( this ).closest( '.pewc-item' ).hasClass( 'active' ) );
1228			if( ! is_hidden && ! is_hidden_group && ! is_dependent ) {
1229				var child_product_price = parseFloat( $( this ).closest( '.pewc-item' ).attr( 'data-
1229price' ) );
1230				child_products_total += parseFloat( child_product_price );
1231			}
1232
1233		});
1234
1235		if( product_price < 0 ) product_price = 0;
1236
1237		// Summary panel rows
1238
1239		// Summary panel for add-on groups
1240		$( '.pewc-summary-panel-group-row' ).addClass( 'pewc-summary-panel-field-row-inactive' );
1241
1242		$( '.pewc-group-wrap' ).not( '.pewc-group-hidden' ).each( function() {
1243			var group_id = $( this ).attr( 'data-group-id' );
1244			$( '.pewc-summary-panel-group-'+group_id ).removeClass( 'pewc-summary-panel-field-row-inactive' );
1245		});
1246
1247		// Summary panel for add-on fields
1248		$( '.pewc-summary-panel-field-row' ).addClass( 'pewc-summary-panel-field-row-inactive' );
1249
1250		// 3.26.14, added .pewc-hidden-calculation to the not() selector so that hidden Calculation fields are not displayed on the Summary panel
1251		$( '.pewc-active-field' ).not( '.pewc-hidden-field, .pewc-hidden-calculation' ).each( function() {
1252			var field_id = $( this ).attr( 'data-field-id' );
1253			var field_type = $( '.pewc-field-' + field_id ).attr( 'data-field-type' );
1254			$( '#pewc-summary-row-' + field_id ).removeClass( 'pewc-summary-panel-field-row-inactive' ).addClass( 'pewc-field-' + field_type );
1255			var field_price = parseFloat( $( this ).attr( 'data-field-price' ) );
1256			if( field_price ) {
1257				field_price = field_price.toFixed( pewc_vars.decimals );
1258			}
1259
1260			var field_label = $( this ).attr( 'data-field-label' );
1261			var field_value;
1262			if( $( this ).attr( 'data-field-type') != 'checkbox' ) {
1263				field_value = $( this ).attr( 'data-field-value' );
1264			}
1265			$( '#pewc-summary-row-' + field_id ).find( '.pewc-summary-panel-product-name' ).text( field_label );
1266			$( '#pewc-summary-row-' + field_id ).find( '.pewc-summary-panel-product-value' ).text( field_value );
1267			$( '#pewc-summary-row-' + field_id ).find( '.pewc-summary-panel-price' ).html( pewc_wc_price( field_price ) );
1268		});
1269
1270		var qty = 1;
1271		// 3.27.0, we use 'linked' so that add-ons are multiplied per day and per num_bookings (quantity)?
1272		qty = pewc_get_quantity( qty, 'linked' );
1273
1274		// See if we need to apply a discount to the add-ons care of Dynamic Pricing and Discount Rules
1275		// Updated on 3.21.4
1276		orig_total_price = total_price; // 3.21.7, for DPDR
1277		if ( pewc_wcfad_apply_discount() ) {
1278			total_price = pewc_wcfad.adjust_price( total_price );
1279			if ( repeatable_prices > 0 ) {
1280				repeatable_prices = pewc_wcfad.adjust_price( repeatable_prices ); // 3.26.7
1281			}
1282		}
1283
1284		// Summary panel subtotal (3.9.8)
1285		// 4.3.20, commented out, the total_price (add-on prices) here is not multiplied by the quantity. Maybe just use the grand_total (later below) for the summary subtotal?
1286		//var subtotal = parseFloat( child_products_total ) + parseFloat( total_price ) + parseFloat( qty * product_price );
1287		//if( ! isNaN( subtotal ) ) {
1288		//	$( '#pewc-summary-panel-subtotal' ).html( pewc_wc_price( subtotal.toFixed(pewc_vars.decimals) ) );
1289		//}
1290
1291		var total_grid_variations = $( '#pewc-grid-total-variations' ).val();
1292
1293		// 3.27.0, for Booking products, product_price already includes "qty" (num_units), no need to multiply again
1294		// 4.1.1, also skip for variable products using Better Variations grid mode
1295		if ( ! pewc_is_booking_product() && ! pewc_wcbvp_variation_grid() ) {
1296			var product_price = qty * product_price;
1297		}
1298
1299		var grand_total = product_price;
1300		var orig_grand_total = qty * orig_product_price; // 3.21.7, for DPDR
1301		base_price = product_price;
1302		product_price = product_price.toFixed(pewc_vars.decimals);
1303		product_price = pewc_wc_price( product_price );
1304		product_price = add_price_suffix( product_price, base_price );
1305		$('#pewc-per-product-total').html( product_price );
1306
1307		total_price = qty * total_price;
1308		orig_total_price = qty * orig_total_price; // 3.21.7, for DPDR
1309
1310		// 3.26.7, we have a separate variable for repeatable field prices in case we dont want them multiplied with quantity
1311		if ( repeatable_prices > 0 ) {
1312			total_price += repeatable_prices;
1313			orig_total_price += repeatable_prices;
1314		}
1315
1316		// Multiply add-ons by number of variations in bulk grid
1317		// 2.7.1, added > 0 to the condition so that option total doesn't become 0 if no variations are selected
1318		if( total_grid_variations > 0 ) {
1319			total_price = total_grid_variations * total_price;
1320		}
1321		total_price += child_products_total;
1322		grand_total += total_price;
1323		orig_grand_total += orig_total_price; // 3.21.7, for DPDR
1324
1325		if( ! isNaN( total_price ) ) {
1326			var base_total_price = total_price;
1327			total_price = total_price.toFixed(pewc_vars.decimals);
1328			total_price = pewc_wc_price( total_price );
1329			total_price = add_price_suffix( total_price, base_total_price );
1330			$('#pewc-options-total').html( total_price );
1331		}
1332
1333		if( flat_rate_total < 0 ) flat_rate_total = 0;
1334		base_flat_rate_total = flat_rate_total;
1335		grand_total += flat_rate_total;
1336		flat_rate_total = flat_rate_total.toFixed(pewc_vars.decimals);
1337		flat_rate_total = pewc_wc_price( flat_rate_total );
1338		flat_rate_total = add_price_suffix( flat_rate_total, base_flat_rate_total );
1339		$('#pewc-flat-rate-total').html( flat_rate_total );
1340
1341		// Set the product price using a calculation field
1342		// 3.13.3 added 2nd condition to apply only calculated price if at least 1 calculation field is not hidden
1343		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 ) {
1344			if ( $('input[name="pewc_calc_set_price"]').length > 1 ) {
1345				// 3.17.2, compatibility with Product Table Ultimate
1346				// find the first non-hidden total
1347				var new_grand_total = 0;
1348				$('input[name="pewc_calc_set_price"]').each(function(){
1349					if ( $(this).attr( 'data-calc-set' ) == 1 && $(this).closest( '.pewc-product-extra-groups-wrap' ).is( ':visible' ) ) {
1350						new_grand_total = parseFloat( $(this).closest( '.pewc-product-extra-groups-wrap' ).find('input[name="pewc_calc_set_price"][data-calc-set="1"]').val() );
1351					}
1352				});
1353				if ( new_grand_total > 0 ) {
1354					grand_total = new_grand_total;
1355				}
1356			} else {
1357				// single product page
1358				grand_total = parseFloat( $( '#pewc_calc_set_price').val() );
1359			}
1360
1361			// 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
1362			// we copy it here before the possible DPDR discount below
1363			orig_grand_total = grand_total;
1364
1365			if ( $('form.cart .quantity .qty').length > 0 ) {
1366
1367				// 3.12.0, apply dynamic pricing if it exists
1368				if ( pewc_wcfad_apply_discount() ) {
1369					grand_total = pewc_wcfad.adjust_price( grand_total );
1370				}
1371
1372				// 3.11.6 multiply product price by quantity
1373				grand_total = grand_total * parseFloat( $('form.cart .quantity .qty').val() );
1374				// 4.3.2, for DPDR
1375				orig_grand_total = orig_grand_total * parseFloat( $('form.cart .quantity .qty').val() );
1376
1377			}
1378		}
1379
1380		if( ! isNaN( grand_total ) ) {
1381			if ( isNaN( orig_grand_total ) || orig_grand_total == grand_total ) {
1382				orig_grand_total = ''; // 3.21.7, let's clear this so that we know we don't need it
1383			}
1384
1385			var base_price = grand_total;
1386			grand_total = grand_total.toFixed( pewc_vars.decimals );
1387			grand_total = pewc_wc_price( grand_total );
1388
1389			// 4.3.20, added here, grand_total formatted already
1390			$( '#pewc-summary-panel-subtotal' ).html( grand_total );
1391
1392			if( pewc_vars.update_price == 'yes' ) {
1393				update_product_price( grand_total, base_price, orig_grand_total );
1394			}
1395			grand_total = add_price_suffix( grand_total, base_price );
1396			$('#pewc-grand-total').html( grand_total );
1397			if ( $( '#pewc-grand-total_clone' ).length > 0 ) {
1398				// 3.26.11, also update the grand total inside the lightbox
1399				$( '#pewc-grand-total_clone' ).html( grand_total );
1400			}
1401		}
1402
1403		// Re-run this because some browsers are too quick
1404		// This won't run if we're using the optimised condition option
1405		if( $update == 0 && pewc_vars.conditions_timer < 1 ) {
1406			var interval = setTimeout( function() {
1407				pewc_update_total_js( 1 );
1408				if( ! total_updated ) {
1409					// Check any calculations before input fields are updated
1410					$( 'body' ).trigger( 'pewc_trigger_calculations' );
1411					total_updated = true;
1412				}
1413			},
1414			250 );
1415		}
1416
1417		// 3.15.0, let other plugins hook into this
1418		$( 'body' ).trigger( 'pewc_after_update_total_js', [ base_total_price, base_price, grand_total ] );
1419	}
1420
1421	/*
1422	 * Counts selected checkboxes, swatches, or products
1423	 */
1424	function pewc_update_checkbox_field_counter( field_wrapper, counter ) {
1425
1426		var current_count = field_wrapper.attr( 'data-field-selected-counter' );
1427
1428		// hopefully this prevents this process from being run multiple times
1429		if ( current_count != counter ) {
1430			field_wrapper.attr( 'data-field-selected-counter', counter );
1431			// Optimised validation will hook into the trigger below
1432			$( 'body' ).trigger( 'pewc_field_selected_counter_updated', [ field_wrapper, counter ] );
1433		}
1434	}
1435
1436	function add_price_suffix( price, base_price ) {
1437		if( pewc_vars.show_suffix == 'yes' ) {
1438			var price_suffix_setting = pewc_vars.price_suffix_setting;
1439			if( price_suffix_setting.indexOf( '{price_excluding_tax}' ) > -1 ) {
1440				var price_ex_tax = base_price * ( pewc_vars.percent_exc_tax / 100 );
1441				suffix = price_suffix_setting.replace( '{price_excluding_tax}', pewc_wc_price( price_ex_tax.toFixed( pewc_vars.decimals ), false, false ) );
1442			} else if( price_suffix_setting.indexOf( '{price_including_tax}' ) > -1 ) {
1443				var price_inc_tax = base_price * ( pewc_vars.percent_inc_tax / 100 );
1444				suffix = price_suffix_setting.replace( '{price_including_tax}', pewc_wc_price( price_inc_tax.toFixed( pewc_vars.decimals ), false, false ) );
1445			} else {
1446				suffix = pewc_vars.price_suffix;
1447			}
1448			price = price + ' <small class="woocommerce-price-suffix">' + suffix + '</small>';
1449		}
1450		return price;
1451	}
1452
1453	function update_product_price( grand_total, base_price, orig_grand_total ) {
1454		var price_suffix_setting = pewc_vars.price_suffix_setting;
1455		// We can rebuild him
1456		// 3.27.5, Related Products could also have pewc-main-price, so we assume the first one to be the correct main one
1457		// This fixes an issue where if a Related Product has a hidden price, that it affects all prices on the product page
1458		// Let's also exclude main price from QuickView here instead of later in the function
1459		var main_price = $( '.pewc-main-price' ).not( '.pewc-quickview-product-wrapper .pewc-main-price' );
1460		if ( main_price.length > 1 ) {
1461			// get only the first?
1462			main_price.each(function( index, element){
1463				// add a special class to the first main price, we assume that's the real main price
1464				if ( index < 1 ) {
1465					$( this ).addClass( 'pewc-main-main-price' );
1466					return false;
1467				};
1468			});
1469			main_price = $( '.pewc-main-price.pewc-main-main-price' );
1470		}
1471
1472		if ( $( '.pewc-variable-product' ).length > 0 && pewc_vars.original_variable_price_range ) {
1473			// 4.4.1, this is a variable product, and we don't want to replace the variable price range until a variation has been selected
1474			var variationId = $('.variations_form').find('input[name="variation_id"]').val();
1475			if ( variationId && variationId !== '0' ) {
1476				// fully selected, allow to proceed, but first save original if it does not exist yet
1477				if ( ! main_price.attr( 'data-pewc-orig-price' ) ) {
1478					main_price.attr( 'data-pewc-orig-price', main_price.html() )
1479				}
1480			} else {
1481				// not selected / incomplete, return so that the price range is not touched. Put back original price range if it exists
1482				if ( main_price.attr( 'data-pewc-orig-price' ) ) {
1483					main_price.html( main_price.attr( 'data-pewc-orig-price' ) );
1484					main_price.removeAttr( 'data-pewc-orig-price' );
1485				}
1486				return;
1487			}
1488		}
1489
1490		var suffix = main_price.find( '.woocommerce-price-suffix' ).html();
1491		var label = main_price.find( '.wcfad-rule-label' ).html();
1492		var before = main_price.find( '.pewc-label-before' ).html();
1493		var after = main_price.find( '.pewc-label-after' ).html();
1494		var hide = main_price.find( '.pewc-label-hidden' );
1495		var new_total = '';
1496
1497		if( hide.length > 0 ) {
1498			new_total = '<span class="pewc-label-hidden">' + hide.html() + '</span>';
1499		} else {
1500			if( before ) {
1501				new_total += '<span class="pewc-label-before">' + before + ' </span>';
1502			}
1503
1504			// 3.21.7
1505			if ( orig_grand_total != '' && pewc_vars.disable_wcfad_label != 'yes' ) {
1506				orig_grand_total.toFixed( pewc_vars.decimals );
1507				orig_grand_total = pewc_wc_price( orig_grand_total );
1508				new_total += ' <s>' + orig_grand_total + '</s> ';
1509			}
1510
1511			new_total += grand_total;
1512
1513			if( after ) {
1514				new_total += '<span class="pewc-label-after"> ' + after + '</span>';
1515			}
1516			if( suffix ) {
1517				if( price_suffix_setting.indexOf( '{price_excluding_tax}' ) > -1 ) {
1518					var price_ex_tax = base_price * ( pewc_vars.percent_exc_tax / 100 );
1519					suffix = price_suffix_setting.replace( '{price_excluding_tax}', pewc_wc_price( price_ex_tax.toFixed( pewc_vars.decimals ), false, false ) );
1520				} else if( price_suffix_setting.indexOf( '{price_including_tax}' ) > -1 ) {
1521					var price_inc_tax = base_price * ( pewc_vars.percent_inc_tax / 100 );
1522					suffix = price_suffix_setting.replace( '{price_including_tax}', pewc_wc_price( price_inc_tax.toFixed( pewc_vars.decimals ), false, false ) );
1523				}
1524				if( label && suffix.indexOf( 'wcfad-rule-label' ) < 0 ) {
1525					suffix += '<br><span class="wcfad-rule-label">' + label + '</span>';
1526				}
1527				new_total += '&nbsp;<small class="woocommerce-price-suffix">' + suffix + '</small>';
1528			}
1529		}
1530
1531		// 3.22.1, retain DPDR label even if Update pricing label is enabled
1532		//var main_price = $( '.pewc-main-price').not( '.pewc-quickview-product-wrapper .pewc-main-price' ); // 3.27.5, commented out, maybe no longer needed?
1533		if ( main_price.find( '.wcfad-rule-label' ).length > 0 && new_total.indexOf( 'wcfad-rule-label' ) == -1 ) {
1534			// this has a DPDR discount label, add it to the new_total
1535			var dpdr_label = main_price.find( '.wcfad-rule-label' );
1536			new_total += '<br>' + dpdr_label[0].outerHTML;
1537		}
1538		main_price.html( new_total );
1539	}
1540
1541	function set_summary_panel_data( field, value, added_price ) {
1542		$( field ).attr( 'data-field-value', value );
1543		$( field ).attr( 'data-field-price', added_price );
1544		$( field ).addClass( 'pewc-active-field' );
1545	}
1546
1547	// old position of pewc_wc_price_without_currency and pewc_wc_price, moved outside of this container since 3.21.4
1548
1549	function format_separator( num ) {
1550	  return num.toString().replace( /(\d)(?=(\d{3})+(?!\d))/g, '$1,' );
1551	}
1552	// var interval = setInterval(function(){
1553	// 	pewc_update_total_js();
1554	// },
1555	// 500);
1556
1557	// 3.24.7, add a trigger event so that other plugins like PTU can re-trigger the form.cart input changes
1558	$( 'body' ).on( 'pewc_attach_form_cart_input_change', function() {
1559		$( 'form.cart' ).on('keyup input change paste', 'input:not(.pewc-grid-quantity-field), select, textarea.pewc-has-field-price', function(){
1560			// Debounced: batches rapid keyup/input events and redundant change events.
1561			pewc_update_total_js_debounced();
1562			$( 'body' ).trigger( 'pewc_updated_total_js' );
1563		});
1564	});
1565	$( 'body' ).trigger( 'pewc_attach_form_cart_input_change' );
1566
1567	var interval = setTimeout( function() {
1568		pewc_update_total_js();
1569		if ( 'yes' == pewc_vars.enable_character_counter ) {
1570			pewc_update_text_field_counters();
1571		}
1572	},
1573	250 );
1574	$( 'body' ).on( 'pewc_add_button_clicked', function() {
1575		pewc_update_total_js();
1576	});
1577	$( 'body' ).on( 'pewc_force_update_total_js', function() {
1578		// Debounced: this event fires multiple times per user action from conditions.js.
1579		pewc_update_total_js_debounced();
1580	});
1581
1582	// Accordion and tabs
1583	// 4.3.3, created a function for the click so that repeatable groups can use it. Moved the function out of the container
1584	$( '.pewc-groups-accordion h3' ).on( 'click', function( e ){
1585		pewc_accordion_click( $( this ) );
1586	});
1587
1588	if( pewc_vars.accordion_toggle == 'open' ) {
1589		$('.pewc-group-wrap').addClass('group-active');
1590	} else if( pewc_vars.accordion_toggle == 'closed' ) {
1591		$('.pewc-group-wrap').removeClass('group-active');
1592	} else {
1593		$('.first-group').addClass('group-active');
1594	}
1595
1596	$('.pewc-tab').on('click',function(e) {
1597		// 3.13.7
1598		if ( $(this).hasClass( 'pewc-disabled-group') ) {
1599			return;
1600		}
1601
1602		e.preventDefault();
1603		var tab_id = $(this).attr('data-group-id');
1604		$('.pewc-tab').removeClass('active-tab tab-failed');
1605		$( '.pewc-group-js-validation-notice' ).hide();
1606		$(this).addClass('active-tab');
1607		$('.pewc-group-wrap').removeClass('group-active');
1608		$('.pewc-group-wrap-'+tab_id).addClass('group-active');
1609	});
1610	$('.pewc-next-step-button').on('click',function(e) {
1611		e.preventDefault();
1612		// 3.13.7
1613		if ( $(this).hasClass( 'pewc-disabled-group') ) {
1614			return;
1615		}
1616
1617		var tab_id = $( this ).attr( 'data-group-id' );
1618		var tab_index = $( this ).closest( '.pewc-group-wrap' ).attr( 'data-group-index' );
1619		var direction = $( this ).attr( 'data-direction' );
1620		$( '.pewc-tab' ).removeClass( 'active-tab tab-failed' );
1621		$( '.pewc-group-js-validation-notice' ).hide();
1622		// Check if the next group is visible
1623		if( $( '.pewc-group-wrap-' + tab_id ).hasClass( 'pewc-group-hidden' ) ) {
1624			// Count the total tabs
1625			var total_tabs = $( '.pewc-group-wrap' ).length;
1626			if( direction == 'next' ) {
1627				// Find the next group ID
1628				for( var i = parseInt( tab_index ) + 1; i < total_tabs; i++ ) {
1629					if( ! $( '.pewc-group-index-' + i ).hasClass( 'pewc-group-hidden' ) ) {
1630						tab_id = $( '.pewc-group-index-' + i ).attr( 'data-group-id' );
1631						break;
1632					}
1633				}
1634			} else {
1635				// Find the previous group ID
1636				for( var i = parseInt( tab_index ) - 1; i >= 0; i-- ) {
1637					if( ! $( '.pewc-group-index-' + i ).hasClass( 'pewc-group-hidden' ) ) {
1638						tab_id = $( '.pewc-group-index-' + i ).attr( 'data-group-id' );
1639						break;
1640					}
1641				}
1642			}
1643		}
1644		$( '#pewc-tab-' + tab_id ).addClass( 'active-tab' );
1645		$( '.pewc-group-wrap' ).removeClass( 'group-active' );
1646		$( '.pewc-group-wrap-' + tab_id ).addClass( 'group-active' );
1647
1648		// Scroll to top
1649		if ( pewc_vars.steps_group_disable_scroll_to_top != 'yes' ) {
1650			if( $( '.pewc-steps-wrapper' ).length > 0 ) {
1651				$([document.documentElement, document.body]).animate({
1652					scrollTop: $( '.pewc-steps-wrapper' ).offset().top
1653	    		}, 150);
1654			}
1655		}
1656	});
1657
1658	function pewc_get_text_str_len( str, wrapper ) {
1659		var new_str, str_ex_spaces ;
1660		var field = $(wrapper).find('.pewc-form-field');
1661		// Don't include spaces
1662		if( pewc_vars.remove_spaces != 'yes' ) {
1663			str_ex_spaces = str.replace(/\s/g, "");
1664		} else {
1665			str_ex_spaces = str;
1666		}
1667
1668		var str_len = str_ex_spaces.length;
1669		// Exclude alphanumerics if selected
1670		if( $(field).attr('data-alphanumeric') == 1 ) {
1671			str_ex_spaces = str_ex_spaces.replace(/\W/g, '');
1672			$(field).val(str_ex_spaces);
1673			str_len = str_ex_spaces.length;
1674		}
1675		// Allow alphanumerics but don't charge if selected
1676		if( $(field).attr('data-alphanumeric-charge') == 1 ) {
1677			str_ex_spaces = str_ex_spaces.replace(/\W/g, '');
1678			// $(field).val(str_ex_spaces);
1679			str_len = str_ex_spaces.length;
1680		}
1681		// If free characters are allowed
1682		var freechars = $(field).attr('data-freechars');
1683		str_len -= freechars;
1684		str_len = Math.max(0,str_len);
1685		return str_len;
1686	}
1687
1688	function pewc_disable_child_product_quantities() {
1689		$( '.woocommerce-cart-form__cart-item.pewc-child-product' ).each( function() {
1690			if( pewc_vars.disable_qty || pewc_vars.multiply_independent == 'yes' ) {
1691				$(this).find('.product-quantity input').attr('disabled',true);
1692			}
1693		});
1694	}
1695
1696	// Disable quantity fields in Barn2 Fast Cart
1697	$('body').on('click', 'a.wfc-open-cart-button', function( e ) {
1698		var timeout = setTimeout(
1699			function() {
1700				$( '.wfc-cart-form__cart-item.pewc-child-product' ).each( function() {
1701					if( pewc_vars.disable_qty || pewc_vars.multiply_independent == 'yes' ) {
1702						$(this).find('.product-quantity input').attr('disabled',true);
1703					}
1704				});
1705			},
1706			250
1707		);
1708	} );
1709
1710	// only do this if there are actually child products
1711	if ( $('.woocommerce-cart-form__cart-item.pewc-child-product').length > 0 ) {
1712		// call function on page load
1713		pewc_disable_child_product_quantities();
1714		// when cart is updated, disable quantities again
1715		$('body').on('updated_cart_totals', pewc_disable_child_product_quantities);
1716	}
1717
1718	// If child product is selected, manage allowable purchase quantity
1719	// Applies to radio and select
1720	$('body').on('change','.products-quantities-independent .pewc-child-select-field',function(){
1721		var number_field = $(this).closest('.child-product-wrapper').find('.pewc-child-quantity-field');
1722		if ( $( this ).val() != '') {
1723			// select field is not blank, update quantity
1724			if( $(number_field).val() == 0 ) {
1725				// Automatically enter a quantity when a product is selected
1726				$(number_field).val(1);
1727			};
1728		} else {
1729			// reset number field
1730			$( number_field ).val(0);
1731		}
1732		//var available_stock = $(this).find(':selected').data('stock');
1733		//if( available_stock ) {
1734		//	var number = $(number_field).attr('max',available_stock);
1735		//	if( $(number).val() > available_stock ) {
1736		//		$(number_field).val(available_stock);
1737		//	}
1738		//} else {
1739		//	$(number_field).removeAttr('max');
1740		//}
1741		// 3.27.3
1742		pewc_update_independent_quantity_input_max( $( this ), number_field );
1743	});
1744
1745	// 3.27.3, created a separate function so that we can call this on page load
1746	function pewc_update_independent_quantity_input_max( select_field, number_field) {
1747
1748		var available_stock = $( select_field ).find( ':selected' ).data( 'stock' );
1749		if( available_stock ) {
1750			var number = $( number_field ).attr( 'max', available_stock );
1751			if( $( number ).val() > available_stock ) {
1752				$( number_field ).val( available_stock );
1753			}
1754		} else {
1755			$( number_field ).removeAttr( 'max' );
1756		}
1757
1758	}
1759
1760	$('body').on('change input keyup paste click','.products-quantities-independent .pewc-child-quantity-field',function( e ) {
1761		e.stopPropagation(); // this prevents the click event from bubbling up to the event attached to the layer
1762
1763		// 4.4.1, disable auto-select using a filter
1764		if ( pewc_vars.disable_click_column_layout && $( this ).val() > 0 ) {
1765			return;
1766		}
1767
1768		if ( $( this ).closest( '.pewc-item' ).hasClass( 'pewc-item-products-select' ) || $( this ).closest( '.pewc-item' ).hasClass( 'pewc-item-products-variable-select' ) ) {
1769			// this is a Products select field
1770			var selIndex = 0;
1771			if( $(this).val() > 0 ) {
1772				var selField = $( this ).closest( '.pewc-item' ).find( 'select.pewc-child-select-field' );
1773				// find first select option with value if not already selected
1774				selIndex = selField.prop( 'selectedIndex' );
1775				if ( selIndex < 1 && selField.val() == '' ) {
1776					$( this ).closest( '.pewc-item' ).find( 'select.pewc-child-select-field option' ).each( function( index, element ) {
1777						if ( $(this).val() != '' && selIndex < 1 ) {
1778							selIndex = index;
1779							return;
1780						}
1781					});
1782				}
1783			}
1784			$( this ).closest( '.pewc-item' ).find( 'select.pewc-child-select-field' ).prop( 'selectedIndex', selIndex );
1785		} else {
1786			// Ensure this child product is selected
1787			// for checkbox images
1788			if( $(this).val() > 0 ) {
1789				var checkbox = $(this).closest('.pewc-checkbox-wrapper').find('input[type=checkbox]').prop('checked',true).trigger( 'change' );
1790			} else {
1791				var checkbox = $(this).closest('.pewc-checkbox-wrapper').find('input[type=checkbox]').prop('checked',fal
1791se).trigger( 'change' );
1792			}
1793		}
1794		var available_stock = $(this).find(':selected').data('stock');
1795		// $( 'body' ).trigger( 'pewc_update_child_quantity', [ $(this).closest('.pewc-checkbox-image-wrapper').find('input[type=checkbox]') ] );
1796		$( 'body' ).trigger( 'pewc_update_child_quantity', [ $(this).closest('.pewc-checkbox-wrapper').find('input[type=checkbox]') ] );
1797		pewc_update_total_js();
1798	});
1799
1800	// Read and cache the full variation data map for a Variable Select field
1801	// from its <script type="application/json"> block.
1802	function pewc_get_variable_select_data( wrapper ) {
1803		var cached = wrapper.data( 'pewc-variable-select-data' );
1804		if ( cached ) {
1805			return cached;
1806		}
1807		var field_id = wrapper.find( '.pewc-variable-select-product' ).data( 'target' );
1808		var $json = wrapper.find( '.pewc-variable-select-data[data-for="' + field_id + '"]' );
1809		var data = {};
1810		if ( $json.length ) {
1811			try {
1812				data = JSON.parse( $json.text() ) || {};
1813			} catch ( e ) {
1814				data = {};
1815			}
1816		}
1817		wrapper.data( 'pewc-variable-select-data', data );
1818		return data;
1819	}
1820
1821	// Return the variations array for the currently selected product
1822	function pewc_get_selected_product_variations( $product_select ) {
1823		var wrapper = $product_select.closest( '.pewc-variable-select-wrapper' );
1824		var data = pewc_get_variable_select_data( wrapper );
1825		var product_id = $product_select.val();
1826		if ( product_id === '' || ! data[ product_id ] ) {
1827			return [];
1828		}
1829		return Array.isArray( data[ product_id ] ) ? data[ product_id ] : [];
1830	}
1831
1832	// Variable Select layout: populate the variation select when a variable product is chosen
1833	function pewc_populate_variable_select_variations( product_select ) {
1834
1835		var $product_select = $( product_select );
1836		var wrapper = $product_select.closest( '.pewc-variable-select-wrapper' );
1837		var $variation_select = wrapper.find( '.pewc-variable-select-variation' );
1838		var $details = wrapper.find( '.pewc-variable-select-details' );
1839
1840		if ( ! $variation_select.length ) {
1841			return;
1842		}
1843
1844		var variations = pewc_get_selected_product_variations( $product_select );
1845		// data-selected-variation only applies on the very first run (initial page load)
1846		var preselect = $variation_select.attr( 'data-selected-variation' );
1847		$variation_select.attr( 'data-selected-variation', '' );
1848
1849		// Stash the variation data so the variation-select change handler can read it
1850		wrapper.data( 'pewc-variations', variations );
1851
1852		$variation_select.empty();
1853
1854		if ( $product_select.val() === '' || ! variations.length ) {
1855			$details.hide();
1856			$variation_select.val( '' );
1857			$variation_select.trigger( 'change' );
1858			$( 'body' ).trigger( 'pewc_force_update_total_js' );
1859			return;
1860		}
1861
1862		var matched_preselect = false;
1863		$.each( variations, function( index, variation ) {
1864			var $option = $( '<option></option>' )
1865				.val( variation.id )
1866				.text( variation.label )
1867				.attr( 'data-option-cost', variation.cost )
1868				.attr( 'data-field-value', variation.label )
1869				.attr( 'data-stock', variation.stock );
1870			if ( variation.disabled ) {
1871				$option.attr( 'disabled', 'disabled' );
1872			}
1873			if ( preselect && parseInt( preselect, 10 ) === parseInt( variation.id, 10 ) ) {
1874				$option.prop( 'selected', true );
1875				matched_preselect = true;
1876			}
1877			$variation_select.append( $option );
1878		});
1879		// Auto-select the first variation when none was pre-selected
1880		if ( ! matched_preselect ) {
1881			$variation_select.prop( 'selectedIndex', 0 );
1882		}
1883
1884		// Populate the details before revealing the panel to avoid a flash of empty content
1885		pewc_update_variable_select_details( $variation_select, true );
1886
1887		$variation_select.trigger( 'change' );
1888		$( 'body' ).trigger( 'pewc_force_update_total_js' );
1889
1890	}
1891
1892	// Update the thumbnail, price, stock and description for the selected variation
1893	function pewc_update_variable_select_details( variation_select, reveal ) {
1894
1895		var $variation_select = $( variation_select );
1896		var wrapper = $variation_select.closest( '.pewc-variable-select-wrapper' );
1897		var $details = wrapper.find( '.pewc-variable-select-details' );
1898
1899		if ( ! $details.length ) {
1900			return;
1901		}
1902
1903		var selected_id = $variation_select.val();
1904		var variations = wrapper.data( 'pewc-variations' ) || [];
1905		var variation = null;
1906
1907		$.each( variations, function( index, v ) {
1908			if ( parseInt( v.id, 10 ) === parseInt( selected_id, 10 ) ) {
1909				variation = v;
1910				return false;
1911			}
1912		});
1913
1914		if ( ! variation ) {
1915			$details.hide();
1916			return;
1917		}
1918
1919		var $thumb = $details.find( '.pewc-variable-select-thumbnail' );
1920		if ( $thumb.length ) {
1921			var new_image = variation.image || '';
1922			if ( $thumb.data( 'pewc-current-image' ) !== new_image ) {
1923				$thumb.data( 'pewc-current-image', new_image );
1924				$thumb.html( new_image );
1925			}
1926		}
1927		$details.find( '.pewc-variable-select-price' ).html( variation.price || '' );
1928		$details.find( '.pewc-variable-select-stock' ).html( variation.stock_html || '' );
1929		$details.find( '.pewc-variable-select-description' ).html( variation.description || '' );
1930
1931		// Only reveal once content is in place
1932		if ( reveal || $details.is( ':visible' ) ) {
1933			$details.show();
1934		}
1935
1936	}
1937
1938	$( 'body' ).on( 'change', '.pewc-variable-select-product', function() {
1939		pewc_populate_variable_select_variations( this );
1940	});
1941
1942	$( 'body' ).on( 'change', '.pewc-variable-select-variation', function() {
1943		pewc_update_variable_select_details( this );
1944	});
1945
1946	$( function() {
1947		$( '.pewc-variable-select-product' ).each( function() {
1948			var wrapper = $( this ).closest( '.pewc-variable-select-wrapper' );
1949			var $product_select = $( this );
1950			// Stash the variation data so the variation-select change handler works from the start
1951			wrapper.data( 'pewc-variations', pewc_get_selected_product_variations( $product_select ) );
1952			if ( $product_select.val() === '' ) {
1953				return;
1954			}
1955			// The server has already rendered the details for the stored product/variation.
1956			// Only rebuild if that markup is missing (e.g. cached select without the panel).
1957			if ( wrapper.find( '.pewc-variable-select-variation option' ).length < 1 ) {
1958				pewc_populate_variable_select_variations( this );
1959			}
1960		});
1961	});
1962
1963	// 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.
1964	$( '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 ){
1965		var item_field_wrapper = $( this ).closest( '.pewc-item-field-wrapper' );
1966		var pewc_item_wrapper = item_field_wrapper.closest( '.pewc-item' );
1967		var radio_type = '';
1968		var number_checked = 0;
1969
1970		if ( pewc_item_wrapper.hasClass( 'pewc-item-products-radio' ) ) {
1971			radio_type = 'radio images';
1972			number_checked = item_field_wrapper.find( '.pewc-radio-images-wrapper .pewc-radio-image-wrapper.checked' ).length;
1973		} else {
1974			radio_type = 'radio list';
1975			number_checked = item_field_wrapper.find( '.pewc-radio-wrapper input.pewc-radio-form-field:checked' ).length;
1976		}
1977
1978		var number_value = $( this ).val();
1979		if ( number_value > 0 && number_checked < 1 ) {
1980			// we don't have a product selected, select the first one?
1981			if ( radio_type == 'radio images' ) {
1982				item_field_wrapper.find( '.pewc-radio-images-wrapper .pewc-radio-image-wrapper' ).each( function(){
1983					if ( ! $( this ).hasClass( 'checked' ) ) {
1984						$( this ).addClass( 'checked' );
1985					}
1986					$( this ).find( 'input.pewc-radio-form-field' ).prop( 'checked', true );
1987					return false; // break the loop since we only want to select the first one
1988				});
1989			} else {
1990				// radio list
1991				item_field_wrapper.find( '.pewc-radio-list-wrapper .pewc-radio-wrapper input.pewc-radio-form-field' ).each( function(){
1992					$( this ).prop( 'checked', true );
1993					return false; // break the loop since we only want to select the first one
1994				});
1995			}
1996		} else if ( number_value < 1 && number_checked > 0 ) {
1997			// de-select all products
1998			if ( radio_type == 'radio images' ) {
1999				item_field_wrapper.find( '.pewc-radio-images-wrapper .pewc-radio-image-wrapper.checked' ).each( function(){
2000					$( this ).removeClass( 'checked' );
2001					$( this ).find( 'input.pewc-radio-form-field' ).prop( 'checked', false );
2002				});
2003			} else {
2004				// radio list
2005				item_field_wrapper.find( '.pewc-radio-list-wrapper .pewc-radio-wrapper input.pewc-radio-form-field:checked' ).each( function(){
2006					$( this ).prop( 'checked', false );
2007				});
2008			}
2009		}
2010	});
2011
2012	$('body').on('change input keyup paste','.pewc-item-products-independent.pewc-child-qty-target .pewc-child-quantity-field',function() {
2013		// This runs when the user manually updates a child product quantity that has been set by a calculation field (independent quantities, radio items only)
2014		// If the calculation field has a reverse formula, use the result to set the source field value
2015		var wrapper = $( this ).closest( '.pewc-item' );
2016		// This is the ID of the calculation field that triggers this quantity update
2017		var triggered_by = $( wrapper ).attr( 'data-child-qty-triggered-by' );
2018		// Get the "reverse formula" - i.e. the method to calculate how to update the source input field
2019		var reverse_field_id = $( '.pewc-field-' + triggered_by ).attr( 'data-reverse-formula-field' );
2020		var reverse_formula = calculations.get_formula_by_id( reverse_field_id );
2021		// Do this calc "live" to avoid any race conditions with other fields getting updated
2022		calc_field = $( '.pewc-field-' + reverse_field_id );
2023		calc_field_id = $( calc_field ).attr( 'data-field-id' );
2024		price_wrapper = $( calc_field ).find( '.pewc-calculation-price-wrapper' );
2025		calc_field_id = $( calc_field ).attr( 'data-field-id' );
2026		formula = $( price_wrapper ).find( '.pewc-data-formula' ).val();
2027		fields = $( price_wrapper ).find( '.pewc-data-fields' ).val();
2028		round = $( price_wrapper ).find( '.pewc-formula-round' ).val();
2029		decimals = $( price_wrapper ).find( '.pewc-decimal-places' ).val();
2030		if( fields ) {
2031			fields = JSON.parse( fields );
2032		}
2033		var reverse_result = calculations.evaluate_formula( fields, reverse_formula, round, decimals, calc_field_id );
2034		// Update the "source" input field with the result of the reverse calculation
2035		// The source input is the number field used in the main calculation field
2036		var source_field_id = $( '.pewc-field-' + triggered_by ).attr( 'data-reverse-input-field' );
2037		$( '.pewc-field-' + source_field_id ).find( 'input' ).val( reverse_result );
2038
2039		// Check if the calculation can be overridden by manual quantity updates
2040		if( $( '.pewc-field-' + triggered_by ).hasClass( 'pewc-quantity-overrides' ) ) {
2041			// 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
2042			$( wrapper ).addClass( 'pewc-quantity-updated' );
2043		}
2044		
2045	});
2046	$( 'body' ).on( 'pewc_update_child_quantity', function( e, el ) {
2047		// This is triggered when the quantity field for a child product is updated
2048		var child_qty = $( el ).closest('.pewc-checkbox-wrapper').find('input[type=number]').val();
2049		if( child_qty > 0 ) {
2050			$( el ).closest('.pewc-checkbox-image-wrapper').addClass('checked');
2051		} else {
2052			$( el ).closest('.pewc-checkbox-image-wrapper').removeClass('checked');
2053		}
2054	});
2055	$( 'body' ).on( 'click', '.products-quantities-independent .pewc-checkbox-form-field', function( e ) {
2056		// 4.3.5, added 2nd condition
2057		// 4.4.1, added 3rd condition
2058		if(
2059			$( this ).closest( '.pewc-checkbox-images-wrapper' ).hasClass( 'pewc-force-quantity' ) || 
2060			$( this ).closest( '.pewc-checkbox-image-wrapper' ).find( '.pewc-column-attributes-select' ).length > 0 || 
2061			pewc_vars.disable_click_column_layout
2062		) {
2063			e.stopPropagation();
2064			e.preventDefault(); // 3.25.7, prevent the hidden input checkbox from being unchecked and deselected
2065			return;
2066		}
2067
2068		// this is triggered when clicking the child product's image
2069		if( $(this).is(':checked') ){
2070			var number = $(this).closest('.pewc-checkbox-wrapper').find('input[type=number]').val();
2071			if( number==0 ) {
2072				var default_quantity = $(this).closest( '.pewc-checkbox-wrapper' ).find( 'input[type=number]' ).attr( 'data-default-quantity' );
2073				if( default_quantity == undefined || pewc_vars.set_child_quantity_default != 'yes' ) {
2074					default_quantity = 1;
2075				}
2076				$(this).closest('.pewc-checkbox-wrapper').find('input[type=number]').val( default_quantity );
2077				//$(this).closest('.pewc-checkbox-image-wrapper').addClass('checked'); // commented out in 3.13.2, this is handled when the wrapper itself is clicked
2078			}
2079		} else {
2080			var number = $(this).closest('.pewc-checkbox-wrapper').find('input[type=number]').val(0);
2081			//$(this).closest('.pewc-checkbox-image-wrapper').removeClass('checked'); // commented out in 3.13.2
2082		}
2083		e.stopPropagation(); // added in 3.13.2. this may be triggered when the wrapper is clicked. Prevents infinite loop
2084	});
2085	$( 'body' ).on( 'click', '.products-quantities-linked .pewc-checkbox-form-field, .products-quantities-one-only .pe
2085wc-checkbox-form-field', function( e ) {
2086		e.stopPropagation(); // 3.13.3, prevents infinite loop
2087		if( $(this).is(':checked') ){
2088			$(this).closest('.pewc-checkbox-image-wrapper').addClass('checked');
2089		} else {
2090			$(this).closest('.pewc-checkbox-image-wrapper').removeClass('checked');
2091		}
2092	});
2093
2094	// 4.5.0, 'Select All' option for Products fields (Checkboxes List layout)
2095	$( 'body' ).on( 'change', '.pewc-select-all-form-field', function( e ) {
2096
2097		var select_all = $( this );
2098		var wrapper = select_all.closest( '.child-product-wrapper' );
2099		// Checkboxes that are out of stock/unavailable are already rendered disabled server-side; leave those alone
2100		var other_checkboxes = wrapper.find( '.pewc-checkbox-wrapper:not(.pewc-select-all-wrapper):not(.pewc-checkbox-disabled) .pewc-checkbox-form-field' );
2101
2102		if( select_all.is( ':checked' ) ) {
2103			// Check every available child product, but don't use the 'disabled' attribute -
2104			// disabled fields are excluded from form submission, so the checkboxes must stay
2105			// checked+enabled and are instead visually/interactively locked via the CSS class below
2106			other_checkboxes.prop( 'checked', true );
2107			wrapper.find( '.pewc-checkbox-wrapper' ).not( '.pewc-select-all-wrapper' ).addClass( 'pewc-select-all-active' );
2108		} else {
2109			other_checkboxes.prop( 'checked', false );
2110			wrapper.find( '.pewc-checkbox-wrapper' ).removeClass( 'pewc-select-all-active' );
2111		}
2112
2113		$( 'body' ).trigger( 'pewc_force_update_total_js' );
2114
2115	});
2116
2117	// Prevent the individual checkboxes (and their quantity fields) from being changed while 'Select All' is active
2118	$( 'body' ).on( 'click', '.pewc-select-all-active .pewc-checkbox-form-field, .pewc-select-all-active .pewc-child-quantity-field', function( e ) {
2119		e.preventDefault();
2120		e.stopImmediatePropagation();
2121	});
2122	$( 'body' ).on( 'keydown', '.pewc-select-all-active .pewc-checkbox-form-field, .pewc-select-all-active .pewc-child-quantity-field', function( e ) {
2123		e.preventDefault();
2124	});
2125
2126	// Toggle class on label when text swatch element is updated
2127	$( 'body' ).on( 'change', '.pewc-text-swatch input', function( e ) {
2128		var field_type = $( this ).closest( '.pewc-item' ).attr( 'data-field-type' );
2129		if( field_type == 'radio' ) {
2130			$( this ).closest( 'ul' ).find( 'label' ).removeClass( 'active-swatch' );
2131		}
2132
2133		if( $( this ).prop( 'checked' ) == true ) {
2134			$( this ).closest( 'label' ).addClass( 'active-swatch' );
2135		} else {
2136			$( this ).closest( 'label' ).removeClass( 'active-swatch' );
2137		}
2138	});
2139
2140	$( 'body' ).on( 'click', '.pewc-radio-image-wrapper, .pewc-checkbox-image-wrapper', function( e ) {
2141		var wrapper = $( this );
2142		if( $( wrapper ).hasClass( 'pewc-checkbox-disabled' ) ) {
2143			return;
2144		}
2145		if( $( wrapper ).closest( '.pewc-components-wrapper' ).hasClass( 'pewc-force-quantity' ) ) {
2146			return;
2147		}
2148
2149		// 4.3.5, disable the click event for Column layout with attributes selection
2150		// 4.4.1, disable the click using a filter
2151		if ( $( wrapper ).find( '.pewc-column-attributes-select' ).length > 0 || pewc_vars.disable_click_column_layout ) {
2152			return;
2153		}
2154
2155		// 
2156		var radio;
2157		var is_image_swatch_checkbox = $( wrapper ).closest( '.pewc-item' ).hasClass( 'pewc-item-image-swatch-checkbox' );
2158		var is_checkbox = $( wrapper ).hasClass( 'pewc-checkbox-image-wrapper' );
2159		// Remove all checked for radio button
2160		if( ! is_image_swatch_checkbox && ! is_checkbox ) {
2161			var checked = $( wrapper ).find( '.pewc-radio-form-field' ).prop( 'checked' );
2162			var group = $( wrapper ).closest( '.pewc-radio-images-wrapper' ).find( '.pewc-radio-image-wrapper' ).removeClass( 'checked' );
2163			if( ! checked ) {
2164				$( wrapper ).addClass( 'checked' );
2165				//radio = $( wrapper ).find( '.pewc-radio-form-field' ).trigger( 'click' );
2166			}
2167			// Defer the heavy synchronous chain (conditions, price update) so the browser can
2168			// paint the checked class before running the condition check / price recalculation.
2169			radio = $( wrapper ).find( '.pewc-radio-form-field' );
2170			setTimeout( function() { radio.trigger( 'click' ); }, 0 ); // moved here 3.9.5 for lightbox
2171		} else {
2172			// Checkbox
2173			if ( is_checkbox ) {
2174				// added in 3.13.2 for Products checkbox images
2175				e.preventDefault(); // this helps avoid the conflict with clicking the child product image
2176				radio = $( wrapper ).find( '.pewc-checkbox-form-field' );
2177				$( wrapper ).toggleClass( 'checked' );
2178				if ( is_image_swatch_checkbox ) {
2179					// 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
2180					var checked = $( radio ).prop( 'checked' );
2181					var new_checked = ! checked;
2182					setTimeout( function() { $( radio ).prop( 'checked', new_checked ).trigger( 'change' ); }, 0 );
2183				} else {
2184					// keeping this here in case Products field need this
2185					setTimeout( function() { $( radio ).trigger( 'click' ); }, 0 ); // this triggers the click event attached to .products-quantities-independent .pewc-checkbox-form-field
2186				}
2187				e.stopPropagation();
2188			} else {
2189				radio = $( wrapper ).find( '.pewc-radio-form-field' );
2190				var checked = $( radio ).prop( 'checked' );
2191				$( wrapper ).toggleClass( 'checked' );
2192				var new_checked = ! checked;
2193				setTimeout( function() { $( radio ).prop( 'checked', new_checked ).trigger( 'click' ); }, 0 ); // click added 3.9.5
2194			}
2195		}
2196
2197	}).on( 'click', '.pewc-radio-image-wrapper .pewc-radio-form-field', function( e ) {
2198		// 4.3.5, disable the click event for Column layout with attributes selection
2199		// 4.4.1, disable the click using a filter
2200		var wrapper = $( this ).closest( '.pewc-radio-image-wrapper' );
2201		if ( $( wrapper ).find( '.pewc-column-attributes-select' ).length > 0 || pewc_vars.disable_click_column_layout ) {
2202			return;
2203		}
2204		var is_image_swatch_checkbox = $( this ).closest( '.pewc-item' ).hasClass( 'pewc-item-image-swatch-checkbox' );
2205		if( ! is_image_swatch_checkbox ) {
2206			// Stop propagation for radio buttons
2207			e.stopPropagation();
2208			// Deselect the radio button
2209			var checked = $( this ).closest( '.pewc-radio-image-wrapper' ).hasClass( 'checked' );
2210			if( ! checked ) {
2211				$( this ).prop( 'checked', false ).trigger( 'change' ); // added on 3.9.5 for lightbox
2212				// pewc_update_total_js() removed: trigger(change) above fires pewc_update_total_js_debounced via .pe
2212wc-form-field handler
2213			}
2214		} else {
2215			e.stopPropagation(); // added on 3.9.5, for checkbox in lightbox
2216			$( this ).closest( '.pewc-radio-image-wrapper' ).toggleClass( 'checked' ); // originally here before 3.9.5
2217		}
2218		$form = $( this ).closest( 'form' );
2219		add_on_images.update_add_on_image( $( this ), $form );
2220	});
2221
2222	$( 'body' ).on( 'click' , '.products-quantities-independent .pewc-radio-form-field', function() {
2223		if($(this).is(':checked')) {
2224			var number_field = $(this).closest('.pewc-item-field-wrapper').find('input[type=number]');
2225			var number = $(number_field).val();
2226			if( number == 0 ) {
2227				$( number_field ).val( 1 );
2228			}
2229			if( $(this).attr('data-stock') > 0 ) {
2230				// Ensure the quantity field doesn't display more than the available stock
2231				$(number_field).attr( 'max', $(this).attr('data-stock') );
2232				if( $(number_field).val() > $(this).attr('data-stock') ) {
2233					$(number_field).val( $(this).attr('data-stock') );
2234				}
2235			}
2236		} else {
2237			//var number = $(this).closest( '.pewc-radio-images-wrapper' ).find( 'input[type=number]' ).val( 0 );
2238			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
2239		}
2240	});
2241
2242	// 3.12.0, handler for enabling/disabling the add-to-cart button
2243	function pewc_toggle_add_to_cart_button( eventType, disabled, caller ) {
2244
2245		var button = $( 'body' ).find( 'form.cart .single_add_to_cart_button' );
2246		var disable_class = 'pewc-disabled-by-'+caller;
2247
2248		if ( button.length < 1 ) return; // do nothing
2249
2250		// 4.3.14, it is possible to have more than one button e.g. Add to Quote button
2251		button.each( function(){
2252			var curr_button = $( this );
2253			if ( disabled ) {
2254				// always disable button
2255				curr_button.attr( 'disabled', true );
2256				if ( ! curr_button.hasClass( disable_class ) ) {
2257					curr_button.addClass( disable_class );
2258
2259					// 3.21.5
2260					var button_text = pewc_vars.calculating_text;
2261					if ( caller === 'upload' ) {
2262						button_text = pewc_vars.uploading_text;
2263					}
2264					pewc_update_add_to_cart_button_text( curr_button, button_text, disabled );
2265				}
2266			} else {
2267				// remove the disable_class added by the caller when it enabled it previously
2268				curr_button.removeClass( disable_class );
2269				// 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)
2270				if ( curr_button.attr( 'class' ).indexOf( 'pewc-disabled-by' ) == -1 ) {
2271					// our special class was not found, safe to enable again
2272					curr_button.attr( 'disabled', false );
2273					var default_text = pewc_vars.default_add_to_cart_text;
2274					if ( curr_button.attr( 'data-pewc-orig-button-text' ) ) {
2275						default_text = curr_button.attr( 'data-pewc-orig-button-text' );
2276					}
2277					pewc_update_add_to_cart_button_text( curr_button, default_text );
2278				}
2279			}
2280		});
2281
2282	}
2283	$( 'body' ).on( 'pewc_toggle_add_to_cart_button', pewc_toggle_add_to_cart_button );
2284
2285	function pewc_update_add_to_cart_button_text( button, button_text, disabled=false ) {
2286		if ( button.is( 'button' ) ) {
2287			if ( disabled && ! button.attr( 'data-pewc-orig-button-text' ) ) {
2288				// 4.3.14, save first the original text e.g. could be Add to Quote
2289				button.attr( 'data-pewc-orig-button-text', button.text() );
2290			}
2291			button.text( button_text );
2292		} else {
2293			if ( disabled && ! button.attr( 'data-pewc-orig-button-text' ) ) {
2294				// 4.3.14, save first the original text
2295				button.attr( 'data-pewc-orig-button-text', button.val() );
2296			}
2297			button.val( button_text ); // maybe an input type submit button
2298		}
2299	}
2300
2301	var calculations = {
2302
2303		init: function() {
2304
2305			if( pewc_vars.calculations_timer > 0 ) {
2306				if ( pewc_vars.event_driven_conditions === 'yes' ) {
2307					// 4.3.5: bind recalculate to field change events instead of polling every 500ms.
2308					// These are the same triggers used by the non-optimised path but run within the
2309					// optimised context so we don't fall back to legacy condition-checking behaviour.
2310					$( 'body' ).on( 'keyup input change paste', 'form.cart .qty', this.recalculate );
2311					$( '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 );
2312					$( 'body' ).on( 'keyup input change paste', '.pewc-number-uploads', this.recalculate );
2313					$( 'body' ).on( 'pewc_trigger_calculations', this.recalculate );
2314					$( 'body' ).on( 'pewc_conditions_checked', this.recalculate );
2315					$( 'body' ).one( 'pewc_after_update_total_js', this.recalculate );
2316				} else {
2317					var interval = setInterval(
2318						this.recalculate,
2319						pewc_vars.calculations_timer
2320					);
2321				}
2322
2323				// since 3.12.0, disable add-to-cart button while recalculating
2324				if ( pewc_vars.disable_button_recalculate == 'yes' ) {
2325					$( 'body' ).on( 'keyup input change paste', 'form.cart .qty', this.disable_add_to_cart_button );
2326					$( '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 );
2327					$( 'body' ).on( 'keyup input change paste', '.pewc-number-uploads', this.disable_add_to_cart_button );
2328					$( 'body' ).on( 'pewc_trigger_calculations', this.disable_add_to_cart_button );
2329					$( 'body' ).on( 'pewc_conditions_checked', this.disable_add_to_cart_button );
2330				}
2331			} else {
2332				// $( 'body' ).one( 'keyup input change paste', '.pewc-number-field.pewc-calculation-trigger, .pewc-field-triggers-condition .pewc-number-field', this.recalculate );
2333				$( 'body' ).on( 'keyup input change paste', 'form.cart .qty', this.recalculate );
2334				$( '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 );
2335				$( 'body' ).on( 'keyup input change paste', '.pewc-number-uploads', this.recalculate );
2336				$( 'body' ).on( 'pewc_trigger_calculations', this.recalculate );
2337				$( 'body' ).on( 'pewc_conditions_checked', this.recalculate );
2338			}
2339
2340		},
2341
2342		// 3.12.0
2343		disable_add_to_cart_button: function( e ) {
2344			// 3.12.2. Only disable if product has calculation fields
2345			var num_calcs = $( '.pewc-product-extra-groups-wrap .pewc-item-calculation' ).not( '.pewc-hidden-field' ).length;
2346
2347			if( parseFloat( num_calcs ) < 1 ) {
2348				return;
2349			}
2350			pewc_toggle_add_to_cart_button( e, true, 'calculation_recalculate' );
2351		},
2352
2353		recalculate: function( e ) {
2354
2355			// If we don't have any calculation fields, just bounce
2356			var num_calcs = parseInt( $( '.pewc-product-extra-groups-wrap .pewc-item-calculation' ).not( '.pewc-hidden-field' ).length );
2357			var num_formulas_in_field_prices = parseInt( $( '.pewc-product-extra-groups-wrap .pewc-field-price-has-formula' ).not( '.pewc-hidden-field' ).length );
2358			var num_formulas_in_option_prices = parseInt( $( '.pewc-product-extra-groups-wrap .pewc-field-option-price-has-formula' ).not( '.pewc-hidden-field' ).length );
2359
2360			if( num_calcs < 1 && num_formulas_in_field_prices < 1 && num_formulas_in_option_prices < 1 ) {
2361				return;
2362			}
2363
2364			var calc_field, price_wrapper, dimensions_wrapper, formula, tags, calc_formula, replace, calc_field_id, calc_value, prev_calc_value;
2365
2366			var calc_fields = [];
2367
2368			var update = 0;
2369
2370			if ( pewc_vars.calculations_timer > 0 && pewc_vars.disable_button_recalculate == 'yes' ) {
2371				// 3.12.0, we use this to determine if we have to enable or disable the add-to-cart button
2372				var pewc_total_calc_price_start = $( '#pewc_total_calc_price' ).val();
2373			}
2374
2375			// Find any calculation fields
2376			$( 'body' ).find( 'form.cart .pewc-item-calculation' ).not( '.pewc-hidden-field' ).each( function() {
2377
2378				if( $( this ).hasClass( 'pewc-variation-dependent' ) && ! $( this ).hasClass( 'active' ) ) {
2379					return;
2380				}
2381
2382				var group = $( this ).closest( '.pewc-group-wrap' );
2383				if( $( group ).hasClass( 'pewc-group-hidden' ) ) {
2384					return;
2385				}
2386
2387				var group_id = $( group ).attr( 'data-group-id' );
2388
2389				calc_field = $( this );
2390				var field_id = $( calc_field ).attr( 'data-id' );
2391				calc_field_id = $( calc_field ).attr( 'data-field-id' );
2392				price_wrapper = $( calc_field ).find( '.pewc-calculation-price-wrapper' );
2393				formula = $( price_wrapper ).find( '.pewc-data-formula' ).val();
2394				fields = $( price_wrapper ).find( '.pewc-data-fields' ).val();
2395				tags = $( price_wrapper ).find( '.pewc-data-tag' ).val();
2396				action = $( price_wrapper ).find( '.pewc-action' ).val();
2397				round = $( price_wrapper ).find( '.pewc-formula-round' ).val();
2398				decimals = $( price_wrapper ).find( '.pewc-decimal-places' ).val();
2399				calc_value = $( price_wrapper ).find( '.pewc-calculation-value' );
2400				prev_calc_value = calc_value.val();
2401
2402				if( fields ) {
2403					fields = JSON.parse( fields );
2404				}
2405
2406				var result = calculations.evaluate_formula( fields, formula, round, decimals, calc_field_id );
2407
2408				if( result == '*' ) {
2409					$( calc_field ).closest( '.pewc-item-calculation' ).attr( 'data-price', 0 );
2410					$( price_wrapper ).find( 'span' ).html( pewc_vars.null_signifier );
2411					calc_value.val( 0 );
2412					if ( prev_calc_value != 0 ) {
2413						// 3.12.2. Trigger only if the value changed to avoid infinite loop
2414						calc_value.trigger( 'calculation_field_updated' )
2415					}
2416					if( pewc_vars.disable_button_calcs == 'yes' ) {
2417						calc_fields.push( calc_field_id );
2418						//$( 'body' ).find( 'form.cart .single_add_to_cart_button' ).attr( 'disabled', true );
2419						$( 'body' ).trigger( 'pewc_toggle_add_to_cart_button', [ true, 'calculation' ] ); // since 3.12.0
2420					}
2421				} else if( ! result || ! isNaN( result ) ) {
2422					if( pewc_vars.disable_button_calcs == 'yes' ) {
2423						calc_fields = calc_fields.filter( function( item ) {
2424							return item !== calc_field_id;
2425						});
2426						if( calc_fields.length < 1 ) {
2427							//$( 'body' ).find( 'form.cart .single_add_to_cart_button' ).attr( 'disabled', false );
2428							$( 'body' ).trigger( 'pewc_toggle_add_to_cart_button', [ false, 'calculation' ] ); // since 3.12.0
2429						}
2430					}
2431					$( price_wrapper ).find( 'span' ).html( result );
2432
2433					if( action == 'cost' || action == 'price' ) {
2434						$( calc_field ).closest( '.pewc-item-calculation' ).attr( 'data-price', result );
2435						$( price_wrapper ).find( 'span' ).html( pewc_wc_price( result ) );
2436					} else if( action == 'qty' ) {
2437						$( 'form.cart' ).find( '.quantity .qty' ).val( result ).trigger( 'pewc_qty_changed' );
2438					} else if( action == 'child-qty' ) {
2439						// When a calculation updates, check if it should update a child product quantity field (independent, radio buttons only)
2440						// If it does, we update the quantity field						
2441						// This is the product field that will have its quantity set
2442						var product_field_id = $( calc_field ).closest( '.pewc-item-calculation' ).find( '.pewc-calculation-price-wrapper' ).attr( 'data-product-field-id' );
2443						// This is the ID of the child product that will be selected
2444						var child_qty_product_id = $( calc_field ).closest( '.pewc-item-calculation' ).find( '.pewc-calculation-price-wrapper' ).attr( 'data-child-product-id' );
2445						// Only set the result of this calculation once - don't update quantity if the user has updated it manually themselves
2446						if( ! $( '.pewc-field-' + product_field_id ).hasClass( 'pewc-quantity-updated' ) ) {
2447							$( '.pewc-field-' + product_field_id ).find( '.pewc-child-quantity-field' ).val( result ).trigger( 'pewc_update_child_quantity' );
2448							var group_name = 'pewc_group_' + group_id + '_' + product_field_id;
2449							// Auto select item (provided an item is not already selected)
2450							if( $( "input[name='" + group_name + "_child_product[]']:checked" ).length < 1 ) {
2451								$( '#' + group_name + '_' + child_qty_product_id ).prop( 'checked', true );
2452								$( '#' + group_name + '_' + child_qty_product_id ).closest( '.pewc-radio-image-wrapper' ).addClass( 'checked' );
2453							}
2454						}						
2455					} else if ( ! $( calc_field ).hasClass( 'pewc-hidden-calculation' ) ) {
2456						// no-action falls here, don't bother if calc field is hidden
2457						// pewc-result-format is filterable
2458						var result_format = $( price_wrapper ).find( '.pewc-result-format' ).val();
2459						if ( result_format == 'price' ) {
2460							$( price_wrapper ).find( 'span' ).html( pewc_wc_price( result ) );
2461						} else if ( result_format == 'price without currency' ) {
2462							$( price_wrapper ).find( 'span' ).html( pewc_wc_price_without_currency( result ) );
2463						}
2464					}
2465
2466					if( action == 'price' ) {
2467						$( 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
2468						//$( '#pewc_calc_set_price' ).val( result ).attr( 'data-calc-set', 1 ); // before 3.17.2
2469					}
2470
2471					calc_value.val( result );
2472					if ( prev_calc_value != result ) {
2473						// 3.12.2. Trigger only if the value changed to avoid infinite loop
2474						calc_value.trigger( 'calculation_field_updated' );
2475						calc_value.trigger( 'change' ); // 3.17.2, makes this field more responsive to changes by typing
2476					}
2477				} else if( result && isNaN( result ) && result != 'error' ) {
2478					allow_text_calcs_fields = pewc_vars.allow_text_calcs_fields;
2479					if( pewc_vars.allow_text_calcs ) {
2480						$( price_wrapper ).find( 'span' ).html( result );
2481						calc_value.val( result );
2482					} else if( allow_text_calcs_fields.includes( parseInt( calc_field_id ) ) ) {
2483						$( price_wrapper ).find( 'span' ).html( result );
2484						calc_value.val( result );
2485					}
2486				}
2487
2488				update++;
2489
2490			});
2491
2492			// 3.26.0
2493			if ( num_formulas_in_field_prices > 0 ) {
2494				calculations.evaluate_field_prices();
2495			}
2496			if ( num_formulas_in_option_prices > 0 ) {
2497				calculations.evaluate_option_prices();
2498			}
2499
2500			// Update the totals
2501			if( update > 0 ) {
2502				update = 0;
2503				pewc_update_total_js();
2504			}
2505
2506			if ( pewc_vars.calculations_timer > 0 && pewc_vars.disable_button_recalculate == 'yes' ) {
2507				// 3.12.0, we use this to determine if we have to enable or disable the add-to-cart button
2508				var pewc_total_calc_price_end = $( '#pewc_total_calc_price' ).val();
2509				var d = new Date();
2510				var time = d.getTime();
2511
2512				if ( pewc_total_calc_price_start != pewc_total_calc_price_end ) {
2513					// maybe we're not done calculating, disable the add-to-cart button
2514					$( 'body' ).trigger( 'pewc_toggle_add_to_cart_button', [ true, 'calculation_recalculate' ] );
2515					// record the last time there was a change
2516					$( '#pewc_total_calc_price' ).attr( 'data-last-calc-time', time );
2517				} else {
2518					// maybe we're done calculating, let's wait a second?
2519					if ( isNaN( $( '#pewc_total_calc_price' ).attr( 'data-last-calc-time') ) ) {
2520						// maybe this is not yet created, save a value
2521						$( '#pewc_total_calc_price' ).attr( 'data-last-calc-time', time );
2522					} else {
2523						var diff = parseFloat( time ) - parseFloat( $( '#pewc_total_calc_price' ).attr( 'data-last-calc-time') );
2524						if ( isNaN( diff ) || diff < pewc_vars.recalculate_waiting_time ) {
2525							// do nothing if not a number, or less than waiting time (default 0.7 seconds)
2526						} else {
2527							//enable the add-to-cart button
2528							$( 'body' ).trigger( 'pewc_toggle_add_to_cart_button', [ false, 'calculation_recalculate' ] );
2529						}
2530					}
2531				}
2532
2533			}
2534
2535		},
2536
2537		evaluate_look_up_table: function( calc_field_id ) {
2538
2539			var result = false;
2540
2541			if( pewc_look_up_fields == undefined ) return false;
2542
2543			var look_up_field = pewc_look_up_fields[calc_field_id];
2544
2545			var table = look_up_field[0];
2546			var x_field = look_up_field[1];
2547			var y_field = look_up_field[2];
2548
2549			var x_value = this.get_field_value( x_field );
2550			var y_value = this.get_field_value( y_field );
2551
2552			var tables = pewc_look_up_tables[table];
2553			if( tables == undefined ) {
2554				return false;
2555			}
2556
2557			var x_axis = tables[x_value];
2558
2559			// If there's not an element in the tables array for our x value, find the next one
2560			if( x_axis == undefined && x_value && x_value != undefined ) {
2561				if ( this.exact_match( calc_field_id, 'x' ) ) {
2562					return '*'; // 3.13.0, let's use the null signifier
2563				} else {
2564					x_value = calculations.find_nearest_index( x_value, tables );
2565					x_axis = tables[x_value];
2566				}
2567			} else if( x_axis == undefined && x_value==0 && x_value != undefined ) {
2568				x_axis = tables[Object.keys(tables)[0]];
2569			}
2570
2571			if( x_axis != undefined ) {
2572
2573				var y_axis = tables[y_value];
2574
2575				// if( y_axis == undefined && y_value && y_value != undefined ) {
2576				if( y_value && y_value != undefined ) {
2577					if ( ! this.exact_match( calc_field_id, 'y' ) ) {
2578						y_value = calculations.find_nearest_index( y_value, x_axis );
2579					}
2580				}
2581				if( y_value == 'max' ) {
2582					// Get last value in x_axis
2583					result = x_axis[Object.keys(x_axis)[Object.keys(x_axis).length - 1]];
2584				} else {
2585					result = x_axis[y_value];
2586				}
2587
2588				if ( this.exact_match( calc_field_id, 'y' ) && result == undefined ) {
2589					result = '*'; // 3.13.0
2590				}
2591			} else {
2592
2593				return false;
2594
2595			}
2596
2597			return result;
2598
2599		},
2600
2601		get_field_value: function( field_id ) {
2602
2603			var value = 0;
2604
2605			if( $( '.pewc-field-' + field_id ).find( 'input.pewc-number-field' ).length > 0 ) {
2606				return $( '.pewc-field-' + field_id ).find( 'input.pewc-number-field' ).val();
2607			} else if( $( '.pewc-field-' + field_id ).find( 'select' ).length > 0 ) {
2608				if( ! isNaN( $( '.pewc-field-' + field_id ).find( 'select option:selected' ).attr( 'value' ) ) ) {
2609					// Return the option 'label' if it's numeric
2610					return $( '.pewc-field-' + field_id ).find( 'select option:selected' ).attr( 'value' );
2611				} else {
2612					// Return the option's 'price'
2613					return $( '.pewc-field-' + field_id ).find( 'select option:selected' ).attr( 'data-option-cost' );
2614				}
2615				
2616			} else if( $( '.pewc-field-' + field_id ).find( 'input.pewc-radio-form-field[type="radio"]:checked' ).length > 0 ) {
2617				return $( '.pewc-field-' + field_id ).find( 'input.pewc-radio-form-field[type="radio"]:checked' ).attr( 'data-option-cost' );
2618			}
2619
2620			return value;
2621		},
2622
2623		find_nearest_index: function( value, axis ) {
2624
2625			var keys = Object.keys( axis ); // Just the keys
2626			keys.sort( (a,b) => a-b ); // sort the keys numerically. This is needed if keys have decimals
2627
2628			if( parseFloat( value ) <= parseFloat( keys[0] ) ) {
2629				return keys[0];
2630			}
2631
2632			// If first element is empty, replace with 0
2633			if( pewc_vars.set_initial_key == 'yes' ) {
2634				if( isNaN( keys[0] ) || keys[0] == '' ) {
2635					keys[0] = 0;
2636				}
2637			}
2638
2639			for( var i=0; i < keys.length; i++ ) {
2640				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
2641					return keys[i+1];
2642				}
2643			}
2644
2645			if( keys[( keys.length ) - 1] == 'max' ) {
2646				return 'max';
2647			}
2648
2649			// Return this as a fallback in case we've gone over the last index
2650			return keys[i];
2651
2652		},
2653
2654		exact_match: function( calc_field_id, axis ) {
2655			// since 3.13.0
2656			if ( $( '.pewc-item-calculation.pewc-field-' + calc_field_id ).attr( 'data-exact-match-' + axis ) == 'yes' ) {
2657				return true;
2658			} else {
2659				return false;
2660			}
2661		},
2662
2663		evaluate_formula: function( fields, formula, round, decimals, calc_field_id ) {
2664
2665			var calc_formula = formula;
2666
2667			if( fields ) {
2668
2669				// Replace any field tags with values
2670				for( var i in fields ) {
2671
2672					// Look for any price values
2673					if( fields[i].indexOf( '_option_price' ) > -1 ) {
2674						var field_id = fields[i].replace( '_option_price', '' );
2675						// We want the price of the selected option in this field, not its value
2676						var o_price = parseFloat( $( 'form.cart .pewc-field-' + field_id ).attr( 'data-selected-option-price' ) );
2677						if( isNaN( o_price ) || ( $( 'form.cart .pewc-field-' + field_id ).length == 0 && pewc_vars.zero_missing_field == 'yes' ) ) {
2678							o_price = 0;
2679						}
2680						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2681						calc_formula = calc_formula.replace( replace, o_price );
2682					} else if ( fields[i].indexOf( '_option_value' ) > -1 ) {
2683						var field_id = fields[i].replace( '_option_value', '' );
2684						// We want the value of the selected option in this field
2685						var o_value = parseFloat( $( 'form.cart .pewc-field-' + field_id ).attr('data-field-value') );
2686						if( ( $( 'form.cart .pewc-field-' + field_id ).length == 0 && pewc_vars.zero_missing_field == 'yes' ) || isNaN( o_value ) ) {
2687							o_value = 0;
2688						}
2689						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2690						calc_formula = calc_formula.replace( replace, o_value );
2691					} else if( fields[i].indexOf( '_field_price' ) > -1 ) {
2692						// We want the price of the field
2693						var field_id = fields[i].replace( '_field_price', '' );
2694						var f_price = parseFloat( $( 'form.cart .pewc-field-' + field_id ).attr( 'data-field-price' ) );
2695						if( $( 'form.cart .pewc-field-' + field_id ).length == 0 && pewc_vars.zero_missing_field == 'yes' ) {
2696							f_price = 0;
2697						}
2698						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2699						calc_formula = calc_formula.replace( replace, f_price );
2700					} else if( fields[i].indexOf( '_number_uploads' ) > -1 ) {
2701						// We want the number of uploads
2702						var field_id = fields[i].replace( '_number_uploads', '' );
2703						var num_uploads = parseFloat( $( 'form.cart .pewc-field-' + field_id ).find( '.pewc-number-uploads' ).val() );
2704						if( $( 'form.cart .pewc-field-' + field_id ).length == 0 && pewc_vars.zero_missing_field == 'yes' ) {
2705							num_uploads = 0;
2706						}
2707						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2708						calc_formula = calc_formula.replace( replace, num_uploads );
2709					} else if( fields[i].indexOf( '_pdf_count' ) > -1 ) {
2710						// Get the number of pages for this uploaded PDF
2711						var field_id = fields[i].replace( '_pdf_count', '' );
2712						var pdf_count = parseFloat( $( '#field_' + field_id + "_pdf_count" ).val() );
2713						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2714						calc_formula = calc_formula.replace( replace, pdf_count );
2715					} else if( fields[i].indexOf( '_weight' ) > -1 ) {
2716						// Get the weight of child products selected in specified field
2717						var field_id = fields[i].replace( '_weight', '' );
2718						// Find the selected item in the field and get the weight
2719						var weight = $( 'form.cart .pewc-field-' + field_id ).find( 'input:checked').closest( '.pewc-radio-wrapper' ).attr( 'data-
2719product-weight' );
2720						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2721						calc_formula = calc_formula.replace( replace, weight );
2722					} else if( fields[i].indexOf( '_length' ) > -1 ) {
2723						// Get the length of child products selected in specified field
2724						var field_id = fields[i].replace( '_length', '' );
2725						// Find the selected item in the field and get the length
2726						var length = $( 'form.cart .pewc-field-' + field_id ).find( 'input:checked').closest( '.pewc-radio-wrapper' ).attr( 'data-product-length' );
2727						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2728						calc_formula = calc_formula.replace( replace, length );
2729					} else if( fields[i].indexOf( '_width' ) > -1 ) {
2730						// Get the width of child products selected in specified field
2731						var field_id = fields[i].replace( '_width', '' );
2732						// Find the selected item in the field and get the width
2733						var width = $( 'form.cart .pewc-field-' + field_id ).find( 'input:checked').closest( '.pewc-radio-wrapper' ).attr( 'data-product-width' );
2734						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2735						calc_formula = calc_formula.replace( replace, width );
2736					} else if( fields[i].indexOf( '_height' ) > -1 ) {
2737						// Get the height of child products selected in specified field
2738						var field_id = fields[i].replace( '_height', '' );
2739						// Find the selected item in the field and get the height
2740						var height = $( 'form.cart .pewc-field-' + field_id ).find( 'input:checked').closest( '.pewc-radio-wrapper' ).attr( 'data-product-height' );
2741						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2742						calc_formula = calc_formula.replace( replace, height );
2743					} else if( fields[i].indexOf( '_quantity' ) > -1 ) {
2744						// Get the quantity of child products in specified field - independent quantities, radio list / images only
2745						var field_id = fields[i].replace( '_quantity', '' );
2746						// Find the selected item in the field and get the quantity
2747						var quantity = $( 'form.cart .pewc-field-' + field_id ).find( '.pewc-independent-quantity-field').val();
2748						replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2749						calc_formula = calc_formula.replace( replace, quantity );
2750					} else {
2751						// Look for the value of number fields
2752						var f_val = parseFloat( $( 'form.cart .pewc-number-field-' + fields[i] ).val() );
2753						if( ! f_val && pewc_vars.zero_missing_field == 'yes' ) {
2754							f_val = 0;
2755						}
2756						if( ! isNaN( f_val ) ) {
2757							if( $( 'form.cart .pewc-field-' + fields[i] ).length == 0 && pewc_vars.zero_missing_field == 'yes' ) {
2758								f_val = 0;
2759							}
2760							replace = new RegExp( '{field_' + fields[i] + '}', 'g' );
2761							calc_formula = calc_formula.replace( replace, f_val );
2762						}
2763					}
2764
2765				}
2766
2767			}
2768
2769			if( formula === undefined ) {
2770				console.log( 'formula not defined: ' + calc_field_id );
2771				return false;
2772			}
2773
2774			var product_price = parseFloat( $('#pewc-product-price').val() );
2775			// 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
2776			if ( typeof pewc_wcfad !== 'undefined' && pewc_wcfad.reset_product_price( formula, calc_field_id ) ) {
2777				product_price = parseFloat( $('#pewc-product-price-original').val() );
2778			}
2779			var quantity = parseFloat( $( 'form.cart .quantity' ).find( '.qty' ).val() );
2780			if( formula.includes( "{look_up_table}" ) ) {
2781				calc_formula = calculations.evaluate_look_up_table( calc_field_id );
2782			}
2783			if( formula.includes( "{product_weight}" ) ) {
2784				var product_weight = parseFloat( $( '#pewc_product_weight' ).val() );
2785				calc_formula = calc_formula.replace( /{product_weight}/g, parseFloat( product_weight ) );
2786			}
2787			if( formula.includes( "{product_height}" ) ) {
2788				var product_height = parseFloat( $( '#pewc_product_height' ).val() );
2789				calc_formula = calc_formula.replace( /{product_height}/g, parseFloat( product_height ) );
2790			}
2791			if( formula.includes( "{product_length}" ) ) {
2792				var product_length = parseFloat( $( '#pewc_product_length' ).val() );
2793				calc_formula = calc_formula.replace( /{product_length}/g, parseFloat( product_length ) );
2794			}
2795			if( formula.includes( "{product_width}" ) ) {
2796				var product_width = parseFloat( $( '#pewc_product_width' ).val() );
2797				calc_formula = calc_formula.replace( /{product_width}/g, parseFloat( product_width ) );
2798			}
2799			if( formula.includes( "{product_price}" ) && product_price ) {
2800				calc_formula = calc_formula.replace( /{product_price}/g, parseFloat( product_price ) );
2801			}
2802			if( formula.includes( "{quantity}" ) && quantity ) {
2803				calc_formula = calc_formula.replace( /{quantity}/g, parseFloat( quantity ) );
2804			}
2805			if( formula.includes( "{variable_1}" ) && pewc_vars.variable_1 ) {
2806				calc_formula = calc_formula.replace( /{variable_1}/g, parseFloat( pewc_vars.variable_1 ) );
2807			}
2808			if( formula.includes( "{variable_2}" ) && pewc_vars.variable_2 ) {
2809				calc_formula = calc_formula.replace( /{variable_2}/g, parseFloat( pewc_vars.variable_2 ) );
2810			}
2811			if( formula.includes( "{variable_3}" ) && pewc_vars.variable_3 ) {
2812				calc_formula = calc_formula.replace( /{variable_3}/g, parseFloat( pewc_vars.variable_3 ) );
2813			}
2814			if( formula.includes( "{calculated_booking_cost}" ) ) {
2815				var calculated_booking_cost = parseFloat( $( '#calculated_booking_cost' ).val() );
2816				calc_formula = calc_formula.replace( /{calculated_booking_cost}/g, parseFloat( calculated_booking_cost ) );
2817			}
2818			if( formula.includes( "{num_units_int}" ) ) {
2819				var num_units_int = parseFloat( $( '#num_units_int' ).val() );
2820				calc_formula = calc_formula.replace( /{num_units_int}/g, parseFloat( num_units_int ) );
2821			}
2822			if( formula.includes( "{num_bookings}" ) ) {
2823				var num_units_int = parseFloat( $( '#num_bookings' ).val() );
2824				calc_formula = calc_formula.replace( /{num_bookings}/g, parseFloat( num_units_int ) );
2825			}
2826			if( formula.includes( "{total_variations}" ) ) {
2827				var total_variations = parseFloat( $( '#wcbvp_total_variations' ).val() );
2828				calc_formula = calc_formula.replace( /{total_variations}/g, parseFloat( total_variations ) );
2829			}
2830			if( formula.includes( "{pa_" ) ) {
2831				var attribute = formula.replace( "{", "" );
2832				var attribute = attribute.replace( "}", "" );
2833				var attribute_data = pewc_vars.attribute_data;
2834				calc_formula = parseFloat( attribute_data[attribute] );
2835			}
2836
2837			if( pewc_vars.global_calc_vars ) {
2838				var global_calc_vars = pewc_vars.global_calc_vars;
2839				// Iterate through our global vars
2840				for( var key in global_calc_vars ) {
2841					if( formula.includes( "{" + key + "}" ) ) {
2842						var global_var = "{" + key + "}";
2843						var global_var_regex = new RegExp( global_var, 'g' );
2844						calc_formula = calc_formula.replace( global_var_regex, global_calc_vars[key] );
2845					}
2846				}
2847			}
2848
2849			// Check for ACF fields
2850			if( typeof pewc_acf_fields != 'undefined' ) {
2851				for( var key in pewc_acf_fields ) {
2852					if( formula.includes( "{acf_" + key + "}" ) ) {
2853						var acf_field = "{acf_" + key + "}";
2854						// Find all instances
2855						var acf_field_regex = new RegExp( acf_field, 'g' );
2856						calc_formula = calc_formula.replace( acf_field_regex, pewc_acf_fields[key] );
2857					}
2858				}
2859			}
2860
2861			var result;
2862
2863			if( calc_formula == '*' ) return calc_formula;
2864
2865			if( pewc_vars.allow_text_calcs ) {
2866				return calc_formula;
2867			}
2868			
2869			allow_text_calcs_fields = pewc_vars.allow_text_calcs_fields;
2870			if( allow_text_calcs_fields.includes( parseInt( calc_field_id ) ) ) {
2871				return calc_formula;
2872			}
2873
2874			try {
2875				result = math.eval( calc_formula );
2876
2877				if( round == 'ceil' ) {
2878					result = math.ceil( result );
2879				} else if( round == 'floor' ) {
2880					result = math.floor( result );
2881				}
2882				if( pewc_vars.math_round == 'yes' ) {
2883					result = Math.round( result * 100 ) / 100;
2884				}
2885				return result.toFixed( parseFloat( decimals ) );
2886			} catch( err ) {
2887				// Check all tags have been replaced
2888				return 'error';
2889			}
2890
2891		},
2892
2893		get_formula_by_id: function( reverse_field_id ) {
2894
2895			var formula = $( '.pewc-field-' + reverse_field_id ).find( '.pewc-data-formula' ).val();
2896			return formula;
2897
2898		},
2899
2900		evaluate_field_prices: function() {
2901
2902			$( 'body' ).find( 'form.cart .pewc-field-price-has-formula' ).not( '.pewc-hidden-field' ).each( function() {
2903				if( $( this ).hasClass( 'pewc-variation-dependent' ) && ! $( this ).hasClass( 'active' ) ) {
2904					return;
2905				}
2906
2907				var group = $( this ).closest( '.pewc-group-wrap' );
2908				if( $( group ).hasClass( 'pewc-group-hidden' ) ) {
2909					return;
2910				}
2911
2912				var group_id = $( group ).attr( 'data-group-id' );
2913
2914				var pewc_item = $( this );
2915				var field_id = $( pewc_item ).attr( 'data-id' );
2916				var data_field_id = $( pewc_item ).attr( 'data-field-id' );
2917				//var price_wrapper = $( pewc_item ).find( '.pewc-calculation-price-wrapper' );
2918				var formula = $( pewc_item ).attr( 'data-field-price-formula' );
2919				if ( formula == undefined ) {
2920					return;
2921				}
2922				var fields = $( pewc_item ).attr( 'data-field-price-formula-fields' );
2923				var tags = $( pewc_item ).attr( 'data-field-price-formula-tags' );
2924				//var action = $( price_wrapper ).find( '.pewc-action' ).val();
2925				var round = $( pewc_item ).attr( 'data-field-price-formula-round' );
2926				var decimals = $( pewc_item ).attr( 'data-field-price-formula-decimals' );
2927				//var calc_value = $( price_wrapper ).find( '.pewc-calculation-value' );
2928				//var prev_calc_value = calc_value.val();
2929
2930				if( fields ) {
2931					fields = JSON.parse( fields );
2932				}
2933
2934				var result = calculations.evaluate_formula( fields, formula, round, decimals, data_field_id );
2935				if ( isNaN( result ) ) {
2936					result = 0;
2937				}
2938				$( pewc_item ).attr( 'data-price', result ); // data-field-price is field price (data-price) + option-price
2939				if ( 'checkbox' === $( pewc_item ).attr( 'data-field-type' ) ) {
2940					$( pewc_item ).find( '.pewc-checkbox-price' ).html( pewc_wc_price( result, true ) );
2941				} else {
2942					$( pewc_item ).find( '.pewc-field-price' ).html( pewc_wc_price( result, true ) );
2943				}
2944				$( pewc_item ).find( 'input[name="' + field_id + '_field_price_calculated"]' ).val( result );
2945			});
2946
2947		},
2948
2949		evaluate_option_prices: function() {
2950
2951			$( 'body' ).find( 'form.cart .pewc-field-option-price-has-formula' ).not( '.pewc-hidden-field' ).each( function() {
2952				if( $( this ).hasClass( 'pewc-variation-dependent' ) && ! $( this ).hasClass( 'active' ) ) {
2953					return;
2954				}
2955
2956				var group = $( this ).closest( '.pewc-group-wrap' );
2957				if( $( group ).hasClass( 'pewc-group-hidden' ) ) {
2958					return;
2959				}
2960
2961				var group_id = $( group ).attr( 'data-group-id' );
2962
2963				var pewc_item = $( this );
2964				var field_id = $( pewc_item ).attr( 'data-id' );
2965				var data_field_id = $( pewc_item ).attr( 'data-field-id' );
2966				var round = $( pewc_item ).attr( 'data-field-price-formula-round' );
2967				var decimals = $( pewc_item ).attr( 'data-field-price-formula-decimals' );
2968
2969				$( this ).find( '.pewc-option-price-has-formula' ).each( function(){
2970					var opt = $( this );
2971					var formula = $( opt ).attr( 'data-option-cost-formula' );
2972					if ( formula == undefined ) {
2973						return;
2974					}
2975					var fields = $( opt ).attr( 'data-option-price-formula-fields' );
2976					var tags = $( opt ).attr( 'data-option-price-formula-tags' );
2977					var index = $( opt ).attr( 'data-option-index' );
2978
2979					if( fields ) {
2980						fields = JSON.parse( fields );
2981					}
2982
2983					var result = calculations.evaluate_formula( fields, formula, round, decimals, data_field_id );
2984					if ( isNaN( result ) ) {
2985						result = 0;
2986					}
2987					if ( $( opt ).attr( 'data-option-cost' ) == result && 'select' === $( pewc_item ).attr( 'data-field-type' ) ) {
2988						return; // no need to update, prevents Select fields from blinking
2989					}
2990					$( opt ).attr( 'data-option-cost', result );
2991					$( opt ).closest( 'label' ).find( '.pewc-option-cost-label' ).html( pewc_wc_price( result ) );
2992					if ( 'select' === $( pewc_item ).attr( 'data-field-type' ) ) {
2993						var new_text = $( opt ).val() + pewc_vars.separator + pewc_wc_price( result, true );
2994						$( this ).text( new_text );
2995					} else if ( 'select-box' === $( pewc_item ).attr( 'data-field-type' ) ) {
2996						var selectbox = $( '#' + field_id + '_select_box' );
2997						if ( selectbox.length > 0 ) {
2998							var optprice = 0;
2999							selectbox.find( '.dd-option' ).each( function( index, element ){
3000								optprice = parseFloat( $( 'input[name="' + field_id + '_option_' + index + '_price_calculated"]' ).val() );
3001								if ( ! isNaN( optprice ) ) {
3002									$( element ).find( '.dd-option-description' ).html( pewc_wc_price( optprice, true ) );
3003								}
3004							});
3005							// 4.4.0, added condition
3006							if ( $( pewc_item ).find( '.dd-selected-value' ).length > 0 ) {
3007								var selected_value = $( pewc_item ).find( '.dd-selected-value' ).val();
3008								var select_option_index = 0;
3009								select_option_index = $( 'select#' + field_id + ' option[value="' + selected_value.replace( /"/g, '\\"' ) + '"]').index();
3010								optprice = parseFloat( $( 'input[name="' + field_id + '_option_' + select_option_index + '_price_calculated"]' ).val() );
3011								if ( ! isNaN( optprice ) ) {
3012									$( pewc_item ).find( '.dd-selected-description' ).html( pewc_wc_price( optprice, true ) );
3013									$( pewc_item ).attr( 'data-selected-option-price', optprice );
3014								}
3015							}
3016						}
3017					}
3018					$( pewc_item ).find( 'input[name="' + field_id  + '_option_' + index + '_price_calculated"]' ).val( result );
3019				});
3020			});
3021
3022		}
3023
3024	}
3025
3026	calculations.init();
3027
3028	var hidden_groups = {
3029
3030		init: function() {
3031			$( 'body' ).on( 'pewc_conditions_checked', this.check_group_visibility );
3032		},
3033
3034		/**
3035		 * Check whether to hide or display groups
3036		 */
3037		check_group_visibility: function() {
3038
3039			// Check each group
3040			$( 'body' ).find( '.pewc-group-wrap' ).each( function() {
3041				var all_hidden = true;
3042				var group = $( this );
3043				$( group ).find( '.pewc-item' ).each( function() {
3044					if( ! $( this ).hasClass( 'pewc-hidden-field' ) ) {
3045						all_hidden = false;
3046					}
3047				});
3048				if( all_hidden ) {
3049					$( group ).addClass( 'pewc-hidden-group' );
3050				} else {
3051					$( group ).removeClass( 'pewc-hidden-group' );
3052				}
3053			});
3054
3055		}
3056
3057	}
3058
3059	hidden_groups.init();
3060
3061	var summary_panel = {
3062
3063		init: function() {
3064			$( '.pewc-form-field' ).on( 'change update keyup', this.update_panel );
3065		},
3066
3067		update_panel: function( e ) {
3068			var field_id = $( this ).closest( '.pewc-item' ).attr( 'data-field-id' );
3069			var field_value = $( this ).val();
3070		},
3071
3072	}
3073
3074	summary_panel.init();
3075
3076	/**
3077	 * Sets product images for the chosen add-on
3078	 */
3079	var add_on_images = {
3080
3081		init: function() {
3082
3083			var $product        = $( 'form.cart' ).closest( '.product' ),
3084				$product_gallery  = $product.find( pewc_vars.product_gallery ),
3085				$gallery_nav      = $product.find( '.flex-control-nav' ),
3086				$gallery_img      = $gallery_nav.find( 'li:eq(0) img' ),
3087				$product_img_wrap = $product_gallery.find( pewc_vars.product_img_wrap ).eq( 0 ),
3088				$product_img      = $product_img_wrap.find( 'img' ).eq( 0 ),
3089				$product_link     = $product_img_wrap.find( 'a' ).eq( 0 );
3090
3091			if( add_on_images.replace_image() ) {
3092				// create an attribute where we can track where a replaced image came from
3093				$product_img.attr( 'data-pewc-from-field', '' );
3094
3095				// 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?
3096				$( document ).ready( function() {
3097					// we need to delay this so that the main image container takes the size of the original product image
3098					add_on_images.replace_main_with_default();
3099				});
3100
3101				// 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
3102				$( 'body' ).on( 'pewc_group_visibility_updated', function( e, id, action ) {
3103					add_on_images.check_if_src_hidden( $product_img );
3104				});
3105
3106				// 3.21.4, trigger replace main image if field is initially hidden by a condition
3107				$( 'body' ).on( 'pewc_field_visibility_updated', function( e, id, action ) {
3108					var pewc_item = $( '.pewc-item.' + id );
3109					// 3.26.6, changed condition from data-default-value to data-field-value to accommodate Edit Options
3110					if ( pewc_item.attr( 'data-field-value' ) != '' ) {
3111						// only do this if field has selected value that needs to replace the main image
3112						if ( pewc_item.data( 'field-type' ) === 'image_swatch' ) {
3113							// 3.24.6, find the first checked/selected element
3114							var field = pewc_item.find( 'input[name="' + id + '[]"]:checked' )[0];
3115						} else {
3116							var field = pewc_item.find( 'input[name="' + id + '[]"]' )[0];
3117						}
3118						var $form = pewc_item.closest( 'form' );
3119						add_on_images.update_add_on_image( $( field ), $form );
3120					}
3121				});
3122
3123			}
3124
3125			// If we've got parent/child swatches, then hide/show the correct child swatch
3126			$( '.pewc-swatch-parent .pewc-radio-form-field' ).on( 'change', this.change_child );
3127
3128			// If we've got parent/child swatches, then ensure that all the child swatches are in sync
3129			$( '.pewc-swatch-child .pewc-radio-form-field' ).on( 'change', this.sync_children );
3130
3131		},
3132
3133		replace_image: function( field ) {
3134			// 3.17.2
3135			if( pewc_vars.replace_image ) {
3136				// global Replace main image, or the filter pewc_get_add_on_image_action, is used
3137				return pewc_vars.replace_image;
3138			} else if ( field ) {
3139				if ( field.hasClass( 'pewc-replace-main-image' ) ) {
3140					return true;
3141				}
3142			} else {
3143				// if we have just one field that has enabled Replace main image, activate
3144				if ( $( document ).find( '.pewc-replace-main-image' ).length > 0 ) {
3145					return true;
3146				}
3147			}
3148			return false;
3149		},
3150
3151		save_original_src: function( $product_img ) {
3152			if ( $product_img.attr( 'data-pewc-old-src' ) ) {
3153				return; // already set, do nothing
3154			}
3155			// Set original src values
3156			$product_img.attr( 'data-pewc-old-src', $product_img.attr( 'src' ) );
3157			// 3.13.3, data-src is used by WooCommerce zoom image
3158			if ( $product_img.attr( 'data-src' ) ) {
3159				$product_img.attr( 'data-pewc-old-data-src', $product_img.attr( 'data-src' ) );
3160			} else {
3161				$product_img.attr( 'data-pewc-old-data-src', '' );
3162			}
3163			if ( $product_img.attr( 'srcset' ) ) {
3164				$product_img.attr( 'data-pewc-old-srcset', $product_img.attr( 'srcset' ) );
3165			} else {
3166				$product_img.attr( 'data-pewc-old-srcset', '' );
3167			}
3168			// photoswipe gallery
3169			if ( $product_img.attr( 'data-large_image' ) ) {
3170				$product_img.attr( 'data-pewc-old-data-large_image', $product_img.attr( 'data-large_image' ) );
3171			} else {
3172				$product_img.attr( 'data-pewc-old-data-large_image', '' );
3173			}
3174			if ( $product_img.attr( 'data-large_image_width' ) ) {
3175				$product_img.attr( 'data-pewc-old-data-large_image_width', $product_img.attr( 'data-large_image_width' ) );
3176			} else {
3177				$product_img.attr( 'data-pewc-old-data-large_image_width', '' );
3178			}
3179			if ( $product_img.attr( 'data-large_image_height' ) ) {
3180				$product_img.attr( 'data-pewc-old-data-large_image_height', $product_img.attr( 'data-large_image_height' ) );
3181			} else {
3182				$product_img.attr( 'data-pewc-old-data-large_image_height', '' );
3183			}
3184
3185		},
3186
3187		// 4.3.13, created a separate function outside of save_original_src()
3188		save_original_zoom_src: function( $product_img ) {
3189
3190			if ( $product_img.attr( 'data-pewc-old-zoom' ) ) {
3191				return; // already set, do nothing
3192			}
3193
3194			var zoomImg = $product_img.closest( pewc_vars.product_img_wrap ).find( pewc_vars.product_img_zoom ).eq(0);
3195			if ( zoomImg.length ) {
3196				$product_img.attr( 'data-pewc-old-zoom', zoomImg.attr( pewc_vars.product_img_zoom_src ) );
3197			} else {
3198				// zoomImg not yet in DOM (e.g. Enfold theme) — fall back to data-src, which jquery.zoom uses to populate zoomImg
3199				$product_img.attr( 'data-pewc-old-zoom', $product_img.attr( 'data-src' ) || $product_img.attr( 'src' ) );
3200			}
3201
3202		},
3203
3204		update_add_on_image: function( field, $form ) {
3205			
3206			var field_wrapper = $( field ).closest( '.pewc-item' );
3207			var is_layered = $( field_wrapper ).attr( 'data-field-layered' );
3208
3209			if( ! add_on_images.replace_image( field_wrapper ) && is_layered != 'yes' ) {
3210				return;
3211			}
3212
3213			var field_type = $( field_wrapper ).attr( 'data-field-type' );
3214
3215			var $product        	= $form.closest( '.product' ),
3216				$product_gallery  	= $product.find( pewc_vars.product_gallery ),
3217				$layer_parent 		= pewc_vars.layer_parent,
3218				$gallery_nav      	= $product.find( '.flex-control-nav' ),
3219				$gallery_img      	= $gallery_nav.find( 'li:eq(0) img' ),
3220				$product_img_wrap 	= $product_gallery.find( pewc_vars.product_img_wrap ).eq( 0 ),
3221				$product_img      	= $product_img_wrap.find( 'img' ).eq( 0 ),
3222				$product_link     	= $product_img_wrap.find( 'a' ).eq( 0 );
3223
3224			if( ! $( field_wrapper ).hasClass( 'pewc-has-field-image' ) && field_type != 'image_swatch' && field_type != 'select-box' ) {
3225				// 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
3226				add_on_images.check_if_src_hidden( $product_img );
3227				return;
3228			}
3229
3230			// 3.21.4, Ignore fields in hidden groups
3231			if ( $( field_wrapper ).closest( '.pewc-group-wrap' ).hasClass( 'pewc-group-hidden' ) ) {
3232				add_on_images.check_if_src_hidden( $product_img );
3233				return; 
3234			}
3235
3236			// 3.21.4, Ignore hidden variation-dependent fields and hidden fields
3237			if( ( $( field_wrapper ).hasClass( 'pewc-variation-dependent' ) && ! $( field_wrapper ).hasClass( 'active' ) ) || $( field_wrapper ).hasClass( 'pewc-hidden-field' ) ) {
3238				add_on_images.check_if_src_hidden( $product_img );
3239				return;
3240			}
3241
3242			var add_on_image_wrapper;
3243			var add_on_image_src;
3244			var add_on_image_large_image, add_on_image_large_image_width, add_on_image_large_image_height;
3245			var turn = 'off';
3246
3247			var add_on_image_field = '', add_on_image_option = '';
3248
3249			if( field_type == 'checkbox' && $( field ).prop( 'checked' ) && add_on_images.replace_image( field_wrapper ) != 'replace_image_swatch_only' ) {
3250				turn = 'on';
3251				add_on_image_wrapper = $( field_wrapper ).find( '.pewc-item-field-image-wrapper' );
3252				add_on_image_src = $( add_on_image_wrapper ).attr( 'data-image-full-size' );
3253				add_on_image_srcset = add_on_image_src;
3254				// photoswipe gallery
3255				add_on_image_large_image = $( add_on_image_wrapper ).attr( 'data-image-full-size' );
3256				add_on_image_large_image_width = $( add_on_image_wrapper ).attr( 'data-large_image_width' );
3257				add_on_image_large_image_height = $( add_on_image_wrapper ).attr( 'data-large_image_height' );
3258				// 3.27.4, for Checkbox field, maybe we only need to detect this class to know it's checked?
3259				add_on_image_field = 'pewc-add-on-image-' + $( field_wrapper ).attr( 'data-field-id' );
3260			}
3261			if( field_type == 'image_swatch') {
3262				add_on_image_wrapper = field.closest( '.pewc-radio-image-wrapper' );
3263
3264				if ( add_on_image_wrapper.hasClass( 'checked' ) ) {
3265					add_on_image_src = add_on_image_wrapper.find( 'img' ).attr( 'data-src' );
3266					add_on_image_srcset = add_on_image_src;
3267					// photoswipe gallery
3268					add_on_image_large_image = add_on_image_wrapper.find( 'img' ).attr( 'data-large_image' );
3269					add_on_image_large_image_width = add_on_image_wrapper.find( 'img' ).attr( 'data-large_image_width' );
3270					add_on_image_large_image_height = add_on_image_wrapper.find( 'img' ).attr( 'data-large_image_height' );
3271
3272					if (add_on_image_src != undefined) {
3273						turn = 'on';
3274						// 3.27.5
3275						if ( $( field_wrapper ).hasClass( 'pewc-item-radio' ) ) {
3276							$product_img.closest( '.' + pewc_vars.layer_parent ).removeClass(function(index, className) {
3277								return (className.match(/(^|\s)pewc\-add\-on\-image\-\S+/g) || []).join(' ');
3278							});
3279						}
3280						// 3.27.4
3281						add_on_image_field = 'pewc-add-on-image-' + $( field_wrapper ).attr( 'data-field-id' );
3282						add_on_image_option = add_on_image_field + '-' + $( field ).attr( 'id' ).replace( $( field_wrapper ).attr( 'data-id' ) + '_', '' );
3283					}
3284				}
3285			} else if ( field_type == 'select-box' && add_on_images.replace_image( field_wrapper ) != 'replace_image_swatch_only' ) {
3286				// 3.13.7
3287				if ( field_wrapper.find( 'input.dd-selected-value' ).val() != '' ) {
3288					// check if the full image exists
3289					var src_image = field_wrapper.find( 'input.dd-selected-image-full' );
3290					if ( src_image.length > 0 ) {
3291						add_on_image_src = src_image.val();
3292					} else {
3293						src_image = field_wrapper.find( 'img.dd-selected-image' );
3294						add_on_image_src = src_image.attr( 'src' );
3295					}
3296					add_on_image_srcset = add_on_image_src;
3297					// photoswipe gallery
3298					add_on_image_large_image = add_on_image_src;
3299					add_on_image_large_image_width = src_image.attr( 'data-imgsrc-width' );
3300					add_on_image_large_image_height = src_image.attr( 'data-imgsrc-height' );
3301
3302					if ( add_on_image_src != undefined) {
3303						turn = 'on';
3304						// 3.27.4, always remove first for Select Box, so that the previous option selected is removed first
3305						$product_img.closest( '.' + pewc_vars.layer_parent ).removeClass(function(index, className) {
3306							return (className.match(/(^|\s)pewc\-add\-on\-image\-\S+/g) || []).join(' ');
3307						});
3308						add_on_image_field = 'pewc-add-on-image-' + $( field_wrapper ).attr( 'data-field-id' );
3309						add_on_image_option = add_on_image_field + '-index-' + $( field_wrapper ).find( 'select' ).prop( 'selectedIndex' );
3310					}
3311				}
3312			}
3313
3314			if( is_layered == 'yes' ) {
3315				// This is a layered image so we are going to create/update layers
3316				var field_id = $( field_wrapper ).attr( 'data-field-id' );
3317				var layer_id = 'pewc-layer-' + field_id;
3318				var layer_index = $( field_wrapper ).attr( 'data-field-index' );
3319				// This is the wrapper, e.g. woocommerce-product-gallery__wrapper
3320				// Add our cloned image into a div within this wrapper
3321				// The wrapper can be absolutely positioned over the main image
3322				var swatch_src = $( add_on_image_wrapper ).find( 'img' ).attr( 'data-large_image' );
3323				// Check for an alternative image to replace the main image
3324				if( $( add_on_image_wrapper ).find( 'img' ).attr( 'data-alt_image' ).length > 0 ) {
3325					swatch_src = $( add_on_image_wrapper ).find( 'img' ).attr( 'data-alt_image' );
3326				}
3327				if( $( '.' + layer_id ).length === 0 && $( add_on_image_wrapper ).hasClass( 'checked' ) ) {
3328					// Get the selected swatch image src
3329					var layer_image = '<img class="pewc-layer-image" src="' + swatch_src + '">';
3330					// Make the layer
3331					// var layer = $product_img.clone().insertAfter( $product_img ).addClass( layer_id );
3332					$( $( '.' + $layer_parent ) ).append( '<div class="pewc-image-layer ' + layer_id + '" style="z-index:' + ( layer_index + 1 ) * 10 + '">' + layer_image + '</div>' );
3333				} else if( $( '.' + layer_id ).length !== 0 && $( add_on_image_wrapper ).hasClass( 'checked' ) ) {
3334					// Layer exists but need to update the image inside
3335					// swatch_src = $( add_on_image_wrapper ).find( 'img' ).attr( 'data-large_image' );
3336					$( '.' + layer_id ).find( 'img' ).attr( 'src', swatch_src );
3337				} else if( ! $( add_on_image_wrapper ).hasClass( 'checked' ) ) {
3338					$( '.' + layer_id ).remove();
3339				}
3340
3341				// 3.27.8, add special classes
3342				if ( add_on_image_field != '' && ! $( '.' + pewc_vars.layer_parent ).hasClass( add_on_image_field ) ) {
3343					$product_img.closest( '.' + pewc_vars.layer_parent ).addClass( add_on_image_field );
3344				}
3345				if ( add_on_image_option != '' && ! $( '.' + pewc_vars.layer_parent ).hasClass( add_on_image_option ) ) {
3346					$product_img.closest( '.' + pewc_vars.layer_parent ).addClass( add_on_image_option );
3347				}
3348
3349			} else if ( add_on_image_src && turn == 'on' ) {
3350
3351				// maybe save original
3352				add_on_images.save_original_src( $product_img );
3353				add_on_images.save_original_zoom_src( $product_img );
3354
3355				$product_img.attr( 'data-pewc-from-field', $( field_wrapper ).attr( 'data-id' ) );
3356				$product_img.attr( 'src', add_on_image_src );
3357				$product_img.attr( 'srcset', add_on_image_srcset );
3358				$product_img.attr( 'data-src', add_on_image_src ); // 3.13.3, used by WC zoomImg
3359				// replace photoswipe gallery
3360				$product_img.attr( 'data-large_image', add_on_image_large_image );
3361				$product_img.attr( 'data-large_image_width', add_on_image_large_image_width );
3362				$product_img.attr( 'data-large_image_height', add_on_image_large_image_height );
3363
3364				// replace zoom image
3365				//var zoomImg = $product_img.closest( pewc_vars.product_img_wrap ).find( pewc_vars.product_img_zoom ).eq(0);
3366				//if ( zoomImg ) {
3367				//	zoomImg.attr( pewc_vars.product_img_zoom_src, add_on_image_src );
3368				//}
3369
3370				// 4.3.13, newer version, waits for zoomImg to be ready
3371				var $wrap   = $product_img.closest( pewc_vars.product_img_wrap );
3372				var zoomImg = $wrap.find( pewc_vars.product_img_zoom ).eq(0);
3373
3374				if ( zoomImg.length ) {
3375					add_on_images.save_original_zoom_src( $product_img );
3376					zoomImg.attr( pewc_vars.product_img_zoom_src, add_on_image_src );
3377				} else if ( $wrap[0] ) {
3378					var _src = add_on_image_src;
3379					var zoomObserver = new MutationObserver( function() {
3380						var $z = $wrap.find( pewc_vars.product_img_zoom ).eq(0);
3381						if ( $z.length ) {
3382							zoomObserver.disconnect();
3383							add_on_images.save_original_zoom_src( $product_img );
3384							$z.attr( pewc_vars.product_img_zoom_src, _src );
3385						}
3386					} );
3387					zoomObserver.observe( $wrap[0], { childList: true, subtree: true } );
3388				}
3389
3390				// 3.27.4, add special classes
3391				if ( add_on_image_field != '' && ! $( '.' + pewc_vars.layer_parent ).hasClass( add_on_image_field ) ) {
3392					$product_img.closest( '.' + pewc_vars.layer_parent ).addClass( add_on_image_field );
3393				}
3394				if ( add_on_image_option != '' && ! $( '.' + pewc_vars.layer_parent ).hasClass( add_on_image_option ) ) {
3395					$product_img.closest( '.' + pewc_vars.layer_parent ).addClass( add_on_image_option );
3396				}
3397			} else {
3398				// 3.27.4, remove all our special classes, it will be added back if we still have a swatch selected
3399				$product_img.closest( '.' + pewc_vars.layer_parent ).removeClass(function(index, className) {
3400					return (className.match (/(^|\s)pewc\-add\-on\-image\-\S+/g) || []).join(' ');
3401				});
3402				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
3403			}
3404
3405			// 3.13.2 bring back the focus on the main image to see the selected image swatch
3406			if ( pewc_vars.replace_image_focus == 'yes' ) {
3407				var control_list_selector = '.' + pewc_vars.control_container + ' ' + pewc_vars.control_list;
3408				$( control_list_selector ).first().find( pewc_vars.control_element ).trigger( 'click' ); // 3.25.6, changed from click() to trigger('click') because click() is deprecated
3409				$( '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
3410			}
3411		},
3412
3413		// If we are using secondary images, then hide/show the correct child swatch field
3414		change_child: function( e ) {
3415			
3416			var parent_swatch = e.target;
3417			var parent_index = $( parent_swatch ).closest( '.pewc-item' ).find( '.pewc-radio-image-wrapper.checked input' ).attr( 'data-option-index' );
3418			if( ! isNaN( parent_index ) ) {
3419				$( '.pewc-swatch-child' ).addClass( 'pewc-visibility-hidden' );
3420				$( '.pewc-swatch-child-' + parent_index ).removeClass( 'pewc-visibility-hidden' );
3421				var active_layer_id = $( '.pewc-swatch-child-' + parent_index ).attr( 'data-field-id' );
3422				// Get the selected child index
3423				var selected_input = $( '.pewc-swatch-child' ).not( '.pewc-visibility-hidden' ).closest( '.pewc-item' ).find( '.pewc-radio-image-wrapper.checked input' );
3424				var index = $( selected_input ).attr( 'data-option-index' );
3425				// Trigger the child swatch
3426				// var selected = $( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' ).prop( 'checked' );
3427
3428				$( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper.pewc-radio-form-field' ).prop('checked', false);
3429
3430				// When we change the child, we need to hide unwanted image layers on the main image
3431				$( '.pewc-layer-' + active_layer_id ).show();
3432				// Hide the other child swatch layers
3433				var child_swatch_ids = JSON.parse( pewc_vars.child_swatch_ids );
3434				for( var i in child_swatch_ids ) {
3435					if( child_swatch_ids[i] != active_layer_id ) {
3436						$( '.pewc-layer-' + child_swatch_ids[i] ).fadeOut( 150 );
3437					} 
3438				}
3439				// Find any layers that we need to hide
3440				// $( '.pewc-show-for' ).each( function( layer_index, element ) {
3441				// 	// This layer only shows when a specific field is visible
3442				// 	var show_for = $( this ).attr( 'data-show-for' );
3443				// 	var layer_id = $( this ).attr( 'data-field-id' );
3444				// 	if( show_for != active_layer_id ) {
3445				// 		$( '.pewc-layer-' + layer_id ).fadeOut( 150 );
3446				// 	} else {
3447				// 		$( '.pewc-layer-' + layer_id ).fadeIn( 150 );
3448				// 	}
3449				// });
3450				// $( '.pewc-image-layer' ).not( '.pewc-layer-' + active_layer_id ).fadeOut( 250 );
3451				
3452
3453				// if( ! selected ) {
3454					$( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' ).addClass( 'here-' + parent_index + '-' + index ).trigger( 'click' );
3455					// selected = $( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' ).prop( 'checked' );
3456					$( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' ).trigger( 'change' );
3457					// if( selected ) {
3458						// $( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' ).prop( 'checked', false ).trigger( 'change' );
3459						// selected = $( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' ).prop( 'checked' );
3460						// $( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' ).addClass( 'here-' + parent_index + '-' + index ).trigger( 'click' );
3461						// selected = $( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' ).prop( 'checked' );
3462					// }
3463
3464				// }
3465				
3466			}
3467
3468		},
3469
3470		// If we've updated a child swatch, we need to ensure that other child swatches have the same value
3471		sync_children: function( e ) {
3472
3473			// Get the active parent index
3474			var parent_index = $( '.pewc-swatch-parent' ).find( '.pewc-radio-image-wrapper.checked input' ).attr( 'data-option-index' );
3475			var child_swatch = e.target;
3476			// Get the index of the selected child swatch
3477			var index = $( child_swatch ).closest( '.pewc-item' ).find( '.pewc-radio-image-wrapper.checked input' ).attr( 'data-option-index' );
3478			if( ! isNaN( index ) ) {
3479				// Ensure that all other child swatch fields have the same item selected
3480				$( '.pewc-swatch-child' ).find( '.pewc-radio-image-wrapper' ).removeClass( 'checked' );
3481				$( '.pewc-swatch-child' ).find( '.pewc-radio-image-wrapper-' + index ).addClass( 'checked' ).find( 'input' );
3482				// Need to ensure that the correct main image is displayed
3483				// Trigger a click on the currently visible selected swatch
3484				var input = $( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' );
3485				$( '.pewc-swatch-child-' + parent_index ).find( '.pewc-radio-image-wrapper-' + index + ' input' ).trigger( 'click' );
3486			}
3487
3488		},
3489
3490		check_if_src_hidden: function( $product_img ) {
3491			if ( $product_img.attr('data-pewc-from-field') != '' ) {
3492
3493				// 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
3494				var pewc_from_field = $( ".pewc-item."+$product_img.attr('data-pewc-from-field') );
3495
3496				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' ) ) ) {
3497					// field is hidden, reset image
3498					// 3.21.4, added variation-dependent fields
3499					//add_on_images.reset_main_image( $product_img );
3500					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
3501				}
3502			}
3503		},
3504
3505		reset_main_image: function ( $product_img ) {
3506			$product_img.attr( 'data-pewc-from-field', '' );
3507			$product_img.attr( 'src', $product_img.attr( 'data-pewc-old-src' ) );
3508			$product_img.attr( 'srcset', $product_img.attr( 'data-pewc-old-srcset' ) );
3509			$product_img.attr( 'data-src', $product_img.attr( 'data-pewc-old-data-src' ) ); // 3.13.3
3510			// photoswipe gallery
3511			$product_img.attr( 'data-large_image', $product_img.attr( 'data-pewc-old-data-large_image' ) );
3512			$product_img.attr( 'data-large_image_width', $product_img.attr( 'data-pewc-old-data-large_image_width' ) );
3513			$product_img.attr( 'data-large_image_height', $product_img.attr( 'data-pewc-old-data-large_image_height' ) );
3514			// zoom image
3515			var zoomImg = $product_img.closest( pewc_vars.product_img_wrap ).find( pewc_vars.product_img_zoom ).eq(0);
3516			if ( zoomImg ) {
3517				zoomImg.attr( pewc_vars.product_img_zoom_src, $product_img.attr( 'data-pewc-old-zoom' ) );
3518			}
3519		},
3520
3521		replace_main_with_default: function( $product_img='', is_layered=true ) {
3522			// 3.17.2
3523			var replace_fields = [ 'image_swatch', 'select-box', 'checkbox' ];
3524			var replaced = false;
3525
3526			$( '.pewc-item' ).each( function( index, element ) {
3527				// 3.20.1
3528				var layered_image = $(this).hasClass( 'pewc-layered-image' );
3529
3530				// Replace main image is not active for this field, skip
3531				// 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
3532				if ( ! add_on_images.replace_image( $(this) ) && ! layered_image ) {
3533					return;
3534				}
3535
3536				// 3.25.4, skip layered images when resetting normal swatch fields?
3537				if ( layered_image && ! is_layered ) {
3538					return;
3539				}
3540
3541				// Main image has been replaced, we can skip
3542				// 3.20.1, don't skip if this is a layered image
3543				if ( replaced && ! layered_image ) {
3544					return;
3545				}
3546
3547				// Ignore fields in hidden groups
3548				if ( $( this ).closest( '.pewc-group-wrap' ).hasClass( 'pewc-group-hidden' ) ) {
3549					return; 
3550				}
3551
3552				// Ignore hidden variation-dependent fields and hidden fields
3553				if( ( $( this ).hasClass( 'pewc-variation-dependent' ) && ! $( this ).hasClass( 'active' ) ) || $( this ).hasClass( 'pewc-hidden-field' ) ) {
3554					return;
3555				}
3556
3557				if ( replace_fields.indexOf( $( this ).attr( 'data-field-type' ) ) > -1 && $( this ).attr( 'data-field-value' ) != '' ) {
3558					// 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
3559					var field_type = $( this ).attr( 'data-field-type' );
3560					if ( field_type  == 'image_swatch' ) {
3561						// find the first checked input, that must be the default
3562						$( this ).find( '.pewc-radio-form-field' ).each( function( index, element ){
3563							// 3.20.1, allow multiple layered images with default values
3564							if ( $( this ).is( ':checked' ) && ( ! replaced || layered_image ) ) {
3565								// 3.26.15, only replace if option has an image
3566								if ( $( this ).closest( '.pewc-radio-image-wrapper' ).find( 'img' ).attr( 'data-src' ) ) {
3567									add_on_images.update_add_on_image( $( this ), $(this).closest( 'form' ) );
3568									replaced = true;
3569									return;
3570								}
3571							}
3572						});
3573					} else if ( field_type == 'checkbox' ) {
3574						if ( $( this ).find( '.pewc-form-field' ).is( ':checked' ) && $( this ).find( '.pewc-item-field-image-wrapper' ).length > 0 ) {
3575							// 4.3.0, only do this if checkbox has an image, prevent an infinite loop
3576							add_on_images.update_add_on_image( $( this ).find( '.pewc-form-field' ), $(this).closest( 'form' ) );
3577							replaced = true;
3578							return;
3579						}
3580					} else if ( field_type == 'select-box' ) {
3581						add_on_images.update_add_on_image( $( this ).find( 'select.pewc-form-field' ), $(this).closest( 'form' ) );
3582						replaced = true;
3583						return;
3584					}
3585				}
3586			});
3587
3588			// 3.24.7, if we didn't find a swatch, reset the main image
3589			if ( ! replaced && $product_img != '' ) {
3590				add_on_images.reset_main_image( $product_img );
3591			}
3592		},
3593
3594	}
3595
3596	add_on_images.init();
3597
3598	var tooltips = {
3599
3600		init: function() {
3601
3602			if( pewc_vars.enable_tooltips == 'yes' && ! pewc_vars.dequeue_tooltips ) {
3603				$( '.tooltip' ).tooltipster(
3604					{
3605						theme: 'tooltipster-shadow',
3606		        		side: 'right',
3607						contentAsHTML: pewc_vars.contentAsHTML,
3608						autoClose : pewc_vars.autoClose,
3609						interactive : pewc_vars.interactive,
3610						hideOnClick : pewc_vars.hideOnClick,
3611						trigger : pewc_vars.trigger,
3612						triggerOpen : pewc_vars.triggerOpen,
3613						triggerClose: pewc_vars.triggerClose
3614					}
3615				);
3616			}
3617
3618		}
3619
3620	}
3621
3622	tooltips.init();
3623
3624	var quickview = {
3625
3626		init: function() {
3627			$( 'body' ).on( 'click', '.pewc-show-quickview', this.show_quickview );
3628			$( 'body' ).on( 'click', '#pewc-quickview-background, .pewc-close-quickview', this.hide_quickview );
3629		},
3630
3631		show_quickview: function( e ) {
3632			e.stopPropagation();
3633			if( pewc_vars.quickview == 'yes' ) {
3634				// Open the link in a new tab
3635				e.preventDefault();
3636				$( 'body' ).addClass( 'pewc-quickview-active' );
3637			}
3638			
3639			// $( '.pewc-quickview-product-wrapper' ).hide();
3640			$( '#pewc-quickview-' + $(this).closest( 'li.pewc-item' ).attr( 'data-id' ) + '_' + $( this ).attr( 'data-child-product-id' ) ).css( 'left', '50%' );
3641		},
3642
3643		hide_quickview: function( e ) {
3644			 e.preventDefault();
3645			 $( 'body' ).removeClass( 'pewc-quickview-active' );
3646			 $( '.pewc-quickview-product-wrapper' ).css( 'left', '-5000px' );
3647		}
3648
3649	}
3650
3651	quickview.init();
3652
3653	var check_time = {
3654
3655		interval_id: null,
3656
3657		init: function() {
3658			var today = new Date();
3659			var loaded = $( '.pewc-cl-wrapper' ).first().attr( 'data-today' );
3660			today.setHours(0,0,0,0);
3661			if( today > loaded ) {
3662				$( '.pewc-cl-wrapper' ).addClass( 'disabled' );
3663				$( '.pewc-cl-wrapper' ).find( '.pewc-radio-form-field' ).prop( 'disabled', true );
3664			}
3665			// check_time.check();
3666			check_time.interval_id = setInterval(
3667				function() {
3668					check_time.check();
3669				},
3670				5000
3671			);
3672			$( '.pewc-cl-wrapper' ).find( 'input' ).on( 'change', this.update_date );
3673
3674			// Auto-select the default option in each calendar list field so that
3675			// calculations using {field_XXX_option_price} have a value on page load.
3676			// data-default-value holds the day offset (e.g. "6"), matching data-offset on each radio.
3677			$( 'form.cart .pewc-item-calendar-list' ).each( function() {
3678				var $field = $( this );
3679				if ( $field.find( 'input[type=radio]:checked' ).length === 0 ) {
3680					var default_val = $field.attr( 'data-default-value' );
3681					var $enabled = $field.find( '.pewc-cl-wrapper:not(.disabled) input[type=radio]:enabled' );
3682					var $target = ( default_val !== '' && default_val !== undefined )
3683						? $enabled.filter( '[data-offset="' + default_val + '"]' )
3684						: $();
3685					if ( ! $target.length ) {
3686						$target = $enabled.first();
3687					}
3688					if ( $target.length ) {
3689						$target.prop( 'checked', true ).trigger( 'change' );
3690					}
3691				}
3692			} );
3693		},
3694
3695		check: function() {
3696			$( '.pewc-cl-has-time' ).each( function() {
3697				var hour = $( this ).attr( 'data-hour' );
3698				var min = $( this ).attr( 'data-minute' );
3699				if( ! hour || ! min ) {
3700					return;
3701				}
3702				if( check_time.is_after( hour, min ) ) {
3703					clearInterval( check_time.interval_id );
3704					var now = new Date();
3705					var client_minutes = now.getHours() * 60 + now.getMinutes();
3706					var url = new URL( window.location.href );
3707					url.searchParams.set( 'pewc_client_minutes', client_minutes );
3708					window.location.replace( url.toString() );
3709					return false; // Break out of .each()
3710				}
3711			});
3712		},
3713
3714		is_after: function( hour, min ) {
3715			let ms_today = Date.now() - new Date().setHours(0,0,0,0);
3716			return ms_today > (hour*3.6e6 + min*6e4);
3717		},
3718
3719		update_date: function() {
3720			var field_id = $( this ).closest( '.pewc-item' ).attr( 'data-field-id' );
3721			var id = $( this ).closest( '.pewc-item' ).attr( 'data-id' );
3722			$( '#pewc_cl_' + field_id ).val( $( this ).attr( 'data-date' ) );
3723			$( '#pewc_cl_price_' + field_id ).val( $( this ).closest( '.pewc-item' ).attr( 'data-field-price' ) );
3724			$( '#pewc_cl_offset_' + id ).val( $( this ).attr( 'data-offset' ) );
3725		}
3726
3727	}
3728
3729	check_time.init();
3730
3731
3732})(jQuery);
3733
3734// 3.21.4, moved outside so that other scripts can use this function
3735function pewc_wc_price_without_currency( price ) {
3736
3737	var price_settings = {
3738		decimal: pewc_vars.decimal_separator,
3739		thousand: pewc_vars.thousand_separator,
3740		precision: pewc_vars.decimals,
3741		format: '%v'
3742	};
3743
3744	if ( pewc_vars.price_trim_zeros == 'yes' && price == parseInt( price ) ) {
3745		// 3.21.3, trim zeros if filter is active
3746		price_settings.precision = 0;
3747	}
3748
3749	// since 3.12.0
3750	price = accounting.formatMoney( price, price_settings );
3751
3752	return price;
3753
3754}
3755
3756// 3.21.4, moved outside so that other scripts can use this function
3757function pewc_wc_price( price, price_only=false, update_pewc_total_calc_price=true ) {
3758
3759	if ( update_pewc_total_calc_price ) {
3760		jQuery( '#pewc_total_calc_price' ).val( price ); // Used in Bookings for WooCommerce
3761	}
3762
3763	// since 3.12.0
3764	var currency_html = '<span class="woocommerce-Price-currencySymbol">%s</span>';
3765	var currency_format = '';
3766	if ( price_only ) {
3767		currency_html = '%s';
3768	}
3769
3770	if( pewc_vars.currency_pos == 'left' ) {
3771		currency_format = currency_html+'%v';
3772	} else if( pewc_vars.currency_pos == 'right' ) {
3773		currency_format = '%v'+currency_html;
3774	} else if( pewc_vars.currency_pos == 'left_space' ) {
3775		currency_format = currency_html+' %v';
3776	} else if( pewc_vars.currency_pos == 'right_space' ) {
3777		currency_format = '%v '+currency_html;
3778	}
3779
3780	var price_settings = {
3781		symbol: pewc_vars.currency_symbol,
3782		decimal: pewc_vars.decimal_separator,
3783		thousand: pewc_vars.thousand_separator,
3784		precision: pewc_vars.decimals,
3785		format: currency_format
3786	};
3787
3788	if ( pewc_vars.price_trim_zeros == 'yes' && price == parseInt( price ) ) {
3789		// 3.21.3, trim zeros if filter is active
3790		price_settings.precision = 0;
3791	}
3792
3793	price = accounting.formatMoney( price, price_settings );
3794
3795	if ( ! price_only ) {
3796		return '<span class="woocommerce-Price-amount amount"><bdi>' + price + '</bdi></span>';
3797	}
3798
3799	return price;
3800
3801}
3802
3803// 3.21.7
3804function pewc_wcfad_apply_discount() {
3805	return typeof pewc_wcfad !== 'undefined' && pewc_wcfad.apply_discount();
3806}
3807
3808// 3.27.0
3809function pewc_is_booking_product() {
3810
3811	return ( jQuery( '#num_units_int' ).length > 0 );
3812
3813}
3814
3815// 3.27.0, for compatibility with Bookings for WooCommerce
3816function pewc_get_quantity( qty=1, type='' ) {
3817
3818	if ( pewc_wcbvp_variation_grid() ) {
3819		// 4.1.1, return the total variations selected when using Better Variations grid mode
3820		qty = jQuery( '#wcbvp_total_variations' ).val();
3821		if ( qty < 1 ) qty = 1; // so that the add-on price updates even if no variations have been selected yet
3822	} else if( jQuery( 'form.cart .quantity .qty' ).val() && 'one-only' !== type ) {
3823		qty = jQuery( 'form.cart .quantity .qty' ).val();
3824	} else if ( pewc_is_booking_product() ) {
3825		// for Booking products, where the quantity field is not available
3826		qty = 1; // 3.27.11, changed to 1 so that "Price per booking unit" setting is respected. Previously jQuery( '#num_units_int' ).val();
3827		if ( jQuery( '#num_bookings' ).length > 0 && ! isNaN( jQuery( '#num_bookings' ).val() ) && 'linked' === type ) {
3828			// also multiply by quantity?
3829			qty = qty * jQuery( '#num_bookings' ).val();
3830		}
3831	}
3832
3833	return qty;
3834
3835}
3836
3837// 4.1.1, Better Variations grid mode
3838function pewc_wcbvp_variation_grid() {
3839	return ( jQuery( 'body' ).find( '.wcbvp-grid-quantity-field' ).length > 0 );
3840}
3841
3842// 4.3.3, separated into a function and moved here so that repeatable groups can access it
3843function pewc_accordion_click( header ){
3844	var is_open = jQuery( header ).closest( '.pewc-group-wrap' ).hasClass( 'group-active' );
3845
3846	if ( jQuery( header ).closest( '.pewc-group-wrap' ).hasClass( 'pewc-disabled-group') ) {
3847		return;
3848	}
3849	if( pewc_vars.close_accordion == 'yes' ) {
3850		jQuery( '.pewc-group-wrap' ).removeClass( 'group-active' );
3851	}
3852	// Don't reopen group if we've just closed it, only if close_accordion snippet is active
3853	if( ! is_open || pewc_vars.close_accordion != 'yes' ) {
3854		jQuery( header ).closest('.pewc-group-wrap').toggleClass('group-active');
3855	}
3856}

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.