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.