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.util.isEmpty = function( obj, customEmptyValues ) { 444 var emptyValues = customEmptyValues || [ undefined, null, false, 0, '', '0' ]; 445 var isEmptyValue = 446 emptyValues.filter( function( item ) { 447 return obj === item; 448 } ).length === 1; 449 var isEmptyObject = false; 450 451 if ( obj && typeof obj === 'object' ) { 452 isEmptyObject = 453 Object.keys( obj ).filter( function( key ) { 454 return Object.prototype.hasOwnProperty.call( obj, key ); 455 } ).length === 0; 456 return isEmptyObject; 457 } 458 459 return isEmptyValue || isEmptyObject; 460 }; 461 462 $.epoAPI.util.isEmptyValue = function( obj ) { 463 return $.epoAPI.util.isEmpty( obj, [ undefined, null, false ] ); 464 }; 465 466 $.epoAPI.util.clenValue = function( value, retIfEmpty ) { 467 if ( $.epoAPI.util.isEmptyValue( value ) ) { 468 return retIfEmpty || ''; 469 } 470 return value; 471 }; 472 473 $.epoAPI.locale.getSystemDecimalSeparator = function() { 474 var n = 1.1; 475 476 // This gets null on languages that don't return 1 in a number format. 477 n = /^1(.+)1$/.exec( n.toLocaleString() ); 478 479 if ( n ) { 480 n = n[ 1 ]; 481 } else { 482 n = ','; 483 } 484 485 return n; 486 }; 487 488 $.epoAPI.template.html = function( template, obj ) { 489 var $template_html = template( obj ); 490 491 $template_html = $template_html.replace( '/*<![CDATA[*/', '' ); 492 $template_html = $template_html.replace( '/*]]>*/', '' ); 493 494 return $template_html; 495 }; 496 497 $.epoAPI.filters = {}; 498 499 $.epoAPI.addFilter = function( $tag, $function_to_add, $priority, $accepted_args ) { 500 var $idx; 501 502 $priority = parseInt( $priority, 10 ); 503 if ( isNaN( $priority ) ) { 504 $priority = 10; 505 } 506 $accepted_args = parseInt( $accepted_args, 10 ); 507 if ( isNaN( $accepted_args ) ) { 508 $accepted_args = 1; 509 } 510 $idx = $function_to_add + '_' + $priority; 511 if ( ! $.epoAPI.filters[ $tag ] ) { 512 $.epoAPI.filters[ $tag ] = {}; 513 } 514 if ( ! $.epoAPI.filters[ $tag ][ $priority ] ) { 515 $.epoAPI.filters[ $tag ][ $priority ] = {}; 516 } 517 $.epoAPI.filters[ $tag ][ $priority ][ $idx ] = { 518 func: $function_to_add, 519 accepted_args: $accepted_args 520 }; 521 522 return true; 523 }; 524 525 $.epoAPI.removeFilter = function( $tag, $function_to_remove, $priority ) { 526 var $idx; 527 $priority = parseInt( $priority, 10 ); 528 if ( isNaN( $priority ) ) { 529 $priority = 10; 530 } 531 $idx = $function_to_remove + '_' + $priority; 532 533 if ( $.epoAPI.filters[ $tag ] && $.epoAPI.filters[ $tag ][ $priority ] && $.epoAPI.filters[ $tag ][ $priority ][ $idx ] ) { 534 delete $.epoAPI.filters[ $tag ][ $priority ][ $idx ]; 535 return true; 536 } 537 538 return false;
539 }; 540 541 $.epoAPI.applyFilter = function( $tag, $value ) { 542 var $args = $.makeArray( arguments ); 543 var priorities; 544 545 $args.splice( 0, 1 ); 546 547 if ( ! $.epoAPI.filters[ $tag ] ) { 548 return $value; 549 } 550 551 priorities = $.epoAPI.filters[ $tag ]; 552 $.each( priorities, function( i, el ) { 553 $.each( el, function( i2, el2 ) { 554 var func = el2.func; 555 556 if ( func instanceof Function ) { 557 $value = func.apply( null, $args ); 558 } else if ( window[ func ] && window[ func ] instanceof Function ) { 559 $value = window[ func ].apply( null, $args ); 560 } 561 } ); 562 } ); 563 564 return $value; 565 }; 566 567 // Backwards compatibility (to be removed in the future) 568 $.tc_add_filter = $.epoAPI.addFilter; 569 $.tc_remove_filter = $.epoAPI.removeFilter; 570 $.tc_apply_filters = $.epoAPI.applyFilter; 571}( window.jQuery ) ); 572 573/* 574 * Formatting functions 575 * 576 * Code modifiled from accounting.js 577 * http://openexchangerates.github.io/accounting.js/ 578 */ 579 580( function( $ ) { 581 'use strict'; 582 583 /** 584 * Check and normalise the value of precision (must be positive integer) 585 * 586 * @param {any} val the value to check. 587 * @param {any} base the value to return is check fails. 588 */ 589 function checkPrecision( val, base ) { 590 val = Math.round( Math.abs( val ) ); 591 return isNaN( val ) ? base : val; 592 } 593 594 /** 595 * Takes a string/array of strings, removes all formatting/cruft 596 * and returns the raw float value. 597 * 598 * @param {any} value the value to unformat. 599 * @param {any} decimal the decimal point. 600 */ 601 function unformat( value, decimal ) { 602 var regex; 603 var unformatted; 604 605 // Recursively unformat arrays: 606 if ( Array.isArray( value ) ) { 607 return value.map( value, function( val ) { 608 return unformat( val, decimal ); 609 } ); 610 } 611 612 // Fails silently (need decent errors): 613 value = value || 0; 614 615 // Return the value as-is if it's already a number: 616 if ( typeof value === 'number' ) { 617 return value; 618 } 619 620 // Default decimal point comes from settings, but could be set to eg. "," in opts: 621 decimal = decimal || '.'; 622 623 // Build regex to strip out everything except digits, decimal point and minus sign: 624 regex = new RegExp( '[^0-9-' + decimal + ']', [ 'g' ] ); 625 unformatted = parseFloat( 626 ( '' + value ) 627 .replace( regex, '' ) // strip out any cruft 628 .replace( decimal, '.' ) // make sure decimal point is standard 629 ); 630 631 // This will fail silently which may cause trouble, let's wait and see: 632 return ! isNaN( unformatted ) ? unformatted : 0; 633 } 634 635 /** 636 * Implementation of toFixed() that treats floats more like decimals 637 * 638 * Fixes binary rounding issues (eg. (0.615).toFixed(2) === "0.61") that present 639 * problems for accounting- and finance-related software. 640 * 641 * @param {any} value the value to convert. 642 * @param {int} precision the precision. 643 */ 644 function toFixed( value, precision ) { 645 var exponentialForm; 646 var rounded; 647 var finalResult; 648 649 if ( ! Number.isFinite( value ) ) { 650 return '-'; 651 } 652 653 precision = checkPrecision( precision, 2 ); 654 655 exponentialForm = Number( unformat( value ) * Math.pow( 10, precision ) ); 656 rounded = Math.round( exponentialForm ); 657 finalResult = Number( rounded / Math.pow( 10, precision ) ).toFixed( precision ); 658 return finalResult; 659 } 660 661 /** 662 * Format into currency or a number, with comma-separated thousands and custom precision/decimal places 663 * 664 * opts = { 665 * symbol: "$", // currency symbol is '$' 666 * format: "%s%v", // controls output: %s = symbol, %v = value (can be object, see docs) 667 * decimal: ".", // decimal point separator 668 * thousand: ",", // thousands separator 669 * precision: 2, // decimal places 670 * } 671 * 672 * @param {any} number the value to convert. 673 * @param {Object} opts the options for formatting. 674 */ 675 function format( number, opts ) { 676 var formats; 677 var useFormat; 678 var negative; 679 var base; 680 var mod; 681 682 // Resursively format arrays: 683 if ( Array.isArray( number ) ) { 684 return number.map( function( val ) { 685 return format( val, opts ); 686 } ); 687 } 688 689 // Clean up number: 690 number = unformat( number ); 691 692 // Do not format if opts are not correct or missing 693 if ( ! opts ) { 694 return number; 695 } 696 697 // Clean up precision 698 opts.precision = checkPrecision( opts.precision ); 699 700 // Format currency 701 if ( opts.format && opts.symbol ) { 702 // Check format (returns object with pos, neg and zero): 703 formats = { 704 pos: opts.format, 705 neg: opts.format.replace( '-', '' ).replace( '%v', '-%v' ), 706 zero: opts.format 707 }; 708 709 // Choose which format to use for this value: 710 useFormat = number > 0 ? formats.pos : number < 0 ? formats.neg : formats.zero; 711 712 // Return with currency symbol added: 713 opts.opts = { 714 precision: opts.precision,
715 thousand: opts.thousand, 716 decimal: opts.decimal 717 }; 718 719 number = useFormat.replace( '%s', opts.symbol ).replace( '%v', format( Math.abs( number ), opts.opts ) ); 720 721 // Format number 722 } else { 723 if ( ! Number.isFinite( number ) ) { 724 return '-'; 725 } 726 // Do some calc: 727 negative = number < 0 ? '-' : ''; 728 base = parseInt( toFixed( Math.abs( number || 0 ), opts.precision ), 10 ) + ''; 729 mod = base.length > 3 ? base.length % 3 : 0; 730 731 // Format the number: 732 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 ] : '' ); 733 } 734 735 return number; 736 } 737 738 $.epoAPI.math.unformat = unformat; 739 $.epoAPI.math.format = format; 740 $.epoAPI.math.toFixed = toFixed; 741}( window.jQuery ) ); 742 743/** 744 * 3. ThemeComplete jQuery extensions 745 * 746 * @param {Object} $ The jQuery object. 747 */ 748( function( $ ) { 749 'use strict'; 750 751 var expo; 752 var rCRLF = /\r?\n/g; 753 var rcheckableType = /^(?:checkbox|radio)$/i; 754 var rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i; 755 var rsubmittable = /^(?:input|select|textarea|keygen)/i; 756 757 // Extend jQuery easing 758 if ( ! $.easing.easeInExpo ) { 759 expo = function( p ) { 760 return Math.pow( p, 6 ); 761 }; 762 $.easing.easeInExpo = expo; 763 $.easing.easeOutExpo = function( p ) { 764 return 1 - expo( 1 - p ); 765 }; 766 $.easing.easeInOutExpo = function( p ) { 767 return p < 0.5 ? expo( p * 2 ) / 2 : 1 - ( expo( ( p * -2 ) + 2 ) / 2 ); 768 }; 769 } 770 771 // Add jQuery plugins 772 $.fn.extend( { 773 // Create checkbox switch 774 tmcheckboxes: function() { 775 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' ); 776 tm_settings_wrap_checkbox.wrap( '<label class="tm-epo-switch-wrapper-label"></label>' ); 777 tm_settings_wrap_checkbox.wrap( '<span class="tm-epo-switch-wrapper tc"></span>' ); 778 tm_settings_wrap_checkbox.after( '<span class="tc-label tm-epo-switch tc"></span>' ); 779 return this; 780 }, 781 782 // Encode a set of HTML elements as an array of names and values. 783 // Elements do not need to be inside a form 784 tcSerializeArray: function() { 785 return this.find( ':input' ) 786 .filter( function() { 787 var type = this.type; 788 789 // Use .is( ":disabled" ) so that fieldset[disabled] works 790 return this.name && ! $( this ).is( ':disabled' ) && rsubmittable.test( this.nodeName ) && ! rsubmitterTypes.test( type ) && ( this.checked || ! rcheckableType.test( type ) ); 791 } ) 792 .map( function( i, elem ) { 793 var val = $( this ).val(); 794 795 if ( val === null ) { 796 return null; 797 } 798 799 if ( Array.isArray( val ) ) { 800 return $.map( val, function( thisval ) { 801 return { name: elem.name, value: thisval.replace( rCRLF, '\r\n' ) }; 802 } ); 803 } 804 805 return { name: elem.name, value: val.replace( rCRLF, '\r\n' ) }; 806 } ) 807 .get(); 808 }, 809 810 // convert element to a valid JSON object 811 tcSerializeObject: function() { 812 var o = {}; 813 var a = this.tcSerializeArray(); 814 815 $.each( a, function() { 816 var name = this.name; 817 var value = this.value || ''; 818 819 if ( name.endsWith( '[]' ) ) { 820 if ( ! o[ name ] ) { 821 o[ name ] = []; 822 } 823 o[ name ].push( value ); 824 } else { 825 o[ name ] = value; 826 } 827 } ); 828 829 return o; 830 }, 831 832 // Scroll container to a specific element 833 tcScrollTo: function( obj, duration, offset ) { 834 var element = this; 835 836 obj = $( obj ); 837 if ( obj.length === 0 ) { 838 return this; 839 } 840 if ( ! duration ) { 841 duration = 0; 842 } 843 if ( ! offset ) { 844 offset = 0; 845 } 846 if ( element[ 0 ].self === window ) { 847 element = $( 'html, body' ); 848 } else { 849 if ( element.find( '.woodmart-scroll-content' ).length ) { 850 element = element.find( '.woodmart-scroll-content' ); 851 } 852 if ( ! element.offset() ) { 853 element = $( 'html, body' ); 854 } else { 855 offset = offset + ( element.scrollTop() - element.offset().top ); 856 } 857 } 858 859 return element.animate( 860 { 861 scrollTop: $( obj ).offset().top + offset 862 }, 863 duration 864 ); 865 }, 866 867 /** 868 * Textarea and select clone() bug workaround | Spencer Tipping 869 * Licensed under the terms of the MIT source code license 870 * https://github.com/spencertipping/jquery.fix.clone/blob/master/jquery.fix.clone.js 871 */ 872 tcClone: function() { 873 var i; 874 var l; 875 var j; 876 var m; 877 var result = $.fn.clone.apply( this, arguments ); 878 var textareas = this.find( 'textarea' ).add( this.filter( 'textarea' ) ); 879 var resultTextareas = result.find( 'textarea' ).add( result.filter( 'textarea' ) ); 880 var selects = this.find( 'select' ).add( this.filter( 'select' ) ); 881 var resultSelects = result.find( 'select' ).add( result.filter( 'select' ) ); 882 883 for ( i = 0, l = textareas.length; i < l; i += 1 ) { 884 $( resultTextareas[ i ] ).val( $( textareas[ i ] ).val() ); 885 } 886 for ( i = 0, l = selects.length; i < l; i += 1 ) { 887 for ( j = 0, m = selects[ i ].options.length; j < m; j += 1 ) { 888 if ( selects[ i ].options[ j ].selected === true ) { 889 resultSelects[ i ].options[ j ].selected = true; 890 } 891 } 892 } 893 894 return result; 895 } 896 } ); 897}( 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.