PageSourceSearch

https://airolator.com/wp-content/plugins/woocommerce-tm-extra-product-options/assets/js/tm-api.js?ver=7.5.1

js airolator.com collected 2026-10-09 00:53:12 UTC 22,321 bytes, 867 lines download raw bytes

1/**
2 * The following API is shared on both frontend and backend.
3 *
4 * No external libraries are loaded in this file.
5 *
6 * 1. Polyfills
7 * 2. themeComplete plugin JS API
8 * 3. themeComplete jQuery extensions
9 */
10/*jshint bitwise: false*/
11/**
12 * 1. Polyfills
13 *
14 * The following are required methods for
15 * the String, Number and Object prototype
16 */
17( function() {
18	'use strict';
19
20	/**
21	 * String.prototype.isNumeric()
22	 *
23	 * Determines whether a string contains a numeric value
24	 *
25	 * https://stackoverflow.com/questions/18082/validate-decimal-numbers-in-javascript-isnumeric
26	 */
27	if ( ! String.prototype.isNumeric ) {
28		Object.defineProperty( String.prototype, 'isNumeric', {
29			value: function() {
30				return ! isNaN( parseFloat( this ) ) && isFinite( this );
31			}
32		} );
33	}
34}() );
35
36// jQuery Mask Plugin v1.14.15
37// github.com/igorescobar/jQuery-Mask-Plugin
38window.jQuery.jMaskGlobals = {
39	maskElements: '.tc-extra-product-options input'
40};
41
42/**
43 * 2. ThemeComplete plugin JS API
44 */
45
46( function( $ ) {
47	'use strict';
48
49	$.epoAPI = {};
50	$.epoAPI.error = false;
51	$.epoAPI.math = {};
52	$.epoAPI.dom = {};
53	$.epoAPI.util = {};
54	$.epoAPI.locale = {};
55	$.epoAPI.template = {};
56
57	$.epoAPI.math.toFloat = function( s, d ) {
58		var n;
59
60		if ( ! ( typeof s === 'string' || typeof s === 'number' ) || isNaN( s ) ) {
61			return 0;
62		}
63		n = parseFloat( s );
64		if ( isNaN( n ) ) {
65			if ( d !== undefined ) {
66				return d;
67			}
68			return s;
69		}
70
71		return n;
72	};
73
74	$.epoAPI.math.toInt = function( s, d ) {
75		var n;
76
77		if ( ! ( typeof s === 'string' || typeof s === 'number' ) || isNaN( s ) || s === '' ) {
78			return 0;
79		}
80		n = parseInt( s, 10 );
81		if ( isNaN( n ) ) {
82			if ( d !== undefined ) {
83				return d;
84			}
85			return s;
86		}
87
88		return n;
89	};
90
91	/**
92	 * Rounds a number
93	 * modified from http://locutus.io/php/math/round/
94	 *
95	 * @param {any}    value     the value to round.
96	 * @param {int}    precision the precision.
97	 * @param {string} mode      the rounding mode.
98	 */
99	$.epoAPI.math.round = function( value, precision, mode ) {
100		var m;
101		var f;
102		var isHalf;
103		var n;
104		var sgn; // helper variables
105
106		// making sure precision is integer
107		precision = parseInt( precision, 10 );
108		if ( ! Number.isFinite( precision ) ) {
109			precision = 0;
110		}
111		m = Math.pow( 10, precision );
112		value = value * m;
113
114		// sign of the number
115		if ( typeof value === 'number' ) {
116			if ( value ) {
117				if ( value < 0 ) {
118					sgn = -1;
119				} else {
120					sgn = 1;
121				}
122			} else {
123				sgn = 0;
124			}
125		} else {
126			sgn = 0;
127		}
128
129		isHalf = value % 1 === 0.5 * sgn;
130		f = Math.floor( value );
131
132		if ( isHalf ) {
133			switch ( mode ) {
134				case 'PHP_ROUND_HALF_DOWN':
135					// rounds .5 toward zero
136					if ( sgn < 0 ) {
137						n = 1;
138					} else {
139						n = 0;
140					}
141					value = f + n;
142					break;
143				case 'PHP_ROUND_HALF_EVEN':
144					// rouds .5 towards the next even integer
145					value = f + ( ( f % 2 ) * sgn );
146					break;
147				case 'PHP_ROUND_HALF_ODD':
148					// rounds .5 towards the next odd integer
149					n = f % 2;
150					if ( n ) {
151						n = 0;
152					} else {
153						n = 1;
154					}
155					value = f + n;
156					break;
157				default:
158					// rounds .5 away from zero
159					if ( sgn > 0 ) {
160						n = 1;
161					} else {
162						n = 0;
163					}
164					value = f + n;
165			}
166		}
167
168		if ( ! isHalf ) {
169			value = Math.round( value );
170		}
171
172		return value / m;
173	};
174
175	// https://locutus.io/php/misc/uniqid/index.html
176	$.epoAPI.math.uniqueid = function( prefix, moreEntropy ) {
177		var retId;
178		var _formatSeed = function( seed, reqWidth ) {
179			seed = parseInt( seed, 10 ).toString( 16 ); // to hex str
180			if ( reqWidth < seed.length ) {
181				// so long we split
182				return seed.slice( seed.length - reqWidth );
183			}
184			if ( reqWidth > seed.length ) {
185				// so short we pad
186				return new Array( 1 + ( reqWidth - seed.length ) ).join( '0' ) + seed;
187			}
188			return seed;
189		};
190		var radom;
191
192		if ( prefix === undefined ) {
193			prefix = '';
194		}
195
196		$.epoAPI.php = $.epoAPI.php || {};
197
198		if ( ! $.epoAPI.php.uniqidSeed ) {
199			// init seed with big random int
200			$.epoAPI.php.uniqidSeed = Math.floor( Math.random() * 0x75bcd15 );
201		}
202		$.epoAPI.php.uniqidSeed += 1;
203
204		// start with prefix, add current milliseconds hex string
205		retId = prefix;
206		retId += _formatSeed( parseInt( Date.now() / 1000, 10 ), 8 );
207		// add seed hex string
208		retId += _formatSeed( $.epoAPI.php.uniqidSeed, 5 );
209		if ( moreEntropy ) {
210			// for more entropy we add a float lower to 10
211			radom = Math.random() * 10;
212			retId += radom.toFixed( 8 ).toString();
213		}
214
215		return retId;
216	};
217
218	$.epoAPI.dom.id = function( id ) {
219		if ( typeof id === 'undefined' ) {
220			return id;
221		}
222		if ( ! ( typeof id === 'string' || typeof id === 'number' ) || ( typeof id === 'number' && isNaN( id ) ) ) {
223			return id.toString();
224		}
225		return id.toString().replace( /(%|:|\.|\[|\]|,|=)/g, '\\$1' );
226	};
227
228	$.epoAPI.dom.scroll = function() {
229		var scrollLeft;
230		var scrollTop;
231
232		if ( window.pageYOffset ) {
233			scrollTop = window.pageYOffset;
234			scrollLeft = window.pageXOffset;
235		} else if ( document.documentElement && document.documentElement.scrollTop ) {
236			scrollTop = document.documentElement.scrollTop;
237			scrollLeft = document.documentElement.scrollLeft;
238		} else if ( document.body ) {
239			scrollTop = document.body.scrollTop;
240			scrollLeft = document.body.scrollLeft;
241		}
242
243		return { left: scrollLeft, top: scrollTop };
244	};
245
246	$.epoAPI.dom.size = function() {
247		var totalDocumentHeight;
248		var totalDocumentWidth;
249		var fullHeight;
250		var fullWidth;
251		var visibleWidth;
252		var visibleHeight;
253
254		if ( window.innerHeight && window.scrollMaxY ) {
255			totalDocumentWidth = window.innerWidth + window.scrollMaxX;
256			totalDocumentHeight = window.innerHeight + window.scrollMaxY;
257		} else if ( document.body.scrollHeight > document.body.offsetHeight ) {
258			totalDocumentWidth = document.body.scrollWidth;
259			totalDocumentHeight = document.body.scrollHeight;
260		} else {
261			totalDocumentWidth = document.body.offsetWidth;
262			totalDocumentHeight = document.body.offsetHeight;
263		}
264
265		if ( window.innerHeight ) {
266			if ( document.documentElement.clientWidth ) {
267				visibleWidth = document.documentElement.clientWidth;
268			} else {
269				visibleWidth = window.innerWidth;
270			}
271			visibleHeight = window.innerHeight;
272		} else if ( document.documentElement && document.documentElement.clientHeight ) {
273			visibleWidth = document.documentElement.clientWidth;
274			visibleHeight = document.documentElement.clientHeight;
275		} else if ( document.body ) {
276			visibleWidth = document.body.clientWidth;
277			visibleHeight = document.body.clientHeight;
278		}
279		if ( totalDocumentHeight < visibleHeight ) {
280			fullHeight = visibleHeight;
281		} else {
282			fullHeight = totalDocumentHeight;
283		}
284		if ( totalDocumentWidth < visibleWidth ) {
285			fullWidth = visibleWidth;
286		} else {
287			fullWidth = totalDocumentWidth;
288		}
289
290		return {
291			fullWidth: fullWidth,
292			fullHeight: fullHeight,
293
294			visibleWidth: visibleWidth,
295			visibleHeight: visibleHeight,
296
297			totalWidth: totalDocumentWidth,
298			totalHeight: totalDocumentHeight
299		};
300	};
301
302	$.epoAPI.util.escapeSelector = ( function() {
303		/* original escape string
304		 *  /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;
305		 */
306		var selectorEscape = /([!"$%&'()*+,/:;<=>?@[\]^`{|}~])/g;
307		return function( selector ) {
308			return selector.replace( selectorEscape, '\\$1' );
309		};
310	}() );
311
312	$.epoAPI.util.parseParams = function( string, decode ) {
313		if ( typeof string !== 'string' || string.split === undefined ) {
314			return [];
315		}
316		return string
317			.split( '&' )
318			.map( function( value ) {
319				var obj = {};
320
321				if ( decode === true ) {
322					value = decodeURIComponent( value.replace( /\+/g, '%20' ) );
323				}
324
325				value = value.split( '=' ).map( function( v ) {
326					var a = v.split( '?' );
327
328					if ( a.length > 1 ) {
329						return a[ 1 ];
330					}
331					return v;
332				} );
333
334				if ( value.length > 1 ) {
335					obj[ value[ 0 ] ] = value[ 1 ];
336				}
337
338				return obj;
339			} )
340			.filter( function( n ) {
341				return n !== null;
342			} )
343			.reduce( function( current, next ) {
344				return Object.assign( {}, current, next );
345			}, {} );
346	};
347
348	// jQuery trim is deprecated, provide a trim method based on String.prototype.trim
349	$.epoAPI.util.trim = function( str ) {
350		if ( typeof str === 'string' ) {
351			// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim#Polyfill
352			return str.replace( /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '' );
353		}
354		return str;
355	};
356
357	$.epoAPI.util.parseJSON = function( s ) {
358		var parsedjson;
359		var JSON = window.JSON;
360
361		try {
362			parsedjson = JSON.parse( s + '' );
363			if ( parsedjson && typeof parsedjson === 'object' && parsedjson !== null ) {
364				return parsedjson;
365			}
366		} catch ( err ) {
367			$.epoAPI.error = err;
368			return false;
369		}
370
371		return false;
372	};
373
374	$.epoAPI.util.decodeHTML = function( html ) {
375		var txt = document.createElement( 'textarea' );
376		txt.innerHTML = html;
377		return txt.value;
378	};
379
380	$.epoAPI.util.getStorage = function( type ) {
381		var storage;
382		var x;
383		try {
384			storage = window[ type ];
385			x = '__storage_test__';
386			storage.setItem( x, x );
387			storage.removeItem( x );
388			return storage;
389		} catch ( e ) {
390			return false;
391		}
392	};
393
394	$.epoAPI.util.basename = function( path ) {
395		return path.replace( /.*\//, '' );
396	};
397
398	$.epoAPI.util.getType = function( obj ) {
399		// Get the type string using `toString.call()`
400		var type = Object.prototype.toString.call( obj ).match( /\[object (\w+)]/ )[ 1 ].toLowerCase();
401
402		// If it's a plain object, make sure it's not a class instance
403		if ( type === 'object' && Object.getPrototypeOf( obj ) === Object.prototype ) {
404			return 'object'; // Plain object ({} or new Object())
405		}
406		if ( type === 'object' ) {
407			type = 'other';
408		}
409
410		// Return the type for arrays and other types directly from the match result
411		return type;
412	};
413
414	// https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
415	// https://medium.com/javascript-in-plain-english/how-to-deep-copy-objects-and-arrays-in-javascript-7c911359b089
416	$.epoAPI.util.deepCopyArray = function( inObject ) {
417		var outObject;
418		var value;
419
420		if ( window.structuredClone !== undefined ) {
421			return window.structuredClone( inObject );
422		}
423
424		if ( typeof inObject !== 'object' || inObject === null ) {
425			return inObject; // Return the value if inObject is not an object
426		}
427
428		// Create an array or object to hold the values
429		outObject = Array.isArray( inObject ) ? [] : {};
430
431		Object.keys( inObject ).forEach( function( key ) {
432			if ( inObject ) {
433				value = inObject[ key ];
434
435				// Recursively (deep) copy for nested objects, including arrays
436				outObject[ key ] = typeof value === 'object' && value !== null ? $.epoAPI.util.deepCopyArray( value ) : value;
437			}
438		} );
439
440		return outObject;
441	};
442
443	$.epoAPI.locale.getSystemDecimalSeparator = function() {
444		var n = 1.1;
445
446		// This gets null on languages that don't return 1 in a number format.
447		n = /^1(.+)1$/.exec( n.toLocaleString() );
448
449		if ( n ) {
450			n = n[ 1 ];
451		} else {
452			n = ',';
453		}
454
455		return n;
456	};
457
458	$.epoAPI.template.html = function( template, obj ) {
459		var $template_html = template( obj );
460
461		$template_html = $template_html.replace( '/*<![CDATA[*/', '' );
462		$template_html = $template_html.replace( '/*]]>*/', '' );
463
464		return $template_html;
465	};
466
467	$.epoAPI.filters = {};
468
469	$.epoAPI.addFilter = function( $tag, $function_to_add, $priority, $accepted_args ) {
470		var $idx;
471
472		$priority = parseInt( $priority, 10 );
473		if ( isNaN( $priority ) ) {
474			$priority = 10;
475		}
476		$accepted_args = parseInt( $accepted_args, 10 );
477		if ( isNaN( $accepted_args ) ) {
478			$accepted_args = 1;
479		}
480		$idx = $function_to_add + '_' + $priority;
481		if ( ! $.epoAPI.filters[ $tag ] ) {
482			$.epoAPI.filters[ $tag ] = {};
483		}
484		if ( ! $.epoAPI.filters[ $tag ][ $priority ] ) {
485			$.epoAPI.filters[ $tag ][ $priority ] = {};
486		}
487		$.epoAPI.filters[ $tag ][ $priority ][ $idx ] = {
488			func: $function_to_add,
489			accepted_args: $accepted_args
490		};
491
492		return true;
493	};
494
495	$.epoAPI.removeFilter = function( $tag, $function_to_remove, $priority ) {
496		var $idx;
497		$priority = parseInt( $priority, 10 );
498		if ( isNaN( $priority ) ) {
499			$priority = 10;
500		}
501		$idx = $function_to_remove + '_' + $priority;
502
503		if ( $.epoAPI.filters[ $tag ] && $.epoAPI.filters[ $tag ][ $priority ] && $.epoAPI.filters[ $tag ][ $priority ][ $idx ] ) {
504			delete $.epoAPI.filters[ $tag ][ $priority ][ $idx ];
505			return true;
506		}
507
508		return false;
509	};
510
511	$.epoAPI.applyFilter = function( $tag, $value ) {
512		var $args = $.makeArray( arguments );
513		var priorities;
514
515		$args.splice( 0, 1 );
516
517		if ( ! $.epoAPI.filters[ $tag ] ) {
518			return $value;
519		}
520
521		priorities = $.epoAPI.filters[ $tag ];
522		$.each( priorities, function( i, el ) {
523			$.each( el, function( i2, el2 ) {
524				var func = el2.func;
525
526				if ( func instanceof Function ) {
527					$value = func.apply( null, $args );
528				} else if ( window[ func ] && window[ func ] instanceof Function ) {
529					$value = window[ func ].apply( null, $args );
530				}
531			} );
532		} );
533
534		return $value;
535	};
536
537	// Backwards compatibility (to be removed in the future)
538	$.tc_add_filter = $.epoAPI.addFilter;
539	$.tc_remove_filter = $.epoAPI.removeFilter;
540	$.tc_apply_filters = $.epoAPI.applyFilter;
541}( window.jQuery ) );
542
543/*
544 * Formatting functions
545 *
546 * Code modifiled from accounting.js
547 * http://openexchangerates.github.io/accounting.js/
548 */
549
550( function( $ ) {
551	'use strict';
552
553	/**
554	 * Check and normalise the value of precision (must be positive integer)
555	 *
556	 * @param {any} val  the value to check.
557	 * @param {any} base the value to return is check fails.
558	 */
559	function checkPrecision( val, base ) {
560		val = Math.round( Math.abs( val ) );
561		return isNaN( val ) ? base : val;
562	}
563
564	/**
565	 * Takes a string/array of strings, removes all formatting/cruft
566	 * and returns the raw float value.
567	 *
568	 * @param {any} value   the value to unformat.
569	 * @param {any} decimal the decimal point.
570	 */
571	function unformat( value, decimal ) {
572		var regex;
573		var unformatted;
574
575		// Recursively unformat arrays:
576		if ( Array.isArray( value ) ) {
577			return value.map( value, function( val ) {
578				return unformat( val, decimal );
579			} );
580		}
581
582		// Fails silently (need decent errors):
583		value = value || 0;
584
585		// Return the value as-is if it's already a number:
586		if ( typeof value === 'number' ) {
587			return value;
588		}
589
590		// Default decimal point comes from settings, but could be set to eg. "," in opts:
591		decimal = decimal || '.';
592
593		// Build regex to strip out everything except digits, decimal point and minus sign:
594		regex = new RegExp( '[^0-9-' + decimal + ']', [ 'g' ] );
595		unformatted = parseFloat(
596			( '' + value )
597				.replace( regex, '' ) // strip out any cruft
598				.replace( decimal, '.' ) // make sure decimal point is standard
599		);
600
601		// This will fail silently which may cause trouble, let's wait and see:
602		return ! isNaN( unformatted ) ? unformatted : 0;
603	}
604
605	/**
606	 * Implementation of toFixed() that treats floats more like decimals
607	 *
608	 * Fixes binary rounding issues (eg. (0.615).toFixed(2) === "0.61") that present
609	 * problems for accounting- and finance-related software.
610	 *
611	 * @param {any} value     the value to convert.
612	 * @param {int} precision the precision.
613	 */
614	function toFixed( value, precision ) {
615		var exponentialForm;
616		var rounded;
617		var finalResult;
618
619		if ( ! Number.isFinite( value ) ) {
620			return '-';
621		}
622
623		precision = checkPrecision( precision, 2 );
624
625		exponentialForm = Number( unformat( value ) * Math.pow( 10, precision ) );
626		rounded = Math.round( exponentialForm );
627		finalResult = Number( rounded / Math.pow( 10, precision ) ).toFixed( precision );
628		return finalResult;
629	}
630
631	/**
632	 * Format into currency or a number, with comma-separated thousands and custom precision/decimal places
633	 *
634	 * opts = {
635	 *     symbol: "$",    // currency symbol is '$'
636	 *     format: "%s%v", // controls output: %s = symbol, %v = value (can be object, see docs)
637	 *     decimal: ".",   // decimal point separator
638	 *     thousand: ",",  // thousands separator
639	 *     precision: 2,   // decimal places
640	 * }
641	 *
642	 * @param {any}    number the value to convert.
643	 * @param {Object} opts   the options for formatting.
644	 */
645	function format( number, opts ) {
646		var formats;
647		var useFormat;
648		var negative;
649		var base;
650		var mod;
651
652		// Resursively format arrays:
653		if ( Array.isArray( number ) ) {
654			return number.map( function( val ) {
655				return format( val, opts );
656			} );
657		}
658
659		// Clean up number:
660		number = unformat( number );
661
662		// Do not format if opts are not correct or missing
663		if ( ! opts ) {
664			return number;
665		}
666
667		// Clean up precision
668		opts.precision = checkPrecision( opts.precision );
669
670		// Format currency
671		if ( opts.format && opts.symbol ) {
672			// Check format (returns object with pos, neg and zero):
673			formats = {
674				pos: opts.format,
675				neg: opts.format.replace( '-', '' ).replace( '%v', '-%v' ),
676				zero: opts.format
677			};
678
679			// Choose which format to use for this value:
680			useFormat = number > 0 ? formats.pos : number < 0 ? formats.neg : formats.zero;
681
682			// Return with currency symbol added:
683			opts.opts = {
684				precision: opts.precision,
685				thousand: opts.thousand,
686				decimal: opts.decimal
687			};
688
689			number = useFormat.replace( '%s', opts.symbol ).replace( '%v', format( Math.abs( number ), opts.opts ) );
690
691			// Format number
692		} else {
693			if ( ! Number.isFinite( number ) ) {
694				return '-';
695			}
696			// Do some calc:
697			negative = number < 0 ? '-' : '';
698			base = parseInt( toFixed( Math.abs( number || 0 ), opts.precision ), 10 ) + '';
699			mod = base.length > 3 ? base.length % 3 : 0;
700
701			// Format the number:
702			number = negative + ( mod ? base.substring( 0, mod ) + opts.thousand : '' ) + base.substring( mod ).replace( /(\d{3})(?=\d)/g, '$1' + opts.thousand ) + ( opts.precision ? opts.decimal + toFixed( Math.abs( number ), opts.precision ).split( '.' )[ 1 ] : '' );
703		}
704
705		return number;
706	}
707
708	$.epoAPI.math.unformat = unformat;
709	$.epoAPI.math.format = format;
710	$.epoAPI.math.toFixed = toFixed;
711}( window.jQuery ) );
712
713/**
714 * 3. ThemeComplete jQuery extensions
715 *
716 * @param {Object} $ The jQuery object.
717 */
718( function( $ ) {
719	'use strict';
720
721	var expo;
722	var rCRLF = /\r?\n/g;
723	var rcheckableType = /^(?:checkbox|radio)$/i;
724	var rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i;
725	var rsubmittable = /^(?:input|select|textarea|keygen)/i;
726
727	// Extend jQuery easing
728	if ( ! $.easing.easeInExpo ) {
729		expo = function( p ) {
730			return Math.pow( p, 6 );
731		};
732		$.easing.easeInExpo = expo;
733		$.easing.easeOutExpo = function( p ) {
734			return 1 - expo( 1 - p );
735		};
736		$.easing.easeInOutExpo = function( p ) {
737			return p < 0.5 ? expo( p * 2 ) / 2 : 1 - ( expo( ( p * -2 ) + 2 ) / 2 );
738		};
739	}
740
741	// Add jQuery plugins
742	$.fn.extend( {
743		// Create checkbox switch
744		tmcheckboxes: function() {
745			var tm_settings_wrap_checkbox = this.find( ":checkbox:not('.tm-default-checkbox')" ).not( '.wp-tab-panel :checkbox, .tm-weekdays-picker-wrap :checkbox, .tm-months-picker-wrap :checkbox' );
746			tm_settings_wrap_checkbox.wrap( '<label class="tm-epo-switch-wrapper-label"></label>' );
747			tm_settings_wrap_checkbox.wrap( '<span class="tm-epo-switch-wrapper tc"></span>' );
748			tm_settings_wrap_checkbox.after( '<span class="tc-label tm-epo-switch tc"></span>' );
749			return this;
750		},
751
752		// Encode a set of HTML elements as an array of names and values.
753		// Elements do not need to be inside a form
754		tcSerializeArray: function() {
755			return this.find( ':input' )
756				.filter( function() {
757					var type = this.type;
758
759					// Use .is( ":disabled" ) so that fieldset[disabled] works
760					return this.name && ! $( this ).is( ':disabled' ) && rsubmittable.test( this.nodeName ) && ! rsubmitterTypes.test( type ) && ( this.checked || ! rcheckableType.test( type ) );
761				} )
762				.map( function( i, elem ) {
763					var val = $( this ).val();
764
765					if ( val === null ) {
766						return null;
767					}
768
769					if ( Array.isArray( val ) ) {
770						return $.map( val, function( thisval ) {
771							return { name: elem.name, value: thisval.replace( rCRLF, '\r\n' ) };
772						} );
773					}
774
775					return { name: elem.name, value: val.replace( rCRLF, '\r\n' ) };
776				} )
777				.get();
778		},
779
780		// convert element to a valid JSON object
781		tcSerializeObject: function() {
782			var o = {};
783			var a = this.tcSerializeArray();
784
785			$.each( a, function() {
786				var name = this.name;
787				var value = this.value || '';
788
789				if ( name.endsWith( '[]' ) ) {
790					if ( ! o[ name ] ) {
791						o[ name ] = [];
792					}
793					o[ name ].push( value );
794				} else {
795					o[ name ] = value;
796				}
797			} );
798
799			return o;
800		},
801
802		// Scroll container to a specific element
803		tcScrollTo: function( obj, duration, offset ) {
804			var element = this;
805
806			obj = $( obj );
807			if ( obj.length === 0 ) {
808				return this;
809			}
810			if ( ! duration ) {
811				duration = 0;
812			}
813			if ( ! offset ) {
814				offset = 0;
815			}
816			if ( element[ 0 ].self === window ) {
817				element = $( 'html, body' );
818			} else {
819				if ( element.find( '.woodmart-scroll-content' ).length ) {
820					element = element.find( '.woodmart-scroll-content' );
821				}
822				if ( ! element.offset() ) {
823					element = $( 'html, body' );
824				} else {
825					offset = offset + ( element.scrollTop() - element.offset().top );
826				}
827			}
828
829			return element.animate(
830				{
831					scrollTop: $( obj ).offset().top + offset
832				},
833				duration
834			);
835		},
836
837		/**
838		 * Textarea and select clone() bug workaround | Spencer Tipping
839		 * Licensed under the terms of the MIT source code license
840		 * https://github.com/spencertipping/jquery.fix.clone/blob/master/jquery.fix.clone.js
841		 */
842		tcClone: function() {
843			var i;
844			var l;
845			var j;
846			var m;
847			var result = $.fn.clone.apply( this, arguments );
848			var textareas = this.find( 'textarea' ).add( this.filter( 'textarea' ) );
849			var resultTextareas = result.find( 'textarea' ).add( result.filter( 'textarea' ) );
850			var selects = this.find( 'select' ).add( this.filter( 'select' ) );
851			var resultSelects = result.find( 'select' ).add( result.filter( 'select' ) );
852
853			for ( i = 0, l = textareas.length; i < l; i += 1 ) {
854				$( resultTextareas[ i ] ).val( $( textareas[ i ] ).val() );
855			}
856			for ( i = 0, l = selects.length; i < l; i += 1 ) {
857				for ( j = 0, m = selects[ i ].options.length; j < m; j += 1 ) {
858					if ( selects[ i ].options[ j ].selected === true ) {
859						resultSelects[ i ].options[ j ].selected = true;
860					}
861				}
862			}
863
864			return result;
865		}
866	} );
867}( 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.