PageSourceSearch

https://www.backsplash.com/wp-content/plugins/woocommerce-tm-extra-product-options/assets/js/tm-epo.js?ver=7.6

js backsplash.com collected 2026-09-25 23:41:08 UTC 505,644 bytes, 14,215 lines download raw bytes

1( function( window, document, $ ) {
2	'use strict';
3
4	var tcAPI = {};
5	var TMEPOJS = window.TMEPOJS;
6	var wp = window.wp;
7	var TMEPOQTRANSLATEXJS = window.TMEPOQTRANSLATEXJS;
8	var noUiSlider = window.noUiSlider;
9	var ClipboardEvent = window.ClipboardEvent;
10	var DataTransfer = window.DataTransfer;
11	var lateVariationEvent = [];
12	var latecpflogicactions = [];
13	var tmLazyloadContainer = false;
14	var variationsFormIsLoaded = false;
15	var jBody = $( 'body' );
16	var jWindow = $( window );
17	var jDocument = $( document );
18	var errorObject;
19	var FloatingTotalsBox;
20	var currentAjaxButton;
21	var currentAddToCartButton;
22	var errorContainer = $( window );
23	var tcmexp = window.tcmexp;
24	var _ = window._;
25	var priceCache = false;
26
27	var getLocalInputDecimalSeparator = function() {
28		if ( TMEPOJS.tm_epo_global_input_decimal_separator === '' ) {
29			return TMEPOJS.currency_format_decimal_sep;
30		}
31		return $.epoAPI.locale.getSystemDecimalSeparator();
32	};
33
34	var getLocalDecimalSeparator = function() {
35		if ( TMEPOJS.tm_epo_global_displayed_decimal_separator === '' ) {
36			return TMEPOJS.currency_format_decimal_sep;
37		}
38		return $.epoAPI.locale.getSystemDecimalSeparator();
39	};
40
41	var getLocalThousandSeparator = function() {
42		if ( TMEPOJS.tm_epo_global_displayed_decimal_separator === '' ) {
43			return TMEPOJS.currency_format_thousand_sep;
44		}
45		return $.epoAPI.locale.getSystemDecimalSeparator();
46	};
47
48	var getEpoDelay = function() {
49		if ( TMEPOJS.tm_epo_start_animation_delay ) {
50			return TMEPOJS.tm_epo_start_animation_delay;
51		} else if ( window.tc_epo_delay ) {
52			return window.tc_epo_delay;
53		}
54		return 500;
55	};
56
57	var getEpoAnimationDelay = function() {
58		if ( TMEPOJS.tm_epo_animation_delay ) {
59			return TMEPOJS.tm_epo_start_animation_delay;
60		} else if ( window.tc_epo_animation_delay ) {
61			return window.tc_epo_animation_delay;
62		}
63		return 500;
64	};
65
66	var originalVal = $.fn.val;
67
68	if ( ! TMEPOJS || ! wp ) {
69		return;
70	}
71
72	// Trigger plugin events when other plugins use val.
73	$.fn.val = function() {
74		var result = originalVal.apply( this, arguments );
75		if ( arguments.length > 0 ) {
76			if ( $( this ).is( '.input-text.qty' ) ) {
77				$( this ).trigger( 'change.cpf' );
78			}
79		}
80		return result;
81	};
82
83	// Set update event for Lazy Load XT
84	if ( TMEPOJS.tm_epo_no_lazy_load === 'no' && $.lazyLoadXT ) {
85		$.extend( $.lazyLoadXT, {
86			autoInit: false,
87			updateEvent: $.lazyLoadXT.updateEvent + ' tmlazy'
88		} );
89	}
90
91	tcAPI.localInputDecimalSeparator = getLocalInputDecimalSeparator();
92	tcAPI.localDecimalSeparator = getLocalDecimalSeparator();
93	tcAPI.localThousandSeparator = getLocalThousandSeparator();
94	tcAPI.epoDelay = getEpoDelay();
95	tcAPI.epoAnimationDelay = getEpoAnimationDelay();
96	tcAPI.getElementFromFieldCache = [];
97	tcAPI.epoSelector = '.tc-extra-product-options';
98	tcAPI.associatedEpoSelector = '.tc-extra-product-options-inline';
99	tcAPI.associatedEpoCart = '.tc-epo-element-product-container-cart';
100	tcAPI.addToCartSelector = "input[name='add-to-cart']";
101	tcAPI.tcAddToCartSelector = 'input.tc-add-to-cart';
102	tcAPI.qtySelector = "input.qty,input[name='quantity'],select.qty,.drop-down-button #qty,.plus-minus-button #qty,.slider-input #amount";
103	tcAPI.associateQtySelector = 'input.tm-qty-alt';
104	tcAPI.addToCartButtonSelector = '.add_to_cart_button, .single_add_to_cart_button';
105	tcAPI.compositeSelector = '.bto_item,.component';
106	tcAPI.nativeProductPriceSelector = TMEPOJS.tm_epo_global_product_price_selector || '.woocommerce .product p.price, .wc-block-components-product-price';
107	tcAPI.associatedNativeProductPriceSelector = '.product-price .associated-price';
108	tcAPI.templateEngine = $.epoAPI.applyFilter( 'tc_adjust_templateEngine', {
109		plain_price: wp.template( 'tc-plain-price' ),
110		suffix: wp.template( 'tc-suffix' ),
111		main_suffix: wp.template( 'tc-main-suffix' ),
112		price: wp.template( 'tc-price' ),
113		price_m: wp.template( 'tc-price-m' ),
114		sale_price: wp.template( 'tc-sale-price' ),
115		sale_price_m10: wp.template( 'tc-sale-price-m10' ),
116		sale_price_m01: wp.template( 'tc-sale-price-m01' ),
117		sale_price_m11: wp.template( 'tc-sale-price-m11' ),
118		tc_chars_remanining: wp.template( 'tc-chars-remanining' ),
119		tc_final_totals: wp.template( 'tc-final-totals' ),
120		tc_floating_box: wp.template( 'tc-floating-box' ),
121		tc_floating_box_nks: wp.template( 'tc-floating-box-nks' ),
122		tc_formatted_price: wp.template( 'tc-formatted-price' ),
123		tc_formatted_sale_price: wp.template( 'tc-formatted-sale-price' ),
124		tc_lightbox: wp.template( 'tc-lightbox' ),
125		tc_lightbox_zoom: wp.template( 'tc-lightbox-zoom' ),
126		tc_section_pop_link: wp.template( 'tc-section-pop-link' ),
127		tc_upload_messages: wp.template( 'tc-upload-messages' )
128	} );
129
130	// make API available to 3rd party plugins
131	$.tcAPI = function() {
132		return tcAPI;
133	};
134	// method for accessing internal api variables
135	$.tcAPIGet = function( name ) {
136		return tcAPI[ name ];
137	};
138
139	// method for setting  internal api variables
140	$.tcAPISet = function( name, value ) {
141		tcAPI[ name ] = value;
142	};
143
144	if ( $.tc_validator ) {
145		$.extend( $.tc_validator.messages, {
146			required: TMEPOJS.tm_epo_global_validator_messages.required,
147			email: TMEPOJS.tm_epo_global_validator_messages.email,
148			url: TMEPOJS.tm_epo_global_validator_messages.url,
149			number: TMEPOJS.tm_epo_global_validator_messages.number,
150			digits: TMEPOJS.tm_epo_global_validator_messages.digits,
151			maxlengthsingle: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.maxlengthsingle ),
152			maxlength: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.maxlength ),
153			minlengthsingle: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.minlengthsingle ),
154			minlength: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.minlength ),
155			max: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.max ),
156			min: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.min ),
157			step: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.step ),
158			lettersonly: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.lettersonly ),
159			lettersspaceonly: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.lettersspaceonly ),
160			alphanumeric: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.alphanumeric ),
161			alphanumericunicode: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.alphanumericunicode ),
162			alphanumericunicodespace: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.alphanumericunicodespace ),
163			repeaterminrows: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.repeaterminrows ),
164			repeatermaxrows: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.repeatermaxrows )
165		} );
166
167		/*
168		ASCII Digits
169		\u0030-\u0039
170
171		Latin Alphabet
172		\u0041-\u005A\u0061-\u007A
173
174		Latin-1 Supplement
175		\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF
176
177		Latin Extended-A
178		\u0100-\u0148\u014A-\u017F
179
180		Latin Extended-B
181		\u0180-\u01BF\u01C4-\u024F
182
183		Latin Extended Additional
184		\u1E02-\u1EF3
185
186		Greek and Coptic
187		\u0370-\u03FF
188
189		Cyrillic
190		\u0400-\u04FF\u0500-\u052F
191
192		Japanese Hiragana
193		\u3040-\u309f
194		Japanese Katakana
195		\u30a0-\u30ff
196		Japanese Kanji (common & uncommon)
197		\u4e00-\u9faf
198		Japanese Kanji (rare)
199		\u3400-\u4dbf
200
201		Arabic
202		\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF\u10E60-\u10E7F\u1EC70-\u1ECBF\u1ED00-\u1ED4F\u1EE00-\u1EEFF
203
204		\u0600-\u06ff
205		\u0600-\u06FF
206
207		Armenian
208		\u0530-\u1058F
209
210		\u0030-\u0039\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u0148\u014A-\u017F\u0180-\u01BF\u01C4-\u024F\u1E02-\u1EF3\u0370-\u03FF\u0400-\u04FF\u0500-\u052F\u3040-\u309f\u30a0-\u30ff\u4e00-\u9faf\u3400-\u4dbf\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF\u10E60-\u10E7F\u1EC70-\u1ECBF\u1ED00-\u1ED4F\u1EE00-\u1EEFF\u0530-\u1058F
211
212		*/
213
214		$.tc_validator.addMethod(
215			'alphanumeric',
216			function( value, element ) {
217				return this.optional( element ) || /^[a-zA-Z0-9.-]+$/i.test( value );
218			},
219			$.tc_validator.messages.alphanumeric
220		);
221
222		$.tc_validator.addMethod(
223			'lettersonly',
224			function( value, element ) {
225				return this.optional( element ) || /^[a-z]+$/i.test( value );
226			},
227			$.tc_validator.messages.lettersonly
228		);
229
230		$.tc_validator.addMethod(
231			'lettersspaceonly',
232			function( value, element ) {
233				return this.optional( element ) || /^[a-z,\u0020]+$/i.test( value );
234			},
235			$.tc_validator.messages.lettersspaceonly
236		);
237
238		$.tc_validator.addMethod(
239			'alphanumericunicode',
240			function( value, element ) {
241				return (
242					this.optional( element ) ||
243					/^[\u0030-\u0039\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u0148\u014A-\u017F\u0180-\u01BF\u01C4-\u024F\u1E02-\u1EF3\u0370-\u03FF\u0400-\u04FF\u0500-\u052F\u3040-\u309f\u30a0-\u30ff\u4e00-\u9faf\u3400-\u4dbf\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF\u10E60-\u10E7F\u1EC70-\u1ECBF\u1ED00-\u1ED4F\u1EE00-\u1EEFF\u0530-\u1058F]+$/i.test(
244						value
245					)
246				);
247			},
248			$.tc_validator.messages.alphanumericunicode
249		);
250
251		$.tc_validator.addMethod(
252			'alphanumericunicodespace',
253			function( value, element ) {
254				return (
255					this.optional( element ) ||
256					/^[\u0030-\u0039\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u0148\u014A-\u017F\u0180-\u01BF\u01C4-\u024F\u1E02-\u1EF3\u0370-\u03FF\u0400-\u04FF\u0500-\u052F\u3040-\u309f\u30a0-\u30ff\u4e00-\u9faf\u3400-\u4dbf\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF\u10E60-\u10E7F\u1EC70-\u1ECBF\u1ED00-\u1ED4F\u1EE00-\u1EEFF\u0530-\u1058F,\u0020]+$/i.test(
257						value
258					)
259				);
260			},
261			$.tc_validator.messages.alphanumericunicodespace
262		);
263		$.tc_validator.addMethod(
264			'repeaterminrows',
265			function( value, element, param ) {
266				return $.epoAPI.math.toInt( $( element ).closest( '.tc-element-inner-wrap' ).find( '.tc-repeater-element' ).length ) >= $.epoAPI.math.toInt( param );
267			},
268			$.tc_validator.messages.repeaterminrows
269		);
270		$.tc_validator.addMethod(
271			'repeatermaxrows',
272			function( value, element, param ) {
273				return $.epoAPI.math.toInt( $( element ).closest( '.tc-element-inner-wrap' ).find( '.tc-repeater-element' ).length ) <= $.epoAPI.math.toInt( param );
274			},
275			$.tc_validator.messages.repeatermaxrows
276		);
277		$.tc_validator.addMethod(
278			'product_element_radio_qty',
279			function( value, element ) {
280				var qty = $( element ).closest( '.tm-element-ul-product' ).find( 'input.tc-epo-field-product.tm
280cp-radio:checked' ).closest( '.tc-epo-element-product-holder' ).find( '.tm-qty' ).first().val();
281				return qty > 0;
282			},
283			$.tc_validator.messages.required
284		);
285		$.tc_validator.addMethod(
286			'product_element_select_qty',
287			function( value, element ) {
288				var qty = $( element ).closest( '.tm-element-ul-product' ).find( 'select.tc-epo-field-product.tmcp-select' ).closest( '.tc-epo-element-product-holder' ).find( '.tm-qty' ).first().val();
289				return qty > 0;
290			},
291			$.tc_validator.messages.required
292		);
293	}
294
295	$.epoAPI.util.unformat = function( o ) {
296		var a = $.epoAPI.math.unformat( o, tcAPI.localInputDecimalSeparator );
297		var n = parseFloat( a );
298
299		if ( ! Number.isFinite( n ) ) {
300			return a;
301		}
302		return n;
303	};
304
305	if ( ! $.tmType ) {
306		$.tmType = function( obj ) {
307			return Object.prototype.toString
308				.call( obj )
309				.match( /\s([a-zA-Z]+)/ )[ 1 ]
310				.toLowerCase();
311		};
312	}
313
314	if ( ! $.is_on_screen ) {
315		$.fn.is_on_screen = function() {
316			// we don't use jWindow because we want the current window object
317			var win = $( window );
318			var scroll = $.epoAPI.dom.scroll();
319			var bounds = this.offset();
320			var viewport = {
321				top: scroll.top,
322				left: scroll.left
323			};
324
325			viewport.right = viewport.left + win.width();
326			viewport.bottom = viewport.top + win.height();
327			bounds.right = bounds.left + this.outerWidth();
328			bounds.bottom = bounds.top + this.outerHeight();
329
330			return ! ( viewport.right < bounds.left || viewport.left > bounds.right || viewport.bottom < bounds.top || viewport.top > bounds.bottom );
331		};
332	}
333
334	if ( ! $().tmtoggle ) {
335		$.fn.tmtoggle = function() {
336			var elements = this;
337			var is_one_open_for_accordion = false;
338			var init_done = 0;
339
340			if ( elements.length === 0 ) {
341				return;
342			}
343
344			if ( window.tc_accordion_offset === undefined ) {
345				window.tc_accordion_offset = -100;
346			}
347
348			elements.toArray().forEach( function( t ) {
349				var headers;
350				var wrap;
351				var wraps;
352
353				t = $( t );
354
355				if ( ! t.data( 'tm-toggle-init' ) ) {
356					t.data( 'tm-toggle-init', 1 );
357					headers = t.find( '.tm-toggle' );
358					wrap = t.find( '.tm-collapse-wrap' );
359					wraps = $( '.tm-collapse.tmaccordion' );
360					if ( wraps.closest( '.tc-epo-element-product-holder' ).length > 0 ) {
361						wraps = wraps.closest( '.tc-epo-element-product-holder' ).find( '.tm-collapse.tmaccordion' ).find( '.tm-toggle' );
362					} else {
363						wraps = $( '.tm-collapse.tmaccordion' ).not( '.tc-epo-element-product-holder .tm-collapse.tmaccordion' ).find( '.tm-toggle' );
364					}
365					if ( headers.length === 0 || wrap.length === 0 ) {
366						return;
367					}
368
369					if ( wrap.is( '.closed' ) ) {
370						$( wrap ).removeClass( 'closed open' ).addClass( 'closed' ).hide();
371						$( headers ).find( '.tm-arrow' ).removeClass( 'tcfa-angle-down tcfa-angle-up' ).addClass( 'tcfa-angle-down' );
372						$( headers ).removeClass( 'toggle-header-open toggle-header-closed' ).addClass( 'toggle-header-closed' );
373						$( headers ).attr( 'aria-expanded', false );
374					} else {
375						$( wrap ).removeClass( 'closed open' ).addClass( 'open' ).show();
376						$( headers ).find( '.tm-arrow' ).removeClass( 'tcfa-angle-down tcfa-angle-up' ).addClass( 'tcfa-angle-up' );
377						$( headers ).removeClass( 'toggle-header-open toggle-header-closed' ).addClass( 'toggle-header-open' );
378						$( headers ).attr( 'aria-expanded', true );
379						is_one_open_for_accordion = true;
380					}
381
382					headers.toArray().forEach( function( header ) {
383						header = $( header );
384						header.on( 'closewrap.tmtoggle', function() {
385							if ( t.is( '.tmaccordion' ) && $( wrap ).is( '.closed' ) ) {
386								return;
387							}
388							$( wrap ).removeClass( 'closed open' ).addClass( 'closed' );
389							$( this ).find( '.tm-arrow' ).removeClass( 'tcfa-angle-down tcfa-angle-up' ).addClass( 'tcfa-angle-down' );
390							$( this ).removeClass( 'toggle-header-open toggle-header-closed' ).addClass( 'toggle-header-closed' );
391							$( this ).attr( 'aria-expanded', false );
392							$( wrap ).removeClass( 'tm-animated fadein' );
393							if ( t.is( '.tmaccordion' ) ) {
394								$( wrap ).animate( { height: 'toggle' }, 100, function() {
395									$( wrap ).hide();
396								} );
397							} else {
398								$( wrap ).animate( { height: 'toggle' }, 100, function() {
399									$( wrap ).hide();
400								} );
401							}
402							jWindow.trigger( 'tmlazy' );
403						} );
404
405						header.on( 'openwrap.tmtoggle', function( e, data ) {
406							if ( t.is( '.tmaccordion' ) ) {
407								$( wraps ).not( $( this ) ).trigger( 'closewrap.tmtoggle' );
408							}
409							$( wrap ).removeClass( 'closed open' ).addClass( 'open' );
410							$( this ).find( '.tm-arrow' ).removeClass( 'tcfa-angle-down tcfa-angle-up' ).addClass( 'tcfa-angle-up' );
411							$( this ).removeClass( 'toggle-header-open toggle-header-closed' ).addClass( 'toggle-header-open' );
412							$( this ).attr( 'aria-expanded', true );
413							$( wrap ).show().removeClass( 'tm-animated fadein' ).addClass( 'tm-animated fadein' );
414							setTimeout( function() {
415								jWindow.trigger( 'tmlazy' );
416							}, 200 );
417							setTimeout( function() {
418								if ( data === undefined && init_done && t.is( '.tmaccordion' ) && ! t.is_on_screen() ) {
419									jWindow.tcScrollTo( header, 10, window.tc_accordion_offset );
420								}
421							}, 110 );
422						} );
423
424						header.on( 'click.tmtoggle keydown.tmtoggle', function( e ) {
425							// If it's a keydown event, only trigger if the Enter key was pressed
426							if ( e.type === 'keydown' && e.key !== 'Enter' ) {
427								return; // Ignore all other keypresses
428							}
429							e.preventDefault();
430							if ( $( wrap ).is( '.closed' ) ) {
431								$( this ).trigger( 'openwrap.tmtoggle' );
432							} else {
433								$( this ).trigger( 'closewrap.tmtoggle' );
434							}
435						} );
436
437						header
438							.find( '.tm-qty' )
439							.closest( '.cpf-element' )
440							.find( '.tm-epo-field' )
441							.on( 'change.cpf', function() {
442								header.trigger( 'openwrap.tmtoggle' );
443							} );
444					} );
445				}
446			} );
447			if ( undefined === window.tc_accordion_closed_on_page_load && ! is_one_open_for_accordion && elements.filter( '.tmaccordion' ).length > 0 ) {
448				elements.filter( '.tmaccordion' ).first().find( '.tm-toggle' ).trigger( 'openwrap.tmtoggle', { nomove: 1 } );
449			}
450			init_done = 1;
451			return elements;
452		};
453	}
454
455	if ( ! $().tmpoplink ) {
456		$.fn.tmpoplink = function( options ) {
457			var elements = this;
458			var floatbox_template;
459			var settings = {
460				classname: 'flasho tc-wrapper cart-popup'
461			};
462
463			if ( elements.length === 0 ) {
464				return;
465			}
466			if ( options ) {
467				settings = $.extend( {}, settings, options );
468			}
469
470			floatbox_template = function( data ) {
471				return $.epoAPI.template.html( wp.template( 'tc-cart-options-popup' ), {
472					title: data.title,
473					id: data.id,
474					html: data.html,
475					close: TMEPOJS.i18n_close
476				} );
477			};
478
479			return elements.toArray().forEach( function( t ) {
480				var id;
481				var title;
482				var html;
483				var $_html;
484
485				t = $( t );
486				if ( t.is( '.tc-poplink' ) ) {
487					return;
488				}
489				t.addClass( 'tc-poplink' );
490				id = t.attr( 'href' );
491				title = t.attr( 'data-title' );
492				html = $( id ).html();
493				if ( ! title ) {
494					title = TMEPOJS.i18n_addition_options;
495				}
496				$_html = floatbox_template( {
497					id: 'tc-floatbox-content',
498					html: html,
499					title: title
500				} );
501
502				t.on( 'click.tmpoplink', function( e ) {
503					$.tcFloatBox( {
504						fps: 1,
505						ismodal: false,
506						width: '80%',
507						height: '80%',
508						classname: settings.classname,
509						data: $_html
510					} );
511
512					e.preventDefault();
513				} );
514			} );
515		};
516	}
517
518	function readableFileSize( a, b, c, d, e ) {
519		b = Math;
520		c = b.log;
521		d = 1024;
522		e = c( a ) / c( d ) | 0; //eslint-disable-line no-bitwise
523
524		return ( ( a / b.pow( d, e ) ).toFixed( e ? 2 : 0 ) ) + ' ' + ( e ? 'KMGTPEZY'[ --e ] + 'B' : 'bytes' );
525	}
526
527	function toggleState( thisProductContainerWrap, disabled ) {
528		thisProductContainerWrap.toArray().forEach( function( setter ) {
529			setter = $( setter );
530			setter.find( ':input' ).prop( 'disabled', function( i, v ) {
531				var state = $( this ).data( 'tc-state' );
532				if ( state === undefined ) {
533					$( this ).data( 'tc-state', v );
534					return disabled;
535				}
536				if ( state === false ) {
537					return disabled;
538				}
539				return state;
540			} );
541		} );
542	}
543	// Function to calculate tax amount
544	function calculateTaxAmount( priceWithTax, _cart ) {
545		var taxable;
546		var tax_rate;
547		var pricesIncludeTax;
548		var tax_display_mode;
549		var current_variation;
550		var priceWithoutTax;
551		var taxAmount = 0;
552
553		if ( _cart ) {
554			taxable = _cart.attr( 'data-taxable' );
555			tax_rate = _cart.attr( 'data-tax-rate' );
556			pricesIncludeTax = _cart.attr( 'data-prices-include-tax' ) || TMEPOJS.prices_include_tax;
557			tax_display_mode = _cart.attr( 'data-tax-display-mode' );
558			if ( _cart.data( 'current_variation' ) !== undefined ) {
559				current_variation = _cart.data( 'current_variation' );
560			}
561
562			if ( current_variation !== undefined ) {
563				current_variation = _cart.data( 'current_variation' );
564				taxable = current_variation.tc_is_taxable;
565				tax_rate = current_variation.tc_tax_rate;
566			}
567		}
568
569		if ( taxable ) {
570			tax_rate = parseFloat( tax_rate / 100 );
571
572			if ( pricesIncludeTax === '1' ) {
573				if ( tax_display_mode === 'incl' ) {
574					priceWithTax = parseFloat( priceWithTax );
575
576					// Calculate price without tax
577					priceWithoutTax = priceWithTax / ( 1 + tax_rate );
578
579					// Calculate tax amount
580					taxAmount = priceWithTax - priceWithoutTax;
581				} else {
582					// Calculate price without tax
583					priceWithoutTax = priceWithTax;
584
585					// Calculate tax amount
586					taxAmount = priceWithTax * tax_rate;
587				}
588			} else if ( tax_display_mode === 'incl' ) {
589				// Calculate price without tax
590				priceWithoutTax = priceWithTax / ( 1 + tax_rate );
591
592				// Calculate tax amount
593				taxAmount = priceWithTax - priceWithoutTax;
594			}
595
596			taxAmount = $.epoAPI.math.toFloat( taxAmount );
597		}
598
599		return taxAmount;
600	}
601	// Taxes setup
602	function get_price_including_tax( price, _cart, element, force, variation, pricetype, doubleforce ) {
603		var taxable;
604		var tax_rate;
605		var prices_include_tax;
606		var is_vat_exempt;
607		var non_base_location_prices;
608		var taxes_of_one;
609		var base_taxes_of_one;
610		var modded_taxes_of_one;
611		var current_variation;
612
613		if ( ! Number.isFinite( parseFloat( price ) ) ) {
614			price = 0;
615		}
616		price = price * 10000;
617		if ( _cart ) {
618			taxable = _cart.attr( 'data-taxable' );
619			tax_rate = _cart.attr( 'data-tax-rate' );
620			prices_include_tax = _cart.attr( 'data-prices-include-tax' ) || TMEPOJS.prices_include_tax;
621			is_vat_exempt = _cart.attr( 'data-is-vat-exempt' );
622			non_base_location_prices = _cart.attr( 'data-non-base-location-prices' );
623			taxes_of_one = _cart.attr( 'data-taxes-of-one' );
624			base_taxes_of_one = _cart.attr( 'data-base-taxes-of-one' );
625			modded_taxes_of_one = _cart.attr( 'data-modded-taxes-of-one' );
626
627			if ( _cart.data( 'current_variation' ) !== undefined ) {
628				current_variation = _cart.data( 'current_variation' );
629			} else if ( variation !== undefined ) {
630				current_variation = variation;
631			}
632
633			if ( current_variation !== undefined ) {
634				current_variation = _cart.data( 'current_variation' );
635				taxable = current_variation.tc_is_taxable;
636				tax_rate = current_variation.tc_tax_rate;
637				non_base_location_prices = current_variation.tc_non_base_location_prices;
638				taxes_of_one = current_variation.tc_taxes_of_one;
639				base_taxes_of_one = current_variation.tc_base_taxes_of_one;
640				modded_taxes_of_one = current_variation.tc_modded_taxes_of_one;
641			}
642
643			if ( element ) {
644				if ( element.data( 'tax-obj' ) ) {
645					tax_rate = element.data( 'tax-obj' );
646					if ( tax_rate.has_fee === 'no' ) {
647						taxable = false;
648					} else if ( tax_rate.has_fee === 'yes' ) {
649						taxable = true;
650					}
651					if ( base_taxes_of_one === '' || base_taxes_of_one === undefined ) {
652						base_taxes_of_one = tax_rate / 100;
653					}
654					if ( tax_rate.base_taxes_of_one !== undefined ) {
655						base_taxes_of_one = tax_rate.base_taxes_of_one;
656					}
657					tax_rate = tax_rate.tax_rate;
658					taxes_of_one = tax_rate / 100;
659				}
660			}
661			if ( taxable ) {
662				if ( prices_include_tax === '1' && ! force ) {
663					if ( is_vat_exempt === '1' ) {
664						if ( non_base_location_prices === '1' ) {
665							price = parseFloat( price ) - ( taxes_of_one * price );
666						} else {
667							price = parseFloat( price ) - ( base_taxes_of_one * price );
668						}
669					} else if ( non_base_location_prices === '1' ) {
670						price = parseFloat( price ) - ( base_taxes_of_one * price ) + ( modded_taxes_of_one * price );
671					}
672				} else if ( element || current_variation === undefined || doubleforce ) {
673					price = parseFloat( price ) + ( parseFloat( price ) * taxes_of_one );
674				}
675			}
676		}
677		price = price / 10000;
678
679		return price;
680	}
681
682	function get_price_excluding_tax( price, _cart, element, force, variation, pricetype, doubleforce ) {
683		var taxable;
684		var tax_rate;
685		var taxes_of_one;
686		var base_taxes_of_one;
687		var prices_include_tax;
688		var current_variation;
689		var tax_display_mode;
690
691		if ( ! Number.isFinite( parseFloat( price ) ) ) {
692			price = 0;
693		}
694		price = price * 10000;
695
696		if ( _cart ) {
697			tax_display_mode = _cart.attr( 'data-tax-display-mode' );
698
699			taxable = _cart.attr( 'data-taxable' );
700			tax_rate = _cart.attr( 'data-tax-rate' );
701			taxes_of_one = _cart.attr( 'data-taxes-of-one' );
702			base_taxes_of_one = _cart.attr( 'data-base-taxes-of-one' );
703			prices_include_tax = _cart.attr( 'data-prices-include-tax' );
704
705			if ( _cart.data( 'current_variation' ) !== undefined ) {
706				current_variation = _cart.data( 'current_variation' );
707			} else if ( variation !== undefined ) {
708				current_variation = variation;
709			}
710			if ( current_variation !== undefined ) {
711				taxable = current_variation.tc_is_taxable;
712				tax_rate = current_variation.tc_tax_rate;
713				taxes_of_one = current_variation.tc_taxes_of_one;
714				base_taxes_of_one = current_variation.tc_base_taxes_of_one;
715			}
716
717			if ( element ) {
718				if ( element.data( 'tax-obj' ) ) {
719					tax_rate = element.data( 'tax-obj' );
720					if ( tax_rate.has_fee === 'no' ) {
721						taxable = false;
722					} else if ( tax_rate.has_fee === 'yes' ) {
723						taxable = true;
724					}
725					if ( base_taxes_of_one === '' || base_taxes_of_one === undefined ) {
726						base_taxes_of_one = tax_rate / 100;
727					}
728					if ( tax_rate.base_taxes_of_one !== undefined ) {
729						base_taxes_of_one = tax_rate.base_taxes_of_one;
730					}
731					tax_rate = tax_rate.tax_rate;
732				}
733			}
734
735			if ( taxable ) {
736				if ( prices_include_tax === '1' || force ) {
737					if ( tax_display_mode === 'incl' ) {
738						// This should never run on this function
739					} else if ( element || current_variation === undefined || force || doubleforce ) {
740						if ( base_taxes_of_one === taxes_of_one ) {
741							price = parseFloat( price ) - parseFloat( taxes_of_one * price );
742						} else {
743							price = price * ( 1 - parseFloat( base_taxes_of_one ) );
744						}
745					}
746				}
747			}
748		}
749		price = price / 10000;
750
751		return price;
752	}
753
754	function tm_set_tax_price( value, _cart, element, pricetype, force, variation, doubleforce ) {
755		var tax_display_mode;
756
757		if ( ! Number.isFinite( parseFloat( value ) ) ) {
758			value = 0;
759		}
760		if ( _cart ) {
761			tax_display_mode = _cart.attr( 'data-tax-display-mode' ) || TMEPOJS.tax_display_mode;
762			if ( tax_display_mode === 'incl' ) {
763				value = get_price_including_tax( value, _cart, element, force, variation, pricetype, doubleforce );
764			} else {
765				value = get_price_excluding_tax( value, _cart, element, force, variation, pricetype, doubleforce );
766			}
767		}
768		return value;
769	}
770
771	// Return a formatted currency value
772	function formatPrice( value, args ) {
773		var data;
774		if ( ! args ) {
775			args = {};
776		}
777		data = $.extend( {
778			symbol: '',
779			format: '',
780			decimal: tcAPI.localDecimalSeparator,
781			thousand: tcAPI.localThousandSeparator,
782			precision: TMEPOJS.currency_format_num_decimals
783		}, args );
784
785		if ( TMEPOJS.tm_epo_trim_zeros === 'yes' ) {
786			if ( ( ( value % 1 ).toString() !== '0' ) === false ) {
787				data.precision = 0;
788			}
789		}
790
791		return $.epoAPI.applyFilter( 'tc_formatPrice', $.epoAPI.math.format( value, data ), data, value );
792	}
793
794	// Return a formatted currency value
795	function tm_set_price_( value, sign ) {
796		return (
797			sign +
798			formatPrice( value, { symbol: TMEPOJS.currency_format_symbol, format: TMEPOJS.currency_format } )
799		);
800	}
801
802	// Return a formatted currency value
803	function tm_set_price( value, _cart, notax, element, pricetype ) {
804		var val;
805		var sign = TMEPOJS.option_plus_sign + ' ';
806
807		if ( ! notax ) {
808			value = tm_set_tax_price( value, _cart, element, pricetype );
809		}
810
811		val = Math.abs( value );
812
813		if ( TMEPOJS.tm_epo_global_options_price_sign === 'minus' ) {
814			sign = '';
815		}
816		if ( value < 0 ) {
817			sign = TMEPOJS.option_minus_sign + ' ';
818		}
819
820		return tm_set_price_( val, sign );
821	}
822
823	// Return a price currency value without any formatting
824	function tm_get_price( value, _cart, notax, element, pricetype, force ) {
825		if ( ! notax ) {
826			value = tm_set_tax_price( value, _cart, element, pricetype, force );
827		}
828
829		return value;
830	}
831
832	// FloatingTotalsBox plugin
833	FloatingTotalsBox = function( this_epo_totals_container, is_quickview, main_cart ) {
834		this.this_epo_totals_container = this_epo_totals_container;
835		this.is_quickview = is_quickview;
836		this.main_cart = main_cart;
837
838		if ( ! is_quickview && TMEPOJS.floating_totals_box && TMEPOJS.floating_totals_box !== 'disable' && main_cart && this_epo_totals_container.length ) {
839			this.init();
840			return this;
841		}
842
843		return false;
844	};
845
846	FloatingTotalsBox.prototype = {
847		constructor: FloatingTotalsBox,
848
849		onUpdate: function() {
850			var tm_epo_totals_html = this.this_epo_totals_container.data( 'tm-html' );
851			var tm_floating_box_data = this.this_epo_totals_container.data( 'tm-floating-box-data' );
852			var values_obj = [];
853			var floatingBoxHtml;
854			var floatingBoxaddToCartButton;
855			var len;
856			var i;
857			var row;
858			var tempDiv;
859			var j;
860			var spans;
861			var container;
862
863			if ( tm_floating_box_data && tm_floating_box_data.length ) {
864				len = tm_floating_box_data.length;
865				for ( i = 0; i < len; i++ ) {
866					row = tm_floating_box_data[ i ];
867					// Ensure title and value are properly set
868					row.title = row.title ? String( row.title ) : '&nbsp;';
869					row.value = row.value ? String( row.value ) : '&nbsp;';
870
871					// Sanitize title by removing spans
872					if ( row.title !== '&nbsp;' ) {
873						tempDiv = document.createElement( 'div' );
874						tempDiv.innerHTML = row.title;
875						spans = tempDiv.querySelectorAll( 'span' );
876						for ( j = 0; j < spans.length; j++ ) {
877							spans[ j ].remove();
878						}
879						row.title = tempDiv.innerHTML;
880					}
881
882					// Handle "is_nks" logic
883					if ( this.is_nks ) {
884						if ( row.label_show !== '' ) {
885							row.title = '';
886						}
887						if ( row.value_show !== '' ) {
888							row.value = '';
889						}
890					}
891
892					// Auto-hide price if zero
893					if ( TMEPOJS.tm_epo_auto_hide_price_if_zero === 'yes' && $.epoAPI.util.isEmpty( row.price ) === true ) {
894						row.price = '';
895					} else {
896						row.price = tm_set_price( row.price, this.this_epo_totals_container, true );
897					}
898
899					// Push processed data into values_obj
900					values_obj.push( {
901						label_show: row.label_show,
902						value_show: row.value_show,
903						title: row.title,
904						value: row.value,
905						quantity: row.quantity,
906						price: row.price
907					} );
908				}
909			}
910
911			if ( ( ( tm_epo_totals_html && tm_epo_totals_html === '' ) && ( ! tm_floating_box_data || ! tm_floating_box_data.length ) ) || ! ( ( tm_epo_totals_html && tm_epo_totals_html !== '' ) || this.is_nks ) ) {
912				tm_epo_totals_html = '';
913				this.floatingBox.hide();
914			}
915
916			floatingBoxHtml = $.epoAPI.template.html( this.engineTemplate, {
917				html_before: TMEPOJS.floating_totals_box_html_before,
918				html_after: TMEPOJS.floating_totals_box_html_after,
919				option_label: TMEPOJS.i18n_option_label,
920				option_value: TMEPOJS.i18n_option_value,
921				option_qty: TMEPOJS.i18n_option_qty,
922				option_price: TMEPOJS.i18n_option_price,
923				values: values_obj,
924				totals: tm_epo_totals_html
925			} );
926
927			this.floatingBox.html( floatingBoxHtml );
928			this.onUpdateScroll();
929
930			if ( TMEPOJS.tm_epo_no_lazy_load !== 'yes' ) {
931				this.floatingBox.addClass( 'lazyxt' );
932				container = this.floatingBox.find( 'img.tmlazy' );
933				container.lazyLoadXT();
934				container.on( 'lazyshow', function() {
935					jWindow.trigger( 'lazyLoadXToncomplete' );
936				} );
937			}
938
939			if ( TMEPOJS.floating_totals_box_add_button === 'yes' ) {
940				floatingBoxaddToCartButton = this.main_cart.find( tcAPI.addToCartButtonSelector ).first();
941				floatingBoxaddToCartButton
942					.tcClone()
943					.addClass( 'tc-add-to-cart-button' )
944					.on( 'click', function() {
945						floatingBoxaddToCartButton.trigger( 'click' );
946					} )
947					.appendTo( this.floatingBox );
948			}
949		},
950
951		onUpdateScroll: function() {
952			if ( TMEPOJS.floating_totals_box_visibility === 'always' ) {
953				if ( ( this.floatingBox.children().length === 0 || this.floatingBox.text().trim() === '' ) && ! this.is_nks_alt ) {
954					this.floatingBox.hide();
955				} else {
956					this.floatingBox.show();
957				}
958				return;
959			}
960			if ( TMEPOJS.floating_totals_box_visibility === 'hideafterscroll' ) {
961				if ( jWindow.scrollTop() > $.epoAPI.math.toFloat( TMEPOJS.floating_totals_box_pixels ) && ! this.is_nks_alt ) {
962					if ( ! this.floatingBox.is( ':hidden' ) ) {
963						if ( this.is_nks === false ) {
964							this.floatingBox.fadeOut();
965						} else {
966							this.floatingBox.hide();
967						}
968					}
969				} else if ( this.floatingBox.is( ':hidden' ) || this.is_nks_alt ) {
970					if ( ! ( this.floatingBox.children().length === 0 || this.floatingBox.text().trim() === '' ) || this.is_nks_alt ) {
971						if ( this.is_nks === false ) {
972							this.floatingBox.fadeIn();
973						} else {
974							this.floatingBox.show();
975						}
976					}
977				}
978			}
979
980			if ( TMEPOJS.floating_totals_box_visibility === 'afterscroll' ) {
981				if ( jWindow.scrollTop() >
981 $.epoAPI.math.toFloat( TMEPOJS.floating_totals_box_pixels ) || this.is_nks_alt ) {
982					if ( ( this.floatingBox.is( ':hidden' ) && ! ( this.floatingBox.children().length === 0 || this.floatingBox.text().trim() === '' ) ) || this.is_nks_alt ) {
983						if ( this.is_nks === false ) {
984							this.floatingBox.fadeIn();
985						} else {
986							this.floatingBox.show();
987						}
988					} else if ( ! this.floatingBox.is( ':hidden' ) && ( this.floatingBox.children().length === 0 || this.floatingBox.text().trim() === '' ) ) {
989						if ( this.is_nks === false ) {
990							this.floatingBox.fadeOut();
991						} else {
992							this.floatingBox.hide();
993						}
994					}
995				} else if ( ! this.floatingBox.is( ':hidden' ) ) {
996					if ( this.is_nks === false ) {
997						this.floatingBox.fadeOut();
998					} else {
999						this.floatingBox.hide();
1000					}
1001				}
1002			}
1003		},
1004
1005		addEvents: function() {
1006			this.onUpdate();
1007
1008			this.main_cart.on( 'tm-epo-after-update', this.onUpdate.bind( this ) );
1009			this.main_cart.on( 'tm-epo-short-update', this.onUpdate.bind( this ) );
1010
1011			if ( this.is_nks === false ) {
1012				jWindow.on( 'scroll', this.onUpdateScroll.bind( this ) );
1013			}
1014		},
1015
1016		init: function() {
1017			this.floatingBox = $( '<div class="tm-floating-box ' + TMEPOJS.floating_totals_box + '"></div>' );
1018			this.nks_selector = $( '.tm-floating-box-nks' ).first();
1019			this.alt_selector = $( '.tm-floating-box-alt' ).first();
1020			this.engineTemplate = tcAPI.templateEngine.tc_floating_box;
1021			this.is_nks = false;
1022			this.is_nks_alt = false;
1023
1024			if ( this.nks_selector.length > 0 ) {
1025				this.is_nks = true;
1026				this.floatingBox.removeClass( 'top left right bottom' ).appendTo( this.nks_selector ).show();
1027			} else if ( this.alt_selector.length > 0 ) {
1028				this.floatingBox.removeClass( 'top left right bottom' ).appendTo( this.alt_selector ).hide();
1029			} else {
1030				this.floatingBox.appendTo( 'body' ).hide();
1031			}
1032
1033			if ( this.nks_selector.length > 0 || this.alt_selector.length > 0 ) {
1034				this.is_nks_alt = true;
1035				this.engineTemplate = tcAPI.templateEngine.tc_floating_box_nks;
1036			}
1037
1038			this.addEvents();
1039		}
1040	};
1041
1042	$.tcFloatingTotalsBox = function( this_epo_totals_container, is_quickview, main_cart ) {
1043		var data = false;
1044
1045		if ( this_epo_totals_container && this_epo_totals_container.length && this_epo_totals_container.data( 'tcfloatingtotalsbox' ) === undefined ) {
1046			data = new FloatingTotalsBox( this_epo_totals_container, is_quickview, main_cart );
1047			this_epo_totals_container.data( 'tcfloatingtotalsbox', data );
1048		}
1049
1050		return data;
1051	};
1052
1053	$.tc_product_image = {};
1054	$.tc_product_image_store = {};
1055
1056	// replace obj1 values with obj2 values
1057	$.tc_replace_object_values = function( obj1, obj2 ) {
1058		Object.keys( obj1 ).forEach( function( x ) {
1059			Object.keys( obj1[ x ] ).forEach( function( attr ) {
1060				if ( undefined !== obj2[ x ] && undefined !== obj2[ x ][ attr ] && Object.prototype.hasOwnProperty.call( obj2[ x ], attr ) ) {
1061					obj1[ x ][ attr ] = obj2[ x ][ attr ];
1062				}
1063			} );
1064		} );
1065		return obj1;
1066	};
1067	// copy obj2 values to obj1
1068	$.tc_maybe_copy_object_values = function( obj1, obj2 ) {
1069		Object.keys( obj2 ).forEach( function( x ) {
1070			Object.keys( obj2[ x ] ).forEach( function( attr ) {
1071				if ( undefined !== obj2[ x ] && Object.prototype.hasOwnProperty.call( obj2[ x ], attr ) && undefined !== obj2[ x ][ attr ] && ( undefined === obj1[ x ] || undefined === obj1[ x ][ attr ] ) ) {
1072					if ( undefined === obj1[ x ] ) {
1073						obj1[ x ] = {};
1074					}
1075					obj1[ x ][ attr ] = obj2[ x ][ attr ];
1076				}
1077			} );
1078		} );
1079		return obj1;
1080	};
1081
1082	$.tc_pre_populate_store = function() {
1083		var obj = {};
1084
1085		obj[ 0 ] = {};
1086		obj[ 1 ] = {};
1087		obj[ 2 ] = {};
1088		obj[ 3 ] = {};
1089
1090		obj[ 0 ].src = '';
1091		obj[ 0 ].srcset = '';
1092		obj[ 0 ].sizes = '';
1093		obj[ 0 ].title = '';
1094		obj[ 0 ].alt = '';
1095		obj[ 0 ][ 'data-src' ] = '';
1096		obj[ 0 ][ 'data-large_image' ] = '';
1097		obj[ 0 ][ 'data-large_image_width' ] = '';
1098		obj[ 0 ][ 'data-large_image_height' ] = '';
1099		obj[ 1 ][ 'data-thumb' ] = '';
1100		obj[ 2 ].src = '';
1101		obj[ 3 ].href = '';
1102		obj[ 3 ].title = '';
1103
1104		return obj;
1105	};
1106
1107	$.tc_populate_store = function( img, product_element ) {
1108		var $gallery_img = product_element.find( '.flex-control-nav li:eq(0) img' );
1109		var $gallery_wrapper = product_element.find( '.woocommerce-product-gallery__wrapper ' );
1110		var $product_img_wrap = $gallery_wrapper.find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ).eq( 0 );
1111		var $product_img = img;
1112		var $product_link = img.closest( 'a' );
1113		var obj = {};
1114
1115		obj[ 0 ] = {};
1116		obj[ 1 ] = {};
1117		obj[ 2 ] = {};
1118		obj[ 3 ] = {};
1119
1120		obj[ 0 ].src = $product_img.attr( 'src' );
1121		obj[ 0 ].srcset = $product_img.attr( 'srcset' );
1122		obj[ 0 ].sizes = $product_img.attr( 'sizes' );
1123		obj[ 0 ].title = $product_img.attr( 'title' );
1124		obj[ 0 ].alt = $product_img.attr( 'alt' );
1125		obj[ 0 ][ 'data-src' ] = $product_img.attr( 'data-src' );
1126		obj[ 0 ][ 'data-large_image' ] = $product_img.attr( 'data-large_image' );
1127		obj[ 0 ][ 'data-large_image_width' ] = $product_img.attr( 'data-large_image_width' );
1128		obj[ 0 ][ 'data-large_image_height' ] = $product_img.attr( 'data-large_image_height' );
1129		obj[ 1 ][ 'data-thumb' ] = $product_img_wrap.attr( 'data-thumb' );
1130		obj[ 2 ].src = $gallery_img.attr( 'src' );
1131		obj[ 3 ].href = $product_link.attr( 'href' );
1132		obj[ 3 ].title = $product_link.attr( 'title' );
1133
1134		return obj;
1135	};
1136
1137	$.tc_maybe_copy_object_values_from_img = function( obj1, img, product_element ) {
1138		var $gallery_img = product_element.find( '.flex-control-nav li:eq(0) img' );
1139		var $gallery_wrapper = product_element.find( '.woocommerce-product-gallery__wrapper' );
1140		var $product_img_wrap = $gallery_wrapper.find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ).eq( 0 );
1141		var $product_img = img;
1142		var $product_link = img.closest( 'a' );
1143
1144		var all = [ $product_img, $product_img_wrap, $gallery_img, $product_link ];
1145		var attrs_all = [
1146			[ 'src', 'srcset', 'sizes', 'title', 'alt', 'data-src', 'data-large_image', 'data-large_image_width', 'data-large_image_height', 'large-image' ],
1147			[ 'data-thumb' ],
1148			[ 'src' ],
1149			[ 'href', 'title' ]
1150		];
1151		var i;
1152		var item;
1153		var attrs;
1154		var attr;
1155		var j;
1156
1157		for ( i = 0; i < all.length; i++ ) {
1158			item = all[ i ];
1159
1160			if ( item && item[ 0 ] ) {
1161				attrs = item[ 0 ].attributes;
1162
1163				for ( j = 0; j < attrs.length; j++ ) {
1164					attr = attrs[ j ];
1165
1166					if ( attr.specified && attrs_all[ i ].indexOf( attr.name ) !== -1 ) {
1167						if ( obj1[ i ] === undefined || ( obj1[ i ] !== undefined && obj1[ i ][ attr.name ] === undefined ) ) {
1168							if ( undefined === obj1[ i ] ) {
1169								obj1[ i ] = {};
1170							}
1171							obj1[ i ][ attr.name ] = attr.value;
1172						}
1173					}
1174				}
1175			}
1176		}
1177
1178		return obj1;
1179	};
1180
1181	// Stores a default attribute for an element so it can be reset later
1182	$.fn.tc_set_attr = function( attr, value, id ) {
1183		if ( undefined === id ) {
1184			id = 0;
1185		}
1186		if ( undefined === $.tc_product_image[ id ] || ( undefined !== $.tc_product_image[ id ] && undefined === $.tc_product_image[ id ][ attr ] ) ) {
1187			if ( undefined === $.tc_product_image[ id ] ) {
1188				$.tc_product_image[ id ] = {};
1189			}
1190			$.tc_product_image[ id ][ attr ] = '';
1191			if ( this.attr( attr ) ) {
1192				$.tc_product_image[ id ][ attr ] = this.attr( attr );
1193			}
1194		}
1195		if ( false === value ) {
1196			this.removeAttr( attr );
1197		} else {
1198			this.attr( attr, value );
1199		}
1200	};
1201
1202	// Reset a default attribute for an element so it can be reset later
1203	$.fn.tc_reset_attr = function( attr, id ) {
1204		if ( undefined === id ) {
1205			id = 0;
1206		}
1207		if ( undefined === $.tc_product_image[ id ] ) {
1208			return;
1209		}
1210		if ( undefined !== $.tc_product_image[ id ][ attr ] ) {
1211			this.attr( attr, $.tc_product_image[ id ][ attr ] );
1212		}
1213		delete $.tc_product_image[ id ][ attr ];
1214	};
1215
1216	$.fn.tc_update_attr = function( attr, id ) {
1217		if ( undefined === id ) {
1218			id = 0;
1219		}
1220		if ( undefined !== $.tc_product_image[ id ] ) {
1221			$.tc_product_image[ id ][ attr ] = this.attr( attr );
1222		}
1223	};
1224
1225	$.fn.tc_image_update = function( dom, image ) {
1226		var element = $( dom );
1227		var $form = this;
1228		var $image = $( image );
1229		var epo_object = $form.data( 'epo_object' );
1230		var image_info;
1231		var $product_img;
1232		var product_element = epo_object.main_product.closest( '#product-' + epo_object.product_id );
1233		var $product_element = product_element;
1234		var $product_img_thumb;
1235		var $product_link;
1236		var use_image_info;
1237
1238		if ( product_element.length <= 0 ) {
1239			$product_element = epo_object.main_product.closest( '.post-' + epo_object.product_id );
1240		}
1241
1242		$product_img_thumb = $product_element.find( '.flex-control-nav li:eq(0) img' );
1243
1244		if ( element.is( 'select' ) ) {
1245			element = element.children( 'option:selected' );
1246		}
1247		image_info = element.data( 'image-variations' );
1248
1249		if ( TMEPOJS.tm_epo_global_product_image_selector !== '' ) {
1250			$product_img = $( TMEPOJS.tm_epo_global_product_image_selector );
1251		} else {
1252			$product_img = $product_element.find( 'a.woocommerce-main-image img, img.woocommerce-main-image,a img' ).not( '.thumbnails img,.product_list_widget img,img.emoji,a.woocommerce-product-gallery__trigger img' ).first();
1253		}
1254		$product_link = $product_img.closest( 'a' );
1255
1256		if ( $product_img.length > 1 ) {
1257			$product_img = $product_img.first();
1258		}
1259
1260		if ( element && image_info && $image.length > 0 ) {
1261			$image.removeAttr( 'data-o_src' ).removeAttr( 'data-o_title' ).removeAttr( 'data-o_alt' ).removeAttr( 'data-o_srcset' ).removeAttr( 'data-o_sizes' ).removeAttr( 'srcset' ).removeAttr( 'sizes' );
1262
1263			use_image_info = image_info.imagep;
1264			if ( ! image_info.imagep.image_link ) {
1265				use_image_info = image_info.image;
1266			}
1267
1268			$image.attr( 'title', use_image_info.image_title );
1269			$image.attr( 'alt', use_image_info.image_alt );
1270			if ( use_image_info.image_srcset ) {
1271				$image.attr( 'srcset', use_image_info.image_srcset );
1272			}
1273			if ( use_image_info.image_sizes ) {
1274				$image.attr( 'sizes', use_image_info.image_sizes );
1275			}
1276
1277			$product_img.tc_set_attr( 'title', use_image_info.image_title );
1278			$product_img.tc_set_attr( 'alt', use_image_info.image_alt );
1279
1280			$product_img.tc_set_attr( 'data-large-image', use_image_info.image_link );
1281			if ( $product_img.data.wc27_zoom_target ) {
1282				$product_img.data.wc27_zoom_target.tc_set_attr( 'data-thumb', use_image_info.image_link );
1283				$product_img_thumb.tc_set_attr( 'src', use_image_info.image_link );
1284				if ( use_image_info.image_srcset ) {
1285					$product_img_thumb.tc_set_attr( 'srcset', use_image_info.image_srcset );
1286				}
1287				if ( use_image_info.image_sizes ) {
1288					$product_img_thumb.tc_set_attr( 'sizes', use_image_info.image_sizes );
1289				}
1290			}
1291
1292			$product_link.tc_set_attr( 'href', use_image_info.image_link );
1293			$product_link.tc_set_attr( 'title', use_image_info.image_caption );
1294		} else {
1295			$product_img.tc_reset_attr( 'title' );
1296			$product_img.tc_reset_attr( 'alt' );
1297
1298			$product_img.tc_reset_attr( 'data-large-image' );
1299			if ( $product_img.data.wc27_zoom_target ) {
1300				$product_img.data.wc27_zoom_target.tc_reset_attr( 'data-thumb' );
1301				$product_img_thumb.tc_reset_attr( 'src' );
1302				$product_img_thumb.tc_reset_attr( 'srcset' );
1303				$product_img_thumb.tc_reset_attr( 'sizes' );
1304			}
1305
1306			$product_link.tc_reset_attr( 'href' );
1307			$product_link.tc_reset_attr( 'title' );
1308		}
1309	};
1310
1311	// variations checker
1312	$.fn.tm_find_matching_variations = function( product_variations, settings ) {
1313		var matching = [];
1314		var i;
1315		var variation;
1316
1317		if ( product_variations ) {
1318			for ( i = 0; i < product_variations.length; i += 1 ) {
1319				variation = product_variations[ i ];
1320
1321				if ( $.fn.tm_variations_match( variation.attributes, settings ) ) {
1322					matching.push( variation );
1323				}
1324			}
1325		}
1326
1327		return matching;
1328	};
1329
1330	$.fn.tm_variations_match = function( attrs1, attrs2 ) {
1331		var match = true;
1332		var val1;
1333		var val2;
1334
1335		Object.keys( attrs1 ).forEach( function( x ) {
1336			if ( Object.prototype.hasOwnProperty.call( attrs1, x ) ) {
1337				val1 = attrs1[ x ];
1338				val2 = attrs2[ x ];
1339
1340				if ( val1 !== undefined && val2 !== undefined && val1.length !== 0 && val2.length !== 0 && val1 !== val2 ) {
1341					match = false;
1342				}
1343			}
1344		} );
1345
1346		return match;
1347	};
1348
1349	function get_element_from_field( element, ckey ) {
1350		var $element = $( element );
1351		var data_uniqid;
1352		var the_epo_id;
1353		var _class;
1354		var epoContainer;
1355
1356		if ( $element.length === 0 ) {
1357			return;
1358		}
1359
1360		if ( $element.is( '.cpf-section' ) ) {
1361			return element.find( '.tm-epo-field' );
1362		}
1363		data_uniqid = $element.attr( 'data-uniqid' );
1364		epoContainer = $element.closest( tcAPI.epoSelector );
1365		the_epo_id = epoContainer.attr( 'data-epo-id' );
1366
1367		if ( ! epoContainer.is( '.reactivate' ) && tcAPI.getElementFromFieldCache && tcAPI.getElementFromFieldCache[ the_epo_id ] && tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ] && tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] ) {
1368			return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ];
1369		}
1370		_class = $element
1371			.attr( 'class' )
1372			.split( ' ' )
1373			.map( function( cls ) {
1374				if ( cls.indexOf( 'cpf-type-', 0 ) !== -1 ) {
1375					return cls;
1376				}
1377				return null;
1378			} )
1379			.filter( function( v ) {
1380				if ( v !== null && v !== undefined ) {
1381					return v;
1382				}
1383				return null;
1384			} );
1385
1386		if ( _class.length > 0 ) {
1387			_class = _class[ 0 ];
1388			if ( _class === 'cpf-type-product' ) {
1389				if ( $element.is( '.cpf-type-product-mode-product' ) || $element.is( '.cpf-type-product-checkbox' ) || $element.is( '.cpf-type-product-thumbnailmultiple' ) || $element.is( '.cpf-type-product-custombundle' ) ) {
1390					_class = 'cpf-type-checkbox';
1391				} else if ( $element.is( '.cpf-type-product-dropdown' ) ) {
1392					_class = 'cpf-type-select';
1393				} else {
1394					_class = 'cpf-type-radio';
1395				}
1396			}
1397			if ( tcAPI.getElementFromFieldCache[ the_epo_id ] === undefined ) {
1398				tcAPI.getElementFromFieldCache[ the_epo_id ] = [];
1399			}
1400			if ( tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ] === undefined ) {
1401				tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ] = [];
1402			}
1403			switch ( _class ) {
1404				case 'cpf-type-radio':
1405					tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tmcp-radio' );
1406					return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ];
1407
1408				case 'cpf-type-checkbox':
1409					tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tmcp-checkbox' );
1410					return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ];
1411
1412				case 'cpf-type-select':
1413					tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tmcp-select' );
1414					return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ];
1415
1416				case 'cpf-type-selectmultiple':
1417					tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tmcp-selectmultiple' );
1418					return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ];
1419
1420				case 'cpf-type-textarea':
1421					tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tmcp-textarea' );
1422					return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ];
1423
1424				case 'cpf-type-textfield':
1425					tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tmcp-textfield' );
1426					return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ];
1427
1428				case 'cpf-type-color':
1429					tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tm-color-picker' );
1430					return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ];
1431
1432				case 'cpf-type-range':
1433					tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tmcp-range' );
1434					return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ];
1435
1436				case 'cpf-type-date':
1437					tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tmcp-date' );
1438					return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ];
1439
1440				case 'cpf-type-time':
1441					tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tmcp-time' );
1442					return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ];
1443
1444				case 'cpf-type-variations':
1445					tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.closest( '.cpf-section' ).find( '.tm-epo-field.tm-epo-variation-element' );
1446					return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ];
1447			}
1448		}
1449	}
1450
1451	// tc-lightbox
1452	if ( ! $().tclightbox ) {
1453		$.fn.tclightbox = function() {
1454			var elements = this;
1455
1456			if ( elements.length === 0 ) {
1457				return;
1458			}
1459
1460			return elements.toArray().forEach( function( lb ) {
1461				var $this = $( lb );
1462				var _imgsrc;
1463				var _label;
1464				var _input;
1465				var tclightboxwrap;
1466				var _img_button;
1467				var preload_img;
1468				var addButtonEvent;
1469
1470				if ( $this.is( '.tcinit' ) ) {
1471					return;
1472				}
1473				_imgsrc = $this.attr( 'src' ) || $this.attr( 'data-original' );
1474				_label = $this.closest( 'label' );
1475				_input = _label.closest( '.tmcp-field-wrap' ).find( ".tm-epo-field[id='" + _label.attr( 'for' ) + "']" );
1476				_imgsrc = $this.attr( 'data-large_image' ) || _input.attr( 'data-imagel' ) || _input.attr( 'data-imagep' ) || _input.attr( 'data-image' ) || _imgsrc;
1477
1478				if ( ! _imgsrc ) {
1479					return;
1480				}
1481
1482				$this.addClass( 'tcinit' ).before( $.epoAPI.template.html( tcAPI.templateEngine.tc_lightbox, {} ) );
1483				tclightboxwrap = $this.prev();
1484
1485				$this.wrap( "<div class='tc-lightbox-image-wrap'/>" );
1486				$this.after( tclightboxwrap );
1487
1488				_img_button = tclightboxwrap.find( '.tc-lightbox-button' );
1489
1490				addButtonEvent = function() {
1491					_img_button.addClass( 'tcinit' ).on( 'click.tclightbox', function( buttonevent ) {
1492						var size;
1493						var _img;
1494
1495						if ( $( '.tc-closing.tc-lightbox' ).length > 0 ) {
1496							return;
1497						}
1498
1499						size = $.epoAPI.dom.size();
1500						_img = $( '<img>' )
1501							.addClass( 'tc-lightbox-img' )
1502							.attr( 'src', _imgsrc )
1503							.css( 'maxHeight', size.visibleHeight + 'px' )
1504							.css( 'maxWidth', size.visibleWidth + 'px' );
1505
1506						$.tcFloatBox( {
1507							fps: 1,
1508							ismodal: false,
1509							width: 'auto',
1510							height: 'auto',
1511							classname: 'flasho tc-lightbox',
1512							animateIn: 'tc-lightbox-zoomin',
1513							animateOut: 'tc-lightbox-zoomout',
1514							data: $.epoAPI.template.html( tcAPI.templateEngine.tc_lightbox_zoom, { img: _img[ 0 ].outerHTML } ),
1515							zIndex: 102001,
1516							cancelClass: '.tc-lightbox-img, .tc-lightbox-button-close',
1517							unique: true
1518						} );
1519
1520						buttonevent.preventDefault();
1521					} );
1522				};
1523				if ( TMEPOJS.tm_epo_preload_lightbox_image === 'yes' ) {
1524					preload_img = new Image();
1525					preload_img.src = _imgsrc;
1526					preload_img.onload = function() {
1527						addButtonEvent();
1528					};
1529				} else {
1530					addButtonEvent();
1531				}
1532			} );
1533		};
1534	}
1535
1536	// Start Section popup
1537	if ( ! $().tmsectionpoplink ) {
1538		$.fn.tmsectionpoplink = function() {
1539			var elements = this;
1540
1541			if ( elements.length === 0 ) {
1542				return;
1543			}
1544
1545			return elements.toArray().forEach( function( pl ) {
1546				var $this = $( pl );
1547				var id;
1548				var title;
1549				var section;
1550				var clicked;
1551				var cancelfunc;
1552				var cancelpop;
1553
1554				if ( $this.data( 'tmsectionpoplink' ) ) {
1555					return;
1556				}
1557
1558				$this.data( 'tmsectionpoplink', true );
1559				id = $this.attr( 'data-sectionid' );
1560				title = TMEPOJS.i18n_addition_options;
1561				section = $this.closest( ".cpf-section[data-uniqid='" + id + "']" );
1562				clicked = false;
1563				cancelfunc = function() {
1564					var pop = $( '#tm-section-pop-up' );
1565					pop.parents().removeClass( 'noanimated' );
1566
1567					pop.after( section );
1568					pop.remove();
1569
1570					section.find( '.tm-section-link' ).show();
1571					section.find( '.tm-section-pop' ).hide();
1572				};
1573				cancelpop = function( e ) {
1574					if ( e.target === $( '.flasho' )[ 0 ] || $( e.target ).closest( '.flasho' ).length ) {
1575						return;
1576					}
1577
1578					cancelfunc();
1579				};
1580
1581				if ( $this.attr( 'data-title' ) ) {
1582					title = $this.attr( 'data-title' );
1583				}
1584
1585				$this.on( 'click.tmsectionpoplink', function( e ) {
1586					var pop;
1587
1588					e.preventDefault();
1589					clicked = false;
1590
1591					section.before(
1592						$.epoAPI.template.html( tcAPI.templateEngine.tc_section_pop_link, {
1593							title: title,
1594							close: TMEPOJS.i18n_close
1595						} )
1596					);
1597
1598					pop = $( '#tm-section-pop-up' );
1599
1600					pop.on( 'click', cancelpop );
1601
1602					pop.find( '.float-editbox' ).prepend( section );
1603
1604					section.find( '.tm-section-link' ).hide();
1605					section.find( '.tm-section-pop' ).show();
1606
1607					pop.parents().addClass( 'noanimated' );
1608
1609					pop.find( '.floatbox-cancel' ).on( 'click', function() {
1610						if ( clicked ) {
1611							return;
1612						}
1613						clicked = true;
1614						cancelfunc();
1615					} );
1616					jWindow.trigger( 'tmlazy' );
1617					jWindow.trigger( 'tmsectionpoplink' );
1618				} );
1619			} );
1620		};
1621	} // End Section popup
1622
1623	function getVariationIdSelector( currentCart ) {
1624		var variationIdSelector = "input[name^='variation_id']";
1625
1626		if ( currentCart.find( 'input.variation_id' ).length > 0 ) {
1627			variationIdSelector = 'input.variation_id';
1628		} else {
1629			variationIdSelector = 'input.product-variation-id';
1630		}
1631
1632		return variationIdSelector;
1633	}
1634
1635	function getVariationIdElement( currentCart, not ) {
1636		var variationIdSelector = getVariationIdSelector( currentCart );
1637		var variationIdElement = currentCart.find( variationIdSelector );
1638
1639		if ( currentCart.is( '.tc-epo-element-product-container-cart' ) ) {
1640			variationIdElement = currentCart.closest( '.tc-epo-element-product-li-container' ).find( variationIdSelector );
1641		} else {
1642			variationIdElement = currentCart.find( variationIdSelector ).not( '.tc-epo-element-product-container-variation-id ' + variationIdSelector );
1643		}
1644		if ( not ) {
1645			variationIdElement = variationIdElement.not( not );
1646		}
1647
1648		return variationIdElement;
1649	}
1650
1651	function getCurrentVariation( currentCart ) {
1652		var field_div;
1653		var newCart;
1654
1655		if ( currentCart.is( '.tc-epo-element-product-container-cart' ) ) {
1656			field_div = currentCart.closest( '.cpf-element' );
1657			if ( field_div.is( '.cpf-type-product-thumbnailmultiple' ) || field_div.is( '.cpf-type-product-checkbox' ) || field_div.is( '.cpf-type-product-custombundle' ) ) {
1658				newCart = currentCart.closest( '.tc-epo-element-product-holder' ).find( '.tc-epo-element-product-container-variation-id' );
1659			} else if ( field_div.is( '.cpf-type-product-thumbnail' ) || field_div.is( '.cpf-type-product-radio' ) || field_div.is( '.cpf-type-product-dropdown' ) || field_div.is( '.cpf-type-product-single' ) ) {
1660				newCart = field_div.find( '.tc-epo-element-product-container-variation-id' );
1661			}
1662			if ( newCart && newCart.length ) {
1663				currentCart = newCart;
1664			}
1665		}
1666		return currentCart.find( getVariationIdSelector( currentCart ) ).val() || 0;
1667	}
1668
1669	function getQtyElement( currentCart ) {
1670		var qty = currentCart.find( tcAPI.qtySelector ).last();
1671		if ( qty.length === 0 ) {
1672			qty = currentCart.find( tcAPI.associateQtySelector ).last();
1673		}
1674		qty = $.epoAPI.applyFilter( 'tc_getQtyElement', qty, currentCart );
1675		return qty;
1676	}
1677
1678	function getCurrentQty( currentCart ) {
1679		return $.epoAPI.applyFilter( 'tc_getCurrentQty', $.epoAPI.math.toFloat( getQtyElement( currentCart ).val() ), currentCart );
1680	}
1681
1682	function add_variation_event( name, selector, func ) {
1683		lateVariationEvent[ lateVariationEvent.length ] = {
1684			name: name,
1685			selector: selector,
1686			func: func
1687		};
1688	}
1689
1690	function field_is_active( field, nochecks, single, simpleCheck ) {
1691		var ret = true;
1692		var insideProductCheck = false;
1693		var productElement;
1694		field = $( field );
1695		productElement = field.filter( '.tc-epo-field-product' );
1696		if ( productElement.length && productElement.data( 'islogicinit' ) === undefined ) {
1697			insideProductCheck = true;
1698		}
1699		field.toArray().forEach( function( element ) {
1700			if ( ! ret && field.has( '.tc-epo-field-product' ).length ) {
1701				if ( insideProductCheck || productElement.is( '.tcdisabled' ) ) {
1702					if ( simpleCheck ) {
1703						field_check_active_simple( element );
1704					} else {
1705						field_check_active( element, nochecks, single, simpleCheck );
1706					}
1707				}
1708			} else if ( simpleCheck ) {
1709				ret = field_check_active_simple( element );
1710			} else {
1711				ret = field_check_active( element, nochecks, single, simpleCheck ) && ret;
1712			}
1713		} );
1714
1715		return ret;
1716	}
1717
1718	function field_check_active_simple( field ) {
1719		var hideElement;
1720		var isInsideProductElement;
1721		var productElementActive;
1722		var productElementSectionActive;
1723		var section;
1724
1725		field = $( field );
1726		if ( field.is( '.cpf-element' ) ) {
1727			hideElement = field;
1728			field = field.find( '.tmcp-field, .tmcp-fee-field' );
1729		} else {
1730			hideElement = field.closest( '.cpf-element' );
1731		}
1732
1733		section = hideElement.closest( '.cpf-section' );
1734
1735		isInsideProductElement = ! field.is( '.tc-epo-field-product' ) && hideElement.closest( '.cpf-type-product' );
1736
1737		if ( isInsideProductElement.length ) {
1738			productElementActive = isInsideProductElement.data( 'isactive' );
1739			isInsideProductElement = isInsideProductElement.closest( '.cpf-section' );
1740			productElementSectionActive = isInsideProductElement.data( 'isactive' );
1741		}
1742		if ( productElementActive !== false && productElementSectionActive !== false && hideElement.data( 'isactive' ) !== false && section.data( 'isactive' ) !== false ) {
1743			return true;
1744		}
1745
1746		return false;
1747	}
1748
1749	function field_check_active( field, nochecks, single ) {
1750		var hideElement;
1751		var singleField;
1752		var ul;
1753		var isInsideProductElement;
1754		var productElementActive;
1755		var productElementSectionActive;
1756		var productElementQty;
1757		var section;
1758		var disableElements;
1759		var sectionLi;
1760		var allSectionsDisabled;
1761		var tabSlide;
1762		var epoFields;
1763
1764		field = $( field );
1765		if ( field.is( '.cpf-element' ) ) {
1766			hideElement = field;
1767			field = field.find( '.tmcp-field, .tmcp-fee-field' );
1768		} else {
1769			hideElement = field.closest( '.cpf-element' );
1770		}
1771
1772		section = hideElement.closest( '.cpf-section' );
1773		sectionLi = section.closest( '.tm-extra-product-options-field' );
1774
1775		if ( single ) {
1776			ul = field.closest( '.tmcp-ul-wrap' );
1777		} else {
1778			ul = hideElement;
1779		}
1780
1781		if ( field.is( '.tc-epo-field-product' ) && field.data( 'islogicinit' ) === undefined ) {
1782			field.data( 'islogicinit', 1 );
1783		}
1784
1785		if ( ! field.is( '.tc-force-disabled' ) ) {
1786			isInsideProductElement = ! field.is( '.tc-epo-field-product' ) && hideElement.closest( '.cpf-type-product' );
1787
1788			if ( isInsideProductElement.length ) {
1789				productElementQty = isInsideProductElement.find( tcAPI.associateQtySelector );
1790				if ( productElementQty.length ) {
1791					if ( $.epoAPI.math.toFloat( productElementQty.val() ) > 0 ) {
1792						field.removeClass( 'ignore' );
1793						productElementQty.removeClass( 'ignore' );
1794					} else {
1795						field.addClass( 'ignore' );
1796						productElementQty.addClass( 'ignore' );
1797					}
1798				}
1799				productElementActive = isInsideProductElement.data( 'isactive' );
1800				isInsideProductElement = isInsideProductElement.closest( '.cpf-section' );
1801				productElementSectionActive = isInsideProductElement.data( 'isactive' );
1802			}
1803			if ( productElementActive !== false && productElementSectionActive !== false && hideElement.data( 'isactive' ) !== false && section.data( 'isactive' ) !== false ) {
1804				singleField = field.first();
1805				field.prop( 'disabled', false );
1806				if ( field.data( 'tc-state' ) !== undefined ) {
1807					field.data( 'tc-state', false );
1808				}
1809
1810				if ( TMEPOJS.tm_epo_show_only_active_quantities !== 'yes' ) {
1811					if ( singleField.is( ':radio, .cpf-type-radio' ) || singleField.is( ':checkbox, .cpf-type-checkbox' ) ) {
1812						field.filter( ':checked' ).closest( '.tmcp-field-wrap' ).find( '.tm-qty, .tc-qty-button' ).prop( 'disabled', false );
1813						field.not( ':checked' ).closest( '.tmcp-field-wrap' ).find( '.tm-qty, .tc-qty-button' ).prop( 'disabled', true );
1814					} else if ( singleField.is( 'select, .cpf-type-select, .cpf-type-selectmultiple' ) ) {
1815						if ( singleField.val() ) {
1816							ul.find( '.tm-qty, .tc-qty-button' ).prop( 'disabled', false );
1817						} else {
1818							ul.find( '.tm-qty, .tc-qty-button' ).prop( 'disabled', true );
1819						}
1820					} else if ( singleField.val() ) {
1821						ul.find( '.tm-qty, .tc-qty-button' ).prop( 'disabled', false );
1822					} else {
1823						ul.find( '.tm-qty, .tc-qty-button' ).prop( 'disabled', true );
1824					}
1825				} else if ( ! nochecks ) {
1826					hideElement.find( '.tm-quantity' ).trigger( 'showhide.cpfcustom' );
1827				}
1828
1829				if ( ! singleField.is( '.cpf-element' ) ) {
1830					field.removeClass( 'tcdisabled' ).addClass( 'tcenabled' );
1831
1832					if ( field.is( '.tmcp-upload' ) ) {
1833						if ( field.next( '.tmcp-upload-hidden' ).length ) {
1834							field.next( '.tmcp-upload-hidden' ).removeClass( 'tcdisabled' ).addClass( 'tcenabled' ).prop( 'disabled', false );
1835						}
1836					}
1837				}
1838
1839				hideElement.removeClass( 'tc-container-disabled' ).addClass( 'tc-container-enabled' );
1840				hideElement.find( '.product-variation-id, .tc-epo-field-product-counter' ).prop( 'disabled', false );
1841
1842				field.trigger( {
1843					type: 'tm-field-is-active',
1844					field: field,
1845					value: true
1846				} );
1847				section.removeClass( 'section-disabled' );
1848				sectionLi.removeClass( 'tc-hidden' );
1849
1850				hideElement.closest( '.owl-item' ).removeClass( 'tc-hidden-visibility' );
1851
1852				return true;
1853			}
1854		}
1855
1856		if ( ! field.is( '.cpf-element' ) ) {
1857			field.prop( 'disabled', true ).removeClass( 'tcenabled' ).addClass( 'tcdisabled' );
1858			if ( field.data( 'tc-state' ) !== undefined ) {
1859				field.data( 'tc-state', true );
1860			}
1861			hideElement.find( '.tm-qty, .tc-qty-button' ).prop( 'disabled', true );
1862			if ( field.is( '.tmcp-upload' ) ) {
1863				if ( field.next( '.tmcp-upload-hidden' ).length ) {
1864					field.next( '.tmcp-upload-hidden' ).removeClass( 'tcenabled' ).addClass( 'tcdisabled' ).prop( 'disabled', true );
1865				}
1866			}
1867		}
1868
1869		if ( field.is( '.tc-force-disabled' ) ) {
1870			epoFields = hideElement.find( '.tmcp-field, .tmcp-fee-field' );
1871			if ( epoFields.length !== epoFields.filter( '.tc-force-disabled' ).length ) {
1872				return false;
1873			}
1874		}
1875
1876		hideElement.removeClass( 'tc-container-enabled' ).addClass( 'tc-container-disabled' );
1877		hideElement.find( '.product-variation-id, .tc-epo-field-product-counter' ).prop( 'disabled', true );
1878
1879		field.trigger( {
1880			type: 'tm-field-is-active',
1881			field: field,
1882			value: false
1883		} );
1884
1885		disableElements = section.find( '.cpf-element.tc-container-enabled' ).length === 0;
1886		if ( disableElements ) {
1887			section.addClass( 'section-disabled' );
1888			allSectionsDisabled = sectionLi.children( '.cpf-section' ).filter( function() {
1889				return ! $( this ).hasClass( 'section-disabled' );
1890			} ).length === 0;
1891			if ( allSectionsDisabled ) {
1892				sectionLi.addClass( 'tc-hidden' );
1893			}
1894		}
1895
1896		tabSlide = hideElement.closest( '.tc-tab-slide' ).find( '.cpf-element.tc-container-enabled' ).length === 0;
1897		if ( tabSlide ) {
1898			hideElement.closest( '.owl-item' ).addClass( 'tc-hidden-visibility' );
1899		}
1900
1901		return false;
1902	}
1903
1904	function tm_variation_check_match( element, val2, operator ) {
1905		var $element = $( element );
1906		var epoId = $element.attr( 'data-epo_id' ) || $element.attr( 'data-epo-id' );
1907		var productId = $element.attr( 'data-product_id' ) || $element.attr( 'data-product-id' );
1908
1909		var variationsForm = $( '.variations_form[data-epo_id="' + epoId + '"][data-product_id="' + productId + '"]' );
1910		var val1;
1911		var variationIdSelector = 'input[name^="variation_id"]';
1912		var $variationId;
1913
1914		variationsForm = $.epoAPI.applyFilter( 'tm_variation_check_match_variationsForm', variationsForm, epoId, productId, $element );
1915		if ( $element.attr( 'data-product_type' ) === 'variation' ) {
1916			variationsForm = $element;
1917			$variationId = productId;
1918		}
1919		if ( variationsForm.length === 0 && $element.is( '.cpf-type-variations' ) && ! epoId && ! productId ) {
1920			variationsForm = $element.closest( '.tc-epo-element-product-container' );
1921			if ( variationsForm.length ) {
1922				productId = variationsForm.attr( 'data-product_id' );
1923				$variationId = productId;
1924			}
1925		}
1926
1927		if ( variationsForm.length === 0 ) {
1928			return false;
1929		}
1930
1931		if ( ! $variationId ) {
1932			$variationId = variationsForm.find( variationIdSelector );
1933
1934			if ( $variationId.length === 0 ) {
1935				variationIdSelector = 'input.variation_id';
1936
1937				$variationId = variationsForm.find( variationIdSelector );
1938
1939				if ( $variationId.length === 0 ) {
1940					$variationId = variationsForm.closest( '.tc-epo-element-product-li-container' ).find( '.product-variation-id' );
1941				}
1942			}
1943			if ( $variationId.length ) {
1944				$variationId = $variationId.val();
1945			} else {
1946				$variationId = 0;
1947			}
1948		}
1949
1950		if ( element !== null && val2 !== null && element !== undefined && val2 !== undefined && element !== false && val2 !== false ) {
1951			if ( val2 ) {
1952				val2 = parseInt( val2, 10 );
1953			} else {
1954				val2 = -1;
1955			}
1956		}
1957
1958		val1 = parseInt( $variationId, 10 );
1959
1960		if ( ! Number.isFinite( val1 ) ) {
1961			val1 = 0;
1962		}
1963		if ( ! Number.isFinite( val2 ) ) {
1964			val2 = 0;
1965		}
1966
1967		switch ( operator ) {
1968			case 'is':
1969				return val1 !== '' && val1 === val2;
1970
1971			case 'isnot':
1972				return val1 !== '' && val1 !== val2;
1973
1974			case 'isempty':
1975				return val1 === '' || val1 === 0;
1976
1977			case 'isnotempty':
1978				return val1 !== '' && val1 !== 0;
1979
1980			case 'startswith':
1981				return val1.toString().startsWith( val2 );
1982
1983			case 'endswith':
1984				return val1.toString().endsWith( val2 );
1985
1986			case 'greaterthan':
1987				return parseFloat( val1 ) > parseFloat( val2 );
1988
1989			case 'lessthan':
1990				return parseFloat( val1 ) < parseFloat( val2 );
1991
1992			case 'greaterthanequal':
1993				return parseFloat( val1 ) >= parseFloat( val2 );
1994
1995			case 'lessthanequal':
1996				return parseFloat( val1 ) <= parseFloat( val2 );
1997		}
1998		return false;
1999	}
2000
2001	function tm_variationattributes_check_match( element, rule ) {
2002		var $element = $( element );
2003		var val2 = rule.value;
2004		var operator = rule.operator;
2005		var epoId = $element.attr( 'data-epo_id' ) || $element.attr( 'data-epo-id' );
2006		var productId = $element.attr( 'data-product_id' ) || $element.attr( 'data-product-id' );
2007
2008		var variationsForm = $( '.variations_form[data-epo_id="' + epoId + '"][data-product_id="' + productId + '"]' );
2009		var val1;
2010		var $att;
2011
2012		variationsForm = $.epoAPI.applyFilter( 'tm_variation_check_match_variationsForm', variationsForm, epoId, productId, $element );
2013		if ( $element.attr( 'data-product_type' ) === 'variation' ) {
2014			variationsForm = $element;
2015		}
2016		if ( variationsForm.length === 0 && $element.is( '.cpf-type-variations' ) && ! epoId && ! productId ) {
2017			variationsForm = $element.closest( '.tc-epo-element-product-container' );
2018			if ( variationsForm.length ) {
2019				productId = variationsForm.attr( 'data-product_id' );
2020			}
2021		}
2022
2023		if ( variationsForm.length === 0 ) {
2024			return false;
2025		}
2026
2027		$att = variationsForm.find( '[name="attribute_' + rule.taxonomy + '"]' );
2028
2029		if ( ! $att.length ) {
2030			return false;
2031		}
2032
2033		val1 = $att.find( 'option:selected' ).attr( 'value' );
2034
2035		switch ( operator ) {
2036			case 'is':
2037				return val1 !== '' && val1 === val2;
2038
2039			case 'isnot':
2040				return val1 !== '' && val1 !== val2;
2041
2042			case 'isempty':
2043				return val1 === '' || val1 === 0;
2044
2045			case 'isnotempty':
2046				return val1 !== '' && val1 !== 0;
2047
2048			case 'startswith':
2049				return val1.toString().startsWith( val2 );
2050
2051			case 'endswith':
2052				return val1.toString().endsWith( val2 );
2053		}
2054		return false;
2055	}
2056
2057	function tm_check_match( val1, val2, operator ) {
2058		if ( val1 !== null && val2 !== null ) {
2059			val1 = encodeURIComponent( val1 );
2060			if ( $.qtranxj_split ) {
2061				//backwards compatible
2062				val2 = encodeURIComponent( $.qtranxj_split( decodeURIComponent( val2 ) )[ TMEPOQTRANSLATEXJS.language ] );
2063			} else {
2064				//backwards compatible
2065				val2 = encodeURIComponent( decodeURIComponent( val2 ) );
2066			}
2067
2068			if ( val1 ) {
2069				val1 = val1.toLowerCase();
2070			} else {
2071				val1 = '';
2072			}
2073			if ( val2 ) {
2074				val2 = val2.toLowerCase();
2075			} else {
2076				val2 = '';
2077			}
2078		} else {
2079			return false;
2080		}
2081
2082		val1 = val1.toString();
2083		val2 = val2.toString();
2084
2085		switch ( operator ) {
2086			case 'is':
2087				return val1 !== null && val1 === val2;
2088
2089			case 'isnot':
2090				return val1 !== null && val1 !== val2;
2091
2092			case 'isempty':
2093				return ! ( val1 !== 'undefined' && val1 !== undefined && val1 !== '' );
2094
2095			case 'isnotempty':
2096				return val1 !== 'undefined' && val1 !== undefined && val1 !== '';
2097
2098			case 'startswith':
2099				return val1.startsWith( val2 );
2100
2101			case 'endswith':
2102				return val1.endsWith( val2 );
2103
2104			case 'greaterthan':
2105				return parseFloat( val1 ) > parseFloat( val2 );
2106
2107			case 'lessthan':
2108				return parseFloat( val1 ) < parseFloat( val2 );
2109
2110			case 'greaterthanequal':
2111				return parseFloat( val1 ) >= parseFloat( val2 );
2112
2113			case 'lessthanequal':
2114				return parseFloat( val1 ) <= parseFloat( val2 );
2115		}
2116
2117		return false;
2118	}
2119
2120	function tm_check_section_match( elements, operator ) {
2121		var any_checked;
2122		var val;
2123		var all_elements = elements.find( '.cpf-element' );
2124		var radio_checked;
2125		var checkbox_checked;
2126		var noSplit = false;
2127
2128		if ( elements.is( '.tc-hidden' ) ) {
2129			if ( operator === 'isnotempty' ) {
2130				return false;
2131			} else if ( operator === 'isempty' ) {
2132				return true;
2133			}
2134		}
2135
2136		if ( operator === 'isnotempty' ) {
2137			any_checked = false;
2138		} else if ( operator === 'isempty' ) {
2139			any_checked = true;
2140		}
2141
2142		$( all_elements ).toArray().forEach( function( element ) {
2143			var _class;
2144			var elementToCheck = '';
2145
2146			element = $( element );
2147			if ( element.is( '.cpf-type-product' ) ) {
2148				elementToCheck = ':not(' + tcAPI.associatedEpoSelector + ' .tm-epo-field)';
2149			}
2150			if ( field_is_active( element, undefined, undefined, true ) ) {
2151				_class = element
2152					.attr( 'class' )
2153					.split( ' ' )
2154					.map( function( cls ) {
2155						if ( cls.indexOf( 'cpf-type-', 0 ) !== -1 ) {
2156							return cls;
2157						}
2158						return null;
2159					} )
2160					.filter( function( v ) {
2161						if ( v !== null && v !== undefined ) {
2162							return v;
2163						}
2164						return null;
2165					} );
2166
2167				if ( _class.length > 0 ) {
2168					_class = _class[ 0 ];
2169					if ( _class === 'cpf-type-product' ) {
2170						noSplit = true;
2171						if ( element.is( '.cpf-type-product-mode-product' ) || element.is( '.cpf-type-product-checkbox' ) || element.is( '.cpf-type-product-thumbnailmultiple' ) || element.is( '.cpf-type-product-custombundle' ) ) {
2172							_class = 'cpf-type-checkbox';
2173						} else if ( element.is( '.cpf-type-product-dropdown' ) ) {
2174							_class = 'cpf-type-select';
2175						} else {
2176							_class = 'cpf-type-radio';
2177						}
2178					}
2179					switch ( _class ) {
2180						case 'cpf-type-radio':
2181							radio_checked = element.find( 'input.tm-epo-field.tmcp-radio:checked' + elementToCheck );
2182							if ( operator === 'isnotempty' ) {
2183								any_checked = any_checked || radio_checked.length > 0;
2184								if ( radio_checked.length > 0 ) {
2185									val = radio_checked.length;
2186								}
2187							} else if ( operator === 'isempty' ) {
2188								any_checked = any_checked && radio_checked.length === 0;
2189							}
2190							break;
2191
2192						case 'cpf-type-checkbox':
2193							checkbox_checked = element.find( 'input.tm-epo-field.tmcp-checkbox:checked' + elementToCheck );
2194							if ( operator === 'isnotempty' ) {
2195								any_checked = any_checked || checkbox_checked.length > 0;
2196								if ( checkbox_checked.length > 0 ) {
2197									val = checkbox_checked.length;
2198								}
2199							} else if ( operator === 'isempty' ) {
2200								any_checked = any_checked && checkbox_checked.length === 0;
2201							}
2202							break;
2203
2204						case 'cpf-type-select':
2205							val = element.find( 'select.tm-epo-field.tmcp-select' + elementToCheck ).val();
2206							if ( val && ! noSplit ) {
2207								val = val.slice( 0, val.lastIndexOf( '_' ) );
2208							}
2209							break;
2210
2211						case 'cpf-type-selectmultiple':
2212							val = element.find( 'select.tm-epo-field.tmcp-selectmultiple' + elementToCheck ).val();
2213							if ( val && ! noSplit ) {
2214								val.forEach( function( option, i ) {
2215									val[ i ] = option.slice( 0, option.lastIndexOf( '_' ) );
2216								} );
2217							}
2218							break;
2219
2220						default:
2221							val = element.find( '.tm-epo-field' + elementToCheck ).val();
2222							break;
2223					}
2224					if ( Array.isArray( val ) ) {
2225						if ( operator === 'isnotempty' ) {
2226							any_checked = any_checked || val.some( function( item ) {
2227								return tm_check_match( item, '', operator );
2228							} );
2229						} else if ( operator === 'isempty' ) {
2230							any_checked = any_checked && val.every( function( item ) {
2231								return tm_check_match( item, '', operator );
2232							} );
2233						}
2234					} else if ( operator === 'isnotempty' ) {
2235						any_checked = any_checked || tm_check_match( val, '', operator );
2236					} else if ( operator === 'isempty' ) {
2237						any_checked = any_checked && tm_check_match( val, '', operator );
2238					}
2239				} else {
2240					any_checked = false;
2241				}
2242			}
2243		} );
2244
2245		return any_checked;
2246	}
2247
2248	function tm_check_field_match( f ) {
2249		var element = f.element;
2250		var operator = f.rule.operator;
2251		var value = f.rule.value;
2252		var type = f.type;
2253		var val;
2254		var radio_checked;
2255		var checkbox_checked;
2256		var ret;
2257		var _class;
2258		var noSplit = false;
2259		var elementToCheck = '';
2260
2261		if ( type === 'quantity' ) {
2262			return tm_check_match( element.val(), value, operator );
2263		}
2264		if ( type === 'productid' ) {
2265			return tm_check_match( element, value, operator );
2266		}
2267		if ( type === 'variation' ) {
2268			return tm_variation_check_match( element, value, operator );
2269		}
2270		if ( type === 'variationattributes' ) {
2271			return tm_variationattributes_check_match( element, f.rule );
2272		}
2273		element = $( f.element );
2274
2275		if ( ! element.length ) {
2276			return false;
2277		}
2278		if ( element.is( '.cpf-section' ) ) {
2279			return tm_check_section_match( element, operator );
2280		}
2281		if ( element.is( '.cpf-type-product' ) ) {
2282			elementToCheck = ':not(' + tcAPI.associatedEpoSelector + ' .tm-epo-field)';
2283		}
2284		_class = element
2285			.attr( 'class' )
2286			.split( ' ' )
2287			.map( function( cls ) {
2288				if ( cls.indexOf( 'cpf-type-', 0 ) !== -1 ) {
2289					return cls;
2290				}
2291				return null;
2292			} )
2293			.filter( function( v ) {
2294				if ( v !== null && v !== undefined ) {
2295					return v;
2296				}
2297				return null;
2298			} );
2299
2300		if ( _class.length > 0 ) {
2301			_class = _class[ 0 ];
2302			if ( _class === 'cpf-type-product' ) {
2303				noSplit = true;
2304				if ( element.is( '.cpf-type-product-mode-product' ) || element.is( '.cpf-type-product-checkbox' ) || element.is( '.cpf-type-product-thumbnailmultiple' ) || element.is( '.cpf-type-product-custombundle' ) ) {
2305					_class = 'cpf-type-checkbox';
2306				} else if ( element.is( '.cpf-type-product-dropdown' ) ) {
2307					_class = 'cpf-type-select';
2308				} else {
2309					_class = 'cpf-type-radio';
2310				}
2311			}
2312			switch ( _class ) {
2313				case 'cpf-type-radio':
2314					radio_checked = element.find( 'input.tm-epo-field.tmcp-radio:checked' + elementToCheck );
2315
2316					if ( operator === 'is' || operator === 'isnot' ) {
2317						if ( radio_checked.length === 0 && operator === 'is' ) {
2318							return false;
2319						}
2320						if ( radio_checked.length === 0 && operator === 'isnot' ) {
2321							return true;
2322						}
2323					}
2324					if ( operator === 'isnotempty' ) {
2325						return radio_checked.length > 0;
2326					}
2327					if ( operator === 'isempty' ) {
2328						return radio_checked.length === 0;
2329					}
2330					val = element.find( 'input.tm-epo-field.tmcp-radio:checked' + elementToCheck ).val();
2331					if ( val && ! noSplit ) {
2332						val = val.slice( 0, val.lastIndexOf( '_' ) );
2333					}
2334					break;
2335				case 'cpf-type-checkbox':
2336					checkbox_checked = element.find( 'input.tm-epo-field.tmcp-checkbox:checked' + elementToCheck );
2337
2338					if ( operator === 'is' || operator === 'isnot' ) {
2339						if ( checkbox_checked.length === 0 && operator === 'is' ) {
2340							return false;
2341						}
2342						if ( checkbox_checked.length === 0 && operator === 'isnot' ) {
2343							return true;
2344						}
2345						ret = false;
2346						checkbox_checked.toArray().forEach( function( el ) {
2347							val = $( el ).val();
2348							if ( val && ! noSplit ) {
2349								val = val.slice( 0, val.lastIndexOf( '_' ) );
2350							}
2351							if ( tm_check_match( val, value, operator ) ) {
2352								ret = true;
2353							} else if ( operator === 'isnot' ) {
2354								ret = false;
2355								return false;
2356							}
2357						} );
2358						return ret;
2359					}
2360					if ( operator === 'isnotempty' ) {
2361						return checkbox_checked.length > 0;
2362					}
2363					if ( operator === 'isempty' ) {
2364						return checkbox_checked.length === 0;
2365					}
2366					break;
2367				case 'cpf-type-select':
2368					val = element.find( 'select.tm-epo-field.tmcp-select' + elementToCheck ).val();
2369					if ( val && ! noSplit ) {
2370						val = val.slice( 0, val.lastIndexOf( '_' ) );
2371					}
2372					break;
2373				case 'cpf-type-selectmultiple':
2374					val = element.find( 'select.tm-epo-field.tmcp-selectmultiple' + elementToCheck ).val();
2375					if ( val && ! noSplit ) {
2376						val.forEach( function( option, i ) {
2377							val[ i ] = option.slice( 0, option.lastIndexOf( '_' ) );
2378						} );
2379					}
2380					break;
2381				case 'cpf-type-variations':
2382					return tm_variation_check_match( element, value, operator );
2383
2384				default:
2385					val = element.find( '.tm-epo-field' + elementToCheck ).val();
2386					break;
2387			}
2388			if ( Array.isArray( val ) ) {
2389				return val.some( function( item ) {
2390					return tm_check_match( item, value, operator );
2391				} );
2392			}
2393			return tm_check_match( val, value, operator );
2394		}
2395		return false;
2396	}
2397
2398	function tm_check_rules( o, theevent ) {
2399		o.toArray().forEach( function( oel ) {
2400			var $this = $( oel );
2401			var matches = $this.data( 'matches' );
2402			var toggle = $this.data( 'toggle' );
2403			var fields = $this.data( 'fields' );
2404			var checked = [];
2405			var show = toggle !== 'show';
2406			var ifield;
2407			var i;
2408			var field;
2409			var ii;
2410			var im;
2411			var sectionFields;
2412			var isInSectionRepeater;
2413
2414			if ( ! fields ) {
2415				return;
2416			}
2417
2418			sectionFields = $this.closest( '.tc-section-fields' );
2419			isInSectionRepeater = sectionFields.is( '.tc-repeater-section' );
2420
2421			for ( i = 0; i < fields.length; i++ ) {
2422				ifield = fields[ i ];
2423				if ( Array.isArray( ifield ) ) {
2424					checked[ i ] = 0;
2425					for ( ii = 0; ii < ifield.length; ii++ ) {
2426						field = ifield[ ii ];
2427						if ( isInSectionRepeater ) {
2428							field.element = sectionFields.find( '[data-uniqid="' + field.element.attr( 'data-uniqid' ) + '"' );
2429						}
2430						if ( theevent !== 'cpflogic' || field_is_active( $( field.element ), undefined, undefined, true ) ) {
2431							if ( tm_check_field_match( field ) ) {
2432								checked[ i ] = ( checked[ i ] || 0 ) + 1;
2433							}
2434						}
2435					}
2436				}
2437			}
2438
2439			for ( im = 0; im < matches.length; im++ ) {
2440				if ( parseInt( checked[ im ], 10 ) === parseInt( matches[ im ], 10 ) ) {
2441					show = ! show;
2442					break;
2443				}
2444			}
2445
2446			if ( show ) {
2447				if ( theevent === 'cpflogic' && ! $this.data( 'did_initial_activation' ) ) {
2448					latecpflogicactions.push( function() {
2449						var enabledEpos = $this.find( '.tm-epo-field.tcenabled' );
2450						enabledEpos.toArray().forEach( function( el ) {
2451							el = $( el );
2452							if ( ! el.data( 'initial_activation' ) && ! $this.closest( '.cpf-section' ).is( '.tc-hidden' ) && field_is_active( el ) ) {
2453								el.trigger( 'tc_element_epo_rules' );
2454								el.data( 'initial_activation', 1 );
2455							}
2456						} );
2457						if ( ( $this.is( '.cpf-element' ) && enabledEpos.length ) || $this.is( '.cpf-section' ) ) {
2458							$this.data( 'did_initial_activation', 1 );
2459						}
2460					} );
2461				}
2462				$this.removeClass( 'tc-hidden' );
2463			} else {
2464				$this.addClass( 'tc-hidden' );
2465			}
2466
2467			$this.data( 'isactive', show ).trigger( 'tc-logic' );
2468		} );
2469	}
2470
2471	function run_cpfdependson( obj ) {
2472		var iscpfdependson;
2473		var last_activate_field = [];
2474		var epo_object;
2475
2476		if ( ! $( obj ).length ) {
2477			obj = 'body';
2478		}
2479		obj = $( obj );
2480		iscpfdependson = obj.find( '.iscpfdependson' );
2481		iscpfdependson.toArray().forEach( function( elements ) {
2482			$( elements ).toArray().forEach( function( el ) {
2483				tm_check_rules( $( el ) );
2484			} );
2485		} );
2486		iscpfdependson.toArray().forEach( function( elements ) {
2487			$( elements ).toArray().forEach( function( el ) {
2488				tm_check_rules( $( el ), 'cpflogic' );
2489			} );
2490		} );
2491		iscpfdependson.toArray().forEach( function( elements ) {
2492			$( elements ).toArray().forEach( function( o ) {
2493				o = $( o );
2494				if ( o.is( '.cpf-section' ) ) {
2495					o = o.find( '.cpf-element' );
2496				}
2497				o.toArray().forEach( function( theelement ) {
2498					var $theelement = $( theelement );
2499					var $theelementepos = $theelement.find( '.tm-epo-field' );
2500					var len = $theelementepos.length;
2501					if ( len > 0 ) {
2502						field_is_active( $theelementepos );
2503					} else {
2504						field_is_active( $theelement );
2505					}
2506				} );
2507			} );
2508		} );
2509		latecpflogicactions.forEach( function( func ) {
2510			func();
2511		} );
2512		latecpflogicactions = [];
2513		if ( $().selectric ) {
2514			$( '.tm-extra-product-options select' ).selectric( 'refresh' );
2515		}
2516		setTimeout( function() {
2517			$( '.tm-owl-slider' ).toArray().forEach( function( slider ) {
2518				$( slider ).trigger( 'refresh.owl.carousel' );
2519			} );
2520		}, 200 );
2521
2522		obj.find( '.tm-product-image:checked,select.tm-product-image' ).toArray().forEach( function( t ) {
2523			t = $( t );
2524			if ( field_is_active( t ) && t.val() !== '' ) {
2525				last_activate_field.push( t );
2526			}
2527		} );
2528		if ( last_activate_field.length ) {
2529			last_activate_field[ last_activate_field.length - 1 ].trigger( 'tm_trigger_product_image' );
2530		} else {
2531			epo_object = obj.data( 'epo_object' );
2532			if ( epo_object ) {
2533				epo_object.main_product.trigger( 'tm_restore_product_image' );
2534			}
2535		}
2536
2537		jWindow.trigger( 'cpflogicrun' );
2538		jWindow.trigger( 'tmlazy' );
2539		jWindow.trigger( 'cpflogicdone' );
2540	}
2541
2542	// Start Conditional logic
2543	if ( ! $().cpfdependson ) {
2544		$.fn.cpfdependson = function( fields, toggle, refresh, epoObject ) {
2545			var elements = this;
2546			var matches = [];
2547			var $this_epo_container = null;
2548			var get_element;
2549			var $element;
2550			var $pid1;
2551			var $epo_id1;
2552			var _events;
2553			var $container;
2554			var i;
2555			var ii;
2556			var iii;
2557			var e;
2558			var ifield;
2559			var field;
2560			var $this;
2561			var show;
2562			var sectionFields;
2563			var isInSectionRepeater;
2564
2565			if ( ! elements.length || typeof fields !== 'object' ) {
2566				return;
2567			}
2568
2569			if ( ! toggle ) {
2570				toggle = 'show';
2571			}
2572
2573			sectionFields = elements.first().closest( '.tc-section-fields' );
2574			isInSectionRepeater = sectionFields.is( '.tc-repeater-section' );
2575
2576			// Initialize the matches array
2577			for ( i = 0; i < fields.length; i++ ) {
2578				matches[ i ] = 0;
2579				ifield = fields[ i ];
2580
2581				if ( Array.isArray( ifield ) ) {
2582					for ( ii = 0; ii < ifield.length; ii++ ) {
2583						field = ifield[ ii ];
2584						if ( typeof field !== 'object' ) {
2585							continue;
2586						}
2587						if ( isInSectionRepeater ) {
2588							field.element = sectionFields.find( '[data-uniqid="' + field.element.attr( 'data-uniqid' ) + '"' );
2589						}
2590
2591						if ( field.type === 'quantity' ) {
2592							if ( ! field.element.data( 'didcpflogic' ) ) {
2593								_events = 'change.cpflogic input.cpflogic';
2594								field.element.off( _events ).on( _events, function() {
2595									run_cpfdependson( epoObject.this_epo_container );
2596								} ).data( 'didcpflogic', 1 );
2597							}
2598						} else if ( field.type === 'variation' || field.type === 'variationattributes' ) {
2599							add_variation_event( 'found_variation.tmlogic', false, function() {
2600								run_cpfdependson( field.element );
2601								jWindow.trigger( 'tm-do-epo-update' );
2602							} );
2603
2604							add_variation_event( 'hide_variation.tmlogic', false, function() {
2605								run_cpfdependson( field.element );
2606								jWindow.trigger( 'tm-do-epo-update' );
2607							} );
2608						} else {
2609							get_element = get_element_from_field( field.element, isInSectionRepeater ? sectionFields.index() : 0 );
2610							if ( get_element && get_element.length > 0 ) {
2611								for ( iii = 0; iii < get_element.length; iii++ ) {
2612									if ( ! get_element[ iii ] ) {
2613										continue;
2614									}
2615									$element = $( get_element[ iii ] );
2616
2617									if ( $element.length === 0 ) {
2618										continue;
2619									}
2620
2621									_events = 'change.cpflogic';
2622
2623									// this essentially only works for the plugin so we use
2624									// cache and not recalcualte each time
2625									if ( ! $this_epo_container || $this_epo_container.closest( tcAPI.associatedEpoSelector ).length ) {
2626										$container = $element.closest( tcAPI.epoSelector );
2627										$pid1 = '.tm-product-id-' + $container.attr( 'data-product-id' );
2628										$epo_id1 = "[data-epo-id='" + $container.attr( 'data-epo-id' ) + "']";
2629										$this_epo_container = $( tcAPI.epoSelector + $pid1 + $epo_id1 );
2630									}
2631
2632									if ( ! $element.data( 'tmhaslogicevents' ) || refresh ) {
2633										/* For variation elements we must only add the event once,
2634										* otherwise if the variable product is on a product element
2635										* it will generate multiple events and slow down the site
2636										*/
2637										if ( ! $element.data( 'tmhaslogicevents' ) && $element.is( '.tm-epo-variation-element' ) ) {
2638											// associated product event prefixes are added later
2639											add_variation_event( 'found_variation.tmlogic', false, function() {
2640												run_cpfdependson( $this_epo_container );
2641												jWindow.trigger( 'tm-do-epo-update' );
2642											} );
2643
2644											add_variation_event( 'hide_variation.tmlogic', false, function() {
2645												run_cpfdependson( $this_epo_container );
2646												jWindow.trigger( 'tm-do-epo-update' );
2647											} );
2648										} else {
2649											if ( $element.is( ':text, textarea' ) ) {
2650												_events = 'change.cpflogic input.cpflogic';
2651											}
2652											if ( $element.is( ':input[type="number"]' ) ) {
2653												_events = 'change.cpflogic input.cpflogic keypress.cpflogic';
2654											}
2655
2656											$element.off( _events ).on( _events, function() {
2657												run_cpfdependson( $this_epo_container );
2658											} );
2659										}
2660
2661										$element.data( 'tmhaslogicevents', 1 );
2662									}
2663								}
2664							}
2665						}
2666
2667						matches[ i ]++;
2668					}
2669				}
2670			}
2671
2672			// Loop through all elements and apply visibility toggling
2673			for ( e = 0; e < elements.length; e++ ) {
2674				$this = $( elements[ e ] );
2675				show = toggle === 'hide';
2676
2677				$this.data( {
2678					matches: matches,
2679					toggle: toggle,
2680					fields: fields,
2681					isactive: show
2682				} );
2683
2684				if ( show ) {
2685					$this.removeClass( 'tc-hidden' );
2686				} else {
2687					$this.addClass( 'tc-hidden' );
2688				}
2689			}
2690
2691			elements.addClass( 'iscpfdependson is-epo-depend' ).data( 'iscpfdependson', 1 );
2692			return elements;
2693		};
2694
2695		$.fn.run_cpfdependson = function() {
2696			run_cpfdependson();
2697		};
2698	}
2699
2700	$.tcepo = {
2701		formSubmitEvents: {},
2702
2703		oneOptionIsSelected: {},
2704
2705		initialActivation: {},
2706
2707		// Holds the active precentage of total current price type fields
2708		lateFieldsPrices: {},
2709
2710		errorObject: {},
2711
2712		showHideTotal: {}
2713	};
2714
2715	function validate_logic( l ) {
2716		return typeof l === 'object' && 'toggle' in l && 'rules' in l && l.rules.length > 0;
2717	}
2718
2719	function convert_rules( rules ) {
2720		if ( rules.what ) {
2721			if ( rules.what === 'all' ) {
2722				rules.rules = [ rules.rules ];
2723			} else if ( rules.what === 'any' ) {
2724				rules.rules = rules.rules.reduce( function( accumulator, elrule ) {
2725					accumulator.push( [ elrule ] );
2726					return accumulator;
2727				}, [] );
2728			}
2729			delete rules.what;
2730		}
2731		return rules;
2732	}
2733
2734	function getLogicType( section, element ) {
2735		var type = 'element';
2736		if ( section === 'product-properties' ) {
2737			switch ( String( element ) ) {
2738				case '0':
2739					type = 'quantity';
2740					break;
2741				case '1':
2742					type = 'productid';
2743					break;
2744				case '2':
2745					type = 'variation';
2746					break;
2747				case '3':
2748					type = 'variationattributes';
2749					break;
2750			}
2751		}
2752
2753		return type;
2754	}
2755
2756	// The following loops are required for the logic to work on composite products that have custom variations
2757	function cpf_section_logic( epoObject ) {
2758		var obj = epoObject.this_epo_container;
2759		var root_element = $( obj );
2760		var all_sections = root_element.find( '.cpf-section' ).not( '.cpf-type-product .cpf-section' );
2761		var search_obj;
2762		var cpf_section;
2763		var sect;
2764		var logic;
2765		var haslogic;
2766		var fields;
2767		var section;
2768		var element;
2769		var type;
2770		var obj_section;
2771		var obj_element;
2772		var closestProductElement;
2773		var selector = '[data-haslogic="1"]';
2774
2775		if ( root_element.is( '.cpf-section' ) ) {
2776			search_obj = false;
2777		} else {
2778			search_obj = all_sections;
2779		}
2780
2781		if ( ! epoObject.is_associated ) {
2782			selector = '[data-haslogic="1"]:not(".cpf-type-product .cpf-section")';
2783		}
2784
2785		root_element.toArray().forEach( function( obj_el ) {
2786			if ( $( obj_el ).is( '.cpf-section' ) ) {
2787				cpf_section = $( obj_el );
2788			} else {
2789				cpf_section = $( obj_el ).find( '.cpf-section' );
2790			}
2791
2792			cpf_section.filter( selector ).toArray().forEach( function( el ) {
2793				var irule;
2794				var rule;
2795				var i;
2796				var ii;
2797				sect = $( el );
2798				logic = sect.data( 'logic' );
2799				// backwards compatibility conversion.
2800				logic = convert_rules( logic );
2801				haslogic = parseInt( sect.data( 'haslogic' ), 10 );
2802				fields = [];
2803				closestProductElement = sect.parent().closest( '.cpf-type-product' );
2804
2805				if ( haslogic === 1 && validate_logic( logic ) ) {
2806					for ( i = 0; i < logic.rules.length; i++ ) {
2807						irule = logic.rules[ i ];
2808						if ( ! irule || ! Array.isArray( irule ) ) {
2809							continue;
2810						}
2811						fields[ i ] = [];
2812						for ( ii = 0; ii < irule.length; ii++ ) {
2813							rule = irule[ ii ];
2814							section = rule.section;
2815							element = rule.element;
2816							type = getLogicType( section, element );
2817
2818							if ( type === 'quantity' ) {
2819								if ( closestProductElement.length ) {
2820									obj_element = epoObject.main_cart.find( tcAPI.associateQtySelector );
2821								} else {
2822									obj_element = epoObject.main_cart.find( epoObject.qtySelector );
2823								}
2824							} else if ( type === 'productid' ) {
2825								obj_element = epoObject.product_id;
2826							} else if ( type === 'variation' || type === 'variationattributes' ) {
2827								if ( closestProductElement.length ) {
2828									obj_element = closestProductElement.find( '.tc-epo-element-product-container' );
2829									if ( ! obj_element.length ) {
2830										obj_element = closestProductElement.closest( '.tc-epo-element-product-container' );
2831									}
2832								} else {
2833									obj_element = root_element;
2834								}
2835							} else if ( search_obj ) {
2836								if ( closestProductElement.length ) {
2837									obj_section = root_element.find( '.cpf-section' ).filter( "[data-uniqid='" + section + "']" );
2838									if ( element !== section ) {
2839										obj_element = obj_section.find( '.cpf-element' ).eq( element );
2840									} else {
2841										obj_element = obj_section;
2842									}
2843								} else {
2844									obj_section = search_obj.filter( "[data-uniqid='" + section + "']" );
2845									if ( element !== section ) {
2846										obj_element = obj_section.find( '.cpf-element:not(.cpf-element .cpf-element)' ).eq( element );
2847									} else {
2848										obj_element = obj_section;
2849									}
2850								}
2851							} else if ( element !== section ) {
2852								obj_element = root_element.find( '.cpf-element' ).eq( element );
2853							} else {
2854								obj_section = root_element.find( '.cpf-section' ).filter( "[data-uniqid='" + section + "']" );
2855								obj_element = obj_section;
2856							}
2857
2858							fields[ i ].push( {
2859								element: obj_element,
2860								rule: rule,
2861								type: type
2862							} );
2863						}
2864					}
2865					if ( ! sect.data( 'iscpfdependson' ) ) {
2866						sect.data( 'cpfdependson-fields', fields );
2867						sect.cpfdependson( fields, logic.toggle, false, epoObject );
2868					} else {
2869						sect.cpfdependson( sect.data( 'cpfdependson-fields' ), logic.toggle, true, epoObject );
2870					}
2871				}
2872			} );
2873		} );
2874	}
2875
2876	function cpf_element_logic( epoObject ) {
2877		var obj = epoObject.this_epo_container;
2878		var root_element = $( obj );
2879		var all_sections = root_element.find( '.cpf-section' ).not( '.cpf-type-product .cpf-section' );
2880		var search_obj;
2881		var current_element;
2882		var logic;
2883		var haslogic;
2884		var section;
2885		var element;
2886		var type;
2887		var obj_section;
2888		var obj_element;
2889		var closestProductElement;
2890		var isInProductElement = false;
2891		var selector = '.cpf-element[data-haslogic="1"]';
2892
2893		if ( root_element.parent().is( tcAPI.associatedEpoSelector ) ) {
2894			all_sections = root_element.find( '.cpf-section' );
2895			isInProductElement = true;
2896		}
2897		if ( root_element.is( '.cpf-section' ) ) {
2898			search_obj = false;
2899		} else {
2900			search_obj = all_sections;
2901		}
2902
2903		if ( ! epoObject.is_associated ) {
2904			selector = '.cpf-element[data-haslogic="1"]:not(".cpf-type-product .cpf-element")';
2905		}
2906
2907		root_element.find( selector ).toArray().forEach( function( el ) {
2908			var fields = [];
2909			var irule;
2910			var rule;
2911			var i;
2912			var ii;
2913
2914			current_element = $( el );
2915			logic = current_element.data( 'logic' );
2916			// backwards compatibility conversion.
2917			logic = convert_rules( logic );
2918
2919			haslogic = parseInt( current_element.data( 'haslogic' ), 10 );
2920
2921			if ( isInProductElement ) {
2922				closestProductElement = root_element;
2923			} else {
2924				closestProductElement = current_element.parent().closest( '.cpf-type-product' );
2925			}
2926
2927			if ( haslogic === 1 && validate_logic( logic ) ) {
2928				for ( i = 0; i < logic.rules.length; i++ ) {
2929					irule = logic.rules[ i ];
2930					if ( ! irule || ! Array.isArray( irule ) ) {
2931						continue;
2932					}
2933					fields[ i ] = [];
2934					for ( ii = 0; ii < irule.length; ii++ ) {
2935						rule = irule[ ii ];
2936						section = rule.section;
2937						element = rule.element;
2938						type = getLogicType( section, element );
2939
2940						if ( type === 'quantity' ) {
2941							if ( closestProductElement.length ) {
2942								obj_element = epoObject.main_cart.find( tcAPI.associateQtySelector );
2943							} else {
2944								obj_element = epoObject.main_cart.find( epoObject.qtySelector );
2945							}
2946						} else if ( type === 'productid' ) {
2947							obj_element = epoObject.product_id;
2948						} else if ( type === 'variation' || type === 'variationattributes' ) {
2949							if ( closestProductElement.length ) {
2950								obj_element = closestProductElement.find( '.tc-epo-element-product-container' );
2951								if ( ! obj_element.length ) {
2952									obj_element = closestProductElement.closest( '.tc-epo-element-product-container' );
2953								}
2954							} else {
2955								obj_element = root_element;
2956							}
2957						} else if ( search_obj ) {
2958							if ( closestProductElement.length ) {
2959								obj_section = root_element.find( '.cpf-section' ).filter( "[data-uniqid='" + section + "']" );
2960								if ( element !== section ) {
2961									obj_element = obj_section.find( '.cpf-element' ).eq( element );
2962								} else {
2963									obj_element = obj_section;
2964								}
2965							} else {
2966								obj_section = search_obj.filter( "[data-uniqid='" + section + "']" );
2967								if ( element !== section ) {
2968									obj_element = obj_section.find( '.cpf-element:not(.cpf-element .cpf-element)' ).eq( element );
2969								} else {
2970									obj_element = obj_section;
2971								}
2972							}
2973						} else if ( element !== section ) {
2974							obj_element = root_element.find( '.cpf-element' ).eq( element );
2975						} else {
2976							obj_section = root_element.find( '.cpf-section' ).filter( "[data-uniqid='" + section + "']" );
2977							obj_element = obj_section;
2978						}
2979
2980						fields[ i ].push( {
2981							element: obj_element,
2982							rule: rule,
2983							type: type
2984						} );
2985					}
2986				}
2987
2988				if ( ! current_element.data( 'iscpfdependson' ) ) {
2989					current_element.data( 'cpfdependson-fields', fields );
2990					current_element.cpfdependson( fields, logic.toggle, false, epoObject );
2991				} else {
2992					current_element.cpfdependson( current_element.data( 'cpfdependson-fields' ), logic.toggle, true, epoObject );
2993				}
2994			}
2995		} );
2996	} // End Conditional logic
2997
2998	// Return price value without tax
2999	function tm_set_price_without_tax( value, _cart, force ) {
3000		var taxable;
3001		var tax_rate;
3002		var tax_display_mode;
3003		var prices_include_tax;
3004
3005		if ( _cart ) {
3006			taxable = _cart.attr( 'data-taxable' );
3007			tax_rate = _cart.attr( 'data-tax-rate' );
3008			tax_display_mode = _cart.attr( 'data-tax-display-mode' );
3009			prices_include_tax = _cart.attr( 'data-prices-include-tax' );
3010
3011			if ( force || ( taxable && tax_display_mode === 'incl' && prices_include_tax !== '1' ) ) {
3012				value = parseFloat( value ) / ( 1 + ( tax_rate / 100 ) );
3013			}
3014		}
3015
3016		return value;
3017	}
3018
3019	// Return price with tax
3020	function tm_set_price_with_tax( value, _cart, force ) {
3021		var taxable;
3022		var tax_rate;
3023		var tax_display_mode;
3024		var prices_include_tax;
3025
3026		if ( _cart ) {
3027			taxable = _cart.attr( 'data-taxable' );
3028			tax_rate = _cart.attr( 'data-tax-rate' );
3029			tax_display_mode = _cart.attr( 'data-tax-display-mode' );
3030			prices_include_tax = _cart.attr( 'data-prices-include-tax' );
3031			if ( force || ( taxable && tax_display_mode !== 'incl' && prices_include_tax === '1' ) ) {
3032				value = parseFloat( value ) * ( 1 + ( tax_rate / 100 ) );
3033			}
3034		}
3035
3036		return value;
3037	}
3038
3039	// Return  price
3040	function tm_set_backend_price( value, _cart, variation ) {
3041		var taxable;
3042		var tax_display_mode;
3043		var prices_include_tax;
3044
3045		if ( _cart ) {
3046			taxable = _cart.attr( 'data-taxable' );
3047			tax_display_mode = _cart.attr( 'data-tax-display-mode' );
3048			prices_include_tax = _cart.attr( 'data-prices-include-tax' );
3049			if ( taxable ) {
3050				if ( variation && variation.tc_tax_rate && String( variation.tc_tax_rate ) === '0' ) {
3051					return value;
3052				}
3053				if ( prices_include_tax === '1' ) {
3054					if ( tax_display_mode === 'incl' ) {
3055						// if we are not in the base tax
3056						if ( variation.tc_base_taxes_of_one !== variation.tc_modded_taxes_of_one ) {
3057							value = parseFloat( ( ( 1 - variation.tc_taxes_of_one ) * value ) * ( 1 / ( 1 - variation.tc_base_taxes_of_one ) ) );
3058						}
3059					} else {
3060						value = tm_set_price_with_tax( value, _cart );
3061					}
3062				} else if ( prices_include_tax !== '1' && tax_display_mode === 'incl' ) {
3063					value = tm_set_price_without_tax( value, _cart );
3064				}
3065			}
3066		}
3067
3068		return value;
3069	}
3070
3071	// Return a formatted currency value
3072	function tm_set_price_totals( value, _cart, notax, element ) {
3073		var sign = '';
3074		var val;
3075
3076		if ( ! notax ) {
3077			value = tm_set_tax_price( value, _cart, element, undefined, true );
3078		}
3079		val = Math.abs( value );
3080
3081		if ( value < 0 ) {
3082			sign = TMEPOJS.minus_sign + ' ';
3083		}
3084
3085		return tm_set_price_( val, sign );
3086	}
3087
3088	function replace_suffixes( value, rawValue, tc_totals_ob, totalsHolder ) {
3089		if ( totalsHolder.attr( 'data-tax-display-mode' ) === 'excl' ) {
3090			tc_totals_ob[ value ] = tc_totals_ob[ value ].replaceAll( '{price_excluding_tax}', tm_set_price_totals( tc_totals_ob[ rawValue ], totalsHolder, true ) );
3091			tc_totals_ob[ value ] = tc_totals_ob[ value ].replaceAll( '{price_including_tax}', tm_set_price_totals( tm_set_price_with_tax( tc_totals_ob[ rawValue ], totalsHolder, true ), totalsHolder, true ) );
3092		} else {
3093			tc_totals_ob[ value ] = tc_totals_ob[ value ].replaceAll( '{price_including_tax}', tm_set_price_totals( tc_totals_ob[ rawValue ], totalsHolder, true ) );
3094			tc_totals_ob[ value ] = tc_totals_ob[ value ].replaceAll( '{price_excluding_tax}', tm_set_price_totals( tm_set_price_without_tax( tc_totals_ob[ rawValue ], totalsHolder, true ), totalsHolder, true ) );
3095		}
3096		return tc_totals_ob;
3097	}
3098
3099	function replace_suffixes_in_html( html, price, totalsHolder ) {
3100		if ( totalsHolder.attr( 'data-tax-display-mode' ) === 'excl' ) {
3101			html = html.replaceAll( '{price_excluding_tax}', tm_set_price_totals( price, totalsHolder, true ) );
3102			html = html.replaceAll( '{price_including_tax}', tm_set_price_totals( tm_set_price_with_tax( price, totalsHolder, true ), totalsHolder, true ) );
3103		} else {
3104			html = html.replaceAll( '{price_including_tax}', tm_set_price_totals( price, totalsHolder, true ) );
3105			html = html.replaceAll( '{price_excluding_tax}', tm_set_price_totals( tm_set_price_without_tax( price, totalsHolder, true ), totalsHolder, true ) );
3106		}
3107		return html;
3108	}
3109
3110	function tm_force_update_price( epoObject, obj, price, formatted_price, original_price, useFormattedPrice ) {
3111		tm_update_price( {
3112			epoObject: epoObject,
3113			obj: obj,
3114			price: price,
3115			formatted_price: formatted_price,
3116			original_price: original_price,
3117			force: true,
3118			useFormattedPrice: useFormattedPrice
3119		} );
3120	}
3121
3122	function tm_update_price( priceobj ) {
3123		var $obj;
3124		var w;
3125		var $ba_amount;
3126		var f;
3127		var pw;
3128		var price;
3129		var formatted_price;
3130		var original_price;
3131		var force;
3132		var useFormattedPrice;
3133		var template;
3134		var templatePrice;
3135		var html;
3136		var totalsHolder;
3137		var sign;
3138
3139		$obj = $( priceobj.obj );
3140
3141		if ( $obj.length === 0 ) {
3142			return;
3143		}
3144
3145		w = $obj.closest( '.tmcp-field-wrap' );
3146		pw = $obj.closest( '.tc-price-wrap' );
3147		f = w.find( '.tm-epo-field' );
3148
3149		price = priceobj.price || 0;
3150		formatted_price = priceobj.formatted_price || '';
3151		original_price = priceobj.original_price || '';
3152		force = priceobj.force || false;
3153		useFormattedPrice = priceobj.useFormattedPrice || false;
3154		totalsHolder = priceobj.epoObject.this_epo_totals_container;
3155
3156		if ( ! force && f.attr( 'data-no-price-change' ) === '1' && f.data( 'price-changed' ) ) {
3157			return;
3158		}
3159
3160		price = $.epoAPI.applyFilter( 'tc_adjust_update_price_price', price ); //number
3161		formatted_price = $.epoAPI.applyFilter( 'tc_adjust_update_price_formatted_price', formatted_price, price ); //formatted
3162		original_price = $.epoAPI.applyFilter( 'tc_adjust_update_price_original_price', original_price ); //number
3163
3164		if ( ! Number.isFinite( parseFloat( original_price ) ) ) {
3165			original_price = 0;
3166		}
3167		if ( ! Number.isFinite( parseFloat( price ) ) ) {
3168			price = 0;
3169		}
3170
3171		$ba_amount = w.find( '.before-amount,.after-amount' );
3172
3173		if ( ( TMEPOJS.tm_epo_auto_hide_price_if_zero === 'yes' && ( $.epoAPI.util.isEmpty( price ) === false || ( TMEPOJS.tm_epo_no_hide_price_if_original_not_zero === 'yes' && $.epoAPI.util.isEmpty( price ) === true && $.epoAPI.util.isEmpty( original_price ) === false ) ) ) || TMEPOJS.tm_epo_auto_hide_price_if_zero !== 'yes' ) {
3174			if ( ( $.epoAPI.util.isEmpty( price ) === true && f.attr( 'data-no-price' ) === '1' ) || ( ! force && f.length > 0 && ( f.attr( 'data-no-price' ) === '1' || ( f.attr( 'data-type' ) === 'variable' && ! f.data( 'price' ) ) ) ) ) {
3175				pw.addClass( 'tm-hidden' );
3176				$obj.addClass( 'tm-hidden' );
3177				$obj.empty();
3178				$ba_amount.addClass( 'tm-hidden' );
3179			} else {
3180				if ( original_price && original_price !== undefined && parseFloat( original_price ) !== parseFloat( price ) ) {
3181					if ( useFormattedPrice ) {
3182						template = tcAPI.templateEngine.plain_price;
3183						templatePrice = { price: formatted_price };
3184					} else {
3185						if ( price < 0 && ! original_price < 0 ) {
3186							template = tcAPI.templateEngine.sale_price_m10;
3187							price = Math.abs( price );
3188						} else if ( ! price < 0 && original_price < 0 ) {
3189							template = tcAPI.templateEngine.sale_price_m01;
3190							original_price = Math.abs( original_price );
3191						} else if ( price < 0 && original_price < 0 ) {
3192							template = tcAPI.templateEngine.sale_price_m11;
3193							price = Math.abs( price );
3194							original_price = Math.abs( original_price );
3195						} else {
3196							template = tcAPI.templateEngine.sale_price;
3197						}
3198						templatePrice = { price: formatPrice( original_price ), sale_price: formatPrice( price ) };
3199					}
3200				} else if ( useFormattedPrice ) {
3201					template = tcAPI.templateEngine.plain_price;
3202					templatePrice = { price: formatted_price };
3203				} else {
3204					template = tcAPI.templateEngine.price;
3205					if ( price < 0 ) {
3206						template = tcAPI.templateEngine.price_m;
3207						price = Math.abs( price );
3208					}
3209					templatePrice = { price: formatPrice( price ) };
3210				}
3211				html = $.epoAPI.util.decodeHTML( $.epoAPI.template.html( template, templatePrice ) );
3212				html = replace_suffixes_in_html( html, price, totalsHolder );
3213				html = $.epoAPI.applyFilter( 'tc_adjust_update_price_formatted_price_html', html );
3214				sign = '';
3215				if ( ! useFormattedPrice && price > 0 && TMEPOJS.tm_epo_global_options_price_sign !== 'minus' ) {
3216					sign = TMEPOJS.option_plus_sign + ' ';
3217				}
3218				$obj.html( sign + html );
3219				pw.removeClass( 'tm-hidden' );
3220				$obj.removeClass( 'tm-hidden' );
3221				$ba_amount.removeClass( 'tm-hidden' );
3222			}
3223		} else {
3224			pw.addClass( 'tm-hidden' );
3225			$obj.addClass( 'tm-hidden' );
3226			$obj.empty();
3227			$ba_amount.addClass( 'tm-hidden' );
3228		}
3229	}
3230
3231	function get_variation_current_settings( form, epoObject ) {
3232		var current_settings = {};
3233
3234		if ( epoObject.thisForm ) {
3235			form = epoObject.thisForm;
3236		}
3237
3238		form.find( '.variations select, .tc-epo-variable-product-selector' ).toArray().forEac
3238h( function( el ) {
3239			var attribute_name;
3240			var value;
3241			el = $( el );
3242
3243			// Get attribute name from data-attribute_name, or from input name
3244			// if it doesn't exist
3245			if ( typeof el.data( 'attribute_name' ) !== 'undefined' ) {
3246				attribute_name = el.data( 'attribute_name' );
3247			} else {
3248				attribute_name = el.attr( 'name' );
3249			}
3250
3251			// Encode entities
3252			value = el.val();
3253
3254			// Add to settings array
3255			current_settings[ attribute_name ] = value;
3256		} );
3257
3258		return current_settings;
3259	}
3260
3261	function do_tm_custom_variations_update( form, all_variations, epoObject ) {
3262		var check_if_all_are_not_set = [];
3263		var formSettings = get_variation_current_settings( form, epoObject );
3264		var redo_check = true;
3265		var variationId = form.find( getVariationIdSelector( form ) ).val();
3266		var ii;
3267
3268		variationId = ( variationId !== '0' && variationId !== '' ) || form.find( '.cpf-type-variations' ).find( '.tm-epo-variation-element:checked' ).length > 0 || form.find( '.cpf-type-variations' ).find( '.tm-epo-variation-element option[value!=""]:selected' );
3269
3270		if ( ! variationId ) {
3271			return;
3272		}
3273		form.find( '.cpf-type-variations' ).toArray().forEach( function( el, i ) {
3274			var t = $( el ).find( '.tm-epo-variation-element' );
3275			var id;
3276			var v;
3277			var exists = false;
3278
3279			check_if_all_are_not_set[ i ] = true;
3280
3281			if ( t.is( 'select' ) ) {
3282				id = $.epoAPI.dom.id( t.attr( 'data-tm-for-variation' ) );
3283				v = t.val();
3284				if ( v ) {
3285					check_if_all_are_not_set[ i ] = false;
3286				}
3287				t.children( 'option' ).toArray().forEach( function( o ) {
3288					exists = false;
3289					form.find( "[data-attribute_name='attribute_" + id + "']" )
3290						.children( 'option' )
3291						.toArray().forEach( function( att ) {
3292							if ( $( att ).attr( 'value' ) === $( o ).attr( 'value' ) ) {
3293								exists = true;
3294								return false;
3295							}
3296						} );
3297					if ( ! exists ) {
3298						$( o ).prop( 'disabled', true ).hide();
3299					} else {
3300						$( o ).prop( 'disabled', false ).show();
3301					}
3302				} );
3303			} else {
3304				t.toArray().forEach( function( oe ) {
3305					var o = $( oe );
3306					var li = o.closest( 'li' );
3307					var input = li.find( '.tm-epo-variation-element' );
3308					var this_settings = $.extend( true, {}, formSettings );
3309					var matching_variations;
3310					var variation;
3311					var is_in_stock;
3312
3313					id = o.attr( 'data-tm-for-variation' );
3314					v = o.val();
3315					if ( o.is( ':checked' ) ) {
3316						check_if_all_are_not_set[ i ] = false;
3317					}
3318
3319					this_settings[ 'attribute_' + id ] = v;
3320
3321					matching_variations = $.fn.tm_find_matching_variations( all_variations, this_settings );
3322					variation = matching_variations.shift();
3323
3324					is_in_stock = variation && 'is_in_stock' in variation && variation.is_in_stock;
3325
3326					if ( ! is_in_stock ) {
3327						if ( ! input.is( ':checked' ) && ! is_in_stock ) {
3328							li.addClass( 'pointereventsoff' );
3329						} else {
3330							li.removeClass( 'pointereventsoff' );
3331						}
3332
3333						o.attr( 'disabled', 'disabled' ).addClass( 'tm-disabled' );
3334
3335						input.attr( 'disabled', 'disabled' );
3336						input.attr( 'data-tm-disabled', 'disabled' );
3337
3338						li.addClass( 'tm-attribute-disabled' ).fadeTo( 'fast', 0.5 );
3339					} else {
3340						o.prop( 'disabled', false ).removeClass( 'tm-disabled' );
3341						li.removeClass( 'pointereventsoff tm-attribute-disabled' ).fadeTo( 'fast', 1, function() {
3342							$( this ).css( 'opacity', '' );
3343						} );
3344						input.prop( 'disabled', false );
3345						input.removeAttr( 'data-tm-disabled' );
3346					}
3347				} );
3348			}
3349		} );
3350
3351		if ( check_if_all_are_not_set ) {
3352			check_if_all_are_not_set.shift();
3353
3354			for ( ii = 0; ii < check_if_all_are_not_set.length; ii++ ) {
3355				if ( check_if_all_are_not_set[ ii ] === false ) {
3356					redo_check = false;
3357					break;
3358				}
3359			}
3360
3361			if ( redo_check ) {
3362				form.find( '.cpf-type-variations' )
3363					.first()
3364					.toArray().forEach( function( el ) {
3365						var t;
3366						var li;
3367						var input;
3368
3369						t = $( el ).find( '.tm-epo-variation-element' );
3370
3371						if ( ! t.is( 'select' ) ) {
3372							t.toArray().forEach( function( o ) {
3373								o = $( o );
3374								li = o.closest( 'li' );
3375								input = li.find( '.tm-epo-variation-element' );
3376								o.prop( 'disabled', false ).removeClass( 'tm-disabled' );
3377								li.removeClass( 'tm-attribute-disabled' ).stop().css( 'opacity', '' );
3378								input.prop( 'disabled', false );
3379								input.removeAttr( 'data-tm-disabled' );
3380							} );
3381						}
3382					} );
3383			}
3384		}
3385	}
3386
3387	function tm_custom_variations_update( form, epoObject ) {
3388		var data;
3389		var all_variations = form.data( 'product_variations' );
3390		var product_id = parseInt( form.data( 'product_id' ), 10 );
3391		var globalVariationObject = form.data( 'globalVariationObject' ) || false;
3392
3393		if ( TMEPOJS.skipCustomVariationsUpdate ) {
3394			return;
3395		}
3396
3397		if ( ! product_id ) {
3398			product_id = form.data( 'tc_product_id' );
3399		}
3400
3401		if ( ! product_id && form.is( tcAPI.compositeSelector ) ) {
3402			data = form.find( '.component_options' ).data( 'options_data' );
3403			product_id = data[ 0 ].option_id;
3404			if ( ! all_variations ) {
3405				all_variations = form.find( '.details.component_data' ).data( 'product_variations' );
3406			}
3407		}
3408
3409		if ( ! epoObject.is_associated ) {
3410			// Fallback to window property if not set - backwards compat
3411			if ( ! all_variations && window.product_variations && window.product_variations.product_id ) {
3412				all_variations = window.product_variations.product_id;
3413			}
3414			if ( ! all_variations && window.product_variations ) {
3415				all_variations = window.product_variations;
3416			}
3417			if ( ! all_variations && window[ 'product_variations_' + product_id ] ) {
3418				all_variations = window[ 'product_variations_' + product_id ];
3419			}
3420		}
3421
3422		if ( ! all_variations ) {
3423			if ( ! globalVariationObject ) {
3424				data = {
3425					action: 'woocommerce_tm_get_variations_array',
3426					post_id: product_id
3427				};
3428				$.post(
3429					TMEPOJS.ajax_url,
3430					data,
3431					function( response ) {
3432						globalVariationObject = response;
3433						form.data( 'globalVariationObject', response );
3434						do_tm_custom_variations_update( form, globalVariationObject.variations, epoObject );
3435					},
3436					'json'
3437				);
3438			} else {
3439				do_tm_custom_variations_update( form, globalVariationObject.variations, epoObject );
3440			}
3441
3442			return;
3443		}
3444		// may need 2.4 check for woocommerce_ajax_variation_threshold
3445		do_tm_custom_variations_update( form, all_variations, epoObject );
3446	}
3447
3448	function tm_fix_stock( cart, html ) {
3449		var custom_variations;
3450		var section;
3451
3452		if ( html === undefined ) {
3453			return false;
3454		}
3455		cart = $( cart );
3456		custom_variations = cart.find( '.tm-epo-variation-element' ).first();
3457		section = custom_variations.closest( '.tm-epo-variation-section' );
3458
3459		if ( custom_variations.length ) {
3460			section.find( '.tm-stock' ).remove();
3461			section.append( '<div class="tm-stock">' + html + '</div>' );
3462			return true;
3463		}
3464		cart.find( '.tm-stock' ).remove();
3465		cart.find( '.variations' ).after( '<div class="tm-stock">' + html + '</div>' );
3466		return true;
3467	}
3468
3469	function fix_stock( $this, form ) {
3470		var stock;
3471
3472		if ( TMEPOJS.tm_epo_global_move_out_of_stock === 'no' ) {
3473			return;
3474		}
3475		stock = $this.find( '.woocommerce-variation-availability' ).last();
3476		if ( ! stock.length ) {
3477			stock = $this.find( '.stock' ).last();
3478		}
3479
3480		if ( stock.length ) {
3481			form.find( '.tm-stock' ).remove();
3482			if ( tm_fix_stock( form, stock.prop( 'outerHTML' ) ) ) {
3483				stock.remove();
3484			}
3485		} else {
3486			form.find( '.tm-stock' ).remove();
3487		}
3488	}
3489
3490	function get_main_input_id( main_product, product, id ) {
3491		var selector = '';
3492		var inputid;
3493
3494		if ( id ) {
3495			selector = selector + "[value='" + id + "']";
3496		}
3497		if ( ! product ) {
3498			product = main_product;
3499		}
3500		inputid = product.find( tcAPI.addToCartSelector + selector );
3501		if ( inputid.length === 0 ) {
3502			inputid = product.find( tcAPI.tcAddToCartSelector + selector );
3503		}
3504		return inputid.last();
3505	}
3506
3507	function get_main_form( main_product, product, selector, id ) {
3508		if ( ! selector ) {
3509			selector = 'form';
3510		}
3511		return get_main_input_id( main_product, product, id ).closest( selector );
3512	}
3513
3514	function get_main_cart( main_product, product, selector, id ) {
3515		return get_main_form( main_product, product, selector, id );
3516	}
3517
3518	function tm_get_native_prices_block( obj ) {
3519		var selector = $.epoAPI.applyFilter( 'tcGetNativePricesBlockSelector', '.single_variation .price', obj );
3520
3521		return $( obj ).find( selector ).not( '.tc-price' );
3522	}
3523
3524	// URL replacement setup
3525	function tm_set_url_fields() {
3526		jDocument.on( 'click.cpfurl change.cpfurl tmredirect', '.tc-url-container .tmcp-radio, .tc-url-container .tmcp-radio+label', function( e ) {
3527			var data_url = $( this ).attr( 'data-url' );
3528			if ( data_url ) {
3529				if ( window.location !== data_url ) {
3530					e.preventDefault();
3531					window.location = data_url;
3532				}
3533			}
3534		} );
3535		jDocument.on( 'change.cpfurl tmredirect', '.tc-url-container .tmcp-select', function( e ) {
3536			var data_url = $( this ).children( 'option:selected' ).attr( 'data-url' );
3537			if ( data_url ) {
3538				if ( window.location !== data_url ) {
3539					e.preventDefault();
3540					window.location = data_url;
3541				}
3542			}
3543		} );
3544	}
3545
3546	function tm_floating_totals( this_epo_totals_container, is_quickview, main_cart ) {
3547		$.tcFloatingTotalsBox( this_epo_totals_container, is_quickview, main_cart );
3548	}
3549
3550	function tm_show_hide_add_to_cart_button( main_product, currentEpoObject ) {
3551		var button;
3552		var qty;
3553		var showHideCart = currentEpoObject.showHideCart;
3554
3555		if ( ! currentEpoObject.is_associated && showHideCart !== undefined ) {
3556			if ( TMEPOJS.tm_epo_hide_add_cart_button === 'yes' || TMEPOJS.tm_epo_hide_all_add_cart_button === 'yes' || TMEPOJS.tm_epo_hide_required_add_cart_button === 'yes' ) {
3557				button = main_product.find( tcAPI.addToCartButtonSelector ).first();
3558				qty = main_product.find( tcAPI.qtySelector ).first();
3559
3560				if ( showHideCart ) {
3561					button.removeClass( 'tc-hide-add-to-cart-button' );
3562					qty.removeClass( 'tc-hide-add-to-cart-button' );
3563				} else {
3564					button.addClass( 'tc-hide-add-to-cart-button' );
3565					qty.addClass( 'tc-hide-add-to-cart-button' );
3566				}
3567
3568				jWindow.trigger( 'epoShowHideCart', {
3569					main_product: main_product,
3570					currentEpoObject: currentEpoObject,
3571					showHideCart: showHideCart,
3572					button: button,
3573					qty: qty
3574				} );
3575			}
3576		}
3577	}
3578
3579	function addShowHidetoEpoObject( currentEpoObject, epoEventId, epoObject ) {
3580		var has_epo;
3581		var this_epo_container;
3582		var epos;
3583		var allElementsAreSelected;
3584		var showHideCart = true;
3585		var showHideTotal = true;
3586		var one_option_is_selected = $.tcepo.oneOptionIsSelected[ epoEventId ];
3587
3588		if ( currentEpoObject.is_associated ) {
3589			currentEpoObject = $.epoAPI.applyFilter( 'tc_currentEpoObject_associated', currentEpoObject, epoEventId, epoObject );
3590			return currentEpoObject;
3591		}
3592
3593		if ( typeof epoObject === 'object' ) {
3594			has_epo = epoObject.has_epo;
3595			this_epo_container = epoObject.this_epo_container;
3596			has_epo = has_epo && ( this_epo_container.find( '.tmcp-fee-field' ).length || this_epo_container.find( '.tmcp-field' ).not( '.cpf-type-variations .tmcp-field' ).length );
3597		} else {
3598			has_epo = epoObject;
3599		}
3600
3601		currentEpoObject.showHideCart = undefined;
3602		currentEpoObject.showHideTotal = undefined;
3603
3604		if ( has_epo && ( TMEPOJS.tm_epo_hide_add_cart_button === 'yes' || TMEPOJS.tm_epo_hide_all_add_cart_button === 'yes' || TMEPOJS.tm_epo_hide_required_add_cart_button === 'yes' || TMEPOJS.tm_epo_hide_totals_until_any === 'yes' || TMEPOJS.tm_epo_hide_totals_until_all_required === 'yes' || TMEPOJS.tm_epo_hide_totals_until_all === 'yes' ) ) {
3605			// Hide cart button until an element is chosen
3606			if ( TMEPOJS.tm_epo_hide_add_cart_button === 'yes' ) {
3607				showHideCart = one_option_is_selected;
3608			}
3609
3610			// Hide Final total box until an element is chosen
3611			if ( TMEPOJS.tm_epo_hide_totals_until_any === 'yes' ) {
3612				showHideTotal = one_option_is_selected;
3613			}
3614
3615			// Hide until all required elements are chosen
3616			if ( TMEPOJS.tm_epo_hide_required_add_cart_button === 'yes' || TMEPOJS.tm_epo_hide_totals_until_all_required === 'yes' ) {
3617				epos = currentEpoObject.this_epo_container.find( '.cpf-element' ).not( '.cpf-type-variations' ).filter( '.tc-container-enabled.tc-is-required' );
3618				allElementsAreSelected = checkFullSelection( epos );
3619				if ( TMEPOJS.tm_epo_hide_required_add_cart_button === 'yes' ) {
3620					showHideCart = allElementsAreSelected;
3621				}
3622				if ( TMEPOJS.tm_epo_hide_totals_until_all_required === 'yes' ) {
3623					showHideTotal = allElementsAreSelected;
3624				}
3625			}
3626
3627			// Hide until all elements are chosen
3628			if ( TMEPOJS.tm_epo_hide_all_add_cart_button === 'yes' || TMEPOJS.tm_epo_hide_totals_until_all === 'yes' ) {
3629				epos = currentEpoObject.this_epo_container.find( '.cpf-element' ).not( '.cpf-type-variations' ).filter( '.tc-container-enabled' );
3630				allElementsAreSelected = checkFullSelection( epos );
3631				if ( TMEPOJS.tm_epo_hide_all_add_cart_button === 'yes' ) {
3632					showHideCart = allElementsAreSelected;
3633				}
3634				if ( TMEPOJS.tm_epo_hide_totals_until_all === 'yes' ) {
3635					showHideTotal = allElementsAreSelected;
3636				}
3637			}
3638
3639			currentEpoObject.showHideCart = showHideCart;
3640			currentEpoObject.showHideTotal = showHideTotal;
3641			$.tcepo.showHideTotal[ epoEventId ] = showHideTotal;
3642		}
3643
3644		currentEpoObject = $.epoAPI.applyFilter( 'tc_currentEpoObject', currentEpoObject, epoEventId, epoObject );
3645
3646		return currentEpoObject;
3647	}
3648
3649	function checkFullSelection( epos, mode ) {
3650		var funcCallback = function( element ) {
3651			var elementToCheck = '';
3652			var _class;
3653			var noSplit = false;
3654			var radio_checked;
3655			var checkbox_checked;
3656			var val;
3657
3658			element = $( element );
3659			if ( element.is( '.cpf-type-product' ) ) {
3660				elementToCheck = ':not(' + tcAPI.associatedEpoSelector + ' .tm-epo-field)';
3661			}
3662			_class = element
3663				.attr( 'class' )
3664				.split( ' ' )
3665				.map( function( cls ) {
3666					if ( cls.indexOf( 'cpf-type-', 0 ) !== -1 ) {
3667						return cls;
3668					}
3669					return null;
3670				} )
3671				.filter( function( v ) {
3672					if ( v !== null && v !== undefined ) {
3673						return v;
3674					}
3675					return null;
3676				} );
3677
3678			if ( _class.length > 0 ) {
3679				_class = _class[ 0 ];
3680				if ( _class === 'cpf-type-product' ) {
3681					noSplit = true;
3682					if ( element.is( '.cpf-type-product-mode-product' ) || element.is( '.cpf-type-product-checkbox' ) || element.is( '.cpf-type-product-thumbnailmultiple' ) || element.is( '.cpf-type-product-custombundle' ) ) {
3683						_class = 'cpf-type-checkbox';
3684					} else if ( element.is( '.cpf-type-product-dropdown' ) ) {
3685						_class = 'cpf-type-select';
3686					} else {
3687						_class = 'cpf-type-radio';
3688					}
3689				}
3690				switch ( _class ) {
3691					case 'cpf-type-radio':
3692						radio_checked = element.find( 'input.tm-epo-field.tmcp-radio:checked' + elementToCheck );
3693						return radio_checked.length > 0;
3694
3695					case 'cpf-type-checkbox':
3696						checkbox_checked = element.find( 'input.tm-epo-field.tmcp-checkbox:checked' + elementToCheck );
3697						return checkbox_checked.length > 0;
3698
3699					case 'cpf-type-select':
3700						val = element.find( 'select.tm-epo-field.tmcp-select' + elementToCheck ).val();
3701						if ( val && ! noSplit ) {
3702							val = val.slice( 0, val.lastIndexOf( '_' ) );
3703						}
3704						break;
3705
3706					case 'cpf-type-selectmultiple':
3707						val = element.find( 'select.tm-epo-field.tmcp-selectmultiple' + elementToCheck ).val();
3708						if ( val && ! noSplit ) {
3709							val.forEach( function( option, i ) {
3710								val[ i ] = option.slice( 0, option.lastIndexOf( '_' ) );
3711							} );
3712						}
3713						break;
3714
3715					default:
3716						val = element.find( '.tm-epo-field' + elementToCheck ).val();
3717						break;
3718				}
3719				if ( Array.isArray( val ) ) {
3720					return val.some( function( item ) {
3721						return item !== '';
3722					} );
3723				}
3724				return val !== '';
3725			}
3726			return false;
3727		};
3728		if ( mode === 'some' ) {
3729			return epos.toArray().some( funcCallback );
3730		}
3731		return epos.toArray().every( funcCallback );
3732	}
3733
3734	function goto_error_item( item, epoEventId ) {
3735		var el = $.tcepo.errorObject[ epoEventId ] || item;
3736		var elsection;
3737		var elsectionlink;
3738		var cpfElement;
3739		var productSection;
3740		var pos;
3741
3742		if ( el ) {
3743			if ( TMEPOJS.tm_epo_disable_error_scroll !== 'yes' ) {
3744				elsection = el.closest( '.cpf-section' );
3745				elsectionlink = elsection.find( '.tm-section-link' );
3746				cpfElement = el.closest( '.cpf-element' );
3747				productSection = el.closest( '.cpf-type-product' ).closest( '.cpf-section' );
3748
3749				if ( productSection.length && productSection.find( '.tm-toggle' ).length ) {
3750					productSection.find( '.tm-toggle' ).trigger( 'openwrap.tmtoggle' );
3751				}
3752
3753				if ( elsection.find( '.tm-toggle' ).length ) {
3754					elsection.find( '.tm-toggle' ).trigger( 'openwrap.tmtoggle' );
3755				}
3756				if ( window.tc_validation_offset === undefined ) {
3757					window.tc_validation_offset = -100;
3758				}
3759				if ( elsection.is( '.section_popup' ) ) {
3760					errorContainer.tcScrollTo( elsectionlink, 300, window.tc_validation_offset );
3761					elsectionlink.trigger( 'click.tmsectionpoplink' );
3762				} else if ( elsection.is( '.tm-owl-slider-section' ) ) {
3763					pos = el.closest( '.owl-item' ).index();
3764					elsection.find( '.tcowl-carousel' ).trigger( 'to.owl.carousel', [ pos, 100 ] );
3765					setTimeout( function() {
3766						elsection.find( '.tcowl-carousel' ).trigger( 'refresh.owl.carousel' );
3767
3768						if ( cpfElement.length > 0 ) {
3769							errorContainer.tcScrollTo( cpfElement, 300, window.tc_validation_offset );
3770						}
3771					}, 200 );
3772				} else if ( elsection.is( '.tc-tabs-section' ) ) {
3773					pos = el.closest( '.tc-tab-slide' ).index();
3774					el.closest( '.tc-tabs' ).find( '.tc-tab-headers .tc-tab-header .tab-header[data-id="tc-tab-slide' + pos + '"]' ).trigger( 'click.tmtabs' );
3775					setTimeout( function() {
3776						if ( cpfElement.length > 0 ) {
3777							errorContainer.tcScrollTo( cpfElement, 300, window.tc_validation_offset );
3778						}
3779					}, 200 );
3780				} else if ( cpfElement.length > 0 ) {
3781					errorContainer.tcScrollTo( cpfElement, 300, window.tc_validation_offset );
3782				}
3783			}
3784
3785			if ( ! item ) {
3786				$.tcepo.errorObject[ epoEventId ] = false;
3787			}
3788		}
3789	}
3790
3791	function tm_limit_c_selection( field, prevent ) {
3792		var allowed = parseInt( field.attr( 'data-limit' ), 10 );
3793		var checked = false;
3794		var val;
3795		var q;
3796
3797		if ( allowed > 0 ) {
3798			checked = 0;
3799			field
3800				.closest( '.tm-extra-product-options-checkbox' )
3801				.find( "input.tm-epo-field[type='checkbox']:checked" )
3802				.toArray().forEach( function( cb ) {
3803					cb = $( cb );
3804					q = cb.closest( 'li.tmcp-field-wrap' ).find( 'input.tm-qty' );
3805					if ( q.length > 0 ) {
3806						val = parseInt( q.val(), 10 );
3807						if ( val <= 0 ) {
3808							val = 1;
3809						}
3810						checked = parseInt( checked, 10 ) + val;
3811					} else {
3812						checked = parseInt( checked, 10 ) + 1;
3813					}
3814				} );
3815			if ( checked > allowed ) {
3816				if ( prevent ) {
3817					field.prop( 'checked', '' ).trigger( 'change' );
3818				}
3819				return false;
3820			}
3821		}
3822		return true;
3823	}
3824
3825	function tm_exact_c_selection( field, prevent ) {
3826		var allowed = parseInt( field.attr( 'data-exactlimit' ), 10 );
3827		var checked = false;
3828		var val;
3829		var q;
3830
3831		if ( allowed > 0 ) {
3832			checked = 0;
3833			field
3834				.closest( '.tm-extra-product-options-checkbox' )
3835				.find( "input.tm-epo-field[type='checkbox']:checked" )
3836				.toArray().forEach( function( cb ) {
3837					cb = $( cb );
3838					q = cb.closest( 'li.tmcp-field-wrap' ).find( 'input.tm-qty' );
3839					if ( q.length > 0 ) {
3840						val = parseInt( q.val(), 10 );
3841						if ( val <= 0 ) {
3842							val = 1;
3843						}
3844						checked = parseInt( checked, 10 ) + val;
3845					} else {
3846						checked = parseInt( checked, 10 ) + 1;
3847					}
3848				} );
3849			if ( checked > allowed ) {
3850				if ( prevent ) {
3851					field.prop( 'checked', '' ).trigger( 'change' );
3852				}
3853				return false;
3854			}
3855		}
3856		return true;
3857	}
3858
3859	function tm_limit_cont( fields, main_product, epoEventId ) {
3860		var checkall = true;
3861		var first_error_obj = false;
3862		var limit;
3863		var eln;
3864		var checked;
3865		var val;
3866		var q;
3867		var ew;
3868		var em;
3869		var message;
3870
3871		fields.toArray().forEach( function( field ) {
3872			field = $( field );
3873			limit = field.find( "[type='checkbox'][data-limit]" );
3874			if ( limit.length && field_is_active( limit ) ) {
3875				eln = parseInt( limit.attr( 'data-limit' ), 10 );
3876				checked = 0;
3877				field.find( "input.tm-epo-field[type='checkbox']:checked" ).toArray().forEach( function( cb ) {
3878					cb = $( cb );
3879					q = cb.closest( 'li.tmcp-field-wrap' ).find( 'input.tm-qty' );
3880					if ( q.length > 0 ) {
3881						val = parseInt( q.val(), 10 );
3882						if ( val <= 0 ) {
3883							val = 1;
3884						}
3885						checked = parseInt( checked, 10 ) + val;
3886					} else {
3887						checked = parseInt( checked, 10 ) + 1;
3888					}
3889				} );
3890				ew = field.closest( '.cpf-element' );
3891				em = ew.find( 'div.tm-error-min' );
3892
3893				if ( eln < checked ) {
3894					checkall = false;
3895					first_error_obj = field;
3896					if ( eln === 1 ) {
3897						message = TMEPOJS.tm_epo_global_validator_messages.epolimitsingle.replaceAll( '{0}', eln );
3898					} else {
3899						message = TMEPOJS.tm_epo_global_validator_messages.epolimit.replaceAll( '{0}', eln );
3900					}
3901					if ( em.length ) {
3902						em.remove();
3903					}
3904					if ( TMEPOJS.tm_epo_global_error_label_placement === 'before' ) {
3905						field.closest( '.tc-element-container' ).before( '<div class="tm-error-min tm-error tc-cell tcwidth tcwidth-100">' + message + '</div>' );
3906					} else {
3907						field.closest( '.tc-element-container' ).after( '<div class="tm-error-min tm-error tc-cell tcwidth tcwidth-100">' + message + '</div>' );
3908					}
3909					main_product.find( tcAPI.addToCartButtonSelector ).first().removeClass( 'disabled loading fpd-disabled' ).prop( 'disabled', false );
3910				} else {
3911					em.remove();
3912				}
3913			}
3914		} );
3915		if ( first_error_obj ) {
3916			$.tcepo.errorObject[ epoEventId ] = first_error_obj;
3917		}
3918		return checkall;
3919	}
3920
3921	function tm_check_limit_cont( limit_cont, main_product, epoEventId ) {
3922		$.tcepo.formSubmitEvents[ epoEventId ][ $.tcepo.formSubmitEvents[ epoEventId ].length ] = {
3923			trigger: function() {
3924				return tm_limit_cont( limit_cont, main_product, epoEventId );
3925			},
3926			on_true: function() {
3927				return true;
3928			},
3929			on_false: function() {
3930				goto_error_item( $( limit_cont ).find( '.tm-epo-field' ).first(), epoEventId );
3931				return true;
3932			}
3933		};
3934	}
3935
3936	function tm_exactlimit_cont( fields, main_product, epoEventId ) {
3937		var checkall = true;
3938		var first_error_obj = false;
3939		var exactlimit;
3940		var eln;
3941		var checked;
3942		var val;
3943		var q;
3944		var ew;
3945		var em;
3946		var message;
3947
3948		fields.toArray().forEach( function( field ) {
3949			field = $( field );
3950			exactlimit = field.find( "[type='checkbox'][data-exactlimit]" );
3951			if ( exactlimit.length && field_is_active( exactlimit ) ) {
3952				eln = parseInt( exactlimit.attr( 'data-exactlimit' ), 10 );
3953				checked = 0;
3954				field.find( "input.tm-epo-field[type='checkbox']:checked" ).toArray().forEach( function( cb ) {
3955					cb = $( cb );
3956					q = cb.closest( 'li.tmcp-field-wrap' ).find( 'input.tm-qty' );
3957					if ( q.length > 0 ) {
3958						val = parseInt( q.val(), 10 );
3959						if ( val <= 0 ) {
3960							val = 1;
3961						}
3962						checked = parseInt( checked, 10 ) + val;
3963					} else {
3964						checked = parseInt( checked, 10 ) + 1;
3965					}
3966				} );
3967				ew = field.closest( '.cpf-element' );
3968				em = ew.find( 'div.tm-error-min' );
3969
3970				if ( eln !== checked ) {
3971					checkall = false;
3972					first_error_obj = field;
3973					if ( eln === 1 ) {
3974						message = TMEPOJS.tm_epo_global_validator_messages.epoexactsingle.replaceAll( '{0}', eln );
3975					} else {
3976						message = TMEPOJS.tm_epo_global_validator_messages.epoexact.replaceAll( '{0}', eln );
3977					}
3978					if ( em.length ) {
3979						em.remove();
3980					}
3981					if ( TMEPOJS.tm_epo_global_error_label_placement === 'before' ) {
3982						field.closest( '.tc-element-container' ).before( '<div class="tm-error-min tm-error tc-cell tcwidth tcwidth-100">' + message + '</div>' );
3983					} else {
3984						field.closest( '.tc-element-container' ).after( '<div class="tm-error-min tm-error tc-cell tcwidth tcwidth-100">' + message + '</div>' );
3985					}
3986					main_product.find( tcAPI.addToCartButtonSelector ).first().removeClass( 'disabled loading fpd-disabled' ).prop( 'disabled', false );
3987				} else {
3988					em.remove();
3989				}
3990			}
3991		} );
3992		if ( first_error_obj ) {
3993			$.tcepo.errorObject[ epoEventId ] = first_error_obj;
3994		}
3995		return checkall;
3996	}
3997
3998	function tm_check_exactlimit_cont( exactlimit_cont, main_product, epoEventId ) {
3999		$.tcepo.formSubmitEvents[ epoEventId ][ $.tcepo.formSubmitEvents[ epoEventId ].length ] = {
4000			trigger: function() {
4001				return tm_exactlimit_cont( exactlimit_cont, main_product, epoEventId );
4002			},
4003			on_true: function() {
4004				return true;
4005			},
4006			on_false: function() {
4007				goto_error_item( $( exactlimit_cont ).find( '.tm-epo-field' ).first(), epoEventId );
4008				return true;
4009			}
4010		};
4011	}
4012
4013	function tm_minimumlimit_cont( fields, epoEventId ) {
4014		var checkall = true;
4015		var first_error_obj = false;
4016		var eln;
4017		var checked;
4018		var val;
4019		var q;
4020		var ew;
4021		var em;
4022		var message;
4023
4024		fields.toArray().forEach( function( field ) {
4025			var minimumlimit;
4026
4027			field = $( field );
4028			minimumlimit = field.find( "[type='checkbox'][data-minimumlimit]" );
4029
4030			if ( minimumlimit.length && field_is_active( minimumlimit ) ) {
4031				eln = parseInt( minimumlimit.attr( 'data-minimumlimit' ), 10 );
4032				checked = 0;
4033				field.find( "input.tm-epo-field[type='checkbox']:checked" ).toArray().forEach( function( cb ) {
4034					cb = $( cb );
4035					q = cb.closest( 'li.tmcp-field-wrap' ).find( 'input.tm-qty' );
4036					if ( q.length > 0 ) {
4037						val = parseInt( q.val(), 10 );
4038						if ( val <= 0 ) {
4039							val = 1;
4040						}
4041						checked = parseInt( checked, 10 ) + val;
4042					} else {
4043						checked = parseInt( checked, 10 ) + 1;
4044					}
4045				} );
4046				ew = field.closest( '.cpf-element' );
4047				em = ew.find( 'div.tm-error-min' );
4048				if ( eln > checked ) {
4049					checkall = false;
4050					first_error_obj = field;
4051					if ( eln === 1 ) {
4052						message = TMEPOJS.tm_epo_global_validator_messages.epominsingle.replaceAll( '{0}', eln );
4053					} else {
4054						message = TMEPOJS.tm_epo_global_validator_messages.epomin.replaceAll( '{0}', eln );
4055					}
4056					if ( em.length ) {
4057						em.remove();
4058					}
4059					if ( TMEPOJS.tm_epo_global_error_label_placement === 'before' ) {
4060						field.closest( '.tc-element-container' ).before( '<div class="tm-error-min tm-error tc-cell tcwidth tcwidth-100">' + message + '</div>' );
4061					} else {
4062						field.closest( '.tc-element-container' ).after( '<div class="tm-error-min tm-error tc-cell tcwidth tcwidth-100">' + message + '</div>' );
4063					}
4064				} else {
4065					em.remove();
4066				}
4067			}
4068		} );
4069
4070		if ( first_error_obj ) {
4071			$.tcepo.errorObject[ epoEventId ] = first_error_obj;
4072		}
4073
4074		return checkall;
4075	}
4076
4077	function tm_check_minimumlimit_cont( minimumlimit_cont, epoEventId ) {
4078		$.tcepo.formSubmitEvents[ epoEventId ][ $.tcepo.formSubmitEvents[ epoEventId ].length ] = {
4079			trigger: function() {
4080				return tm_minimumlimit_cont( minimumlimit_cont, epoEventId );
4081			},
4082			on_true: function() {
4083				return true;
4084			},
4085			on_false: function() {
4086				goto_error_item( false, epoEventId );
4087				return true;
4088			}
4089		};
4090	}
4091
4092	function cleanPrice( price ) {
4093		if ( price === null ) {
4094			return 0;
4095		}
4096
4097		if ( typeof price === 'object' ) {
4098			price = price[ 0 ];
4099		}
4100
4101		if ( ! Number.isFinite( parseFloat( price ) ) ) {
4102			price = 0;
4103		}
4104
4105		return price;
4106	}
4107
4108	function tm_apply_dpd( price, totals, apply, force ) {
4109		price = cleanPrice( price );
4110
4111		if ( apply ) {
4112			price = $.epoAPI.applyFilter( 'tc_apply_dpd', price, totals, apply, force );
4113		}
4114
4115		return price;
4116	}
4117
4118	function tm_calculate_product_regular_price( totals, allowfalse ) {
4119		var price = 0;
4120
4121		if ( totals.length > 0 ) {
4122			price = totals.data( 'regular-price' );
4123		}
4124
4125		price = $.epoAPI.applyFilter( 'tc_calculate_product_regular_price', price, totals );
4126
4127		if ( allowfalse && price === false ) {
4128			return false;
4129		}
4130		price = parseFloat( price );
4131
4132		if ( ! Number.isFinite( price ) ) {
4133			price = 0;
4134		}
4135
4136		return price;
4137	}
4138
4139	function tm_calculate_product_price( totals, allowfalse ) {
4140		var price = 0;
4141
4142		if ( totals.length > 0 ) {
4143			price = totals.data( 'price' );
4144		}
4145
4146		price = $.epoAPI.applyFilter( 'tc_calculate_product_price', price, totals );
4147
4148		if ( allowfalse && price === false ) {
4149			return false;
4150		}
4151		price = parseFloat( price );
4152
4153		if ( ! Number.isFinite( price ) ) {
4154			price = 0;
4155		}
4156
4157		return price;
4158	}
4159
4160	function calculateMathPrice( price, thisElement, epoObject, noevents, useOriginalPrice, funcTotal, cumulativeTotal, mathskip ) {
4161		var formula = price.toString();
4162		var val = 0;
4163		var matches;
4164		var match;
4165		var elementWrap;
4166		var allElements;
4167		var element;
4168		var reg;
4169		var elementPrice = 0;
4170		var pos;
4171		var type;
4172		var id;
4173		var thisVal;
4174		var thisValForced;
4175		var thisElementId = thisElement.closest( '.cpf-element' ).attr( 'data-uniqid' );
4176		var thisElementWrap = thisElement.closest( '.tmcp-ul-wrap' );
4177		var totalsHolder_tc_totals_ob = epoObject.this_epo_totals_container.data( 'totalsHolder_tc_totals_ob' );
4178		var thisElementIndex = thisElementWrap.find( '.tmcp-field, .tmcp-fee-field, .tmcp-sub-fee-field' ).filter( ':checked' ).index( thisElement );
4179		var thisElementIndexForced = thisElementWrap.find( '.tmcp-field, .tmcp-fee-field, .tmcp-sub-fee-field' ).index( thisElement );
4180		var this_epo_container = epoObject.is_associated ? epoObject.this_epo_container : epoObject.this_epo_container.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector );
4181		var constants = $.epoAPI.util.parseJSON( TMEPOJS.tm_epo_math ) || {};
4182		var productPrice;
4183		var dynamicProductPrice;
4184		var __price;
4185		var __price_type;
4186
4187		if ( thisElementIndex === -1 && ! thisElement.is( '.tmcp-checkbox, .tmcp-radio' ) ) {
4188			thisElementIndex = 0;
4189		}
4190		if ( thisElementIndexForced === -1 && ! thisElement.is( '.tmcp-checkbox, .tmcp-radio' ) ) {
4191			thisElementIndexForced = 0;
4192		}
4193
4194		if ( ! thisElement.is( '.tcdisabled' ) && ! noevents && ! thisElement.data( 'addedtcEpoBeforeOptionPriceCalculation' ) ) {
4195			jWindow.on( 'tcEpoBeforeOptionPriceCalculation.math' + thisElementId, function() {
4196				tm_element_epo_rules( epoObject, thisElement, undefined, undefined, undefined, true );
4197			} );
4198			jWindow.on( 'tcEpoAfterNormalOptionPriceCalculation.math' + thisElementId, function() {
4199				thisElement.data( 'fetchOptionPrices', false );
4200				thisElement.data( 'fetchOptionPrices-forced', false );
4201				thisElement.data( 'fetchOptionPrices-fee', false );
4202				thisElement.data( 'fetchOptionPrices-fee-forced', false );
4203				thisElement.data( 'fetchOptionPrices-sub-fee', false );
4204				thisElement.data( 'fetchOptionPrices-sub-fee-forced', false );
4205			} );
4206			thisElement.data( 'addedtcEpoBeforeOptionPriceCalculation', 1 );
4207		}
4208
4209		if ( thisElement.is( '.tmcp-field' ) ) {
4210			if ( thisElement.data( 'fetchOptionPrices' ) ) {
4211				thisVal = thisElement.data( 'fetchOptionPrices' );
4212				thisValForced = thisElement.data( 'fetchOptionPrices-forced' );
4213			} else {
4214				thisVal = fetchOptionPrices( epoObject, thisElementWrap, '.tmcp-field', 0, 0, [], true, undefined, undefined, undefined, undefined, undefined, true );
4215				thisValForced = fetchOptionPrices( epoObject, thisElementWrap, '.tmcp-field', 0, 0, [], true, true, undefined, undefined, undefined, undefined, true );
4216				thisElement.data( 'fetchOptionPrices', thisVal );
4217				thisElement.data( 'fetchOptionPrices-forced', thisValForced );
4218			}
4219		} else if ( thisElement.is( '.tmcp-fee-field' ) ) {
4220			if ( thisElement.data( 'fetchOptionPrices-fee' ) ) {
4221				thisVal = thisElement.data( 'fetchOptionPrices-fee' );
4222				thisValForced = thisElement.data( 'fetchOptionPrices-fee-forced' );
4223			} else {
4224				thisVal = fetchOptionPrices( epoObject, thisElementWrap, '.tmcp-fee-field', 0, 0, [], true, undefined, undefined, undefined, undefined, undefined, true );
4225				thisValForced = fetchOptionPrices( epoObject, thisElementWrap, '.tmcp-fee-field', 0, 0, [], true, true, undefined, undefined, undefined, undefined, true );
4226				thisElement.data( 'fetchOptionPrices-fee', thisVal );
4227				thisElement.data( 'fetchOptionPrices-fee-forced', thisValForced );
4228			}
4229		} else if ( thisElement.is( '.tmcp-sub-fee-field' ) ) {
4230			if ( thisElement.data( 'fetchOptionPrices-sub-fee' ) ) {
4231				thisVal = thisElement.data( 'fetchOptionPrices-sub-fee' );
4232				thisValForced = thisElement.data( 'fetchOptionPrices-sub-fee-forced' );
4233			} else {
4234				thisVal = fetchOptionPrices( epoObject, thisElementWrap, '.tmcp-sub-fee-field', 0, 0, [], true, undefined, undefined, undefined, undefined, undefined, true );
4235				thisValForced = fetchOptionPrices( epoObject, thisElementWrap, '.tmcp-sub-fee-field', 0, 0, [], true, true, undefined, undefined, undefined, undefined, true );
4236				thisElement.data( 'fetchOptionPrices-sub-fee', thisVal );
4237				thisElement.data( 'fetchOptionPrices-sub-fee-forced', thisValForced );
4238			}
4239		}
4240
4241		Object.keys( constants ).forEach( function( key ) {
4242			var name;
4243			var value;
4244
4245			if ( constants[ key ].name !== '' && constants[ key ].value !== '' ) {
4246				name = constants[ key ].name;
4247				value = constants[ key ].value;
4248				if ( name.startsWith( '{' ) ) {
4249					formula = formula.replaceAll( name, value );
4250				} else if ( constants[ key ].name.isNumeric() ) {
4251					formula = formula.replaceAll( '{' + name + '}', value );
4252				} else {
4253					name = '{' + name + '}';
4254					if ( value.startsWith( '{' ) ) {
4255						formula = formula.replaceAll( name, value );
4256					} else {
4257						formula = formula.replaceAll( name, $.epoAPI.math.unformat( value.replace( ',', '.' ) ) );
4258					}
4259				}
4260			}
4261		} );
4262
4263		if ( totalsHolder_tc_totals_ob !== undefined ) {
4264			// product quantity
4265			formula = formula.replaceAll( '{quantity}', $.epoAPI.math.unformat( totalsHolder_tc_totals_ob.qty ) );
4266			// original product price
4267			if ( useOriginalPrice && totalsHolder_tc_totals_ob.original_product_price !== undefined ) {
4268				productPrice = $.epoAPI.math.unformat( totalsHolder_tc_totals_ob.original_product_price );
4269			} else {
4270				productPrice = $.epoAPI.math.unformat( totalsHolder_tc_totals_ob.product_price );
4271			}
4272			if ( totalsHolder_tc_totals_ob.dynamic_product_price !== undefined ) {
4273				dynamicProductPrice = $.epoAPI.math.unformat( totalsHolder_tc_totals_ob.dynamic_product_price );
4274			} else {
4275				dynamicProductPrice = 0;
4276			}
4277		} else {
4278			// product quantity
4279			formula = formula.replaceAll( '{quantity}', 0 );
4280			// original product price
4281			productPrice = 0;
4282			dynamicProductPrice = 0;
4283		}
4284
4285		productPrice = $.epoAPI.math.toFloat( productPrice );
4286
4287		formula = formula.replaceAll( '{product_price}', productPrice );
4288		formula = formula.replaceAll( '{dynamic_product_price}', dynamicProductPrice );
4289
4290		if ( ! funcTotal ) {
4291			funcTotal = 0;
4292		}
4293		funcTotal = $.epoAPI.math.toFloat( funcTotal );
4294
4295		if ( ! cumulativeTotal ) {
4296			cumulativeTotal = 0;
4297		}
4298		cumulativeTotal = $.epoAPI.math.toFloat( cumulativeTotal );
4299
4300		formula = formula.replaceAll( '{options_total}', funcTotal );
4301		formula = formula.replaceAll( '{product_price_plus_options_total}', productPrice + funcTotal );
4302		formula = formula.replaceAll( '{cumulative_total}', cumulativeTotal );
4303		formula = formula.replaceAll( '{product_price_plus_cumulative_total}', productPrice + cumulativeTotal );
4304
4305		if ( thisValForced.floatingBoxData !== undefined && thisValForced.floatingBoxData[ thisElementIndexForced ] !== undefined ) {
4306			// the option/element value to float
4307			if ( thisValForced.floatingBoxData[ thisElementIndexForced ].input_type === 'number' || thisValForced.floatingBoxData[ thisElementIndexForced ].input_type === 'hidden' ) {
4308				formula = formula
4309					.replaceAll( '{this.value}', $.epoAPI.math.toFloat( $.epoAPI.math.unformat( thisValForced.floatingBoxData[ thisElementIndexForced ].valueText ) ) );
4310			} else {
4311				formula = formula
4312					.replaceAll( '{this.value}', $.epoAPI.math.toFloat( $.epoAPI.math.unformat( thisValForced.floatingBoxData[ thisElementIndexForced ].valueText, tcAPI.localDecimalSeparator ) ) );
4313			}
4314			// the option/element raw value
4315			formula = formula.replaceAll( '{this.rawvalue}', thisValForced.floatingBoxData[ thisElementIndexForced ].valueText );
4316			// the option/element raw value
4317			formula = formula.replaceAll( '{this.text}', thisValForced.floatingBoxData[ thisElementIndexForced ].valueText );
4318			// the option/element value length
4319			formula = formula
4320				.replaceAll( '{this.value.length}', thisValForced.floatingBoxData[ thisElementIndexForced ].valueText.length );
4321		} else {
4322			formula = formula
4323				// the option/element value to float
4324				.replaceAll( '{this.value}', 0 )
4325				// the option/element raw value
4326				.replaceAll( '{this.rawvalue}', '' )
4327				// the option/element raw value
4328				.replaceAll( '{this.text}', '' )
4329				// the option/element value length
4330				.replaceAll( '{this.value.length}', 0 );
4331		}
4332
4333		formula = formula
4334			// the number of options the user has selected
4335			.replaceAll( '{this.count}', thisVal.floatingBoxData.length )
4336			// the total option quantity of this element
4337			.replaceAll(
4338				'{this.count.quantity}',
4339				thisVal.floatingBoxData
4340					.map( function( x ) {
4341						return x.quantity;
4342					} )
4343					.reduce( function( acc, thisval ) {
4344						return $.epoAPI.math.toFloat( acc ) + $.epoAPI.math.toFloat
4344( thisval );
4345					}, 0 )
4346			)
4347			// the option quantity of this element
4348			.replaceAll( '{this.quantity}', thisElement.data( 'tm-quantity' ) );
4349
4350		if ( formula.match( /\{(\s)*?field\.([^}]*)}/ ) ) {
4351			matches = formula.match( /\{(\s)*?field\.([^}]*)}/g );
4352			matches.forEach( function( field ) {
4353				match = field.match( /\{(\s)*?field\.([^}]*)}/ );
4354				if ( undefined !== match[ 2 ] && 'string' === typeof match[ 2 ] ) {
4355					pos = match[ 2 ].lastIndexOf( '.' );
4356					if ( pos !== -1 ) {
4357						id = match[ 2 ].substring( 0, pos );
4358						type = match[ 2 ].substring( pos + 1 );
4359
4360						if ( $.inArray( type, [ 'price', 'value', 'value.length', 'rawvalue', 'text', 'text.length', 'quantity', 'count', 'count.quantity' ] ) !== -1 ) {
4361							elementWrap = this_epo_container.find( "[data-uniqid='" + $.epoAPI.util.escapeSelector( id ) + "']" );
4362							if ( elementWrap.length ) {
4363								allElements = elementWrap.find( '.tmcp-field, .tmcp-fee-field, .tmcp-sub-fee-field' );
4364								element = allElements.first();
4365
4366								if ( ! thisElement.is( '.tcdisabled' ) && ! noevents && ! thisElement.data( 'addedfieldtcEpoBeforeOptionPriceCalculation' ) ) {
4367									jWindow.on( 'tcEpoBeforeOptionPriceCalculation.math' + thisElementId, function() {
4368										tm_element_epo_rules( epoObject, thisElement, undefined, undefined, undefined, true );
4369										thisElement.trigger( 'tm-math-select-change-html-all' );
4370									} );
4371									thisElement.data( 'addedfieldtcEpoBeforeOptionPriceCalculation', 1 );
4372								}
4373								val = 0;
4374								switch ( type ) {
4375									case 'text':
4376									case 'rawvalue':
4377										val = '';
4378										break;
4379								}
4380
4381								if ( elementWrap.is( '.tc-container-enabled' ) ) {
4382									if ( ! mathskip ) {
4383										allElements.toArray().forEach( function( singleElement ) {
4384											singleElement = $( singleElement );
4385											// For now we only recalculate dynamic elements
4386											if ( thisElement.attr( 'id' ) !== singleElement.attr( 'id' ) && ( thisElement.is( '.tmcp-dynamic' ) || singleElement.is( '.tmcp-dynamic' ) ) ) {
4387												tm_element_epo_rules( epoObject, singleElement, undefined, undefined, undefined, true, undefined, undefined, true );
4388											}
4389											if ( ! noevents && ! singleElement.data( 'addedmathevent' ) ) {
4390												singleElement.on( 'input.mathevent', function() {
4391													if ( ! thisElement.is( '.tcdisabled' ) ) {
4392														thisElement.trigger( 'change.cpf', { calculateMathPrice: 1 } );
4393													}
4394												} );
4395												singleElement.data( 'addedmathevent', 1 );
4396											}
4397										} );
4398									}
4399									if ( element.is( '.tmcp-field' ) ) {
4400										val = fetchOptionPrices( epoObject, elementWrap, '.tmcp-field', 0, 0, [], true, undefined, undefined, true, undefined, undefined, true );
4401									} else if ( element.is( '.tmcp-fee-field' ) ) {
4402										val = fetchOptionPrices( epoObject, elementWrap, '.tmcp-fee-field', 0, 0, [], true, undefined, undefined, true, undefined, undefined, true );
4403									} else if ( element.is( '.tmcp-sub-fee-field' ) ) {
4404										val = fetchOptionPrices( epoObject, elementWrap, '.tmcp-sub-fee-field', 0, 0, [], true, undefined, undefined, true, undefined, undefined, true );
4405									}
4406
4407									switch ( type ) {
4408										// element price
4409										case 'price':
4410											val = val.total;
4411											if ( thisElement.is( '.tmcp-dynamic' ) ) {
4412												__price = get_type( epoObject, element, 'price' );
4413												__price_type = get_type( epoObject, element, 'price_type' );
4414												if ( 'math' === __price_type && __price.includes( '{dynamic_product_price}' ) ) {
4415													val = 0;
4416												}
4417											}
4418											break;
4419
4420										// element value
4421										case 'value':
4422										case 'text':
4423										case 'rawvalue':
4424											if ( val.floatingBoxData ) {
4425												val = val.floatingBoxData
4426													.map( function( x ) {
4427														if ( x.input_type === 'number' || x.input_type === 'hidden' ) {
4428															if ( type === 'text' || type === 'rawvalue' ) {
4429																return x.valueText;
4430															}
4431															return $.epoAPI.math.unformat( x.valueText );
4432														}
4433														if ( type === 'text' || type === 'rawvalue' ) {
4434															return x.valueText;
4435														}
4436														return $.epoAPI.math.unformat( x.valueText, tcAPI.localIn
4436putDecimalSeparator );
4437													} )
4438													.reduce( function( acc, thisval ) {
4439														if ( type === 'text' || type === 'rawvalue' ) {
4440															return acc + thisval;
4441														}
4442														return $.epoAPI.math.toFloat( acc ) + $.epoAPI.math.toFloat( thisval );
4443													}, ( type === 'text' || type === 'rawvalue' ) ? '' : 0 );
4444
4445												if ( type === 'text' || type === 'rawvalue' ) {
4446													if ( val === '' ) {
4447														val = "''";
4448													} else if ( ! val.toString().isNumeric() ) {
4449														val = "'" + val.replaceAll( "'", "\\'" ) + "'";
4450													}
4451												}
4452											}
4453											break;
4454
4455										// element value length
4456										case 'value.length':
4457										case 'text.length':
4458											if ( val.floatingBoxData ) {
4459												val = val.floatingBoxData
4460													.map( function( x ) {
4461														return x.valueText;
4462													} )
4463													.reduce( function( acc, thisval ) {
4464														return $.epoAPI.math.toFloat( acc ) + thisval.length;
4465													}, 0 );
4466											}
4467											break;
4468
4469										// element quantity
4470										// the total option quantity of this element
4471										case 'quantity':
4472										case 'count.quantity':
4473											if ( val.floatingBoxData ) {
4474												val = val.floatingBoxData
4475													.map( function( x ) {
4476														return x.quantity;
4477													} )
4478													.reduce( function( acc, thisval ) {
4479														return $.epoAPI.math.toFloat( acc ) + $.epoAPI.math.toFloat( thisval );
4480													}, 0 );
4481											}
4482											break;
4483
4484										// number of element options the user has selected
4485										case 'count':
4486											if ( val.floatingBoxData ) {
4487												val = val.floatingBoxData.length;
4488											}
4489											break;
4490									}
4491									if ( type !== 'text' && type !== 'rawvalue' ) {
4492										val = $.epoAPI.math.toFloat( val );
4493										if ( ! Number.isFinite( val ) ) {
4494											val = 0;
4495										}
4496									}
4497								}
4498							} else {
4499								val = 0;
4500								switch ( type ) {
4501									case 'text':
4502									case 'rawvalue':
4503										val = '';
4504										break;
4505								}
4506							}
4507							reg = new RegExp( match[ 0 ] );
4508							if ( type === 'text' || type === 'rawvalue' ) {
4509								formula = val === '' ? formula.replace( reg, "''" ) : formula.replace( reg, val );
4510							} else {
4511								formula = ! Number.isFinite( val ) ? formula.replace( reg, "'" + val.replace( "'", "\\'" ) + "'" ) : formula.replace( reg, val );
4512							}
4513						}
4514					}
4515				}
4516			} );
4517		}
4518
4519		try {
4520			elementPrice = tcmexp.evaluate( formula );
4521		} catch ( e ) {
4522			elementPrice = 0;
4523		}
4524
4525		return elementPrice;
4526	}
4527
4528	function get_type( epoObject, obj, type ) {
4529		var element = $( obj );
4530		var setter = element;
4531		var cart;
4532		var current_variation;
4533		var rules;
4534		var rulestype;
4535		var _rulestype;
4536		var pricetype;
4537		var variation_id_selector;
4538		var _tmcpulwrap;
4539		var price;
4540		var _rules;
4541
4542		cart = epoObject.main_cart;
4543		variation_id_selector = "input[name^='variation_id']";
4544		if ( cart.find( 'input.variation_id' ).length > 0 ) {
4545			variation_id_selector = 'input.variation_id';
4546		}
4547		current_variation = cart.find( variation_id_selector ).val();
4548		// Get current woocommerce variation
4549		if ( ! current_variation ) {
4550			current_variation = 0;
4551		}
4552
4553		if ( element.is( 'select' ) ) {
4554			setter = element.find( 'option:selected' );
4555		}
4556
4557		rules = $.epoAPI.util.parseJSON( setter.attr( 'data-rules' ) );
4558		rulestype = $.epoAPI.util.parseJSON( setter.attr( 'data-rulestype' ) );
4559
4560		pricetype = '';
4561		if ( typeof rules === 'object' ) {
4562			if ( current_variation in rules ) {
4563				price = rules[ current_variation ];
4564			} else {
4565				_rules = $.epoAPI.util.parseJSON( element.closest( '.tmcp-ul-wrap' ).attr( 'data-rules' ) );
4566
4567				if ( typeof _rules === 'object' ) {
4568					if ( current_variation in _rules ) {
4569						price = _rules[ current_variation ];
4570					} else {
4571						price = rules[ 0 ];
4572					}
4573				} else {
4574					price = rules[ 0 ];
4575				}
4576			}
4577			if ( typeof rulestype === 'object' ) {
4578				if ( current_variation in rulestype ) {
4579					pricetype = rulestype[ current_variation ];
4580				} else {
4581					_rulestype = $.epoAPI.util.parseJSON( element.closest( '.tmcp-ul-wrap' ).attr( 'data-rulestype' ) );
4582					if ( typeof _rulestype === 'object' ) {
4583						if ( current_variation in _rulestype ) {
4584							pricetype = _rulestype[ current_variation ];
4585						} else {
4586							pricetype = rulestype[ 0 ];
4587						}
4588					} else {
4589						pricetype = rulestype[ 0 ];
4590					}
4591				}
4592			} else {
4593				rulestype = $.epoAPI.util.parseJSON( element.closest( '.tmcp-ul-wrap' ).attr( 'data-rulestype' ) );
4594				if ( typeof rulestype === 'object' ) {
4595					if ( current_variation in rulestype ) {
4596						pricetype = rulestype[ current_variation ];
4597					} else {
4598						pricetype = rulestype[ 0 ];
4599					}
4600				}
4601			}
4602		} else {
4603			_tmcpulwrap = element.closest( '.tmcp-ul-wrap' );
4604			rules = $.epoAPI.util.parseJSON( _tmcpulwrap.attr( 'data-rules' ) );
4605
4606			if ( typeof rules === 'object' ) {
4607				if ( current_variation in rules ) {
4608					price = rules[ current_variation ];
4609				} else {
4610					price = rules[ 0 ];
4611				}
4612				if ( typeof rulestype === 'object' ) {
4613					if ( current_variation in rulestype ) {
4614						pricetype = rulestype[ current_variation ];
4615					} else {
4616						_rulestype = $.epoAPI.util.parseJSON( _tmcpulwrap.attr( 'data-rulestype' ) );
4617						if ( typeof _rulestype === 'object' ) {
4618							if ( current_variation in _rulestype ) {
4619								pricetype = _rulestype[ current_variation ];
4620							} else {
4621								pricetype = rulestype[ 0 ];
4622							}
4623						} else {
4624							pricetype = rulestype[ 0 ];
4625						}
4626					}
4627				} else {
4628					rulestype = $.epoAPI.util.parseJSON( _tmcpulwrap.attr( 'data-rulestype' ) );
4629					if ( typeof rulestype === 'object' ) {
4630						if ( current_variation in rulestype ) {
4631							pricetype = rulestype[ current_variation ];
4632						} else {
4633							pricetype = rulestype[ 0 ];
4634						}
4635					}
4636				}
4637			}
4638		}
4639
4640		if ( typeof price === 'object' ) {
4641			price = price[ 0 ];
4642		}
4643
4644		if ( typeof pricetype === 'object' ) {
4645			pricetype = pricetype[ 0 ];
4646		}
4647		if ( element.is( '.tmcp-fee-field' ) ) {
4648			if ( $.inArray( pricetype, [ 'fee', 'stepfee', 'currentstepfee' ] ) !== -1 ) {
4649				pricetype = '';
4650			}
4651		}
4652
4653		if ( type === 'price' ) {
4654			return price;
4655		}
4656
4657		return pricetype;
4658	}
4659
4660	function wordLength( str ) {
4661		var regex = new RegExp( /[\p{L}\d!@#$%^&*()_+=\{[\}\]|\\"':;?/>.<,-]+/, 'gu' );
4662		var m;
4663		var len = 0;
4664
4665		while ( ( m = regex.exec( str ) ) !== null ) {
4666			// This is necessary to avoid infinite loops with zero-width matches
4667			if ( m.index === regex.lastIndex ) {
4668				regex.lastIndex++;
4669			}
4670			len = len + m.length;
4671		}
4672		return len;
4673	}
4674
4675	function tm_calculate_price_by_type( pricetype, price, original_price, setter, product_price, product_original_price, epoTotalsContainer, apply_dpd, funcTotal, cumulativeTotal, mathskip, manthnoevent, cart, element, epoObject, bundleid, epoEventId, is_range_field ) {
4676		var undiscounted_price;
4677		var freechars, textlength, cart_total, min_value;
4678		var mathopc = false;
4679		var setterValue = setter.val();
4680
4681		switch ( pricetype ) {
4682			case '':
4683				undiscounted_price = price;
4684				price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd );
4685				// original_price No change
4686				break;
4687			case 'fixednon':
4688				freechars = parseInt( setter.attr( 'data-freechars' ), 10 );
4689				if ( ! Number.isFinite( freechars ) ) {
4690					freechars = 0;
4691				}
4692				textlength = setterValue.length - freechars;
4693				if ( textlength <= 0 ) {
4694					price = 0;
4695				}
4696				undiscounted_price = price;
4697				price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd );
4698				break;
4699			case 'math':
4700				if ( price !== original_price ) {
4701					mathopc = true;
4702				} else {
4703					mathopc = false;
4704				}
4705				if ( mathopc ) {
4706					original_price = calculateMathPrice( original_price, element, epoObject, true, true, funcTotal, cumulativeTotal, mathskip );
4707				}
4708				price = calculateMathPrice( price, element, epoObject, manthnoevent, $.epoAPI.applyFilter( 'tc_use_undiscounted_price', undefined, element, cart, epoTotalsContainer ), funcTotal, cumulativeTotal, mathskip );
4709				if ( ! mathopc ) {
4710					original_price = price;
4711				}
4712				undiscounted_price = price;
4713				price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd );
4714				// original_price No other change
4715				break;
4716			case 'percent_cart_total':
4717				cart_total = parseFloat( TMEPOJS.cart_total );
4718
4719				if ( ! Number.isFinite( cart_total ) ) {
4720					cart_total = 0;
4721				}
4722				undiscounted_price = ( price / 100 ) * cart_total;
4723				price = ( tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) / 100 ) * cart_total;
4724				original_price = ( tm_apply_dpd( original_price, epoTotalsContainer, apply_dpd ) / 100 ) * cart_total;
4725				break;
4726
4727			case 'percent':
4728				undiscounted_price = ( price / 100 ) * product_price;
4729				price = ( tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) / 100 ) * product_price;
4730				original_price = ( original_price / 100 ) * product_original_price;
4731				break;
4732			case 'percentcurrenttotal':
4733				$.tcepo.lateFieldsPrices[ epoEventId ].push( {
4734					setter: setter,
4735					price: price,
4736					original_price: original_price,
4737					bundleid: bundleid,
4738					pricetype: pricetype
4739				} );
4740				setter.data( 'tm-price-for-late', price ).data( 'tm-original-price-for-late', original_price ).data( 'islate', 1 ).addClass( 'tm-epo-late-field' );
4741				undiscounted_price = 0;
4742				price = 0;
4743				original_price = 0;
4744				break;
4745			case 'fixedcurrenttotal':
4746				price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd );
4747				$.tcepo.lateFieldsPrices[ epoEventId ].push( {
4748					setter: setter,
4749					price: price,
4750					original_price: original_price,
4751					bundleid: bundleid,
4752					pricetype: pricetype
4753				} );
4754				setter.data( 'tm-price-for-late', price ).data( 'tm-original-price-for-late', original_price ).data( 'islate', 1 ).addClass( 'tm-epo-late-field' );
4755				undiscounted_price = 0;
4756				price = 0;
4757				original_price = 0;
4758				break;
4759			case 'word':
4760				undiscounted_price = price * wordLength( setterValue );
4761				price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * wordLength( setterValue );
4762				original_price = original_price * wordLength( setterValue );
4763				break;
4764			case 'wordpercent':
4765				undiscounted_price = ( price / 100 ) * product_price * wordLength( setterValue );
4766				price = ( tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) / 100 ) * product_price * wordLength( setterValue );
4767				original_price = ( original_price / 100 ) * product_original_price * wordLength( setterValue );
4768				break;
4769			case 'wordnon':
4770				freechars = parseInt( setter.attr( 'data-freechars' ), 10 );
4771				if ( ! Number.isFinite( freechars ) ) {
4772					freechars = 0;
4773				}
4774				textlength = wordLength( setterValue ) - freechars;
4775				if ( textlength < 0 ) {
4776					textlength = 0;
4777				}
4778				undiscounted_price = price * textlength;
4779				price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * textlength;
4780				original_price = original_price * textlength;
4781				break;
4782			case 'wordpercentnon':
4783				freechars = parseInt( setter.attr( 'data-freechars' ), 10 );
4784				if ( ! Number.isFinite( freechars ) ) {
4785					freechars = 0;
4786				}
4787				textlength = wordLength( setterValue ) - freechars;
4788				if ( textlength < 0 ) {
4789					textlength = 0;
4790				}
4791				undiscounted_price = ( price / 100 ) * product_price * textlength;
4792				price = ( tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) / 100 ) * product_price * textlength;
4793				original_price = ( original_price / 100 ) * product_original_price * textlength;
4794				break;
4795
4796			case 'char':
4797				undiscounted_price = price * setterValue.length;
4798				price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * setterValue.length;
4799				original_price = original_price * setterValue.length;
4800				break;
4801			case 'charpercent':
4802				undiscounted_price = ( price / 100 ) * product_price * setterValue.length;
4803				price = ( tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) / 100 ) * product_price * setterValue.length;
4804				original_price = ( original_price / 100 ) * product_original_price * setterValue.length;
4805				break;
4806			case 'charnospaces':
4807				undiscounted_price = price * setterValue.replace( /\s/g, '' ).length;
4808				price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * setterValue.replace( /\s/g, '' ).length;
4809				original_price = original_price * setterValue.replace( /\s/g, '' ).length;
4810				break;
4811			case 'charnofirst':
4812				textlength = setterValue.length - 1;
4813				if ( textlength < 0 ) {
4814					textlength = 0;
4815				}
4816				undiscounted_price = price * textlength;
4817				price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * textlength;
4818				original_price = original_price * textlength;
4819				break;
4820
4821			case 'charnon':
4822				freechars = parseInt( setter.attr( 'data-freechars' ), 10 );
4823				if ( ! Number.isFinite( freechars ) ) {
4824					freechars = 0;
4825				}
4826				textlength = setterValue.length - freechars;
4827				if ( textlength < 0 ) {
4828					textlength = 0;
4829				}
4830				undiscounted_price = price * textlength;
4831				price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * textlength;
4832				original_price = original_price * textlength;
4833				break;
4834			case 'charpercentnon':
4835				freechars = parseInt( setter.attr( 'data-freechars' ), 10 );
4836				if ( ! Number.isFinite( freechars ) ) {
4837					freechars = 0;
4838				}
4839				textlength = setterValue.length - freechars;
4840				if ( textlength < 0 ) {
4841					textlength = 0;
4842				}
4843				undiscounted_price = ( price / 100 ) * product_price * textlength;
4844				price = ( tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) / 100 ) * product_price * textlength;
4845				original_price = ( original_price / 100 ) * product_original_price * textlength;
4846				break;
4847			case 'charnonnospaces':
4848				freechars = parseInt( setter.attr( 'data-freechars' ), 10 );
4849				if ( ! Number.isFinite( freechars ) ) {
4850					freechars = 0;
4851				}
4852				textlength = setterValue.replace( /\s/g, '' ).length - freechars;
4853				if ( textlength < 0 ) {
4854					textlength = 0;
4855				}
4856				undiscounted_price = price * textlength;
4857				price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * textlength;
4858				original_price = original_price * textlength;
4859				break;
4860			case 'charpercentnonnospaces':
4861				freechars = parseInt( setter.attr( 'data-freechars' ), 10 );
4862				if ( ! Number.isFinite( freechars ) ) {
4863					freechars = 0;
4864				}
4865				textlength = setterValue.replace( /\s/g, '' ).length - freechars;
4866				if ( textlength < 0 ) {
4867					textlength = 0;
4868				}
4869				undiscounted_price = ( price / 100 ) * product_price * textlength;
4870				price = ( tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) / 100 ) * product_price * textlength;
4871				original_price = ( original_price / 100 ) * product_original_price * textlength;
4872				break;
4873
4874			case 'charpercentnofirst':
4875				textlength = setterValue.length - 1;
4876				if ( textlength < 0 ) {
4877					textlength = 0;
4878				}
4879				undiscounted_price = ( price / 100 ) * product_price * textlength;
4880				price = ( tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) / 100 ) * product_price * textlength;
4881				original_price = ( original_price / 100 ) * product_original_price * textlength;
4882				break;
4883			case 'step':
4884				if ( is_range_field ) {
4885					undiscounted_price = price * setterValue;
4886					price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * setterValue;
4887					original_price = original_price * $.epoAPI.math.toFloat( setterValue );
4888				} else {
4889					undiscounted_price = price * $.epoAPI.math.toFloat( setterValue );
4890					price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * $.epoAPI.math.toFloat( setterValue );
4891					original_price = original_price * $.epoAPI.math.toFloat( setterValue );
4892				}
4893				break;
4894			case 'currentstep':
4895				if ( is_range_field ) {
4896					undiscounted_price = setterValue;
4897					price = tm_apply_dpd( setterValue, epoTotalsContainer, apply_dpd );
4898					original_price = tm_apply_dpd( setterValue, epoTotalsContainer, apply_dpd );
4899				} else {
4900					undiscounted_price = $.epoAPI.math.toFloat( setterValue );
4901					price = tm_apply_dpd( $.epoAPI.math.toFloat( setterValue ), epoTotalsContainer, apply_dpd );
4902					original_price = tm_apply_dpd( $.epoAPI.math.toFloat( setterValue ), epoTotalsContainer, apply_dpd );
4903				}
4904				break;
4905			case 'intervalstep':
4906				if ( is_range_field ) {
4907					min_value = parseFloat( $( '.tm-range-picker[data-field-id="' + setter.attr( 'id' ) + '"]' ).attr( 'data-min' ) );
4908					undiscounted_price = price * ( setterValue - min_value );
4909					price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * ( setterValue - min_value );
4910					original_price = original_price * ( setterValue - min_value );
4911				}
4912				break;
4913			case 'row':
4914				undiscounted_price = price * ( ( setterValue.match( /(\r\n|\n|\r)/gm ) || [] ).length + 1 );
4915				price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * ( ( setterValue.match( /(\r\n|\n|\r)/gm ) || [] ).length + 1 );
4916				original_price = original_price * ( ( setterValue.match( /(\r\n|\n|\r)/gm ) || [] ).length + 1 );
4917				break;
4918		}
4919
4920		return {
4921			price: price,
4922			original_price: original_price,
4923			undiscounted_price: undiscounted_price
4924		};
4925	}
4926
4927	// Set field price rules
4928	function tm_element_epo_rules( epoObject, obj, args, setter_override, noremove, manthnoevent, funcTotal, cumulativeTotal, mathskip ) {
4929		var element = obj instanceof $ ? obj : $( obj );
4930		var setterall = element;
4931		var cart;
4932		var current_variation;
4933		var bundleid;
4934		var epoTotalsContainer;
4935		var apply_dpd;
4936		var product_price;
4937		var product_original_price;
4938		var is_range_field = element.is( '.tmcp-range' );
4939		var rules;
4940		var rulestype;
4941		var original_rules;
4942		var _rules;
4943		var _rulestype;
4944		var _original_rules;
4945		var pricetype;
4946		var price;
4947		var original_price;
4948		var raw_price;
4949		var raw_original_price;
4950		var formatted_price = '';
4951		var main_product = epoObject.main_product;
4952		var epoEventId = epoObject.epoEventId;
4953		var variation_id_selector;
4954		var _tmcpulwrap;
4955		var per_product_pricing = true;
4956		var addedPrice = 0;
4957		var originalAddedPrice = 0;
4958		var undiscounted_raw_price;
4959		var undiscounted_raw_original_price;
4960		var undiscounted_price;
4961		var undiscounted_original_price;
4962		var isFilled;
4963		var useFormattedPrice = false;
4964		var priceResult;
4965
4966		if ( element.data( 'associated_price_set' ) ) {
4967			return;
4968		}
4969
4970		if ( ! args ) {
4971			cart = epoObject.main_cart;
4972			if ( cart.data( 'per_product_pricing' ) !== undefined ) {
4973				per_product_pricing = cart.data( 'per_product_pricing' );
4974			}
4975			variation_id_selector = "input[name^='variation_id']";
4976			if ( cart.find( 'input.variation_id' ).length > 0 ) {
4977				variation_id_selector = 'input.variation_id';
4978			}
4979			current_variation = cart.find( variation_id_selector ).val();
4980
4981			bundleid = $.epoAPI.applyFilter( 'tc_get_bundleid', cart.attr( 'data-product_id' ), cart, epoObject );
4982
4983			// Get current woocommerce variation
4984			if ( ! current_variation ) {
4985				current_variation = 0;
4986			}
4987
4988			epoTotalsContainer = $.epoAPI.applyFilter( 'tc_get_totals_container', epoObject.this_epo_totals_container, element, main_product, bundleid );
4989			product_price = tm_calculate_product_price( epoTotalsContainer );
4990			product_original_price = tm_calculate_product_regular_price( epoTotalsContainer );
4991			apply_dpd = epoTotalsContainer.data( 'fields-price-rules' );
4992		} else {
4993			cart = args.cart;
4994			current_variation = args.current_variation;
4995
4996			bundleid = args.bundleid;
4997			epoTotalsContainer = args.epoTotalsContainer;
4998			product_price = args.product_price;
4999			product_original_price = args.product_original_price;
5000			apply_dpd = args.apply_dpd;
5001			per_product_pricing = args.per_product_pricing;
5002		}
5003		product_price = $.epoAPI.applyFilter( 'tc_alter_product_price', product_price, element, cart, epoTotalsContainer, bundleid );
5004		product_original_price = $.epoAPI.applyFilter( 'tc_alter_product_original_price', product_original_price, element, cart, epoTotalsContainer );
5005
5006		if ( product_price === false || ! per_product_pricing ) {
5007			return;
5008		}
5009
5010		if ( element.is( 'select' ) ) {
5011			setterall = element.find( 'option:selected' );
5012		}
5013		if ( setter_override ) {
5014			setterall = setter_override;
5015		}
5016
5017		setterall.toArray().forEach( function( setter ) {
5018			setter = $( setter );
5019
5020			rules = $.epoAPI.util.parseJSON( setter.attr( 'data-rules' ) );
5021			rulestype = $.epoAPI.util.parseJSON( setter.attr( 'data-rulestype' ) );
5022			original_rules = $.epoAPI.util.parseJSON( setter.attr( 'data-original-rules' ) );
5023			if ( element.is( '.tmcp-dynamic' ) ) {
5024				rules = $.epoAPI.util.parseJSON( setter.attr( 'data-formula' ) );
5025				original_rules = $.epoAPI.util.parseJSON( setter.attr( 'data-formula' ) );
5026				rulestype = $.epoAPI.util.parseJSON( setter.attr( 'data-calculation-type' ) );
5027			}
5028			if ( original_rules === undefined ) {
5029				original_rules = rules;
5030			}
5031
5032			pricetype = '';
5033			if ( typeof rules === 'object' ) {
5034				if ( current_variation in rules ) {
5035					price = rules[ current_variation ];
5036					original_price = original_rules[ current_variation ];
5037				} else {
5038					_rules = $.epoAPI.util.parseJSON( element.closest( '.tmcp-ul-wrap' ).attr( 'data-rules' ) );
5039					_original_rules = element.closest( '.tmcp-ul-wrap' ).data( 'original-rules' );
5040
5041					if ( typeof _rules === 'object' ) {
5042						if ( current_variation in _rules ) {
5043							price = _rules[ current_variation ];
5044						} else {
5045							price = rules[ 0 ];
5046						}
5047					} else {
5048						price = rules[ 0 ];
5049					}
5050
5051					if ( typeof _original_rules === 'object' ) {
5052						if ( current_variation in _original_rules ) {
5053							original_price = _original_rules[ current_variation ];
5054						} else {
5055							original_price = original_rules[ 0 ];
5056						}
5057					} else {
5058						original_price = original_rules[ 0 ];
5059					}
5060				}
5061
5062				if ( typeof rulestype === 'object' ) {
5063					if ( current_variation in rulestype ) {
5064						pricetype = rulestype[ current_variation ];
5065					} else {
5066						_rulestype = $.epoAPI.util.parseJSON( element.closest( '.tmcp-ul-wrap' ).attr( 'data-rulestype' ) );
5067						if ( typeof _rulestype === 'object' ) {
5068							if ( current_variation in _rulestype ) {
5069								pricetype = _rulestype[ current_variation ];
5070							} else {
5071								pricetype = rulestype[ 0 ];
5072							}
5073						} else {
5074							pricetype = rulestype[ 0 ];
5075						}
5076					}
5077				} else {
5078					rulestype = $.epoAPI.util.parseJSON( element.closest( '.tmcp-ul-wrap' ).attr( 'data-rulestype' ) );
5079					if ( typeof rulestype === 'object' ) {
5080						if ( current_variation in rulestype ) {
5081							pricetype = rulestype[ current_variation ];
5082						} else {
5083							pricetype = rulestype[ 0 ];
5084						}
5085					}
5086				}
5087			} else {
5088				_tmcpulwrap = element.closest( '.tmcp-ul-wrap' );
5089				rules = $.epoAPI.util.parseJSON( _tmcpulwrap.attr( 'data-rules' ) );
5090				original_rules = $.epoAPI.util.parseJSON( _tmcpulwrap.attr( 'data-original-rules' ) );
5091
5092				if ( typeof rules === 'object' ) {
5093					if ( current_variation in rules ) {
5094						price = rules[ current_variation ];
5095					} else {
5096						price = rules[ 0 ];
5097					}
5098					if ( typeof original_rules === 'object' ) {
5099						if ( current_variation in original_rules ) {
5100							original_price = original_rules[ current_variation ];
5101						} else {
5102							original_price = original_rules[ 0 ];
5103						}
5104					} else {
5105						original_price = price;
5106					}
5107
5108					if ( typeof rulestype === 'object' ) {
5109						if ( current_variation in rulestype ) {
5110							pricetype = rulestype[ current_variation ];
5111						} else {
5112							_rulestype = $.epoAPI.util.parseJSON( _tmcpulwrap.attr( 'data-rulestype' ) );
5113							if ( typeof _rulestype === 'object' ) {
5114								if ( current_variation in _rulestype ) {
5115									pricetype = _rulestype[ current_variation ];
5116								} else {
5117									pricetype = rulestype[ 0 ];
5118								}
5119							} else {
5120								pricetype = rulestype[ 0 ];
5121							}
5122						}
5123					} else {
5124						rulestype = $.epoAPI.util.parseJSON( _tmcpulwrap.attr( 'data-rulestype' ) );
5125						if ( typeof rulestype === 'object' ) {
5126							if ( current_variation in rulestype ) {
5127								pricetype = rulestype[ current_variation ];
5128							} else {
5129								pricetype = rulestype[ 0 ];
5130							}
5131						}
5132					}
5133				}
5134			}
5135
5136			if ( typeof pricetype === 'object' ) {
5137				pricetype = pricetype[ 0 ];
5138			}
5139			if ( element.is( '.tmcp-fee-field' ) ) {
5140				if ( $.inArray( pricetype, [ 'fee', 'stepfee', 'currentstepfee' ] ) !== -1 ) {
5141					pricetype = '';
5142				}
5143				apply_dpd = 0;
5144			}
5145
5146			if ( noremove === undefined ) {
5147				if ( element.is( 'select' ) ) {
5148					element.find( 'option' ).removeClass( 'tm-epo-late-field' ).removeData( 'tm-price-for-late islate' );
5149				} else {
5150					setter.removeClass( 'tm-epo-late-field' ).removeData( 'tm-price-for-late islate' );
5151				}
5152			}
5153			if ( pricetype !== 'math' ) {
5154				price = cleanPrice( price );
5155				original_price = cleanPrice( original_price );
5156			} else if ( typeof price === 'object' ) {
5157				price = price[ 0 ];
5158			}
5159
5160			undiscounted_raw_price = price;
5161			undiscounted_raw_original_price = original_price;
5162
5163			priceResult = tm_calculate_price_by_type(
5164				pricetype, price, original_price, setter,
5165				product_price, product_original_price,
5166				epoTotalsContainer, apply_dpd,
5167				funcTotal, cumulativeTotal, mathskip,
5168				manthnoevent, cart, element, epoObject,
5169				bundleid, epoEventId, is_range_field
5170			);
5171			price = priceResult.price;
5172			original_price = priceResult.original_price;
5173			undiscounted_price = priceResult.undiscounted_price;
5174
5175			raw_price = price;
5176			raw_original_price = original_price;
5177
5178			undiscounted_original_price = original_price;
5179			undiscounted_raw_price = undiscounted_price;
5180			undiscounted_raw_original_price = undiscounted_original_price;
5181
5182			if ( element.data( 'tm-quantity' ) ) {
5183				undiscounted_price = undiscounted_price * parseFloat( element.data( 'tm-quantity' ) );
5184				undiscounted_original_price = undiscounted_original_price * parseFloat( element.data( 'tm-quantity' ) );
5185				undiscounted_raw_price = undiscounted_raw_price * parseFloat( element.data( 'tm-quantity' ) );
5186				undiscounted_raw_original_price = undiscounted_raw_original_price * parseFloat( element.data( 'tm-quantity' ) );
5187
5188				price = price * parseFloat( element.data( 'tm-quantity' ) );
5189				original_price = original_price * parseFloat( element.data( 'tm-quantity' ) );
5190				raw_price = raw_price * parseFloat( element.data( 'tm-quantity' ) );
5191				raw_original_price = raw_original_price * parseFloat( element.data( 'tm-quantity' ) );
5192			}
5193
5194			addedPrice = addedPrice + parseFloat( price );
5195			originalAddedPrice = originalAddedPrice + parseFloat( original_price );
5196
5197			element.data( 'price_set', 1 );
5198			setter.data( 'price_set', 1 );
5199
5200			setter.data( 'undiscounted_raw_price', undiscounted_raw_price );
5201			setter.data( 'undiscounted_raw_original_price', undiscounted_raw_original_price );
5202			setter.data( 'undiscounted_price', tm_set_tax_price( undiscounted_price, epoTotalsContainer, setter, pricetype ) );
5203			setter.data( 'undiscounted_original_price', tm_set_tax_price( undiscounted_original_price, epoTotalsContainer, setter, pricetype ) );
5204
5205			setter.data( 'raw_price', raw_price );
5206			setter.data( 'raw_original_price', raw_original_price );
5207			setter.data( 'price', tm_set_tax_price( price, epoTotalsContainer, setter, pricetype ) );
5208			setter.data( 'original_price', tm_set_tax_price( original_price, epoTotalsContainer, setter, pricetype ) );
5209
5210			if ( ! setter_override ) {
5211				if ( element.is( '.tc-epo-field-product' ) ) {
5212					isFilled = false;
5213					if ( element.is( 'select' ) ) {
5214						if ( element.val() !== '' ) {
5215							isFilled = true;
5216						}
5217					} else if ( ( element.is( ':checkbox' ) || element.is( ':radio' ) ) ) {
5218						if ( element.is( ':checked' ) ) {
5219							isFilled = true;
5220						}
5221					} else if ( element.val() !== '' ) {
5222						isFilled = true;
5223					}
5224
5225					if ( ! isFilled ) {
5226						formatted_price = setter.data( 'price-html' );
5227						useFormattedPrice = true;
5228					}
5229				}
5230				tm_update_price( {
5231					epoObject: epoObject,
5232					obj: setter.closest( '.tmcp-field-wrap' ).find( '.tc-price' ),
5233					price: tm_get_price( addedPrice, epoTotalsContainer, false, setter, pricetype ),
5234					formatted_price: formatted_price,
5235					original_price: tm_get_price( originalAddedPrice, epoTotalsContainer, false, setter, pricetype ),
5236					force: false,
5237					useFormattedPrice: useFormattedPrice
5238				} );
5239				element.data( 'price-changed', 1 );
5240			}
5241		} );
5242	}
5243
5244	function tm_epo_rules( epoObject, theCart ) {
5245		var all_carts;
5246		var variation_id_selector;
5247		var per_product_pricing = true;
5248		var current_variation;
5249		var bundleid;
5250		var epoContainer;
5251		var epoTotalsContainer;
5252		var apply_dpd;
5253		var rules;
5254		var original_rules;
5255		var price;
5256		var original_price;
5257		var product_price;
5258		var product_original_price;
5259		var all_fields;
5260		var active_fields;
5261		var args;
5262		var main_product = epoObject.main_product;
5263		var epoEventId = epoObject.epoEventId;
5264		var this_epo_container = epoObject.this_epo_container;
5265		var this_epo_totals_container = epoObject.this_epo_totals_container;
5266
5267		if ( ! theCart ) {
5268			all_carts = main_product.find( '.cart' );
5269		} else {
5270			all_carts = theCart;
5271		}
5272		if ( all_carts.length <= 0 ) {
5273			return;
5274		}
5275
5276		$.tcepo.lateFieldsPrices[ epoEventId ] = [];
5277
5278		all_carts.toArray().forEach( function( cart ) {
5279			cart = $( cart );
5280			variation_id_selector = "input[name^='variation_id']";
5281			if ( cart.find( 'input.variation_id' ).length > 0 ) {
5282				variation_id_selector = 'input.variation_id';
5283			}
5284
5285			if ( cart.data( 'per_product_pricing' ) !== undefined ) {
5286				per_product_pricing = cart.data( 'per_product_pricing' );
5287			}
5288
5289			current_variation = cart.find( variation_id_selector ).val();
5290			bundleid = $.epoAPI.applyFilter( 'tc_get_bundleid', cart.attr( 'data-product_id' ), cart, epoObject );
5291
5292			// get current woocommerce variation
5293			if ( ! current_variation ) {
5294				current_variation = 0;
5295			}
5296
5297			epoContainer = $.epoAPI.applyFilter( 'tc_get_epo_container', this_epo_container, cart, main_product, bundleid );
5298			epoTotalsContainer = $.epoAPI.applyFilter( 'tc_get_totals_container', this_epo_totals_container, cart, main_product, bundleid );
5299
5300			// WooCommerce Dynamic Pricing & Discounts
5301			apply_dpd = epoTotalsContainer.data( 'fields-price-rules' );
5302
5303			// set initial prices for all fields
5304			if ( ! epoContainer.data( 'tm_rules_init_done' ) ) {
5305				if ( epoTotalsContainer.data( 'force-quantity' ) ) {
5306					cart.find( tcAPI.qtySelector ).val( epoTotalsContainer.data( 'force-quantity' ) );
5307				}
5308				epoContainer.toArray().forEach( function( el ) {
5309					$( el ).closest( '.tmcp-field-wrap' ).find( '.tm-epo-field' ).data( 'tm-quantity', $( el ).val() );
5310				} );
5311
5312				epoContainer
5313					.find( '.tmcp-attributes, .tmcp-elements' )
5314					.toArray()
5315					.forEach( function( element ) {
5316						element = $( element );
5317						rules = $.epoAPI.util.parseJSON( element.attr( 'data-rules' ) );
5318						original_rules = $.epoAPI.util.parseJSON( element.attr( 'data-original-rules' ) );
5319
5320						// if rule doesn't exit then init an empty rule
5321						if ( typeof rules !== 'object' ) {
5322							rules = {
5323								0: '0'
5324							};
5325						}
5326						if ( typeof original_rules !== 'object' ) {
5327							original_rules = {
5328								0: '0'
5329							};
5330						}
5331						if ( typeof rules === 'object' ) {
5332							// we skip price validation test so that every field has at least a price of 0
5333							price = tm_apply_dpd( rules[ $.epoAPI.math.toFloat( current_variation ) ], epoTotalsContainer, apply_dpd );
5334							original_price = tm_apply_dpd( original_rules[ $.epoAPI.math.toFloat( current_variation ) ], epoTotalsContainer, apply_dpd );
5335
5336							element
5337								.find( '.tmcp-field, .tmcp-fee-field ' )
5338								.toArray()
5339								.forEach( function( el ) {
5340									el = $( el );
5341									if ( per_product_pricing ) {
5342										if ( el.attr( 'data-no-price' ) === '1' ) {
5343											price = 0;
5344											original_price = 0;
5345										}
5346										el.data( 'raw_price', price );
5347										el.data( 'raw_original_price', original_price );
5348
5349										el.data( 'price', tm_set_tax_price( price, epoTotalsContainer, el ) );
5350										el.data( 'original_price', tm_set_tax_price( original_price, epoTotalsContainer, el ) );
5351
5352										tm_update_price( {
5353											epoObject: epoObject,
5354											obj: el.closest( '.tmcp-field-wrap' ).find( '.tc-price' ),
5355											price: tm_get_price( price, epoTotalsContainer ),
5356											original_price: tm_get_price( original_price, epoTotalsContainer ),
5357											force: false,
5358											useFormattedPrice: false
5359										} );
5360									} else {
5361										el.data( 'price', 0 );
5362										el.data( 'original_price', 0 );
5363										el.closest( '.tmcp-field-wrap' ).find( '.amount' ).empty();
5364									}
5365								} );
5366						}
5367					} );
5368				epoContainer.data( 'tm_rules_init_done', 1 );
5369			}
5370
5371			// skip specific field rules if per_product_pricing is false
5372			if ( ! per_product_pricing ) {
5373				return true;
5374			}
5375
5376			product_price = tm_calculate_product_price( epoTotalsContainer );
5377			product_original_price = tm_calculate_product_regular_price( epoTotalsContainer );
5378
5379			args = {
5380				cart: cart,
5381				current_variation: current_variation,
5382				bundleid: bundleid,
5383				epoTotalsContainer: epoTotalsContainer,
5384				product_price: product_price,
5385				product_original_price: product_original_price,
5386				apply_dpd: apply_dpd,
5387				per_product_pricing: per_product_pricing
5388			};
5389
5390			all_fields = epoContainer.find( '.tmcp-field,.tmcp-sub-fee-field,.tmcp-fee-field' );
5391			if ( ! epoObject.is_associated ) {
5392				all_fields = all_fields.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-field,' + tcAPI.associatedEpoSelector + ' ' + '.tmcp-sub-fee-field,' + tcAPI.associatedEpoSelector + ' ' + '.tmcp-fee-field' );
5393			}
5394			active_fields = all_fields.filter( '.tcenabled' );
5395
5396			// note: find a better way if any
5397			if ( ! $.tcepo.initialActivation[ epoEventId ] || ( active_fields.length === 0 && all_fields.length > 0 ) ) {
5398				all_fields.toArray().forEach( function( el ) {
5399					field_is_active( $( el ) );
5400				} );
5401				epoContainer.find( '.cpf-type-divider,.cpf-type-header' ).toArray().forEach( function( el ) {
5402					field_is_active( $( el ) );
5403				} );
5404
5405				$.tcepo.initialActivation[ epoEventId ] = true;
5406			}
5407
5408			//  apply specific field rules
5409			all_fields.filter( '.tcenabled' ).toArray().forEach( function( element ) {
5410				tm_element_epo_rules( epoObject, element, args );
5411			} );
5412
5413			all_fields.toArray().forEach( function( element ) {
5414				$( element ).on( 'tc_element_epo_rules', function() {
5415					tm_element_epo_rules( epoObject, element, args );
5416				} );
5417			} );
5418		} );
5419	}
5420
5421	function add_late_fields_prices( epoObject, currentProductPrice, originalProductPrice, options_total, original_options_total, bid, _cart, applydpd ) {
5422		var total = 0;
5423		var originalTotal = 0;
5424		var totalFees = 0;
5425		var originalTotalFees = 0;
5426		var price;
5427		var originalPrice;
5428		var priceType;
5429		var setter;
5430		var id;
5431		var hidden;
5432		var bundleid;
5433		var realSetter;
5434		var productId;
5435		var epoId;
5436		var epoEventId = epoObject.epoEventId;
5437		var taxPrice;
5438		var taxOriginalPrice;
5439		var hiddenName;
5440		var productPrice;
5441		var oProductPrice;
5442		var apply_dpd;
5443
5444		if ( applydpd !== undefined ) {
5445			apply_dpd = applydpd;
5446		} else {
5447			apply_dpd = epoObject.this_epo_totals_container.data( 'fields-price-rules' );
5448		}
5449		productPrice = currentProductPrice;
5450		oProductPrice = originalProductPrice;
5451
5452		$.tcepo.lateFieldsPrices[ epoEventId ].forEach( function( field ) {
5453			price = field.price;
5454			originalPrice = field.original_price;
5455			priceType = field.pricetype;
5456			setter = field.setter;
5457			bundleid = field.bundleid;
5458			realSetter = setter;
5459
5460			if ( priceType === 'percentcurrenttotal' ) {
5461				hiddenName = '_hidden';
5462			} else {
5463				hiddenName = '_hiddenfixed';
5464			}
5465
5466			if ( setter.is( 'option' ) ) {
5467				realSetter = setter.closest( 'select' );
5468			}
5469
5470			productPrice = parseFloat( $.epoAPI.applyFilter( 'tc_alter_product_price', productPrice, realSetter, _cart, epoObject.this_epo_totals_container, bid ) );
5471			oProductPrice = parseFloat( $.epoAPI.applyFilter( 'tc_alter_original_product_price', oProductPrice, realSetter, _cart, epoObject.this_epo_totals_container, bid ) );
5472
5473			id = $.epoAPI.dom.id( realSetter.attr( 'name' ) );
5474			productId = $( '.tc-totals-form.tm-totals-form-' + _cart.attr( 'data-cart-id' ) ).attr( 'data-product-id' );
5475			epoId = $( '.tc-totals-form.tm-totals-form-' + _cart.attr( 'data-cart-id' ) ).attr( 'data-epo-id' );
5476			//workaround to support composite products
5477			hidden = $( tcAPI.epoSelector + '.tm-product-id-' + productId + "[data-epo-id='" + epoId + "']" ).find( '#' + id + hiddenName );
5478
5479			if ( bundleid === bid ) {
5480				if ( priceType === 'percentcurrenttotal' ) {
5481					price = ( parseFloat( price ) / 100 ) * ( tm_apply_dpd( parseFloat( productPrice ), epoObject.this_epo_totals_container, apply_dpd ) + parseFloat( options_total ) );
5482					originalPrice = ( parseFloat( originalPrice ) / 100 ) * ( parseFloat( oProductPrice ) + parseFloat( original_options_total ) );
5483				} else if ( priceType === 'fixedcurrenttotal' ) {
5484					price = parseFloat( price ) + parseFloat( options_total );
5485					originalPrice = parseFloat( originalPrice ) + parseFloat( original_options_total );
5486				}
5487				if ( realSetter.data( 'tm-quantity' ) ) {
5488					price = price * parseFloat( realSetter.data( 'tm-quantity' ) );
5489					originalPrice = originalPrice * parseFloat( realSetter.data( 'tm-quantity' ) );
5490				}
5491
5492				if ( setter.data( 'isset' ) === 1 && field_is_active( setter ) ) {
5493					if ( realSetter.is( '.tmcp-field' ) ) {
5494						total = total + price;
5495						originalTotal = originalTotal + originalPrice;
5496					} else if ( realSetter.is( '.tmcp-fee-field' ) ) {
5497						totalFees = totalFees + price;
5498						originalTotalFees = originalTotalFees + originalPrice;
5499					}
5500				}
5501
5502				taxPrice = tm_set_tax_price( price, _cart, setter );
5503				taxOriginalPrice = tm_set_tax_price( originalPrice, _cart, setter );
5504
5505				setter.data( 'price', taxPrice );
5506				setter.data( 'pricew', taxPrice );
5507				setter.data( 'original_price', taxOriginalPrice );
5508				setter.data( 'original_pricew', taxOriginalPrice );
5509
5510				tm_update_price( {
5511					epoObject: epoObject,
5512					obj: setter.closest( '.tmcp-field-wrap' ).find( '.tc-price' ),
5513					price: tm_get_price( taxPrice, _cart, false, setter ),
5514					original_price: tm_get_price( taxOriginalPrice, _cart, false, setter ),
5515					force: false,
5516					useFormattedPrice: false
5517				} );
5518
5519				if ( hidden.length === 0 ) {
5520					realSetter.before( '<input type="hidden" id="' + id + hiddenName + '" name="' + id + hiddenName + '" value="' + tm_set_price_without_tax( price, _cart ) + '">' );
5521				}
5522				if ( setter.is( '.tm-epo-field.tmcp-radio' ) || setter.is( '.tm-epo-field.tmcp-checkbox' ) ) {
5523					if ( setter.is( ':checked' ) ) {
5524						hidden.val( tm_set_price_without_tax( price, _cart ) );
5525					}
5526				} else {
5527					hidden.val( tm_set_price_without_tax( price, _cart ) );
5528				}
5529			} else if ( setter.data( 'pricew' ) !== undefined ) {
5530				// Prices are already taxed
5531				tm_update_price( {
5532					epoObject: epoObject,
5533					obj: setter.closest( '.tmcp-field-wrap' ).find( '.tc-price' ),
5534					price: setter.data( 'pricew' ),
5535					original_price: ( setter.data( 'original_pricew' ) !== undefined ? setter.data( 'original_pricew' ) : setter.data( 'pricew' ) ),
5536					force: false,
5537					useFormattedPrice: false
5538				} );
5539			}
5540		} );
5541
5542		return {
5543			normal: [ total, originalTotal ],
5544			fees: [ totalFees, originalTotalFees ]
5545		};
5546	}
5547
5548	function tm_lazyload() {
5549		var container;
5550
5551		if ( TMEPOJS.tm_epo_no_lazy_load === 'yes' ) {
5552			return;
5553		}
5554
5555		if ( tmLazyloadContainer ) {
5556			container = $( tmLazyloadContainer ).find( 'img.tmlazy' );
5557		} else {
5558			container = $( tcAPI.epoSelector + ' img.tmlazy, .tc-styled-variations img.tmlazy' );
5559		}
5560
5561		container.lazyLoadXT();
5562		container.on( 'lazyshow', function() {
5563			jWindow.trigger( 'lazyLoadXToncomplete' );
5564		} );
5565	}
5566
5567	function tm_css_styles( obj ) {
5568		var $cart;
5569		var sliderSection;
5570
5571		if ( ! obj ) {
5572			return;
5573		}
5574
5575		$cart = $( '.cart' );
5576
5577		sliderSection = obj.find( '.tm-owl-slider-section' );
5578		if ( ! sliderSection.length ) {
5579			sliderSection = obj;
5580			if ( ! sliderSection.is( '.tc-repeater-section' ) ) {
5581				sliderSection = false;
5582			}
5583		}
5584
5585		if ( sliderSection ) {
5586			sliderSection.toArray().forEach( function( slider ) {
5587				slider = $( slider );
5588
5589				slider.find( '.tc-slider-content' ).addClass( 'tm-owl-slider' );
5590
5591				slider = slider.find( '.tm-owl-slider' );
5592				if ( slider.length ) {
5593					slider
5594						.addClass( 'tcowl-carousel-show' )
5595						.addClass( 'tcowl-carousel' )
5596						.on( 'changed.owl.carousel', function() {
5597							$cart.css( 'display', 'block' ).addClass( 'slider-setup' );
5598						} )
5599						.tmowlCarousel( Object.assign( {
5600							rtl: TMEPOJS.isRTL === '1',
5601							dots: false,
5602							nav: true,
5603							items: 1,
5604							autoHeight: true,
5605							mouseDrag: false,
5606							touchDrag: true,
5607							navText: [ TMEPOJS.i18n_prev_text, TMEPOJS.i18n_next_text ],
5608							navClass: [ 'owl-prev button', 'owl-next button' ],
5609							navElement: 'a',
5610							loop: false,
5611							navRewind: false
5612						}, window.tmowlCarouselSettings || {} ) );
5613
5614					slider.removeClass( 'tcowl-carousel-show' );
5615				}
5616			} );
5617		}
5618
5619		if ( $.fn.tcTabs ) {
5620			obj.find( '.tc-tabs' ).tcTabs( {
5621				headers: 'tc-tab-headers',
5622				header: 'tab-header',
5623				dataopenattribute: 'data-tab',
5624				sortabletabs: false
5625			} );
5626		}
5627	}
5628
5629	function repeaterAdd( el, elementInnerWrap ) {
5630		var cpf = elementInnerWrap.closest( '.cpf-element' );
5631		var maxRows = cpf.data( 'repeater-max-rows' );
5632		var minRows = cpf.data( 'repeater-min-rows' ) || 1;
5633		var repeater = elementInnerWrap.find( '.tc-repeater-element' );
5634		var rows = repeater.length;
5635		var repeaterLast = repeater.last();
5636		var repeaterLastUL = repeaterLast.find( '.tmcp-ul-wrap' );
5637		var clone;
5638		var cloneUl;
5639		var index = el.data( 'tc-repeater-init' );
5640
5641		if ( maxRows ) {
5642			if ( rows >= maxRows ) {
5643				return false;
5644			}
5645		}
5646
5647		if ( rows + 1 >= maxRows && el.is( '.tc-repeater-add' ) ) {
5648			el.closest( '.tc-repeater-wrap' ).addClass( 'tc-hidden' );
5649		}
5650
5651		if ( repeaterLastUL.is( '.tm-element-ul-date, .tm-element-ul-time' ) ) {
5652			repeaterLastUL.find( '.tm-epo-field' ).tm_datepicker( 'destroy' );
5653			repeaterLastUL.find( '.tmcp-date-select' ).off();
5654		}
5655		if ( repeaterLastUL.is( '.tm-element-ul-color' ) ) {
5656			repeaterLastUL.find( '.tm-epo-field' ).spectrum( 'destroy' );
5657		}
5658
5659		clone = repeaterLast.tcClone( true );
5660
5661		clone.find( '.tm-epo-field' ).attr( 'id', function( i, value ) {
5662			return value.replace( /\_\d+$/g, '' ) + '_' + index;
5663		} );
5664		clone.find( '[data-for]' ).attr( 'data-for', function( i, value ) {
5665			return value.replace( /\_\d+$/g, '' ) + '_' + index;
5666		} );
5667		clone.find( '[for]:not(:has(.tmcp-date-select))' ).attr( 'for', function( i, value ) {
5668			return value.replace( /\_\d+$/g, '' ) + '_' + index;
5669		} );
5670		clone.find( '[data-field-id]' ).attr( 'data-field-id', function( i, value ) {
5671			return value.replace( /\_\d+$/g, '' ) + '_' + index;
5672		} );
5673		clone.find( '[data-tm-date]' ).attr( 'data-tm-date', function( i, value ) {
5674			return value.replace( /\_\d+$/g, '' ) + '_' + index;
5675		} );
5676		clone.find( '.tmcp-date-select' ).attr( 'id', function( i, value ) {
5677			return $( this ).attr( 'data-tm-date' ) + '_' + value.substring( value.lastIndexOf( '_' ) + 1 );
5678		} );
5679		clone.find( '[for]:has(.tmcp-date-select)' ).attr( 'for', function( i, value ) {
5680			return $( this ).find( '.tmcp-date-select' ).attr( 'data-tm-date' ) + '_' + value.substring( value.lastIndexOf( '_' ) + 1 );
5681		} );
5682		clone.find( '.tm-epo-field' ).attr( 'name', function( i, value ) {
5683			return value.replace( /\[\d+\]/g, '[' + index + ']' );
5684		} );
5685		clone.find( '.tm-qty' ).attr( 'name', function( i, value ) {
5686			return value.replace( /\[\d+\]/g, '[' + index + ']' );
5687		} );
5688		clone.find( '.tmcp-date-select' ).attr( 'name', function( i, value ) {
5689			return value.replace( /\[\d+\]/g, '[' + index + ']' );
5690		} );
5691
5692		cloneUl = clone.find( '.tmcp-ul-wrap' );
5693
5694		if ( rows >= minRows && elementInnerWrap.find( '.tc-repeater-element' ).length >= 1 ) {
5695			elementInnerWrap.find( '.tc-repeater-delete' ).removeClass( 'tc-hidden' );
5696			clone.find( '.tc-repeater-delete' ).removeClass( 'tc-hidden' );
5697		}
5698
5699		if ( cloneUl.is( '.tm-element-ul-checkbox' ) ) {
5700			clone.find( 'li.tmcp-field-wrap' ).removeClass( 'tc-active' );
5701			clone
5702				.find( '.tm-epo-field.tmcp-checkbox' )
5703				.prop( 'checked', false );
5704			clone
5705				.find( '.tm-epo-field.tmcp-checkbox' )
5706				.filter( function( i, x ) {
5707					return $.inArray( $( x ).val(), el.data( 'repeater-init-value' ) ) !== -1;
5708				} )
5709				.prop( 'checked', true )
5710				.closest( 'li.tmcp-field-wrap' ).addClass( 'tc-active' );
5711		} else if ( cloneUl.is( '.tm-element-ul-radio' ) ) {
5712			clone.find( 'li.tmcp-field-wrap' ).removeClass( 'tc-active' );
5713			clone
5714				.find( '.tm-epo-field.tmcp-radio' )
5715				.filter( function( i, x ) {
5716					return $( x ).val() === el.data( 'repeater-init-value' );
5717				} )
5718				.prop( 'checked', true )
5719				.closest( 'li.tmcp-field-wrap' ).addClass( 'tc-active' );
5720		} else {
5721			clone.find( '.tm-epo-field' ).val( el.data( 'repeater-init-value' ) );
5722		}
5723
5724		if ( ! cloneUl.is( '.tm-element-ul-checkbox' ) && ! cloneUl.is( '.tm-element-ul-radio' ) ) {
5725			clone.find( '.tm-epo-field' ).val( el.data( 'repeater-init-value' ) );
5726		}
5727
5728		if ( cloneUl.is( '.tm-element-ul-upload' ) ) {
5729			clone.find( '.tc-upload-preview' ).remove();
5730			clone.find( '.tm-filename' ).remove();
5731		}
5732
5733		clone.find( '.tc-element-qty' ).toArray().forEach( function( elc ) {
5734			var qelc = $( elc );
5735			var defaultValue = qelc.attr( 'data-default-value' );
5736			qelc.val( defaultValue ).trigger( 'change' );
5737		} );
5738
5739		el.data( 'tc-repeater-init', el.data( 'tc-repeater-init' ) + 1 );
5740
5741		return [ clone, repeaterLast, repeaterLastUL ];
5742	}
5743
5744	function repeaterAddAfter( epoObject, clone, repeaterLastUL, doevents ) {
5745		var cloneUl = clone.find( '.tmcp-ul-wrap' );
5746
5747		if ( cloneUl.is( '.tm-element-ul-range' ) ) {
5748			clone.find( '.tm-range-picker' ).removeData( 'tc-picker-init' ).attr( 'class', 'tm-range-picker' ).html( '' );
5749			setRangePickers( clone );
5750		}
5751		if ( cloneUl.is( '.tm-element-ul-date, .tm-element-ul-time' ) ) {
5752			tm_set_datepicker( repeaterLastUL );
5753			tm_set_datepicker( cloneUl );
5754		}
5755		if ( cloneUl.is( '.tm-element-ul-color' ) ) {
5756			tm_set_color_pickers( repeaterLastUL );
5757			tm_set_color_pickers( cloneUl );
5758		}
5759		clone.find( '.tm-tooltip' ).removeData( 'tctooltip' ).removeData( 'tm-has-tm-tip' );
5760		$.tcToolTip( clone.find( '.tm-tooltip' ) );
5761
5762		//  apply specific field rules
5763		clone.find( '.tm-epo-field' )
5764			.removeData( 'addedtcEpoBeforeOptionPriceCalculation' )
5765			.toArray().forEach( function( elc ) {
5766				elc = $( elc );
5767				field_is_active( elc, false, true );
5768				if ( elc.is( '.tcenabled' ) ) {
5769					tm_element_epo_rules( epoObject, elc );
5770				}
5771				elc.on( 'tc_element_epo_rules', function() {
5772					tm_element_epo_rules( epoObject, elc );
5773				} );
5774			} );
5775		if ( ! doevents ) {
5776			return;
5777		}
5778		if ( cloneUl.is( '.tm-element-ul-checkbox' ) ) {
5779			clone
5780				.find( '.tm-epo-field.tmcp-checkbox' )
5781				.filter( ':checked' )
5782				.trigger( 'change.cpf' );
5783		} else if ( cloneUl.is( '.tm-element-ul-radio' ) ) {
5784			clone
5785				.find( '.tm-epo-field.tmcp-radio' )
5786				.filter( ':checked' )
5787				.trigger( 'change.cpf' );
5788		} else {
5789			clone.find( '.tm-epo-field' ).trigger( 'change.cpf' );
5790		}
5791	}
5792
5793	function repeaterDelete( elementInnerWrap, repeaterElement, repeaterObj, $this ) {
5794		var cpf = elementInnerWrap.closest( '.cpf-element' );
5795		var minRows = cpf.data( 'repeater-min-rows' );
5796		var rows = elementInnerWrap.find( '.tc-repeater-element' ).length;
5797		var repeaterElementIndex = repeaterElement.index();
5798		var message;
5799
5800		if ( minRows ) {
5801			if ( rows <= minRows ) {
5802				if ( $.tc_validator && $this ) {
5803					message = '<div class="tm-error-repeater tm-error tc-cell tcwidth tcwidth-100">' + $.tc_validator.messages.repeaterminrows( minRows ) + '</div>';
5804					$this.tcToolTip( { tip: message, onetime: true, trigger: true, tipclass: 'tc-error' } );
5805				}
5806				return false;
5807			}
5808		}
5809		if ( rows === 1 ) {
5810			return;
5811		}
5812		if ( rows === 2 || ( rows - 1 ) <= minRows ) {
5813			elementInnerWrap.find( '.tc-repeater-delete' ).addClass( 'tc-hidden' );
5814		}
5815		if ( repeaterObj.is( '.tc-repeater-add' ) ) {
5816			repeaterObj.closest( '.tc-repeater-wrap' ).removeClass( 'tc-hidden' );
5817		}
5818		repeaterElement.remove();
5819		repeaterObj.data( 'tc-repeater-init', repeaterObj.data( 'tc-repeater-init' ) - 1 );
5820		if ( repeaterElementIndex + 1 === rows ) {
5821			return;
5822		}
5823		elementInnerWrap.find( '.tc-repeater-element' )
5824			.toArray()
5825			.forEach( function( clone, index ) {
5826				clone = $( clone );
5827				clone.find( '.tm-epo-field' ).attr( 'id', function( i, value ) {
5828					return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' );
5829				} );
5830				clone.find( '[data-for]' ).attr( 'data-for', function( i, value ) {
5831					return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' );
5832				} );
5833				clone.find( '[for]:not(:has(.tmcp-date-select))' ).attr( 'for', function( i, value ) {
5834					return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' );
5835				} );
5836				clone.find( '[data-field-id]' ).attr( 'data-field-id', function( i, value ) {
5837					return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' );
5838				} );
5839				clone.find( '[data-tm-date]' ).attr( 'data-tm-date', function( i, value ) {
5840					return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' );
5841				} );
5842				clone.find( '.tmcp-date-select' ).attr( 'id', function( i, value ) {
5843					return $( this ).attr( 'data-tm-date' ) + '_' + value.substring( value.lastIndexOf( '_' ) + 1 );
5844				} );
5845				clone.find( '[for]:has(.tmcp-date-select)' ).attr( 'for', function( i, value ) {
5846					return $( this ).find( '.tmcp-date-select' ).attr( 'data-tm-date' ) + '_' + value.substring( value.lastIndexOf( '_' ) + 1 );
5847				} );
5848				clone.find( '.tm-epo-field' ).attr( 'name', function( i, value ) {
5849					return value.replace( /\[\d+\]/g, '[' + index + ']' );
5850				} );
5851				clone.find( '.tm-qty' ).attr( 'name', function( i, value ) {
5852					return value.replace( /\[\d+\]/g, '[' + index + ']' );
5853				} );
5854				clone.find( '.tmcp-date-select' ).attr( 'name', function( i, value ) {
5855					return value.replace( /\[\d+\]/g, '[' + index + ']' );
5856				} );
5857			} );
5858	}
5859
5860	function repeaterDeleteSection( elementInnerWrap, repeaterElement, repeaterObj, $this ) {
5861		var cpf = elementInnerWrap.closest( '.cpf-section' );
5862		var minRows = cpf.data( 'repeater-min-rows' );
5863		var rows = elementInnerWrap.find( '.tc-repeater-section' ).length;
5864		var repeaterElementIndex = repeaterElement.index();
5865		var message;
5866
5867		if ( minRows ) {
5868			if ( rows <= minRows ) {
5869				if ( $.tc_validator && $this ) {
5870					message = '<div class="tm-error-repeater tm-error tc-cell tcwidth tcwidth-100">' + $.tc_validator.messages.repeaterminrows( minRows ) + '</div>';
5871					$this.tcToolTip( { tip: message, onetime: true, trigger: true, tipclass: 'tc-error' } );
5872				}
5873				return false;
5874			}
5875		}
5876		if ( rows === 1 ) {
5877			return;
5878		}
5879		if ( rows === 2 || ( rows - 1 ) <= minRows ) {
5880			elementInnerWrap.find( '.tc-repeater-section-delete' ).addClass( 'tc-hidden' );
5881			elementInnerWrap.find( '.tc-repeater-section' ).removeClass( 'has-delete' );
5882			cpf.find( '.tcowl-carousel' ).trigger( 'refresh.owl.carousel' );
5883		}
5884		if ( repeaterObj.is( '.tc-section-repeater-add' ) ) {
5885			repeaterObj.closest( '.tc-repeater-wrap' ).removeClass( 'tc-hidden' );
5886		}
5887		repeaterElement.remove();
5888		repeaterObj.data( 'tc-repeater-init', repeaterObj.data( 'tc-repeater-init' ) - 1 );
5889		if ( repeaterElementIndex + 1 === rows ) {
5890			return;
5891		}
5892		elementInnerWrap.find( '.tc-repeater-section' )
5893			.toArray()
5894			.forEach( function( clone, index ) {
5895				clone = $( clone );
5896
5897				clone.find( '.tm-epo-field' ).attr( 'id', function( i, value ) {
5898					return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' );
5899				} );
5900				clone.find( '[data-for]' ).attr( 'data-for', function( i, value ) {
5901					return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' );
5902				} );
5903				clone.find( '[for]:not(:has(.tmcp-date-select))' ).attr( 'for', function( i, value ) {
5904					return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' );
5905				} );
5906				clone.find( '[data-field-id]' ).attr( 'data-field-id', function( i, value ) {
5907					return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' );
5908				} );
5909				clone.find( '[data-tm-date]' ).attr( 'data-tm-date', function( i, value ) {
5910					return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' );
5911				} );
5912				clone.find( '.tmcp-date-select' ).attr( 'id', function( i, value ) {
5913					return $( this ).attr( 'data-tm-date' ) + '_' + value.substring( value.lastIndexOf( '_' ) + 1 );
5914				} );
5915				clone.find( '[for]:has(.tmcp-date-select)' ).attr( 'for', function( i, value ) {
5916					return $( this ).find( '.tmcp-date-select' ).attr( 'data-tm-date' ) + '_' + value.substring( value.lastIndexOf( '_' ) + 1 );
5917				} );
5918				clone.find( '.tm-epo-field' ).attr( 'name', function( i, value ) {
5919					return value.replace( /\[\d+\]/g, '[' + index + ']' );
5920				} );
5921				clone.find( '.tm-qty' ).attr( 'name', function( i, value ) {
5922					return value.replace( /\[\d+\]/g, '[' + index + ']' );
5923				} );
5924				clone.find( '.tmcp-date-select' ).attr( 'name', function( i, value ) {
5925					return value.replace( /\[\d+\]/g, '[' + index + ']' );
5926				} );
5927			} );
5928	}
5929
5930	function repeaterAddSection( el, elementInnerWrap ) {
5931		var cpf = elementInnerWrap.closest( '.cpf-section' );
5932		var maxRows = cpf.data( 'repeater-max-rows' );
5933		var minRows = cpf.data( 'repeater-min-rows' ) || 1;
5934		var repeater = elementInnerWrap.find( '.tc-repeater-section' );
5935		var rows = repeater.length;
5936		var repeaterLast = repeater.last();
5937		var repeaterLastUL = repeaterLast.find( '.tmcp-ul-wrap' );
5938		var clone;
5939		var cloneUl;
5940		var index = el.data( 'tc-repeater-init' );
5941		var repeaterInitValue = el.data( 'repeater-init-value' );
5942
5943		if ( maxRows ) {
5944			if ( rows >= maxRows ) {
5945				return false;
5946			}
5947		}
5948
5949		if ( rows + 1 >= maxRows && el.is( '.tc-repeater-add' ) ) {
5950			el.closest( '.tc-repeater-wrap' ).addClass( 'tc-hidden' );
5951		}
5952
5953		repeaterLastUL.toArray().forEach( function( field ) {
5954			var rlul = $( field );
5955			if ( rlul.is( '.tm-element-ul-date, .tm-element-ul-time' ) ) {
5956				rlul.find( '.tm-epo-field' ).tm_datepicker( 'destroy' );
5957				rlul.find( '.tmcp-date-select' ).off();
5958			}
5959			if ( rlul.is( '.tm-element-ul-color' ) ) {
5960				rlul.find( '.tm-epo-field' ).spectrum( 'destroy' );
5961			}
5962		} );
5963
5964		clone = repeaterLast.tcClone( true );
5965
5966		clone.find( '.tm-epo-field' ).attr( 'id', function( i, value ) {
5967			return value.replace( /\_\d+$/g, '' ) + '_' + index;
5968		} );
5969		clone.find( '[data-for]' ).attr( 'data-for', function( i, value ) {
5970			return value.replace( /\_\d+$/g, '' ) + '_' + index;
5971		} );
5972		clone.find( '[for]:not(:has(.tmcp-date-select))' ).attr( 'for', function( i, value ) {
5973			return value.replace( /\_\d+$/g, '' ) + '_' + index;
5974		} );
5975		clone.find( '[data-field-id]' ).attr( 'data-field-id', function( i, value ) {
5976			return value.replace( /\_\d+$/g, '' ) + '_' + index;
5977		} );
5978		clone.find( '[data-tm-date]' ).attr( 'data-tm-date', function( i, value ) {
5979			return value.replace( /\_\d+$/g, '' ) + '_' + index;
5980		} );
5981		clone.find( '.tmcp-date-select' ).attr( 'id', function( i, value ) {
5982			return $( this ).attr( 'data-tm-date' ) + '_' + value.substring( value.lastIndexOf( '_' ) + 1 );
5983		} );
5984		clone.find( '[for]:has(.tmcp-date-select)' ).attr( 'for', function( i, value ) {
5985			return $( this ).find( '.tmcp-date-select' ).attr( 'data-tm-date' ) + '_' + value.substring( value.lastIndexOf( '_' ) + 1 );
5986		} );
5987		clone.find( '.tm-epo-field' ).attr( 'name', function( i, value ) {
5988			return value.replace( /\[\d+\]/g, '[' + index + ']' );
5989		} );
5990		clone.find( '.tm-qty' ).attr( 'name', function( i, value ) {
5991			return value.replace( /\[\d+\]/g, '[' + index + ']' );
5992		} );
5993		clone.find( '.tmcp-date-select' ).attr( 'name', function( i, value ) {
5994			return value.replace( /\[\d+\]/g, '[' + index + ']' );
5995		} );
5996
5997		cloneUl = clone.find( '.tmcp-ul-wrap' );
5998
5999		if ( rows >= minRows && elementInnerWrap.find( '.tc-repeater-section' ).length >= 1 ) {
6000			elementInnerWrap.find( '.tc-repeater-section-delete' ).removeClass( 'tc-hidden' );
6001			clone.find( '.tc-repeater-section-delete' ).removeClass( 'tc-hidden' );
6002			repeater.addClass( 'has-delete' );
6003			clone.addClass( 'has-delete' );
6004			cpf.find( '.tcowl-carousel' ).trigger( 'refresh.owl.carousel' );
6005		}
6006
6007		cloneUl.toArray().forEach( function( field ) {
6008			var cUl = $( field );
6009			if ( cUl.is( '.tm-element-ul-checkbox' ) ) {
6010				cUl.find( 'li.tmcp-field-wrap' ).removeClass( 'tc-active' );
6011				cUl
6012					.find( '.tm-epo-field.tmcp-checkbox' )
6013					.prop( 'checked', false );
6014				cUl
6015					.find( '.tm-epo-field.tmcp-checkbox' )
6016					.filter( function( i, x ) {
6017						var $field = $( x );
6018						var fieldId = $field.attr( 'id' ).replace( /_(\d+)$/, '' );
6019						return $.inArray( $field.val(), repeaterInitValue[ fieldId ] ) !== -1;
6020					} )
6021					.prop( 'checked', true )
6022					.closest( 'li.tmcp-field-wrap' ).addClass( 'tc-active' );
6023			} else if ( cUl.is( '.tm-element-ul-radio' ) ) {
6024				cUl.find( 'li.tmcp-field-wrap' ).removeClass( 'tc-active' );
6025				cUl
6026					.find( '.tm-epo-field.tmcp-radio' )
6027					.filter( function( i, x ) {
6028						var $field = $( x );
6029						var fieldId = $field.attr( 'id' ).replace( /_(\d+)$/, '' );
6030						return $field.val() === repeaterInitValue[ fieldId ];
6031					} )
6032					.prop( 'checked', true )
6033					.closest( 'li.tmcp-field-wrap' ).addClass( 'tc-active' );
6034			} else {
6035				cUl.find( '.tm-epo-field' ).each( function() {
6036					var $field = $( this );
6037					var fieldId = $field.attr( 'id' ).replace( /_(\d+)$/, '' );
6038					if ( repeaterInitValue.hasOwnProperty( fieldId ) ) {
6039						$field.val( repeaterInitValue[ fieldId ] );
6040					}
6041				} );
6042			}
6043
6044			if ( ! cUl.is( '.tm-element-ul-checkbox' ) && ! cUl.is( '.tm-element-ul-radio' ) ) {
6045				cUl.find( '.tm-epo-field' ).each( function() {
6046					var $field = $( this );
6047					var fieldId = $field.attr( 'id' ).replace( /_(\d+)$/, '' );
6048					if ( repeaterInitValue.hasOwnProperty( fieldId ) ) {
6049						$field.val( repeaterInitValue[ fieldId ] );
6050					}
6051				} );
6052			}
6053
6054			if ( cUl.is( '.tm-element-ul-upload' ) ) {
6055				cUl.find( '.tc-upload-preview' ).remove();
6056				cUl.find( '.tm-filename' ).remove();
6057			}
6058		} );
6059
6060		clone.find( '.tc-element-qty' ).toArray().forEach( function( elc ) {
6061			var qelc = $( elc );
6062			var defaultValue = qelc.attr( 'data-default-value' );
6063			qelc.val( defaultValue ).trigger( 'change' );
6064		} );
6065
6066		el.data( 'tc-repeater-init', el.data( 'tc-repeater-init' ) + 1 );
6067
6068		return [ clone, repeaterLast, repeaterLastUL ];
6069	}
6070
6071	function repeaterAddSectionAfter( epoObject, clone, repeaterLastUL, doevents ) {
6072		var cloneUl = clone.find( '.tmcp-ul-wrap' );
6073		var doDate;
6074		var doColor;
6075		cloneUl.toArray().forEach( function( field ) {
6076			var cUL = $( field );
6077			if ( cUL.is( '.tm-element-ul-range' ) ) {
6078				cUL.find( '.tm-range-picker' ).removeData( 'tc-picker-init' ).attr( 'class', 'tm-range-picker' ).html( '' );
6079				setRangePickers( cUL );
6080			}
6081			if ( cUL.is( '.tm-element-ul-date, .tm-element-ul-time' ) ) {
6082				doDate = true;
6083				tm_set_datepicker( cUL );
6084			}
6085			if ( cUL.is( '.tm-element-ul-color' ) ) {
6086				doColor = true;
6087				tm_set_color_pickers( cUL );
6088			}
6089			if ( doevents ) {
6090				if ( cUL.is( '.tm-element-ul-checkbox' ) ) {
6091					cUL
6092						.find( '.tm-epo-field.tmcp-checkbox' )
6093						.filter( ':checked' )
6094						.trigger( 'change.cpf' );
6095				} else if ( cUL.is( '.tm-element-ul-radio' ) ) {
6096					cUL
6097						.find( '.tm-epo-field.tmcp-radio' )
6098						.filter( ':checked' )
6099						.trigger( 'change.cpf' );
6100				} else {
6101					cUL.find( '.tm-epo-field' ).trigger( 'change.cpf' );
6102				}
6103			}
6104		} );
6105		if ( doDate ) {
6106			tm_set_datepicker( repeaterLastUL );
6107		}
6108		if ( doColor ) {
6109			tm_set_color_pickers( repeaterLastUL );
6110		}
6111
6112		clone.find( '.tm-tooltip' ).removeData( 'tctooltip' ).removeData( 'tm-has-tm-tip' );
6113		$.tcToolTip( clone.find( '.tm-tooltip' ) );
6114
6115		//  apply specific field rules
6116		clone.find( '.tm-epo-field' )
6117			.removeData( 'addedtcEpoBeforeOptionPriceCalculation' )
6118			.toArray().forEach( function( elc ) {
6119				elc = $( elc );
6120				field_is_active( elc, false, true );
6121				if ( elc.is( '.tcenabled' ) ) {
6122					tm_element_epo_rules( epoObject, elc );
6123				}
6124				elc.on( 'tc_element_epo_rules', function() {
6125					tm_element_epo_rules( epoObject, elc );
6126				} );
6127			} );
6128		clone.find( '.tc-tabs' ).removeData( 'tctabs' );
6129		clone.find( '.tcowl-carousel' ).removeData( 'owl.carousel' );
6130		clone.find( '.owl-nav, .owl-dots' ).remove();
6131		tm_css_styles( clone );
6132	}
6133
6134	function tm_set_repeaters( obj, epoObject ) {
6135		var currentCart;
6136		var qtyElement;
6137		var quantityRepeaters;
6138		var sectionQuantityRepeaters;
6139		if ( ! obj ) {
6140			return;
6141		}
6142		obj = $( obj );
6143
6144		if ( obj.length ) {
6145			currentCart = epoObject.main_cart;
6146			qtyElement = getQtyElement( currentCart );
6147			qtyElement = $.epoAPI.applyFilter( 'qtyElementForRepeaterQuantity', qtyElement, {
6148				epo: epoObject,
6149				currentCart: currentCart,
6150				obj: obj,
6151				qtyElement: qtyElement
6152			} );
6153			quantityRepeaters = obj.find( '.tc-repeater-quantity' );
6154			quantityRepeaters
6155				.toArray()
6156				.forEach( function( repeater, qx ) {
6157					var el = $( repeater );
6158					var tmEpoField;
6159					var repeaterElement;
6160					var length;
6161					var elementInnerWrap;
6162					var maxRows = el.data( 'repeater-max-rows' );
6163
6164					if ( el.data( 'tc-repeater-init' ) ) {
6165						return;
6166					}
6167					repeaterElement = el.find( '.tc-repeater-element' );
6168					length = repeaterElement.length;
6169					tmEpoField = repeaterElement.first().find( '.tm-epo-field' );
6170					if ( tmEpoField.is( ':checkbox' ) ) {
6171						el.data( 'repeater-init-value',
6172							tmEpoField.filter( ':checked' ).toArray().map( function( x ) {
6173								return $( x ).val();
6174							} ) );
6175					} else if ( tmEpoField.is( ':radio' ) ) {
6176						el.data( 'repeater-init-value', tmEpoField.filter( ':checked' ).val() );
6177					} else {
6178						el.data( 'repeater-init-value', tmEpoField.val() );
6179					}
6180					el.data( 'tc-repeater-init', length );
6181					el.data( 'tc-repeater-name', tmEpoField.attr( 'name' ) );
6182
6183					if ( qtyElement.length ) {
6184						elementInnerWrap = el.find( '.tc-element-inner-wrap' );
6185						qtyElement
6186							.off( 'change.r' + qx + 'cpf input.r' + qx + 'cpf' )
6187							.on( 'change.r' + qx + 'cpf input.r' + qx + 'cpf', function( event ) {
6188								var field = $( this );
6189								var prevValue = field.data( 'epopreviousvalue' );
6190								var value = $.epoAPI.applyFilter( 'qtyElementForRepeaterQuantityValue', field.val(), {
6191									epo: epoObject,
6192									currentCart: currentCart,
6193									obj: obj,
6194									qtyElement: qtyElement,
6195									field: field
6196								} );
6197								var difference = value - prevValue;
6198								var thisRepeaterElement;
6199								var i;
6200								var ele;
6201								var cloned;
6202								var repeaterLastUL;
6203								var fieldprevval;
6204								if ( prevValue === undefined ) {
6205									prevValue = value - 1;
6206									difference = value - prevValue;
6207								}
6208								if ( event.isTrigger !== undefined ) {
6209									prevValue = el.find( '.tc-element-inner-wrap' ).find( '.tc-repeater-element' ).length;
6210									difference = value - prevValue;
6211								}
6212								if ( maxRows && difference > maxRows ) {
6213									difference = maxRows - 1;
6214								}
6215								if ( difference === 0 ) {
6216									return;
6217								}
6218								fieldprevval = $.epoAPI.applyFilter( 'qtyElementForRepeaterQuantity_epopreviousvalue', field.val(), {
6219									epo: epoObject,
6220									currentCart: currentCart,
6221									obj: obj,
6222									qtyElement: qtyElement,
6223									field: field
6224								} );
6225								if ( fieldprevval <= 0 ) {
6226									fieldprevval = 1;
6227								}
6228								if ( qx === quantityRepeaters.length ) {
6229									field.data( 'epopreviousvalue', fieldprevval );
6230								}
6231								if ( difference > 0 ) {
6232									thisRepeaterElement = elementInnerWrap.find( '.tc-repeater-element' ).eq( value - 1 );
6233									if ( thisRepeaterElement.length ) {
6234										return;
6235									}
6236									for ( i = 0; i < difference; i++ ) {
6237										cloned = repeaterAdd( el, elementInnerWrap );
6238										if ( cloned ) {
6239											if ( ele ) {
6240												ele = ele.add( cloned[ 0 ] );
6241											} else {
6242												ele = cloned[ 0 ];
6243											}
6244											if ( i === 0 ) {
6245												repeaterLastUL = cloned[ 2 ];
6246											}
6247										}
6248									}
6249									if ( ele ) {
6250										ele.appendTo( elementInnerWrap.find( '.tc-element-container' ) );
6251										repeaterAddAfter( epoObject, ele, repeaterLastUL );
6252									}
6253								} else {
6254									for ( i = value - difference; i > value; i -= 1 ) {
6255										thisRepeaterElement = elementInnerWrap.find( '.tc-repeater-element' ).eq( i - 1 );
6256										repeaterDelete( elementInnerWrap, thisRepeaterElement, el );
6257									}
6258								}
6259								currentCart.trigger( {
6260									type: 'tm-epo-update',
6261									norules: 2
6262								} );
6263							} );
6264						qtyElement.data( 'epopreviousvalue', $.epoAPI.applyFilter( 'qtyElementForRepeaterQuantityValue', qtyElement.val(), {
6265							epo: epoObject,
6266							currentCart: currentCart,
6267							obj: obj,
6268							qtyElement: qtyElement,
6269							field: qtyElement
6270						} ) ).trigger( 'change' );
6271					}
6272				} );
6273
6274			obj.find( '.tc-repeater-add' )
6275				.toArray()
6276				.forEach( function( repeater ) {
6277					var el = $( repeater );
6278					var tmEpoField;
6279					var elementInnerWrap;
6280					var repeaterElement;
6281					var length;
6282					if ( el.data( 'tc-repeater-init' ) ) {
6283						return;
6284					}
6285					elementInnerWrap = el.closest( '.tc-element-inner-wrap' );
6286					repeaterElement = elementInnerWrap.find( '.tc-repeater-element' );
6287					length = repeaterElement.length;
6288					tmEpoField = repeaterElement.first().find( '.tm-epo-field' );
6289					if ( elementInnerWrap.find( '.tc-repeater-element' ).length > 1 ) {
6290						elementInnerWrap.find( '.tc-repeater-delete' ).removeClass( 'tc-hidden' );
6291					}
6292					if ( tmEpoField.is( ':checkbox' ) ) {
6293						el.data( 'repeater-init-value',
6294							tmEpoField.filter( ':checked' ).toArray().map( function( x ) {
6295								return $( x ).val();
6296							} ) );
6297					} else if ( tmEpoField.is( ':radio' ) ) {
6298						el.data( 'repeater-init-value', tmEpoField.filter( ':checked' ).val() );
6299					} else {
6300						el.data( 'repeater-init-value', tmEpoField.val() );
6301					}
6302					el.data( 'tc-repeater-init', length );
6303					el.data( 'tc-repeater-name', tmEpoField.attr( 'name' ) );
6304
6305					el.on( 'click.repeater', function() {
6306						var ele = repeaterAdd( el, elementInnerWrap );
6307						if ( ele ) {
6308							ele[ 0 ].appendTo( elementInnerWrap.find( '.tc-element-container' ) );
6309							repeaterAddAfter( epoObject, ele[ 0 ], ele[ 2 ], true );
6310						}
6311					} );
6312				} );
6313
6314			obj.find( '.tc-repeater-delete .delete' ).on( 'click', function() {
6315				var $this = $( this );
6316				var elementInnerWrap = $this.closest( '.tc-element-inner-wrap' );
6317				var repeaterElement = $this.closest( '.tc-repeater-element' );
6318				repeaterDelete( elementInnerWrap, repeaterElement, elementInnerWrap.find( '.tc-repeater-add' ), $this );
6319				epoObject.form.trigger( {
6320					type: 'tm-epo-update',
6321					norules: 2
6322				} );
6323			} );
6324
6325			obj.find( '.tc-section-repeater-add' )
6326				.toArray()
6327				.forEach( function( repeater ) {
6328					var el = $( repeater );
6329					var tmEpoField;
6330					var elementInnerWrap;
6331					var repeaterElement;
6332					var length;
6333					var fieldData = [];
6334					if ( el.data( 'tc-repeater-init' ) ) {
6335						return;
6336					}
6337					elementInnerWrap = el.closest( '.tc-section-inner-wrap' );
6338					repeaterElement = elementInnerWrap.find( '.tc-repeater-section' );
6339					length = repeaterElement.length;
6340					tmEpoField = elementInnerWrap.find( '.sections_repeater' );
6341					if ( elementInnerWrap.find( '.tc-repeater-section' ).length > 1 ) {
6342						elementInnerWrap.find( '.tc-section-repeater-delete' ).removeClass( 'tc-hidden' );
6343					}
6344					repeaterElement.first().find( '.tm-epo-field' )
6345						.toArray()
6346						.forEach( function( field ) {
6347							var epofield = $( field );
6348							var id = epofield.attr( 'id' );
6349							if ( epofield.is( ':checkbox' ) ) {
6350								fieldData[ id ] = epofield.filter( ':checked' ).toArray().map( function( x ) {
6351									return $( x ).val();
6352								} );
6353							} else if ( epofield.is( ':radio' ) ) {
6354								fieldData[ id ] = epofield.filter( ':checked' ).val();
6355							} else {
6356								fieldData[ id ] = epofield.val();
6357							}
6358						} );
6359					el.data( 'repeater-init-value', fieldData );
6360
6361					el.data( 'tc-repeater-init', length );
6362					el.data( 'tc-repeater-name', tmEpoField.attr( 'name' ) );
6363
6364					el.on( 'click.repeater', function() {
6365						var ele = repeaterAddSection( el, elementInnerWrap );
6366						if ( ele ) {
6367							ele[ 1 ].after( ele[ 0 ] );
6368							repeaterAddSectionAfter( epoObject, ele[ 0 ], ele[ 2 ], true );
6369							tmEpoField.val( function( i, currentValue ) {
6370								return currentValue ? parseInt( currentValue, 10 ) + 1 : 2;
6371							} );
6372						}
6373					} );
6374				} );
6375
6376			sectionQuantityRepeaters = obj.find( '.tc-section-repeater-quantity' );
6377			sectionQuantityRepeaters
6378				.toArray()
6379				.forEach( function( repeater, qx ) {
6380					var el = $( repeater );
6381					var tmEpoField;
6382					var elementInnerWrap;
6383					var repeaterElement;
6384					var length;
6385					var fieldData = [];
6386					var maxRows = el.closest( '.cpf-section' ).data( 'repeater-max-rows' );
6387					if ( el.data( 'tc-repeater-init' ) ) {
6388						return;
6389					}
6390					elementInnerWrap = el.find( '.tc-section-inner-wrap' );
6391					repeaterElement = elementInnerWrap.find( '.tc-repeater-section' );
6392					length = repeaterElement.length;
6393					tmEpoField = elementInnerWrap.find( '.sections_repeater' );
6394					repeaterElement.first().find( '.tm-epo-field' )
6395						.toArray()
6396						.forEach( function( field ) {
6397							var epofield = $( field );
6398							var id = epofield.attr( 'id' );
6399							if ( epofield.is( ':checkbox' ) ) {
6400								fieldData[ id ] = epofield.filter( ':checked' ).toArray().map( function( x ) {
6401									return $( x ).val();
6402								} );
6403							} else if ( epofield.is( ':radio' ) ) {
6404								fieldData[ id ] = epofield.filter( ':checked' ).val();
6405							} else {
6406								fieldData[ id ] = epofield.val();
6407							}
6408						} );
6409					el.data( 'repeater-init-value', fieldData );
6410
6411					el.data( 'tc-repeater-init', length );
6412					el.data( 'tc-repeater-name', tmEpoField.attr( 'name' ) );
6413
6414					if ( qtyElement.length ) {
6415						qtyElement
6416							.off( 'change.rs' + qx + 'cpf input.rs' + qx + 'cpf' )
6417							.on( 'change.rs' + qx + 'cpf input.rs' + qx + 'cpf', function( event ) {
6418								var field = $( this );
6419								var prevValue = field.data( 'epopreviousvalue' + qx );
6420								var value = $.epoAPI.applyFilter( 'qtyElementForRepeaterQuantityValue', field.val(), {
6421									epo: epoObject,
6422									currentCart: currentCart,
6423									obj: obj,
6424									qtyElement: qtyElement,
6425									field: field
6426								} );
6427								var difference = value - prevValue;
6428								var thisRepeaterElement;
6429								var i;
6430								var ele;
6431								var cloned;
6432								var repeaterLastUL;
6433								var fieldprevval;
6434								var firstcloned;
6435								if ( prevValue === undefined ) {
6436									prevValue = value - 1;
6437									difference = value - prevValue;
6438								}
6439								if ( event.isTrigger !== undefined ) {
6440									prevValue = el.find( '.tc-section-inner-wrap' ).find( '.tc-repeater-section' ).length;
6441									difference = value - prevValue;
6442								}
6443								if ( maxRows && difference > maxRows ) {
6444									difference = maxRows - 1;
6445								}
6446								if ( difference === 0 ) {
6447									return;
6448								}
6449								fieldprevval = $.epoAPI.applyFilter( 'qtyElementForRepeaterQuantity_epopreviousvalue', field.val(), {
6450									epo: epoObject,
6451									currentCart: currentCart,
6452									obj: obj,
6453									qtyElement: qtyElement,
6454									field: field
6455								} );
6456								if ( fieldprevval <= 0 ) {
6457									fieldprevval = 1;
6458								}
6459								if ( qx === quantityRepeaters.length ) {
6460									field.data( 'epopreviousvalue' + qx, fieldprevval );
6461								}
6462								if ( difference > 0 ) {
6463									thisRepeaterElement = elementInnerWrap.find( '.tc-repeater-section' ).eq( value - 1 );
6464									if ( thisRepeaterElement.length ) {
6465										return;
6466									}
6467									for ( i = 0; i < difference; i++ ) {
6468										cloned = repeaterAddSection( el, elementInnerWrap );
6469										if ( cloned ) {
6470											if ( ! firstcloned ) {
6471												firstcloned = cloned;
6472											}
6473											if ( ele ) {
6474												ele = ele.add( cloned[ 0 ] );
6475											} else {
6476												ele = cloned[ 0 ];
6477											}
6478											if ( i === 0 ) {
6479												repeaterLastUL = cloned[ 2 ];
6480											}
6481										}
6482									}
6483									if ( ele ) {
6484										tmEpoField.val( function( ii, currentValue ) {
6485											return currentValue ? parseInt( currentValue, 10 ) + parseInt( difference, 10 ) : 2;
6486										} );
6487										
6487firstcloned[ 1 ].after( ele );
6488										repeaterAddSectionAfter( epoObject, ele, repeaterLastUL );
6489									}
6490								} else {
6491									for ( i = value - difference; i > value; i -= 1 ) {
6492										thisRepeaterElement = elementInnerWrap.find( '.tc-repeater-section' ).eq( i - 1 );
6493										repeaterDeleteSection( elementInnerWrap, thisRepeaterElement, el );
6494									}
6495									tmEpoField.val( elementInnerWrap.find( '.tc-repeater-section' ).length );
6496								}
6497								currentCart.trigger( {
6498									type: 'tm-epo-update',
6499									norules: 2
6500								} );
6501							} );
6502						qtyElement.data( 'epopreviousvalue' + qx, $.epoAPI.applyFilter( 'qtyElementForRepeaterQuantityValue', qtyElement.val(), {
6503							epo: epoObject,
6504							currentCart: currentCart,
6505							obj: obj,
6506							qtyElement: qtyElement,
6507							field: qtyElement
6508						} ) ).trigger( 'change' );
6509					}
6510				} );
6511
6512			obj.find( '.tc-repeater-section-delete .delete' ).on( 'click', function() {
6513				var $this = $( this );
6514				var elementInnerWrap = $this.closest( '.tc-section-inner-wrap' );
6515				var repeaterElement = $this.closest( '.tc-repeater-section' );
6516				var tmEpoField;
6517				tmEpoField = elementInnerWrap.find( '.sections_repeater' );
6518				repeaterDeleteSection( elementInnerWrap, repeaterElement, elementInnerWrap.find( '.tc-section-repeater-add' ), $this );
6519				tmEpoField.val( function( ii, currentValue ) {
6520					return currentValue ? parseInt( currentValue, 10 ) - 1 : 2;
6521				} );
6522				epoObject.form.trigger( {
6523					type: 'tm-epo-update',
6524					norules: 2
6525				} );
6526			} );
6527		}
6528	}
6529
6530	function tm_set_color_pickers( obj ) {
6531		if ( ! obj ) {
6532			return;
6533		}
6534		obj = $( obj ).find( '.tm-color-picker' );
6535		if ( obj.length ) {
6536			obj.spectrum( {
6537				type: 'color',
6538				theme: 'epo',
6539				showButtons: true,
6540				allowEmpty: true,
6541				showInitial: true,
6542				showInput: true,
6543				clickoutFiresChange: false,
6544				chooseText: TMEPOJS.closeText,
6545				cancelText: TMEPOJS.i18n_cancel,
6546				clearText: ''
6547			} );
6548			obj.spectrum( 'enable' );
6549		}
6550	}
6551
6552	function tm_set_lightbox( obj ) {
6553		if ( ! obj ) {
6554			return;
6555		}
6556		if ( $( obj ).length ) {
6557			// document ready
6558			$( function() {
6559				$( obj ).tclightbox();
6560			} );
6561		}
6562	}
6563
6564	function has_active_changes_product_image( field ) {
6565		var uic = field.closest( '.tmcp-field-wrap' ).find( 'label img' );
6566		var src = $( uic ).first().attr( 'data-original' );
6567
6568		if ( field.is( 'select.tm-product-image' ) ) {
6569			field = field.children( 'option:selected' );
6570		}
6571
6572		if ( ! src ) {
6573			src = $( uic ).first().attr( 'src' );
6574		}
6575		if ( ! src ) {
6576			src = field.attr( 'data-image' );
6577		}
6578		if ( field.attr( 'data-imagep' ) ) {
6579			src = field.attr( 'data-imagep' );
6580		}
6581		if ( src ) {
6582			return true;
6583		}
6584
6585		return false;
6586	}
6587
6588	function tm_set_upload_fields( epoObject ) {
6589		var field;
6590		var dT;
6591		var name;
6592		var file;
6593		var selector = epoObject.is_associated
6594			? epoObject.this_epo_container.find( '.tm-epo-field.tmcp-upload' )
6595			: epoObject.this_epo_container.find( '.tm-epo-field.tmcp-upload' ).not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-epo-field.tmcp-upload' );
6596
6597		try {
6598			selector
6599				.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-epo-field.tmcp-upload' )
6600				.toArray()
6601				.forEach( function( el ) {
6602					var dataFiles;
6603					var dataFilename;
6604					file = [];
6605					field = $( el );
6606					if ( field.attr( 'data-file' ) === '' ) {
6607						return false;
6608					}
6609					dataFiles = field.attr( 'data-file' ).split( '|' );
6610					if ( dataFiles.length === 0 ) {
6611						return false;
6612					}
6613					if ( ClipboardEvent || DataTransfer ) {
6614						dT = new ClipboardEvent( '' ).clipboardData || new DataTransfer();
6615					}
6616					dataFiles.forEach( function( dataFile ) {
6617						dataFilename = $.epoAPI.util.basename( dataFile );
6618						if ( ClipboardEvent || DataTransfer ) {
6619							dT.items.add( new File( [ dataFile ], dataFilename ) );
6620						}
6621						file.push( dataFile );
6622					} );
6623					if ( dT ) {
6624						el.files = dT.files;
6625					}
6626					file = file.join( '|' );
6627					name = field.attr( 'name' );
6628					field.trigger( 'tcupload' );
6629					field.after( '<input type="hidden" class="tmcp-upload-hidden" name="' + name + '" value="' + file + '">' );
6630					field.removeAttr( 'data-file' );
6631				} );
6632		} catch ( err ) {
6633			window.console.log( err );
6634			$( '.tm-epo-field.tmcp-upload' ).not( '.tm-multiple-file-upload' ).addClass( 'tc-nodt' );
6635			errorObject = err;
6636		}
6637	}
6638
6639	function tm_set_upload_rules( epoObject ) {
6640		var epoEventId = epoObject.epoEventId;
6641		var this_epo_container = epoObject.this_epo_container;
6642
6643		if ( TMEPOJS.tm_epo_upload_popup === 'yes' ) {
6644			$.tcepo.formSubmitEvents[ epoEventId ][ $.tcepo.formSubmitEvents[ epoEventId ].length ] = {
6645				trigger: function() {
6646					return true;
6647				},
6648				on_true: function() {
6649					var upload_fields = this_epo_container.data( 'num_uploads' );
6650					var thisPopup;
6651					var ajaxSuccessFunc;
6652					if ( upload_fields && Object.keys( upload_fields ).length ) {
6653						thisPopup = $.tcFloatBox( {
6654							fps: 1,
6655							ismodal: true,
6656							width: '50%',
6657							height: '300px',
6658							classname: 'flasho tc-wrapper',
6659							data: $.epoAPI.template.html( tcAPI.templateEngine.tc_upload_messages, {
6660								files: upload_fields,
6661								title: TMEPOJS.i18n_uploading_files,
6662								message: TMEPOJS.i18n_uploading_message
6663							} )
6664						} );
6665						ajaxSuccessFunc = function() {
6666							thisPopup.destroy();
6667							jDocument.off( 'ajaxSuccess', ajaxSuccessFunc );
6668						};
6669						jDocument.on( 'ajaxSuccess', ajaxSuccessFunc );
6670					}
6671
6672					return true;
6673				},
6674				on_false: function() {
6675					return true;
6676				}
6677			};
6678		}
6679	}
6680
6681	function tm_set_expanables() {
6682		var obj = $( '.tc-expand' );
6683		obj.toArray().forEach( function( o ) {
6684			var el = $( o );
6685			var max = parseInt( el.attr( 'data-max-items' ), 10 );
6686			var ul = el.find( '.tmcp-ul-wrap' );
6687			var gap = ul.css( 'gap' ) || ul.css( 'row-gap' );
6688			var lis = ul.find( '> li' );
6689			var lisMax = lis.slice( 0, max );
6690			var height;
6691			var totalHeight;
6692			if ( lisMax.length ) {
6693				totalHeight = lis.toArray()
6694					.reduce( function( sum, element ) {
6695						return sum + $( element ).outerHeight( true );
6696					}, 0 );
6697				totalHeight = 'calc(100px + ' + totalHeight + 'px + (' + gap + ' * (' + max + ' - 1) ) )';
6698				height = lisMax.toArray()
6699					.reduce( function( sum, element ) {
6700						return sum + $( element ).outerHeight( true );
6701					}, 0 );
6702				height = 'calc(' + height + 'px + (' + gap + ' * (' + max + ' - 1) ) )';
6703				ul.css( 'max-height', height );
6704				ul.after( $( '<button type="button" data-height="' + height + '" data-total-height="' + totalHeight + '" class="button load-more-button">Load more</button>' ) );
6705			}
6706		} );
6707		jDocument.on( 'click.txexpand', '.load-more-button', function() {
6708			var b = $( this );
6709			var h;
6710			if ( b.is( '.expanded' ) ) {
6711				b.removeClass( 'expanded' );
6712			} else {
6713				b.addClass( 'expanded' );
6714			}
6715			h = b.is( '.expanded' ) ? $( this ).attr( 'data-total-height' ) : $( this ).attr( 'data-height' );
6716			b.prev().css( 'max-height', h );
6717		} );
6718	}
6719
6720	function tm_set_checkboxes_rules( epoObject ) {
6721		var this_epo_container = epoObject.this_epo_container;
6722		var main_product = epoObject.main_product;
6723		var epoEventId = epoObject.epoEventId;
6724		var limit_cont = this_epo_container.find( '.tm-limit' );
6725		var exactlimit_cont = this_epo_container.find( '.tm-exactlimit' );
6726		var minimumlimit_cont = this_epo_container.find( '.tm-minimumlimit' );
6727
6728		// Limit checkbox selection
6729		this_epo_container.on( 'change.cpflimit', 'input.tm-epo-field.tmcp-checkbox', function() {
6730			var $this = $( this );
6731			tm_limit_c_selection( $this, true );
6732			tm_exact_c_selection( $this, true );
6733		} );
6734		if ( limit_cont.length ) {
6735			tm_check_limit_cont( limit_cont, main_product, epoEventId );
6736		}
6737
6738		// Exact value checkbox check (Todo:check for isvisible)
6739		if ( exactlimit_cont.length ) {
6740			tm_check_exactlimit_cont( exactlimit_cont, main_product, epoEventId );
6741		}
6742
6743		// Minimum number checkbox check (Todo:check for isvisible)
6744		if ( minimumlimit_cont.length ) {
6745			tm_check_minimumlimit_cont( minimumlimit_cont, epoEventId );
6746		}
6747	}
6748
6749	function tm_theme_specific_actions( epoObject ) {
6750		var this_epo_container = epoObject.this_epo_container;
6751		var theme_name = TMEPOJS.theme_name;
6752		var all_epo_selects;
6753		var blaszok_selects;
6754
6755		if ( theme_name ) {
6756			theme_name = theme_name.toLowerCase();
6757			all_epo_selects = this_epo_container.find( 'select' );
6758
6759			switch ( theme_name ) {
6760				case 'flatsome':
6761				case 'flatsome-child':
6762				case 'flatsome child':
6763					all_epo_selects.wrap( '<div class="custom select-wrapper"/>' );
6764					break;
6765
6766				case 'avada':
6767				case 'avada-child':
6768				case 'avada child':
6769					all_epo_selects.wrap( '<div class="avada-select-parent tm-select-parent"></div>' );
6770					$( '<div class="select-arrow">&#xe61f;</div>' ).appendTo( this_epo_container.find( '.tm-select-parent' ) );
6771					if ( window.calc_select_arrow_dimensions ) {
6772						window.calc_select_arrow_dimensions();
6773						jWindow.on( 'tmsectionpoplink cpflogicdone', function() {
6774							window.calc_select_arrow_dimensions();
6775						} );
6776					} else if ( window.calcSelectArrowDimensions ) {
6777						window.calcSelectArrowDimensions();
6778						jWindow.on( 'tmsectionpoplink cpflogicdone', function() {
6779							window.calcSelectArrowDimensions();
6780						} );
6781					}
6782					break;
6783
6784				case 'bazar':
6785				case 'bazar-child':
6786				case 'bazar child':
6787					all_epo_selects.wrap( '<div class="tm-select-wrapper select-wrapper"/>' );
6788					break;
6789
6790				case 'blaszok':
6791				case 'blaszok-child':
6792				case 'blaszok child':
6793					blaszok_selects = function() {
6794						setTimeout( function() {
6795							$( '.tm-extra-product-options select' )
6796								.not( '.hasCustomSelect' )
6797								.filter( ':visible' )
6798								.toArray().forEach( function( el ) {
6799									el = $( el );
6800									if ( ! el.is( '.mpcthSelect' ) ) {
6801										el.width( el.outerWidth() );
6802										el.customSelect( { customClass: 'mpcthSelect' } );
6803									}
6804								} );
6805						}, 100 );
6806					};
6807					jWindow.on( 'cpflogicrun', function() {
6808						blaszok_selects();
6809					} );
6810					jWindow.on( 'epo_options_visible', function() {
6811						blaszok_selects();
6812					} );
6813
6814					break;
6815
6816				case 'handmade':
6817				case 'handmade child theme':
6818					$( '.tm-owl-slider.tcowl-carousel' ).addClass( 'manual' );
6819					break;
6820			}
6821
6822			jWindow.trigger( 'tm-theme-specific-actions', {
6823				epo: {
6824					theme_name: theme_name,
6825					all_epo_selects: all_epo_selects
6826				}
6827			} );
6828		}
6829
6830		// Fix added +/- quantity button on most themes.
6831		jDocument.off( 'click.cpf', '.quantity:not(.buttons_added) .minus, .quantity:not(.buttons_added) .plus' ).on( 'click.cpf', '.quantity:not(.buttons_added) .minus, .quantity:not(.buttons_added) .plus', function() {
6832			$( this ).closest( '.quantity' ).find( tcAPI.qtySelector ).trigger( 'change.cpf' );
6833		} );
6834	}
6835
6836	function tm_custom_variations( epoObject, form, item_id, $main_product, $epo_holder ) {
6837		var epoEventId = epoObject.epoEventId;
6838		var variation_id_selector = "input[name^='variation_id']";
6839		var tm_epo_variation_section;
6840		var li_variations;
6841		var composite_load_test;
6842		var form_event;
6843		var type;
6844		var name;
6845		var selector;
6846		var func;
6847		var i;
6848		var eventName = epoObject.is_associated ? 'tc_variation_form.tmlogic' : 'wc_variation_form.tmlogic';
6849		var eventNamePrefix = epoObject.is_associated ? 'tc_' : '';
6850		var variationsForm = epoObject.variations_form;
6851		var variationsTable = epoObject.is_associated ? variationsForm.find( '.tc-epo-element-variations' ) : variationsForm.find( '.variations' );
6852		var resetSelector = epoObject.is_associated ? '.tc-epo-element-variable-reset-variations' : '.reset_variations';
6853
6854		variationsForm.attr( 'data-epo_id', epoObject.epo_id );
6855
6856		if ( form.find( 'input.variation_id' ).length > 0 ) {
6857			variation_id_selector = 'input.variation_id';
6858		}
6859		if ( $epo_holder.find( '.tm-epo-variation-element' ).length || $epo_holder.data( 'tm-epo-variation-element' ) ) {
6860			tm_epo_variation_section = $epo_holder.find( '.tm-epo-variation-section' ).first();
6861			tm_epo_variation_section.find( '.cpf-type-variations' ).attr( 'data-epo_id', epoObject.epo_id ).attr( 'data-product_id', variationsForm.attr( 'data-product_id' ) );
6862
6863			$epo_holder.data( 'tm-epo-variation-element', tm_epo_variation_section.find( '.tm-epo-variation-element' ) );
6864
6865			if ( item_id && item_id !== 'main' && ! epoObject.is_associated ) {
6866				// on composite
6867
6868				variationsForm = epoObject.form;
6869				variationsTable = variationsForm.find( '.composite_component[data-item_id="' + item_id + '"]' ).find( '.variations' );
6870				variationsForm.attr( 'data-epo_id', epoObject.epo_id );
6871
6872				if ( variationsTable.length === 0 ) {
6873					return;
6874				}
6875
6876				li_variations = tm_epo_variation_section.closest( 'li.tm-extra-product-options-field' );
6877				if ( ! tm_epo_variation_section.is( '.tm-hidden' ) ) {
6878					variationsTable.hide();
6879				}
6880
6881				variationsTable.after( tm_epo_variation_section.addClass( 'tm-extra-product-options nopadding' ) );
6882				if ( li_variations.children().length === 0 || li_variations.text().trim() === '' ) {
6883					li_variations.remove();
6884				}
6885
6886				if ( ! tm_epo_variation_section.is( '.section_popup' ) ) {
6887					tm_epo_variation_section.removeClass( 'tc-cell' );
6888					tm_epo_variation_section.wrap( "<div class='tc-styled-variations'></div>" );
6889				} else {
6890					tm_epo_variation_section.wrap( "<div class='tc-styled-variations tc-row'></div>" );
6891				}
6892
6893				composite_load_test = false;
6894				form.off( eventName ).on( eventName, function() {
6895					composite_load_test = true;
6896					variationsForm.on( 'click.tmlogic', '.reset_variations', function() {
6897						tm_epo_variation_section.find( 'select.tm-epo-variation-element' ).val( '' ).children( 'option' ).prop( 'disabled', false ).show();
6898						tm_epo_variation_section.find( '.tm-epo-variation-element' ).prop( 'disabled', false ).removeClass( 'tm-disabled' ).prop( 'checked', false ).closest( 'li' ).show();
6899						jWindow.trigger( 'tmlazy' );
6900						tm_epo_variation_section.find( '.tm-epo-variation-element' ).trigger( 'tm_trigger_product_image' );
6901						tm_epo_variation_section.find( 'li' ).removeClass( 'tc-active tm-attribute-disabled' ).css( 'opacity', '' );
6902					} );
6903
6904					// Disable option fields that are unavaiable for current set of attributes
6905					form.off( 'woocommerce_update_variation_values_tmlogic' ).on( 'woocommerce_update_variation_values_tmlogic', function() {
6906						tm_custom_variations_update( form, epoObject );
6907					} );
6908					for ( i = 0; i < lateVariationEvent.length; i += 1 ) {
6909						form_event = lateVariationEvent[ i ];
6910						type = typeof form_event;
6911						if ( type === 'object' ) {
6912							name = typeof form_event.name === 'string' || false;
6913							selector = typeof form_event.selector === 'string' || false;
6914							func = typeof form_event.func === 'function' || false;
6915							if ( name && func ) {
6916								if ( selector === "input[name='variation_id']" ) {
6917									selector = variation_id_selector;
6918								}
6919								if ( form_event.selector ) {
6920									form.data( 'tm-styled-variations', 1 )
6921										.off( eventNamePrefix + form_event.name + i, selector )
6922										.on( eventNamePrefix + form_event.name + i, selector, form_event.func );
6923								} else {
6924									form.data( 'tm-styled-variations', 1 )
6925										.off( eventNamePrefix + form_event.name + i )
6926										.on( eventNamePrefix + form_event.name + i, form_event.func );
6927								}
6928							}
6929						}
6930					}
6931					lateVariationEvent = [];
6932					tm_epo_variation_section.find( '.tm-epo-variation-element:not(.tm-hidden .tm-epo-variation-element)' ).last().trigger( 'tm_epo_variation_element_change' );
6933				} );
6934				// document ready
6935				$( function() {
6936					if ( composite_load_test === false ) {
6937						form.trigger( eventName );
6938					}
6939				} );
6940			} else {
6941				if ( tm_epo_variation_section.length ) {
6942					if ( ! tm_epo_variation_section.is( '.tm-hidden' ) ) {
6943						variationsTable.hide();
6944					}
6945
6946					li_variations = tm_epo_variation_section.closest( 'li.tm-extra-product-options-field' );
6947
6948					variationsTable.after( tm_epo_variation_section.addClass( 'tm-extra-product-options nopadding' ) );
6949
6950					if ( li_variations.children().length === 0 || li_variations.text().trim() === '' ) {
6951						li_variations.remove();
6952					}
6953
6954					if ( ! tm_epo_variation_section.is( '.section_popup' ) ) {
6955						tm_epo_variation_section.removeClass( 'tc-cell' );
6956						tm_epo_variation_section.wrap( "<div class='tc-styled-variations'></div>" );
6957					} else {
6958						tm_epo_variation_section.wrap( "<div class='tc-styled-variations tc-row'></div>" );
6959					}
6960
6961					variationsForm.off( 'click.tmlogic', resetSelector ).on( 'click.tmlogic', resetSelector, function() {
6962						tm_epo_variation_section.find( 'select.tm-epo-variation-element' ).val( '' ).children( 'option' ).prop( 'disabled', false ).show();
6963						tm_epo_variation_section.find( '.tm-epo-variation-element' ).prop( 'disabled', false ).removeClass( 'tm-disabled' ).prop( 'checked', false ).closest( 'li' ).show();
6964						jWindow.trigger( 'tmlazy' );
6965						tm_epo_variation_section.find( '.tm-epo-variation-element' ).trigger( 'tm_trigger_product_image' );
6966						tm_epo_variation_section.find( 'li' ).removeClass( 'tc-active tm-attribute-disabled' ).css( 'opacity', '' );
6967					} );
6968				}
6969
6970				// Disable option fields that are unavaiable for current set of attributes
6971				variationsForm.off( 'woocommerce_update_variation_values_tmlogic' ).on( 'woocommerce_update_variation_values_tmlogic', function() {
6972					tm_custom_variations_update( variationsForm, epoObject );
6973				} );
6974
6975				for ( i = 0; i < lateVariationEvent.length; i += 1 ) {
6976					form_event = lateVariationEvent[ i ];
6977					type = typeof form_event;
6978					if ( type === 'object' ) {
6979						name = typeof form_event.name === 'string' || false;
6980						selector = typeof form_event.selector === 'string' || false;
6981						func = typeof form_event.func === 'function' || false;
6982						if ( name && func ) {
6983							if ( selector === "input[name='variation_id']" ) {
6984								selector = variation_id_selector;
6985							}
6986							if ( form_event.selector ) {
6987								variationsForm
6988									.data( 'tm-styled-variations', 1 )
6989									.off( eventNamePrefix + form_event.name + i, selector )
6990									.on( eventNamePrefix + form_event.name + i, selector, form_event.func );
6991							} else {
6992								variationsForm
6993									.data( 'tm-styled-variations', 1 )
6994									.off( eventNamePrefix + form_event.name + i )
6995									.on( eventNamePrefix + form_event.name + i, form_event.func );
6996							}
6997						}
6998					}
6999				}
7000				lateVariationEvent = [];
7001				tm_epo_variation_section.find( '.tm-epo-variation-element:not(.tm-hidden .tm-epo-variation-element)' ).last().trigger( 'tm_epo_variation_element_change' );
7002			}
7003
7004			// global event for custom variations
7005			$.tcepo.formSubmitEvents[ epoEventId ][ $.tcepo.formSubmitEvents[ epoEventId ].length ] = {
7006				trigger: function() {
7007					return true;
7008				},
7009				on_true: function() {
7010					tm_epo_variation_section.find( '.tm-epo-variation-element' ).attr( 'disabled', 'disabled' );
7011					return true;
7012				},
7013				on_false: function() {
7014					tm_epo_variation_section.find( '.tm-epo-variation-element' ).prop( 'disabled', false );
7015				}
7016			};
7017
7018			$( document.body ).on( 'added_to_cart', function() {
7019				tm_epo_variation_section.find( '.tm-epo-variation-element' ).prop( 'disabled', false );
7020			} );
7021		}
7022	}
7023
7024	function repopulate_backup_image_atts( img, product_element ) {
7025		var $gallery_img = product_element.find( '.flex-control-nav li:eq(0) img' );
7026		var $gallery_wrapper = product_element.find( '.woocommerce-product-gallery__wrapper ' );
7027		var $product_img_wrap = $gallery_wrapper.find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ).eq( 0 );
7028		var $product_img = img;
7029		var $product_link = img.closest( 'a' );
7030
7031		$product_img.attr( 'data-o_' + 'src', $.tc_product_image_store[ 0 ].src );
7032		$product_img.attr( 'data-o_' + 'srcset', $.tc_product_image_store[ 0 ].srcset );
7033		$product_img.attr( 'data-o_' + 'sizes', $.tc_product_image_store[ 0 ].sizes );
7034		$product_img.attr( 'data-o_' + 'title', $.tc_product_image_store[ 0 ].title );
7035		$product_img.attr( 'data-o_' + 'alt', $.tc_product_image_store[ 0 ].alt );
7036		$product_img.attr( 'data-o_' + 'data-src', $.tc_product_image_store[ 0 ][ 'data-src' ] );
7037		$product_img.attr( 'data-o_' + 'data-large_image', $.tc_product_image_store[ 0 ][ 'data-large_image' ] );
7038		$product_img.attr( 'data-o_' + 'data-large_image_width', $.tc_product_image_store[ 0 ][ 'data-large_image_width' ] );
7039		$product_img.attr( 'data-o_' + 'data-large_image_height', $.tc_product_image_store[ 0 ][ 'data-large_image_height' ] );
7040		$product_img_wrap.attr( 'data-o_' + 'data-thumb', $.tc_product_image_store[ 1 ][ 'data-thumb' ] );
7041		if ( $.tc_product_image_store[ 2 ] ) {
7042			$gallery_img.attr( 'data-o_' + 'src', $.tc_product_image_store[ 2 ].src );
7043		}
7044
7045		$product_link.attr( 'data-o_' + 'href', $.tc_product_image_store[ 3 ].href );
7046		$product_link.attr( 'data-o_' + 'title', $.tc_product_image_store[ 3 ].title );
7047	}
7048
7049	function reset_saved_image( img, product_element ) {
7050		var $gallery_img = product_element.find( '.flex-control-nav li:eq(0) img' );
7051		var $gallery_wrapper = product_element.find( '.woocommerce-product-gallery__wrapper ' );
7052		var $product_img_wrap = $gallery_wrapper.find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ).eq( 0 );
7053		var $product_img = img;
7054		var $product_link = img.closest( 'a' );
7055
7056		// backup current product image attributes
7057		if ( ! $.isEmptyObject( $.tc_product_image ) ) {
7058			$.tc_product_image_store = $.tc_pre_populate_store();
7059			$.tc_product_image_store = $.tc_maybe_copy_object_values( $.tc_product_image_store, $.tc_product_image );
7060		} else {
7061			$.tc_product_image_store = $.tc_populate_store( img, product_element );
7062		}
7063
7064		$product_img.tc_update_attr( 'src', 0 );
7065		$product_img.tc_update_attr( 'srcset', 0 );
7066		$product_img.tc_update_attr( 'sizes', 0 );
7067		$product_img.tc_update_attr( 'title', 0 );
7068		$product_img.tc_update_attr( 'alt', 0 );
7069		$product_img.tc_update_attr( 'data-src', 0 );
7070		$product_img.tc_update_attr( 'data-large_image', 0 );
7071		$product_img.tc_update_attr( 'data-large_image_width', 0 );
7072		$product_img.tc_update_attr( 'data-large_image_height', 0 );
7073		$product_img_wrap.tc_update_attr( 'data-thumb', 1 );
7074		$gallery_img.tc_update_attr( 'src', 2 );
7075
7076		$product_link.tc_update_attr( 'href', 3 );
7077		$product_link.tc_update_attr( 'title', 3 );
7078	}
7079
7080	function image_update( data, img, product_element ) {
7081		var $gallery_img = product_element.find( '.flex-control-nav li:eq(0) img' );
7082		var $gallery_wrapper = product_element.find( '.woocommerce-product-gallery__wrapper ' );
7083		var $product_img_wrap = $gallery_wrapper.find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ).eq( 0 );
7084		var $product_img = img;
7085		var $product_link = img.closest( 'a' );
7086		var $img_zoom = $product_link.next( '.zoomImg' );
7087
7088		if ( data && data.image_link && data.image_link && data.image_link.length > 1 ) {
7089			if ( data.full_src === null || data.full_src === '' ) {
7090				data.full_src = data.image_link;
7091			}
7092			if ( data.full_src_w === null || data.full_src_w === '' ) {
7093				data.full_src_w = $product_img.attr( 'data-large_image_width' );
7094			}
7095			if ( data.full_src_h === null || data.full_src_h === '' ) {
7096				data.full_src_h = $product_img.attr( 'data-large_image_height' );
7097			}
7098			if ( $product_img.length ) {
7099				if ( ! data.image_srcset ) {
7100					data.image_sizes = false;
7101				}
7102				if ( ! data.image_sizes ) {
7103					data.image_srcset = false;
7104				}
7105				$product_img.tc_set_attr( 'src', data.image_link, 0 );
7106				$product_img.tc_set_attr( 'srcset', data.image_srcset, 0 );
7107				$product_img.tc_set_attr( 'sizes', data.image_sizes, 0 );
7108				$product_img.tc_set_attr( 'title', data.image_title, 0 );
7109				$product_img.tc_set_attr( 'alt', data.image_alt, 0 );
7110				$product_img.tc_set_attr( 'data-src', data.full_src, 0 );
7111				$product_img.tc_set_attr( 'data-large_image', data.full_src, 0 );
7112				$product_img.tc_set_attr( 'data-large_image_width', data.full_src_w, 0 );
7113				$product_img.tc_set_attr( 'data-large_image_height', data.full_src_h, 0 );
7114				$product_img_wrap.tc_set_attr( 'data-thumb', data.image_link, 1 );
7115			}
7116			if ( $gallery_img.length ) {
7117				$gallery_img.tc_set_attr( 'src', data.image_link, 2 );
7118				$gallery_img.tc_set_attr( 'srcset', data.image_srcset, 2 );
7119				$gallery_img.tc_set_attr( 'sizes', data.image_sizes, 2 );
7120			}
7121			if ( $product_link.length ) {
7122				$product_link.tc_set_attr( 'href', data.full_src, 3 );
7123				$product_link.tc_set_attr( 'title', data.image_caption, 3 );
7124			}
7125			if ( $img_zoom.length ) {
7126				$img_zoom.tc_set_attr( 'src', data.full_src, 4 );
7127			}
7128		} else {
7129			if ( $product_img.length ) {
7130				$product_img.tc_reset_attr( 'src', 0 );
7131				$product_img.tc_reset_attr( 'srcset', 0 );
7132				$product_img.tc_reset_attr( 'sizes', 0 );
7133				$product_img.tc_reset_attr( 'title', 0 );
7134				$product_img.tc_reset_attr( 'alt', 0 );
7135				$product_img.tc_reset_attr( 'data-src', 0 );
7136				$product_img.tc_reset_attr( 'data-large_image', 0 );
7137				$product_img.tc_reset_attr( 'data-large_image_width', 0 );
7138				$product_img.tc_reset_attr( 'data-large_image_height', 0 );
7139				$product_img_wrap.tc_reset_attr( 'data-thumb', 1 );
7140			}
7141			if ( $gallery_img.length ) {
7142				$gallery_img.tc_reset_attr( 'src', 2 );
7143				$gallery_img.tc_reset_attr( 'srcset', 2 );
7144				$gallery_img.tc_reset_attr( 'sizes', 2 );
7145			}
7146			if ( $product_link.length ) {
7147				$product_link.tc_reset_attr( 'href', 3 );
7148				$product_link.tc_reset_attr( 'title', 3 );
7149			}
7150			if ( $img_zoom.length ) {
7151				$img_zoom.tc_reset_attr( 'src', 4 );
7152			}
7153		}
7154	}
7155
7156	function get_main_product_image( epoObject, product_element ) {
7157		var img;
7158
7159		if ( epoObject.is_associated ) {
7160			img = product_element.find( '.tc-product-image .wp-post-image' ).first();
7161		} else if ( TMEPOJS.tm_epo_global_product_image_selector !== '' ) {
7162			img = $( TMEPOJS.tm_epo_global_product_image_selector );
7163		} else {
7164			img = product_element.find( '.woocommerce-product-gallery__image:not(.clone), .woocommerce-product-gallery__image--placeholder:not(.clone)' ).eq( 0 ).find( '.wp-post-image' ).first();
7165			if ( img.length === 0 ) {
7166				img = product_element.find( 'a.woocommerce-main-image img, img.woocommerce-main-image,a img' ).not( '.thumbnails img,.product_list_widget img' ).first();
7167			}
7168			if ( img.length === 0 ) {
7169				img = product_element.find( 'img.wp-post-image' ).not( '.thumbnails img,.product_list_widget img' ).first();
7170			}
7171			if ( img.length === 0 ) {
7172				img = product_element.find( '.elementor-widget-wd_single_product_gallery img.wp-post-image' ).first();
7173			}
7174			if ( img.length === 0 ) {
7175				img = product_element.find( '.elementor-widget-ae-post-image .wp-post-image' ).first();
7176			}
7177			if ( img.length === 0 ) {
7178				img = $( '.woocommerce div.product div.images' ).not( '.thumbnails img,.product_list_widget img' ).first();
7179			}
7180		}
7181
7182		if ( $( img ).length > 1 ) {
7183			img = $( img ).first();
7184		}
7185
7186		return img;
7187	}
7188
7189	function get_product_element( epoObject ) {
7190		var main_product;
7191		var product_id;
7192		var product_element;
7193
7194		if ( epoObject.is_associated ) {
7195			return epoObject.main_product.closest( '.tc-epo-element-product-container' );
7196		}
7197
7198		main_product = epoObject.main_product;
7199		product_id = epoObject.product_id;
7200		product_element = main_product.closest( '#product-' + product_id );
7201
7202		if ( product_element.length <= 0 ) {
7203			product_element = main_product.closest( '.post-' + product_id );
7204		}
7205
7206		return product_element;
7207	}
7208
7209	function gallery_compatibility_actions( gallery_type, clone_image, preload_img, visible, event_data, $form, product_element ) {
7210		var gallery;
7211		var _elements;
7212		var ge;
7213		var galleryWidth;
7214		var zoomEnabled;
7215		var image;
7216		var zoom_options;
7217
7218		for ( gallery in gallery_type ) {
7219			if ( Object.prototype.hasOwnProperty.call( gallery_type, gallery ) ) {
7220				gallery = gallery_type[ gallery ];
7221
7222				if ( gallery.enabled ) {
7223					switch ( gallery.type ) {
7224						case 'yith':
7225							if ( ! clone_image ) {
7226								if ( ! visible ) {
7227									gallery.yith_wcmg_zoom.attr( 'href', gallery._yith_wcmg_default_zoom );
7228								} else {
7229									gallery.yith_wcmg_zoom.attr( 'href', gallery.yith_wcmg_default_zoom );
7230								}
7231								if ( gallery.element.data( 'yith_magnifier' ) ) {
7232									gallery.element.yith_magnifier( 'destroy' );
7233								}
7234
7235								gallery.element.yith_magnifier( window.yith_magnifier_options );
7236							} else {
7237								clone_image.attr( 'srcset', preload_img ).attr( 'src-orig', preload_img );
7238
7239								if ( gallery.element.data( 'yith_magnifier' ) ) {
7240									gallery.element.yith_magnifier( 'destroy' );
7241								}
7242								_elements = {
7243									elements: {
7244										zoom: $( '.yith_magnifier_zoom' ),
7245										zoomImage: clone_image,
7246										gallery: $( '.yith_magnifier_gallery li a' )
7247									}
7248								};
7249
7250								gallery.element.yith_magnifier( $.extend( true, {}, window.yith_magnifier_options, _elements ) );
7251							}
7252							break;
7253						case 'iosslider':
7254							setTimeout(
7255								function( g ) {
7256									g.element.iosSlider( 'update' );
7257								}.bind( null, gallery ),
7258								150
7259							);
7260							break;
7261						case 'flexslider':
7262							jWindow.trigger( 'resize' );
7263							break;
7264						case 'elevatezoom':
7265							gallery.element.each(
7266								function( g, j ) {
7267									var elevateZoom = j( this ).data( 'elevateZoom' );
7268									if ( typeof elevateZoom !== 'undefined' ) {
7269										elevateZoom.swaptheimage( g, g );
7270									}
7271								}.bind( null, preload_img, $ )
7272							);
7273							break;
7274						case 'easyzoom':
7275							gallery.element.swap( null, preload_img );
7276							break;
7277						case 'easyzoom-flatsome':
7278							gallery.element.swap( preload_img, preload_img );
7279							break;
7280						case 'woocommerce':
7281							if ( clone_image ) {
7282								gallery.element.flexslider( 0 );
7283								gallery.element.trigger( 'woocommerce_gallery_reset_slide_position' );
7284								ge = gallery.element;
7285								window.setTimeout(
7286									function( g, w ) {
7287										g.trigger( 'woocommerce_gallery_init_zoom' );
7288										w.trigger( 'resize' );
7289									}.bind( null, ge, jWindow ),
7290									10
7291								);
7292							}
7293							break;
7294						case 'zoom':
7295							if ( product_element ) {
7296								galleryWidth = product_element.find( '.woocommerce-product-gallery--with-images' ).width();
7297								zoomEnabled = false;
7298
7299								image = gallery.element.find( 'img.wp-post-image' );
7300								if ( image.attr( 'data-large_image_width' ) > galleryWidth ) {
7301									zoomEnabled = true;
7302								}
7303
7304								if ( zoomEnabled ) {
7305									zoom_options = {
7306										touch: false
7307									};
7308									if ( 'ontouchstart' in window ) {
7309										zoom_options.on = 'click';
7310									}
7311
7312									gallery.element.trigger( 'zoom.destroy' );
7313									gallery.element.zoom( zoom_options );
7314								} else {
7315									gallery.element.trigger( 'zoom.destroy' );
7316								}
7317							}
7318							break;
7319					}
7320				}
7321			}
7322		}
7323
7324		jWindow.trigger( 'tm_gallery_compatibility_actions', {
7325			event_data: event_data,
7326			product_element: product_element,
7327			form: $form
7328		} );
7329	}
7330
7331	function get_gallery_type( epoObject, img, product_element ) {
7332		// YITH WooCommerce Zoom Magnifier
7333		var is_yith_wcmg;
7334		var yith_wcmg;
7335		var yith_wcmg_zoom;
7336		var yith_wcmg_default_zoom;
7337		var _yith_wcmg_default_zoom;
7338		var yith_wcmg_default_image;
7339
7340		// iosslider - Touch Enabled, Responsive jQuery Horizontal Content
7341		// Slider/Carousel/Image Gallery Plugin
7342		var is_iosSlider;
7343		var is_iosSlider_element;
7344
7345		// ThemeFusion flexslider
7346		var is_flexslider;
7347		var is_flexslider_element;
7348
7349		// elevateZoom A Jquery Image Zoom Plugin
7350		var is_elevateZoom;
7351		var is_elevateZoom_obj;
7352
7353		// EasyZoom jQuery image zoom plugin
7354		var is_easyzoom;
7355		var is_easyzoom_element;
7356
7357		// new flatsome easyzoom
7358		var is_easyzoom_flatsome;
7359		var is_easyzoom_flatsome_element;
7360
7361		// WooCommerce 2.7x gallery
7362		var is_wc27_gallery;
7363		var is_wc27_gallery_element;
7364		var wc27_zoom_target;
7365		var wc_single_product_params;
7366		var zoom_target_temp;
7367
7368		// fn.zoom
7369		var is_zoom_enabled;
7370		var zoom_images;
7371		var gallery;
7372
7373		if ( epoObject.is_associated ) {
7374			return {};
7375		}
7376
7377		// YITH WooCommerce Zoom Magnifier
7378		is_yith_wcmg = false;
7379		yith_wcmg = $( '.images' );
7380		yith_wcmg_zoom = $( '.yith_magnifier_zoom' );
7381		yith_wcmg_default_zoom = yith_wcmg.find( '.yith_magnifier_zoom' ).first().attr( 'href' );
7382		_yith_wcmg_default_zoom = yith_wcmg_default_zoom;
7383		yith_wcmg_default_image = yith_wcmg.find( '.yith_magnifier_zoom img' ).first().attr( 'src' );
7384
7385		// iosslider - Touch Enabled, Responsive jQuery Horizontal Content
7386		// Slider/Carousel/Image Gallery Plugin
7387		is_iosSlider = false;
7388		is_iosSlider_element = $( '.iosSlider.product-gallery-slider,.iosSlider.product-slider' );
7389
7390		// ThemeFusion flexslider
7391		is_flexslider = false;
7392		is_flexslider_element = product_element.find( '.images .fusion-flexslider' );
7393
7394		// elevateZoom A Jquery Image Zoom Plugin
7395		is_elevateZoom = img.data( 'elevateZoom' ) || false;
7396		is_elevateZoom_obj = product_element.find( 'div.product-images .woocommerce-main-image' );
7397
7398		// EasyZoom jQuery image zoom plugin
7399		is_easyzoom = false;
7400		is_easyzoom_element = product_element.find( '.images .easyzoom' );
7401
7402		// new flatsome easyzoom
7403		is_easyzoom_flatsome = false;
7404		is_easyzoom_flatsome_element = product_element.find( '.images .easyzoom' );
7405
7406		// WooCommerce 2.7x gallery
7407		is_wc27_gallery = false;
7408		is_wc27_gallery_element = product_element.find( '.woocommerce-product-gallery' );
7409		wc27_zoom_target = false;
7410		wc_single_product_params = window.wc_single_product_params;
7411
7412		// fn.zoom
7413		is_zoom_enabled = typeof $.fn.zoom === 'function' && wc_single_product_params && wc_single_product_params.zoom_enabled;
7414		zoom_images = false;
7415
7416		if ( window.yith_magnifier_options && yith_wcmg.data( 'yith_magnifier' ) ) {
7417			is_yith_wcmg = true;
7418		}
7419
7420		if ( is_iosSlider_element.length && is_iosSlider_element.iosSlider ) {
7421			is_iosSlider = true;
7422		}
7423
7424		if ( is_flexslider_element.length && is_flexslider_element.flexslider ) {
7425			is_flexslider = true;
7426		}
7427
7428		if ( is_easyzoom_element.length && is_easyzoom_element.filter( '.images .easyzoom.first' ).data( 'easyZoom' ) ) {
7429			is_easyzoom_element = is_easyzoom_element.filter( '.images .easyzoom.first' ).data( 'easyZoom' );
7430			is_easyzoom = true;
7431		}
7432
7433		if ( ! is_easyzoom ) {
7434			is_easyzoom_flatsome_element = product_element.find( '.images .has-image-zoom .slide' );
7435			if ( is_easyzoom_flatsome_element.length && is_easyzoom_flatsome_element.filter( '.images .has-image-zoom .slide.first' ).data( 'easyZoom' ) ) {
7436				is_easyzoom_flatsome_element = is_easyzoom_flatsome_element.filter( '.images .has-image-zoom .slide.first' ).data( 'easyZoom' );
7437				is_easyzoom_flatsome = true;
7438			}
7439		}
7440
7441		if ( document.readyState === 'complete' ) {
7442			setTimeout( function() {
7443				if ( is_easyzoom_element.length && is_easyzoom_element.data( 'easyZoom' ) ) {
7444					is_easyzoom_element = is_easyzoom_element.data( 'easyZoom' );
7445					is_easyzoom = true;
7446				}
7447				if ( is_easyzoom_flatsome_element.length && is_easyzoom_flatsome_element.data( 'easyZoom' ) ) {
7448					is_easyzoom_flatsome_element = is_easyzoom_flatsome_element.data( 'easyZoom' );
7449					is_easyzoom_flatsome = true;
7450				}
7451			}, 150 );
7452		} else {
7453			jWindow.on( 'load', function() {
7454				setTimeout( function() {
7455					if ( is_easyzoom_element.length && is_easyzoom_element.data( 'easyZoom' ) ) {
7456						is_easyzoom_element = is_easyzoom_element.data( 'easyZoom' );
7457						is_easyzoom = true;
7458					}
7459					if ( is_easyzoom_flatsome_element.length && is_easyzoom_flatsome_element.data( 'easyZoom' ) ) {
7460						is_easyzoom_flatsome_element = is_easyzoom_flatsome_element.data( 'easyZoom' );
7461						is_easyzoom_flatsome = true;
7462					}
7463				}, 150 );
7464			} );
7465		}
7466
7467		if ( is_wc27_gallery_element.length && is_wc27_gallery_element.data( 'flexslider' ) ) {
7468			is_wc27_gallery = true;
7469
7470			if ( typeof $.fn.zoom === 'function' && wc_single_product_params && wc_single_product_params.zoom_enabled ) {
7471				zoom_target_temp = img.closest( '.woocommerce-product-gallery__image' );
7472				// Ommiting the following condition:
7473				// && img.width() > $( '.woocommerce-product-gallery' ).width()
7474				if ( zoom_target_temp.length > 0 ) {
7475					wc27_zoom_target = zoom_target_temp;
7476					img.data.wc27_zoom_target = wc27_zoom_target;
7477				}
7478			}
7479		}
7480
7481		if ( ! is_wc27_gallery && is_zoom_enabled ) {
7482			zoom_images = product_element.find( '.woocommerce-product-gallery .woocommerce-product-gallery__image' );
7483		}
7484
7485		gallery = {
7486			is_yith_wcmg: {
7487				type: 'yith',
7488				enabled: is_yith_wcmg,
7489				element: yith_wcmg,
7490				yith_wcmg_zoom: yith_wcmg_zoom,
7491				_yith_wcmg_default_zoom: _yith_wcmg_default_zoom,
7492				yith_wcmg_default_image: yith_wcmg_default_image
7493			},
7494			is_iosSlider: {
7495				type: 'iosslider',
7496				enabled: is_iosSlider,
7497				element: is_iosSlider_element
7498			},
7499			is_flexslider: {
7500				type: 'flexslider',
7501				enabled: is_flexslider,
7502				element: is_flexslider_element
7503			},
7504			is_elevateZoom: {
7505				type: 'elevatezoom',
7506				enabled: is_elevateZoom,
7507				element: is_elevateZoom_obj
7508			},
7509			is_easyzoom: {
7510				type: 'easyzoom',
7511				enabled: is_easyzoom,
7512				element: is_easyzoom_element
7513			},
7514			is_easyzoom_flatsome: {
7515				type: 'easyzoom-flatsome',
7516				enabled: is_easyzoom_flatsome,
7517				element: is_easyzoom_flatsome_element
7518			},
7519			is_wc27_gallery: {
7520				type: 'woocommerce',
7521				enabled: is_wc27_gallery,
7522				element: is_wc27_gallery_element
7523			},
7524			is_zoom_enabled: {
7525				type: 'zoom',
7526				enabled: ! is_wc27_gallery && is_zoom_enabled,
7527				element: zoom_images
7528			}
7529		};
7530
7531		return gallery;
7532	}
7533
7534	function tm_product_image_self( epoObject ) {
7535		var this_epo_container = epoObject.is_associated ? epoObject.this_epo_container : epoObject.this_epo_container.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector );
7536		var variationsForm = epoObject.variations_form;
7537		var main_product = epoObject.main_product;
7538		var $form = epoObject.form;
7539		var img;
7540		var gallery_type;
7541		var product_element = get_product_element( epoObject );
7542		var last_active_field = [];
7543		var el;
7544		var el_current;
7545		var imp;
7546		var selector;
7547		var eventNamePrefix = epoObject.is_associated ? 'tc_' : '';
7548		// This currently has a limitation that it doesn't work if there is variation active onload.
7549		var main_tc_product_image_store;
7550
7551		img = get_main_product_image( epoObject, product_element );
7552		gallery_type = get_gallery_type( epoObject, img, product_element );
7553
7554		if ( $( img ).length > 0 ) {
7555			$form.on( eventNamePrefix + 'reset_image.tcpi', function() {
7556				setTimeout( function() {
7557					if ( TMEPOJS.tm_epo_global_image_recalculate === 'yes' ) {
7558						img = get_main_product_image( epoObject, product_element );
7559						$.tc_product_image_store = main_tc_product_image_store;
7560					}
7561					// restore product image atts from backup
7562					$.tc_product_image = $.tc_replace_object_values( $.tc_product_image, $.tc_product_image_store );
7563
7564					last_active_field = [];
7565
7566					$( this_epo_container.find( '.tm-product-image:checked,select.tm-product-image' ) )
7567						.add( variationsForm.find( '.tm-epo-variation-section' ).first().find( '.tm-product-image:checked,select.tm-product-image' ) )
7568						.toArray().forEach( function( pi ) {
7569							pi = $( pi );
7570							if ( field_is_active( pi ) && pi.val() !== '' ) {
7571								last_active_field.push( pi );
7572							}
7573						} );
7574					if ( last_active_field.length ) {
7575						last_active_field[ last_active_field.length - 1 ].trigger( 'tm_trigger_product_image' );
7576					} else {
7577						$.tc_product_image_store = $.tc_populate_store( img, product_element );
7578					}
7579				}, window.tc_epo_product_image_change_delay || 0 );
7580			} );
7581
7582			$form.on( eventNamePrefix + 'found_variation.tcpi', function() {
7583				setTimeout( function() {
7584					if ( TMEPOJS.tm_epo_global_image_recalculate === 'yes' ) {
7585						img = get_main_product_image( epoObject, product_element );
7586					}
7587					reset_saved_image( img, product_element );
7588
7589					last_active_field = [];
7590					$( this_epo_container.find( '.tm-product-image:checked,select.tm-product-image' ) )
7591						.add( variationsForm.find( '.tm-epo-variation-section' ).first().find( '.tm-product-image:checked,select.tm-product-image' ) )
7592						.toArray().forEach( function( pi ) {
7593							pi = $( pi );
7594							if ( field_is_active( pi ) && pi.val() !== '' ) {
7595								last_active_field.push( pi );
7596							}
7597						} );
7598					if ( last_active_field.length ) {
7599						repopulate_backup_image_atts( img, product_element );
7600						last_active_field[ last_active_field.length - 1 ].trigger( 'tm_trigger_product_image' );
7601					}
7602				}, window.tc_epo_product_image_change_delay || 0 );
7603			} );
7604
7605			$.tc_product_image_store = $.tc_maybe_copy_object_values_from_img( $.tc_product_image_store, img, product_element );
7606			main_tc_product_image_store = $.epoAPI.util.deepCopyArray( $.tc_product_image_store );
7607
7608			main_product.off( 'tm_change_product_image' ).on( 'tm_change_product_image', function( evt, event_data ) {
7609				var data;
7610				evt.stopImmediatePropagation();
7611
7612				el = event_data.element;
7613				el_current = event_data.element_current;
7614				if ( el && el_current ) {
7615					imp = el.data( 'imagep' );
7616					selector = '';
7617					if ( imp !== '' ) {
7618						selector = 'imagep';
7619					} else if ( el.data( 'changes-product-image' ) === 'images' ) {
7620						selector = 'image';
7621					}
7622					data = event_data.element_current.data( 'image-variations' );
7623
7624					if ( data ) {
7625						data = data[ selector ];
7626					}
7627
7628					if ( data === undefined ) {
7629						// Enter the following if you want to restore the original product image
7630						// main_product.trigger( 'tm_restore_product_image', event_data );
7631						return;
7632					}
7633
7634					last_active_field = [];
7635					$( this_epo_container.find( '.tm-product-image:checked,select.tm-product-image' ) )
7636						.add( variationsForm.find( '.tm-epo-variation-section' ).first().find( '.tm-product-image:checked,select.tm-product-image' ) )
7637						.toArray().forEach( function( pi ) {
7638							pi = $( pi );
7639							if ( pi.is( 'option' ) ) {
7640								pi = pi.closest( 'select' );
7641							}
7642							if ( pi.val() !== '' && field_is_active( pi ) ) {
7643								last_active_field.push( pi );
7644							}
7645						} );
7646
7647					if ( last_active_field.length ) {
7648						if ( ! last_active_field[ last_active_field.length - 1 ].is( el ) ) {
7649							return;
7650						}
7651					}
7652
7653					setTimeout( function() {
7654						if ( TMEPOJS.tm_epo_global_image_recalculate === 'yes' ) {
7655							img = get_main_product_image( epoObject, product_element );
7656						}
7657						image_update( data, img, product_element );
7658						gallery_compatibility_actions( gallery_type, img, data.image_link, false, event_data, $form, product_element );
7659					}, window.tc_epo_product_image_change_delay || 0 );
7660				}
7661			} );
7662
7663			main_product.off( 'tm_restore_product_image' ).on( 'tm_restore_product_image', function( evt, event_data ) {
7664				evt.stopImmediatePropagation();
7665
7666				el = event_data ? event_data.element : false;
7667				last_active_field = [];
7668
7669				if ( el ) {
7670					$( this_epo_container.find( '.tm-product-image:checked,select.tm-product-image' ) )
7671						.add( variationsForm.find( '.tm-epo-variation-section' ).first().find( '.tm-product-image:checked,select.tm-product-image' ) )
7672						.toArray().forEach( function( pi ) {
7673							pi = $( pi );
7674							if ( field_is_active( pi ) && pi.val() !== '' ) {
7675								last_active_field.push( pi );
7676							}
7677						} );
7678					if ( last_active_field.length ) {
7679						if ( ! last_active_field[ last_active_field.length - 1 ].is( el ) ) {
7680							last_active_field[ last_active_field.length - 1 ].trigger( 'tm_trigger_product_image' );
7681							return;
7682						}
7683					}
7684				}
7685
7686				setTimeout( function() {
7687					if ( TMEPOJS.tm_epo_global_image_recalculate === 'yes' ) {
7688						img = get_main_product_image( epoObject, product_element );
7689					}
7690					image_update( false, img, product_element );
7691					gallery_compatibility_actions( gallery_type, false, img.attr( 'src' ), false, event_data, $form, product_element );
7692				}, window.tc_epo_product_image_change_delay || 0 );
7693			} );
7694
7695			last_active_field = [];
7696			$( this_epo_container.find( '.tm-product-image:checked,select.tm-product-image' ) )
7697				.add( variationsForm.find( '.tm-epo-variation-section' ).first().find( '.tm-product-image:checked,select.tm-product-image' ) )
7698				.toArray().forEach( function( pi ) {
7699					pi = $( pi );
7700					if ( field_is_active( pi ) && pi.val() !== '' ) {
7701						last_active_field.push( pi );
7702					}
7703				} );
7704			if ( last_active_field.length ) {
7705				last_active_field[ last_active_field.length - 1 ].trigger( 'tm_trigger_product_image' );
7706			}
7707		}
7708
7709		jWindow.trigger( 'tm_product_image_loaded' );
7710	}
7711
7712	function tm_product_image_inline( epoObject ) {
7713		var this_epo_container = epoObject.is_associated ? epoObject.this_epo_container : epoObject.this_epo_container.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector );
7714		var main_product = epoObject.main_product;
7715		var product_id = epoObject.product_id;
7716		var $form = epoObject.form;
7717		var img;
7718		var product_element = get_product_element( epoObject );
7719		var gallery_type;
7720		var a;
7721		var img_src_original;
7722		var img_width;
7723		var img_height;
7724		var last_active_field = [];
7725
7726		img = get_main_product_image( epoObject, product_element );
7727
7728		gallery_type = get_gallery_type( epoObject, img, product_element );
7729
7730		if ( $( img ).length > 0 ) {
7731			img.data( 'tm-current-image', false );
7732			a = img.closest( 'a' );
7733			img_src_original = img.attr( 'src' );
7734			img_width = img.width();
7735			img_height = img.height();
7736
7737			main_product.off( 'tm_change_product_image' ).on( 'tm_change_product_image', function( evt, e ) {
7738				setTimeout( function() {
7739					var variation_element_section;
7740					var is_variation_element;
7741					var $this_epo_container;
7742					var tm_last_visible_image_element;
7743					var last_activate_field = [];
7744					var tm_current_image_element_id;
7745					var can_show_image;
7746					var $main_product;
7747					var $current_product_element;
7748					var preload_width;
7749					var preload_height;
7750					var current_cloned_image;
7751					var preloader;
7752					var clone_image;
7753					var preload_img;
7754					var preload_img_onerror;
7755
7756					if ( TMEPOJS.tm_epo_global_image_recalculate === 'yes' ) {
7757						img = get_main_product_image( epoObject, product_element );
7758					}
7759
7760					variation_element_section = e.element.closest( '.cpf-section' );
7761					is_variation_element = variation_element_section.is( '.tm-epo-variation-section' );
7762					$this_epo_container = e.epo_holder;
7763					if ( is_variation_element ) {
7764						$this_epo_container = variation_element_section;
7765					}
7766					tm_last_visible_image_element = $this_epo_container.find( '.tm-product-image:checked,select.tm-product-image' );
7767					last_activate_field = [];
7768					tm_current_image_element_id = e.element.attr( 'id' );
7769					can_show_image = true;
7770					$main_product = e.main_product;
7771					$current_product_element = $main_product.closest( '#product-' + product_id );
7772					preload_width = img_width;
7773					preload_height = img_height;
7774					preloader = $( "<div class='blockUI blockOverlay tm-preloader-img'></div>" );
7775
7776					if ( $current_product_element.length <= 0 ) {
7777						$current_product_element = $main_product.closest( '.post-' + product_id );
7778					}
7779
7780					current_cloned_image = $current_product_element.find( '#' + tm_current_image_element_id + '_tmimage' );
7781					if ( current_cloned_image.length === 0 ) {
7782						current_cloned_image = img;
7783					}
7784
7785					preload_img_onerror = function() {
7786						preloader.remove();
7787						$form.tc_image_update( false );
7788						img.data( 'tm-current-image', false );
7789						$current_product_element.find( '.tm-clone-product-image' ).hide();
7790						img.show();
7791					};
7792
7793					if ( e.src === current_cloned_image.attr( 'src' ) && current_cloned_image.is( ':visible' ) ) {
7794						return;
7795					}
7796
7797					if ( e.src === false ) {
7798						preload_img_onerror();
7799						return;
7800					}
7801
7802					preloader.css( {
7803						width: preload_width,
7804						height: preload_height
7805					} );
7806
7807					// Get last active field
7808					tm_last_visible_image_element.toArray().forEach( function( ie ) {
7809						ie = $( ie );
7810						if (
7811							field_is_active( ie ) &&
7812							has_active_changes_product_image( ie ) &&
7813							tm_check_field_match( {
7814								element: ie.closest( '.cpf-element' ),
7815								rule: {
7816									operator: 'isnotempty',
7817									value: ''
7818								},
7819								type: 'element'
7820							} )
7821						) {
7822							last_activate_field.push( ie );
7823						}
7824					} );
7825					// Get last active image
7826					if ( last_activate_field.length ) {
7827						tm_last_visible_image_element = last_activate_field[ last_activate_field.length - 1 ];
7828					}
7829
7830					if ( tm_last_visible_image_element.attr( 'id' ) !== e.element.attr( 'id' ) ) {
7831						can_show_image = false;
7832					}
7833
7834					clone_image = img.tcClone();
7835					preload_img = new Image();
7836					clone_image.removeAttr( 'data-o_src' ).removeAttr( 'data-o_title' ).removeAttr( 'data-o_alt' ).removeAttr( 'data-o_srcset' ).removeAttr( 'data-o_sizes' ).removeAttr( 'srcset' ).removeAttr( 'sizes' );
7837
7838					if ( can_show_image ) {
7839						img.before( preloader );
7840					}
7841
7842					gallery_type.is_yith_wcmg.yith_wcmg_default_zoom = gallery_type.is_yith_wcmg.element.find( '.yith_magnifier_zoom' ).first().attr( 'href' );
7843					gallery_type.is_yith_wcmg.yith_wcmg_default_image = gallery_type.is_yith_wcmg.element.find( '.yith_magnifier_zoom img' ).first().attr( 'src' );
7844
7845					preload_img.onerror = function() {
7846						preload_img_onerror();
7847					};
7848
7849					preload_img.onload = function() {
7850						if ( 'naturalHeight' in this ) {
7851							if ( this.naturalHeight + this.naturalWidth === 0 ) {
7852								this.onerror();
7853								return;
7854							}
7855						} else if ( this.width + this.height === 0 ) {
7856							this.onerror();
7857							return;
7858						}
7859						$current_product_element.find( '#' + tm_current_image_element_id + '_tmimage' ).remove();
7860						$current_product_element.find( '.tm-clone-product-image' ).hide();
7861						clone_image.prop( 'src', preload_img.src ).hide();
7862
7863						img.hide().after( clone_image );
7864
7865						clone_image.css( 'opacity', 0 ).show();
7866
7867						gallery_compatibility_actions( gallery_type, clone_image, preload_img.src );
7868
7869						preloader.animate(
7870							{
7871								opacity: 0
7872							},
7873							750,
7874							'easeOutExpo',
7875							function() {
7876								preloader.remove();
7877							}
7878						);
7879						clone_image.animate(
7880							{
7881								opacity: 1
7882							},
7883							window.tc_epo_image_animation_delay || 1500,
7884							'easeOutExpo',
7885							function() {}
7886						);
7887
7888						jWindow.trigger( 'tm_change_product_image_loaded', {
7889							src: e.src,
7890							element: e.element,
7891							main_product: e.main_product,
7892							epo_holder: e.epo_holder
7893						} );
7894					};
7895
7896					clone_image
7897						.attr( 'id', tm_current_image_element_id + '_tmimage' )
7898						.addClass( 'tm-clone-product-image' )
7899						.hide();
7900
7901					if ( clone_image.attr( 'src-orig' ) ) {
7902						clone_image.attr( 'src-orig', e.src );
7903					}
7904
7905					if ( can_show_image ) {
7906						preload_img.src = e.src;
7907
7908						$form.tc_image_update( e.element, clone_image );
7909
7910						img.data( 'tm-current-image', tm_current_image_element_id );
7911
7912						jWindow.trigger( 'tm_change_product_image_show', {
7913							src: e.src,
7914							element: e.element,
7915							main_product: e.main_product,
7916							epo_holder: e.epo_holder
7917						} );
7918					} else {
7919						clone_image.prop( 'src', e.src ).hide();
7920						img.after( clone_image );
7921					}
7922
7923					jWindow.trigger( 'tm_change_product_image_end', {
7924						src: e.src,
7925						element: e.element,
7926						main_product: e.main_product,
7927						epo_holder: e.epo_holder
7928					} );
7929				}, window.tc_epo_product_image_change_delay || 0 );
7930			} );
7931
7932			main_product.off( 'tm_restore_product_image' ).on( 'tm_restore_product_image', function( evt, e ) {
7933				setTimeout( function() {
7934					var tm_current_image_element_id;
7935					var $main_product;
7936					var $current_product_element;
7937					var variation_element_section;
7938					var is_variation_element;
7939					var current_element;
7940					var current_image_replacement;
7941					var found;
7942					var is_it_visible;
7943					var len;
7944					var el_to_check;
7945					var imgSrc;
7946					var $this_epo_container;
7947					var i;
7948
7949					if ( ! e || ! e.element ) {
7950						return false;
7951					}
7952					if ( TMEPOJS.tm_epo_global_image_recalculate === 'yes' ) {
7953						img = get_main_product_image( epoObject, product_element );
7954					}
7955
7956					jWindow.trigger( 'tm_restore_product_image_pre', {
7957						element: e.element,
7958						main_product: e.main_product,
7959						epo_holder: e.epo_holder
7960					} );
7961					tm_current_image_element_id = e.element.attr( 'id' );
7962					$main_product = e.main_product;
7963					$current_product_element = $main_product.closest( '#product-' + product_id );
7964					variation_element_section = e.element.closest( '.cpf-section' );
7965					is_variation_element = variation_element_section.is( '.tm-epo-variation-section' );
7966					found = false;
7967					imgSrc = img_src_original;
7968					$this_epo_container = e.epo_holder;
7969					if ( is_variation_element ) {
7970						$this_epo_container = variation_element_section;
7971					}
7972
7973					if ( $current_product_element.length <= 0 ) {
7974						$current_product_element = $main_product.closest( '.post-' + product_id );
7975					}
7976
7977					is_it_visible = $current_product_element.find( '#' + tm_current_image_element_id + '_tmimage' ).is( ':visible' );
7978
7979					$current_product_element.find( '#' + tm_current_image_element_id + '_tmimage' ).remove();
7980
7981					if ( $current_product_element.find( '.tm-clone-product-image' ).length === 0 ) {
7982						img.show();
7983						img.data( 'tm-current-image', false );
7984						$form.tc_image_update( false );
7985					} else {
7986						if ( ! is_it_visible ) {
7987							jWindow.trigger( 'tm_restore_product_image_loaded_exit', {
7988								element: e.element,
7989								main_product: e.main_product,
7990								epo_holder: e.epo_holder
7991							} );
7992							return;
7993						}
7994
7995						len = $current_product_element.find( '.tm-clone-product-image' ).length;
7996						tm_current_image_element_id = img.data( 'tm-current-image' );
7997
7998						for ( i = len - 1; i >= 0; i -= 1 ) {
7999							current_image_replacement = $current_product_element.find( '.tm-clone-product-image' ).eq( i );
8000							current_element = current_image_replacement.attr( 'id' ).replace( '_tmimage', '' );
8001							el_to_check = $this_epo_container.find( "[id='" + current_element + "']" );
8002
8003							if ( el_to_check.is( ':checked' ) && el_to_check.closest( '.cpf-element' ).is( ':visible' ) ) {
8004								$current_product_element.find( '.tm-clone-product-image' ).eq( i ).show();
8005								a.attr( 'href', $current_product_element.find( '.tm-clone-product-image' ).eq( i ).prop( 'src' ) );
8006								img.data( 'tm-current-image', current_element );
8007								found = true;
8008								break;
8009							} else {
8010								$current_product_element.find( '.tm-clone-product-image' ).eq( i ).hide();
8011							}
8012						}
8013						if ( ! found ) {
8014							img.show();
8015							img.data( 'tm-current-image', false );
8016							$form.tc_image_update( false );
8017						} else {
8018							$current_product_element.find( '#' + tm_current_image_element_id + '_tmimage' ).remove();
8019						}
8020					}
8021
8022					if ( found ) {
8023						imgSrc = current_image_replacement.attr( 'src' );
8024					}
8025
8026					gallery_compatibility_actions( gallery_type, false, imgSrc, $current_product_element.find( '.tm-clone-product-image' ).filter( ':visible' ).length );
8027
8028					jWindow.trigger( 'tm_restore_product_image_loaded', {
8029						element: e.element,
8030						main_product: e.main_product,
8031						epo_holder: e.epo_holder
8032					} );
8033				}, window.tc_epo_product_image_change_delay || 0 );
8034			} );
8035
8036			main_product.off( 'tm_attempt_product_image' ).on( 'tm_attempt_product_image', function( evt, e ) {
8037				setTimeout( function() {
8038					var $main_product;
8039					var $current_product_element;
8040					var variation_element_section;
8041					var is_variation_element;
8042					var $this_epo_container;
8043					var tm_last_visible_image_element;
8044					var last_activate_field;
8045					var tm_last_visible_image_element_id;
8046					var current_image_replacement;
8047					var current_element;
8048					var found;
8049					var tm_current_image_element_id;
8050					var len;
8051					var imgSrc;
8052					var el_to_check;
8053					var tmcie_id;
8054					var i;
8055
8056					if ( TMEPOJS.tm_epo_global_image_recalculate === 'yes' ) {
8057						img = get_main_product_image( epoObject, product_element );
8058					}
8059
8060					$main_product = e.main_product;
8061					$current_product_element = $main_product.closest( '#product-' + product_id );
8062					if ( e.element ) {
8063						variation_element_section = e.element.closest( '.cpf-section' );
8064					} else {
8065						variation_element_section = $( $main_product.find( '.tm-epo-variation-section' ).first(), e.epo_holder );
8066					}
8067					is_variation_element = variation_element_section.is( '.tm-epo-variation-section' );
8068					$this_epo_container = e.epo_holder;
8069					if ( is_variation_element ) {
8070						$this_epo_container = variation_element_section;
8071					}
8072					tm_last_visible_image_element = $this_epo_container.find( '.tm-product-image:checked,select.tm-product-image' );
8073					last_activate_field = [];
8074					tm_last_visible_image_element_id = '';
8075					found = false;
8076					tm_current_image_element_id = img.data( 'tm-current-image' );
8077					imgSrc = img_src_original;
8078
8079					if ( $current_product_element.length <= 0 ) {
8080						$current_product_element = $main_product.closest( '.post-' + product_id );
8081					}
8082
8083					$this_epo_container = $main_product.find( '.tm-epo-variation-section' ).first().add( e.epo_holder );
8084					tm_last_visible_image_element = $this_epo_container.find( '.tm-product-image:checked,select.tm-product-image' );
8085
8086					tm_last_visible_image_element.toArray().forEach( function( ie ) {
8087						ie = $( ie );
8088						if (
8089							field_is_active( ie ) &&
8090							has_active_changes_product_image( ie ) &&
8091							tm_check_field_match( {
8092								element: ie.closest( '.cpf-element' ),
8093								rule: {
8094									operator: 'isnotempty',
8095									value: ''
8096								},
8097								type: 'element'
8098							} )
8099						) {
8100							last_activate_field.push( ie );
8101						}
8102					} );
8103
8104					if ( last_activate_field.length ) {
8105						tm_last_visible_image_element = last_activate_field[ last_activate_field.length - 1 ];
8106						tm_last_visible_image_element_id = tm_last_visible_image_element.attr( 'id' );
8107					}
8108
8109					if ( last_activate_field.length && tm_last_visible_image_element.length && ( ! tm_current_image_element_id || tm_last_visible_image_element_id !== tm_current_image_element_id ) ) {
8110						tm_last_visible_image_element.last().trigger( 'tm_trigger_product_image' );
8111						return;
8112					}
8113
8114					tmcie_id = $this_epo_container.find( "[id='" + tm_current_image_element_id + "']" ).closest( '.cpf-element' );
8115					if ( ! tm_current_image_element_id || ( tmcie_id.data( 'isactive' ) !== false && tmcie_id.closest( '.cpf-section' ).data( 'isactive' ) !== false ) ) {
8116						return;
8117					}
8118
8119					$current_product_element.find( '#' + tm_current_image_element_id + '_tmimage' ).remove();
8120					len = $current_product_element.find( '.tm-clone-product-image' ).length;
8121
8122					if ( len === 0 ) {
8123						img.show();
8124						img.data( 'tm-current-image', false );
8125						$form.tc_image_update( false );
8126					} else {
8127						for ( i = len - 1; i >= 0; i -= 1 ) {
8128							current_image_replacement = $current_product_element.find( '.tm-clone-product-image' ).eq( i );
8129							current_element = current_image_replacement.attr( 'id' ).replace( '_tmimage', '' );
8130							el_to_check = $this_epo_container.find( "[id='" + current_element + "']" );
8131
8132							if ( el_to_check.is( ':checked' ) && el_to_check.closest( '.cpf-element' ).is( ':visible' ) ) {
8133								$current_product_element.find( '.tm-clone-product-image' ).eq( i ).show();
8134								a.attr( 'href', $current_product_element.find( '.tm-clone-product-image' ).eq( i ).prop( 'src' ) );
8135								img.data( 'tm-current-image', current_element );
8136								found = true;
8137								break;
8138							} else {
8139								$current_product_element.find( '.tm-clone-product-image' ).eq( i ).hide();
8140							}
8141						}
8142
8143						if ( ! found ) {
8144							img.show();
8145							img.data( 'tm-current-image', false );
8146							$form.tc_image_update( false );
8147						}
8148					}
8149
8150					if ( found ) {
8151						imgSrc = current_image_replacement.attr( 'src' );
8152					}
8153
8154					gallery_compatibility_actions( gallery_type, false, imgSrc, $current_product_element.find( '.tm-clone-product-image' ).filter( ':visible' ).length );
8155				}, window.tc_epo_product_image_change_delay || 0 );
8156			} );
8157
8158			$( this_epo_container.find( '.tm-product-image:checked,select.tm-product-image' ) )
8159				.add( main_product.find( '.tm-epo-variation-section' ).first().find( '.tm-product-image:checked,select.tm-product-image' ) )
8160				.toArray().forEach( function( pi ) {
8161					pi = $( pi );
8162					if ( field_is_active( pi ) && pi.val() !== '' ) {
8163						last_active_field.push( pi );
8164					}
8165				} );
8166			if ( last_active_field.length ) {
8167				last_active_field[ last_active_field.length - 1 ].trigger( 'tm_trigger_product_image' );
8168			}
8169		}
8170
8171		jWindow.trigger( 'tm_product_image_loaded' );
8172	}
8173
8174	function tm_product_image( epoObject ) {
8175		var galleryImages;
8176		setTimeout( function() {
8177			if ( TMEPOJS.tm_epo_global_product_image_mode === 'inline' ) {
8178				tm_product_image_inline( epoObject );
8179			} else {
8180				tm_product_image_self( epoObject );
8181			}
8182
8183			if ( $.fn.wc_product_gallery ) {
8184				galleryImages = epoObject.this_epo_container;
8185				if ( epoObject.is_associated ) {
8186					galleryImages = epoObject.main_product;
8187				}
8188				galleryImages.find( '.cpf-type-product-custombundle .tc-associated-product-image' ).tclightbox();
8189			}
8190		}, window.tc_epo_product_image_setup_delay || 0 );
8191	}
8192
8193	function tc_compatibility( epoObject ) {
8194		jWindow.trigger( 'tm-epo-compatibility', {
8195			epo: epoObject
8196		} );
8197	}
8198
8199	// Range picker setup
8200	function setRangePickers( obj ) {
8201		if ( ! noUiSlider ) {
8202			return;
8203		}
8204		obj.find( '.tm-range-picker' )
8205			.toArray()
8206			.forEach( function( picker ) {
8207				var el = $( picker );
8208				var $decimals = el.attr( 'data-step' ).split( '.' );
8209				var $tmfid = obj.find( '#' + $.epoAPI.dom.id( el.attr( 'data-field-id' ) ) );
8210				var $min = parseFloat( el.attr( 'data-min' ) );
8211				var $max = parseFloat( el.attr( 'data-max' ) );
8212				var $start = parseFloat( el.attr( 'data-start' ) );
8213				var $step = parseFloat( el.attr( 'data-step' ) );
8214				var $show_picker_value = el.attr( 'data-show-picker-value' );
8215				var $show_label = el.closest( 'li' ).find( '.tm-show-picker-value' );
8216				var $noofpips = parseFloat( el.attr( 'data-noofpips' ) );
8217				var $pips = null;
8218				var $tmh;
8219
8220				if ( el.data( 'tc-picker-init' ) ) {
8221					return;
8222				}
8223				el.data( 'tc-picker-init', 1 );
8224
8225				if ( $decimals.length === 1 ) {
8226					$decimals = 0;
8227				} else {
8228					$decimals = $decimals[ 1 ].length;
8229				}
8230				if ( ! Number.isFinite( $min ) ) {
8231					$min = 0;
8232				}
8233				if ( ! Number.isFinite( $max ) ) {
8234					$max = 0;
8235				}
8236				if ( $max <= $min ) {
8237					$max = parseFloat( $max ) + 1;
8238				}
8239				$start = $.epoAPI.math.unformat( $start, tcAPI.localDecimalSeparator );
8240				if ( ! Number.isFinite( $start ) ) {
8241					$start = 0;
8242				}
8243				$start = formatPrice( $start, { precision: $decimals } );
8244				if ( ! Number.isFinite( $step ) ) {
8245					$step = 0;
8246				}
8247				if ( ! Number.isFinite( $noofpips ) ) {
8248					$noofpips = 10;
8249				}
8250				if ( $noofpips < 2 ) {
8251					$noofpips = 2;
8252				}
8253
8254				if ( el.attr( 'data-pips' ) === 'yes' ) {
8255					$pips = {
8256						mode: 'count',
8257						values: $noofpips,
8258						filter: function( value, type ) {
8259							value = parseFloat( $.epoAPI.math.toFixed( value, $decimals ) );
8260
8261							if ( $step <= 0 ) {
8262								return 0;
8263							}
8264
8265							if ( type === 1 ) {
8266								if ( ! Number.isInteger( value ) ) {
8267									return 2;
8268								}
8269							}
8270
8271							return type;
8272						},
8273						format: {
8274							from: function( value ) {
8275								return $.epoAPI.math.unformat( value, tcAPI.localInputDecimalSeparator );
8276							},
8277							to: function( value ) {
8278								return formatPrice( value, { precision: $decimals } );
8279							}
8280						},
8281						density: 2
8282					};
8283				}
8284
8285				noUiSlider.create( el.get( 0 ), {
8286					direction: TMEPOJS.text_direction,
8287					start: $start,
8288					step: $step,
8289					connect: 'lower',
8290					// Configure tapping, or make the selected range dragable.
8291					behaviour: 'tap',
8292					// Full number format support.
8293					format: {
8294						from: function( value ) {
8295							return $.epoAPI.math.unformat( value, tcAPI.localDecimalSeparator );
8296						},
8297						to: function( value ) {
8298							return formatPrice( value, { precision: $decimals } );
8299						}
8300					},
8301					// Support for non-linear ranges by adding intervals.
8302					range: {
8303						min: [ $min ],
8304						max: [ $max ]
8305					},
8306					pips: $pips,
8307					tooltips: {
8308						from: function( value ) {
8309							return $.epoAPI.math.unformat( value, tcAPI.localInputDecimalSeparator );
8310						},
8311						to: function( value ) {
8312							return formatPrice( value, { precision: $decimals } );
8313						}
8314					}
8315				} );
8316
8317				$tmh = el.find( '.noui-handle-lower' );
8318				el.get( 0 ).noUiSlider.on( 'slide', function() {
8319					$tmfid.trigger( 'change.cpf' );
8320				} );
8321				el.get( 0 ).noUiSlider.on( 'update', function( values, handle ) {
8322					values[ handle ] = $.epoAPI.math.unformat( values[ handle ], tcAPI.localDecimalSeparator );
8323					handle = 0; //fixes rtl issue.
8324					if ( $show_picker_value !== 'left' && $show_picker_value !== 'right' ) {
8325						$tmh.attr(
8326							'title',
8327							formatPrice( values[ handle ], { precision: $decimals } )
8328						);
8329					}
8330					$tmfid.val( values[ handle ] ).trigger( 'change' );
8331					if ( $show_picker_value !== '' ) {
8332						$show_label.html(
8333							formatPrice( values[ handle ], { precision: $decimals } )
8334						);
8335					}
8336				} );
8337
8338				if ( $show_picker_value !== '' ) {
8339					$show_label.html( $start );
8340				}
8341
8342				if ( $show_picker_value !== 'left' && $show_picker_value !== 'right' ) {
8343					$tmh.attr( 'title', $start );
8344					el.addClass( 'noui-show-tooltip' );
8345				}
8346			} );
8347	}
8348
8349	// Range picker event setup
8350	function setRangePickersEvents() {
8351		if ( ! noUiSlider || jDocument.data( 'setRangePickersEvents' ) ) {
8352			return;
8353		}
8354		jDocument.on( 'click', '.tm-show-picker-value', function() {
8355			var $this = $( this );
8356			var li = $this.closest( '.tmcp-field-wrap' );
8357			var value = li.find( '.tmcp-range' ).val();
8358			var edit;
8359			var html5Slider = $this.closest( '.tmcp-field-wrap' ).find( '.tm-range-picker' );
8360
8361			$this.addClass( 'tc-hidden' ).after( $( '<input type="number" class="tm-show-picker-value-edit">' ) );
8362			edit = li.find( '.tm-show-picker-value-edit' );
8363			edit.focus().val( value ).wrap( '<div class="tm-show-picker-value-edit-wrap"></div>' );
8364			edit.attr( 'step', html5Slider.attr( 'data-step' ) );
8365			edit.attr( 'min', html5Slider.attr( 'data-min' ) );
8366			edit.attr( 'max', html5Slider.attr( 'data-max' ) );
8367			$( '.tm-show-picker-value-edit' ).focus().on( 'focusout', function() {
8368				$this = li.find( '.tm-show-picker-value-edit' );
8369				$this.closest( '.tmcp-field-wrap' ).find( '.tm-show-picker-value' ).removeClass( 'tc-hidden' );
8370				$this.closest( '.tm-show-picker-value-edit-wrap' ).remove();
8371			} );
8372		} );
8373		jDocument.on( 'change input', '.tm-show-picker-value-edit', function() {
8374			var $this = $( this );
8375			var html5Slider = $this.closest( '.tmcp-field-wrap' ).find( '.tm-range-picker' );
8376			var $decimals = html5Slider.attr( 'data-step' ).split( '.' );
8377			var value = $this.val();
8378			if ( $decimals.length === 1 ) {
8379				$decimals = 0;
8380			} else {
8381				$decimals = $decimals[ 1 ].length;
8382			}
8383
8384			html5Slider.get( 0 ).noUiSlider.set( [ formatPrice( value, { precision: $decimals } ), null ] );
8385		} );
8386		jDocument.on( 'keydown', '.tm-show-picker-value-edit', function( event ) {
8387			var key;
8388
8389			key = event.which;
8390			if ( key === 13 ) {
8391				event.preventDefault();
8392			}
8393		} );
8394		jDocument.data( 'setRangePickersEvents', 1 );
8395	}
8396
8397	function validate_date_with_options( date, inputElement ) {
8398		var input = $( inputElement );
8399		var inst = $.tm_datepicker._getInst( input[ 0 ] );
8400		var enabled_only_dates = input.data( 'tc-enabled_only_dates' );
8401		var disabled_weekdays = input.data( 'tc-disabled_weekdays' );
8402		var disabled_months = input.data( 'tc-disabled_months' );
8403		var disabled_dates = input.data( 'tc-disabled_dates' );
8404		var format = input.data( 'tc-format' );
8405		var day = date.getDay();
8406		var month = date.getDay() + 1;
8407		var string;
8408
8409		if ( ! $.tm_datepicker._isInRange( inst, date ) ) {
8410			return false;
8411		}
8412		if ( enabled_only_dates !== '' ) {
8413			string = $.tm_datepicker.formatDate( format, date );
8414			return enabled_only_dates.indexOf( string ) !== -1;
8415		}
8416		if ( disabled_weekdays.indexOf( day.toString() ) !== -1 ) {
8417			return false;
8418		}
8419		if ( disabled_months.indexOf( month.toString() ) !== -1 ) {
8420			return false;
8421		}
8422		if ( disabled_dates !== '' ) {
8423			string = $.tm_datepicker.formatDate( format, date );
8424			return disabled_dates.indexOf( string ) === -1;
8425		}
8426		return true;
8427	}
8428
8429	function correctDate( days ) {
8430		var sign, testDate, count, added, noOfDaysToAdd;
8431		if ( days.toString().isNumeric() ) {
8432			sign = days === 0 ? days : ( days > 0 ? 1 : -1 );
8433			if ( sign !== 0 ) {
8434				testDate = new Date();
8435				count = 1;
8436				added = false;
8437				noOfDaysToAdd = Math.abs( days );
8438				while ( count <= noOfDaysToAdd ) {
8439					if ( added === false ) {
8440						added = 0;
8441					}
8442					testDate.setDate( testDate.getDate() + ( 1 * sign ) );
8443					added++;
8444					if ( testDate.getDay() !== 0 && testDate.getDay() !== 6 ) {
8445						count++;
8446					}
8447				}
8448				if ( added !== false ) {
8449					days = added * sign;
8450				}
8451			}
8452		}
8453		return days;
8454	}
8455	// Date and time picker setup
8456	function tm_set_datepicker( obj ) {
8457		var inputIds;
8458		var elem;
8459		var timepickerSelector = '.tm-epo-timepicker';
8460
8461		if ( ! $.tm_datepicker ) {
8462			return;
8463		}
8464
8465		inputIds = $( 'input' )
8466			.map( function() {
8467				return this.id;
8468			} )
8469			.get()
8470			.join( ' ' );
8471
8472		elem = document.createElement( 'input' );
8473		elem.setAttribute( 'type', 'date' );
8474
8475		if ( elem.type === 'text' ) {
8476			timepickerSelector = '.tm-epo-system-timepicker';
8477		}
8478
8479		obj.find( timepickerSelector )
8480			.toArray()
8481			.forEach( function( el ) {
8482				var field = $( el );
8483				var _mintime = null;
8484				var _maxtime = null;
8485				var format = field.attr( 'data-time-format' ).trim();
8486				var date_theme = field.attr( 'data-time-theme' ).trim();
8487				var date_theme_size = field.attr( 'data-time-theme-size' ).trim();
8488				var date_theme_position = field.attr( 'data-time-theme-position' ).trim();
8489				var data_translation_hour = field.attr( 'data-tranlation-hour' ).trim();
8490				var data_translation_minute = field.attr( 'data-tranlation-minute' ).trim();
8491				var data_translation_second = field.attr( 'data-tranlation-second' ).trim();
8492
8493				field.attr( 'type', 'text' );
8494
8495				if ( field.attr( 'data-min-time' ).trim() !== '' ) {
8496					_mintime = field.attr( 'data-min-time' ).trim();
8497				}
8498				if ( field.attr( 'data-max-time' ).trim() !== '' ) {
8499					_maxtime = field.attr( 'data-max-time' ).trim();
8500				}
8501
8502				if ( field.attr( 'data-custom-time-format' ).trim() !== '' ) {
8503					format = field.attr( 'data-custom-time-format' ).trim();
8504				}
8505				if ( ! data_translation_hour ) {
8506					data_translation_hour = TMEPOJS.hourText;
8507				}
8508				if ( ! data_translation_minute ) {
8509					data_translation_minute = TMEPOJS.minuteText;
8510				}
8511				if ( ! data_translation_second ) {
8512					data_translation_second = TMEPOJS.secondText;
8513				}
8514
8515				field.tm_timepicker( Object.assign( {
8516					isRTL: TMEPOJS.isRTL,
8517					hourText: data_translation_hour,
8518					minuteText: data_translation_minute,
8519					secondText: data_translation_second,
8520					timeFormat: format,
8521					minTime: _mintime,
8522					maxTime: _maxtime,
8523					closeText: TMEPOJS.closeText,
8524					showOn: 'both',
8525					buttonText: '',
8526
8527					beforeShow: function( input, inst ) {
8528						$( inst.dpDiv )
8529							.removeClass( inputIds )
8530							.removeClass( 'tm-ui-skin-epo tm-ui-skin-epo-black tm-datepicker-medium tm-datepicker-small tm-datepicker-large tm-datepicker-normal tm-datepicker-top tm-datepicker-bottom' )
8531							.addClass( this.id + ' tm-bsbb-all tm-ui-skin-' + date_theme + ' tm-timepicker tm-datepicker tm-datepicker-' + date_theme_position + ' tm-datepicker-' + date_theme_size )
8532							.appendTo( 'body' );
8533
8534						jDocument.off( 'click', '.tm-ui-dp-overlay' ).on( 'click', '.tm-ui-dp-overlay', function() {
8535							field.tm_timepicker( 'hide' );
8536						} );
8537						jBody.addClass( 'tm-static' );
8538						field.prop( 'readonly', true );
8539
8540						jWindow.trigger( {
8541							type: 'tm-timepicker-beforeShow',
8542							input: input,
8543							inst: inst
8544						} );
8545					},
8546					onClose: function() {
8547						jBody.removeClass( 'tm-static' );
8548						field.prop( 'readonly', false );
8549						field.trigger( 'change' );
8550					}
8551				}, window.tmTimepickerSettings || window.timepicker_settings || {} ) );
8552				$( '#ui-tm-datepicker-div' ).hide();
8553			} );
8554
8555		obj.find( '.tm-epo-datepicker' )
8556			.toArray()
8557			.forEach( function( el ) {
8558				var field = $( el );
8559				var startDate = parseInt( field.attr( 'data-start-year' ).trim(), 10 );
8560				var endDate = parseInt( field.attr( 'data-end-year' ).trim(), 10 );
8561				var minDate = field.attr( 'data-min-date' ).trim();
8562				var maxDate = field.attr( 'data-max-date' ).trim();
8563				var disabled_dates = field.attr( 'data-disabled-dates' ).trim();
8564				var enabled_only_dates = field.attr( 'data-enabled-only-dates' ).trim();
8565				var exlude_disabled = field.attr( 'data-exlude-disabled' ).trim();
8566				var disabled_weekdays = field.attr( 'data-disabled-weekdays' ).trim().split( ',' );
8567				var disabled_months = field.attr( 'data-disabled-months' ).trim().split( ',' );
8568				var format = field.attr( 'data-date-format' ).trim();
8569				var show = field.attr( 'data-date-showon' ).trim();
8570				var default_date = field.attr( 'data-date-defaultdate' ).trim();
8571				var date_theme = field.attr( 'data-date-theme' ).trim();
8572				var date_theme_size = field.attr( 'data-date-theme-size' ).trim();
8573				var date_theme_position = field.attr( 'data-date-theme-position' ).trim();
8574				var $split;
8575				var $index;
8576				var $split2;
8577				var $index2;
8578
8579				if ( disabled_dates !== '' ) {
8580					$split = disabled_dates.split( ',' );
8581					$index = disabled_dates.indexOf( ',' );
8582
8583					if ( $index !== -1 && $split.length > 0 ) {
8584						disabled_dates = $split;
8585					}
8586				}
8587				if ( enabled_only_dates !== '' ) {
8588					$split2 = enabled_only_dates.split( ',' );
8589					$index2 = enabled_only_dates.indexOf( ',' );
8590
8591					if ( $index2 !== -1 && $split2.length > 0 ) {
8592						enabled_only_dates = $split2;
8593					}
8594				}
8595
8596				if ( minDate === '' ) {
8597					if ( startDate === '' ) {
8598						minDate = null;
8599					} else {
8600						minDate = new Date( startDate, 1 - 1, 1 );
8601					}
8602				} else if ( exlude_disabled ) {
8603					minDate = correctDate( minDate );
8604				}
8605				if ( maxDate === '' ) {
8606					if ( endDate === '' ) {
8607						maxDate = null;
8608					} else {
8609						maxDate = new Date( endDate, 12 - 1, 31 );
8610					}
8611				} else if ( exlude_disabled ) {
8612					maxDate = correctDate( maxDate );
8613				}
8614
8615				field.data( 'tc-enabled_only_dates', enabled_only_dates );
8616				field.data( 'tc-disabled_weekdays', disabled_weekdays );
8617				field.data( 'tc-disabled_months', disabled_months );
8618				field.data( 'tc-disabled_dates', disabled_dates );
8619				field.data( 'tc-format', format );
8620
8621				field.tm_datepicker( Object.assign( {
8622					monthNames: TMEPOJS.monthNames,
8623					monthNamesShort: TMEPOJS.monthNamesShort,
8624					dayNames: TMEPOJS.dayNames,
8625					dayNamesShort: TMEPOJS.dayNamesShort,
8626					dayNamesMin: TMEPOJS.dayNamesMin,
8627					isRTL: TMEPOJS.isRTL,
8628					showOtherMonths: true,
8629					selectOtherMonths: true,
8630					showOn: show,
8631					defaultDate: default_date,
8632					buttonText: '',
8633					showButtonPanel: true,
8634					firstDay: TMEPOJS.first_day,
8635					closeText: TMEPOJS.closeText,
8636					currentText: TMEPOJS.currentText,
8637					dateFormat: format,
8638					minDate: minDate,
8639					maxDate: maxDate,
8640					onSelect: function() {
8641						var input = $( this );
8642						var id = '#' + $.epoAPI.dom.id( input.attr( 'id' ) );
8643						var date = input.tm_datepicker( 'getDate' );
8644						var day = '';
8645						var month = '';
8646						var year = '';
8647						var day_field = obj.find( id + '_day' );
8648						var month_field = obj.find( id + '_month' );
8649						var year_field = obj.find( id + '_year' );
8650						var string;
8651						var ld;
8652
8653						if ( date ) {
8654							day = date.getDate();
8655							month = date.getMonth() + 1;
8656							year = date.getFullYear();
8657							string = $.tm_datepicker.formatDate( format, date );
8658							if (
8659								disabled_months.indexOf( month.toString() ) !== -1 ||
8660								disabled_weekdays.indexOf( date.getDay().toString() ) !== -1 ||
8661								disabled_dates.indexOf( string ) !== -1 ||
8662								( enabled_only_dates !== '' && enabled_only_dates.indexOf( string ) === -1 )
8663							) {
8664								ld = input.data( 'tm-last-date' );
8665								if ( input.data( 'tm-last-date' ) ) {
8666									ld = input.data( 'tm-last-date' );
8667								} else {
8668									ld = '';
8669								}
8670								input.val( ld );
8671								input.tm_datepicker( 'setDate', ld );
8672								if ( ld ) {
8673									date = input.tm_datepicker( 'getDate' );
8674									day = date.getDate();
8675									month = date.getMonth() + 1;
8676									year = date.getFullYear();
8677								} else {
8678									day = '';
8679									month = '';
8680									year = '';
8681								}
8682							}
8683						}
8684
8685						day_field.val( day );
8686						month_field.val( month );
8687						year_field.val( year );
8688
8689						input.data( 'tm-last-date', input.val() );
8690						input.tm_datepicker( 'hide' );
8691					},
8692					beforeShow: function( input, inst ) {
8693						$( inst.dpDiv )
8694							.removeClass( inputIds )
8695							.removeClass( 'tm-datepicker-normal tm-datepicker-top tm-datepicker-bottom' )
8696							.addClass( this.id + ' tm-bsbb-all tm-ui-skin-' + date_theme + ' tm-datepicker tm-datepicker-' + date_theme_position + ' tm-datepicker-' + date_theme_size )
8697							.appendTo( 'body' );
8698
8699						jDocument.off( 'click', '.tm-ui-dp-overlay' ).on( 'click', '.tm-ui-dp-overlay', function() {
8700							field.tm_datepicker( 'hide' );
8701						} );
8702						jDocument.off( 'click', '.ui-tm-datepicker-current' ).on( 'click', '.ui-tm-datepicker-current', function() {
8703							var tempDate = new Date(),
8704								today = $.tm_datepicker._daylightSavingAdjust( new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) );
8705							var day = today.getDay();
8706							var month = today.getMonth() + 1;
8707							var id = '#' + inst.id.replace( /\\\\/g, '\\' );
8708							var check = false;
8709							var string;
8710							var date = field.tm_datepicker( 'getDate' );
8711
8712							if ( enabled_only_dates !== '' ) {
8713								string = $.tm_datepicker.formatDate( format, date );
8714								check = enabled_only_dates.indexOf( string ) !== -1;
8715							} else if ( disabled_months.indexOf( month.toString() ) !== -1 || disabled_weekdays.indexOf( day.toString() ) !== -1 ) {
8716								check = false;
8717							} else {
8718								if ( disabled_dates !== '' ) {
8719									string = $.tm_datepicker.formatDate( format, date );
8720									return [ disabled_dates.indexOf( string ) === -1, '' ];
8721								}
8722								check = true;
8723							}
8724							if ( check ) {
8725								$.tm_datepicker._setDate( inst, today );
8726								$.tm_datepicker._gotoToday( id );
8727							}
8728						} );
8729						jBody.addClass( 'tm-static' );
8730
8731						jWindow.trigger( {
8732							type: 'tm-datepicker-beforeShow',
8733							input: input,
8734							inst: inst
8735						} );
8736					},
8737					onClose: function() {
8738						jBody.removeClass( 'tm-static' );
8739						field.trigger( 'change' );
8740					},
8741					beforeShowDay: function( date ) {
8742						var day = date.getDay();
8743						var month = date.getMonth() + 1;
8744						var string;
8745
8746						if ( enabled_only_dates !== '' ) {
8747							string = $.tm_datepicker.formatDate( format, date );
8748							return [ enabled_only_dates.indexOf( string ) !== -1, '' ];
8749						}
8750						if ( disabled_months.indexOf( month.toString() ) !== -1 || disabled_weekdays.indexOf( day.toString() ) !== -1 ) {
8751							return [ false, '' ];
8752						}
8753						if ( disabled_dates !== '' ) {
8754							string = $.tm_datepicker.formatDate( format, date );
8755							return [ disabled_dates.indexOf( string ) === -1, '' ];
8756						}
8757						return [ true, '' ];
8758					}
8759				}, window.tmDatepickerSettings || {} ) );
8760
8761				$( '#ui-tm-datepicker-div' ).hide();
8762			} );
8763
8764		obj.find( '.tmcp-date-select' )
8765			.on( 'change.cpf', function() {
8766				var id = '#' + $.epoAPI.dom.id( $( this ).attr( 'data-tm-date' ) );
8767				var input = obj.find( id );
8768				var format = input.attr( 'data-date-format' );
8769				var day = obj.find( id + '_day' ).val();
8770				var month = obj.find( id + '_month' ).val();
8771				var year = obj.find( id + '_year' ).val();
8772				var dateFormat = $.tm_datepicker.formatDate( format, new Date( year, parseInt( month, 10 ) - 1, day ) );
8773
8774				if ( day > 0 && month > 0 && year > 0 ) {
8775					input.tm_datepicker( 'setDate', dateFormat );
8776					input.trigger( 'change' );
8777				} else {
8778					input.val( '' );
8779					input.trigger( 'change.cpf' );
8780				}
8781			} )
8782			.on( 'focus.cpf', function() {
8783				var id = '#' + $.epoAPI.dom.id( $( this ).attr( 'data-tm-date' ) );
8784				var input = obj.find( id );
8785				var day_select = obj.find( id + '_day' );
8786				var month_select = obj.find( id + '_month' );
8787				var year_select = obj.find( id + '_year' );
8788				var day = day_select.val();
8789				var month = month_select.val();
8790				var year = year_select.val();
8791				var _select = $( this );
8792
8793				if ( ( year !== '' && month !== '' && day !== '' ) || ( year !== '' && month !== '' && day === '' ) || ( day !== '' && year !== '' && month === '' ) || ( day !== '' && month !== '' && year === '' ) ) {
8794					_select
8795						.find( 'option' )
8796						.toArray()
8797						.forEach( function( element ) {
8798							var option = $( element );
8799							var val = option.val();
8800							var date_string = year + '-' + month + '-' + day;
8801							var d;
8802
8803							if ( _select.is( '.tmcp-date-day' ) ) {
8804								if ( year === '' || month === '' ) {
8805									return;
8806								}
8807								date_string = year + '-' + month + '-' + val;
8808							} else if ( _select.is( '.tmcp-date-month' ) ) {
8809								if ( year === '' || day === '' ) {
8810									return;
8811								}
8812								date_string = year + '-' + val + '-' + day;
8813							} else if ( _select.is( '.tmcp-date-year' ) ) {
8814								if ( day === '' || month === '' ) {
8815									return;
8816								}
8817								date_string = val + '-' + month + '-' + day;
8818							}
8819
8820							if ( val !== '' ) {
8821								try {
8822									d = $.tm_datepicker.parseDate( 'yy-mm-dd', date_string );
8823									if ( d ) {
8824										if ( validate_date_with_options( d, input ) ) {
8825											option.prop( 'disabled', false );
8826										} else {
8827											option.prop( 'disabled', true );
8828										}
8829									}
8830								} catch ( err ) {
8831									window.console.log( err );
8832
8833									option.prop( 'disabled', true );
8834									errorObject = err;
8835								}
8836							}
8837						} );
8838				} else {
8839					day_select.find( 'option' ).prop( 'disabled', false );
8840					month_select.find( 'option' ).prop( 'disabled', false );
8841					year_select.find( 'option' ).prop( 'disabled', false );
8842				}
8843			} );
8844
8845		jWindow.on( 'resizestart', function() {
8846			var activeElement = $( document.activeElement );
8847
8848			if ( activeElement.is( '.hasDatepicker' ) ) {
8849				activeElement.data( 'resizestarted', true );
8850
8851				// we don't use jWindow here because we want the current window width
8852				if ( $( window ).width() < 768 ) {
8853					activeElement.data( 'resizewidth', true );
8854					return;
8855				}
8856				activeElement.tm_datepicker( 'hide' );
8857			}
8858		} );
8859		jWindow.on( 'resizestop', function() {
8860			var activeElement = $( document.activeElement );
8861
8862			if ( activeElement.is( '.hasDatepicker' ) && activeElement.data( 'resizestarted' ) ) {
8863				if ( activeElement.data( 'resizewidth' ) ) {
8864					activeElement.tm_datepicker( 'hide' );
8865				}
8866				activeElement.tm_datepicker( 'show' );
8867			}
8868			activeElement.data( 'resizestarted', false );
8869			activeElement.data( 'resizewidth', false );
8870		} );
8871	}
8872
8873	function apply_submit_events( epoObject ) {
8874		var epoEventId = epoObject.epoEventId;
8875		var main_product = epoObject.main_product;
8876		var type;
8877		var form_is_submit = ! $.tcepo.formSubmitEvents[ epoEventId ].some( function( form_event ) {
8878			return typeof form_event && ( typeof form_event.trigger === 'function' || false ) && ! form_event.trigger();
8879		} );
8880
8881		$.tcepo.formSubmitEvents[ epoEventId ].forEach( function( form_event ) {
8882			type = typeof form_event;
8883			if ( type === 'object' ) {
8884				if ( form_is_submit ) {
8885					form_event.on_true();
8886				} else {
8887					form_event.on_false();
8888				}
8889			}
8890		} );
8891
8892		if ( ! form_is_submit ) {
8893			setTimeout( function() {
8894				main_product.find( tcAPI.addToCartButtonSelector ).first().removeClass( 'disabled' ).removeClass( 'loading' ).prop( 'disabled', false ).removeClass( 'fpd-disabled' );
8895			}, 100 );
8896		}
8897
8898		jWindow.trigger( 'tm-apply-submit-events', {
8899			epo: {
8900				form_is_submit: form_is_submit
8901			}
8902		} );
8903
8904		return form_is_submit;
8905	}
8906
8907	function tm_apply_validation( epoObject ) {
8908		var form = epoObject.form;
8909		var this_epo_container = epoObject.this_epo_container;
8910		var main_product = epoObject.main_product;
8911		var epoEventId = epoObject.epoEventId;
8912		var validation_rules;
8913		var has_rules;
8914
8915		if ( TMEPOJS.tm_epo_global_enable_validation === 'yes' ) {
8916			validation_rules = {};
8917
8918			this_epo_container
8919				.find( '.tmcp-ul-wrap' )
8920				.toArray()
8921				.forEach( function( tmcpulwrap ) {
8922					var field;
8923					var field_name;
8924					var subFieldName;
8925					var subRule;
8926					var productField;
8927
8928					tmcpulwrap = $( tmcpulwrap );
8929					has_rules = tmcpulwrap.data( 'tm-validation' );
8930					if ( has_rules && $.tmType( has_rules ) === 'object' ) {
8931						field = tmcpulwrap.find( '.tm-epo-field' );
8932						field_name = field.first().attr( 'name' );
8933						if ( tmcpulwrap.is( '.tm-extra-product-options-radio.tm-element-ul-radio' ) ) {
8934							field_name = field.last().attr( 'name' );
8935							validation_rules[ field_name ] = has_rules;
8936						} else if ( tmcpulwrap.is( '.tm-extra-product-options-checkbox.tm-element-ul-checkbox' ) ) {
8937							field.toArray().forEach( function( fname ) {
8938								if ( 'required' in has_rules ) {
8939									has_rules.required = function( elem ) {
8940										var len = tmcpulwrap.find( 'input.tm-epo-field.tmcp-checkbox:checked' ).length;
8941										if ( len === 0 ) {
8942											if ( field.last().attr( 'name' ) === $( elem ).attr( 'name' ) ) {
8943												return true;
8944											}
8945											return false;
8946										}
8947										return len <= 0;
8948									};
8949								}
8950								validation_rules[ $( fname ).attr( 'name' ) ] = has_rules;
8951							} );
8952						} else if ( tmcpulwrap.is( '.tm-extra-product-options-product.tm-element-ul-product' ) ) {
8953							field = field.filter( '.tc-epo-field-product' );
8954							if ( field.is( ':checkbox' ) ) {
8955								field.toArray().forEach( function( fname ) {
8956									if ( 'required' in has_rules ) {
8957										productField = $( fname );
8958										if ( productField.is( ':checkbox' ) ) {
8959											has_rules.required = function( elem ) {
8960												var checkedFields = tmcpulwrap.find( 'input.tm-epo-field.tmcp-checkbox:checked' );
8961												var len = checkedFields.length;
8962												var qtyCheck;
8963												if ( len === 0 ) {
8964													if ( field.last().attr( 'name' ) === $( elem ).attr( 'name' ) ) {
8965														return true;
8966													}
8967													return false;
8968												}
8969												qtyCheck = checkedFields.map( function() {
8970													return $( this );
8971												} ).get().some( function( element ) {
8972													return element.closest( '.tc-epo-element-product-holder' ).find( '.tm-qty' ).first().val() <= 0;
8973												} );
8974												if ( len > 0 ) {
8975													return qtyCheck;
8976												}
8977												return len <= 0;
8978											};
8979											if ( productField.attr( 'data-type' ) === 'variable' ) {
8980												subFieldName = productField.closest( '.tc-epo-element-product-holder' ).find( '.product-variation-id' ).first().attr( 'name' );
8981												subRule = {
8982													required: function( elem ) {
8983														var element = $( elem );
8984														var holder = element.closest( '.tc-epo-element-product-holder' );
8985														var checkbox = holder.find( '.tc-epo-field-product' );
8986
8987														if ( field_is_active( checkbox, true ) && checkbox.is( ':checked' ) ) {
8988															return true;
8989														}
8990														return false;
8991													}
8992												};
8993												validation_rules[ subFieldName ] = subRule;
8994											}
8995										}
8996									}
8997									validation_rules[ productField.attr( 'name' ) ] = has_rules;
8998								} );
8999							} else if ( field.is( ':radio' ) ) {
9000								has_rules.product_element_radio_qty = true;
9001								validation_rules[ field.attr( 'name' ) ] = has_rules;
9002								subFieldName = field.closest( '.tc-element-container' ).find( '.product-variation-id' ).first().attr( 'name' );
9003								subRule = {
9004									required: function( elem ) {
9005										var element = $( elem );
9006										var holder = element.closest( '.tc-element-container' );
9007										var radiobutton = holder.find( '.tc-epo-field-product:checked' );
9008
9009										if ( radiobutton.length && radiobutton.attr( 'data-type' ) === 'variable' && field_is_active( radiobutton, true ) && radiobutton.is( ':checked' ) ) {
9010											return true;
9011										}
9012										return false;
9013									}
9014								};
9015								validation_rules[ subFieldName ] = subRule;
9016							} else if ( field.is( 'select' ) ) {
9017								has_rules.product_element_select_qty = true;
9018								validation_rules[ field.attr( 'name' ) ] = has_rules;
9019								subFieldName = field.closest( '.tc-element-container' ).find( '.product-variation-id' ).first().attr( 'name' );
9020								subRule = {
9021									required: function( elem ) {
9022										var element = $( elem );
9023										var holder = element.closest( '.tc-element-container' );
9024										var select = holder.find( '.tc-epo-field-product' );
9025
9026										if ( select.length && select.children( ':selected' ).attr( 'data-type' ) === 'variable' && field_is_active( select, true ) ) {
9027											return true;
9028										}
9029										return false;
9030									}
9031								};
9032								validation_rules[ subFieldName ] = subRule;
9033							}
9034						} else {
9035							validation_rules[ field_name ] = has_rules;
9036						}
9037					}
9038				} );
9039
9040			form.removeData( 'tc_validator' );
9041			form.tc_validate( {
9042				focusInvalid: false,
9043				ignore:
9044					tcAPI.qtySelector +
9045					',.tcdisabled,.tmcp-upload-hidden,#wc_bookings_field_duration,input.tm-qty:hidden[type="number"],input.input-text.qty,.ignore,.variations select,.tc-epo-variable-product-selector,.tm-extra-product-options-variations input,.tm-extra-product-options-variations select,input:not(' + tcAPI.epoSelector + ' input),select:not(' + tcAPI.epoSelector + ' select)',
9046				rules: validation_rules,
9047				errorClass: 'tm-error',
9048				validClass: 'tm-valid',
9049				errorElement: 'label',
9050				errorPlacement: function( error, element ) {
9051					error.addClass( 'tc-cell tcwidth tcwidth-100' );
9052					if ( TMEPOJS.tm_epo_global_error_label_placement === 'before' ) {
9053						element.closest( '.tc-element-container' ).before( error );
9054					} else {
9055						element.closest( '.tc-element-container' ).after( error );
9056					}
9057					return false;
9058				},
9059				invalidHandler: function( event, validator ) {
9060					jWindow.trigger( 'tm-invalidHandler', {
9061						epo: {
9062							validator: validator
9063						}
9064					} );
9065					setTimeout( function() {
9066						if ( ! main_product.find( tcAPI.addToCartButtonSelector ).first().is( '.disabled' ) ) {
9067							main_product.find( tcAPI.addToCartButtonSelector ).first().removeClass( 'loading' ).prop( 'disabled', false ).removeClass( 'fpd-disabled' );
9068							main_product.find( tcAPI.addToCartButtonSelector ).first().removeClass( 'disabled' ).removeClass( 'loading' ).prop( 'disabled', false ).removeClass( 'fpd-disabled' );
9069						}
9070					}, 100 );
9071					if ( validator.errorList && validator.errorList[ 0 ] && validator.errorList[ 0 ].element ) {
9072						goto_error_item( $( validator.errorList[ 0 ].element ), epoEventId );
9073					}
9074				},
9075				submitHandler: function() {
9076					var ajaxSuccessFunc;
9077					if ( ! epoObject.is_quickview ) {
9078						main_product.find( tcAPI.addToCartButtonSelector ).first().addClass( 'disabled' );
9079						ajaxSuccessFunc = function() {
9080							main_product.find( tcAPI.addToCartButtonSelector ).first().removeClass( 'disabled' );
9081							jDocument.off( 'ajaxSuccess', ajaxSuccessFunc );
9082						};
9083						jDocument.on( 'ajaxSuccess', ajaxSuccessFunc );
9084					}
9085					return apply_submit_events( epoObject );
9086				}
9087			} );
9088
9089			// This should handle most ajax based add to cart solutions
9090			form.find( tcAPI.addToCartButtonSelector ).on( 'click', function( e ) {
9091				if ( ! form.tc_validate().form() ) {
9092					e.preventDefault();
9093					e.stopImmediatePropagation();
9094				}
9095			} );
9096
9097			return true;
9098		}
9099		return false;
9100	}
9101
9102	function tm_form_submit_event( epoObject ) {
9103		var form = epoObject.form;
9104		var epoEventId = epoObject.epoEventId;
9105
9106		jWindow.trigger( 'tm-from-submit', {
9107			epo: epoObject,
9108			functions: {
9109				tm_apply_validation: tm_apply_validation,
9110				apply_submit_events: apply_submit_events
9111			}
9112		} );
9113		if ( ! tm_apply_validation( epoObject ) && $.tcepo.formSubmitEvents[ epoEventId ].length ) {
9114			form.on( 'submit', function() {
9115				apply_submit_events( epoObject );
9116			} );
9117		}
9118
9119		jWindow.on( 'tc_apply_validation', function() {
9120			return tm_apply_validation( epoObject );
9121		} );
9122	}
9123
9124	function found_variation_tmepo( dataObject ) {
9125		var epoHolder = dataObject.epoHolder;
9126		var totalsHolder = dataObject.totalsHolder;
9127		var totalsHolderContainer = dataObject.totalsHolderContainer;
9128		var currentCart = dataObject.currentCart;
9129		var variationForm = dataObject.variationForm;
9130		var variation = dataObject.variation;
9131		var variations = totalsHolder.data( 'variations' );
9132		var product_price;
9133
9134		totalsHolder.data( 'current_variation', variation );
9135
9136		/**
9137		 * Currency converters that don't allow multi currency checkout will fail the following if statement
9138		 *
9139		 * if (variation.display_price!=undefined) {
9140		 *     product_price = variation.display_price;
9141		 *     totalsHolder.data('price', product_price);
9142		 * } else ...
9143		 *
9144		 */
9145		// This needs to be the first check as the next one
9146		// fails for taxed products as it displays the backend price only.
9147		if ( variation && 'display_price' in variation && ! totalsHolder.data( 'tm-epo-is-woocs' ) ) {
9148			product_price = variation.display_price;
9149
9150			totalsHolder.data( 'priceIsWithDiscount', '1' );
9151			// Fancy product Designer
9152			totalsHolder.removeData( 'tcprice' );
9153		} else if ( variations && variation && variation.variation_id && variations[ variation.variation_id ] !== undefined ) {
9154			product_price = variations[ variation.variation_id ];
9155
9156			// Fancy product Designer
9157			totalsHolder.removeData( 'tcprice' );
9158		} else if ( variation && $( variation.price_html ).find( '.amount:last' ).length ) {
9159			product_price = $( variation.price_html ).find( '.amount:last' ).text();
9160			product_price = product_price.replace( TMEPOJS.currency_format_thousand_sep, '' );
9161			product_price = product_price.replace( TMEPOJS.currency_format_decimal_sep, '.' );
9162			product_price = product_price.replace( /[^0-9.]/g, '' );
9163			product_price = parseFloat( product_price );
9164
9165			// Fancy product Designer
9166			totalsHolder.removeData( 'tcprice' );
9167		}
9168
9169		product_price = tm_set_backend_price( product_price, totalsHolder, variation );
9170		totalsHolder.data( 'price', product_price );
9171
9172		totalsHolderContainer.find( '.cpf-product-price' ).val( product_price );
9173
9174		setTimeout( function() {
9175			epoHolder.find( 'select.tm-epo-field' ).trigger( 'tm-select-change-html-all-math' );
9176		}, 100 );
9177
9178		// This must be run every time to get correct results for percent price types
9179		// if set norules then discount will not auto work upon chosing a variation
9180		if ( ! variationForm.data( 'tm-styled-variations' ) ) {
9181			currentCart.trigger( {
9182				type: 'tm-epo-update'
9183			} );
9184		}
9185	}
9186
9187	function fetchOptionPrices( epoObject, epoHolder, selector, total, original_total, floatingBoxData, showTotal, forced, setPriceTax, useUndiscountedPrice, mathTotal, cumulative, nopriceCac
9187heSelector, cartQty ) {
9188		var obj;
9189		var noDpd;
9190		var priceArray;
9191		var priceCacheSelector = 'none';
9192		var total_taxed;
9193		var original_total_taxed;
9194		var vat_total = 0;
9195		var currentTotalsContainer;
9196		var epoinline;
9197		var funcTotal;
9198		var cumulativeTotal;
9199
9200		if ( ! nopriceCacheSelector ) {
9201			priceCacheSelector = epoHolder.attr( 'class' ) + epoHolder.attr( 'data-uniqid' ) + selector + epoObject.is_associated + setPriceTax + forced + setPriceTax + useUndiscountedPrice || 'none';
9202		}
9203
9204		if ( priceCacheSelector !== 'none' && priceCache !== true && priceCache !== false && priceCache[ priceCacheSelector ] !== undefined ) {
9205			return priceCache[ priceCacheSelector ];
9206		}
9207
9208		noDpd = useUndiscountedPrice ? 'undiscounted_' : '';
9209		obj = epoHolder.find( selector );
9210		if ( epoObject.is_associated === false ) {
9211			obj = obj.not( tcAPI.associatedEpoSelector + ' ' + selector + ',.cpf-type-variations ' + selector );
9212		}
9213		if ( ! forced ) {
9214			obj = obj.filter( '.tcenabled' );
9215		}
9216
9217		if ( ! total ) {
9218			total = 0;
9219		}
9220		if ( ! original_total ) {
9221			original_total = 0;
9222		}
9223
9224		funcTotal = total;
9225		cumulativeTotal = total;
9226
9227		total_taxed = total;
9228		original_total_taxed = original_total;
9229
9230		if ( ! floatingBoxData ) {
9231			floatingBoxData = [];
9232		}
9233
9234		currentTotalsContainer = epoObject.this_epo_totals_container;
9235
9236		if ( obj.length ) {
9237			obj.toArray().forEach( function( tmcpfield ) {
9238				var field = $( tmcpfield );
9239				var _value = '';
9240				var fieldval;
9241				var field_div = field.closest( '.cpf-element' );
9242				var field_wrap = field.closest( '.tmcp-field-wrap' );
9243				var field_label_show = field_div.attr( 'data-fblabelshow' );
9244				var field_value_show = field_div.attr( 'data-fbvalueshow' );
9245				var field_title = '';
9246				var option_quantity = field_wrap.find( '.tm-qty' ).val();
9247				var option_price;
9248				var option_price_taxed;
9249				var option_original_price;
9250				var option_original_price_taxed;
9251				var liw;
9252				var cri;
9253				var tl;
9254				var options;
9255				var forrangepicker;
9256				var $decimals;
9257				var _valueText = '';
9258				var setter;
9259				var dofloatingBoxData = false;
9260
9261				if ( selector === '.tc-epo-field-product' ) {
9262					if ( field_div.is( '.cpf-type-product-thumbnailmultiple' ) || field_div.is( '.cpf-type-product-checkbox' ) || field_div.is( '.cpf-type-product-custombundle' ) ) {
9263						epoinline = field.closest( '.tc-epo-element-product-holder' ).find( tcAPI.associatedEpoSelector );
9264					} else if ( field_div.is( '.cpf-type-product-thumbnail' ) || field_div.is( '.cpf-type-product-radio' ) || field_div.is( '.cpf-type-product-dropdown' ) ) {
9265						epoinline = field_div.find( '.tc-epo-element-product-container[data-product_id="' + field.val() + '"]' ).find( tcAPI.associatedEpoSelector );
9266					} else if ( field_div.is( '.cpf-type-product-single' ) ) {
9267						epoinline = field_div.find( tcAPI.associatedEpoSelector );
9268					}
9269					currentTotalsContainer = $( '.tc-epo-totals' + '.tm-product-id-' + epoinline.attr( 'data-product-id' ) + '[data-epo-id="' + epoinline.attr( 'data-epo-id' ) + '"]' );
9270				}
9271
9272				if ( currentTotalsContainer.length ) {
9273					if ( field_label_show === '' ) {
9274						field_title = field_div.find( '.tc-epo-element-label-text' ).html();
9275					}
9276
9277					if ( option_quantity === undefined ) {
9278						option_quantity = '';
9279					}
9280					if ( mathTotal ) {
9281						tm_element_epo_rules( epoObject, field, undefined, undefined, undefined, undefined, funcTotal, cumulativeTotal );
9282					}
9283					if ( field.is( ':checkbox, :radio, :input' ) ) {
9284						option_price = 0;
9285						option_price_taxed = 0;
9286						option_original_price = 0;
9287						option_original_price_taxed = 0;
9288						if ( field.is( '.tmcp-checkbox, .tmcp-radio' ) ) {
9289							if ( forced || field.is( ':checked' ) ) {
9290								option_price = field.data( noDpd + 'raw_price' );
9291								option_price_taxed = field.data( noDpd + 'price' );
9292								option_original_price = field.data( noDpd + 'raw_original_price' );
9293								option_original_price_taxed = field.data( noDpd + 'original_price' );
9294								showTotal = true;
9295								field.data( 'isset', 1 );
9296								liw = field.closest( 'li.tmcp-field-wrap' );
9297								cri = liw.find( '.tc-image' );
9298								_value = '';
9299								_valueText = '';
9300
9301								tl = field.closest( 'li.tmcp-field-wrap' ).find( '.tc-label-text' );
9302								if ( tl.length ) {
9303									_value = tl.html();
9304									_valueText = _value;
9305								}
9306
9307								if ( cri.length ) {
9308									cri = cri.closest( '.tc-label-wrap' ).clone().addClass( 'tc-img-floating' );
9309									cri.find( '.tc-label, .tc-epo-style-wrapper, .tc-input-wrap' ).remove();
9310									_value = cri[ 0 ].outerHTML + '<span class="tc-label-text">' + _value + '</span>';
9311								}
9312								dofloatingBoxData = true;
9313							} else {
9314								field.data( 'isset', 0 );
9315							}
9316						} else if ( field.is( '.tmcp-select' ) ) {
9317							setter = field.find( 'option:selected' );
9318							option_price = setter.data( noDpd + 'raw_price' );
9319							option_price_taxed = setter.data( noDpd + 'price' );
9320							option_original_price = setter.data( noDpd + 'raw_original_price' );
9321							option_original_price_taxed = setter.data( noDpd + 'original_price' );
9322
9323							options = field.children( 'option:selected' );
9324							if ( ! ( options.val() === '' && options.attr( 'data-rulestype' ) === '' ) ) {
9325								showTotal = true;
9326							}
9327
9328							field.find( 'option' ).data( 'isset', 0 );
9329							setter.data( 'isset', 1 );
9330
9331							if ( ! ( setter.val() === '' && setter.attr( 'data-rulestype' ) === '' ) ) {
9332								_value = setter.attr( 'data-text' );
9333								dofloatingBoxData = true;
9334								_valueText = _value;
9335							}
9336						} else if ( field.is( '.tmcp-selectmultiple' ) ) {
9337							setter = field.find( 'option:selected' );
9338							setter.toArray().forEach( function( setterel ) {
9339								setterel = $( setterel );
9340								option_price = option_price + $.epoAPI.math.toFloat( setterel.data( noDpd + 'raw_price' ) );
9341								option_price_taxed = option_price_taxed + $.epoAPI.math.toFloat( setterel.data( noDpd + 'price' ) );
9342								option_original_price = option_original_price + $.epoAPI.math.toFloat( setterel.data( noDpd + 'raw_original_price' ) );
9343								option_original_price_taxed = option_original_price_taxed + $.epoAPI.math.toFloat( setterel.data( noDpd + 'original_price' ) );
9344
9345								options = field.children( 'option:selected' );
9346								if ( ! ( options.val() === '' && options.attr( 'data-rulestype' ) === '' ) ) {
9347									showTotal = true;
9348								}
9349
9350								field.find( 'option' ).data( 'isset', 0 );
9351								setterel.data( 'isset', 1 );
9352
9353								if ( ! ( setterel.val() === '' && setterel.attr( 'data-rulestype' ) === '' ) ) {
9354									_value = setterel.attr( 'data-text' );
9355									dofloatingBoxData = true;
9356									_valueText = _value;
9357								}
9358							} );
9359						} else {
9360							fieldval = field.val();
9361							if ( field.is( "[type='file']" ) ) {
9362								fieldval = fieldval.replace( 'C:\\fakepath\\', '' );
9363							}
9364							if ( fieldval ) {
9365								if ( field.is( '.tmcp-range' ) && fieldval === '0' ) {
9366									field.data( 'isset', 0 );
9367								} else {
9368									option_price = field.data( noDpd + 'raw_price' );
9369									option_price_taxed = field.data( noDpd + 'price' );
9370									option_original_price = field.data( noDpd + 'raw_original_price' );
9371									option_original_price_taxed = field.data( noDpd + 'original_price' );
9372									showTotal = true;
9373									field.data( 'isset', 1 );
9374
9375									_value = fieldval;
9376									if ( field.is( '.tmcp-range' ) ) {
9377										forrangepicker = field.closest( '.tmcp-field-wrap' ).find( '.tm-range-picker' );
9378										$decimals = forrangepicker.attr( 'data-step' ).split( '.' );
9379										if ( $decimals.length === 1 ) {
9380											$decimals = 0;
9381										} else {
9382											$decimals = $decimals[ 1 ].length;
9383										}
9384										_value = formatPrice( _value, { precision: $decimals } );
9385									}
9386									dofloatingBoxData = true;
9387									if ( field.is( '.tmcp-dynamic' ) ) {
9388										field_label_show = 'hidden';
9389										field_value_show = 'hidden';
9390									}
9391									_valueText = fieldval;
9392								}
9393							} else {
9394								field.data( 'isset', 0 );
9395							}
9396						}
9397						if ( ! option_price ) {
9398							option_price = 0;
9399						}
9400						if ( ! option_original_price ) {
9401							option_original_price = 0;
9402						}
9403						if ( ! option_price_taxed ) {
9404							option_price_taxed = 0;
9405						}
9406						if ( ! option_original_price_taxed ) {
9407							option_original_price_taxed = 0;
9408						}
9409						if ( dofloatingBoxData ) {
9410							floatingBoxData.push( {
9411								title: field_title,
9412								value: _value,
9413								valueText: _valueText,
9414								price: option_price_taxed,
9415								original_price: option_original_price_taxed,
9416								quantity: option_quantity,
9417								label_show: field_label_show,
9418								value_show: field_value_show,
9419								input_type: field.attr( 'type' )
9420							} );
9421						}
9422						if ( undefined !== cartQty && cartQty > 0 && field.is( '.tc-is-dnmpbq' ) ) {
9423							option_price = option_price / cartQty;
9424						}
9425
9426						option_price_taxed = tm_set_tax_price( option_price, currentTotalsContainer, field, undefined, undefined, undefined, true );
9427						option_original_price_taxed = tm_set_tax_price( option_original_price, currentTotalsContainer, field, undefined, undefined, undefined, true );
9428
9429						if ( setPriceTax ) {
9430							option_price = option_price_taxed;
9431							option_original_price = option_original_price_taxed;
9432						}
9433
9434						total = $.epoAPI.math.toFloat( total ) + $.epoAPI.math.toFloat( option_price );
9435						total = $.epoAPI.math.toFloat( $.epoAPI.math.round( total, 10 ) );
9436						original_total = $.epoAPI.math.toFloat( original_total ) + $.epoAPI.math.toFloat( option_original_price );
9437						original_total = $.epoAPI.math.toFloat( $.epoAPI.math.round( original_total, 10 ) );
9438
9439						total_taxed = $.epoAPI.math.toFloat( total_taxed ) + $.epoAPI.math.toFloat( option_price_taxed );
9440						total_taxed = $.epoAPI.math.toFloat( $.epoAPI.math.round( total_taxed, 10 ) );
9441						vat_total = vat_total + $.epoAPI.math.toFloat( calculateTaxAmount( option_price_taxed, currentTotalsContainer ) );
9442						original_total_taxed = $.epoAPI.math.toFloat( original_total_taxed ) + $.epoAPI.math.toFloat( option_original_price_taxed );
9443						original_total_taxed = $.epoAPI.math.toFloat( $.epoAPI.math.round( original_total_taxed, 10 ) );
9444
9445						if ( cumulative ) {
9446							cumulativeTotal = total;
9447						}
9448					}
9449				}
9450			} );
9451		}
9452		priceArray = {
9453			total: total,
9454			original_total: original_total,
9455			total_taxed: total_taxed,
9456			original_total_taxed: original_total_taxed,
9457			vat_total: vat_total,
9458			floatingBoxData: floatingBoxData,
9459			showTotal: showTotal,
9460			elementsLength: obj.length
9461		};
9462
9463		if ( priceCache === true ) {
9464			priceCache = {};
9465			priceCache[ priceCacheSelector ] = priceArray;
9466		} else if ( priceCache !== true && priceCache !== false ) {
9467			priceCache[ priceCacheSelector ] = priceArray;
9468		}
9469
9470		return priceArray;
9471	}
9472
9473	function show_product_html( thisEpoObject, thisMainProduct, thisVariableProductContainer, type, $this, currentCart, variableProductContainers, isTrigger, qtyalt ) {
9474		var epoObjectCopy = $.extend( true, {}, thisEpoObject );
9475		var item_tm_extra_product_options = thisVariableProductContainer.find( tcAPI.associatedEpoSelector );
9476		var item = thisVariableProductContainer;
9477		var newEpoObject;
9478		var showOnly = true;
9479
9480		$this.removeData( 'triggeredforced' );
9481
9482		if ( item.closest( '.cpf-element' ).is( '.tc-hidden' ) ) {
9483			return;
9484		}
9485
9486		variableProductContainers.addClass( 'tm-hidden' );
9487		if ( variableProductContainers.length ) {
9488			toggleState( variableProductContainers, true );
9489		}
9490
9491		if ( type === 'variable' ) {
9492			if ( ! thisVariableProductContainer.is( '.tc-init-variations' ) ) {
9493				thisVariableProductContainer.addClass( 'variations_form' );
9494				setTimeout( function() {
9495					newEpoObject = tm_init_epo( item, false, item_tm_extra_product_options.attr( 'data-product-id' ), item_tm_extra_product_options.attr( 'data-epo-id' ), $this, epoObjectCopy );
9496					thisVariableProductContainer.addClass( 'tc-init-variations' );
9497					thisVariableProductContainer.tc_product_variation_form( $this, currentCart, variableProductContainers, newEpoObject );
9498				}, 40 );
9499				showOnly = false;
9500			} else {
9501				thisVariableProductContainer.trigger( 'refresh.tc-variation-form' );
9502			}
9503		} else if ( ! thisVariableProductContainer.is( '.tc-init-product' ) ) {
9504			thisVariableProductContainer.addClass( 'tc-init-product' );
9505			variableProductContainers.find( '.tc-epo-element-variable-product' ).removeClass( 'variations_form' );
9506			variableProductContainers.find( '.tc-epo-element-variations' ).removeClass( 'variations' );
9507
9508			setTimeout( function() {
9509				tm_init_epo( item, false, item_tm_extra_product_options.attr( 'data-product-id' ), item_tm_extra_product_options.attr( 'data-epo-id' ), $this, epoObjectCopy );
9510			}, 20 );
9511			showOnly = false;
9512		}
9513
9514		setTimeout( function() {
9515			if ( variableProductContainers.length ) {
9516				toggleState( thisVariableProductContainer, false );
9517			}
9518			thisVariableProductContainer
9519				.find( ':checkbox:checked, :radio:checked' )
9520				.toArray().forEach( function( vpc ) {
9521					$( vpc ).closest( '.tmcp-field-wrap' ).addClass( 'tc-active' );
9522				} );
9523		}, 10 );
9524		setTimeout( function() {
9525			if ( qtyalt.length ) {
9526				qtyalt.trigger( 'change' );
9527			}
9528			if ( thisVariableProductContainer.find( tcAPI.epoSelector ).length === 0 ) {
9529				thisVariableProductContainer.addClass( 'no-epo' );
9530			}
9531			thisVariableProductContainer.removeClass( 'tm-hidden' );
9532			if ( showOnly ) {
9533				jWindow.trigger( 'cpflogicdone' );
9534				thisVariableProductContainer.find( '.tm-quantity' ).trigger( 'showhide.cpfcustom' );
9535			}
9536			if ( isTrigger === undefined && TMEPOJS.tm_epo_global_product_element_scroll === 'yes' ) {
9537				jWindow.tcScrollTo( thisVariableProductContainer, 200, $.epoAPI.math.toFloat
9537( TMEPOJS.tm_epo_global_product_element_scroll_offset ) );
9538			}
9539			jWindow.trigger( 'show_product_html', {
9540				thisEpoObject: thisEpoObject,
9541				thisMainProduct: thisMainProduct,
9542				thisVariableProductContainer: thisVariableProductContainer,
9543				type: type,
9544				this: $this,
9545				currentCart: currentCart,
9546				variableProductContainers: variableProductContainers,
9547				isTrigger: isTrigger,
9548				qtyalt: qtyalt
9549			} );
9550		}, 210 );
9551	}
9552
9553	function setQtyData( qtyElement, value ) {
9554		var data = qtyElement.data();
9555		if ( value === undefined ) {
9556			value = qtyElement.val();
9557		}
9558		if ( data ) {
9559			Object.keys( data ).filter( function( key ) {
9560				return key.indexOf( 'epopreviousvalue' ) === 0;
9561			} ).forEach( function( key ) {
9562				qtyElement.data( key, value );
9563			} );
9564		}
9565	}
9566
9567	function epoEventHandlers( epoObject, cartContainer, alternativeCart ) {
9568		// if cartContainer & alternativeCart is defined we are on a non default product (eg. composite product)
9569		var product_id = epoObject.product_id;
9570		var main_product = epoObject.main_product;
9571		var main_cart = epoObject.main_cart;
9572		var this_epo_container = epoObject.this_epo_container;
9573		var this_totals_container = epoObject.this_totals_container;
9574		var this_epo_totals_container = epoObject.this_epo_totals_container;
9575		var epoEventId = epoObject.epoEventId;
9576		var main_epo_inside_form = epoObject.main_epo_inside_form;
9577		var epo_id_selector = epoObject.epo_id_selector;
9578		var epo_id = epoObject.epo_id;
9579		var product_id_selector = epoObject.product_id_selector;
9580		var itemId = 'main';
9581		var epoHolder;
9582		var totalsHolderContainer;
9583		var totalsHolder;
9584		var currentCart;
9585		var variation_id_selector;
9586		var this_product_type;
9587		var variationForm;
9588		var qtyElement;
9589		var finalTotalBoxMode;
9590		var finalTotalBoxShowFinal;
9591		var finalTotalBoxShowOptions;
9592		var eventName = epoObject.is_associated ? 'tc-variation-form' : 'wc-variation-form';
9593		var eventNamePrefix = epoObject.is_associated ? 'tc_' : '';
9594		var epoVariationSection;
9595		var thismaxlength;
9596		var epoFieldAll;
9597		var selectSelector;
9598		var epoFieldText;
9599		var epoResetRadio;
9600		var epoFieldUpload;
9601		var epoFieldHasClearButton;
9602		var tmQty;
9603		var tmQuantity;
9604
9605		// Non default product (eg. composite product)
9606		if ( alternativeCart && cartContainer ) {
9607			itemId = $.epoAPI.applyFilter( 'tc_get_item_id', cartContainer.attr( 'data-item_id' ), cartContainer );
9608			epoHolder = main_product.find( '.tm-extra-product-options.tm-cart-' + itemId );
9609			totalsHolderContainer = main_product.find( '.tm-totals-form-' + itemId );
9610			totalsHolder = main_product.find( '.tm-epo-totals.tm-cart-' + itemId );
9611			variationForm = cartContainer.find( '.variations_form' ).first();
9612		// Default product
9613		} else {
9614			if ( ! main_cart || main_cart.length === 0 ) {
9615				if ( this_epo_container.is( '.tc-shortcode' ) ) {
9616					main_cart = main_product;
9617				} else {
9618					main_cart = get_main_cart( main_product, main_product, 'form', product_id );
9619				}
9620			}
9621			cartContainer = main_cart.parent();
9622			epoHolder = this_epo_container;
9623			totalsHolderContainer = this_totals_container;
9624			totalsHolder = this_epo_totals_container;
9625			variationForm = epoObject.variations_form;
9626		}
9627
9628		if ( epoObject.is_associated ) {
9629			itemId = epoHolder.attr( 'data-cart-id' );
9630		}
9631
9632		currentCart = alternativeCart || main_cart;
9633		totalsHolder.data( 'tm_for_cart', currentCart );
9634
9635		variation_id_selector = getVariationIdSelector( currentCart );
9636		qtyElement = getQtyElement( currentCart );
9637
9638		totalsHolder.data( 'variationIdElement', getVariationIdElement( currentCart, '.wceb_picker_wrap ' + variation_id_selector ) );
9639		totalsHolder.data( 'qty_element', qtyElement );
9640
9641		this_product_type = totalsHolder.data( 'type' );
9642
9643		variationForm.data( 'tc_product_id', product_id );
9644
9645		finalTotalBoxMode = totalsHolder.attr( 'data-tm-epo-final-total-box' );
9646		finalTotalBoxShowFinal = totalsHolder.attr( 'data-tm-epo-show-final-total' );
9647		finalTotalBoxShowOptions = totalsHolder.attr( 'data-tm-epo-show-options-total' );
9648
9649		jWindow.trigger( 'epoEventHandlersStart', {
9650			epo: epoObject,
9651			cart: currentCart,
9652			alternativeCart: alternativeCart,
9653			cartContainer: cartContainer,
9654			totalsHolderContainer: totalsHolderContainer,
9655			totalsHolder: totalsHolder,
9656			epoHolder: epoHolder
9657		} );
9658
9659		jWindow.on( 'epoCalculateRules', function( event, dataObject ) {
9660			if ( event && dataObject && dataObject.currentCart ) {
9661				tm_epo_rules( epoObject, dataObject.currentCart );
9662			}
9663		} );
9664
9665		if ( currentCart.is( 'form' ) ) {
9666			currentCart.on( 'reset', function() {
9667				var form = $( this );
9668				setTimeout( function() {
9669					$( form.data( 'epo_id_selector' ) ).find( '.tm-epo-field' ).trigger( 'change' );
9670				}, 1 );
9671			} );
9672		}
9673
9674		tm_epo_rules( epoObject, currentCart );
9675
9676		epoFieldAll = epoHolder.find( '.tm-epo-field' );
9677		if ( ! epoObject.is_associated ) {
9678			epoFieldAll = epoFieldAll.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-epo-field' );
9679		}
9680
9681		epoFieldText = epoHolder.find( '.tm-epo-field.tmcp-textarea,.tm-epo-field.tmcp-textfield' );
9682		if ( ! epoObject.is_associated ) {
9683			epoFieldText = epoFieldText.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-epo-field' );
9684		}
9685
9686		epoResetRadio = epoHolder.find( '.tm-epo-reset-radio' );
9687		if ( ! epoObject.is_associated ) {
9688			epoResetRadio = epoResetRadio.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-epo-reset-radio' );
9689		}
9690
9691		epoFieldUpload = epoHolder.find( '.tm-epo-field.tmcp-upload' );
9692		if ( ! epoObject.is_associated ) {
9693			epoFieldUpload = epoFieldUpload.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-epo-field.tmcp-upload' );
9694		}
9695
9696		epoFieldHasClearButton = epoHolder.find( '.tm-has-clearbutton .tm-epo-field' );
9697		if ( ! epoObject.is_associated ) {
9698			epoFieldHasClearButton = epoFieldHasClearButton.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-has-clearbutton .tm-epo-field' );
9699		}
9700
9701		tmQty = epoHolder.find( '.tm-quantity .tm-qty' );
9702		if ( ! epoObject.is_associated ) {
9703			tmQty = tmQty.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-quantity .tm-qty' );
9704		}
9705
9706		tmQuantity = epoHolder.find( '.tm-quantity' );
9707		if ( ! epoObject.is_associated ) {
9708			tmQuantity = tmQuantity.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-quantity' );
9709		}
9710
9711		selectSelector = epoHolder.find( 'select.tm-epo-field' );
9712		if ( ! epoObject.is_associated ) {
9713			selectSelector = selectSelector.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' select.tm-epo-field' );
9714		}
9715		// update price amount for select elements
9716		selectSelector
9717			.off( 'tm-select-change-html' )
9718			.on( 'tm-select-change-html', function() {
9719				var field = $( this );
9720				var e_tip;
9721				var e_description;
9722				var sign;
9723				var formatted_price;
9724
9725				if ( field.is( '.tc-epo-field-product' ) || field.is( '.tmcp-selectmultiple' ) ) {
9726					return;
9727				}
9728
9729				if ( main_cart && main_cart.data( 'per_product_pricing' ) !== undefined && ! main_cart.data( 'per_product_pricing' ) ) {
9730					return;
9731				}
9732
9733				formatted_price = tm_set_price( field.find( 'option:selected' ).data( 'price' ), totalsHolder, true, field );
9734				e_tip = field.closest( '.tmcp-field-wrap' ).find( '.tc-tooltip' );
9735				e_description = field.closest( '.tmcp-field-wrap' ).find( '.tc-inline-description' );
9736
9737				// Prices are already taxed
9738				tm_update_price( {
9739					epoObject: epoObject,
9740					obj: field.closest( '.tmcp-field-wrap' ).find( '.tc-price' ),
9741					price: field.find( 'option:selected' ).data( 'price' ),
9742					original_price: field.find( 'option:selected' ).data( 'original_price' ),
9743					force: false,
9744					useFormattedPrice: false
9745				} );
9746
9747				if ( e_tip.length > 0 ) {
9748					e_tip.attr( 'data-tm-tooltip-html', field.find( 'option:selected' ).attr( 'data-tm-tooltip-html' ) ).trigger( 'tc-tooltip-html-changed' );
9749				}
9750
9751				if ( e_description.length > 0 ) {
9752					if ( field.find( 'option:selected' ).attr( 'data-tm-tooltip-html' ) ) {
9753						e_description.html( field.find( 'option:selected' ).attr( 'data-tm-tooltip-html' ) );
9754					} else {
9755						e_description.html( '' );
9756					}
9757				}
9758
9759				if (
9760					( field.find( 'option:selected' ).attr( 'data-hide-amount' ) === '0' || TMEPOJS.tm_epo_show_price_inside_option_hidden_even === 'yes' ) &&
9761					TMEPOJS.tm_epo_show_price_inside_option === 'yes' &&
9762					field.find( 'option:selected' ).attr( 'data-text' ) &&
9763					( field.find( 'option:selected' ).data( 'price' ) || ( TMEPOJS.tm_epo_no_hide_price_if_original_not_zero === 'yes' && field.find( 'option:selected' ).data( 'original_price' ) ) )
9764				) {
9765					if (
9766						( TMEPOJS.tm_epo_auto_hide_price_if_zero === 'yes' && $.epoAPI.util.isEmpty( field.find( 'option:selected' ).data( 'price' ) ) === false ) ||
9767						( TMEPOJS.tm_epo_auto_hide_price_if_zero !== 'yes' && field.find( 'option:selected' ).attr( 'data-
9767price' ) !== '' )
9768					) {
9769						sign = '';
9770						field.find( 'option:selected' ).html( field.find( 'option:selected' ).attr( 'data-text' ) + ' (' + sign + formatted_price + ')' );
9771					} else {
9772						field.find( 'option:selected' ).html( field.find( 'option:selected' ).attr( 'data-text' ) );
9773					}
9774				}
9775
9776				if ( field.val() === '' ) {
9777					e_tip.addClass( 'tm-hidden' );
9778				} else if ( field.find( 'option:selected' ).attr( 'data-tm-tooltip-html' ) ) {
9779					e_tip.removeClass( 'tm-hidden' );
9780				} else {
9781					e_tip.addClass( 'tm-hidden' );
9782				}
9783			} )
9784			.off( 'tm-math-select-change-html-all tm-select-change-html-all tm-select-change-html-all-math' )
9785			.on( 'tm-math-select-change-html-all tm-select-change-html-all tm-select-change-html-all-math', function( event ) {
9786				var field = $( this );
9787				var e_tip;
9788				var e_description;
9789				var divider;
9790				var thisformatted_price;
9791
9792				if ( field.is( '.tc-epo-field-product' ) ) {
9793					return;
9794				}
9795
9796				e_tip = field.closest( '.tmcp-field-wrap' ).find( '.tc-tooltip' );
9797				e_description = field.closest( '.tmcp-field-wrap' ).find( '.tc-inline-description' );
9798
9799				if ( e_tip.length > 0 ) {
9800					e_tip.attr( 'data-tm-tooltip-html', field.find( 'option:selected' ).attr( 'data-tm-tooltip-html' ) ).trigger( 'tc-tooltip-html-changed' );
9801				}
9802
9803				if ( field.val() === '' ) {
9804					e_tip.addClass( 'tm-hidden' );
9805				} else if ( field.find( 'option:selected' ).attr( 'data-tm-tooltip-html' ) ) {
9806					e_tip.removeClass( 'tm-hidden' );
9807				} else {
9808					e_tip.addClass( 'tm-hidden' );
9809				}
9810
9811				if ( e_description.length > 0 ) {
9812					if ( field.find( 'option:selected' ).attr( 'data-tm-tooltip-html' ) ) {
9813						e_description.html( field.find( 'option:selected' ).attr( 'data-tm-tooltip-html' ) );
9814					} else {
9815						e_description.html( '' );
9816					}
9817				}
9818
9819				if ( main_cart && main_cart.data( 'per_product_pricing' ) !== undefined && ! main_cart.data( 'per_product_pricing' ) ) {
9820					return;
9821				}
9822
9823				if ( TMEPOJS.tm_epo_show_price_inside_option === 'yes' ) {
9824					field.find( 'option' ).toArray().forEach( function( thisoption ) {
9825						thisoption = $( thisoption );
9826						if ( ! thisoption.val() ) {
9827							return true;
9828						}
9829
9830						if ( event.type === 'tm-select-change-html-all' ) {
9831							thisoption.removeClass( 'tm-epo-late-field' ).removeData( 'tm-price-for-late islate' );
9832							tm_element_epo_rules( epoObject, field, undefined, thisoption, 1 );
9833						} else if ( event.type === 'tm-math-select-change-html-all' ) {
9834							tm_element_epo_rules( epoObject, field, undefined, thisoption, 1, true );
9835						} else if ( event.type === 'tm-select-change-html-all-math' ) {
9836							thisoption.removeClass( 'tm-epo-late-field' ).removeData( 'tm-price-for-late islate' );
9837							tm_element_epo_rules( epoObject, field, undefined, thisoption, 1, true );
9838						}
9839						divider = 1;
9840
9841						if ( TMEPOJS.tm_epo_multiply_price_inside_option !== 'yes' ) {
9842							divider = field.data( 'tm-quantity' );
9843						}
9844
9845						if ( ! divider ) {
9846							divider = 1;
9847						}
9848
9849						if ( ( TMEPOJS.tm_epo_auto_hide_price_if_zero === 'yes' && $.epoAPI.util.isEmpty( thisoption.data( 'price' ) ) === false ) || ( TMEPOJS.tm_epo_auto_hide_price_if_zero !== 'yes' && thisoption.attr( 'data-price' ) !== '' ) ) {
9850							thisformatted_price = tm_set_price( thisoption.data( 'price' ) / divider, totalsHolder, true, field );
9851
9852							if ( ( thisoption.attr( 'data-hide-amount' ) === '0' || TMEPOJS.tm_epo_show_price_inside_option_hidden_even === 'yes' ) && thisoption.attr( 'data-text' ) ) {
9853								thisoption.html( thisoption.attr( 'data-text' ) + ' (' + thisformatted_price + ')' );
9854							}
9855						} else {
9856							thisoption.html( thisoption.attr( 'data-text' ) );
9857						}
9858					} );
9859				}
9860			} )
9861			.off( 'tm-select-price-update-html-all' )
9862			.on( 'tm-select-price-update-html-all', function() {
9863				var field = $( this );
9864				var divider;
9865				var thisformatted_price;
9866
9867				if ( field.is( '.tc-epo-field-product' ) ) {
9868					return;
9869				}
9870
9871				if ( main_cart && main_cart.data( 'per_product_pricing' ) !== undefined && ! main_cart.data( 'per_product_pricing' ) ) {
9872					return;
9873				}
9874
9875				if ( TMEPOJS.tm_epo_show_price_inside_option === 'yes' ) {
9876					field.find( 'option' ).toArray().forEach( function( thisoption ) {
9877						thisoption = $( thisoption );
9878						if ( ! thisoption.val() ) {
9879							return true;
9880						}
9881
9882						divider = 1;
9883
9884						if ( TMEPOJS.tm_epo_multiply_price_inside_option !== 'yes' ) {
9885							divider = field.data( 'tm-quantity' );
9886						}
9887
9888						if ( ! divider ) {
9889							divider = 1;
9890						}
9891
9892						if ( ( TMEPOJS.tm_epo_auto_hide_price_if_zero === 'yes' && $.epoAPI.util.isEmpty( thisoption.data( 'price' ) ) === false ) || ( TMEPOJS.tm_epo_auto_hide_price_if_zero !== 'yes' && thisoption.attr( 'data-price' ) !== '' ) ) {
9893							thisformatted_price = tm_set_price( thisoption.data( 'price' ) / divider, totalsHolder, true, field );
9894
9895							if ( ( thisoption.attr( 'data-hide-amount' ) === '0' || TMEPOJS.tm_epo_show_price_inside_option_hidden_even === 'yes' ) && thisoption.attr( 'data-text' ) ) {
9896								thisoption.html( thisoption.attr( 'data-text' ) + ' (' + thisformatted_price + ')' );
9897							}
9898						} else {
9899							thisoption.html( thisoption.attr( 'data-text' ) );
9900						}
9901					} );
9902				}
9903			} )
9904			.off( 'tm-select-change' )
9905			.on( 'tm-select-change', function() {
9906				var field = $( this );
9907				var thisElementId = field.closest( '.cpf-element' ).attr( 'data-uniqid' );
9908
9909				if ( field.is( '.tc-epo-field-product' ) ) {
9910					return;
9911				}
9912
9913				if ( main_cart && main_cart.data( 'per_product_pricing' ) !== undefined && ! main_cart.data( 'per_product_pricing' ) ) {
9914					return;
9915				}
9916
9917				field.removeData( 'addedtcEpoBeforeOptionPriceCalculation' );
9918				field.removeData( 'addedfieldtcEpoBeforeOptionPriceCalculation' );
9919				jWindow.off( 'tcEpoBeforeOptionPriceCalculation.math' + thisElementId );
9920				jWindow.off( 'tcEpoAfterNormalOptionPriceCalculation.math' + thisElementId );
9921
9922				field.trigger( 'tm-select-change-html' );
9923				field.trigger( 'tm-select-change-html-all' );
9924
9925				currentCart.trigger( {
9926					type: 'tm-epo-update',
9927					norules: 1,
9928					element: field
9929				} );
9930			} ).trigger( 'tm-select-change-html-all' );
9931
9932		// Element quantity selector
9933		tmQty
9934			.off( 'focus.cpf' )
9935			.on( 'focus.cpf', function() {
9936				var qtyField = $( this );
9937				var field = qtyField.closest( '.tmcp-field-wrap' ).find( '.tm-epo-field' );
9938				var currentVal = parseFloat( qtyField.val() );
9939				var max = parseFloat( qtyField.attr( 'max' ) );
9940				var min = parseFloat( qtyField.attr( 'min' ) );
9941				var step = qtyField.attr( 'step' );
9942				var check1 = tm_limit_c_selection( field, false );
9943				var check2 = tm_exact_c_selection( field, false );
9944				var check3 = true;
9945
9946				// Format values
9947				if ( ! currentVal || currentVal === '' || currentVal === 'NaN' ) {
9948					currentVal = 0;
9949				}
9950				if ( max === '' || max === 'NaN' ) {
9951					max = '';
9952				}
9953				if ( min === '' || min === 'NaN' ) {
9954					min = 0;
9955				}
9956				if ( step === 'any' || step === '' || step === undefined || parseFloat( step ) === 'NaN' ) {
9957					step = 1;
9958				}
9959
9960				if ( currentVal < min || currentVal > max ) {
9961					check3 = false;
9962				}
9963
9964				if ( check1 && check2 && check3 ) {
9965					setQtyData( qtyField, currentVal );
9966				} else {
9967					setQtyData( qtyField, min );
9968				}
9969			} )
9970			.off( 'change.cpf' )
9971			.on( 'change.cpf', function( event, data ) {
9972				var qtyField = $( this );
9973				var field = qtyField.closest( '.tmcp-field-wrap' ).find( '.tm-epo-field' );
9974				var currentVal = parseFloat( qtyField.val() );
9975				var max = parseFloat( qtyField.attr( 'max' ) );
9976				var min = parseFloat( qtyField.attr( 'min' ) );
9977				var step = qtyField.attr( 'step' );
9978				var check1 = tm_limit_c_selection( field, false );
9979				var check2 = tm_exact_c_selection( field, false );
9980				var check3 = true;
9981
9982				// Format values
9983				if ( ! currentVal || currentVal === '' || currentVal === 'NaN' ) {
9984					currentVal = 0;
9985				}
9986				if ( max === '' || max === 'NaN' ) {
9987					max = '';
9988				}
9989				if ( min === '' || min === 'NaN' ) {
9990					min = 0;
9991				}
9992				if ( step === 'any' || step === '' || step === undefined || parseFloat( step ) === 'NaN' ) {
9993					step = 1;
9994				}
9995
9996				if ( currentVal < min || currentVal > max ) {
9997					check3 = false;
9998				}
9999
10000				if ( check1 && check2 && check3 ) {
10001					if ( ! epoObject.noEpoUpdate ) {
10002						field.data( 'tm-quantity', qtyField.val() ).trigger( 'change', data );
10003					} else {
10004						field.data( 'tm-quantity', qtyField.val() ).trigger( 'change.cpf', data ).trigger( 'change.cpfproduct', data );
10005					}
10006					field.trigger( 'tm-select-change-html-all' );
10007				} else if ( qtyField.data( 'epopreviousvalue' ) ) {
10008					qtyField.val( qtyField.data( 'epopreviousvalue' ) );
10009				} else {
10010					qtyField.val( min );
10011				}
10012
10013				qtyField.trigger( 'cpf-changed' );
10014			} )
10015			.off( 'tmaddquantity' )
10016			.on( 'tmaddquantity', function() {
10017				var qtyField = $( this );
10018				var field = qtyField.closest( '.tmcp-field-wrap' ).find( '.tm-epo-field' );
10019
10020				field.data( 'tm-quantity', qtyField.val() );
10021			} );
10022
10023		// Insert characters remaining for text-areas and text-fields
10024		thismaxlength = epoHolder.find( '.tmcp-textfield.tm-epo-field[maxlength],textarea.tm-epo-field[maxlength]' );
10025		if ( ! epoObject.is_associated ) {
10026			thismaxlength = thismaxlength.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-epo-field' );
10027		}
10028
10029		thismaxlength.toArray().forEach( function( field ) {
10030			var innerWrap;
10031			var html;
10032			field = $( field );
10033			if ( field.data( 'tcmaxlength' ) ) {
10034				return;
10035			}
10036			field.data( 'tcmaxlength', 1 );
10037			innerWrap = field.closest( '.tmcp-field-wrap-inner' );
10038			html = $.epoAPI.template.html( tcAPI.templateEngine.tc_chars_remanining, {
10039				maxlength: field.attr( 'maxlength' ),
10040				characters_remaining: TMEPOJS.i18n_characters_remaining
10041			} );
10042			innerWrap.append( $( html ) );
10043		} );
10044		thismaxlength
10045			.off( 'change.tc_maxlen input.tc_maxlen' )
10046			.on( 'change.tc_maxlen input.tc_maxlen', function() {
10047				var field = $( this );
10048
10049				field
10050					.closest( '.tmcp-field-wrap' )
10051					.find( '.tc-chars-remanining' )
10052					.html( parseInt( field.attr( 'maxlength' ), 10 ) - parseInt( field.val().length, 10 ) );
10053			} );
10054
10055		// Change product image event
10056		epoFieldAll
10057			.off( 'tm_trigger_product_image' )
10058			.on( 'tm_trigger_product_image', function() {
10059				var field = $( this );
10060				var currentElement;
10061				var uic;
10062				var variation_element_section;
10063				var is_variation_element;
10064				var src;
10065
10066				if ( field.is( '.tm-product-image:checkbox, .tm-product-image:radio, select.tm-product-image' ) ) {
10067					uic = field.closest( '.tmcp-field-wrap' ).find( 'label img' );
10068					variation_element_section = field.closest( '.cpf-section' );
10069					is_variation_element = variation_element_section.is( '.tm-epo-variation-section' );
10070
10071					currentElement = field;
10072					if ( field.is( 'select.tm-product-image' ) ) {
10073						currentElement = field.children( 'option:selected' );
10074					}
10075					if (
10076						$( uic ).length > 0 ||
10077						( is_variation_element && currentElement.attr( 'data-image' ) !== undefined ) ||
10078						( currentElement.attr( 'data-image' ) !== undefined && currentElement.attr( 'data-image' ) !== '' ) ||
10079						( currentElement.attr( 'data-imagep' ) !== undefined && currentElement.attr( 'data-imagep' ) !== '' )
10080					) {
10081						if ( field.is( ':checked' ) || ( field.is( 'select.tm-product-image' ) && field.val() !== '' && ( field.find( 'option:selected' ).attr( 'data-rules' ) !== '' || field.is( '.tm-epo-variation-element' ) ) ) ) {
10082							src = $( uic ).first().attr( 'data-original' );
10083
10084							if ( ! src && ! is_variation_element ) {
10085								src = $( uic ).first().attr( 'src' );
10086							}
10087							if ( ! src ) {
10088								src = currentElement.attr( 'data-image' );
10089							}
10090							if ( currentElement.attr( 'data-imagep' ) ) {
10091								src = currentElement.attr( 'data-imagep' );
10092							}
10093							if ( src ) {
10094								main_product.trigger( 'tm_change_product_image', {
10095									src: src,
10096									element: field,
10097									element_current: currentElement,
10098									main_product: main_product,
10099									epo_holder: epoHolder
10100								} );
10101							} else {
10102								main_product.trigger( 'tm_change_product_image', {
10103									src: false,
10104									element: field,
10105									element_current: currentElement,
10106									main_product: main_product,
10107									epo_holder: epoHolder
10108								} );
10109							}
10110						} else {
10111							main_product.trigger( 'tm_restore_product_image', {
10112								element: field,
10113								element_current: currentElement,
10114								main_product: main_product,
10115								epo_holder: epoHolder
10116							} );
10117						}
10118					} else {
10119						main_product.trigger( 'tm_restore_product_image', {
10120							element: field,
10121							element_current: currentElement,
10122							main_product: main_product,
10123							epo_holder: epoHolder
10124						} );
10125					}
10126				} else {
10127					main_product.trigger( 'tm_attempt_product_image', {
10128						element: field,
10129						element_current: currentElement,
10130						main_product: main_product,
10131						epo_holder: epoHolder
10132					} );
10133				}
10134			} );
10135
10136		tmQuantity
10137			.off( 'showhide.cpfcustom' )
10138			.on( 'showhide.cpfcustom', function() {
10139				var quantity_selector = $( this );
10140				var field = quantity_selector.closest( '.tmcp-field-wrap' ).find( '.tm-epo-field' );
10141				var show = false;
10142				var tmqty;
10143				var tmqtyval;
10144				var tmqtymin;
10145				var radios;
10146				var tmqtybuttons;
10147
10148				if ( ! field.is( '.tm-epo-variation-element' ) ) {
10149					if ( field.is( 'select' ) ) {
10150						if ( field.val() !== '' ) {
10151							show = true;
10152						}
10153					} else if ( field.is( ':checkbox' ) ) {
10154						if ( field.is( ':checked' ) ) {
10155							show = true;
10156						}
10157					} else if ( field.is( ':radio' ) ) {
10158						if ( field.is( ':checked' ) ) {
10159							show = true;
10160							if ( TMEPOJS.tm_epo_show_only_active_quantities === 'yes' ) {
10161								radios = field.closest( '.tc-element-inner-wrap' ).find( '.tm-epo-field.tmcp-radio' );
10162								radios.toArray().forEach( function( rd ) {
10163									$( rd ).closest( '.tmcp-field-wrap' ).find( '.tm-quantity' ).hide();
10164								} );
10165							}
10166						}
10167					} else if ( field.val() ) {
10168						show = true;
10169					}
10170
10171					tmqty = quantity_selector.find( '.tm-qty' );
10172					tmqtybuttons = quantity_selector.find( '.tc-qty-button' );
10173					tmqtyval = tmqty.val();
10174					tmqtymin = tmqty.attr( 'min' ) || '';
10175
10176					if ( show ) {
10177						if ( TMEPOJS.tm_epo_show_only_active_quantities === 'yes' ) {
10178							quantity_selector.show();
10179						}
10180
10181						tmqty.removeClass( 'ignore' ).prop( 'disabled', false );
10182						tmqtybuttons.prop( 'disabled', false );
10183					} else {
10184						if ( TMEPOJS.tm_epo_show_only_active_quantities === 'yes' ) {
10185							quantity_selector.hide();
10186							if ( ! tmqtyval ) {
10187								tmqty.val( tmqtymin );
10188							}
10189						}
10190
10191						tmqty.addClass( 'ignore' ).prop( 'disabled', true );
10192						tmqtybuttons.prop( 'disabled', true );
10193					}
10194
10195					if ( epoHolder.is( '.tc-show' ) ) {
10196						setTimeout( function() {
10197							quantity_selector.closest( '.tcowl-carousel' ).trigger( 'refresh.owl.carousel' );
10198						}, 200 );
10199					}
10200				}
10201			} );
10202
10203		epoFieldAll
10204			.off( 'change.cpfcustom' )
10205			.on( 'change.cpfcustom', function() {
10206				$( this ).closest( '.tmcp-field-wrap' ).find( '.tm-quantity' ).trigger( 'showhide.cpfcustom' );
10207			} );
10208
10209		epoFieldAll
10210			.off( 'change.cpf' )
10211			.on( 'change.cpf', function( event, data ) {
10212				var field = $( this );
10213				var is_li = field.closest( '.tmcp-field-wrap' );
10214				var is_ul = field.closest( '.tmcp-ul-wrap' );
10215				var is_replace;
10216				var connector = is_ul.attr( 'data-tm-connector' );
10217
10218				if ( field.is( ':checkbox, :radio' ) ) {
10219					if ( field.is( ':radio' ) ) {
10220						if ( ! data ) {
10221							if ( connector !== undefined ) {
10222								$( '[data-tm-connector="' + connector + '"]' ).find( '.tmcp-field-wrap' ).removeClass( 'tc-active' ).find( '.tm-epo-reset-radio' ).addClass( 'tm-hidden' );
10223							} else {
10224								is_ul.find( '.tmcp-field-wrap' ).removeClass( 'tc-active' );
10225							}
10226						}
10227						if ( connector !== undefined ) {
10228							$( '[data-tm-connector="' + connector + '"]' ).find( '.tmcp-field-wrap' ).removeClass( 'tc-active' ).find( '.tm-epo-reset-radio' ).addClass( 'tm-hidden' );
10229						}
10230					}
10231					if ( field.is( ':checked' ) ) {
10232						is_li.addClass( 'tc-active' );
10233					} else {
10234						is_li.removeClass( 'tc-active' );
10235					}
10236				}
10237
10238				if ( ! field.is( '.tm-epo-variation-element' ) ) {
10239					if ( field.is( '.use_images:checkbox, .use_images:radio' ) && field.attr( 'data-imagec' ) ) {
10240						is_replace = is_li.find( '.radio-image,.checkbox-image' ).first();
10241						if ( is_replace.length > 0 ) {
10242							if ( field.is( ':checked' ) ) {
10243								is_replace.prop( 'src', field.attr( 'data-imagec' ) );
10244							} else {
10245								is_replace.prop( 'src', field.attr( 'data-image' ) );
10246							}
10247						}
10248					}
10249
10250					if ( field.is( '.use_images:radio' ) && ! data ) {
10251						field
10252							.closest( '.cpf-type-radio' )
10253							.find( '.use_images:radio' )
10254							.not( field )
10255							.toArray().forEach( function( r ) {
10256								r = $( r );
10257								r.closest( '.tmcp-field-wrap' ).find( '.radio-image' ).first().prop( 'src', r.attr( 'data-image' ) );
10258							} );
10259					}
10260
10261					if ( field.is( '.tmcp-range' ) ) {
10262						field.trigger( 'change.cpflogic' );
10263					}
10264					if ( field.is( 'select' ) ) {
10265						field.trigger( 'tm-select-change' );
10266					} else {
10267						if ( field.is( '.tmcp-radio' ) ) {
10268							field
10269								.closest( '.cpf-element' )
10270								.find( '.tm-quantity .tm-qty' )
10271								.toArray().forEach( function( tmqty ) {
10272									tmqty = $( tmqty );
10273									if ( ! tmqty.closest( 'li.tmcp-field-wrap' ).find( '.tmcp-radio' ).is( ':checked' ) ) {
10274										tmqty.attr( 'disabled', 'disabled' );
10275									} else {
10276										tmqty.prop( 'disabled', false );
10277									}
10278								} );
10279						}
10280						priceCache = true;
10281						currentCart.trigger( {
10282							type: 'tm-epo-update',
10283							norules: 1,
10284							element: field
10285						} );
10286						priceCache = false;
10287					}
10288				}
10289
10290				field.trigger( 'tm_trigger_product_image' );
10291
10292				if ( epoHolder.is( '.tc-show' ) ) {
10293					setTimeout( function() {
10294						$( '.tm-owl-slider' ).toArray().forEach( function( slider ) {
10295							$( slider ).trigger( 'refresh.owl.carousel' );
10296						} );
10297					}, 200 );
10298				}
10299				main_product.trigger( 'tm_attempt_product_image', {
10300					element: field,
10301					main_product: main_product,
10302					epo_holder: epoHolder
10303				} );
10304			} );
10305
10306		epoFieldAll.filter( '.tm-epo-field:text,input.tm-epo-field[type="number"],textarea.tm-epo-field' )
10307			.off( 'input.cpf' )
10308			.on( 'input.cpf', function() {
10309				$( this ).trigger( 'change.cpf', { autoload: 1 } );
10310			} );
10311
10312		epoFieldAll
10313			.filter( ':checkbox:checked, :radio:checked' )
10314			.toArray().forEach( function( cb ) {
10315				$( cb )
10316					.closest( '.tmcp-field-wrap' )
10317					.addClass( 'tc-active' )
10318					.trigger( 'change.cpf', { autoload: 1 } );
10319			} );
10320
10321		epoFieldHasClearButton
10322			.off( 'change.cpfclearbutton' )
10323			.on( 'change.cpfclearbutton cpfclearbutton', function() {
10324				var field = $( this );
10325				var radioResetElement;
10326				var fieldWrap = field.closest( '.tmcp-field-wrap' );
10327				var fieldSearch;
10328
10329				if ( field.is( ':checked' ) ) {
10330					fieldSearch = field.closest( '.tc-element-inner-wrap' );
10331
10332					if ( fieldSearch.find( '.tc-epo-element-product-li-container' ).length ) {
10333						fieldSearch = fieldSearch.find( '.tmcp-ul-wrap' ).first().children( '.tmcp-field-wrap' ).not( '.tc-epo-element-product-li-container' );
10334					}
10335
10336					radioResetElement = fieldSearch.find( '.tm-epo-reset-radio' );
10337					if ( ! radioResetElement.length ) {
10338						radioResetElement = field.closest( '.tc-element-inner-wrap' ).find( '.tm-epo-reset-radio' ).first();
10339					}
10340					radioResetElement.removeClass( 'tm-hidden' );
10341
10342					fieldWrap.append( radioResetElement );
10343				}
10344			} );
10345
10346		epoResetRadio
10347			.off( 'click.cpf' )
10348			.on( 'click.cpf', function() {
10349				var radioResetElement = $( this );
10350				var fieldContainer = radioResetElement.closest( '.tc-element-inner-wrap' );
10351				var checkedRadios = fieldContainer.find( '.tm-epo-field.tmcp-radio:checked' );
10352
10353				if ( checkedRadios.length ) {
10354					checkedRadios.prop( 'checked', false );
10355					checkedRadios.trigger( 'change', { forced: 1 } );
10356				}
10357
10358				radioResetElement.addClass( 'tm-hidden' );
10359			} );
10360
10361		if ( _ && _.debounce ) {
10362			epoFieldText.on( 'keyup',
10363				_.debounce( function() {
10364					var $this = $( this );
10365					var mainform = currentCart;
10366					if ( epoObject.is_associated ) {
10367						mainform = epoObject.mainEpoObject.form;
10368					}
10369
10370					if ( TMEPOJS.tm_epo_global_enable_validation === 'yes' && $.tc_validator && $this.closest( '.tmcp-ul-wrap' ).data( 'tm-validation' ) && $this.tc_rules() ) {
10371						mainform.tc_validate().element( $this );
10372					}
10373					$this.trigger( 'change.cpf' );
10374					$this.closest( '.tmcp-field-wrap' ).find( '.tm-quantity' ).trigger( 'showhide.cpfcustom' );
10375				}, 10 )
10376			);
10377		}
10378
10379		epoFieldUpload
10380			.off( 'change.cpfv tcupload' )
10381			.on( 'change.cpfv tcupload', function() {
10382				var field = $( this );
10383				var label = field.closest( 'label' );
10384				var li = field.closest( '.tmcp-field-wrap' );
10385				var cpfUploadContainer = li.find( '.cpf-upload-container' );
10386				var name = li.find( '.tm-filename' );
10387				var val = field.val().replace( 'C:\\fakepath\\', '' );
10388				var valHidden = [];
10389				var num_uploads;
10390				var windowURL = window.URL || window.webkitURL;
10391				var files;
10392				var image;
10393				var uploadPreview = li.find( '.tc-upload-preview' );
10394				var addImage;
10395				var uniqid;
10396
10397				if ( cpfUploadContainer.length && name.length <= 0 ) {
10398					name = $( '<span class="tm-filename"></span>' );
10399					label.after( name );
10400				}
10401				if ( val === undefined || val === 'undefined' ) {
10402					val = '';
10403				}
10404
10405				field.next( '.tmcp-upload-hidden' ).remove();
10406
10407				valHidden = field.attr( 'data-file' );
10408				valHidden = valHidden ? valHidden.split( '|' ) : [];
10409				if ( this.files ) {
10410					files = Array.from( this.files );
10411				} else if ( valHidden.length > 0 ) {
10412					files = valHidden;
10413				}
10414
10415				if ( files.length > 1 ) {
10416					name.html( '' + files.length + ' ' + ( files.length === 1 ? TMEPOJS.i18n_file : TMEPOJS.i18n_files ) );
10417				} else if ( files.length === 1 ) {
10418					name.html( val );
10419				} else {
10420					name.empty();
10421				}
10422				if ( ! uploadPreview.length ) {
10423					uploadPreview = $( '<div class="tc-upload-preview tc-hidden"></div>' );
10424					li.append( uploadPreview );
10425				}
10426
10427				uploadPreview.empty();
10428
10429				num_uploads = epoHolder.data( 'num_uploads' );
10430				if ( ! num_uploads ) {
10431					num_uploads = [];
10432				}
10433				uniqid = field.closest( '.cpf-element' ).attr( 'data-uniqid' );
10434				if ( ! num_uploads[ uniqid ] ) {
10435					num_uploads[ uniqid ] = [];
10436				}
10437
10438				if ( ( val || files.length > 0 ) && windowURL && windowURL.createObjectURL ) {
10439					if ( TMEPOJS.tm_epo_upload_inline_image_preview === 'yes' ) {
10440						if ( files.length > 1 ) {
10441							uploadPreview.addClass( 'multiple' );
10442						} else {
10443							uploadPreview.removeClass( 'multiple' );
10444						}
10445						uploadPreview.removeClass( 'tc-hidden' );
10446					}
10447					addImage = function( dataFile, src, i, fileHolder, ext ) {
10448						var size = field[ 0 ].files && field[ 0 ].files[ i ] && field[ 0 ].files[ i ].size ? field[ 0 ].files[ i ].size : 0;
10449						var imageHTML = '<div class="tc-upload-image">';
10450						if ( src ) {
10451							imageHTML = imageHTML + '<img src="' + src + '">';
10452						} else {
10453							imageHTML = imageHTML + '<div class="tc-file-ext-overlay"></div>';
10454						}
10455						imageHTML = imageHTML + '<div class="tc-file-name">' + dataFile.name + '</div>';
10456						if ( ClipboardEvent || DataTransfer ) {
10457							imageHTML = imageHTML + '<button type="button" class="tc-upload-remove"><svg width="26" height="26" viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg"><path d="M11.586 13l-2.293 2.293a1 1 0 0 0 1.414 1.414L13 14.414l2.293 2.293a1 1 0 0 0 1.414-1.414L14.414 13l2.293-2.293a1 1 0 0 0-1.414-1.414L13 11.586l-2.293-2.293a1 1 0 0 0-1.414 1.414L11.586 13z" fill="currentColor" fill-rule="nonzero"/></svg></button>';
10458						}
10459						if ( ext ) {
10460							imageHTML = imageHTML + '<div class="tc-file-ext">' + ext + '</div>';
10461						}
10462						imageHTML = imageHTML + '<div class="tc-file-size">' + readableFileSize( size ) + '</div>';
10463						imageHTML = imageHTML + '</div>';
10464						fileHolder.append( imageHTML );
10465					};
10466
10467					files.forEach( function( dataFile, i ) {
10468						var fileHolder;
10469						if ( TMEPOJS.tm_epo_upload_inline_image_preview === 'yes' ) {
10470							fileHolder = $( '<div class="tc-upload-file"></div>' );
10471							uploadPreview.append( fileHolder );
10472							image = new Image();
10473							image.onload = function() {
10474								addImage( dataFile, this.src, i, fileHolder );
10475							};
10476							image.onerror = function() {
10477								addImage( dataFile, false, i, fileHolder, dataFile.name.split( '.' ).pop() );
10478							};
10479							if ( valHidden.length > 0 ) {
10480								image.src = valHidden[ i ];
10481							} else {
10482								image.src = windowURL.createObjectURL( dataFile );
10483								windowURL.revokeObjectURL( dataFile );
10484							}
10485						}
10486						num_uploads[ uniqid ].push( dataFile.name );
10487					} );
10488					epoHolder.data( 'num_uploads', num_uploads );
10489				} else {
10490					delete num_uploads[ uniqid ];
10491				}
10492				if ( num_uploads[ uniqid ] && num_uploads[ uniqid ].length === 0 ) {
10493					delete num_uploads[ uniqid ];
10494				}
10495			} );
10496
10497		jDocument.on( 'click', '.tc-upload-remove', function() {
10498			var $this = $( this );
10499			var val;
10500			var cpfElement;
10501			var input;
10502			var fileWrap;
10503			var li;
10504			var uploadPreview;
10505			var name;
10506			var index;
10507			var files;
10508			var dT;
10509			var num_uploads;
10510			var uniqid;
10511			var uploadHidden;
10512			var dataFiles;
10513
10514			if ( ClipboardEvent || DataTransfer ) {
10515				cpfElement = $this.closest( '.cpf-element' );
10516				input = cpfElement.find( '.tm-epo-field' );
10517				fileWrap = $this.closest( '.tc-upload-file' );
10518				li = $this.closest( '.tmcp-field-wrap' );
10519				uploadPreview = li.find( '.tc-upload-preview' );
10520				name = li.find( '.tm-filename' );
10521				index = fileWrap.index();
10522				val = input.val().replace( 'C:\\fakepath\\', '' );
10523				if ( val === undefined || val === 'undefined' ) {
10524					val = '';
10525				}
10526
10527				files = Array.from( input[ 0 ].files );
10528				files.splice( index, 1 );
10529				dT = new ClipboardEvent( '' ).clipboardData || new DataTransfer();
10530
10531				files.forEach( function( dataFile ) {
10532					dT.items.add( dataFile );
10533				} );
10534
10535				if ( files.length > 1 ) {
10536					uploadPreview.addClass( 'multiple' );
10537				} else {
10538					uploadPreview.removeClass( 'multiple' );
10539				}
10540
10541				input[ 0 ].files = dT.files;
10542				fileWrap.remove();
10543				if ( dT.files.length > 1 ) {
10544					name.html( '' + dT.files.length + ' ' + ( dT.files.length === 1 ? TMEPOJS.i18n_file : TMEPOJS.i18n_files ) );
10545				} else if ( dT.files.length === 1 ) {
10546					name.html( val );
10547				} else {
10548					name.empty();
10549				}
10550
10551				num_uploads = epoHolder.data( 'num_uploads' );
10552				if ( ! num_uploads ) {
10553					num_uploads = [];
10554				}
10555				uniqid = cpfElement.closest( '.cpf-element' ).attr( 'data-uniqid' );
10556				if ( ! num_uploads[ uniqid ] ) {
10557					num_uploads[ uniqid ] = [];
10558				}
10559
10560				num_uploads[ uniqid ].splice( index, 1 );
10561				if ( num_uploads[ uniqid ].length === 0 ) {
10562					delete num_uploads[ uniqid ];
10563					input.val( '' );
10564				}
10565
10566				uploadHidden = input.next( '.tmcp-upload-hidden' );
10567				if ( uploadHidden.length ) {
10568					dataFiles = uploadHidden.val().split( '|' );
10569					if ( dataFiles.length > 0 ) {
10570						dataFiles.splice( index, 1 );
10571					}
10572					if ( dataFiles.length === 0 ) {
10573						uploadHidden.remove();
10574					} else {
10575						uploadHidden.val( dataFiles.join( '|' ) );
10576					}
10577				}
10578
10579				epoHolder.data( 'num_uploads', num_uploads );
10580			}
10581		} );
10582
10583		qtyElement
10584			.off( 'change.cpf input.cpf' )
10585			.on( 'change.cpf input.cpf', function() {
10586				var field = $( this );
10587
10588				currentCart.trigger( 'tm-epo-check-dpd' );
10589				setQtyData( field );
10590				// It is required than when you update the product quantity
10591				// to recalculate the option price to accommodate price types
10592				// that depend on quantity
10593				currentCart.trigger( {
10594					type: 'tm-epo-update',
10595					norules: 2
10596				} );
10597			} );
10598		setQtyData( qtyElement );
10599		// Support for math formula on associated products when they are initially hidden
10600		epoHolder
10601			.find( '.cpf-type-product' )
10602			.off( 'tc-logic' )
10603			.on( 'tc-logic', function() {
10604				var $this = $( this );
10605				if ( $this.find( '.tc-init' ).length ) {
10606					return;
10607				}
10608				if ( $this.data( 'isactive' ) && ! $this.data( 'donetclogic' ) ) {
10609					$this.data( 'donetclogic', true );
10610					$this.find( '.tc-epo-field-product' ).trigger( 'change.cpfproduct', { forced: 3 } );
10611				}
10612			} );
10613
10614		// Product element checkbox required status fix
10615		epoHolder
10616			.find( '.cpf-type-product .tc-epo-field-product.tc-epo-field-product-checkbox' )
10617			.off( 'change.cpfrequired' )
10618			.on( 'change.cpfrequired', function() {
10619				var $this = $( this );
10620				var cpfElement = $this.closest( '.cpf-element' );
10621				var checkboxes;
10622				var checkboxesChecked;
10623				var checkboxesNotChecked;
10624				if ( cpfElement.is( '.tc-is-required' ) ) {
10625					checkboxes = cpfElement.find( '.tmcp-field.tc-epo-field-product-checkbox' );
10626					checkboxesNotChecked = checkboxes.not( ':checked' );
10627					checkboxesChecked = cpfElement.find( '.tmcp-field.tc-epo-field-product-checkbox:checked' );
10628
10629					if ( checkboxesChecked.length > 0 ) {
10630						checkboxesNotChecked.prop( 'required', false );
10631						checkboxesChecked.prop( 'required', true );
10632					} else {
10633						checkboxes.attr( 'required', true );
10634						checkboxes.prop( 'required', true );
10635					}
10636				}
10637			} );
10638
10639		// Product element variable product support
10640		epoHolder
10641			.find( '.cpf-type-product .tc-epo-field-product' )
10642			.off( 'change.cpfproduct' )
10643			.on( 'change.cpfproduct', function( e, data ) {
10644				var $this = $( this );
10645				var value;
10646				var type;
10647				var selected;
10648				var variableProductContainers;
10649				var thisVariableProductContainer;
10650				var elementContainer = $this.closest( '.cpf-element' );
10651				var productContainerWraps = elementContainer.find( '.tc-epo-element-product-container-wrap' );
10652				var thisProductContainerWrap = $this.closest( '.tmcp-field-wrap' ).find( '.tc-epo-element-product-container-wrap' );
10653				var hasProductContainerWrap = thisProductContainerWrap.length > 0;
10654				var postData;
10655				var skip = false;
10656				var isTrigger = 1000;
10657				var qtyalt;
10658				var associatedSetter = $this;
10659				var associatedElement;
10660				var isFilled;
10661				var productPrice;
10662				var originalProductPrice;
10663				var epoField = elementContainer.find( '.tm-epo-field' ).not( '.tc-epo-element-product-li-container .tm-epo-field' );
10664				var checked = epoField.filter( ':checked' );
10665				var qty;
10666				var counter = $this.attr( 'data-counter' );
10667
10668				if ( false === elementContainer.data( 'isactive' ) ) {
10669					return;
10670				}
10671				if ( data && data.forced === 2 ) {
10672					return;
10673				}
10674
10675				if ( e.isTrigger !== undefined && $this.data( 'triggeredonce' ) && ! ( data && data.forced ) ) {
10676					return;
10677				}
10678
10679				if ( $this.data( 'triggeredforced' ) === 3 ) {
10680					return;
10681				}
10682
10683				$this.data( 'triggeredonce', 1 );
10684
10685				if ( ! $this.is( ':checkbox' ) ) {
10686					isTrigger = e.isTrigger;
10687				}
10688
10689				if ( epoField.is( ':radio' ) ) {
10690					if ( checked.length > 0 ) {
10691						qty = checked.closest( '.tmcp-field-wrap' ).find( 'input.tm-qty' );
10692					}
10693				} else if ( epoField.is( ':checkbox' ) ) {
10694					if ( checked.length > 0 ) {
10695						qty = $this.closest( '.tmcp-field-wrap' ).find( 'input.tm-qty' );
10696					}
10697				} else {
10698					qty = epoField.closest( '.tmcp-field-wrap' ).find( 'input.tm-qty' );
10699				}
10700
10701				if ( $this.is( ':checkbox' ) ) {
10702					if ( $this.is( '.tc-epo-field-product-hidden' ) ) {
10703						if ( $this.is( ':checked' ) ) {
10704							productContainerWraps.addClass( 'tc-active-product' );
10705						} else {
10706							productContainerWraps.removeClass( 'tc-active-product' );
10707						}
10708
10709						value = $this.val();
10710						type = $this.attr( 'data-type' );
10711						elementContainer.find( '.tc-epo-element-product-li-container:not(.tc-hidden-container .tc-epo-element-product-li-container)' ).removeClass( 'tm-hidden' );
10712					} else {
10713						if ( ! $this.is( ':checked' ) ) {
10714							if ( hasProductContainerWrap ) {
10715								thisProductContainerWrap.addClass( 'tm-hidden' );
10716							}
10717							if ( ! ( data && data.forced ) ) {
10718								return;
10719							}
10720							skip = true;
10721						} else if ( hasProductContainerWrap ) {
10722							thisProductContainerWrap.removeClass( 'tm-hidden' );
10723						}
10724						if ( ! skip ) {
10725							value = $this.val();
10726							type = $this.attr( 'data-type' );
10727							elementContainer.find( '.tc-epo-element-product-li-container:not(.tc-hidden-container .tc-epo-element-product-li-container)' ).removeClass( 'tm-hidden' );
10728						}
10729					}
10730				} else if ( $this.is( ':radio' ) ) {
10731					if ( ! $this.is( ':checked' ) ) {
10732						if ( hasProductContainerWrap ) {
10733							thisProductContainerWrap.addClass( 'tm-hidden' );
10734						}
10735						if ( ! ( data && data.forced ) ) {
10736							return;
10737						}
10738						skip = true;
10739					} else if ( hasProductContainerWrap ) {
10740						productContainerWraps.addClass( 'tm-hidden' );
10741						thisProductContainerWrap.removeClass( 'tm-hidden' );
10742					}
10743					if ( ! skip ) {
10744						value = $this.val();
10745						type = $this.attr( 'data-type' );
10746						elementContainer.find( '.tc-epo-element-product-li-container:not(.tc-hidden-container .tc-epo-element-product-li-container)' ).removeClass( 'tm-hidden' );
10747					}
10748				} else if ( $this.is( 'select' ) ) {
10749					selected = $this.children( ':selected' );
10750					associatedSetter = selected;
10751					counter = selected.index();
10752					if ( $this.children( ':first' ).val() === '' ) {
10753						counter--;
10754					}
10755					value = $this.val();
10756					type = selected.attr( 'data-type' );
10757					elementContainer.find( '.tc-epo-element-product-li-container:not(.tc-hidden-container .tc-epo-element-product-li-container)' ).removeClass( 'tm-hidden' );
10758				}
10759
10760				if ( $this.is( '.tc-epo-field-product-checkbox' ) ) {
10761					variableProductContainers = thisProductContainerWrap.find( '.tc-epo-element-product-container' );
10762				} else {
10763					variableProductContainers = elementContainer.find( '.tc-epo-element-product-container' );
10764				}
10765
10766				thisVariableProductContainer = variableProductContainers.filter( '[data-product_id="' + value + '"]' );
10767
10768				qtyalt = thisVariableProductContainer.find( tcAPI.associateQtySelector );
10769
10770				if ( productContainerWraps.html() !== '' && qty && qty.length > 0 && qtyalt.length === 0 ) {
10771					qty.val( 0 );
10772				}
10773				if ( $this.is( ':checkbox' ) ) {
10774					if ( $this.is( '.tc-epo-field-product-hidden' ) ) {
10775						if ( $this.is( ':checked' ) ) {
10776							if ( qtyalt.val() === '0' ) {
10777								if ( qtyalt.attr( 'min' ) !== '0' ) {
10778									qtyalt.val( qtyalt.attr( 'min' ) ).trigger( 'change' );
10779								}
10780							}
10781						} else {
10782							qtyalt.val( 0 );
10783							qtyalt.closest( '.tm-quantity-alt' ).removeClass( 'tm-hidden' );
10784							if ( data.forced !== 1 ) {
10785								qtyalt.closest( '.tm-quantity-alt' ).find( '.single_add_to_cart_product' ).trigger( 'cpfqtybutton' );
10786							}
10787							productContainerWraps.find( tcAPI.associatedEpoCart ).trigger( 'tm-epo-update' );
10788						}
10789					}
10790				} else if ( $this.is( ':radio' ) ) {
10791					if ( $this.val() && ! $this.data( 'set_initial' ) ) {
10792						if ( qtyalt.val() === '0' ) {
10793							if ( qtyalt.attr( 'min' ) !== '0' ) {
10794								qtyalt.val( qtyalt.attr( 'min' ) ).trigger( 'change' );
10795							}
10796							$this.data( 'set_initial', 1 );
10797						}
10798					}
10799				} else if ( $this.is( 'select' ) ) {
10800					if ( $this.val() && ! $this.data( 'set_initial' ) ) {
10801						if ( qtyalt.val() === '0' ) {
10802							if ( qtyalt.attr( 'min' ) !== '0' ) {
10803								qtyalt.val( qtyalt.attr( 'min' ) ).trigger( 'change' );
10804							}
10805							$this.data( 'set_initial', 1 );
10806						}
10807					}
10808				} else {
10809					return;
10810				}
10811
10812				if ( ! value ) {
10813					variableProductContainers.addClass( 'tm-hidden' );
10814					productPrice = $.epoAPI.util.parseJSON( associatedSetter.attr( 'data-rules' ) );
10815					productPrice = productPrice[ 0 ] || 0;
10816					originalProductPrice = $.epoAPI.util.parseJSON( associatedSetter.attr( 'data-original-rules' ) );
10817					originalProductPrice = originalProductPrice || 0;
10818					if ( associatedSetter.is( '.tcenabled' ) ) {
10819						associatedSetter.data( 'associated_price_set', 1 );
10820					}
10821					associatedSetter.data( 'price_set', 1 );
10822					associatedSetter.data( 'raw_price', productPrice );
10823					associatedSetter.data( 'raw_original_price', originalProductPrice );
10824					associatedSetter.data( 'price', productPrice );
10825					associatedSetter.data( 'original_price', originalProductPrice );
10826
10827					associatedElement = associatedSetter;
10828					if ( associatedElement.is( 'option' ) ) {
10829						associatedElement = associatedSetter.closest( 'select' );
10830					}
10831					isFilled = false;
10832					if ( associatedElement.is( '.tc-epo-field-product' ) ) {
10833						if ( associatedElement.is( 'select' ) ) {
10834							if ( associatedElement.val() !== '' ) {
10835								isFilled = true;
10836							}
10837						} else if ( ( associatedElement.is( ':checkbox' ) || associatedElement.is( ':radio' ) ) ) {
10838							if ( associatedElement.is( ':checked' ) ) {
10839								isFilled = true;
10840							}
10841						} else if ( associatedElement.val() !== '' ) {
10842							isFilled = true;
10843						}
10844					}
10845					tm_force_update_price(
10846						epoObject,
10847						associatedSetter
10848							.closest( '.tmcp-field-wrap' )
10849							.find( '.tc-price' )
10850							.not( tcAPI.associatedEpoSelector + ' .tc-price' ),
10851						productPrice,
10852						isFilled ? tm_set_price_totals( productPrice ) : associatedSetter.data( 'price-html' ),
10853						originalProductPrice,
10854						! isFilled
10855					);
10856
10857					qtyElement.trigger( 'change.cpf' );
10858
10859					return;
10860				}
10861
10862				if ( thisVariableProductContainer.length === 0 ) {
10863					if ( data && data.forced === 3 ) {
10864						$this.data( 'triggeredforced', 3 );
10865					}
10866					// parent_id is used for customization purposes.
10867					postData = {
10868						action: 'wc_epo_get_associated_product_html',
10869						product_id: value,
10870						parent_id: epoHolder.attr( 'data-product-id' ),
10871						mode: elementContainer.attr( 'data-mode' ),
10872						layout_mode: elementContainer.attr( 'data-product-layout-mode' ),
10873						uniqid: elementContainer.attr( 'data-uniqid' ),
10874						name: $this.attr( 'name' ),
10875						counter: counter,
10876						quantity_min: elementContainer.attr( 'data-quantity-min' ),
10877						quantity_max: elementContainer.attr( 'data-quantity-max' ),
10878						priced_individually: elementContainer.attr( 'data-priced-individually' ),
10879						discount: elementContainer.attr( 'data-discount' ),
10880						discount_type: elementContainer.attr( 'data-discount-type' ),
10881						discount_exclude_addons: elementContainer.attr( 'data-discount-exclude-
10881addons' ),
10882						show_image: elementContainer.attr( 'data-show-image' ),
10883						show_title: elementContainer.attr( 'data-show-title' ),
10884						show_title_link: elementContainer.attr( 'data-show-title-link' ),
10885						show_price: elementContainer.attr( 'data-show-price' ),
10886						show_description: elementContainer.attr( 'data-show-description' ),
10887						show_meta: elementContainer.attr( 'data-show-meta' ),
10888						disable_epo: elementContainer.attr( 'data-disable-epo' )
10889					};
10890
10891					elementContainer.block( { message: null, overlayCSS: { background: '#fff', opacity: 0.6 } } );
10892					$.ajax( {
10893						url: TMEPOJS.ajax_url,
10894						type: 'POST',
10895						data: postData,
10896						dataType: 'json',
10897						success: function( response ) {
10898							if ( response.result === 200 ) {
10899								thisVariableProductContainer = $( response.html );
10900								if ( hasProductContainerWrap ) {
10901									$this.closest( '.tmcp-field-wrap' ).find( '.tc-epo-element-product-container-wrap' ).empty().append( thisVariableProductContainer );
10902								} else {
10903									elementContainer.find( '.tc-epo-element-product-container-wrap' ).append( thisVariableProductContainer );
10904								}
10905								show_product_html( epoObject, main_product, thisVariableProductContainer, type, $this, currentCart, variableProductContainers, isTrigger, qtyalt );
10906								thisVariableProductContainer.find( tcAPI.associateQtySelector ).trigger( 'change' );
10907								jWindow.trigger( 'tc_apply_validation' );
10908							}
10909						},
10910						complete: function() {
10911							elementContainer.unblock();
10912						}
10913					} );
10914				} else {
10915					show_product_html( epoObject, main_product, thisVariableProductContainer, type, $this, currentCart, variableProductContainers, isTrigger, qtyalt );
10916					thisVariableProductContainer.find( tcAPI.associateQtySelector ).trigger( 'change' );
10917				}
10918			} );
10919
10920		jDocument
10921			.off( 'click.cpfqtybutton cpfqtybutton', '.cpf-type-product .single_add_to_cart_product' )
10922			.on( 'click.cpfqtybutton cpfqtybutton', '.cpf-type-product .single_add_to_cart_product', function() {
10923				var $this = $( this );
10924				var qtyalt = $this.closest( '.tm-quantity-alt' ).find( tcAPI.associateQtySelector );
10925				var isAdd = $this.is( '.alt' );
10926				var productContainerWraps = $this.closest( '.cpf-element' ).find( '.tc-epo-element-product-container-wrap' );
10927				var qtyMin;
10928				var qtyMax;
10929
10930				if ( $this.data( 'inittriggeredonce' ) ) {
10931					qtyMin = $.epoAPI.math.toInt( qtyalt.attr( 'data-min' ) );
10932					qtyMax = $.epoAPI.math.toInt( qtyalt.attr( 'data-max' ) );
10933					if ( isAdd ) {
10934						productContainerWraps.addClass( 'tc-active-product' );
10935						qtyalt.attr( 'min', qtyMin );
10936						if ( qtyMax ) {
10937							qtyalt.attr( 'max', qtyMax );
10938						}
10939						if ( qtyalt.val() === '0' ) {
10940							if ( qtyalt.attr( 'min' ) === '0' ) {
10941								qtyalt.val( 1 ).trigger( 'change' );
10942							} else {
10943								qtyalt.val( qtyalt.attr( 'min' ) ).trigger( 'change' );
10944							}
10945						}
10946						$this.removeClass( 'alt' ).text( $this.attr( 'data-remove' ) );
10947					} else {
10948						productContainerWraps.removeClass( 'tc-active-product' );
10949						qtyalt.val( 0 ).trigger( 'change' );
10950						qtyalt.closest( '.tm-quantity-alt' ).removeClass( 'tm-hidden' );
10951						$this.addClass( 'alt' ).text( $this.attr( 'data-add' ) );
10952					}
10953				}
10954
10955				$this.data( 'inittriggeredonce', 1 );
10956
10957				productContainerWraps.find( tcAPI.associatedEpoCart ).trigger( 'tm-epo-update' );
10958			} );
10959
10960		jDocument
10961			.off( 'change.cpfqtyalt input.cpfqtyalt', '.cpf-type-product ' + tcAPI.associateQtySelector )
10962			.on( 'change.cpfqtyalt input.cpfqtyalt', '.cpf-type-product ' + tcAPI.associateQtySelector, function() {
10963				var $this = $( this );
10964				var epoField = $this.closest( '.cpf-element' ).find( '.tm-epo-field' ).not( '.tc-epo-element-product-li-container .tm-epo-field' );
10965				var addButton = $this.closest( '.tm-quantity-alt' ).find( '.single_add_to_cart_product' );
10966				var checked = epoField.filter( ':checked' );
10967				var qty;
10968				var qtyMin;
10969				var qtyMax;
10970				var associatedEpoCart;
10971
10972				qtyMin = $.epoAPI.math.toInt( $this.attr( 'min' ) );
10973				qtyMax = $.epoAPI.math.toInt( $this.attr( 'max' ) );
10974
10975				if ( epoField.is( '.tc-epo-field-product-hidden' ) && epoField.is( ':checkbox' ) ) {
10976					if ( checked.length === 0 && $this.val() !== '0' ) {
10977						epoField.prop( 'checked', true ).trigger( 'change' );
10978						checked = epoField.filter( ':checked' );
10979					} else if ( $this.val() === '0' && checked.length ) {
10980						epoField.prop( 'checked', false ).trigger( 'change' );
10981					}
10982				}
10983
10984				if ( epoField.is( ':radio' ) ) {
10985					if ( checked.length === 0 ) {
10986						return;
10987					}
10988					qty = checked.closest( '.tmcp-field-wrap' ).find( 'input.tm-qty' ).not( '.tc-element-qty' );
10989				} else if ( epoField.is( ':checkbox' ) ) {
10990					if ( checked.length === 0 ) {
10991						return;
10992					}
10993					qty = $this.closest( '.tmcp-field-wrap' ).find( 'input.tm-qty' ).not( '.tc-element-qty' );
10994				} else {
10995					qty = epoField.closest( '.tmcp-field-wrap' ).find( 'input.tm-qty' ).not( '.tc-element-qty' );
10996				}
10997
10998				if ( qty.length === 0 ) {
10999					return;
11000				}
11001
11002				qty.attr( 'min', qtyMin );
11003				if ( qtyMax ) {
11004					qty.attr( 'max', qtyMax );
11005				}
11006				associatedEpoCart = $this.closest( '.tc-epo-element-product-container' ).find( tcAPI.associatedEpoCart );
11007				associatedEpoCart.trigger( 'tm-epo-update' );
11008
11009				qty.val( $this.val() );
11010
11011				if ( $.epoAPI.math.toFloat( $this.val() ) > 0 ) {
11012					associatedEpoCart.find( '.tm-epo-field.tcenabled' ).removeClass( 'ignore' );
11013					$this.removeClass( 'ignore' );
11014				} else {
11015					associatedEpoCart.find( '.tm-epo-field.tcenabled' ).addClass( 'ignore' );
11016					$this.addClass( 'ignore' );
11017				}
11018				epoField.trigger( 'change.cpfproduct', { forced: 2 } );
11019				if ( addButton.data( 'inittriggeredonce' ) ) {
11020					if ( $this.val() === '0' ) {
11021						addButton.removeClass( 'alt' );
11022					} else {
11023						addButton.addClass( 'alt' );
11024					}
11025				}
11026				addButton.trigger( 'cpfqtybutton' );
11027			} );
11028
11029		jDocument
11030			.off( 'click.cbsmel' )
11031			.on( 'click.cbsmel', '.tc-choice-button-selector', function( e ) {
11032				var $field = $( this ).closest( '.tmcp-field-wrap' ).find( '.tm-epo-field' );
11033				e.stopPropagation();
11034				if ( $field.length ) {
11035					$field.trigger( 'click' );
11036				}
11037			} );
11038
11039		// Global update event
11040		currentCart.off( 'tm-epo-update' ).on( 'tm-epo-update', function( event ) {
11041			var cart = $( this );
11042			var bundleid;
11043			var productPrice = false;
11044			var rawProductPrice = 0;
11045			var productRegularPrice = false;
11046			var rawProductRegularPrice = 0;
11047			var total = 0;
11048			var original_total = 0;
11049			var showTotal = false;
11050			var cartQty;
11051			var elementQty = 1;
11052			var priceOverrideMode;
11053			var perProductPricing = true;
11054			var floatingBoxData = [];
11055			var currentVariation;
11056			var cart_fee_options_total = 0;
11057			var cart_fee_options_original_total = 0;
11058			var _total;
11059			var _original_total;
11060			var late_total_price;
11061			var tc_totals_ob = {};
11062			var formatted_options_total;
11063			var formatted_options_original_total;
11064			var formatted_fees_total;
11065			var formatted_fees_original_total;
11066			var formatted_final_total;
11067			var formatted_final_original_total;
11068			var extraFee = 0;
11069			var raw_extraFee = 0;
11070			var product_total_price;
11071			var product_total_original_price;
11072			var calculateFinalProductPrice;
11073			var total_plus_fee;
11074			var original_total_plus_fee;
11075			var product_total_price_without_options;
11076			var unit_price;
11077			var unit_original_price;
11078			var formatted_unit_price;
11079			var formatted_unit_original_price;
11080			var html;
11081			var show_options_total = false;
11082			var show_vat_options_total = false;
11083			var show_fees_total = false;
11084			var formatted_extra_fee = '';
11085			var show_extra_fee = false;
11086			var show_final_total = false;
11087			var hide_native_price;
11088			var update_native_html;
11089			var _fprice;
11090			var _f_regular_price;
11091			var customerPriceFormat;
11092			var currentEpoObject;
11093			var raw_total;
11094			var raw__total;
11095			var raw_original_total;
11096			var raw__original_total;
11097			var raw_cart_fee_options_total;
11098			var raw_cart_fee_options_original_total;
11099			var raw_total_plus_fee;
11100			var raw_original_total_plus_fee;
11101			var raw_product_total_price_without_options;
11102			var raw_product_total_price;
11103			var raw_product_total_original_price;
11104			var fetch;
11105			var customer_price_format_wrap_start = '';
11106			var customer_price_format_wrap_end = '';
11107			var associatedSetter;
11108			var associatedPrice;
11109			var associatedRawPrice;
11110			var associatedOriginalPrice;
11111			var associatedRawOriginalPrice;
11112			var associatedFormattedPrice;
11113			var nativeProductPriceSelector;
11114			var elementsLength;
11115			var productFieldSyncVatTotal = 0;
11116			var productFieldSyncTotal = 0;
11117			var productFieldSyncOriginalTotal = 0;
11118			var productFieldSyncTotalTaxed = 0;
11119			var productFieldSyncOriginalTotalTaxed = 0;
11120			var totalProductField = 0;
11121			var originalTotalProductField = 0;
11122			var totalProductFieldTaxed = 0;
11123			var originalTotalProductFieldTaxed = 0;
11124			var _ftotal;
11125			var _foriginal_total;
11126			var totalsHolder_tc_totals_ob;
11127			var temp;
11128			var vat_options_total;
11129			var vat_options_total_plus_fee;
11130			var formatted_vat_options_total;
11131			var formatted_vat_options_total_plus_fee;
11132			var vat_total;
11133			var formatted_vat_total;
11134			var vat_product_base;
11135			var formatted_vat_product_base;
11136			var pricesIncludeTax;
11137			var dynamicCheck;
11138			var dynamicProductPrice = 0;
11139
11140			if ( event.epoObject ) {
11141				currentEpoObject = $.extend( true, {}, event.epoObject );
11142			} else {
11143				currentEpoObject = $.extend( true, {}, epoObject );
11144			}
11145
11146			if ( ! currentEpoObject ) {
11147				return;
11148			}
11149
11150			if ( currentEpoObject.noEpoUpdate ) {
11151				return;
11152			}
11153
11154			jWindow.trigger( 'tcEpoUpdateStart', {
11155				epo: currentEpoObject,
11156				alternativeCart: currentEpoObject,
11157				this_product_type: this_product_type,
11158				cart: cart,
11159				totalsHolder: totalsHolder,
11160				fetchOptionPrices: fetchOptionPrices,
11161				epoHolder: epoHolder
11162			} );
11163
11164			bundleid = $.epoAPI.applyFilter( 'tc_get_bundleid', cart.attr( 'data-
11164product_id' ), cart, currentEpoObject );
11165			priceOverrideMode = totalsHolder.attr( 'data-price-override' );
11166			cartQty = getCurrentQty( cart );
11167			currentVariation = getCurrentVariation( cart );
11168
11169			if ( currentEpoObject.associated_connect && currentEpoObject.associated_connect.length === 1 ) {
11170				cartQty = parseFloat(
11171					currentEpoObject.main_product
11172						.find( tcAPI.associateQtySelector )
11173						.not( tcAPI.associatedEpoSelector + ' ' + tcAPI.qtySelector )
11174						.last()
11175						.val()
11176				);
11177			}
11178
11179			event.stopImmediatePropagation();
11180
11181			productPrice = $.epoAPI.applyFilter( 'tcGetCurrentProductPrice', tm_calculate_product_price( totalsHolder, true ), currentCart, totalsHolder );
11182
11183			rawProductPrice = productPrice;
11184
11185			productRegularPrice = $.epoAPI.applyFilter( 'tcGetCurrentProductRegularPrice', tm_calculate_product_regular_price( totalsHolder, true ), currentCart, totalsHolder );
11186
11187			rawProductRegularPrice = productRegularPrice;
11188
11189			productPrice = $.epoAPI.applyFilter( 'tcCalculateCurrentProductPrice', productPrice, {
11190				epo: currentEpoObject,
11191				alternativeCart: alternativeCart,
11192				cart: cart,
11193				main_product: main_product
11194			} );
11195
11196			if ( ! Number.isFinite( cartQty ) || totalsHolder.attr( 'data-is-sold-individually' ) || getQtyElement( cart ).length === 0 ) {
11197				cartQty = 1;
11198			}
11199			if ( TMEPOJS.tm_epo_total_price_as_unit_price === 'yes' ) {
11200				cartQty = 1;
11201			}
11202
11203			// needed for inital math calculation
11204			totalsHolder_tc_totals_ob = {
11205				qty: cartQty,
11206				product_price: rawProductPrice,
11207				original_product_price: rawProductRegularPrice
11208			};
11209			totalsHolder.data( 'totalsHolder_tc_totals_ob', totalsHolder_tc_totals_ob );
11210
11211			if ( ! event.norules ) {
11212				tm_epo_rules( currentEpoObject, cart );
11213			} else if ( event.norules ) {
11214				if ( event.norules === 1 ) {
11215					tm_element_epo_rules( currentEpoObject, event.element );
11216				}
11217				$.tcepo.lateFieldsPrices[ epoEventId ] = [];
11218
11219				epoHolder
11220					.find( '.tm-epo-late-field' )
11221					.toArray()
11222					.forEach( function( setter ) {
11223						setter = $( setter );
11224						setter.data( 'price', 0 );
11225						$.tcepo.lateFieldsPrices[ epoEventId ].push( {
11226							setter: setter,
11227							price: setter.data( 'tm-price-for-late' ),
11228							original_price: setter.data( 'tm-original-price-for-late' ),
11229							bundleid: bundleid,
11230							pricetype: get_type( currentEpoObject, setter, 'price_type' )
11231						} );
11232					} );
11233			}
11234
11235			// Check for dynamic elements.
11236			dynamicCheck = epoHolder.find( '.tmcp-dynamic.dynamic-product-price:not(.tc-is-math-special, .tc-is-math-cumulative)' );
11237			if ( currentEpoObject.is_associated === false ) {
11238				dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.dynamic-product-price:not(.tc-is-math-special, .tc-is-math-cumulative)' );
11239			}
11240			dynamicCheck = dynamicCheck.filter( '.tcenabled' );
11241			if ( dynamicCheck.length > 0 ) {
11242				fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-dynamic.dynamic-product-price:not(.tc-is-math-special, .tc-is-math-cumulative)', 0, 0, floatingBoxData, showTotal, undefined, undefined, undefined, true, undefined, undefined, cartQty );
11243				productPrice = fetch.total;
11244				dynamicProductPrice = productPrice;
11245				rawProductRegularPrice = fetch.original_total;
11246				rawProductPrice = dynamicProductPrice;
11247				productRegularPrice = dynamicProductPrice;
11248				totalsHolderContainer.find( '.cpf-dynamic-product-price' ).val( dynamicProductPrice );
11249				totalsHolder_tc_totals_ob.dynamic_product_price = dynamicProductPrice;
11250				totalsHolder.data( 'totalsHolder_tc_totals_ob', totalsHolder_tc_totals_ob );
11251			}
11252
11253			if ( currentEpoObject.associated_connect && currentEpoObject.associated_connect.length === 1 ) {
11254				associatedSetter = currentEpoObject.associated_connect;
11255				if ( currentEpoObject.associated_connect.is( 'select' ) ) {
11256					associatedSetter = currentEpoObject.associated_connect.find( 'option:selected' );
11257				}
11258			}
11259
11260			// No reason to continue if the product price is invalid
11261			if ( productPrice === false ) {
11262				totalsHolder.data( 'tm-floating-box-data', [] );
11263				totalsHolder.empty();
11264				if ( currentEpoObject.associated_connect && currentEpoObject.associated_connect.length === 1 ) {
11265					tm_force_update_price(
11266						epoObject,
11267						associatedSetter
11268							.closest( '.tmcp-field-wrap' )
11269							.find( '.tc-price' )
11270							.not( tcAPI.associatedEpoSelector + ' .tc-price' ),
11271						0,
11272						'',
11273						0
11274					);
11275				}
11276				main_cart.trigger( 'tm-epo-short-update', {
11277					container: cartContainer
11278				} );
11279				return;
11280			}
11281
11282			elementQty = $.epoAPI.applyFilter( 'tcAlterElementQty', elementQty, {
11283				epo: currentEpoObject,
11284				alternativeCart: alternativeCart,
11285				currentCart: currentCart,
11286				main_product: main_product
11287			} );
11288
11289			if ( currentCart.data( 'per_product_pricing' ) !== undefined ) {
11290				perProductPricing = currentCart.data( 'per_product_pricing' );
11291			}
11292
11293			perProductPricing = $.epoAPI.applyFilter( 'tcCalculatePerProductPricing', perProductPricing, {
11294				epo: currentEpoObject,
11295				alternativeCart: alternativeCart,
11296				cart: cart,
11297				main_product: main_product
11298			} );
11299
11300			if ( main_epo_inside_form && TMEPOJS.tm_epo_totals_box_placement === 'woocommerce_before_add_to_cart_button' ) {
11301				if ( ( this_product_type === 'variable' || this_product_type === 'variable-subscription' ) && ! totalsHolder.data( 'moved_inside' ) ) {
11302					totalsHolder.data( 'moved_inside', 1 );
11303				}
11304			}
11305
11306			jWindow.trigger( 'tcEpoBeforeOptionPriceCalculation', {
11307				epo: currentEpoObject,
11308				alternativeCart: currentEpoObject,
11309				this_product_type: this_product_type,
11310				cart: cart,
11311				totalsHolder: totalsHolder,
11312				fetchOptionPrices: fetchOptionPrices,
11313				epoHolder: epoHolder,
11314				total: total,
11315				original_total: original_total,
11316				floatingBoxData: floatingBoxData,
11317				showTotal: showTotal,
11318				cart_fee_options_total: cart_fee_options_total,
11319				cart_fee_options_original_total: cart_fee_options_original_total
11320			} );
11321
11322			if ( ! currentEpoObject.associated_connect && ! event.noassociated ) {
11323				if ( TMEPOJS.tm_epo_global_product_element_quantity_sync === 'yes' && ! cart.is( $.tcAPI().associatedEpoCart ) ) {
11324					cart.find( $.tcAPI().associatedEpoCart ).filter( ':visible' ).toArray().forEac
11324h( function( acart ) {
11325						$( acart ).trigger( {
11326							type: 'tm-epo-update',
11327							noassociated: 1
11328						} );
11329					} );
11330				}
11331			}
11332
11333			fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-field:not(.tmcp-dynamic,.tc-epo-field-product, .tc-is-math-special, .tc-is-math-cumulative)', total, original_total, floatingBoxData, showTotal, undefined, undefined, undefined, undefined, undefined, undefined, cartQty );
11334			total = fetch.total;
11335			original_total = fetch.original_total;
11336			floatingBoxData = fetch.floatingBoxData;
11337			showTotal = fetch.showTotal;
11338			elementsLength = fetch.elementsLength;
11339
11340			fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tc-epo-field-product', productFieldSyncTotal, productFieldSyncOriginalTotal, floatingBoxData, showTotal, undefined, undefined, undefined, undefined, undefined, undefined, cartQty );
11341			productFieldSyncTotal = fetch.total;
11342			productFieldSyncOriginalTotal = fetch.original_total;
11343			productFieldSyncTotalTaxed = fetch.total_taxed;
11344			productFieldSyncOriginalTotalTaxed = fetch.original_total_taxed;
11345			productFieldSyncVatTotal = fetch.vat_total;
11346			floatingBoxData = fetch.floatingBoxData;
11347			showTotal = fetch.showTotal;
11348			elementsLength = elementsLength + fetch.elementsLength;
11349
11350			totalsHolder.data( 'tm-floating-box-data', floatingBoxData );
11351
11352			fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-fee-field', cart_fee_options_total, cart_fee_options_original_total, floatingBoxData, showTotal, false, true, undefined, undefined, undefined, undefined, cartQty );
11353			cart_fee_options_total = fetch.total;
11354			cart_fee_options_original_total = fetch.original_total;
11355			floatingBoxData = fetch.floatingBoxData;
11356			showTotal = fetch.showTotal;
11357			elementsLength = elementsLength + fetch.elementsLength;
11358
11359			jWindow.trigger( 'tcEpoAfterNormalOptionPriceCalculation', {
11360				epo: currentEpoObject,
11361				alternativeCart: currentEpoObject,
11362				this_product_type: this_product_type,
11363				cart: cart,
11364				totalsHolder: totalsHolder,
11365				fetchOptionPrices: fetchOptionPrices,
11366				epoHolder: epoHolder,
11367				total: total,
11368				original_total: original_total,
11369				floatingBoxData: floatingBoxData,
11370				showTotal: showTotal,
11371				cart_fee_options_total: cart_fee_options_total,
11372				cart_fee_options_original_total: cart_fee_options_original_total
11373			} );
11374
11375			// Original price + options price type requires this here.
11376			_total = total;
11377			_original_total = original_total;
11378
11379			late_total_price = add_late_fields_prices( currentEpoObject, parseFloat( productPrice ), parseFloat( rawProductRegularPrice ), parseFloat( _total + productFieldSyncTotal ), parseFloat( _original_total + productFieldSyncOriginalTotal ), bundleid, totalsHolder );
11380
11381			fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-field.tc-is-math-special:not(.tmcp-dynamic)', total, original_total, floatingBoxData, showTotal, undefined, undefined, undefined, true, undefined, undefined, cartQty );
11382			total = fetch.total;
11383			original_total = fetch.original_total;
11384			floatingBoxData = fetch.floatingBoxData;
11385			showTotal = fetch.showTotal;
11386			elementsLength = elementsLength + fetch.elementsLength;
11387
11388			_total = total;
11389			_original_total = original_total;
11390
11391			_total = _total + late_total_price.normal[ 0 ];
11392			_original_total = _original_total + late_total_price.normal[ 1 ];
11393
11394			cart_fee_options_total = cart_fee_options_total + late_total_price.fees[ 0 ];
11395			cart_fee_options_original_total = cart_fee_options_original_total + late_total_price.fees[ 1 ];
11396
11397			total = _total;
11398			original_total = _original_total;
11399			fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-field.tc-is-math-cumulative:not(.tmcp-dynamic)', total, original_total, floatingBoxData, showTotal, undefined, undefined, undefined, true, true, undefined, cartQty );
11400			total = fetch.total;
11401			original_total = fetch.original_total;
11402			floatingBoxData = fetch.floatingBoxData;
11403			showTotal = fetch.showTotal;
11404			elementsLength = elementsLength + fetch.elementsLength;
11405
11406			_total = total;
11407			_original_total = original_total;
11408
11409			// Check for dynamic elements.
11410			dynamicCheck = epoHolder.find( '.tmcp-dynamic.dynamic-product-price.tc-is-math-special' );
11411			if ( currentEpoObject.is_associated === false ) {
11412				dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.dynamic-product-price.tc-is-math-special' );
11413			}
11414			dynamicCheck = dynamicCheck.filter( '.tcenabled' );
11415			if ( dynamicCheck.length > 0 ) {
11416				fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-field.tmcp-dynamic.dynamic-product-price.tc-is-math-special', dynamicProductPrice + total, dynamicProductPrice + original_total, floatingBoxData, showTotal, undefined, undefined, undefined, true, undefined, undefined, cartQty );
11417				dynamicProductPrice = $.epoAPI.math.toFloat( fetch.total ) - $.epoAPI.math.toFloat( total );
11418				productPrice = dynamicProductPrice;
11419				rawProductRegularPrice = $.epoAPI.math.toFloat( fetch.original_total ) - $.epoAPI.math.toFloat( original_total );
11420				rawProductPrice = dynamicProductPrice;
11421				productRegularPrice = dynamicProductPrice;
11422				totalsHolderContainer.find( '.cpf-dynamic-product-price' ).val( dynamicProductPrice );
11423				totalsHolder_tc_totals_ob.dynamic_product_price = dynamicProductPrice;
11424				totalsHolder.data( 'totalsHolder_tc_totals_ob', totalsHolder_tc_totals_ob );
11425			}
11426
11427			dynamicCheck = epoHolder.find( '.tmcp-dynamic.dynamic-product-price.tc-is-math-cumulative' );
11428			if ( currentEpoObject.is_associated === false ) {
11429				dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.dynamic-product-price.tc-is-math-cumulative' );
11430			}
11431			dynamicCheck = dynamicCheck.filter( '.tcenabled' );
11432			if ( dynamicCheck.length > 0 ) {
11433				fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-field.tmcp-dynamic.dynamic-product-price.tc-is-math-cumulative', dynamicProductPrice + total, dynamicProductPrice + original_total, floatingBoxData, showTotal, undefined, undefined, undefined, true, undefined, undefined, cartQty );
11434				dynamicProductPrice = $.epoAPI.math.toFloat( fetch.total ) - $.epoAPI.math.toFloat( total );
11435				productPrice = dynamicProductPrice;
11436				rawProductRegularPrice = $.epoAPI.math.toFloat( fetch.original_total ) - $.epoAPI.math.toFloat( original_total );
11437				rawProductPrice = dynamicProductPrice;
11438				productRegularPrice = dynamicProductPrice;
11439				totalsHolderContainer.find( '.cpf-dynamic-product-price' ).val( dynamicProductPrice );
11440				totalsHolder_tc_totals_ob.dynamic_product_price = dynamicProductPrice;
11441				totalsHolder.data( 'totalsHolder_tc_totals_ob', totalsHolder_tc_totals_ob );
11442			}
11443
11444			// Check if there are any dynamic product price elements
11445			dynamicCheck = epoHolder.find( '.tmcp-dynamic.dynamic-product-price' );
11446			if ( currentEpoObject.is_associated === false ) {
11447				dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.dynamic-product-price' );
11448			}
11449			dynamicCheck = dynamicCheck.filter( '.tcenabled' );
11450			if ( ! dynamicCheck.length > 0 ) {
11451				totalsHolderContainer.find( '.cpf-dynamic-product-price' ).val( '' );
11452			}
11453
11454			// Dynamic Calculation
11455			dynamicProductPrice = 0;
11456			dynamicCheck = epoHolder.find( '.tmcp-dynamic.calculation:not(.tc-is-math-special, .tc-is-math-cumulative)' );
11457			if ( currentEpoObject.is_associated === false ) {
11458				dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.calculation:not(.tc-is-math-special, .tc-is-math-cumulative)' );
11459			}
11460			dynamicCheck = dynamicCheck.filter( '.tcenabled' );
11461			if ( dynamicCheck.length > 0 ) {
11462				dynamicCheck.toArray().forEach( function( setter ) {
11463					var f;
11464					var ulWrap;
11465					var setterVal;
11466					setter = $( setter );
11467					ulWrap = setter.closest( '.tmcp-ul-wrap' );
11468					f = fetchOptionPrices( epoObject, ulWrap, '.tmcp-dynamic.calculation:not(.tc-is-math-special, .tc-is-math-cumulative)', dynamicProductPrice, dynamicProductPrice, [], true, true, undefined, undefined, undefined, true, undefined, undefined, cartQty );
11469					setterVal = f.total;
11470					if ( setter.is( '.result-as-price' ) ) {
11471						setterVal = tm_set_price_totals( setterVal, totalsHolder, true );
11472					}
11473					ulWrap.find( '.tc-result' ).html( setterVal );
11474				} );
11475			}
11476
11477			dynamicCheck = epoHolder.find( '.tmcp-dynamic.calculation.tc-is-math-special' );
11478			if ( currentEpoObject.is_associated === false ) {
11479				dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.calculation.tc-is-math-special' );
11480			}
11481			dynamicCheck = dynamicCheck.filter( '.tcenabled' );
11482			if ( dynamicCheck.length > 0 ) {
11483				dynamicCheck.toArray().forEach( function( setter ) {
11484					var f;
11485					var ulWrap;
11486					var setterVal;
11487					setter = $( setter );
11488					ulWrap = setter.closest( '.tmcp-ul-wrap' );
11489					f = fetchOptionPrices( epoObject, ulWrap, '.tmcp-field.tmcp-dynamic.calculation.tc-is-math-special', dynamicProductPrice + total, dynamicProductPrice + original_total, [], true, true, undefined, undefined, true );
11490					setterVal = $.epoAPI.math.toFloat( f.total ) - $.epoAPI.math.toFloat( total );
11491					if ( setter.is( '.result-as-price' ) ) {
11492						setterVal = tm_set_price_totals( setterVal, totalsHolder, true );
11493					}
11494					ulWrap.find( '.tc-result' ).html( setterVal );
11495				} );
11496			}
11497
11498			dynamicCheck = epoHolder.find( '.tmcp-dynamic.calculation.tc-is-math-cumulative' );
11499			if ( currentEpoObject.is_associated === false ) {
11500				dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.calculation.tc-is-math-cumulative' );
11501			}
11502			dynamicCheck = dynamicCheck.filter( '.tcenabled' );
11503			if ( dynamicCheck.length > 0 ) {
11504				dynamicCheck.toArray().forEach( function( setter ) {
11505					var f;
11506					var ulWrap;
11507					var setterVal;
11508					setter = $( setter );
11509					ulWrap = setter.closest( '.tmcp-ul-wrap' );
11510					f = fetchOptionPrices( epoObject, ulWrap, '.tmcp-field.tmcp-dynamic.calculation.tc-is-math-cumulative', dynamicProductPrice + total, dynamicProductPrice + original_total, [], true, true, undefined, undefined, true, undefined, undefined, undefined, cartQty );
11511					setterVal = $.epoAPI.math.toFloat( f.total ) - $.epoAPI.math.toFloat( total );
11512					if ( setter.is( '.result-as-price' ) ) {
11513						setterVal = tm_set_price_totals( setterVal, totalsHolder, true );
11514					}
11515					ulWrap.find( '.tc-result' ).html( setterVal );
11516				} );
11517			}
11518
11519			// Dynamic Weight
11520			dynamicProductPrice = 0;
11521			dynamicCheck = epoHolder.find( '.tmcp-dynamic.change-product-weight:not(.tc-is-math-special, .tc-is-math-cumulative)' );
11522			if ( currentEpoObject.is_associated === false ) {
11523				dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.change-product-weight:not(.tc-is-math-special, .tc-is-math-cumulative)' );
11524			}
11525			dynamicCheck = dynamicCheck.filter( '.tcenabled' );
11526			if ( dynamicCheck.length > 0 ) {
11527				dynamicCheck.toArray().forEach( function( setter ) {
11528					var f;
11529					var ulWrap;
11530					setter = $( setter );
11531					ulWrap = setter.closest( '.tmcp-ul-wrap' );
11532					f = fetchOptionPrices( epoObject, ulWrap, '.tmcp-dynamic.change-product-weight:not(.tc-is-math-special, .tc-is-math-cumulative)', dynamicProductPrice, dynamicProductPrice, [], true, true, undefined, undefined, undefined, undefined, undefined, undefined, cartQty );
11533					ulWrap.find( '.tc-result' ).html( f.total );
11534				} );
11535			}
11536
11537			dynamicCheck = epoHolder.find( '.tmcp-dynamic.change-product-weight.tc-is-math-special' );
11538			if ( currentEpoObject.is_associated === false ) {
11539				dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.change-product-weight.tc-is-math-special' );
11540			}
11541			dynamicCheck = dynamicCheck.filter( '.tcenabled' );
11542			if ( dynamicCheck.length > 0 ) {
11543				dynamicCheck.toArray().forEach( function( setter ) {
11544					var f;
11545					var ulWrap;
11546					setter = $( setter );
11547					ulWrap = setter.closest( '.tmcp-ul-wrap' );
11548					f = fetchOptionPrices( epoObject, ulWrap, '.tmcp-field.tmcp-dynamic.change-product-weight.tc-is-math-special', dynamicProductPrice + total, dynamicProductPrice + original_total, [], true, true, undefined, undefined, true, undefined, undefined, undefined, cartQty );
11549					ulWrap.find( '.tc-result' ).html( $.epoAPI.math.toFloat( f.total ) - $.epoAPI.math.toFloat( total ) );
11550				} );
11551			}
11552
11553			dynamicCheck = epoHolder.find( '.tmcp-dynamic.change-product-weight.tc-is-math-cumulative' );
11554			if ( currentEpoObject.is_associated === false ) {
11555				dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.change-product-weight.tc-is-math-cumulative' );
11556			}
11557			dynamicCheck = dynamicCheck.filter( '.tcenabled' );
11558			if ( dynamicCheck.length > 0 ) {
11559				dynamicCheck.toArray().forEach( function( setter ) {
11560					var f;
11561					var ulWrap;
11562					setter = $( setter );
11563					ulWrap = setter.closest( '.tmcp-ul-wrap' );
11564					f = fetchOptionPrices( epoObject, ulWrap, '.tmcp-field.tmcp-dynamic.change-product-weight.tc-is-math-cumulative', dynamicProductPrice + total, dynamicProductPrice + original_total, [], true, true, undefined, undefined, true, undefined, undefined, undefined, cartQty );
11565					ulWrap.find( '.tc-result' ).html( $.epoAPI.math.toFloat( f.total ) - $.epoAPI.math.toFloat( total ) );
11566				} );
11567			}
11568
11569			// Check for dynamic override elements
11570			dynamicProductPrice = 0;
11571			dynamicCheck = epoHolder.find( '.tmcp-dynamic.override-product-price:not(.tc-is-math-special, .tc-is-math-cumulative)' );
11572			if ( currentEpoObject.is_associated === false ) {
11573				dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.override-product-price:not(.tc-is-math-special, .tc-is-math-cumulative)' );
11574			}
11575			dynamicCheck = dynamicCheck.filter( '.tcenabled' );
11576			if ( dynamicCheck.length > 0 ) {
11577				fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-dynamic.override-product-price:not(.tc-is-math-special, .tc-is-math-cumulative)', dynamicProductPrice, dynamicProductPrice, floatingBoxData, showTotal, undefined, undefined, undefined, undefined, undefined, undefined, cartQty );
11578				dynamicProductPrice = fetch.total;
11579				productPrice = dynamicProductPrice;
11580				rawProductRegularPrice = fetch.original_total;
11581				rawProductPrice = dynamicProductPrice;
11582				productRegularPrice = dynamicProductPrice;
11583				_total = dynamicProductPrice;
11584				_original_total = dynamicProductPrice;
11585				totalsHolderContainer.find( '.cpf-override-product-price' ).val( dynamicProductPrice );
11586				totalsHolder_tc_totals_ob.override_product_price = dynamicProductPrice;
11587				totalsHolder.data( 'totalsHolder_tc_totals_ob', totalsHolder_tc_totals_ob );
11588			}
11589
11590			dynamicCheck = epoHolder.find( '.tmcp-dynamic.override-product-price.tc-is-math-special' );
11591			if ( currentEpoObject.is_associated === false ) {
11592				dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.override-product-price.tc-is-math-special' );
11593			}
11594			dynamicCheck = dynamicCheck.filter( '.tcenabled' );
11595			if ( dynamicCheck.length > 0 ) {
11596				fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-field.tmcp-dynamic.override-product-price.tc-is-math-special', dynamicProductPrice + total, dynamicProductPrice + original_total, floatingBoxData, showTotal, undefined, undefined, undefined, true, undefined, undefined, cartQty );
11597				dynamicProductPrice = $.epoAPI.math.toFloat( fetch.total ) - $.epoAPI.math.toFloat( total );
11598				productPrice = dynamicProductPrice;
11599				rawProductRegularPrice = $.epoAPI.math.toFloat( fetch.original_total ) - $.epoAPI.math.toFloat( original_total );
11600				rawProductPrice = dynamicProductPrice;
11601				productRegularPrice = dynamicProductPrice;
11602				_total = dynamicProductPrice;
11603				_original_total = dynamicProductPrice;
11604				totalsHolderContainer.find( '.cpf-override-product-price' ).val( dynamicProductPrice );
11605				totalsHolder_tc_totals_ob.override_product_price = dynamicProductPrice;
11606				totalsHolder.data( 'totalsHolder_tc_totals_ob', totalsHolder_tc_totals_ob );
11607			}
11608
11609			dynamicCheck = epoHolder.find( '.tmcp-dynamic.override-product-price.tc-is-math-cumulative' );
11610			if ( currentEpoObject.is_associated === false ) {
11611				dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.override-product-price.tc-is-math-cumulative' );
11612			}
11613			dynamicCheck = dynamicCheck.filter( '.tcenabled' );
11614			if ( dynamicCheck.length > 0 ) {
11615				fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-field.tmcp-dynamic.override-product-price.tc-is-math-cumulative', dynamicProductPrice + total, dynamicProductPrice + original_total, floatingBoxData, showTotal, undefined, undefined, undefined, true, undefined, undefined, cartQty );
11616				dynamicProductPrice = $.epoAPI.math.toFloat( fetch.total ) - $.epoAPI.math.toFloat( total );
11617				productPrice = dynamicProductPrice;
11618				rawProductRegularPrice = $.epoAPI.math.toFloat( fetch.original_total ) - $.epoAPI.math.toFloat( original_total );
11619				rawProductPrice = dynamicProductPrice;
11620				productRegularPrice = dynamicProductPrice;
11621				_total = dynamicProductPrice;
11622				_original_total = dynamicProductPrice;
11623				totalsHolderContainer.find( '.cpf-override-product-price' ).val( dynamicProductPrice );
11624				totalsHolder_tc_totals_ob.override_product_price = dynamicProductPrice;
11625				totalsHolder.data( 'totalsHolder_tc_totals_ob', totalsHolder_tc_totals_ob );
11626			}
11627
11628			// Check if there are any dynamic override elements
11629			dynamicCheck = epoHolder.find( '.tmcp-dynamic.override-product-price' );
11630			if ( currentEpoObject.is_associated === false ) {
11631				dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.override-product-price' );
11632			}
11633			dynamicCheck = dynamicCheck.filter( '.tcenabled' );
11634			if ( ! dynamicCheck.length > 0 ) {
11635				totalsHolderContainer.find( '.cpf-override-product-price' ).val( '' );
11636			} else {
11637				_total = 0;
11638				_original_total = 0;
11639			}
11640
11641			jWindow.trigger( 'tcEpoAfterOptionPriceCalculation', {
11642				epo: currentEpoObject,
11643				alternativeCart: currentEpoObject,
11644				this_product_type: this_product_type,
11645				cart: cart,
11646				totalsHolder: totalsHolder,
11647				fetchOptionPrices: fetchOptionPrices,
11648				epoHolder: epoHolder,
11649				total: total,
11650				original_total: original_total,
11651				floatingBoxData: floatingBoxData,
11652				showTotal: showTotal,
11653				cart_fee_options_total: cart_fee_options_total,
11654				cart_fee_options_original_total: cart_fee_options_original_total
11655			} );
11656
11657			setTimeout( function() {
11658				epoHolder.find( 'select.tm-epo-field' ).trigger( 'tm-select-price-update-html-all' );
11659			}, 1 );
11660
11661			$.tcepo.oneOptionIsSelected[ epoEventId ] = showTotal;
11662			currentEpoObject = addShowHidetoEpoObject( currentEpoObject, epoEventId, elementsLength );
11663			tm_show_hide_add_to_cart_button( main_product, currentEpoObject );
11664
11665			if ( cart_fee_options_total > 0 ) {
11666				showTotal = true;
11667			}
11668
11669			if ( alternativeCart && ! perProductPricing ) {
11670				showTotal = false;
11671			}
11672
11673			if (
11674				finalTotalBoxMode === 'enable' ||
11675				finalTotalBoxMode === 'hideifoptionsiszero' ||
11676				finalTotalBoxMode === 'hideiftotaliszero'
11677			) {
11678				showTotal = true;
11679			}
11680
11681			if ( cartQty > 1 ) {
11682				showTotal = true;
11683			}
11684			if ( ( this_product_type === 'variable' || this_product_type === 'variable-subscription' ) && ! $.epoAPI.math.toFloat( currentVariation ) ) {
11685				showTotal = false;
11686			}
11687
11688			if ( finalTotalBoxMode === 'disable' ) {
11689				showTotal = false;
11690			}
11691			if ( TMEPOJS.tm_epo_change_variation_price === 'yes' || TMEPOJS.tm_epo_change_original_price === 'yes' ) {
11692				showTotal = true;
11693			}
11694
11695			if ( currentEpoObject.is_associated && ! perProductPricing ) {
11696				showTotal = false;
11697			}
11698
11699			product_total_price = parseFloat( productPrice * cartQty );
11700
11701			if ( TMEPOJS.extraFee ) {
11702				extraFee = parseFloat( TMEPOJS.extraFee );
11703				if ( ! Number.isFinite( extraFee ) ) {
11704					extraFee = 0;
11705				}
11706			}
11707
11708			calculateFinalProductPrice = $.epoAPI.applyFilter( 'tcCalculateFinalProductPrice', false, {
11709				alternativeCart: alternativeCart,
11710				product_price: productPrice,
11711				product_total_price: product_total_price,
11712				v_product_price: rawProductPrice,
11713				tm_set_tax_price: tm_set_tax_price,
11714				main_product: main_product,
11715				totalsHolder: totalsHolder,
11716				cartQty: cartQty
11717			} );
11718
11719			if (
11720				calculateFinalProductPrice !== false &&
11721				typeof calculateFinalProductPrice === 'object' &&
11722				Object.prototype.hasOwnProperty.call( calculateFinalProductPrice, 'productPrice' ) &&
11723				Object.prototype.hasOwnProperty.call( calculateFinalProductPrice, 'productTotalPrice' )
11724			) {
11725				productPrice = calculateFinalProductPrice.productPrice;
11726				product_total_price = calculateFinalProductPrice.productTotalPrice;
11727			}
11728
11729			_total = $.epoAPI.applyFilter( 'tc_adjust_options_price_per_unit', _total, product_total_price );
11730			total = parseFloat( _total * cartQty * elementQty );
11731			total = $.epoAPI.applyFilter( 'tc_adjust_options_total_price', total, cartQty, elementQty, _total, totalsHolder );
11732			if ( TMEPOJS.tm_epo_global_product_element_quantity_sync === 'no' ) {
11733				totalProductField = parseFloat( productFieldSyncTotal );
11734				totalProductFieldTaxed = parseFloat( productFieldSyncTotalTaxed );
11735			} else {
11736				totalProductField = parseFloat( productFieldSyncTotal * cartQty * elementQty );
11737				totalProductFieldTaxed = parseFloat( productFieldSyncTotalTaxed * cartQty * elementQty );
11738			}
11739			totalProductField = $.epoAPI.applyFilter( 'tc_adjust_options_productfield_total_price', totalProductField, cartQty, elementQty, _total, totalsHolder );
11740			totalProductFieldTaxed = $.epoAPI.applyFilter( 'tc_adjust_options_productfield_total_price_taxed', totalProductFieldTaxed, cartQty, elementQty, _total, totalsHolder );
11741
11742			_original_total = $.epoAPI.applyFilter( 'tc_adjust_options_price_per_unit', _original_total, product_total_price );
11743			original_total = parseFloat( _original_total * cartQty * elementQty );
11744			original_total = $.epoAPI.applyFilter( 'tc_adjust_options_original_total_price', original_total, cartQty, elementQty, _original_total, totalsHolder );
11745			if ( TMEPOJS.tm_epo_global_product_element_quantity_sync === 'no' ) {
11746				originalTotalProductField = parseFloat( productFieldSyncOriginalTotal );
11747				originalTotalProductFieldTaxed = parseFloat( productFieldSyncOriginalTotalTaxed );
11748			} else {
11749				originalTotalProductField = parseFloat( productFieldSyncOriginalTotal * cartQty * elementQty );
11750				originalTotalProductFieldTaxed = parseFloat( productFieldSyncOriginalTotalTaxed * cartQty * elementQty );
11751			}
11752			originalTotalProductField = $.epoAPI.applyFilter( 'tc_adjust_options_productfield_original_total_price', originalTotalProductField, cartQty, elementQty, _original_total, totalsHolder );
11753			originalTotalProductFieldTaxed = $.epoAPI.applyFilter( 'tc_adjust_options_productfield_original_total_price_taxed', originalTotalProductFieldTaxed, cartQty, elementQty, _original_total, totalsHolder );
11754
11755			if ( priceOverrideMode === '1' && parseFloat( total ) > 0 ) {
11756				productPrice = 0;
11757				rawProductPrice = 0;
11758				product_total_price = 0;
11759			}
11760
11761			product_total_price = $.epoAPI.applyFilter( 'tc_adjust_product_total_price_without_options', product_total_price );
11762
11763			total = $.epoAPI.applyFilter( 'tcAdjustTotal', total, {
11764				epo: currentEpoObject,
11765				totalsHolder: totalsHolder,
11766				cart: cart,
11767				main_product: main_product
11768			} );
11769			totalProductField = $.epoAPI.applyFilter( 'tcAdjustProductFieldTotal', totalProductField, {
11770				epo: currentEpoObject,
11771				totalsHolder: totalsHolder,
11772				cart: cart,
11773				main_product: main_product
11774			} );
11775			totalProductFieldTaxed = $.epoAPI.applyFilter( 'tcAdjustProductFieldTotalTaxed', totalProductFieldTaxed, {
11776				epo: currentEpoObject,
11777				totalsHolder: totalsHolder,
11778				cart: cart,
11779				main_product: main_product
11780			} );
11781			original_total = $.epoAPI.applyFilter( 'tcAdjustOriginalTotal', original_total, {
11782				epo: currentEpoObject,
11783				totalsHolder: totalsHolder,
11784				cart: cart,
11785				main_product: main_product
11786			} );
11787			originalTotalProductField = $.epoAPI.applyFilter( 'tcAdjustProductFieldOriginalTotal', originalTotalProductField, {
11788				epo: currentEpoObject,
11789				totalsHolder: totalsHolder,
11790				cart: cart,
11791				main_product: main_product
11792			} );
11793			originalTotalProductFieldTaxed = $.epoAPI.applyFilter( 'tcAdjustProductFieldOriginalTotalTaxed', originalTotalProductFieldTaxed, {
11794				epo: currentEpoObject,
11795				totalsHolder: totalsHolder,
11796				cart: cart,
11797				main_product: main_product
11798			} );
11799
11800			total = parseFloat( $.epoAPI.applyFilter( 'tc_adjust_total', total, totalsHolder ) );
11801			cart_fee_options_total = parseFloat( $.epoAPI.applyFilter( 'tc_adjust_totals_fee', cart_fee_options_total, totalsHolder ) );
11802			original_total = parseFloat( $.epoAPI.applyFilter( 'tc_adjust_original_total', original_total, totalsHolder ) );
11803			cart_fee_options_original_total = parseFloat( $.epoAPI.applyFilter( 'tc_adjust_original_total_fee', cart_fee_options_original_total, totalsHolder ) );
11804			raw_extraFee = extraFee;
11805
11806			total_plus_fee = total + cart_fee_options_total;
11807			original_total_plus_fee = original_total + cart_fee_options_original_total;
11808
11809			raw_total = total;
11810			raw__total = _total;
11811
11812			raw_cart_fee_options_total = cart_fee_options_total;
11813			raw_total_plus_fee = total_plus_fee;
11814
11815			raw_original_total = original_total;
11816			raw__original_total = _original_total;
11817
11818			raw_cart_fee_options_original_total = cart_fee_options_original_total;
11819			raw_original_total_plus_fee = original_total_plus_fee;
11820
11821			raw_product_total_price_without_options = product_total_price;
11822			raw_product_total_price = parseFloat( product_total_price + total_plus_fee + raw_extraFee );
11823			raw_product_total_original_price = parseFloat( rawProductRegularPrice + original_total_plus_fee + raw_extraFee );
11824
11825			productPrice = tm_set_tax_price( productPrice, totalsHolder, undefined, undefined, undefined, undefined, true );
11826			productRegularPrice = tm_set_tax_price( productRegularPrice, totalsHolder, undefined, undefined, undefined, undefined, true );
11827			product_total_price = tm_set_tax_price( product_total_price, totalsHolder, undefined, undefined, undefined, undefined, true );
11828
11829			total = tm_set_tax_price( total, totalsHolder, undefined, undefined, undefined, undefined, true );
11830			_total = tm_set_tax_price( _total, totalsHolder, undefined, undefined, undefined, undefined, true );
11831
11832			total_plus_fee = parseFloat( cart_fee_options_total ) + parseFloat( total );
11833
11834			original_total = tm_set_tax_price( original_total, totalsHolder, undefined, undefined, undefined, undefined, true );
11835			_original_total = tm_set_tax_price( _original_total, totalsHolder, undefined, undefined, undefined, undefined, true );
11836
11837			original_total_plus_fee = parseFloat( cart_fee_options_original_total ) + parseFloat( original_total );
11838
11839			extraFee = tm_set_tax_price( extraFee, totalsHolder, undefined, undefined, undefined, undefined, true );
11840
11841			// Calculate product price
11842			product_total_price_without_options = product_total_price;
11843			product_total_price = $.epoAPI.applyFilter( 'tc_adjust_product_total_price', parseFloat( product_total_price + total_plus_fee + extraFee ), product_total_price_without_options, total_plus_fee, extraFee, total, cart_fee_options_total, totalsHolder );
11844			product_total_original_price = $.epoAPI.applyFilter( 'tc_adjust_product_total_original_price', parseFloat( product_total_price_without_options + original_total_plus_fee + extraFee ), product_total_price_without_options, original_total_plus_fee, extraFee, original_total, cart_fee_options_original_total, totalsHolder );
11845
11846			// Calculate vat options total
11847			pricesIncludeTax = totalsHolder.attr( 'data-prices-include-tax' ) || TMEPOJS.prices_include_tax;
11848			if ( pricesIncludeTax === '1' ) {
11849				vat_options_total = productFieldSyncVatTotal + parseFloat( calculateTaxAmount( total, totalsHolder ) );
11850				vat_options_total_plus_fee = productFieldSyncVatTotal + parseFloat( calculateTaxAmount( total_plus_fee, totalsHolder ) );
11851				vat_total = productFieldSyncVatTotal + parseFloat( calculateTaxAmount( product_total_price, totalsHolder ) );
11852				vat_product_base = parseFloat( calculateTaxAmount( product_total_price_without_options, totalsHolder ) );
11853			} else {
11854				vat_options_total = productFieldSyncVatTotal + parseFloat( total - raw_total );
11855				vat_options_total_plus_fee = productFieldSyncVatTotal + parseFloat( total_plus_fee - raw_total_plus_fee );
11856				vat_total = productFieldSyncVatTotal + parseFloat( product_total_price - raw_product_total_price );
11857				vat_product_base = parseFloat( product_total_price_without_options - raw_product_total_price_without_options );
11858			}
11859
11860			raw_total = raw_total + totalProductField;
11861			raw__total = raw__total + totalProductField;
11862			raw_total_plus_fee = raw_total_plus_fee + totalProductField;
11863			raw_original_total = raw_original_total + originalTotalProductField;
11864			raw__original_total = raw__original_total + originalTotalProductField;
11865			raw_original_total_plus_fee = raw_original_total_plus_fee + originalTotalProductField;
11866			raw_product_total_price = raw_product_total_price + totalProductField;
11867			raw_product_total_original_price = raw_product_total_original_price + originalTotalProductField;
11868			total = total + totalProductFieldTaxed;
11869			_total = _total + totalProductFieldTaxed;
11870			total_plus_fee = total_plus_fee + totalProductFieldTaxed;
11871			original_total = original_total + originalTotalProductFieldTaxed;
11872			_original_total = _original_total + originalTotalProductFieldTaxed;
11873			original_total_plus_fee = original_total_plus_fee + originalTotalProductFieldTaxed;
11874			product_total_price = product_total_price + totalProductFieldTaxed;
11875			product_total_original_price = product_total_original_price + originalTotalProductFieldTaxed;
11876
11877			// Calculate unit price
11878			unit_price = parseFloat( productPrice + parseFloat( _total ) );
11879			unit_original_price = parseFloat( productPrice + parseFloat( _original_total ) );
11880			if ( TMEPOJS.tm_epo_fees_on_unit_price === 'yes' ) {
11881				unit_price = parseFloat( productPrice + parseFloat( _total ) + parseFloat( parseFloat( cart_fee_options_total ) / cartQty ) );
11882				unit_original_price = parseFloat( productPrice + parseFloat( _original_total ) + parseFloat( parseFloat( cart_fee_options_original_total ) / cartQty ) );
11883			}
11884
11885			// Format unit price
11886			formatted_unit_price = tm_set_price_totals( unit_price, totalsHolder, true );
11887			formatted_unit_original_price = tm_set_price_totals( unit_original_price, totalsHolder, true );
11888
11889			// Format extra fee
11890			if ( extraFee ) {
11891				show_extra_fee = true;
11892				formatted_extra_fee = tm_set_price_totals( extraFee, totalsHolder, true );
11893			}
11894
11895			// Format final total
11896			formatted_final_total = tm_set_price_totals( product_total_price, totalsHolder, true );
11897			formatted_final_original_total = tm_set_price_totals( product_total_original_price, totalsHolder, true );
11898
11899			// Format options total
11900			formatted_options_total = tm_set_price_totals( total, totalsHolder, true );
11901
11902			// Format fees total
11903			formatted_fees_total = tm_set_price_totals( cart_fee_options_total, totalsHolder, true );
11904
11905			// Format options original total
11906			formatted_options_original_total = tm_set_price_totals( original_total, totalsHolder, true );
11907
11908			// Format fees original total
11909			formatted_fees_original_total = tm_set_price_totals( cart_fee_options_original_total, totalsHolder, true );
11910
11911			// Format vat options total
11912			formatted_vat_options_total = tm_set_price_totals( vat_options_total );
11913			formatted_vat_options_total_plus_fee = tm_set_price_totals( vat_options_total_plus_fee );
11914			formatted_vat_total = tm_set_price_totals( vat_total );
11915			formatted_vat_product_base = tm_set_price_totals( vat_product_base );
11916
11917			// Backwards compatibility
11918			formatted_unit_price = $.epoAPI.applyFilter( 'tc_adjust_formatted_unit_price', formatted_unit_price, productPrice, _total, cart_fee_options_total, cartQty );
11919			formatted_options_total = $.epoAPI.applyFilter( 'tc_adjust_formatted_options_total', formatted_options_total, total, _total, cartQty );
11920			formatted_fees_total = $.epoAPI.applyFilter( 'tc_adjust_formatted_fees_total', formatted_fees_total, cart_fee_options_total );
11921			formatted_final_total = $.epoAPI.applyFilter( 'tc_adjust_formatted_final_total', formatted_final_total, product_total_price, product_total_price_without_options, total_plus_fee, extraFee, cartQty );
11922
11923			formatted_unit_price = $.epoAPI.applyFilter( 'tcAdjustFormattedUnitPrice', formatted_unit_price, {
11924				epo: currentEpoObject,
11925				totalsHolder: totalsHolder,
11926				event: event,
11927				unit_price: unit_price,
11928				productPrice: productPrice,
11929				_total: _total,
11930				total_plcart_fee_options_totals_fee: cart_fee_options_total,
11931				cartQty: cartQty
11932			} );
11933			formatted_unit_original_price = $.epoAPI.applyFilter( 'tcAdjustFormattedUnitOriginalPrice', formatted_unit_original_price, {
11934				epo: currentEpoObject,
11935				totalsHolder: totalsHolder,
11936				event: event,
11937				unit_original_price: unit_original_price,
11938				productPrice: productPrice,
11939				_original_total: _original_total,
11940				total_plcart_fee_options_totals_fee: cart_fee_options_total,
11941				cartQty: cartQty
11942			} );
11943			formatted_options_total = $.epoAPI.applyFilter( 'tcAdjustFormattedOptionsTotal', formatted_options_total, {
11944				epo: currentEpoObject,
11945				totalsHolder: totalsHolder,
11946				event: event,
11947				total: total,
11948				_total: _total,
11949				total_plus_fee: total_plus_fee,
11950				extraFee: extraFee,
11951				cartQty: cartQty
11952			} );
11953			formatted_options_original_total = $.epoAPI.applyFilter( 'tcAdjustFormattedOptionsOriginalTotal', formatted_options_original_total, {
11954				epo: currentEpoObject,
11955				totalsHolder: totalsHolder,
11956				event: event,
11957				original_total: original_total,
11958				_original_total: _original_total,
11959				original_total_plus_fee: original_total_plus_fee,
11960				extraFee: extraFee,
11961				cartQty: cartQty
11962			} );
11963			formatted_fees_total = $.epoAPI.applyFilter( 'tcAdjustFormattedFeesTotal', formatted_fees_total, {
11964				epo: currentEpoObject,
11965				totalsHolder: totalsHolder,
11966				event: event,
11967				cart_fee_options_total: cart_fee_options_total,
11968				extraFee: extraFee,
11969				cartQty: cartQty
11970			} );
11971			formatted_fees_original_total = $.epoAPI.applyFilter( 'tcAdjustFormattedFeesOriginalTotal', formatted_fees_original_total, {
11972				epo: currentEpoObject,
11973				totalsHolder: totalsHolder,
11974				event: event,
11975				cart_fee_options_original_total: cart_fee_options_original_total,
11976				extraFee: extraFee,
11977				cartQty: cartQty
11978			} );
11979			formatted_final_total = $.epoAPI.applyFilter( 'tcAdjustFormattedFinalTotal', formatted_final_total, {
11980				epo: currentEpoObject,
11981				totalsHolder: totalsHolder,
11982				event: event,
11983				product_total_price: product_total_price,
11984				product_total_price_without_options: product_total_price_without_options,
11985				total_plus_fee: total_plus_fee,
11986				extraFee: extraFee,
11987				cartQty: cartQty
11988			} );
11989			formatted_final_original_total = $.epoAPI.applyFilter( 'tcAdjustFormattedFinalOriginalTotal', formatted_final_original_total, {
11990				epo: currentEpoObject,
11991				totalsHolder: totalsHolder,
11992				event: event,
11993				product_total_original_price: product_total_original_price,
11994				product_total_price_without_options: product_total_price_without_options,
11995				original_total_plus_fee: original_total_plus_fee,
11996				extraFee: extraFee,
11997				cartQty: cartQty
11998			} );
11999
12000			if ( ( total > 0 && finalTotalBoxShowOptions === 'showtgz' ) || finalTotalBoxShowOptions === 'show' ) {
12001				show_options_total = true;
12002				if ( TMEPOJS.tm_epo_enable_vat_options_total === 'yes' ) {
12003					show_vat_options_total = true;
12004				}
12005			}
12006			if ( cart_fee_options_total !== 0 ) {
12007				show_fees_total = true;
12008			}
12009
12010			if ( formatted_final_total && finalTotalBoxShowFinal === 'show' ) {
12011				show_final_total = true;
12012			}
12013
12014			tc_totals_ob = {
12015				qty: cartQty,
12016				product_price: productPrice,
12017				raw_product_price: rawProductPrice,
12018				product_regular_price: productRegularPrice,
12019				raw_product_regular_price: rawProductRegularPrice,
12020				formatted_product_price: tm_set_price_totals( parseFloat( productPrice ) * cartQty ),
12021
12022				late_total_prices: late_total_price,
12023				late_total_price: tm_set_tax_price( late_total_price[ 0 ], totalsHolder ),
12024				late_total_original_price: tm_set_tax_price( late_total_price[ 1 ], totalsHolder ),
12025
12026				raw_options_price_per_unit: raw__total,
12027				raw_options_total_price: raw_total,
12028				raw_cart_fee_options_total_price: raw_cart_fee_options_total,
12029				raw_total_plus_fee: raw_total_plus_fee,
12030
12031				raw_options_original_price_per_unit: raw__original_total,
12032				raw_options_original_total_price: raw_original_total,
12033				raw_cart_fee_options_original_total_price: raw_cart_fee_options_original_total,
12034				raw_original_total_plus_fee: raw_original_total_plus_fee,
12035
12036				raw_product_total_price: raw_product_total_price,
12037				raw_product_total_original_price: raw_product_total_original_price,
12038				raw_product_total_price_without_options: raw_product_total_price_without_options,
12039
12040				options_price_per_unit: _total,
12041				options_total_price: total,
12042				cart_fee_options_total_price: cart_fee_options_total,
12043				total_plus_fee: total_plus_fee,
12044
12045				options_original_price_per_unit: _original_total,
12046				options_original_total_price: original_total,
12047				cart_fee_options_total_original_price: cart_fee_options_original_total,
12048				original_total_plus_fee: original_total_plus_fee,
12049
12050				vat_options_total: vat_options_total,
12051				vat_options_total_plus_fee: vat_options_total_plus_fee,
12052				formatted_vat_options_total: formatted_vat_options_total,
12053				formatted_vat_options_total_plus_fee: formatted_vat_options_total_plus_fee,
12054				vat_total: vat_total,
12055				formatted_vat_total: formatted_vat_total,
12056				vat_product_base: vat_product_base,
12057				formatted_vat_product_base: formatted_vat_product_base,
12058
12059				product_total_price: product_total_price,
12060				product_total_original_price: product_total_original_price,
12061				product_total_price_without_options: product_total_price_without_options,
12062
12063				product_unit_price: unit_price,
12064				product_unit_original_price: unit_original_price,
12065				formatted_unit_price: formatted_unit_price,
12066				formatted_options_total: formatted_options_total,
12067				formatted_fees_total: formatted_fees_total,
12068				formatted_final_total: formatted_final_total,
12069
12070				formatted_unit_original_price: formatted_unit_original_price,
12071				formatted_options_original_total: formatted_options_original_total,
12072				formatted_fees_original_total: formatted_fees_original_total,
12073				formatted_final_original_total: formatted_final_original_total,
12074
12075				formatted_extra_fee: formatted_extra_fee,
12076
12077				show_options_total: show_options_total,
12078				show_fees_total: show_fees_total,
12079				show_extra_fee: show_extra_fee,
12080				show_final_total: show_final_total,
12081				show_options_vat: show_vat_options_total,
12082
12083				show_unit_price: TMEPOJS.tm_epo_show_unit_price === 'yes',
12084				unit_price: currentEpoObject.is_associated ? TMEPOJS.i18n_item_unit_price : TMEPOJS.i18n_unit_price,
12085				options_total: currentEpoObject.is_associated ? TMEPOJS.i18n_item_options_total : TMEPOJS.i18n_options_total,
12086				options_vat_total: currentEpoObject.is_associated ? TMEPOJS.i18n_item_vat_options_total : TMEPOJS.i18n_vat_options_total,
12087				final_total: currentEpoObject.is_associated ? TMEPOJS.i18n_item_final_total : TMEPOJS.i18n_final_total,
12088				fees_total: TMEPOJS.i18n_fees_total,
12089				extra_fee: TMEPOJS.i18n_extra_fee,
12090
12091				totals_box_before_unit_price: TMEPOJS.totals_box_before_unit_price,
12092				totals_box_after_unit_price: TMEPOJS.totals_box_after_unit_price,
12093				totals_box_before_vat_options_totals_price: TMEPOJS.totals_box_before_vat_options_totals_price,
12094				totals_box_after_vat_options_totals_price: TMEPOJS.totals_box_after_vat_options_totals_price,
12095				totals_box_before_options_totals_price: TMEPOJS.totals_box_before_options_totals_price,
12096				totals_box_after_options_totals_price: TMEPOJS.totals_box_after_options_totals_price,
12097				totals_box_before_fee_totals_price: TMEPOJS.totals_box_before_fee_totals_price,
12098				totals_box_after_fee_totals_price: TMEPOJS.totals_box_after_fee_totals_price,
12099				totals_box_before_extra_fee_price: TMEPOJS.totals_box_before_extra_fee_price,
12100				totals_box_after_extra_fee_price: TMEPOJS.totals_box_after_extra_fee_price,
12101				totals_box_before_final_totals_price: TMEPOJS.totals_box_before_final_totals_price,
12102				totals_box_after_final_totals_price: TMEPOJS.totals_box_after_final_totals_price
12103			};
12104
12105			if ( TMEPOJS.customer_price_format ) {
12106				customer_price_format_wrap_start = TMEPOJS.customer_price_format_wrap_start;
12107				customer_price_format_wrap_end = TMEPOJS.customer_price_format_wrap_end;
12108				customerPriceFormat = TMEPOJS.customer_price_format;
12109			}
12110
12111			if ( formatted_options_total && total >= 0 ) {
12112				_ftotal = formatPrice( total );
12113				_foriginal_total = formatPrice( original_total );
12114				if ( customerPriceFormat ) {
12115					_ftotal = customerPriceFormat.replaceAll( '__PRICE__', _ftotal ).replaceAll( '__CODE__', TMEPOJS.current_currency );
12116					if ( ! totalsHolder.data( 'is-on-sale' ) ) {
12117						_foriginal_total = customerPriceFormat.replaceAll( '__PRICE__', _foriginal_total ).replaceAll( '__CODE__', TMEPOJS.current_currency );
12118					}
12119				}
12120				_ftotal = $.epoAPI.applyFilter( 'tcFilterFormattedFTotal', _ftotal, {
12121					epo: currentEpoObject,
12122					totalsHolder: totalsHolder,
12123					event: event,
12124					total: total,
12125					_total: _total,
12126					total_plus_fee: total_plus_fee,
12127					extraFee: extraFee,
12128					cartQty: cartQty
12129				} );
12130				_foriginal_total = $.epoAPI.applyFilter( 'tcFilterFormattedFOriginalTotal', _foriginal_total, {
12131					epo: currentEpoObject,
12132					totalsHolder: totalsHolder,
12133					event: event,
12134					original_total: original_total,
12135					total: original_total,
12136					_total: _total,
12137					total_plus_fee: total_plus_fee,
12138					extraFee: extraFee,
12139					cartQty: cartQty
12140				} );
12141				if ( TMEPOJS.tm_epo_enable_original_final_total === 'yes' && total !== original_total ) {
12142					tc_totals_ob.formatted_options_total = $.epoAPI.util.decodeHTML(
12143						$.epoAPI.template.html( tcAPI.templateEngine.tc_formatted_sale_price, {
12144							price: _foriginal_total,
12145							sale_price: _ftotal,
12146							customer_price_format_wrap_start: customer_price_format_wrap_start,
12147							customer_price_format_wrap_end: customer_price_format_wrap_end
12148						} )
12149					);
12150					tc_totals_ob._foriginal_total = _foriginal_total;
12151					tc_totals_ob._ftotal = _ftotal;
12152				} else {
12153					tc_totals_ob.formatted_options_total = $.epoAPI.util.decodeHTML(
12154						$.epoAPI.util.decodeHTML(
12155							$.epoAPI.template.html( tcAPI.templateEngine.tc_formatted_price, {
12156								price: _ftotal,
12157								customer_price_format_wrap_start: customer_price_format_wrap_start,
12158								customer_price_format_wrap_end: customer_price_format_wrap_end
12159							} )
12160						)
12161					);
12162				}
12163			}
12164
12165			if ( formatted_final_total && product_total_price >= 0 ) {
12166				_fprice = formatPrice( product_total_price );
12167				if ( priceOverrideMode === '1' && parseFloat( total ) > 0 ) {
12168					_f_regular_price = parseFloat( raw_original_total + extraFee );
12169				} else {
12170					_f_regular_price = parseFloat( parseFloat( rawProductRegularPrice * cartQty ) + raw_original_total );
12171				}
12172				if ( customerPriceFormat ) {
12173					_fprice = customerPriceFormat.replaceAll( '__PRICE__', _fprice ).replaceAll( '__CODE__', TMEPOJS.current_currency );
12174					if ( ! totalsHolder.data( 'is-on-sale' ) ) {
12175						_f_regular_price = customerPriceFormat.replaceAll( '__PRICE__', _f_regular_price ).replaceAll( '__CODE__', TMEPOJS.current_currency );
12176					}
12177				}
12178
12179				_fprice = $.epoAPI.applyFilter( 'tc_adjust_native_price', _fprice, product_total_price );
12180				_f_regular_price = tm_set_tax_price( _f_regular_price, totalsHolder, undefined, undefined, undefined, undefined, true ) + parseFloat( cart_fee_options_original_total ) + parseFloat( extraFee );
12181				_f_regular_price = formatPrice( _f_regular_price );
12182				_f_regular_price = $.epoAPI.applyFilter( 'tc_adjust_native_regular_price', _f_regular_price, product_total_price );
12183
12184				if ( TMEPOJS.tm_epo_enable_original_final_total =
12184== 'yes' && ( ( totalsHolder.data( 'is-on-sale' ) && priceOverrideMode !== '1' ) || _f_regular_price !== _fprice ) ) {
12185					tc_totals_ob.formatted_final_total = $.epoAPI.util.decodeHTML(
12186						$.epoAPI.template.html( tcAPI.templateEngine.tc_formatted_sale_price, {
12187							price: _f_regular_price,
12188							sale_price: _fprice,
12189							customer_price_format_wrap_start: customer_price_format_wrap_start,
12190							customer_price_format_wrap_end: customer_price_format_wrap_end
12191						} )
12192					);
12193				} else {
12194					tc_totals_ob.formatted_final_total = $.epoAPI.util.decodeHTML(
12195						$.epoAPI.util.decodeHTML(
12196							$.epoAPI.template.html( tcAPI.templateEngine.tc_formatted_price, {
12197								price: _fprice,
12198								customer_price_format_wrap_start: customer_price_format_wrap_start,
12199								customer_price_format_wrap_end: customer_price_format_wrap_end
12200							} )
12201						)
12202					);
12203				}
12204				tc_totals_ob._f_regular_price = _f_regular_price;
12205				tc_totals_ob._fprice = _fprice;
12206			}
12207
12208			// Add the suffix.
12209			tc_totals_ob.formatted_unit_price = tc_totals_ob.formatted_unit_price + $.epoAPI.util.decodeHTML(
12210				$.epoAPI.util.decodeHTML(
12211					$.epoAPI.template.html( tcAPI.templateEngine.suffix )
12212				)
12213			);
12214
12215			tc_totals_ob.formatted_options_total = tc_totals_ob.formatted_options_total + $.epoAPI.util.decodeHTML(
12216				$.epoAPI.util.decodeHTML(
12217					$.epoAPI.template.html( tcAPI.templateEngine.suffix )
12218				)
12219			);
12220
12221			tc_totals_ob.formatted_final_total = tc_totals_ob.formatted_final_total + $.epoAPI.util.decodeHTML(
12222				$.epoAPI.util.decodeHTML(
12223					$.epoAPI.template.html( tcAPI.templateEngine.suffix )
12224				)
12225			);
12226
12227			tc_totals_ob = replace_suffixes( 'formatted_fees_original_total', 'cart_fee_options_total_original_price', tc_totals_ob, totalsHolder );
12228			tc_totals_ob = replace_suffixes( 'formatted_fees_total', 'cart_fee_options_total_price', tc_totals_ob, totalsHolder );
12229			tc_totals_ob = replace_suffixes( 'formatted_final_original_total', 'product_total_original_price', tc_totals_ob, totalsHolder );
12230			tc_totals_ob = replace_suffixes( 'formatted_final_total', 'product_total_price', tc_totals_ob, totalsHolder );
12231			tc_totals_ob = replace_suffixes( 'formatted_options_original_total', 'options_original_total_price', tc_totals_ob, totalsHolder );
12232			tc_totals_ob = replace_suffixes( 'formatted_options_total', 'options_total_price', tc_totals_ob, totalsHolder );
12233			tc_totals_ob = replace_suffixes( 'formatted_unit_original_price', 'product_unit_original_price', tc_totals_ob, totalsHolder );
12234			tc_totals_ob = replace_suffixes( 'formatted_unit_price', 'product_unit_price', tc_totals_ob, totalsHolder );
12235
12236			if ( $.tcepo.showHideTotal !== undefined && $.tcepo.showHideTotal[ epoEventId ] !== undefined ) {
12237				showTotal = $.tcepo.showHideTotal[ epoEventId ];
12238			}
12239
12240			tc_totals_ob = $.epoAPI.applyFilter( 'tc_adjust_tc_totals_ob', tc_totals_ob, {
12241				epo_object: currentEpoObject,
12242				showTotal: showTotal,
12243				epoHolder: epoHolder,
12244				totalsHolder: totalsHolder,
12245				replace_suffixes: replace_suffixes,
12246				replace_suffixes_in_html: replace_suffixes_in_html,
12247				tm_set_tax_price: tm_set_tax_price,
12248				tm_set_price: tm_set_price,
12249				tm_set_price_totals: tm_set_price_totals,
12250				product_total_price: product_total_price,
12251				product_price: productPrice,
12252				qty: cartQty
12253			} );
12254
12255			if ( tc_totals_ob.showTotal !== undefined ) {
12256				showTotal = tc_totals_ob.showTotal;
12257			}
12258
12259			currentEpoObject.tc_totals_ob = tc_totals_ob;
12260
12261			showTotal = $.epoAPI.applyFilter( 'tcFinalTotalsBoxVisibility', showTotal, {
12262				epo: currentEpoObject,
12263				alternativeCart: alternativeCart,
12264				cart: cart,
12265				main_product: main_product,
12266				totalsHolder: totalsHolder,
12267				this_epo_totals_container: this_epo_totals_container
12268			} );
12269
12270			html = $.epoAPI.template.html( tcAPI.templateEngine.tc_final_totals, tc_totals_ob );
12271
12272			totalsHolder.data( 'tm-html', html );
12273			totalsHolder.data( 'tc_totals_ob', tc_totals_ob );
12274
12275			if ( currentEpoObject.associated_connect && currentEpoObject.associated_connect.length === 1 ) {
12276				if ( currentEpoObject.associated_connect.attr( 'data-no-price' ) === '1' ) {
12277					associatedPrice = 0;
12278					associatedRawPrice = 0;
12279					associatedOriginalPrice = 0;
12280					associatedRawOriginalPrice = 0;
12281					associatedFormattedPrice = '';
12282					tm_force_update_price(
12283						epoObject,
12284						associatedSetter
12285							.closest( '.tmcp-field-wrap' )
12286							.find( '.tc-price' )
12287							.not( tcAPI.associatedEpoSelector + ' .tc-price' ),
12288						associatedPrice,
12289						associatedFormattedPrice,
12290						associatedOriginalPrice
12291					);
12292				} else {
12293					associatedPrice = tc_totals_ob.product_price + tc_totals_ob.options_price_per_unit + ( tc_totals_ob.cart_fee_options_total_price / tc_totals_ob.qty );
12294					associatedRawPrice = tc_totals_ob.raw_product_price + tc_totals_ob.raw_options_price_per_unit + ( tc_totals_ob.raw_cart_fee_options_total_price / tc_totals_ob.qty );
12295					associatedOriginalPrice = tc_totals_ob.product_regular_price + tc_totals_ob.options_original_price_per_unit + ( tc_totals_ob.cart_fee_options_total_original_price / tc_totals_ob.qty );
12296					associatedRawOriginalPrice = tc_totals_ob.raw_product_regular_price + tc_totals_ob.raw_options_original_price_per_unit + ( tc_totals_ob.raw_cart_fee_options_original_total_price / tc_totals_ob.qty );
12297
12298					associatedFormattedPrice = tm_set_price( associatedPrice, currentEpoObject.this_epo_totals_container, false, associatedSetter );
12299
12300					// Mainly used to update the price of the associated element when the associated product is variable.
12301					tm_force_update_price(
12302						epoObject,
12303						associatedSetter
12304							.closest( '.tmcp-field-wrap' )
12305							.find( '.tc-price' )
12306							.not( tcAPI.associatedEpoSelector + ' .tc-price' ),
12307						associatedPrice,
12308						associatedFormattedPrice,
12309						associatedOriginalPrice
12310					);
12311
12312					currentEpoObject.associated_connect.data( 'tm-quantity', tc_totals_ob.qty );
12313
12314					if ( currentEpoObject.associated_connect.data( 'tm-quantity' ) ) {
12315						associatedPrice = associatedPrice * parseFloat( currentEpoObject.associated_connect.data( 'tm-quantity' ) );
12316						associatedRawPrice = associatedRawPrice * parseFloat( currentEpoObject.associated_connect.data( 'tm-quantity' ) );
12317						associatedOriginalPrice = associatedOriginalPrice * parseFloat( currentEpoObject.associated_connect.data( 'tm-quantity' ) );
12318						associatedRawOriginalPrice = associatedRawOriginalPrice * parseFloat( currentEpoObject.associated_connect.data( 'tm-quantity' ) );
12319					}
12320
12321					associatedFormattedPrice = tm_set_price( associatedPrice, currentEpoObject.this_epo_totals_container, false, associatedSetter );
12322				}
12323
12324				currentEpoObject.associated_connect.data( 'price_set', 1 );
12325				if ( associatedSetter.is( '.tcenabled' ) ) {
12326					associatedSetter.data( 'associated_price_set', 1 );
12327				}
12328				associatedSetter.data( 'price_set', 1 );
12329				associatedSetter.data( 'raw_price', associatedRawPrice );
12330				associatedSetter.data( 'raw_original_price', associatedRawOriginalPrice );
12331				associatedSetter.data( 'price', tm_set_tax_price( associatedPrice, currentEpoObject.this_epo_totals_container, associatedSetter ) );
12332				associatedSetter.data( 'original_price', tm_set_tax_price( associatedOriginalPrice, currentEpoObject.this_epo_totals_container, associatedSetter ) );
12333
12334				currentEpoObject.associated_connect.data( 'price-changed', 1 );
12335
12336				setTimeout( function() {
12337					if ( ! ( currentEpoObject.associated_connect && event.noassociated ) ) {
12338						currentEpoObject.mainEpoObject.main_cart.trigger( {
12339							type: 'tm-epo-update',
12340							norules: 2
12341						} );
12342					}
12343				}, 20 );
12344			}
12345
12346			jWindow.trigger( 'tcEpoAfterCalculateTotals', {
12347				epo: currentEpoObject,
12348				alternativeCart: alternativeCart,
12349				this_product_type: this_product_type,
12350				cart: cart,
12351				bundleid: bundleid,
12352				totalsObject: tc_totals_ob,
12353				main_product: main_product,
12354				per_product_pricing: perProductPricing,
12355				event: event
12356			} );
12357
12358			hide_native_price = $.epoAPI.applyFilter( 'hide_native_price', true );
12359
12360			if ( cartQty > 0 ) {
12361				// hide native prices
12362				if ( TMEPOJS.tm_epo_change_variation_price === 'yes' ) {
12363					if ( hide_native_price === true && finalTotalBoxMode !== 'disable' ) {
12364						tm_get_native_prices_block( cart ).hide();
12365					} else {
12366						tm_get_native_prices_block( cart ).show();
12367					}
12368				}
12369
12370				if ( ! showTotal ||
12371					finalTotalBoxMode === 'disable' ||
12372					( finalTotalBoxMode === 'hideiftotaliszero' && product_total_price === 0 ) ||
12373					( finalTotalBoxMode === 'hideifoptionsiszero' && total_plus_fee === 0 )
12374				) {
12375					html = '';
12376					totalsHolder.html( html );
12377					totalsHolder.data( 'tm-floating-box-data', [] );
12378				} else {
12379					totalsHolder.html( html );
12380
12381					jWindow.trigger( 'tc-totals-container', {
12382						epo: tc_totals_ob,
12383						totals_holder: totalsHolder,
12384						data: {
12385							epo_object: currentEpoObject,
12386							tm_set_price: tm_set_price,
12387							tm_set_price_totals: tm_set_price_totals,
12388							product_total_price: product_total_price,
12389							product_price: productPrice,
12390							qty: cartQty
12391						},
12392						tm_epo_js: TMEPOJS
12393					} );
12394				}
12395
12396				if ( formatted_final_total && product_total_price >= 0 ) {
12397					if ( TMEPOJS.tm_epo_change_variation_price === 'yes' ) {
12398						setTimeout( function() {
12399							update_native_html = tm_get_native_prices_block( cart );
12400							if ( totalsHolder.data( 'is-on-sale' ) ) {
12401								temp = $.epoAPI.util.decodeHTML(
12402									$.epoAPI.template.html( tcAPI.templateEngine.tc_formatted_sale_price, {
12403										price: _f_regular_price,
12404										sale_price: _fprice,
12405										customer_price_format_wrap_start: customer_price_format_wrap_start,
12406										customer_price_format_wrap_end: customer_price_format_wrap_end,
12407										before_price_text: TMEPOJS.variation_price_before_price_text,
12408										after_price_text: TMEPOJS.variation_price_after_price_text
12409									} )
12410								);
12411								temp = temp + $.epoAPI.util.decodeHTML(
12412									$.epoAPI.util.decodeHTML(
12413										$.epoAPI.template.html( tcAPI.templateEngine.main_suffix )
12414									)
12415								);
12416								temp = {
12417									formatted: temp,
12418									raw: tc_totals_ob.product_total_price
12419								};
12420								temp = replace_suffixes( 'formatted', 'raw', temp, totalsHolder );
12421								temp = temp.formatted;
12422								update_native_html
12423									.html( temp )
12424									.show();
12425							} else {
12426								temp = $.epoAPI.util.decodeHTML(
12427									$.epoAPI.template.html( tcAPI.templateEngine.tc_formatted_price, {
12428										price: _fprice,
12429										customer_price_format_wrap_start: customer_price_format_wrap_start,
12430										customer_price_format_wrap_end: customer_price_format_wrap_end,
12431										before_price_text: TMEPOJS.variation_price_before_price_text,
12432										after_price_text: TMEPOJS.variation_price_after_price_text
12433									} )
12434								);
12435								temp = temp + $.epoAPI.util.decodeHTML(
12436									$.epoAPI.util.decodeHTML(
12437										$.epoAPI.template.html( tcAPI.templateEngine.main_suffix )
12438									)
12439								);
12440								temp = {
12441									formatted: temp,
12442									raw: tc_totals_ob.product_total_price
12443								};
12444								temp = replace_suffixes( 'formatted', 'raw', temp, totalsHolder );
12445								temp = temp.formatted;
12446								update_native_html
12447									.html( temp )
12448									.show();
12449							}
12450						}, 310 ); // WooCommerce uses 300ms timeout for changing the price.
12451					}
12452
12453					if ( TMEPOJS.tm_epo_change_original_price === 'yes' ) {
12454						if ( ! alternativeCart || main_product.find( '.cpf-bto-price' ).length === 0 ) {
12455							if ( currentEpoObject.associated_connect ) {
12456								nativeProductPriceSelector = currentEpoObject.main_product.find( tcAPI.associatedNativeProductPriceSelector );
12457							} else {
12458								// shop/archive pages.
12459								nativeProductPriceSelector = currentEpoObject.main_product.find( tcAPI.nativeProductPriceSelector );
12460								// product page.
12461								if ( nativeProductPriceSelector.length === 0 ) {
12462									nativeProductPriceSelector = $( tcAPI.nativeProductPriceSelector );
12463								}
12464							}
12465
12466							if ( nativeProductPriceSelector.length === 0 && main_product.is( '.tc-after-shop-loop' ) ) {
12467								nativeProductPriceSelector = main_product.closest( '.product' ).find( '.price' ).not( '.tc-after-shop-loop .price' );
12468							}
12469							if ( nativeProductPriceSelector.data( 'tc-original-html' ) === undefined ) {
12470								nativeProductPriceSelector.data( 'tc-original-html', nativeProductPriceSelector.html() );
12471							}
12472							if ( product_total_price > 0 ) {
12473								if ( totalsHolder.data( 'is-on-sale' ) ) {
12474									temp = $.epoAPI.util.decodeHTML(
12475										$.epoAPI.template.html( tcAPI.templateEngine.tc_formatted_sale_price, {
12476											price: _f_regular_price,
12477											sale_price: _fprice,
12478											customer_price_format_wrap_start: customer_price_format_wrap_start,
12479											customer_price_format_wrap_end: customer_price_format_wrap_end,
12480											before_price_text: TMEPOJS.product_price_before_price_text,
12481											after_price_text: TMEPOJS.product_price_after_price_text
12482										} )
12483									);
12484									temp = temp + $.epoAPI.util.decodeHTML(
12485										$.epoAPI.util.decodeHTML(
12486											$.epoAPI.template.html( tcAPI.templateEngine.main_suffix )
12487										)
12488									);
12489									temp = {
12490										formatted: temp,
12491										raw: tc_totals_ob.product_total_price
12492									};
12493									temp = replace_suffixes( 'formatted', 'raw', temp, totalsHolder );
12494									temp = temp.formatted;
12495									nativeProductPriceSelector
12496										.html( temp )
12497										.show();
12498								} else {
12499									temp = $.epoAPI.util.decodeHTML(
12500										$.epoAPI.template.html( tcAPI.templateEngine.tc_formatted_price, {
12501											price: _fprice,
12502											customer_price_format_wrap_start: customer_price_format_wrap_start,
12503											customer_price_format_wrap_end: customer_price_format_wrap_end,
12504											before_price_text: TMEPOJS.product_price_before_price_text,
12505											after_price_text: TMEPOJS.product_price_after_price_text
12506										} )
12507									);
12508									temp = temp + $.epoAPI.util.decodeHTML(
12509										$.epoAPI.util.decodeHTML(
12510											$.epoAPI.template.html( tcAPI.templateEngine.main_suffix )
12511										)
12512									);
12513									temp = {
12514										formatted: temp,
12515										raw: tc_totals_ob.product_total_price
12516									};
12517									temp = replace_suffixes( 'formatted', 'raw', temp, totalsHolder );
12518									temp = temp.formatted;
12519									nativeProductPriceSelector
12520										.html( temp )
12521										.show();
12522								}
12523							} else if ( this_product_type && this_product_type !== 'composite' ) {
12524								if ( currentEpoObject.associated_connect ) {
12525									if ( currentEpoObject.variations_form.length ) {
12526										temp = currentEpoObject.this_epo_totals_container.data( 'variationIdElement' );
12527										if ( temp.length > 0 ) {
12528											temp = parseFloat( temp.val() );
12529											if ( ! ( ! temp || temp === 0 ) ) {
12530												nativeProductPriceSelector.html( $.epoAPI.util.decodeHTML( TMEPOJS.assoc_current_free_text ) );
12531											}
12532										}
12533									} else {
12534										nativeProductPriceSelector.html( $.epoAPI.util.decodeHTML( TMEPOJS.assoc_current_free_text ) );
12535									}
12536								} else {
12537									nativeProductPriceSelector.html( $.epoAPI.util.decodeHTML( TMEPOJS.current_free_text ) );
12538								}
12539							}
12540						}
12541
12542						jWindow.trigger( 'tcEpoMaybeChangePriceHtml', {
12543							epo: currentEpoObject,
12544							alternativeCart: alternativeCart,
12545							this_product_type: this_product_type,
12546							cart: cart,
12547							bundleid: bundleid,
12548							totalsObject: tc_totals_ob,
12549							main_product: main_product,
12550							nativePrice: _fprice
12551						} );
12552					}
12553				}
12554
12555				if ( alternativeCart ) {
12556					main_cart.trigger( {
12557						type: 'tm-epo-update',
12558						norules: 1
12559					} );
12560				} else {
12561					this_epo_totals_container.data( 'is_active', true );
12562				}
12563			} else {
12564				if ( currentEpoObject.associated_connect ) {
12565					nativeProductPriceSelector = currentEpoObject.main_product.find( tcAPI.associatedNativeProductPriceSelector );
12566					nativeProductPriceSelector.html( nativeProductPriceSelector.data( 'tc-original-html' ) );
12567				}
12568
12569				tm_get_native_prices_block( cart ).toArray().forEach( function( npb ) {
12570					var $npb = $( npb );
12571					if ( ! $npb.data( 'tm-original-html' ) ) {
12572						$npb.data( 'tm-original-html', $npb.html() );
12573					} else {
12574						$npb.html( $npb.data( 'tm-original-html' ) );
12575					}
12576				} );
12577
12578				if ( rawProductPrice === 0 && TMEPOJS.tm_epo_remove_free_price_label === 'yes' ) {
12579					tm_get_native_prices_block( cart ).hide();
12580				} else if ( TMEPOJS.tm_epo_change_variation_price === 'yes' && ! ( hide_native_price === true && finalTotalBoxMode !== 'disable' ) ) {
12581					tm_get_native_prices_block( cart ).show();
12582				}
12583
12584				totalsHolder.empty();
12585
12586				if ( alternativeCart ) {
12587					main_cart.trigger( {
12588						type: 'tm-epo-update',
12589						norules: 1
12590					} );
12591				}
12592			}
12593
12594			main_cart.trigger( 'tm-epo-after-update', {
12595				container: cartContainer
12596			} );
12597
12598			jWindow.trigger( 'tc-epo-after-update', {
12599				epo: tc_totals_ob,
12600				totals_holder: totalsHolder,
12601				data: {
12602					epo_object: currentEpoObject,
12603					add_late_fields_prices: add_late_fields_prices,
12604					tm_set_price: tm_set_price,
12605					tm_set_price_totals: tm_set_price_totals,
12606					product_total_price: product_total_price,
12607					replace_suffixes_in_html: replace_suffixes_in_html,
12608					product_price: productPrice,
12609					qty: cartQty,
12610					bundleid: bundleid,
12611					currentCart: currentCart
12612				},
12613				tm_epo_js: TMEPOJS
12614			} );
12615		} );
12616
12617		if ( this_product_type === 'variable' || this_product_type === 'variable-subscription' ) {
12618			epoVariationSection = epoHolder.find( '.tm-epo-variation-section' ).first();
12619
12620			// Custom variation events
12621			epoVariationSection
12622				.find( '.tm-epo-reset-variation' )
12623				.off( 'click.cpfv' )
12624				.on( 'click.cpfv', function() {
12625					var field = $( this );
12626					var id = $.epoAPI.dom.id( field.attr( 'data-tm-for-variation' ) );
12627					var section = field.closest( '.cpf-type-variations' );
12628					var inputs = field.closest( '.cpf-element' ).find( '.tm-epo-variation-element' );
12629					var lis = field.closest( '.cpf-element' ).find( '.tmcp-field-wrap' );
12630
12631					inputs.prop( 'checked', false );
12632					lis.removeClass( 'tc-active' );
12633					variationForm
12634						.find( "[data-attribute_name='attribute_" + id + "']" )
12635						.val( '' )
12636						.trigger( 'change' );
12637					variationForm.find( "[data-attribute_name='attribute_" + id + "']" ).trigger( 'focusin' );
12638
12639					main_product
12640						.find( '.cpf-type-variations' )
12641						.not( section )
12642						.toArray().forEach( function( el ) {
12643							variationForm.find( "[data-attribute_name='attribute_" + $.epoAPI.dom.id( $( el ).find( '.tm-epo-variation-element' ).first().attr( 'data-tm-for-variation' ) ) + "']" ).trigger( 'focusin' );
12644						} );
12645					field.trigger( 'blur' );
12646					variationForm.trigger( 'woocommerce_update_variation_values_tmlogic' );
12647				} );
12648
12649			epoVariationSection
12650				.find( 'input.tm-epo-variation-element,input.tm-epo-variation-element + span' )
12651				.off( 'mouseup.cpfv' )
12652				.on( 'mouseup.cpfv', function() {
12653					var field = $( this );
12654					var id;
12655
12656					if ( field.is( 'span' ) ) {
12657						field = field.prev( 'input' );
12658					}
12659					if ( field.attr( 'disabled' ) ) {
12660						variationForm.find( '.reset_variations' ).trigger( 'click' );
12661					}
12662					id = $.epoAPI.dom.id( field.attr( 'data-tm-for-variation' ) );
12663					variationForm.find( "[data-attribute_name='attribute_" + id + "']" ).trigger( 'focusin' );
12664				} );
12665
12666			epoVariationSection
12667				.off( 'click.' + eventName + '.tmepo', '.reset_variations, .tc-epo-element-variable-reset-variations' )
12668				.on( 'click.' + eventName + '.tmepo', '.reset_variations, .tc-epo-element-variable-reset-variations', { _epoObject: epoObject }, function( event ) {
12669					var _nativeProductPriceSelector;
12670					if ( TMEPOJS.tm_epo_change_original_price === 'yes' ) {
12671						if ( ! alternativeCart || main_product.find( '.cpf-bto-price' ).length === 0 ) {
12672							if ( event.data._epoObject.associated_connect ) {
12673								_nativeProductPriceSelector = event.data._epoObject.main_product.find( tcAPI.associatedNativeProductPriceSelector );
12674							} else {
12675								_nativeProductPriceSelector = $( tcAPI.nativeProductPriceSelector );
12676							}
12677							if ( _nativeProductPriceSelector.data( 'tc-original-html' ) ) {
12678								_nativeProductPriceSelector.html( _nativeProductPriceSelector.data( 'tc-original-html' ) );
12679							}
12680						}
12681					}
12682					variationForm.find( '.variations .reset_variations, .tc-epo-element-variable-reset-variations' ).first().trigger( 'click' );
12683				} );
12684
12685			epoVariationSection
12686				.find( '.tm-epo-variation-element' )
12687				.off( 'change.cpfv tm_epo_variation_element_change' )
12688				.on( 'change.cpfv tm_epo_variation_element_change', function( e ) {
12689					var field = $( this );
12690					var id = $.epoAPI.dom.id( field.attr( 'data-tm-for-variation' ) );
12691					var value = field.val();
12692					var section = field.closest( '.cpf-type-variations' );
12693					var nativeSelect = variationForm.find( "[data-attribute_name='attribute_" + id + "']" );
12694					var exists;
12695
12696					if ( field.closest( '.tm-epo-variation-section' ).is( '.tm-hidden' ) ) {
12697						return;
12698					}
12699
12700					if ( ! ( e && e.type && e.type === 'tm_epo_variation_element_change' ) ) {
12701						exists = false;
12702						nativeSelect.each( function() {
12703							if ( this.value === value ) {
12704								exists = true;
12705								return false;
12706							}
12707						} );
12708						if ( ! exists ) {
12709							nativeSelect.trigger( 'focusin' );
12710						}
12711						nativeSelect.val( value ).trigger( 'change' );
12712					}
12713
12714					if ( ! value ) {
12715						nativeSelect.trigger( 'focusin' );
12716					}
12717
12718					main_product
12719						.find( '.cpf-type-variations' )
12720						.not( section )
12721						.toArray().forEach( function( vr ) {
12722							variationForm.find( '#' + $.epoAPI.dom.id( $( vr ).find( '.tm-epo-variation-element' ).first().attr( 'data-tm-for-variation' ) ) ).trigger( 'focusin' );
12723						} );
12724
12725					field.trigger( 'blur' );
12726					variationForm.trigger( 'woocommerce_update_variation_values_tmlogic' );
12727				} )
12728				.off( 'focusin.cpfv' )
12729				.on( 'focusin.cpfv', function() {
12730					var field = $( this );
12731					var id;
12732
12733					if ( ! field.is( 'select' ) ) {
12734						return;
12735					}
12736
12737					id = $.epoAPI.dom.id( field.attr( 'data-tm-for-variation' ) );
12738					variationForm.find( "[data-attribute_name='attribute_" + id + "']" ).trigger( 'focusin' );
12739					variationForm.trigger( 'woocommerce_update_variation_values_tmlogic' );
12740				} );
12741
12742			variationForm.off( eventNamePrefix + 'found_variation.tmepo tm_fix_stock', '.single_variation_wrap' ).on( eventNamePrefix + 'found_variation.tmepo tm_fix_stock', '.single_variation_wrap', function() {
12743				fix_stock( $( this ), cartContainer );
12744			} );
12745
12746			// update prices when a variation is found
12747			variationForm
12748				.off( eventNamePrefix + 'found_variation.tmepo' )
12749				.on( eventNamePrefix + 'found_variation.tmepo', function( event, variation ) {
12750					var form = $( this );
12751
12752					totalsHolder.data( 'is-on-sale', variation.tc_is_on_sale );
12753					totalsHolder.data( 'regular-price', tm_set_backend_price( variation.display_regular_price, totalsHolder, variation ) );
12754
12755					jWindow.trigger( 'tm-epo-found-variation', {
12756						epo: epoObject,
12757						totalsHolder: totalsHolder,
12758						totalsHolderContainer: totalsHolderContainer,
12759						currentCart: currentCart,
12760						variationForm: form,
12761						variation: variation
12762					} );
12763
12764					found_variation_tmepo( {
12765						epoHolder: epoHolder,
12766						totalsHolder: totalsHolder,
12767						totalsHolderContainer: totalsHolderContainer,
12768						currentCart: currentCart,
12769						variationForm: form,
12770						variation: variation
12771					} );
12772
12773					fix_stock( form, cartContainer );
12774				} )
12775				.off( eventNamePrefix + 'hide_variation.tmepo' )
12776				.on( eventNamePrefix + 'hide_variation.tmepo', { _epoObject: epoObject }, function( event ) {
12777					var _nativeProductPriceSelector;
12778					if ( TMEPOJS.tm_epo_change_original_price === 'yes' ) {
12779						if ( ! alternativeCart || main_product.find( '.cpf-bto-price' ).length === 0 ) {
12780							if ( event.data._epoObject.associated_connect ) {
12781								_nativeProductPriceSelector = event.data._epoObject.main_product.find( tcAPI.associatedNativeProductPriceSelector );
12782							} else {
12783								_nativeProductPriceSelector = $( tcAPI.nativeProductPriceSelector );
12784							}
12785							if ( _nativeProductPriceSelector.data( 'tc-original-html' ) ) {
12786								_nativeProductPriceSelector.html( _nativeProductPriceSelector.data( 'tc-original-html' ) );
12787							}
12788						}
12789					}
12790					totalsHolder.data( 'price', false );
12791					// Fancy product Designer
12792					totalsHolder.removeData( 'tcprice' );
12793					currentCart.trigger( {
12794						type: 'tm-epo-update',
12795						norules: 2
12796					} );
12797				} )
12798				.off( eventNamePrefix + 'check_variations.tmepo' )
12799				.on( eventNamePrefix + 'check_variations.tmepo', function() {
12800					var data = {};
12801					var chosen = 0;
12802					var reset = epoVariationSection.find( '.reset_variations' );
12803
12804					variationForm.find( '.variations select, .tc-epo-variable-product-selector' ).toArray().forEach( function( sl ) {
12805						var $this = $( sl );
12806						var attribute_name = $this.data( 'attribute_name' ) || $this.attr( 'name' );
12807						var value = $this.val() || '';
12808
12809						if ( value.length > 0 ) {
12810							chosen++;
12811						}
12812
12813						data[ attribute_name ] = value;
12814					} );
12815
12816					if ( chosen > 0 ) {
12817						if ( reset.css( 'visibility' ) === 'hidden' ) {
12818							reset.css( 'visibility', 'visible' ).hide().fadeIn();
12819						}
12820					} else {
12821						reset.css( 'visibility', 'hidden' );
12822					}
12823				} )
12824				.trigger( eventNamePrefix + 'check_variations' );
12825
12826			tm_custom_variations( epoObject, cartContainer, itemId, main_product, epoHolder );
12827		}
12828
12829		selectSelector.trigger( 'tm-select-change-html' );
12830		tmQty.trigger( 'change.cpf', { init: 1 } );
12831		tmQuantity.trigger( 'showhide.cpfcustom' );
12832		epoFieldHasClearButton.filter( ':checked' ).trigger( 'cpfclearbutton' );
12833
12834		jWindow.on( 'tm-do-epo-update', function() {
12835			// This must be run every time to get correct results for percent price types
12836			// if set norules then discount will not auto work upon chosing a variation
12837			currentCart.trigger( {
12838				type: 'tm-epo-update'
12839				//"norules": 2
12840			} );
12841		} );
12842
12843		jWindow.trigger( 'tm-epo-init-events', {
12844			epo: {
12845				epo_id: epo_id,
12846				form: epoObject.form,
12847				currentCart: currentCart,
12848				cart_container: cartContainer,
12849				epo_holder: epoHolder,
12850				totals_holder_container: totalsHolderContainer,
12851				totals_holder: totalsHolder,
12852				main_cart: main_cart,
12853				main_epo_inside_form: main_epo_inside_form,
12854				product_id_selector: product_id_selector,
12855				epo_id_selector: epo_id_selector,
12856				product_id: product_id,
12857				this_epo_container: this_epo_container,
12858				this_totals_container: this_totals_container,
12859				this_epo_totals_container: this_epo_totals_container
12860			}
12861		} );
12862
12863		jWindow.trigger( 'epoEventHandlers', {
12864			epo: epoObject,
12865			currentCart: currentCart,
12866			cartContainer: cartContainer,
12867			qtyElement: qtyElement,
12868			epoHolder: epoHolder,
12869			totalsHolderContainer: totalsHolderContainer,
12870			totalsHolder: totalsHolder,
12871			variationForm: variationForm,
12872			variation_id_selector: variation_id_selector,
12873			main_epo_inside_form: main_epo_inside_form,
12874			this_product_type: this_product_type,
12875			get_price_excluding_tax: get_price_excluding_tax,
12876			get_price_including_tax: get_price_including_tax
12877		} );
12878
12879		// show final totals
12880		if ( finalTotalBoxMode !== 'disable' ) {
12881			totalsHolderContainer.addClass( 'tc-show' );
12882		}
12883
12884		// show extra options
12885		jWindow.trigger( 'epo_options_before_visible' );
12886
12887		if ( TMEPOJS.tm_epo_progressive_display === 'yes' ) {
12888			setTimeout( function() {
12889				epoHolder
12890					.css( 'opacity', 0 )
12891					.addClass( 'tc-show' )
12892					.animate(
12893						{
12894							opacity: 1
12895						},
12896						tcAPI.epoAnimationDelay,
12897						'easeOutExpo',
12898						function() {
12899							jWindow.trigger( 'epo_options_visible' );
12900							jWindow.trigger( 'tmlazy' );
12901						}
12902					);
12903			}, tcAPI.epoDelay );
12904		} else {
12905			epoHolder.addClass( 'tc-show' );
12906			jWindow.trigger( 'epo_options_visible' );
12907			jWindow.trigger( 'tmlazy' );
12908		}
12909
12910		main_product.addClass( 'tc-init' );
12911	}
12912
12913	function run_wc_variation_form_cpf( epoObject ) {
12914		var form = epoObject.variations_form;
12915		var cart = epoObject.main_cart;
12916		var this_epo_container = epoObject.this_epo_container;
12917		var eventName = epoObject.is_associated ? 'tc_variation_form.cpf' : 'wc_variation_form.cpf';
12918		var run = function() {
12919			if ( form.data( 'epo_loaded' ) ) {
12920				return;
12921			}
12922
12923			// Start Condition Logic
12924			cpf_section_logic( epoObject );
12925			cpf_element_logic( epoObject );
12926
12927			jWindow.on( 'epoEventHandlers', function() {
12928				run_cpfdependson( this_epo_container );
12929				tm_lazyload();
12930			} );
12931
12932			// Init field price rules
12933			$.tcepo.lateFieldsPrices[ epoObject.epoEventId ] = [];
12934
12935			epoEventHandlers( epoObject );
12936			tm_set_upload_fields( epoObject );
12937			tm_product_image( epoObject );
12938
12939			jWindow.trigger( 'epo-after-init-in-timeout', { epo: epoObject } );
12940			epoObject.noEpoUpdate = false;
12941			cart.trigger( 'tm-epo-check-dpd' );
12942			cart.trigger( {
12943				type: 'tm-epo-update',
12944				rules: 'init'
12945			} );
12946
12947			form.data( 'epo_loaded', true );
12948		};
12949
12950		form.off( eventName ).on( eventName, function() {
12951			run();
12952		} );
12953
12954		setTimeout( function() {
12955			form.trigger( eventName );
12956		}, window.tcVariationDelayCheck || 2000 );
12957
12958		if ( variationsFormIsLoaded ) {
12959			form.trigger( eventName );
12960		}
12961
12962		jWindow.trigger( 'epo-after-init', { epo: epoObject } );
12963	}
12964
12965	function detect_variation_swatches_interval( epoObject ) {
12966		var $id = requestAnimationFrame( function() {
12967			detect_variation_swatches_interval( epoObject );
12968		} );
12969		var obj = epoObject.variations_form;
12970		var bound = obj.data( 'bound' );
12971		var eventName = epoObject.is_associated ? 'tc_variation_form.cpf' : 'wc_variation_form.cpf';
12972
12973		if ( bound ) {
12974			cancelAnimationFrame( $id );
12975			run_wc_variation_form_cpf( epoObject );
12976			obj.trigger( eventName );
12977		}
12978	}
12979
12980	function manualInitEPO( epoObject, item, itemCart, itemEpoContainer, main_product ) {
12981		var epoObjectOriginal = $.extend( true, {}, epoObject );
12982		var product_id = itemEpoContainer.attr( 'data-product-id' );
12983		var epo_id = itemEpoContainer.attr( 'data-epo-id' );
12984		var product_id_selector = '.tm-product-id-' + product_id;
12985		var epo_id_selector = "[data-epo-id='" + epo_id + "']";
12986		var epoEventId = 'p' + product_id + 'e' + epo_id;
12987		var this_epo_container = $( tcAPI.epoSelector + product_id_selector + epo_id_selector );
12988		var this_totals_container = $( '.tc-totals-form' + product_id_selector + epo_id_selector );
12989		var this_epo_totals_container = $( '.tc-epo-totals' + product_id_selector + epo_id_selector );
12990
12991		epoObject.isManual = true;
12992
12993		$.tcepo.formSubmitEvents[ epoEventId ] = [];
12994		$.tcepo.errorObject[ epoEventId ] = false;
12995		$.tcepo.initialActivation[ epoEventId ] = false;
12996
12997		epoObject.product_id = product_id;
12998		epoObject.product_id_selector = product_id_selector;
12999		epoObject.epo_id = epo_id;
13000		epoObject.epo_id_selector = epo_id_selector;
13001		epoObject.epoEventId = epoEventId;
13002		epoObject.noEpoUpdate = true;
13003		epoObject.thisForm = item;
13004		epoObject.this_epo_container = this_epo_container;
13005		epoObject.this_totals_container = this_totals_container;
13006		epoObject.this_epo_totals_container = this_epo_totals_container;
13007
13008		tm_lazyload();
13009		main_product.find( '.tm-collapse' ).tmtoggle();
13010		main_product.find( '.tm-section-link' ).tmsectionpoplink();
13011
13012		tm_set_datepicker( item );
13013		setRangePickers( item );
13014		setRangePickersEvents();
13015		tm_set_repeaters( item, epoObject );
13016		tm_css_styles( item );
13017		tm_set_color_pickers( itemEpoContainer );
13018		tm_set_lightbox( itemEpoContainer.find( '.tc-lightbox-image' ).not( '.tm-extra-product-options-variations .radio-image' ) );
13019
13020		// Start Condition Logic
13021		cpf_section_logic( epoObject );
13022		cpf_element_logic( epoObject );
13023		run_cpfdependson( itemEpoContainer );
13024
13025		$.tcToolTip( item.find( '.tm-tooltip' ) );
13026		epoEventHandlers( epoObject, item, itemCart );
13027
13028		epoObject.noEpoUpdate = false;
13029
13030		itemCart.trigger( {
13031			type: 'tm-epo-update',
13032			norules: 2
13033		} );
13034		setTimeout( function() {
13035			epoObject.main_cart.trigger( {
13036				type: 'tm-epo-update',
13037				epoObject: epoObjectOriginal,
13038				norules: 1
13039			} );
13040		}, 200 );
13041		fix_stock( itemCart, item );
13042	}
13043
13044	function tm_init_epo( main_product, is_quickview, product_id, epo_id, associated_connect, mainEpoObject, reactivate ) {
13045		// Holds the main cart when using Composite Products
13046		var main_cart = false;
13047		var main_epo_inside_form = false;
13048		var main_totals_inside_form = false;
13049		var epoEventId;
13050		var has_epo = typeof product_id !== 'undefined';
13051		var not_has_epo = false;
13052		var add_to_cart_field;
13053		var product_id_selector;
13054		var epo_id_selector;
13055		var this_epo_container;
13056		var this_totals_container;
13057		var this_epo_totals_container;
13058		var epo_object;
13059		var variations_form;
13060		var detect_variation_swatches = $( '.variation_form_section .variations-table' ).length > 0;
13061		var is_associated = false;
13062
13063		main_product = $( main_product );
13064
13065		if ( main_product.is( '.tc-init' ) && ! reactivate ) {
13066			return true;
13067		}
13068
13069		if ( is_quickview ) {
13070			errorContainer = main_product;
13071		} else {
13072			errorContainer = $( window );
13073		}
13074
13075		jWindow.trigger( 'tm-epo-init-start' );
13076
13077		if ( ! has_epo ) {
13078			if ( main_product.is( '.product' ) ) {
13079				not_has_epo = true;
13080				has_epo = jBody.find( tcAPI.epoSelector ).length;
13081			}
13082		}
13083
13084		// return if product has no extra options and the totals box is not enabled for all products
13085		if ( ! has_epo && TMEPOJS.tm_epo_enable_final_total_box_all === 'no' && ! main_product.is( '.tm-no-options-composite' ) ) {
13086			jWindow.trigger( 'tm-epo-init-end-no-options' );
13087			return;
13088		}
13089
13090		// set the main_product variable again for products that have no extra options
13091		if ( not_has_epo ) {
13092			jWindow.trigger( 'tm-epo-init-no-options' );
13093			if ( main_product.is( '.product' ) && ! ( main_product.is( '.tm-no-options-pxq' ) || main_product.is( '.tm-no-options-composite' ) ) ) {
13094				main_product = jBody;
13095			}
13096		}
13097
13098		if ( ! product_id ) {
13099			add_to_cart_field = main_product.find( tcAPI.addToCartSelector ).last();
13100			if ( add_to_cart_field.length > 0 ) {
13101				product_id = add_to_cart_field.val();
13102			} else {
13103				add_to_cart_field = $( '.tc-totals-form.tm-totals-form-main' );
13104				product_id = add_to_cart_field.attr( 'data-product-id' );
13105			}
13106			if ( ! product_id ) {
13107				product_id = '';
13108			}
13109		}
13110
13111		if ( ! epo_id ) {
13112			epo_id = parseInt( main_product.find( 'input.tm-epo-counter' ).last().val(), 10 );
13113
13114			if ( ! Number.isFinite( epo_id ) ) {
13115				epo_id = '';
13116			}
13117		}
13118
13119		product_id_selector = '.tm-product-id-' + product_id;
13120		epo_id_selector = "[data-epo-id='" + epo_id + "']";
13121		this_epo_container = $( tcAPI.epoSelector + product_id_selector + epo_id_selector );
13122		this_totals_container = $( '.tc-totals-form' + product_id_selector + epo_id_selector );
13123		this_epo_totals_container = $( '.tc-epo-totals' + product_id_selector + epo_id_selector );
13124		variations_form = main_product.find( '.variations_form' ).not( '.composite_component .variations_form' ).first();
13125		epoEventId = 'p' + product_id + 'e' + epo_id;
13126
13127		if ( variations_form && variations_form.attr( 'data-product_id' ) ) {
13128			if ( variations_form.attr( 'data-product_id' ) !== product_id ) {
13129				variations_form = main_product.find( ".variations_form[data-product_id='" + product_id + "']" );
13130			}
13131		}
13132
13133		main_cart = get_main_cart( main_product, main_product, 'form', product_id );
13134		if ( main_cart.length === 0 ) {
13135			if ( main_product.is( '.tc-shortcode-wrap' ) ) {
13136				main_cart = get_main_cart( this_totals_container, this_totals_container, '.tc-totals-form', product_id );
13137			} else if ( main_product.is( '.tc-epo-element-product-container' ) ) {
13138				main_cart = main_product.find( tcAPI.associatedEpoCart );
13139				// should never be 0
13140				if ( main_cart.length === 0 ) {
13141					main_cart = this_epo_container.parent( tcAPI.associatedEpoSelector );
13142					if ( main_cart.length === 0 ) {
13143						main_cart = main_product.find( '.tc-epo-element-product-container-right' );
13144					}
13145				}
13146				is_associated = true;
13147			}
13148		}
13149
13150		if ( is_associated && variations_form.length === 0 && main_product.is( '.variations_form' ) ) {
13151			variations_form = main_product;
13152		}
13153
13154		$.tcepo.formSubmitEvents[ epoEventId ] = [];
13155		$.tcepo.errorObject[ epoEventId ] = false;
13156		$.tcepo.initialActivation[ epoEventId ] = false;
13157
13158		if ( main_cart.find( tcAPI.epoSelector ).length > 0 ) {
13159			main_epo_inside_form = true;
13160		}
13161		if ( main_cart.find( '.tc-totals-form' ).length > 0 ) {
13162			main_totals_inside_form = true;
13163		}
13164
13165		if ( ! main_totals_inside_form ) {
13166			$.tcepo.formSubmitEvents[ epoEventId ][ $.tcepo.formSubmitEvents[ epoEventId ].length ] = {
13167				trigger: function() {
13168					return true;
13169				},
13170				on_true: function() {
13171					// hidden fields see totals.php
13172					var epos_hidden = $( '.tc-totals-form.tm-product-id-' + product_id + "[data-epo-id='" + epo_id + "']" ).tcClone();
13173					var formepo = $( '<div class="tm-hidden tm-formepo-normal"></div>' );
13174
13175					main_cart.find( '.tm-formepo-normal' ).remove();
13176					formepo.append( epos_hidden );
13177					main_cart.append( formepo );
13178					return true;
13179				},
13180				on_false: function() {
13181					setTimeout( function() {
13182						$( '.tm-formepo-normal' ).remove();
13183					}, 100 );
13184				}
13185			};
13186		}
13187		if ( ! main_epo_inside_form ) {
13188			$.tcepo.formSubmitEvents[ epoEventId ][ $.tcepo.formSubmitEvents[ epoEventId ].length ] = {
13189				trigger: function() {
13190					return true;
13191				},
13192				on_true: function() {
13193					// visible fields
13194					var epos = $( tcAPI.epoSelector + '.tm-product-id-' + product_id + "[data-epo-id='" + epo_id + "']" )
13195						.tcClone()
13196						.addClass( 'formepo' );
13197					var formepo = $( '<div class="tm-hidden tm-formepo"></div>' );
13198
13199					main_cart.find( '.tm-formepo' ).remove();
13200					formepo.append( epos );
13201
13202					main_cart.append( formepo );
13203					return true;
13204				},
13205				on_false: function() {
13206					setTimeout( function() {
13207						$( '.tm-formepo' ).remove();
13208					}, 100 );
13209				}
13210			};
13211		}
13212
13213		epo_object = {
13214			main_product: main_product,
13215			main_cart: main_cart,
13216			epo_id: epo_id,
13217			form: get_main_form( main_product ),
13218			main_epo_inside_form: main_epo_inside_form,
13219			product_id_selector: product_id_selector,
13220			epo_id_selector: epo_id_selector,
13221			product_id: product_id,
13222			this_epo_container: this_epo_container,
13223			this_totals_container: this_totals_container,
13224			this_epo_totals_container: this_epo_totals_container,
13225			qtySelector: tcAPI.qtySelector,
13226			manualInitEPO: manualInitEPO,
13227			epoEventId: epoEventId,
13228			variations_form: variations_form,
13229			has_epo: has_epo,
13230			is_quickview: is_quickview,
13231			is_associated: is_associated,
13232			is_epo_shortcode: this_epo_container.is( '.tc-shortcode' ),
13233			mainEpoObject: mainEpoObject,
13234			associated_connect: associated_connect,
13235			noEpoUpdate: true
13236		};
13237
13238		$( epo_object.form ).data( 'epo_object', epo_object );
13239		this_epo_container.data( 'epo_object', epo_object );
13240
13241		main_cart.data( 'product_id', product_id ).data( 'epo_id', epo_id ).data( 'product_id_selector', product_id_selector ).data( 'epo_id_selector', epo_id_selector );
13242
13243		// tm_set_expanables();
13244		tm_set_checkboxes_rules( epo_object );
13245		tm_set_upload_rules( epo_object );
13246		tm_set_datepicker( this_epo_container );
13247		setRangePickers( this_epo_container );
13248		setRangePickersEvents();
13249		tm_set_repeaters( this_epo_container, epo_object );
13250		tm_set_url_fields();
13251
13252		$.tcToolTip( this_epo_container.find( '.tm-tooltip' ) );
13253
13254		this_epo_container.find( '.tm-collapse' ).tmtoggle();
13255		this_epo_container.find( '.tm-section-link' ).tmsectionpoplink();
13256
13257		if ( reactivate ) {
13258			this_epo_container.addClass( 'reactivate' );
13259		}
13260
13261		if ( variations_form.length > 0 ) {
13262			if ( reactivate ) {
13263				variations_form.data( 'epo_loaded', false );
13264			}
13265			this_epo_totals_container.data( 'price', false );
13266			if ( detect_variation_swatches ) {
13267				detect_variation_swatches_interval( epo_object );
13268			} else {
13269				run_wc_variation_form_cpf( epo_object );
13270			}
13271		} else {
13272			setTimeout( function() {
13273				// Start Condition Logic
13274				cpf_section_logic( epo_object );
13275				cpf_element_logic( epo_object );
13276
13277				jWindow.on( 'epoEventHandlers', function() {
13278					run_cpfdependson( this_epo_container );
13279					tm_lazyload();
13280				} );
13281
13282				// Init field price rules
13283				$.tcepo.lateFieldsPrices[ epoEventId ] = [];
13284				epoEventHandlers( epo_object );
13285				tm_set_upload_fields( epo_object );
13286				tm_product_image( epo_object );
13287
13288				jWindow.trigger( 'epo-after-init-in-timeout', { epo: epo_object } );
13289				main_cart.trigger( 'tm-epo-check-dpd' );
13290				epo_object.noEpoUpdate = false;
13291				main_cart.trigger( {
13292					type: 'tm-epo-update',
13293					rules: 'init'
13294				} );
13295			}, 20 );
13296			jWindow.trigger( 'epo-after-init', { epo: epo_object } );
13297		}
13298
13299		tm_css_styles( this_epo_container );
13300		tm_set_color_pickers( this_epo_container );
13301		tm_set_lightbox( this_epo_container.find( '.tc-lightbox-image' ).not( '.tm-extra-product-options-variations .radio-image' ) );
13302		tm_theme_specific_actions( epo_object );
13303		tc_compatibility( epo_object );
13304
13305		if ( ! is_associated ) {
13306			tm_floating_totals( this_epo_totals_container, is_quickview, main_cart );
13307			tm_form_submit_event( epo_object );
13308			epo_object = addShowHidetoEpoObject( epo_object, epoEventId, epo_object );
13309			tm_show_hide_add_to_cart_button( main_product, epo_object );
13310		}
13311
13312		jWindow.trigger( 'tm-epo-init-end', {
13313			epo: epo_object,
13314			replace_suffixes_in_html: replace_suffixes_in_html
13315		} );
13316
13317		return epo_object;
13318	}
13319
13320	function manual_init( container, reactivate ) {
13321		var $this = $( container );
13322		var product_id = $this.attr( 'data-product-id' );
13323		var epo_id = $this.attr( 'data-epo-id' );
13324		var quickview_floating = false;
13325		var testForm = $this.parent();
13326		if ( ! testForm.is( 'form' ) ) {
13327			testForm = $this.closest( 'form' );
13328			if ( ! testForm.is( 'form' ) ) {
13329				testForm = $this.parent();
13330			}
13331		}
13332		testForm = testForm.parent();
13333
13334		tm_init_epo( testForm, quickview_floating, product_id, epo_id, undefined, undefined, reactivate );
13335	}
13336
13337	function init_epo_plugin() {
13338		var epo_container;
13339		var epo_options_container;
13340
13341		if ( TMEPOJS.tm_epo_no_lazy_load === 'no' ) {
13342			$.extend( $.lazyLoadXT, {
13343				autoInit: false,
13344				selector: 'img.tmlazy',
13345				srcAttr: 'data-original',
13346				visibleOnly: false,
13347				updateEvent: $.lazyLoadXT.updateEvent + ' tmlazy'
13348			} );
13349		}
13350		/*
13351		 * tm-no-options-pxq = product has not options but the "Enable Final total box for all products" is on
13352		 * tm-no-options-composite = product is a composite product with no options but at least one of its bundles have options
13353		 */
13354		epo_container = $( '.tm-no-options-pxq, .tm-no-options-composite' );
13355
13356		if ( epo_container.length > 0 ) {
13357			// Special cases
13358			// -------------
13359			// Price x Quantity display (.tm-no-options-pxq) & composite
13360			// without option but a component has extra options
13361			// (.tm-no-options-composite)
13362
13363			epo_container.addClass( 'initializing' );
13364
13365			epo_container.toArray().forEach( function( product_wrap ) {
13366				var inputepoid;
13367				product_wrap = $( product_wrap );
13368				inputepoid = product_wrap.find( 'input.tm-epo-counter' );
13369				if ( inputepoid.length > 1 ) {
13370					inputepoid.toArray().forEach( function( ec ) {
13371						var currentepoid = $( ec );
13372						var currentcart = currentepoid.closest( '.cart' );
13373						var currentcartparent = currentcart.parent();
13374						if ( currentcartparent.is( 'form' ) ) {
13375							currentcartparent = currentcartparent.parent();
13376						}
13377
13378						if ( ! currentcartparent.is( '.initializing' ) ) {
13379							tm_init_epo( currentcartparent, false, undefined, parseInt( currentepoid.val(), 10 ) );
13380						}
13381					} );
13382				} else {
13383					tm_init_epo( product_wrap, false );
13384				}
13385				epo_container.removeClass( 'initializing' );
13386			} );
13387		}
13388
13389		// The setTimeout is used for compatibility with
13390		// skeleton screen mode that some themes have
13391
13392		setTimeout( function() {
13393			try {
13394				// new main way of calling tm_init_epo
13395				// -----------------------------------
13396				// Normal product pages
13397
13398				epo_options_container = $( tcAPI.epoSelector ).not( tcAPI.associatedEpoSelector + ' ' + tcAPI.epoSelector + ', .tm-no-options-pxq, .tm-no-options-composite, .wc-product-table ' + tcAPI.epoSelector );
13399
13400				if ( epo_options_container.length > 0 ) {
13401					epo_container.addClass( 'initializing' );
13402					epo_options_container.toArray().forEach( function( ec ) {
13403						var $this = $( ec );
13404						var product_id = $this.attr( 'data-product-id' );
13405						var epo_id = $this.attr( 'data-epo-id' );
13406						var quickview_floating = false;
13407						var jProductWrap;
13408						var addInputs = false;
13409						var inputepoid;
13410
13411						// First check if we are in a loop.
13412						jProductWrap = $this.closest( '.tc-after-shop-loop.tm-has-options' );
13413
13414						if ( jProductWrap.length === 0 ) {
13415							// Check based on plugin add to cart selector.
13416							jProductWrap = $( tcAPI.tcAddToCartSelector + "[data-epo-id='" + epo_id + "'][value='" + product_id + "']" )
13417								.closest( 'form,.cart' )
13418								.first()
13419								.parent();
13420							// Check based on native add to cart selector.
13421							if ( jProductWrap.length === 0 ) {
13422								jProductWrap = $( tcAPI.addToCartSelector + "[value='" + product_id + "']" )
13423									.closest( 'form,.cart' )
13424									.first()
13425									.parent();
13426								if ( jProductWrap.length === 0 ) {
13427									// Check if we are in a shortcode
13428									jProductWrap = $this.closest( 'form,.cart' ).first().parent( '.tm-has-options' );
13429									if ( jProductWrap.length === 0 ) {
13430										if ( $this.is( '.tc-shortcode' ) ) {
13431											jProductWrap = $this.wrap( '<div class="tc-shortcode-wrap tc-wrap-' + epo_id + '"></div>' );
13432											jProductWrap = $this.parent();
13433										}
13434										if ( jProductWrap.length > 0 ) {
13435											addInputs = true;
13436										}
13437									}
13438								}
13439							}
13440						} else {
13441							addInputs = true;
13442						}
13443
13444						if ( jProductWrap.length > 0 ) {
13445							if ( addInputs ) {
13446								// in shop (variation logic will not work here)
13447								quickview_floating = true;
13448								$this
13449									.closest( 'form,.cart' )
13450									.first()
13451									.append( $( '<input name="add-to-cart" value="' + product_id + '" type="hidden">' ) );
13452								$this.closest( 'form,.cart' ).first().append( $( '<input type="hidden" value="" class="variation_id" name="variation_id">' ) );
13453							}
13454
13455							if ( jProductWrap.is( 'form' ) ) {
13456								jProductWrap = jProductWrap.parent();
13457							}
13458
13459							inputepoid = jProductWrap.find( 'input.tm-epo-counter' );
13460							if ( inputepoid.length > 1 ) {
13461								inputepoid.toArray().forEach( function( c ) {
13462									var currentepoid = $( c );
13463									var currentcart = currentepoid.closest( '.cart' );
13464									var currentcartparent = currentcart.parent();
13465									if ( currentcartparent.is( 'form' ) ) {
13466										currentcartparent = currentcartparent.parent();
13467									}
13468
13469									if ( ! currentcartparent.is( '.initializing' ) ) {
13470										tm_init_epo( currentcartparent, quickview_floating, product_id, parseInt( currentepoid.val(), 10 ) );
13471									}
13472								} );
13473							} else {
13474								tm_init_epo( jProductWrap, quickview_floating, product_id, epo_id );
13475							}
13476						}
13477					} );
13478					epo_container.removeClass( 'initializing' );
13479				}
13480			} catch ( err ) {
13481				window.console.log( err );
13482				errorObject = err;
13483			}
13484		}, 1 );
13485	}
13486
13487	$.tcepo.tm_init_epo = function( main_product, is_quickview, product_id, epo_id ) {
13488		tm_init_epo( main_product, is_quickview, product_id, epo_id );
13489	};
13490
13491	$.tcepo.tmLazyloadContainer = function( container ) {
13492		tmLazyloadContainer = container;
13493	};
13494
13495	jWindow.on( 'tc_manual_init', function( evt, container ) {
13496		var reactivate;
13497		if ( 'container' in container && 'reactivate' in container ) {
13498			reactivate = container.reactivate;
13499			container = container.container;
13500		}
13501		manual_init( container, reactivate );
13502	} );
13503
13504	function tcAjaxAddToCart( $this ) {
13505		var _pid;
13506		var epos;
13507		var _cpf_product_price;
13508		var _dynamic_product_price;
13509		var _override_product_price;
13510		var form_prefix;
13511		var epoid;
13512		var obj;
13513		var data;
13514		var tcTotalsForm;
13515
13516		currentAjaxButton = $this;
13517		_pid = currentAjaxButton.attr( 'data-product_id' );
13518		if ( undefined === _pid ) {
13519			_pid = currentAjaxButton.val();
13520		}
13521
13522		if ( undefined !== _pid ) {
13523			epoid = currentAjaxButton.closest( '.cart' ).find( '.tm-epo-counter' ).val();
13524			if ( ! epoid ) {
13525				epoid = currentAjaxButton.attr( 'data-epo-id' );
13526				if ( ! epoid ) {
13527					return;
13528				}
13529			}
13530			if ( currentAjaxButton.closest( '.tm-has-options' ).length !== 1 && currentAjaxButton.attr( 'data-epo-id' ) === undefined ) {
13531				return;
13532			}
13533
13534			obj = {};
13535
13536			epos = $( tcAPI.epoSelector + '.tm-product-id-' + _pid + '[data-epo-id="' + epoid + '"]' );
13537
13538			if ( epos.length > 1 ) {
13539				if ( epos.filter( '.formepo' ) ) {
13540					epos = epos.filter( '.formepo' );
13541				} else {
13542					epos = epos.first();
13543				}
13544			}
13545
13546			if ( epos.length === 1 ) {
13547				tcTotalsForm = $( '.tc-totals-form.tm-product-id-' + _pid + '[data-epo-id="' + epoid + '"]' );
13548				_cpf_product_price = tcTotalsForm.find( '.cpf-product-price' ).val();
13549				_dynamic_product_price = tcTotalsForm.find( '.cpf-dynamic-product-price' ).val();
13550				_override_product_price = tcTotalsForm.find( '.cpf-override-product-price' ).val();
13551				form_prefix = tcTotalsForm.find( '.tc_form_prefix' ).val();
13552
13553				obj = $.extend( obj, {
13554					tcajax: 1,
13555					tcaddtocart: _pid,
13556					cpf_product_price: _cpf_product_price,
13557					dynamic_product_price: _dynamic_product_price,
13558					override_product_price: _override_product_price
13559				} );
13560				if ( form_prefix ) {
13561					obj.tc_form_prefix = form_prefix;
13562				}
13563			}
13564
13565			data = currentAjaxButton.data();
13566			TMEPOJS.ajaxbuttondata = $.epoAPI.util.deepCopyArray( data );
13567			TMEPOJS.ajaxbutton = currentAjaxButton;
13568
13569			currentAjaxButton.removeData();
13570			currentAjaxButton.data( $.extend( data, epos.tcSerializeObject(), obj ) );
13571
13572			TMEPOJS.ajaxdata = {
13573				epos: epos,
13574				_pid: _pid,
13575				data: data
13576			};
13577		}
13578	}
13579
13580	function ajaxAddToCartFunctions() {
13581		// Betheme ajax add to cart.
13582		$( document ).on( 'click.tcajax', 'body.mfn-ajax-add-to-cart .single_add_to_cart_button:not(.disabled)', function() {
13583			var formepo;
13584			var $this = $( this );
13585			tcAjaxAddToCart( $this );
13586			TMEPOJS.ajaxdata.cart = $this.closest( '.cart' );
13587			TMEPOJS.ajaxdata.cart.find( '.tm-formepo' ).remove();
13588			formepo = $( "<div class='tm-hidden tm-formepo'></div>" );
13589			formepo.append( TMEPOJS.ajaxdata.epos.tcClone().addClass( 'formepo' ) );
13590			$this.after( formepo );
13591		} );
13592
13593		jBody.on( 'click.tcajax', '.ajax_add_to_cart', function() {
13594			tcAjaxAddToCart( $( this ) );
13595			if ( undefined !== TMEPOJS.ajaxdata ) {
13596				delete TMEPOJS.ajaxdata;
13597			}
13598		} );
13599
13600		jBody.on( 'click.tcajax', '.single_add_to_cart_button', function() {
13601			currentAddToCartButton = $( this );
13602		} );
13603
13604		$( document.body ).on( 'added_to_cart', function() {
13605			if ( TMEPOJS.ajaxbuttondata && TMEPOJS.ajaxbutton instanceof $ ) {
13606				TMEPOJS.ajaxbutton.removeData();
13607				TMEPOJS.ajaxbutton.data( TMEPOJS.ajaxbuttondata );
13608			}
13609		} );
13610	}
13611
13612	// This needs to run here to register our event handlers before WooCommerce.
13613	ajaxAddToCartFunctions();
13614
13615	// document ready
13616	$( function() {
13617		tcAPI = $.epoAPI.applyFilter( 'tc_api', tcAPI );
13618
13619		jWindow.on( 'lazyLoadXToncomplete', function() {
13620			$( '.tm-owl-slider' ).toArray().forEach( function( slider ) {
13621				$( slider ).trigger( 'refresh.owl.carousel' );
13622			} );
13623		} );
13624
13625		jWindow.on( 'tc_init_epo_plugin', function( evt ) {
13626			init_epo_plugin( evt );
13627		} );
13628
13629		jWindow.on( 'tcShowLastError', function() {
13630			window.console.log( errorObject );
13631		} );
13632
13633		$.ajaxPrefilter( function( options, originalOptions ) {
13634			var found = false;
13635			var hashes;
13636			var hash;
13637			var i;
13638			var params;
13639			var $thisbutton;
13640			var _data;
13641			var _urldata;
13642			var _pid;
13643			var epos;
13644			var _cpf_product_price;
13645			var _dynamic_product_price;
13646			var _override_product_price;
13647			var form_prefix;
13648			var obj;
13649			var oldData;
13650			var formData;
13651			var can_be_added = false;
13652			var associativeArray = {};
13653			var tcTotalsForm;
13654
13655			if ( TMEPOJS.tm_epo_enable_in_shop === 'yes' ) {
13656				hashes = options.url.split( '?' );
13657
13658				if ( hashes && hashes.length >= 1 ) {
13659					hashes = hashes[ 1 ];
13660					if ( hashes ) {
13661						hash = hashes.split( '&' );
13662						for ( i = 0; i < hash.length; i += 1 ) {
13663							params = hash[ i ].split( '=' );
13664							if ( params.length >= 1 ) {
13665								if ( params[ 0 ] && params[ 1 ] && params[ 0 ] === 'wc-ajax' && params[ 1 ] === 'add_to_cart' ) {
13666									found = true;
13667								}
13668							}
13669						}
13670						if ( found ) {
13671							options.originalsuccess = options.success;
13672							options.success = function( response ) {
13673								if ( response && response.error && response.product_url ) {
13674									if ( currentAjaxButton && currentAjaxButton.length === 1 ) {
13675										$thisbutton = currentAjaxButton;
13676									}
13677									$thisbutton = $( ".ajax_add_to_cart[data-product_id='" + originalOptions.data.product_id + "']" );
13678									$thisbutton.removeClass( 'added' );
13679									$thisbutton.removeClass( 'loading' );
13680								} else {
13681									options.originalsuccess.call( null, response );
13682								}
13683							};
13684						}
13685					}
13686				}
13687			}
13688
13689			if ( FormData && originalOptions.data ) {
13690				_data = originalOptions.data;
13691				if ( typeof originalOptions.data === 'string' ) {
13692					_data = $.epoAPI.util.parseParams( originalOptions.data );
13693				}
13694				if ( typeof _data[ 0 ] === 'object' ) {
13695					_data.forEach( function( item ) {
13696						associativeArray[ item.name ] = item.value;
13697					} );
13698					_data = associativeArray;
13699				}
13700
13701				_urldata = [];
13702				if ( originalOptions.url && originalOptions.url.indexOf ) {
13703					_urldata = $.epoAPI.util.parseParams( originalOptions.url.slice( originalOptions.url.indexOf( '?' ) + 1 ) );
13704				}
13705
13706				if ( 'quantity' in _data && _data.tcaddtocart && ( _data.product_id || _data[ 'add-to-cart' ] || _urldata.product_id || _urldata[ 'add-to-cart' ] ) ) {
13707					can_be_added = true;
13708					_pid = _data.tcaddtocart;
13709				} else if ( Array.isArray( _data ) ) {
13710					can_be_added = _data.some( function( item ) {
13711						return item.name === 'quantity';
13712					} ) && _data.some( function( item ) {
13713						return item.name === 'add-to-cart';
13714					} ) && _data.some( function( item ) {
13715						return item.name === 'tcaddtocart';
13716					} );
13717					_pid = _data.find( function( item ) {
13718						return item.name === 'tcaddtocart';
13719					} );
13720					if ( _pid ) {
13721						_pid = _pid.value;
13722					} else {
13723						_pid = false;
13724					}
13725				}
13726
13727				if ( ! _pid ) {
13728					if ( 'qty' in _data && _data.tcaddtocart ) {
13729						can_be_added = true;
13730						_pid = _data.tcaddtocart;
13731					}
13732				}
13733
13734				if ( can_be_added ) {
13735					if ( currentAjaxButton && currentAjaxButton.length === 1 && currentAjaxButton.closest( '.tm-has-options' ).length === 1 ) {
13736						epos = currentAjaxButton.closest( '.tm-has-options' ).find( tcAPI.epoSelector + '.tm-product-id-' + _pid );
13737					} else {
13738						epos = $( tcAPI.epoSelector + '.tm-product-id-' + _pid );
13739					}
13740
13741					if ( epos.length > 1 ) {
13742						if ( epos.filter( '.formepo' ) ) {
13743							epos = epos.filter( '.formepo' );
13744						} else {
13745							epos = epos.first();
13746						}
13747					}
13748					if ( epos.length === 1 ) {
13749						tcTotalsForm = $( '.tc-totals-form.tm-product-id-' + _pid );
13750						_cpf_product_price = tcTotalsForm.find( '.cpf-product-price' ).val();
13751						_dynamic_product_price = tcTotalsForm.find( '.cpf-dynamic-product-price' ).val();
13752						_override_product_price = tcTotalsForm.find( '.cpf-override-product-price' ).val();
13753						form_prefix = tcTotalsForm.find( '.tc_form_prefix' ).val();
13754						obj = {
13755							tcajax: 1,
13756							tcaddtocart: _pid,
13757							cpf_product_price: _cpf_product_price,
13758							dynamic_product_price: _dynamic_product_price,
13759							override_product_price: _override_product_price
13760						};
13761						if ( form_prefix ) {
13762							obj.tc_form_prefix = form_prefix;
13763						}
13764
13765						oldData = $.epoAPI.util.parseParams( options.data, true );
13766						oldData = $.extend( oldData, epos.tcSerializeObject(), obj );
13767						formData = new FormData();
13768
13769						Object.keys( oldData ).forEach( function( key ) {
13770							if ( key ) {
13771								formData.append( key, oldData[ key ] );
13772							}
13773						} );
13774
13775						epos.find( ':file' )
13776							.toArray()
13777							.forEach( function( el ) {
13778								for ( i = 0; i < $( el )[ 0 ].files.length; i++ ) {
13779									if ( ! el.multiple ) {
13780										formData.delete( $( el ).attr( 'name' ) );
13781									}
13782									formData.append( $( el ).attr( 'name' ), $( el )[ 0 ].files[ i ] );
13783								}
13784							} );
13785
13786						options.data = formData;
13787						options.contentType = false;
13788						options.cache = false;
13789						options.processData = false;
13790					}
13791				}
13792			}
13793		} );
13794
13795		jDocument.ajaxSuccess( function( event, request, settings ) {
13796			// quickview plugins
13797			var qv_container = TMEPOJS.quickview_array || 'null';
13798			var fromaddons = TMEPOJS.quickview_container || 'null';
13799			var added = {};
13800			var selectors;
13801			var container;
13802			var product_id;
13803			var epo_id;
13804			var noProductCheck;
13805			var testContainer;
13806			var parsedUrl;
13807			var time = 1;
13808			var detectContainer;
13809			var requestContainer;
13810
13811			if ( undefined !== TMEPOJS.ajaxdata ) {
13812				TMEPOJS.ajaxdata.cart.find( '.tm-formepo' ).remove();
13813				delete TMEPOJS.ajaxdata;
13814			}
13815
13816			parsedUrl = $.epoAPI.util.parseParams( settings.data );
13817			if ( parsedUrl.action === 'wc_epo_get_associated_product_html' ) {
13818				return;
13819			}
13820
13821			$( '.tm-formepo-normal' ).remove();
13822			$( '.tm-formepo' ).remove();
13823
13824			//fix for menu cart pop up
13825			$( '.tm-cart-link' ).tmpoplink();
13826
13827			qv_container = $.epoAPI.util.parseJSON( qv_container );
13828
13829			fromaddons = $.epoAPI.util.parseJSON( fromaddons );
13830
13831			for ( selectors in fromaddons ) {
13832				if ( Object.prototype.hasOwnProperty.call( fromaddons, selectors ) ) {
13833					added[ fromaddons[ selectors ][ 0 ] ] = $( fromaddons[ selectors ][ 1 ] );
13834				}
13835			}
13836
13837			$.extend( qv_container, added );
13838
13839			detectContainer = function() {
13840				var keyfound = false;
13841				Object.keys( qv_container ).forEach( function( key ) {
13842					if ( $( qv_container[ key ] ).length ) {
13843						keyfound = key;
13844					}
13845				} );
13846				return keyfound;
13847			};
13848			requestContainer = function( times ) {
13849				var id = requestAnimationFrame( function() {
13850					setTimeout( function() {
13851						requestContainer( times - 1 );
13852					}, 200 );
13853				} );
13854				var key = detectContainer();
13855				var epoContainer;
13856				var initepo;
13857
13858				if ( key || 0 === times ) {
13859					cancelAnimationFrame( id );
13860					if ( key ) {
13861						noProductCheck = false;
13862						container = $( qv_container[ key ] );
13863						if ( container.length > 1 && currentAddToCartButton && currentAddToCartButton.length ) {
13864							container = currentAddToCartButton.closest( qv_container[ key ] );
13865						}
13866						if ( container.length > 1 && key !== 'quickview_pro' ) {
13867							return true;
13868						}
13869
13870						if ( key === 'woothemes_quick_view' && container.is( '.fusion-woocommerce-quick-view-container' ) ) {
13871							return true;
13872						}
13873
13874						if ( key === 'fusion_quick_view_load' && container.find( tcAPI.epoSelector ).length === 0 ) {
13875							return true;
13876						}
13877
13878						if ( key === 'woodmart_quick_shop' ) {
13879							parsedUrl = $.epoAPI.util.parseParams( settings.url );
13880							if ( parsedUrl.action === 'woodmart_quick_shop' ) {
13881								testContainer = $( $.epoAPI.util.escapeSelector( qv_container[ key ] + '.post-' + parsedUrl.id ) );
13882								if ( testContainer.length ) {
13883									container = testContainer;
13884									noProductCheck = true;
13885								}
13886							}
13887						}
13888						if ( key === 'woodmart_quick_view' ) {
13889							parsedUrl = $.epoAPI.util.parseParams( settings.url );
13890							if ( parsedUrl.action === 'woodmart_quick_view' ) {
13891								testContainer = $( $.epoAPI.util.escapeSelector( qv_container[ key ] + '.post-' + parsedUrl.id ) );
13892								if ( testContainer.length ) {
13893									container = testContainer;
13894									noProductCheck = true;
13895								}
13896							}
13897						}
13898
13899						if ( key === 'quickview_pro' ) {
13900							parsedUrl = settings.url.split( '/' );
13901							if ( parsedUrl.length ) {
13902								testContainer = $( $.epoAPI.util.escapeSelector( qv_container[ key ] + ' .post-' + parsedUrl[ parsedUrl.length - 1 ] ) );
13903								if ( testContainer.length ) {
13904									container = testContainer;
13905									noProductCheck = true;
13906								}
13907							}
13908						}
13909
13910						if ( key === 'exwoofood_booking_info' || key === 'wqv_popup_content' || key === 'wp_food' || key === 'jet_popup_get_content' ) {
13911							noProductCheck = true;
13912						}
13913
13914						if ( key === 'woofood' && settings.data ) {
13915							parsedUrl = $.epoAPI.util.parseParams( settings.data );
13916							if ( parsedUrl.action === 'woofood_quickview_ajax' ) {
13917								testContainer = testContainer = container.find( 'form' ).parent();
13918								if ( testContainer.length ) {
13919									container = testContainer;
13920									noProductCheck = true;
13921								}
13922							}
13923						}
13924
13925						if ( container.find( '.product' ).length === 0 && container.is( '.product' ) ) {
13926							noProductCheck = true;
13927						}
13928
13929						if ( ( container.find( '.product' ).length > 0 || noProductCheck ) ) {
13930							container.removeClass( 'tc-init' );
13931
13932							if (
13933								key === 'fusion_quick_view_load' ||
13934								key === 'jet_popup_get_content' ||
13935								key === 'wp_food' ||
13936								key === 'woodmart_quick_shop' ||
13937								key === 'woodmart_quick_view' ||
13938								key === 'lightboxpro' ||
13939								key === 'jckqv_quick_view' ||
13940								key === 'yith_quick_view' ||
13941								key === 'theme_flatsome_quick_view'
13942							) {
13943								variationsFormIsLoaded = true;
13944							}
13945							tmLazyloadContainer = container;
13946							if ( tmLazyloadContainer.length > 1 ) {
13947								while ( tmLazyloadContainer.length > 1 ) {
13948									tmLazyloadContainer = tmLazyloadContainer.filter( function() {
13949										return $( this ).find( tcAPI.epoSelector ).length > 0;
13950									} );
13951									if ( tmLazyloadContainer.length === 0 ) {
13952										break;
13953									}
13954								}
13955								if ( tmLazyloadContainer.length === 0 ) {
13956									setTimeout( function() {
13957										requestContainer( 10 );
13958									}, 1000 );
13959
13960									return true;
13961								}
13962							}
13963
13964							epoContainer = tmLazyloadContainer.find( tcAPI.epoSelector );
13965							if ( epoContainer.length === 0 ) {
13966								delete qv_container[ key ];
13967								requestContainer( 10 );
13968								return true;
13969							}
13970
13971							if ( key === 'fusion_quick_view_load' ) {
13972								time = 1400;
13973							}
13974
13975							initepo = function( redo ) {
13976								setTimeout( function() {
13977									product_id = epoContainer.attr( 'data-product-id' );
13978									epo_id = epoContainer.attr( 'data-epo-id' );
13979									if ( key === 'woodmart_quick_shop' ) {
13980										container.addClass( 'has-options' );
13981									}
13982
13983									// Reset element cache
13984									tcAPI.getElementFromFieldCache = [];
13985									tm_init_epo( tmLazyloadContainer, true, product_id, epo_id, undefined, undefined, redo );
13986									jWindow.trigger( 'tmlazy' );
13987									jWindow.trigger( 'tm_epo_loaded_quickview' );
13988									if ( $.jMaskGlobals ) {
13989										tmLazyloadContainer.find( $.jMaskGlobals.maskElements ).toArray().forEach( function( t ) {
13990											t = $( t );
13991
13992											if ( t.attr( 'data-mask' ) ) {
13993												t.mask( t.attr( 'data-mask' ) );
13994											}
13995										} );
13996									}
13997								}, time );
13998							};
13999
14000							initepo();
14001
14002							if ( key === 'minimog_product_quick_view' ) {
14003								$( '.minimog-product' ).on( 'click', '.quick-view-btn', function( evt ) {
14004									var $button = $( this );
14005									var productID = $button.data( 'pid' );
14006									var $template = jBody.children( '#' + 'modal-quick-view-product-' + productID );
14007									evt.preventDefault();
14008									evt.stopPropagation();
14009									if ( $button.hasClass( 'loading' ) ) {
14010										return;
14011									}
14012									if ( ! $.fn.MinimogModal ) {
14013										return;
14014									}
14015									if ( $template.length > 0 ) {
14016										tmLazyloadContainer = $( '.modal-quick-view-popup' );
14017										initepo( true );
14018									}
14019								} );
14020							}
14021						}
14022					}
14023				}
14024			};
14025			requestContainer( 10 );
14026		} );
14027
14028		init_epo_plugin();
14029
14030		$( '.tm-cart-link' ).tmpoplink();
14031		jBody.on( 'updated_checkout wc_fragments_loaded wc_fragments_refreshed wc_fragment_refresh', function() {
14032			$( '.tm-cart-link' ).tmpoplink();
14033		} );
14034
14035		jWindow.trigger( 'tmlazy' );
14036
14037		jWindow.trigger( 'tm_epo_loaded' );
14038	} );
14039
14040	function associated_table_item() {
14041		$( '.tc-associated-table-product td.product-name' ).toArray().forEach( function( el ) {
14042			el = $( el );
14043			if ( el.find( '.product-name' ).length === 0 ) {
14044				el.wrapInner( $( '<div class="tc-associated-table-product-indent"></div>' ) );
14045			}
14046		} );
14047	}
14048
14049	// Associated product cart indent
14050	jBody.on( 'updated_checkout updated_cart_totals', function() {
14051		associated_table_item();
14052	} );
14053
14054	associated_table_item();
14055
14056	// document ready
14057	$( function() {
14058		// Remove accept attribute from upload buttons when in Facebook or Instagram internral browser
14059		var ua = navigator.userAgent || navigator.vendor || window.opera;
14060		ua = ( ua.indexOf( 'FBAN' ) > -1 ) || ( ua.indexOf( 'FBAV' ) > -1 ) || ( ua.indexOf( 'Instagram' ) > -1 );
14061		if ( ua ) {
14062			$( '.tmcp-upload' ).removeAttr( 'accept' );
14063		}
14064
14065		// Fix several custom quantity buttons on themes
14066		jDocument.on( 'click', '.quantity .jckqv-qty-spinner, .quantity .ui-spinner-button', function() {
14067			$( this ).closest( '.quantity' ).find( tcAPI.qtySelector ).trigger( 'change' );
14068		} );
14069
14070		// Quantity selector buttons
14071		$( document ).on( 'click', '.tm-quantity .tc-qty-button, .tm-quantity-alt .tc-qty-button', function() {
14072			var qty = $( this ).closest( '.tm-quantity, .tm-quantity-alt' ).find( '.tm-qty, .tm-qty-alt' );
14073			var val = parseFloat( qty.val() );
14074			var max = parseFloat( qty.attr( 'max' ) );
14075			var min = parseFloat( qty.attr( 'min' ) );
14076			var step = parseFloat( qty.attr( 'step' ) );
14077			if ( isNaN( step ) ) {
14078				step = 1;
14079			}
14080
14081			// Change the value if plus or minus
14082			if ( $( this ).is( '.plus' ) ) {
14083				if ( ! isNaN( max ) && ( max <= val ) ) {
14084					qty.val( max );
14085				} else {
14086					qty.val( val + step );
14087				}
14088			} else if ( ! isNaN( min ) && ( min >= val ) ) {
14089				qty.val( min );
14090			} else if ( val > 0 ) {
14091				qty.val( val - step );
14092			}
14093
14094			$( this ).closest( '.tm-quantity, .tm-quantity-alt' ).find( 'input.tm-qty, input.tm-qty-alt' ).trigger( 'change' );
14095		} );
14096
14097		// bulk variations forms plugin
14098		$( '#wholesale_form' ).on( 'submit', function() {
14099			var _product_id = $( 'form.cart' ).find( tcAPI.addToCartSelector ).val();
14100			// visible fields
14101			var epos = $( tcAPI.epoSelector + ".tm-cart-main[data-product-id='" + _product_id + "']" ).tcClone();
14102			// hidden fields see totals.php
14103			var epos_hidden = $( ".tm-totals-form-main[data-product-id='" + _product_id + "']" ).tcClone();
14104			var formepo = $( "<div class='tm-hidden tm-formepo'></div>" );
14105
14106			formepo.append( epos );
14107			formepo.append( epos_hidden );
14108			$( this ).append( formepo );
14109			return true;
14110		} );
14111
14112		// Disable quote button if option validation fails
14113		jDocument.on( 'click', '#add_to_quote', function( e ) {
14114			var form;
14115			var epo_id;
14116			var epos;
14117
14118			if ( TMEPOJS && TMEPOJS.tm_epo_global_enable_validation === 'yes' ) {
14119				form = $( this ).parents( 'form' );
14120				epo_id = parseInt( form.find( '.tm-epo-counter' ).val(), 10 );
14121				epos = $( tcAPI.epoSelector + "[data-epo-id='" + epo_id + "']" );
14122
14123				// not validated
14124				if ( TMEPOJS.tm_epo_global_enable_validation === 'yes' && $.tc_validator && form.length > 0 && epos.length > 0 && ! form.tc_validate().form() ) {
14125					e.stopImmediatePropagation();
14126				}
14127			}
14128		} );
14129
14130		// PayPal for WooCommerce (PayPal Express Checkout button fix)
14131		$( '.single_add_to_cart_button.paypal_checkout_button' ).on( 'click', function( event ) {
14132			// this is the selector used by the paypal checkout plugin
14133			var form = $( '.cart' );
14134			var validator;
14135
14136			if ( form.data( 'tc_validator' ) ) {
14137				validator = form.data( 'tc_validator' );
14138				if ( validator.errorList ) {
14139					event.stopImmediatePropagation();
14140				}
14141			}
14142		} );
14143
14144		$( '.wc-product-table' ).on( 'init.wcpt', function( event, table ) {
14145			table.$table.find( tcAPI.epoSelector ).addClass( 'hidden' );
14146			table.$table.find( 'thead tr' ).append( '<th>&nbsp;</th>' );
14147			setTimeout( function() {
14148				table.$table.find( '.cart:not(.cart_group)' ).toArray().forEach( function( c ) {
14149					var epo = $( c ).find( tcAPI.epoSelector );
14150					var tr = epo.closest( 'tr' );
14151
14152					$( "<td class='wc-product-table-epo'></td>" ).appendTo( tr ).append( epo );
14153					$( window ).trigger( 'tc_manual_init', epo );
14154					epo.removeClass( 'hidden' );
14155				} );
14156			}, 500 );
14157		} );
14158
14159		// Generate product link.
14160		$( '.generate-product-link' ).on( 'click', function( e ) {
14161			var url = new URL( window.location.href );
14162			var params = url.searchParams;
14163			var newUrl;
14164			var processedRadios = {};
14165
14166			e.preventDefault();
14167
14168			/* Build the query-string from the fields inside #myFormDiv */
14169			$( tcAPI.epoSelector + ':visible' ).find( '.tm-epo-field:enabled' ).each( function() {
14170				var name = this.name;
14171				var value;
14172				var checkedRadio;
14173				if ( this.type === 'radio' ) {
14174					if ( processedRadios[ name ] ) {
14175						return;
14176					}
14177					processedRadios[ name ] = true;
14178
14179					// Find the checked radio in this group
14180					checkedRadio = $( tcAPI.epoSelector + ':visible' )
14181						.find( '.tm-epo-field[name="' + name + '"]:checked' );
14182
14183					value = checkedRadio.length ? checkedRadio.val() : '';
14184				} else if ( this.type === 'checkbox' ) {
14185					value = this.checked ? this.value : '';
14186				} else {
14187					value = $( this ).val();
14188				}
14189
14190				if ( name && value !== '' ) {
14191					params.set( name, value );
14192				}
14193				if ( value === '' ) {
14194					params.delete( name );
14195				}
14196			} );
14197
14198			/* Remove empty values we just stored above */
14199			for ( const [ key, val ] of params.entries() ) {
14200				if ( val === '' ) {
14201					params.delete( key );
14202				}
14203			}
14204
14205			/* Update the browser URL without reloading the page */
14206			newUrl = url.toString();
14207			history.replaceState( null, null, newUrl );
14208			navigator.clipboard.writeText( newUrl ).then( function() {
14209				window.alert( 'Link copied to clipboard:\n' + newUrl );
14210			} ).catch( function( err ) {
14211				window.console.error( 'Could not copy: ', err );
14212			} );
14213		} );
14214	} );
14215}( window, document, window.jQuery ) );

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.