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 $.epoAPI.dom.id = function( id ) { 176 if ( typeof id === 'undefined' ) { 177 return id; 178 } 179 if ( ! ( typeof id === 'string' || typeof id === 'number' ) || ( typeof id === 'number' && isNaN( id ) ) ) { 180 return id.toString(); 181 } 182 return id.toString().replace( /(%|:|\.|\[|\]|,|=)/g, '\\$1' ); 183 }; 184 185 $.epoAPI.dom.scroll = function() { 186 var scrollLeft; 187 var scrollTop; 188 189 if ( window.pageYOffset ) { 190 scrollTop = window.pageYOffset; 191 scrollLeft = window.pageXOffset; 192 } else if ( document.documentElement && document.documentElement.scrollTop ) { 193 scrollTop = document.documentElement.scrollTop; 194 scrollLeft = document.documentElement.scrollLeft; 195 } else if ( document.body ) { 196 scrollTop = document.body.scrollTop; 197 scrollLeft = document.body.scrollLeft; 198 } 199 200 return { left: scrollLeft, top: scrollTop }; 201 }; 202 203 $.epoAPI.dom.size = function() { 204 var totalDocumentHeight; 205 var totalDocumentWidth; 206 var fullHeight; 207 var fullWidth; 208 var visibleWidth; 209 var visibleHeight; 210 211 if ( window.innerHeight && window.scrollMaxY ) { 212 totalDocumentWidth = window.innerWidth + window.scrollMaxX; 213 totalDocumentHeight = window.innerHeight + window.scrollMaxY; 214 } else if ( document.body.scrollHeight > document.body.offsetHeight ) { 215 totalDocumentWidth = document.body.scrollWidth; 216 totalDocumentHeight = document.body.scrollHeight; 217 } else { 218 totalDocumentWidth = document.body.offsetWidth; 219 totalDocumentHeight = document.body.offsetHeight; 220 } 221 222 if ( window.innerHeight ) { 223 if ( document.documentElement.clientWidth ) { 224 visibleWidth = document.documentElement.clientWidth; 225 } else { 226 visibleWidth = window.innerWidth; 227 } 228 visibleHeight = window.innerHeight; 229 } else if ( document.documentElement && document.documentElement.clientHeight ) { 230 visibleWidth = document.documentElement.clientWidth; 231 visibleHeight = document.documentElement.clientHeight; 232 } else if ( document.body ) { 233 visibleWidth = document.body.clientWidth; 234 visibleHeight = document.body.clientHeight; 235 } 236 if ( totalDocumentHeight < visibleHeight ) { 237 fullHeight = visibleHeight; 238 } else { 239 fullHeight = totalDocumentHeight; 240 } 241 if ( totalDocumentWidth < visibleWidth ) { 242 fullWidth = visibleWidth; 243 } else { 244 fullWidth = totalDocumentWidth; 245 } 246 247 return { 248 fullWidth: fullWidth, 249 fullHeight: fullHeight, 250 251 visibleWidth: visibleWidth, 252 visibleHeight: visibleHeight, 253 254 totalWidth: totalDocumentWidth, 255 totalHeight: totalDocumentHeight 256 }; 257 }; 258 259 // jQuery trim is deprecated, provide a trim method based on String.prototype.trim 260 $.epoAPI.util.trim = function( str ) { 261 if ( typeof str === 'string' ) { 262 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim#Polyfill 263 return str.replace( /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '' ); 264 } 265 return str; 266 }; 267 268 $.epoAPI.util.parseJSON = function( s ) { 269 var parsedjson; 270 var JSON = window.JSON; 271 272 try { 273 parsedjson = JSON.parse( s + '' ); 274 if ( parsedjson && typeof parsedjson === 'object' && parsedjson !== null ) { 275 return parsedjson; 276 } 277 } catch ( err ) { 278 $.epoAPI.error = err; 279 return false;
280 } 281 282 return false; 283 }; 284 285 $.epoAPI.util.decodeHTML = function( html ) { 286 var txt = document.createElement( 'textarea' ); 287 txt.innerHTML = html; 288 return txt.value; 289 }; 290 291 $.epoAPI.util.getStorage = function( type ) { 292 var storage; 293 var x; 294 try { 295 storage = window[ type ]; 296 x = '__storage_test__'; 297 storage.setItem( x, x ); 298 storage.removeItem( x ); 299 return storage; 300 } catch ( e ) { 301 return false; 302 } 303 }; 304 305 $.epoAPI.util.basename = function( path ) { 306 return path.replace( /.*\//, '' ); 307 }; 308 309 // https://medium.com/javascript-in-plain-english/how-to-deep-copy-objects-and-arrays-in-javascript-7c911359b089 310 $.epoAPI.util.deepCopyArray = function( inObject ) { 311 var outObject; 312 var value; 313 314 if ( typeof inObject !== 'object' || inObject === null ) { 315 return inObject; // Return the value if inObject is not an object 316 } 317 318 // Create an array or object to hold the values 319 outObject = Array.isArray( inObject ) ? [] : {}; 320 321 Object.keys( inObject ).forEach( function( key ) { 322 if ( inObject ) { 323 value = inObject[ key ]; 324 325 // Recursively (deep) copy for nested objects, including arrays 326 outObject[ key ] = typeof value === 'object' && value !== null ? $.epoAPI.util.deepCopyArray( value ) : value; 327 } 328 } ); 329 330 return outObject; 331 }; 332 333 $.epoAPI.locale.getSystemDecimalSeparator = function() { 334 var n = 1.1; 335 336 n = /^1(.+)1$/.exec( n.toLocaleString() )[ 1 ]; 337 338 return n; 339 }; 340 341 $.epoAPI.template.html = function( template, obj ) { 342 var $template_html = template( obj ); 343 344 $template_html = $template_html.replace( '/*<![CDATA[*/', '' ); 345 $template_html = $template_html.replace( '/*]]>*/', '' ); 346 347 return $template_html; 348 }; 349 350 $.epoAPI.filters = {}; 351 352 $.epoAPI.addFilter = function( $tag, $function_to_add, $priority, $accepted_args ) { 353 var $idx; 354 355 $priority = parseInt( $priority, 10 ); 356 if ( isNaN( $priority ) ) { 357 $priority = 10; 358 } 359 $accepted_args = parseInt( $accepted_args, 10 ); 360 if ( isNaN( $accepted_args ) ) { 361 $accepted_args = 1; 362 } 363 $idx = $function_to_add + '_' + $priority; 364 if ( ! $.epoAPI.filters[ $tag ] ) { 365 $.epoAPI.filters[ $tag ] = {}; 366 } 367 if ( ! $.epoAPI.filters[ $tag ][ $priority ] ) { 368 $.epoAPI.filters[ $tag ][ $priority ] = {}; 369 } 370 $.epoAPI.filters[ $tag ][ $priority ][ $idx ] = { 371 func: $function_to_add, 372 accepted_args: $accepted_args 373 }; 374 375 return true; 376 }; 377 378 $.epoAPI.removeFilter = function( $tag, $function_to_remove, $priority ) { 379 var $idx; 380 $priority = parseInt( $priority, 10 ); 381 if ( isNaN( $priority ) ) { 382 $priority = 10; 383 } 384 $idx = $function_to_remove + '_' + $priority; 385 386 if ( $.epoAPI.filters[ $tag ] && $.epoAPI.filters[ $tag ][ $priority ] && $.epoAPI.filters[ $tag ][ $priority ][ $idx ] ) { 387 delete $.epoAPI.filters[ $tag ][ $priority ][ $idx ]; 388 return true; 389 } 390 391 return false; 392 }; 393 394 $.epoAPI.applyFilter = function( $tag, $value ) { 395 var $args = $.makeArray( arguments ); 396 var priorities; 397 398 $args.splice( 0, 1 ); 399 400 if ( ! $.epoAPI.filters[ $tag ] ) { 401 return $value; 402 } 403 404 priorities = $.epoAPI.filters[ $tag ]; 405 $.each( priorities, function( i, el ) { 406 $.each( el, function( i2, el2 ) { 407 var func = el2.func; 408 409 if ( func instanceof Function ) { 410 $value = func.apply( null, $args ); 411 } else if ( window[ func ] && window[ func ] instanceof Function ) { 412 $value = window[ func ].apply( null, $args ); 413 } 414 } ); 415 } ); 416 417 return $value; 418 }; 419 420 // Backwards compatibility (to be removed in the future) 421 $.tc_add_filter = $.epoAPI.addFilter; 422 $.tc_remove_filter = $.epoAPI.removeFilter; 423 $.tc_apply_filters = $.epoAPI.applyFilter; 424}( window.jQuery ) ); 425 426/* 427 * Formatting functions 428 * 429 * Code modifiled from accounting.js 430 * http://openexchangerates.github.io/accounting.js/ 431 */ 432 433( function( $ ) { 434 'use strict'; 435 436 /** 437 * Check and normalise the value of precision (must be positive integer) 438 * 439 * @param {any} val the value to check. 440 * @param {any} base the value to return is check fails. 441 */ 442 function checkPrecision( val, base ) { 443 val = Math.round( Math.abs( val ) ); 444 return isNaN( val ) ? base : val; 445 } 446 447 /**
448 * Takes a string/array of strings, removes all formatting/cruft 449 * and returns the raw float value. 450 * 451 * @param {any} value the value to unformat. 452 * @param {any} decimal the decimal point. 453 */ 454 function unformat( value, decimal ) { 455 var regex; 456 var unformatted; 457 458 // Recursively unformat arrays: 459 if ( Array.isArray( value ) ) { 460 return value.map( value, function( val ) { 461 return unformat( val, decimal ); 462 } ); 463 } 464 465 // Fails silently (need decent errors): 466 value = value || 0; 467 468 // Return the value as-is if it's already a number: 469 if ( typeof value === 'number' ) { 470 return value; 471 } 472 473 // Default decimal point comes from settings, but could be set to eg. "," in opts: 474 decimal = decimal || '.'; 475 476 // Build regex to strip out everything except digits, decimal point and minus sign: 477 regex = new RegExp( '[^0-9-' + decimal + ']', [ 'g' ] ); 478 unformatted = parseFloat( 479 ( '' + value ) 480 .replace( regex, '' ) // strip out any cruft 481 .replace( decimal, '.' ) // make sure decimal point is standard 482 ); 483 484 // This will fail silently which may cause trouble, let's wait and see: 485 return ! isNaN( unformatted ) ? unformatted : 0; 486 } 487 488 /** 489 * Implementation of toFixed() that treats floats more like decimals 490 * 491 * Fixes binary rounding issues (eg. (0.615).toFixed(2) === "0.61") that present 492 * problems for accounting- and finance-related software. 493 * 494 * @param {any} value the value to convert. 495 * @param {int} precision the precision. 496 */ 497 function toFixed( value, precision ) { 498 var exponentialForm; 499 var rounded; 500 var finalResult; 501 502 if ( ! Number.isFinite( value ) ) { 503 return '-'; 504 } 505 506 precision = checkPrecision( precision, 2 ); 507 508 exponentialForm = Number( unformat( value ) * Math.pow( 10, precision ) ); 509 rounded = Math.round( exponentialForm ); 510 finalResult = Number( rounded / Math.pow( 10, precision ) ).toFixed( precision ); 511 return finalResult; 512 } 513 514 /** 515 * Format into currency or a number, with comma-separated thousands and custom precision/decimal places 516 * 517 * opts = { 518 * symbol: "$", // currency symbol is '$' 519 * format: "%s%v", // controls output: %s = symbol, %v = value (can be object, see docs) 520 * decimal: ".", // decimal point separator 521 * thousand: ",", // thousands separator 522 * precision: 2, // decimal places 523 * } 524 * 525 * @param {any} number the value to convert. 526 * @param {Object} opts the options for formatting. 527 */ 528 function format( number, opts ) { 529 var formats; 530 var useFormat; 531 var negative; 532 var base; 533 var mod; 534 535 // Resursively format arrays: 536 if ( Array.isArray( number ) ) { 537 return number.map( number, function( val ) { 538 return format( val, opts ); 539 } ); 540 } 541 542 // Clean up number: 543 number = unformat( number ); 544 545 // Do not format if opts are not correct or missing 546 if ( ! opts ) { 547 return number; 548 } 549 550 // Clean up precision 551 opts.precision = checkPrecision( opts.precision ); 552 553 // Format currency 554 if ( opts.format && opts.symbol ) { 555 // Check format (returns object with pos, neg and zero): 556 formats = { 557 pos: opts.format, 558 neg: opts.format.replace( '-', '' ).replace( '%v', '-%v' ), 559 zero: opts.format 560 }; 561 562 // Choose which format to use for this value: 563 useFormat = number > 0 ? formats.pos : number < 0 ? formats.neg : formats.zero; 564 565 // Return with currency symbol added: 566 opts.opts = { 567 precision: opts.precision, 568 thousand: opts.thousand, 569 decimal: opts.decimal 570 }; 571 572 number = useFormat.replace( '%s', opts.symbol ).replace( '%v', format( Math.abs( number ), opts.opts ) ); 573 574 // Format number 575 } else { 576 if ( ! Number.isFinite( number ) ) { 577 return '-'; 578 } 579 // Do some calc: 580 negative = number < 0 ? '-' : ''; 581 base = parseInt( toFixed( Math.abs( number || 0 ), opts.precision ), 10 ) + ''; 582 mod = base.length > 3 ? base.length % 3 : 0; 583 584 // Format the number: 585 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 ] : '' ); 586 } 587 588 return number; 589 } 590 591 $.epoAPI.math.unformat = unformat; 592 $.epoAPI.math.format = format; 593 $.epoAPI.math.toFixed = toFixed; 594}( window.jQuery ) ); 595 596/** 597 * 3. themeComplete jQuery extensions 598 * 599 **/ 600( function( $ ) { 601 'use strict'; 602 603 var expo; 604 var rCRLF = /\r?\n/g; 605 var rcheckableType = /^(?:checkbox|radio)$/i; 606 var rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i; 607 var rsubmittable = /^(?:input|select|textarea|keygen)/i; 608 609 // Extend jQuery easing 610 if ( ! $.easing.easeInExpo ) { 611 expo = function( p ) { 612 return Math.pow( p, 6 ); 613 }; 614 $.easing.easeInExpo = expo; 615 $.easing.easeOutExpo = function( p ) { 616 return 1 - expo( 1 - p ); 617 }; 618 $.easing.easeInOutExpo = function( p ) { 619 return p < 0.5 ? expo( p * 2 ) / 2 : 1 - ( expo( ( p * -2 ) + 2 ) / 2 ); 620 }; 621 } 622 623 // Add jQuery plugins 624 $.fn.extend( { 625 // Create checkbox switch 626 tmcheckboxes: function() { 627 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' ); 628 tm_settings_wrap_checkbox.wrap( '<label class="tm-epo-switch-wrapper-label"></label>' ); 629 tm_settings_wrap_checkbox.wrap( '<span class="tm-epo-switch-wrapper tc"></span>' ); 630 tm_settings_wrap_checkbox.after( '<span class="tc-label tm-epo-switch tc"></span>' ); 631 return this; 632 }, 633 634 // Encode a set of HTML elements as an array of names and values. 635 // Elements do not need to be inside a form 636 tcSerializeArray: function() { 637 return this.find( ':input' ) 638 .filter( function() { 639 var type = this.type; 640
641 // Use .is( ":disabled" ) so that fieldset[disabled] works 642 return this.name && ! $( this ).is( ':disabled' ) && rsubmittable.test( this.nodeName ) && ! rsubmitterTypes.test( type ) && ( this.checked || ! rcheckableType.test( type ) ); 643 } ) 644 .map( function( i, elem ) { 645 var val = $( this ).val(); 646 647 if ( val === null ) { 648 return null; 649 } 650 651 if ( Array.isArray( val ) ) { 652 return $.map( val, function( thisval ) { 653 return { name: elem.name, value: thisval.replace( rCRLF, '\r\n' ) }; 654 } ); 655 } 656 657 return { name: elem.name, value: val.replace( rCRLF, '\r\n' ) }; 658 } ) 659 .get(); 660 }, 661 662 // convert element to a valid JSON object 663 tcSerializeObject: function() { 664 var o = {}; 665 var a = this.tcSerializeArray(); 666 667 $.each( a, function() { 668 if ( o[ this.name ] !== undefined ) { 669 if ( this.name.endsWith( '[]' ) ) { 670 if ( ! o[ this.name ].push ) { 671 o[ this.name ] = [ o[ this.name ] ]; 672 } 673 o[ this.name ].push( this.value || '' ); 674 } else { 675 o[ this.name ] = this.value || ''; 676 } 677 } else { 678 o[ this.name ] = this.value || ''; 679 } 680 } ); 681 682 return o; 683 }, 684 685 // Scroll container to a specific element 686 tcScrollTo: function( obj, duration, offset ) { 687 var element = this; 688 689 obj = $( obj ); 690 if ( obj.length === 0 ) { 691 return this; 692 } 693 if ( ! duration ) { 694 duration = 0; 695 } 696 if ( ! offset ) { 697 offset = 0; 698 } 699 if ( element[ 0 ].self === window ) { 700 element = $( 'html, body' ); 701 } else { 702 if ( element.find( '.woodmart-scroll-content' ).length ) { 703 element = element.find( '.woodmart-scroll-content' ); 704 } 705 if ( ! element.offset() ) { 706 element = $( 'html, body' ); 707 } else { 708 offset = offset + ( element.scrollTop() - element.offset().top ); 709 } 710 } 711 712 return element.animate( 713 { 714 scrollTop: $( obj ).offset().top + offset 715 }, 716 duration 717 ); 718 }, 719 720 /** 721 * Textarea and select clone() bug workaround | Spencer Tipping 722 * Licensed under the terms of the MIT source code license 723 * https://github.com/spencertipping/jquery.fix.clone/blob/master/jquery.fix.clone.js 724 */ 725 tcClone: function() { 726 var i; 727 var l; 728 var j; 729 var m; 730 var result = $.fn.clone.apply( this, arguments ); 731 var textareas = this.find( 'textarea' ).add( this.filter( 'textarea' ) ); 732 var resultTextareas = result.find( 'textarea' ).add( result.filter( 'textarea' ) ); 733 var selects = this.find( 'select' ).add( this.filter( 'select' ) ); 734 var resultSelects = result.find( 'select' ).add( result.filter( 'select' ) ); 735 736 for ( i = 0, l = textareas.length; i < l; i += 1 ) { 737 $( resultTextareas[ i ] ).val( $( textareas[ i ] ).val() ); 738 } 739 for ( i = 0, l = selects.length; i < l; i += 1 ) { 740 for ( j = 0, m = selects[ i ].options.length; j < m; j += 1 ) { 741 if ( selects[ i ].options[ j ].selected === true ) { 742 resultSelects[ i ].options[ j ].selected = true; 743 } 744 } 745 } 746 747 return result; 748 } 749 } ); 750}( 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.