PageSourceSearch

https://www.worldleisure.org/wlo2019/wp-content/plugins/woocommerc…m-extra-product-options/assets/js/tm-api.js

js worldleisure.org collected 2026-10-02 06:00:56 UTC 20,860 bytes, 806 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	// jQuery trim is deprecated, provide a trim method based on String.prototype.trim
303	$.epoAPI.util.trim = function( str ) {
304		if ( typeof str === 'string' ) {
305			// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim#Polyfill
306			return str.replace( /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '' );
307		}
308		return str;
309	};
310
311	$.epoAPI.util.parseJSON = function( s ) {
312		var parsedjson;
313		var JSON = window.JSON;
314
315		try {
316			parsedjson = JSON.parse( s + '' );
317			if ( parsedjson && typeof parsedjson === 'object' && parsedjson !== null ) {
318				return parsedjson;
319			}
320		} catch ( err ) {
321			$.epoAPI.error = err;
322			return false;
323		}
324
325		return false;
326	};
327
328	$.epoAPI.util.decodeHTML = function( html ) {
329		var txt = document.createElement( 'textarea' );
330		txt.innerHTML = html;
331		return txt.value;
332	};
333
334	$.epoAPI.util.getStorage = function( type ) {
335		var storage;
336		var x;
337		try {
338			storage = window[ type ];
339			x = '__storage_test__';
340			storage.setItem( x, x );
341			storage.removeItem( x );
342			return storage;
343		} catch ( e ) {
344			return false;
345		}
346	};
347
348	$.epoAPI.util.basename = function( path ) {
349		return path.replace( /.*\//, '' );
350	};
351
352	// https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
353	// https://medium.com/javascript-in-plain-english/how-to-deep-copy-objects-and-arrays-in-javascript-7c911359b089
354	$.epoAPI.util.deepCopyArray = function( inObject ) {
355		var outObject;
356		var value;
357
358		if ( window.structuredClone !== undefined ) {
359			return window.structuredClone( inObject );
360		}
361
362		if ( typeof inObject !== 'object' || inObject === null ) {
363			return inObject; // Return the value if inObject is not an object
364		}
365
366		// Create an array or object to hold the values
367		outObject = Array.isArray( inObject ) ? [] : {};
368
369		Object.keys( inObject ).forEach( function( key ) {
370			if ( inObject ) {
371				value = inObject[ key ];
372
373				// Recursively (deep) copy for nested objects, including arrays
374				outObject[ key ] = typeof value === 'object' && value !== null ? $.epoAPI.util.deepCopyArray( value ) : value;
375			}
376		} );
377
378		return outObject;
379	};
380
381	$.epoAPI.locale.getSystemDecimalSeparator = function() {
382		var n = 1.1;
383
384		// This gets null on languages that don't return 1 in a number format.
385		n = /^1(.+)1$/.exec( n.toLocaleString() );
386
387		if ( n ) {
388			n = n[ 1 ];
389		} else {
390			n = ',';
391		}
392
393		return n;
394	};
395
396	$.epoAPI.template.html = function( template, obj ) {
397		var $template_html = template( obj );
398
399		$template_html = $template_html.replace( '/*<![CDATA[*/', '' );
400		$template_html = $template_html.replace( '/*]]>*/', '' );
401
402		return $template_html;
403	};
404
405	$.epoAPI.filters = {};
406
407	$.epoAPI.addFilter = function( $tag, $function_to_add, $priority, $accepted_args ) {
408		var $idx;
409
410		$priority = parseInt( $priority, 10 );
411		if ( isNaN( $priority ) ) {
412			$priority = 10;
413		}
414		$accepted_args = parseInt( $accepted_args, 10 );
415		if ( isNaN( $accepted_args ) ) {
416			$accepted_args = 1;
417		}
418		$idx = $function_to_add + '_' + $priority;
419		if ( ! $.epoAPI.filters[ $tag ] ) {
420			$.epoAPI.filters[ $tag ] = {};
421		}
422		if ( ! $.epoAPI.filters[ $tag ][ $priority ] ) {
423			$.epoAPI.filters[ $tag ][ $priority ] = {};
424		}
425		$.epoAPI.filters[ $tag ][ $priority ][ $idx ] = {
426			func: $function_to_add,
427			accepted_args: $accepted_args
428		};
429
430		return true;
431	};
432
433	$.epoAPI.removeFilter = function( $tag, $function_to_remove, $priority ) {
434		var $idx;
435		$priority = parseInt( $priority, 10 );
436		if ( isNaN( $priority ) ) {
437			$priority = 10;
438		}
439		$idx = $function_to_remove + '_' + $priority;
440
441		if ( $.epoAPI.filters[ $tag ] && $.epoAPI.filters[ $tag ][ $priority ] && $.epoAPI.filters[ $tag ][ $priority ][ $idx ] ) {
442			delete $.epoAPI.filters[ $tag ][ $priority ][ $idx ];
443			return true;
444		}
445
446		return false;
447	};
448
449	$.epoAPI.applyFilter = function( $tag, $value ) {
450		var $args = $.makeArray( arguments );
451		var priorities;
452
453		$args.splice( 0, 1 );
454
455		if ( ! $.epoAPI.filters[ $tag ] ) {
456			return $value;
457		}
458
459		priorities = $.epoAPI.filters[ $tag ];
460		$.each( priorities, function( i, el ) {
461			$.each( el, function( i2, el2 ) {
462				var func = el2.func;
463
464				if ( func instanceof Function ) {
465					$value = func.apply( null, $args );
466				} else if ( window[ func ] && window[ func ] instanceof Function ) {
467					$value = window[ func ].apply( null, $args );
468				}
469			} );
470		} );
471
472		return $value;
473	};
474
475	// Backwards compatibility (to be removed in the future)
476	$.tc_add_filter = $.epoAPI.addFilter;
477	$.tc_remove_filter = $.epoAPI.removeFilter;
478	$.tc_apply_filters = $.epoAPI.applyFilter;
479}( window.jQuery ) );
480
481/*
482 * Formatting functions
483 *
484 * Code modifiled from accounting.js
485 * http://openexchangerates.github.io/accounting.js/
486 */
487
488( function( $ ) {
489	'use strict';
490
491	/**
492	 * Check and normalise the value of precision (must be positive integer)
493	 *
494	 * @param {any} val  the value to check.
495	 * @param {any} base the value to return is check fails.
496	 */
497	function checkPrecision( val, base ) {
498		val = Math.round( Math.abs( val ) );
499		return isNaN( val ) ? base : val;
500	}
501
502	/**
503	 * Takes a string/array of strings, removes all formatting/cruft
504	 * and returns the raw float value.
505	 *
506	 * @param {any} value   the value to unformat.
507	 * @param {any} decimal the decimal point.
508	 */
509	function unformat( value, decimal ) {
510		var regex;
511		var unformatted;
512
513		// Recursively unformat arrays:
514		if ( Array.isArray( value ) ) {
515			return value.map( value, function( val ) {
516				return unformat( val, decimal );
517			} );
518		}
519
520		// Fails silently (need decent errors):
521		value = value || 0;
522
523		// Return the value as-is if it's already a number:
524		if ( typeof value === 'number' ) {
525			return value;
526		}
527
528		// Default decimal point comes from settings, but could be set to eg. "," in opts:
529		decimal = decimal || '.';
530
531		// Build regex to strip out everything except digits, decimal point and minus sign:
532		regex = new RegExp( '[^0-9-' + decimal + ']', [ 'g' ] );
533		unformatted = parseFloat(
534			( '' + value )
535				.replace( regex, '' ) // strip out any cruft
536				.replace( decimal, '.' ) // make sure decimal point is standard
537		);
538
539		// This will fail silently which may cause trouble, let's wait and see:
540		return ! isNaN( unformatted ) ? unformatted : 0;
541	}
542
543	/**
544	 * Implementation of toFixed() that treats floats more like decimals
545	 *
546	 * Fixes binary rounding issues (eg. (0.615).toFixed(2) === "0.61") that present
547	 * problems for accounting- and finance-related software.
548	 *
549	 * @param {any} value     the value to convert.
550	 * @param {int} precision the precision.
551	 */
552	function toFixed( value, precision ) {
553		var exponentialForm;
554		var rounded;
555		var finalResult;
556
557		if ( ! Number.isFinite( value ) ) {
558			return '-';
559		}
560
561		precision = checkPrecision( precision, 2 );
562
563		exponentialForm = Number( unformat( value ) * Math.pow( 10, precision ) );
564		rounded = Math.round( exponentialForm );
565		finalResult = Number( rounded / Math.pow( 10, precision ) ).toFixed( precision );
566		return finalResult;
567	}
568
569	/**
570	 * Format into currency or a number, with comma-separated thousands and custom precision/decimal places
571	 *
572	 * opts = {
573	 *     symbol: "$",    // currency symbol is '$'
574	 *     format: "%s%v", // controls output: %s = symbol, %v = value (can be object, see docs)
575	 *     decimal: ".",   // decimal point separator
576	 *     thousand: ",",  // thousands separator
577	 *     precision: 2,   // decimal places
578	 * }
579	 *
580	 * @param {any}    number the value to convert.
581	 * @param {Object} opts   the options for formatting.
582	 */
583	function format( number, opts ) {
584		var formats;
585		var useFormat;
586		var negative;
587		var base;
588		var mod;
589
590		// Resursively format arrays:
591		if ( Array.isArray( number ) ) {
592			return number.map( number, function( val ) {
593				return format( val, opts );
594			} );
595		}
596
597		// Clean up number:
598		number = unformat( number );
599
600		// Do not format if opts are not correct or missing
601		if ( ! opts ) {
602			return number;
603		}
604
605		// Clean up precision
606		opts.precision = checkPrecision( opts.precision );
607
608		// Format currency
609		if ( opts.format && opts.symbol ) {
610			// Check format (returns object with pos, neg and zero):
611			formats = {
612				pos: opts.format,
613				neg: opts.format.replace( '-', '' ).replace( '%v', '-%v' ),
614				zero: opts.format
615			};
616
617			// Choose which format to use for this value:
618			useFormat = number > 0 ? formats.pos : number < 0 ? formats.neg : formats.zero;
619
620			// Return with currency symbol added:
621			opts.opts = {
622				precision: opts.precision,
623				thousand: opts.thousand,
624				decimal: opts.decimal
625			};
626
627			number = useFormat.replace( '%s', opts.symbol ).replace( '%v', format( Math.abs( number ), opts.opts ) );
628
629			// Format number
630		} else {
631			if ( ! Number.isFinite( number ) ) {
632				return '-';
633			}
634			// Do some calc:
635			negative = number < 0 ? '-' : '';
636			base = parseInt( toFixed( Math.abs( number || 0 ), opts.precision ), 10 ) + '';
637			mod = base.length > 3 ? base.length % 3 : 0;
638
639			// Format the number:
640			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 ] : '' );
641		}
642
643		return number;
644	}
645
646	$.epoAPI.math.unformat = unformat;
647	$.epoAPI.math.format = format;
648	$.epoAPI.math.toFixed = toFixed;
649}( window.jQuery ) );
650
651/**
652 * 3. ThemeComplete jQuery extensions
653 *
654 * @param {Object} $ The jQuery object.
655 */
656( function( $ ) {
657	'use strict';
658
659	var expo;
660	var rCRLF = /\r?\n/g;
661	var rcheckableType = /^(?:checkbox|radio)$/i;
662	var rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i;
663	var rsubmittable = /^(?:input|select|textarea|keygen)/i;
664
665	// Extend jQuery easing
666	if ( ! $.easing.easeInExpo ) {
667		expo = function( p ) {
668			return Math.pow( p, 6 );
669		};
670		$.easing.easeInExpo = expo;
671		$.easing.easeOutExpo = function( p ) {
672			return 1 - expo( 1 - p );
673		};
674		$.easing.easeInOutExpo = function( p ) {
675			return p < 0.5 ? expo( p * 2 ) / 2 : 1 - ( expo( ( p * -2 ) + 2 ) / 2 );
676		};
677	}
678
679	// Add jQuery plugins
680	$.fn.extend( {
681		// Create checkbox switch
682		tmcheckboxes: function() {
683			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' );
684			tm_settings_wrap_checkbox.wrap( '<label class="tm-epo-switch-wrapper-label"></label>' );
685			tm_settings_wrap_checkbox.wrap( '<span class="tm-epo-switch-wrapper tc"></span>' );
686			tm_settings_wrap_checkbox.after( '<span class="tc-label tm-epo-switch tc"></span>' );
687			return this;
688		},
689
690		// Encode a set of HTML elements as an array of names and values.
691		// Elements do not need to be inside a form
692		tcSerializeArray: function() {
693			return this.find( ':input' )
694				.filter( function() {
695					var type = this.type;
696
697					// Use .is( ":disabled" ) so that fieldset[disabled] works
698					return this.name && ! $( this ).is( ':disabled' ) && rsubmittable.test( this.nodeName ) && ! rsubmitterTypes.test( type ) && ( this.checked || ! rcheckableType.test( type ) );
699				} )
700				.map( function( i, elem ) {
701					var val = $( this ).val();
702
703					if ( val === null ) {
704						return null;
705					}
706
707					if ( Array.isArray( val ) ) {
708						return $.map( val, function( thisval ) {
709							return { name: elem.name, value: thisval.replace( rCRLF, '\r\n' ) };
710						} );
711					}
712
713					return { name: elem.name, value: val.replace( rCRLF, '\r\n' ) };
714				} )
715				.get();
716		},
717
718		// convert element to a valid JSON object
719		tcSerializeObject: function() {
720			var o = {};
721			var a = this.tcSerializeArray();
722
723			$.each( a, function() {
724				if ( o[ this.name ] !== undefined ) {
725					if ( this.name.endsWith( '[]' ) ) {
726						if ( ! o[ this.name ].push ) {
727							o[ this.name ] = [ o[ this.name ] ];
728						}
729						o[ this.name ].push( this.value || '' );
730					} else {
731						o[ this.name ] = this.value || '';
732					}
733				} else {
734					o[ this.name ] = this.value || '';
735				}
736			} );
737
738			return o;
739		},
740
741		// Scroll container to a specific element
742		tcScrollTo: function( obj, duration, offset ) {
743			var element = this;
744
745			obj = $( obj );
746			if ( obj.length === 0 ) {
747				return this;
748			}
749			if ( ! duration ) {
750				duration = 0;
751			}
752			if ( ! offset ) {
753				offset = 0;
754			}
755			if ( element[ 0 ].self === window ) {
756				element = $( 'html, body' );
757			} else {
758				if ( element.find( '.woodmart-scroll-content' ).length ) {
759					element = element.find( '.woodmart-scroll-content' );
760				}
761				if ( ! element.offset() ) {
762					element = $( 'html, body' );
763				} else {
764					offset = offset + ( element.scrollTop() - element.offset().top );
765				}
766			}
767
768			return element.animate(
769				{
770					scrollTop: $( obj ).offset().top + offset
771				},
772				duration
773			);
774		},
775
776		/**
777		 * Textarea and select clone() bug workaround | Spencer Tipping
778		 * Licensed under the terms of the MIT source code license
779		 * https://github.com/spencertipping/jquery.fix.clone/blob/master/jquery.fix.clone.js
780		 */
781		tcClone: function() {
782			var i;
783			var l;
784			var j;
785			var m;
786			var result = $.fn.clone.apply( this, arguments );
787			var textareas = this.find( 'textarea' ).add( this.filter( 'textarea' ) );
788			var resultTextareas = result.find( 'textarea' ).add( result.filter( 'textarea' ) );
789			var selects = this.find( 'select' ).add( this.filter( 'select' ) );
790			var resultSelects = result.find( 'select' ).add( result.filter( 'select' ) );
791
792			for ( i = 0, l = textareas.length; i < l; i += 1 ) {
793				$( resultTextareas[ i ] ).val( $( textareas[ i ] ).val() );
794			}
795			for ( i = 0, l = selects.length; i < l; i += 1 ) {
796				for ( j = 0, m = selects[ i ].options.length; j < m; j += 1 ) {
797					if ( selects[ i ].options[ j ].selected === true ) {
798						resultSelects[ i ].options[ j ].selected = true;
799					}
800				}
801			}
802
803			return result;
804		}
805	} );
806}( 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.