1/*! This file is auto-generated */ 2window.wp=window.wp||{},function(r){var t="undefined"==typeof _wpUtilSettings?{}:_wpUtilSettings;wp.template=_.memoize(function(a){var n,s={evaluate:/<#([\s\S]+?)#>/g,interpolate:/\{\{\{([\s\S]+?)\}\}\}/g,escape:/\{\{([^\}]+?)\}\}(?!\})/g,variable:"data"};return function(t){var e=document.querySelector("script#tmpl-"+a);if(e)return(n=n||_.template(r(e).html(),s))(t);throw new Error("Template not found: #tmpl-"+a)}}),wp.ajax={settings:t.ajax||{},post:function(t,e){return wp.ajax.send({data:_.isObject(t)?t:_.extend(e||{},{action:t})})},send:function(n,t){var e,a;return _.isObject(n)?t=n:(t=t||{}).data=_.extend(t.data||{},{action:n}),t=_.defaults(t||{},{type:"POST",url:wp.ajax.settings.url,context:this}),(e=(a=r.Deferred(function(a){t.success&&a.done(t.success),t.error&&a.fail(t.error),delete t.success,delete t.error,a.jqXHR=r.ajax(t).done(function(t){var e;"1"!==t&&1!==t||(t={success:!0}),_.isObject(t)&&!_.isUndefined(t.success)?(e=this,a.done(function(){n&&n.data&&"query-attachments"===n.data.action&&a.jqXHR.hasOwnProperty("getResponseHeader")&&a.jqXHR.getResponseHeader("X-WP-Total")?e.totalAttachments=parseInt(a.jqXHR.getResponseHeader("X-WP-Total"),10):e.totalAttachments=0}),a[t.success?"resolveWith":"rejectWith"](this,[t.data])):a.rejectWith(this,[t])}).fail(function(){a.rejectWith(this,arguments)})})).promise()).abort=function(){return a.jqXHR.abort(),this},e}}}(jQuery);; 3/*! 4 * jQuery UI Touch Punch 0.2.3 5 * 6 * Copyright 2011â2014, Dave Furfero 7 * Dual licensed under the MIT or GPL Version 2 licenses. 8 * 9 * Depends: 10 * jquery.ui.widget.js 11 * jquery.ui.mouse.js 12 */ 13!function(t){if(t.support.touch="ontouchend"in document,t.support.touch){var o,e=t.ui.mouse.prototype,u=e._mouseInit,n=e._mouseDestroy;e._touchStart=function(t){!o&&this._mouseCapture(t.originalEvent.changedTouches[0])&&(o=!0,this._touchMoved=!1,c(t,"mouseover"),c(t,"mousemove"),c(t,"mousedown"))},e._touchMove=function(t){o&&(this._touchMoved=!0,c(t,"mousemove"))},e._touchEnd=function(t){o&&(c(t,"mouseup"),c(t,"mouseout"),this._touchMoved||c(t,"click"),o=!1)},e._mouseInit=function(){this.element.on({touchstart:t.proxy(this,"_touchStart"),touchmove:t.proxy(this,"_touchMove"),touchend:t.proxy(this,"_touchEnd")}),u.call(this)},e._mouseDestroy=function(){this.element.off({touchstart:t.proxy(this,"_touchStart"),touchmove:t.proxy(this,"_touchMove"),touchend:t.proxy(this,"_touchEnd")}),n.call(this)}}function c(t,o){if(!(t.originalEvent.touches.length>1)){t.preventDefault();var e=t.originalEvent.changedTouches[0],u=document.createEvent("MouseEvents");u.initMouseEvent(o,!0,!0,window,1,e.screenX,e.screenY,e.clientX,e.clientY,!1,!1,!1,!1,0,null),t.target.dispatchEvent(u)}}}(jQuery);; 14/** 15 * The following API is shared on both frontend and backend. 16 * 17 * No external libraries are loaded in this file. 18 * 19 * 1. Polyfills 20 * 2. themeComplete plugin JS API 21 * 3. themeComplete jQuery extensions 22 */ 23/*jshint bitwise: false*/ 24/** 25 * 1. Polyfills 26 * 27 * The following are required methods for 28 * the String, Number and Object prototype 29 */ 30( function() { 31 'use strict'; 32 33 /** 34 * String.prototype.isNumeric() 35 * 36 * Determines whether a string contains a numeric value 37 * 38 * https://stackoverflow.com/questions/18082/validate-decimal-numbers-in-javascript-isnumeric 39 */ 40 if ( ! String.prototype.isNumeric ) { 41 Object.defineProperty( String.prototype, 'isNumeric', { 42 value: function() { 43 return ! isNaN( parseFloat( this ) ) && isFinite( this ); 44 } 45 } ); 46 } 47}() ); 48 49// jQuery Mask Plugin v1.14.15 50// github.com/igorescobar/jQuery-Mask-Plugin 51window.jQuery.jMaskGlobals = { 52 maskElements: '.tc-extra-product-options input' 53}; 54 55/** 56 * 2. ThemeComplete plugin JS API 57 */ 58 59( function( $ ) { 60 'use strict'; 61 62 $.epoAPI = {}; 63 $.epoAPI.error = false; 64 $.epoAPI.math = {}; 65 $.epoAPI.dom = {}; 66 $.epoAPI.util = {}; 67 $.epoAPI.locale = {}; 68 $.epoAPI.template = {}; 69 70 $.epoAPI.math.toFloat = function( s, d ) { 71 var n; 72 73 if ( ! ( typeof s === 'string' || typeof s === 'number' ) || isNaN( s ) ) { 74 return 0; 75 } 76 n = parseFloat( s ); 77 if ( isNaN( n ) ) { 78 if ( d !== undefined ) { 79 return d; 80 } 81 return s; 82 } 83 84 return n; 85 }; 86 87 $.epoAPI.math.toInt = function( s, d ) { 88 var n; 89 90 if ( ! ( typeof s === 'string' || typeof s === 'number' ) || isNaN( s ) || s === '' ) { 91 return 0; 92 } 93 n = parseInt( s, 10 ); 94 if ( isNaN( n ) ) { 95 if ( d !== undefined ) { 96 return d; 97 } 98 return s; 99 } 100 101 return n; 102 }; 103 104 /** 105 * Rounds a number 106 * modified from http://locutus.io/php/math/round/ 107 * 108 * @param {any} value the value to round. 109 * @param {int} precision the precision. 110 * @param {string} mode the rounding mode. 111 */ 112 $.epoAPI.math.round = function( value, precision, mode ) { 113 var m; 114 var f; 115 var isHalf; 116 var n; 117 var sgn; // helper variables 118 119 // making sure precision is integer 120 precision = parseInt( precision, 10 ); 121 if ( ! Number.isFinite( precision ) ) { 122 precision = 0; 123 } 124 m = Math.pow( 10, precision ); 125 value = value * m; 126 127 // sign of the number 128 if ( typeof value === 'number' ) { 129 if ( value ) { 130 if ( value < 0 ) { 131 sgn = -1; 132 } else { 133 sgn = 1; 134 } 135 } else { 136 sgn = 0; 137 } 138 } else { 139 sgn = 0; 140 } 141 142 isHalf = value % 1 === 0.5 * sgn; 143 f = Math.floor( value ); 144 145 if ( isHalf ) { 146 switch ( mode ) { 147 case 'PHP_ROUND_HALF_DOWN': 148 // rounds .5 toward zero 149 if ( sgn < 0 ) { 150 n = 1; 151 } else { 152 n = 0; 153 } 154 value = f + n; 155 break; 156 case 'PHP_ROUND_HALF_EVEN': 157 // rouds .5 towards the next even integer 158 value = f + ( ( f % 2 ) * sgn ); 159 break; 160 case 'PHP_ROUND_HALF_ODD': 161 // rounds .5 towards the next odd integer 162 n = f % 2; 163 if ( n ) { 164 n = 0; 165 } else { 166 n = 1; 167 } 168 value = f + n; 169 break; 170 default: 171 // rounds .5 away from zero 172 if ( sgn > 0 ) { 173 n = 1; 174 } else { 175 n = 0; 176 } 177 value = f + n; 178 } 179 } 180 181 if ( ! isHalf ) { 182 value = Math.round( value ); 183 } 184 185 return value / m; 186 }; 187 188 // https://locutus.io/php/misc/uniqid/index.html 189 $.epoAPI.math.uniqueid = function( prefix, moreEntropy ) { 190 var retId; 191 var _formatSeed = function( seed, reqWidth ) { 192 seed = parseInt( seed, 10 ).toString( 16 ); // to hex str 193 if ( reqWidth < seed.length ) { 194 // so long we split 195 return seed.slice( seed.length - reqWidth ); 196 } 197 if ( reqWidth > seed.length ) { 198 // so short we pad 199 return new Array( 1 + ( reqWidth - seed.length ) ).join( '0' ) + seed; 200 } 201 return seed; 202 }; 203 var radom; 204 205 if ( prefix === undefined ) { 206 prefix = ''; 207 } 208 209 $.epoAPI.php = $.epoAPI.php || {}; 210 211 if ( ! $.epoAPI.php.uniqidSeed ) { 212 // init seed with big random int 213 $.epoAPI.php.uniqidSeed = Math.floor( Math.random() * 0x75bcd15 ); 214 } 215 $.epoAPI.php.uniqidSeed += 1; 216 217 // start with prefix, add current milliseconds hex string 218 retId = prefix; 219 retId += _formatSeed( parseInt( Date.now() / 1000, 10 ), 8 ); 220 // add seed hex string 221 retId += _formatSeed( $.epoAPI.php.uniqidSeed, 5 ); 222 if ( moreEntropy ) { 223 // for more entropy we add a float lower to 10 224 radom = Math.random() * 10; 225 retId += radom.toFixed( 8 ).toString(); 226 } 227 228 return retId; 229 }; 230 231 $.epoAPI.dom.id = function( id ) { 232 if ( typeof id === 'undefined' ) { 233 return id; 234 } 235 if ( ! ( typeof id === 'string' || typeof id === 'number' ) || ( typeof id === 'number' && isNaN( id ) ) ) { 236 return id.toString(); 237 } 238 return id.toString().replace( /(%|:|\.|\[|\]|,|=)/g, '\\$1' ); 239 }; 240 241 $.epoAPI.dom.scroll = function() { 242 var scrollLeft; 243 var scrollTop; 244 245 if ( window.pageYOffset ) { 246 scrollTop = window.pageYOffset; 247 scrollLeft = window.pageXOffset; 248 } else if ( document.documentElement && document.documentElement.scrollTop ) { 249 scrollTop = document.documentElement.scrollTop; 250 scrollLeft = document.documentElement.scrollLeft; 251 } else if ( document.body ) { 252 scrollTop = document.body.scrollTop; 253 scrollLeft = document.body.scrollLeft; 254 } 255 256 return { left: scrollLeft, top: scrollTop }; 257 }; 258 259 $.epoAPI.dom.size = function() { 260 var totalDocumentHeight; 261 var totalDocumentWidth; 262 var fullHeight; 263 var fullWidth; 264 var visibleWidth; 265 var visibleHeight; 266 267 if ( window.innerHeight && window.scrollMaxY ) { 268 totalDocumentWidth = window.innerWidth + window.scrollMaxX; 269 totalDocumentHeight = window.innerHeight + window.scrollMaxY; 270 } else if ( document.body.scrollHeight > document.body.offsetHeight ) { 271 totalDocumentWidth = document.body.scrollWidth; 272 totalDocumentHeight = document.body.scrollHeight; 273 } else { 274 totalDocumentWidth = document.body.offsetWidth; 275 totalDocumentHeight = document.body.offsetHeight; 276 } 277 278 if ( window.innerHeight ) { 279 if ( document.documentElement.clientWidth ) { 280 visibleWidth = document.documentElement.clientWidth; 281 } else { 282 visibleWidth = window.innerWidth; 283 } 284 visibleHeight = window.innerHeight; 285 } else if ( document.documentElement && document.documentElement.clientHeight ) { 286 visibleWidth = document.documentElement.clientWidth; 287 visibleHeight = document.documentElement.clientHeight; 288 } else if ( document.body ) { 289 visibleWidth = document.body.clientWidth; 290 visibleHeight = document.body.clientHeight; 291 } 292 if ( totalDocumentHeight < visibleHeight ) { 293 fullHeight = visibleHeight; 294 } else { 295 fullHeight = totalDocumentHeight; 296 } 297 if ( totalDocumentWidth < visibleWidth ) { 298 fullWidth = visibleWidth; 299 } else { 300 fullWidth = totalDocumentWidth; 301 } 302 303 return { 304 fullWidth: fullWidth, 305 fullHeight: fullHeight, 306 307 visibleWidth: visibleWidth, 308 visibleHeight: visibleHeight, 309 310 totalWidth: totalDocumentWidth, 311 totalHeight: totalDocumentHeight 312 }; 313 }; 314 315 $.epoAPI.util.escapeSelector = ( function() { 316 /* original escape string 317 * /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g; 318 */ 319 var selectorEscape = /([!"$%&'()*+,/:;<=>?@[\]^`{|}~])/g; 320 return function( selector ) { 321 return selector.replace( selectorEscape, '\\$1' ); 322 }; 323 }() ); 324 325 $.epoAPI.util.parseParams = function( string, decode ) { 326 if ( typeof string !== 'string' || string.split === undefined ) { 327 return []; 328 } 329 return string 330 .split( '&' ) 331 .map( function( value ) { 332 var obj = {}; 333 334 if ( decode === true ) { 335 value = decodeURIComponent( value.replace( /\+/g, '%20' ) ); 336 } 337 338 value = value.split( '=' ).map( function( v ) { 339 var a = v.split( '?' ); 340 341 if ( a.length > 1 ) { 342 return a[ 1 ]; 343 } 344 return v; 345 } ); 346 347 if ( value.length > 1 ) { 348 obj[ value[ 0 ] ] = value[ 1 ]; 349 } 350 351 return obj; 352 } ) 353 .filter( function( n ) { 354 return n !== null; 355 } ) 356 .reduce( function( current, next ) { 357 return Object.assign( {}, current, next ); 358 }, {} ); 359 }; 360 361 // jQuery trim is deprecated, provide a trim method based on String.prototype.trim 362 $.epoAPI.util.trim = function( str ) { 363 if ( typeof str === 'string' ) { 364 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim#Polyfill 365 return str.replace( /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '' ); 366 } 367 return str; 368 }; 369 370 $.epoAPI.util.parseJSON = function( s ) { 371 var parsedjson; 372 var JSON = window.JSON; 373 374 try { 375 parsedjson = JSON.parse( s + '' ); 376 if ( parsedjson && typeof parsedjson === 'object' && parsedjson !== null ) { 377 return parsedjson; 378 } 379 } catch ( err ) { 380 $.epoAPI.error = err; 381 return false;
382 } 383 384 return false; 385 }; 386 387 $.epoAPI.util.decodeHTML = function( html ) { 388 var txt = document.createElement( 'textarea' ); 389 txt.innerHTML = html; 390 return txt.value; 391 }; 392 393 $.epoAPI.util.getStorage = function( type ) { 394 var storage; 395 var x; 396 try { 397 storage = window[ type ]; 398 x = '__storage_test__'; 399 storage.setItem( x, x ); 400 storage.removeItem( x ); 401 return storage; 402 } catch ( e ) { 403 return false; 404 } 405 }; 406 407 $.epoAPI.util.basename = function( path ) { 408 return path.replace( /.*\//, '' ); 409 }; 410 411 $.epoAPI.util.getType = function( obj ) { 412 // Get the type string using `toString.call()` 413 var type = Object.prototype.toString.call( obj ).match( /\[object (\w+)]/ )[ 1 ].toLowerCase(); 414 415 // If it's a plain object, make sure it's not a class instance 416 if ( type === 'object' && Object.getPrototypeOf( obj ) === Object.prototype ) { 417 return 'object'; // Plain object ({} or new Object()) 418 } 419 if ( type === 'object' ) { 420 type = 'other'; 421 } 422 423 // Return the type for arrays and other types directly from the match result 424 return type; 425 }; 426 427 // https://developer.mozilla.org/en-US/docs/Web/API/structuredClone 428 // https://medium.com/javascript-in-plain-english/how-to-deep-copy-objects-and-arrays-in-javascript-7c911359b089 429 $.epoAPI.util.deepCopyArray = function( inObject ) { 430 var outObject; 431 var value; 432 433 if ( window.structuredClone !== undefined ) { 434 return window.structuredClone( inObject ); 435 } 436 437 if ( typeof inObject !== 'object' || inObject === null ) { 438 return inObject; // Return the value if inObject is not an object 439 } 440 441 // Create an array or object to hold the values 442 outObject = Array.isArray( inObject ) ? [] : {}; 443 444 Object.keys( inObject ).forEach( function( key ) { 445 if ( inObject ) { 446 value = inObject[ key ]; 447 448 // Recursively (deep) copy for nested objects, including arrays 449 outObject[ key ] = typeof value === 'object' && value !== null ? $.epoAPI.util.deepCopyArray( value ) : value; 450 } 451 } ); 452 453 return outObject; 454 }; 455 456 $.epoAPI.util.isEmpty = function( obj, customEmptyValues ) { 457 var emptyValues = customEmptyValues || [ undefined, null, false, 0, '', '0' ]; 458 var isEmptyValue = 459 emptyValues.filter( function( item ) { 460 return obj === item; 461 } ).length === 1; 462 var isEmptyObject = false; 463 464 if ( obj && typeof obj === 'object' ) { 465 isEmptyObject = 466 Object.keys( obj ).filter( function( key ) { 467 return Object.prototype.hasOwnProperty.call( obj, key ); 468 } ).length === 0; 469 return isEmptyObject; 470 } 471 472 return isEmptyValue || isEmptyObject; 473 }; 474 475 $.epoAPI.util.isEmptyValue = function( obj ) { 476 return $.epoAPI.util.isEmpty( obj, [ undefined, null, false ] ); 477 }; 478 479 $.epoAPI.util.clenValue = function( value, retIfEmpty ) { 480 if ( $.epoAPI.util.isEmptyValue( value ) ) { 481 return retIfEmpty || ''; 482 } 483 return value; 484 }; 485 486 $.epoAPI.locale.getSystemDecimalSeparator = function() { 487 var n = 1.1; 488 489 // This gets null on languages that don't return 1 in a number format. 490 n = /^1(.+)1$/.exec( n.toLocaleString() ); 491 492 if ( n ) { 493 n = n[ 1 ]; 494 } else { 495 n = ','; 496 } 497 498 return n; 499 }; 500 501 $.epoAPI.template.html = function( template, obj ) { 502 var $template_html = template( obj ); 503 504 $template_html = $template_html.replace( '/*<![CDATA[*/', '' ); 505 $template_html = $template_html.replace( '/*]]>*/', '' ); 506 507 return $template_html; 508 }; 509 510 $.epoAPI.filters = {}; 511 512 $.epoAPI.addFilter = function( $tag, $function_to_add, $priority, $accepted_args ) { 513 var $idx; 514 515 $priority = parseInt( $priority, 10 ); 516 if ( isNaN( $priority ) ) { 517 $priority = 10; 518 } 519 $accepted_args = parseInt( $accepted_args, 10 ); 520 if ( isNaN( $accepted_args ) ) { 521 $accepted_args = 1; 522 } 523 $idx = $function_to_add + '_' + $priority; 524 if ( ! $.epoAPI.filters[ $tag ] ) { 525 $.epoAPI.filters[ $tag ] = {}; 526 } 527 if ( ! $.epoAPI.filters[ $tag ][ $priority ] ) { 528 $.epoAPI.filters[ $tag ][ $priority ] = {}; 529 } 530 $.epoAPI.filters[ $tag ][ $priority ][ $idx ] = { 531 func: $function_to_add, 532 accepted_args: $accepted_args 533 }; 534 535 return true; 536 }; 537 538 $.epoAPI.removeFilter = function( $tag, $function_to_remove, $priority ) { 539 var $idx; 540 $priority = parseInt( $priority, 10 ); 541 if ( isNaN( $priority ) ) { 542 $priority = 10; 543 } 544 $idx = $function_to_remove + '_' + $priority; 545 546 if ( $.epoAPI.filters[ $tag ] && $.epoAPI.filters[ $tag ][ $priority ] && $.epoAPI.filters[ $tag ][ $priority ][ $idx ] ) { 547 delete $.epoAPI.filters[ $tag ][ $priority ][ $idx ]; 548 return true; 549 } 550 551 return false;
552 }; 553 554 $.epoAPI.applyFilter = function( $tag, $value ) { 555 var $args = $.makeArray( arguments ); 556 var priorities; 557 558 $args.splice( 0, 1 ); 559 560 if ( ! $.epoAPI.filters[ $tag ] ) { 561 return $value; 562 } 563 564 priorities = $.epoAPI.filters[ $tag ]; 565 $.each( priorities, function( i, el ) { 566 $.each( el, function( i2, el2 ) { 567 var func = el2.func; 568 569 if ( func instanceof Function ) { 570 $value = func.apply( null, $args ); 571 } else if ( window[ func ] && window[ func ] instanceof Function ) { 572 $value = window[ func ].apply( null, $args ); 573 } 574 } ); 575 } ); 576 577 return $value; 578 }; 579 580 // Backwards compatibility (to be removed in the future) 581 $.tc_add_filter = $.epoAPI.addFilter; 582 $.tc_remove_filter = $.epoAPI.removeFilter; 583 $.tc_apply_filters = $.epoAPI.applyFilter; 584}( window.jQuery ) ); 585 586/* 587 * Formatting functions 588 * 589 * Code modifiled from accounting.js 590 * http://openexchangerates.github.io/accounting.js/ 591 */ 592 593( function( $ ) { 594 'use strict'; 595 596 /** 597 * Check and normalise the value of precision (must be positive integer) 598 * 599 * @param {any} val the value to check. 600 * @param {any} base the value to return is check fails. 601 */ 602 function checkPrecision( val, base ) { 603 val = Math.round( Math.abs( val ) ); 604 return isNaN( val ) ? base : val; 605 } 606 607 /** 608 * Takes a string/array of strings, removes all formatting/cruft 609 * and returns the raw float value. 610 * 611 * @param {any} value the value to unformat. 612 * @param {any} decimal the decimal point. 613 */ 614 function unformat( value, decimal ) { 615 var regex; 616 var unformatted; 617 618 // Recursively unformat arrays: 619 if ( Array.isArray( value ) ) { 620 return value.map( value, function( val ) { 621 return unformat( val, decimal ); 622 } ); 623 } 624 625 // Fails silently (need decent errors): 626 value = value || 0; 627 628 // Return the value as-is if it's already a number: 629 if ( typeof value === 'number' ) { 630 return value; 631 } 632 633 // Default decimal point comes from settings, but could be set to eg. "," in opts: 634 decimal = decimal || '.'; 635 636 // Build regex to strip out everything except digits, decimal point and minus sign: 637 regex = new RegExp( '[^0-9-' + decimal + ']', [ 'g' ] ); 638 unformatted = parseFloat( 639 ( '' + value ) 640 .replace( regex, '' ) // strip out any cruft 641 .replace( decimal, '.' ) // make sure decimal point is standard 642 ); 643 644 // This will fail silently which may cause trouble, let's wait and see: 645 return ! isNaN( unformatted ) ? unformatted : 0; 646 } 647 648 /** 649 * Implementation of toFixed() that treats floats more like decimals 650 * 651 * Fixes binary rounding issues (eg. (0.615).toFixed(2) === "0.61") that present 652 * problems for accounting- and finance-related software. 653 * 654 * @param {any} value the value to convert. 655 * @param {int} precision the precision. 656 */ 657 function toFixed( value, precision ) { 658 var exponentialForm; 659 var rounded; 660 var finalResult; 661 662 if ( ! Number.isFinite( value ) ) { 663 return '-'; 664 } 665 666 precision = checkPrecision( precision, 2 ); 667 668 exponentialForm = Number( unformat( value ) * Math.pow( 10, precision ) ); 669 rounded = Math.round( exponentialForm ); 670 finalResult = Number( rounded / Math.pow( 10, precision ) ).toFixed( precision ); 671 return finalResult; 672 } 673 674 /** 675 * Format into currency or a number, with comma-separated thousands and custom precision/decimal places 676 * 677 * opts = { 678 * symbol: "$", // currency symbol is '$' 679 * format: "%s%v", // controls output: %s = symbol, %v = value (can be object, see docs) 680 * decimal: ".", // decimal point separator 681 * thousand: ",", // thousands separator 682 * precision: 2, // decimal places 683 * } 684 * 685 * @param {any} number the value to convert. 686 * @param {Object} opts the options for formatting. 687 */ 688 function format( number, opts ) { 689 var formats; 690 var useFormat; 691 var negative; 692 var base; 693 var mod; 694 695 // Resursively format arrays: 696 if ( Array.isArray( number ) ) { 697 return number.map( function( val ) { 698 return format( val, opts ); 699 } ); 700 } 701 702 // Clean up number: 703 number = unformat( number ); 704 705 // Do not format if opts are not correct or missing 706 if ( ! opts ) { 707 return number; 708 } 709 710 // Clean up precision 711 opts.precision = checkPrecision( opts.precision ); 712 713 // Format currency 714 if ( opts.format && opts.symbol ) { 715 // Check format (returns object with pos, neg and zero): 716 formats = { 717 pos: opts.format, 718 neg: opts.format.replace( '-', '' ).replace( '%v', '-%v' ), 719 zero: opts.format 720 }; 721 722 // Choose which format to use for this value: 723 useFormat = number > 0 ? formats.pos : number < 0 ? formats.neg : formats.zero; 724 725 // Return with currency symbol added: 726 opts.opts = { 727 precision: opts.precision,
728 thousand: opts.thousand, 729 decimal: opts.decimal 730 }; 731 732 number = useFormat.replace( '%s', opts.symbol ).replace( '%v', format( Math.abs( number ), opts.opts ) ); 733 734 // Format number 735 } else { 736 if ( ! Number.isFinite( number ) ) { 737 return '-'; 738 } 739 // Do some calc: 740 negative = number < 0 ? '-' : ''; 741 base = parseInt( toFixed( Math.abs( number || 0 ), opts.precision ), 10 ) + ''; 742 mod = base.length > 3 ? base.length % 3 : 0; 743 744 // Format the number: 745 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 ] : '' ); 746 } 747 748 return number; 749 } 750 751 $.epoAPI.math.unformat = unformat; 752 $.epoAPI.math.format = format; 753 $.epoAPI.math.toFixed = toFixed; 754}( window.jQuery ) ); 755 756/** 757 * 3. ThemeComplete jQuery extensions 758 * 759 * @param {Object} $ The jQuery object. 760 */ 761( function( $ ) { 762 'use strict'; 763 764 var expo; 765 var rCRLF = /\r?\n/g; 766 var rcheckableType = /^(?:checkbox|radio)$/i; 767 var rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i; 768 var rsubmittable = /^(?:input|select|textarea|keygen)/i; 769 770 // Extend jQuery easing 771 if ( ! $.easing.easeInExpo ) { 772 expo = function( p ) { 773 return Math.pow( p, 6 ); 774 }; 775 $.easing.easeInExpo = expo; 776 $.easing.easeOutExpo = function( p ) { 777 return 1 - expo( 1 - p ); 778 }; 779 $.easing.easeInOutExpo = function( p ) { 780 return p < 0.5 ? expo( p * 2 ) / 2 : 1 - ( expo( ( p * -2 ) + 2 ) / 2 ); 781 }; 782 } 783 784 // Add jQuery plugins 785 $.fn.extend( { 786 // Create checkbox switch 787 tmcheckboxes: function() { 788 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' ); 789 tm_settings_wrap_checkbox.wrap( '<label class="tm-epo-switch-wrapper-label"></label>' ); 790 tm_settings_wrap_checkbox.wrap( '<span class="tm-epo-switch-wrapper tc"></span>' ); 791 tm_settings_wrap_checkbox.after( '<span class="tc-label tm-epo-switch tc"></span>' ); 792 return this; 793 }, 794 795 // Encode a set of HTML elements as an array of names and values. 796 // Elements do not need to be inside a form 797 tcSerializeArray: function() { 798 return this.find( ':input' ) 799 .filter( function() { 800 var type = this.type; 801 802 // Use .is( ":disabled" ) so that fieldset[disabled] works 803 return this.name && ! $( this ).is( ':disabled' ) && rsubmittable.test( this.nodeName ) && ! rsubmitterTypes.test( type ) && ( this.checked || ! rcheckableType.test( type ) ); 804 } ) 805 .map( function( i, elem ) { 806 var val = $( this ).val(); 807 808 if ( val === null ) { 809 return null; 810 } 811 812 if ( Array.isArray( val ) ) { 813 return $.map( val, function( thisval ) { 814 return { name: elem.name, value: thisval.replace( rCRLF, '\r\n' ) }; 815 } ); 816 } 817 818 return { name: elem.name, value: val.replace( rCRLF, '\r\n' ) }; 819 } ) 820 .get(); 821 }, 822 823 // convert element to a valid JSON object 824 tcSerializeObject: function() { 825 var o = {}; 826 var a = this.tcSerializeArray(); 827 828 $.each( a, function() { 829 var name = this.name; 830 var value = this.value || ''; 831 832 if ( name.endsWith( '[]' ) ) { 833 if ( ! o[ name ] ) { 834 o[ name ] = []; 835 } 836 o[ name ].push( value ); 837 } else { 838 o[ name ] = value; 839 } 840 } ); 841 842 return o; 843 }, 844 845 // Scroll container to a specific element 846 tcScrollTo: function( obj, duration, offset ) { 847 var element = this; 848 849 obj = $( obj ); 850 if ( obj.length === 0 ) { 851 return this; 852 } 853 if ( ! duration ) { 854 duration = 0; 855 } 856 if ( ! offset ) { 857 offset = 0; 858 } 859 if ( element[ 0 ].self === window ) { 860 element = $( 'html, body' ); 861 } else { 862 if ( element.find( '.woodmart-scroll-content' ).length ) { 863 element = element.find( '.woodmart-scroll-content' ); 864 } 865 if ( ! element.offset() ) { 866 element = $( 'html, body' ); 867 } else { 868 offset = offset + ( element.scrollTop() - element.offset().top ); 869 } 870 } 871 872 return element.animate( 873 { 874 scrollTop: $( obj ).offset().top + offset 875 }, 876 duration 877 ); 878 }, 879 880 /** 881 * Textarea and select clone() bug workaround | Spencer Tipping 882 * Licensed under the terms of the MIT source code license 883 * https://github.com/spencertipping/jquery.fix.clone/blob/master/jquery.fix.clone.js 884 */ 885 tcClone: function() { 886 var i; 887 var l; 888 var j; 889 var m; 890 var result = $.fn.clone.apply( this, arguments ); 891 var textareas = this.find( 'textarea' ).add( this.filter( 'textarea' ) ); 892 var resultTextareas = result.find( 'textarea' ).add( result.filter( 'textarea' ) ); 893 var selects = this.find( 'select' ).add( this.filter( 'select' ) ); 894 var resultSelects = result.find( 'select' ).add( result.filter( 'select' ) ); 895 896 for ( i = 0, l = textareas.length; i < l; i += 1 ) { 897 $( resultTextareas[ i ] ).val( $( textareas[ i ] ).val() ); 898 } 899 for ( i = 0, l = selects.length; i < l; i += 1 ) { 900 for ( j = 0, m = selects[ i ].options.length; j < m; j += 1 ) { 901 if ( selects[ i ].options[ j ].selected === true ) { 902 resultSelects[ i ].options[ j ].selected = true; 903 } 904 } 905 } 906 907 return result; 908 } 909 } ); 910}( window.jQuery ) ); 911; 912/** 913 * jquery.tcfloatbox.js 914 * 915 * @param {Object} $ The jQuery object 916 * @version: v2.0 917 * @author: ThemeComplete 918 * 919 * Created by ThemeComplete 920 * 921 * Copyright (c) 2025 themeComplete http://themecomplete.com 922 */ 923( function( $ ) { 924 'use strict'; 925 926 var FloatBox = function( dom, options ) { 927 this.element = $( dom ); 928 929 this.settings = $.extend( {}, $.fn.tcFloatBox.defaults, options ); 930 this.settings.type = '<' + this.settings.type + '>'; 931 932 if ( this.element.length === 1 ) { 933 this.init(); 934 return this; 935 } 936 937 return false;
938 }; 939 940 FloatBox.prototype = { 941 constructor: FloatBox, 942 943 destroy: function() { 944 var settings = this.settings; 945 946 if ( this.instance !== undefined ) { 947 $.fn.tcFloatBox.instances.splice( this.instance, 1 ); 948 949 delete this.instance; 950 951 if ( settings.hideelements ) { 952 $( 'embed, object, select' ).css( { 953 visibility: 'visible' 954 } ); 955 } 956 957 if ( settings._ovl ) { 958 settings._ovl.off(); 959 } 960 961 $( settings.floatboxIDMain ).remove(); 962 963 this.element.removeData( 'tcfloatbox' ); 964 965 $( window ).off( 'scroll.tcfloatbox' + this.instance ); 966 $( window ).off( 'resize.tcfloatbox' + this.instance ); 967 } 968 969 return this; 970 }, 971 972 hide: function() { 973 var settings = this.settings; 974 975 if ( settings.hideelements ) { 976 $( 'embed, object, select' ).css( { 977 visibility: 'visible' 978 } ); 979 } 980 if ( settings.showoverlay === true ) { 981 if ( settings._ovl ) { 982 settings._ovl.removeClass( 'fl-overlay' ); 983 } 984 } 985 986 $( settings.floatboxID ) 987 .addClass( 'tc-closing' ) 988 .removeClass( settings.animateIn ) 989 .addClass( settings.animateOut ); 990 $( settings.floatboxID ).animate( 991 { 992 opacity: 0 993 }, 994 settings.closefadeouttime, 995 function() { 996 $( settings.floatboxIDMain ).hide(); 997 $( settings.floatboxID ) 998 .removeClass( 'tc-closing' ) 999 .addClass( 'tc-closed' ); 1000 } 1001 ); 1002 1003 $( window ).off( 'scroll.tcfloatbox' + this.instance ); 1004 $( window ).off( 'resize.tcfloatbox' + this.instance ); 1005 }, 1006 1007 show: function() { 1008 var settings = this.settings; 1009 1010 if ( this.element.length === 1 ) { 1011 if ( this.instance === undefined ) { 1012 this.init(); 1013 } 1014 1015 if ( settings.hideelements ) { 1016 $( 'embed, object, select' ).css( { 1017 visibility: 'hidden' 1018 } ); 1019 } 1020 1021 if ( settings.showoverlay === true ) { 1022 if ( ! settings._ovl ) { 1023 settings._ovl = settings.main; 1024 settings._ovl.css( 1025 { 1026 zIndex: parseInt( settings.zIndex, 10 ) - 1 1027 } 1028 ); 1029 if ( ! settings.ismodal ) { 1030 if ( settings.cancelEvent || settings.unique ) { 1031 settings._ovl.on( 1032 'click', 1033 function( e ) { 1034 if ( e.target === $( settings.floatboxID )[ 0 ] || $( e.target ).closest( settings.floatboxID ).length ) { 1035 return; 1036 } 1037 this.applyCancelEvent.call( this, this ); 1038 }.bind( this ) 1039 ); 1040 } else { 1041 settings._ovl.on( 1042 'click', 1043 function( e ) { 1044 if ( e.target === $( settings.floatboxID )[ 0 ] || $( e.target ).closest( settings.floatboxID ).length ) { 1045 return; 1046 } 1047 settings.cancelfunc.call( this, this ); 1048 }.bind( this ) 1049 ); 1050 } 1051 } 1052 } 1053 settings._ovl.addClass( 'fl-overlay' ); 1054 } 1055 1056 if ( settings.showfunc ) { 1057 settings.showfunc.call(); 1058 } 1059 1060 $( settings.floatboxID ) 1061 .removeClass( 'tc-closing tc-closed' ) 1062 .addClass( 1063 settings.animationBaseClass + ' ' + settings.animateIn 1064 ); 1065 1066 $( settings.floatboxID ).addClass( 'flasho-center' ); 1067 } 1068 }, 1069 1070 applyCancelEvent: function() { 1071 var settings = this.settings; 1072 1073 if ( settings.cancelEvent === true ) { 1074 this.destroy(); 1075 } else if ( typeof settings.cancelEvent === 'function' ) { 1076 settings.cancelEvent.call( this, this ); 1077 } 1078 }, 1079 1080 applyCancelEventFromKey: function( e ) { 1081 if ( e.which === 27 ) { 1082 this.applyCancelEvent(); 1083 } 1084 }, 1085 1086 applyUpdateEvent: function() { 1087 var settings = this.settings; 1088 1089 if ( typeof settings.updateEvent === 'function' ) { 1090 settings.updateEvent.call( this, this ); 1091 } 1092 }, 1093 1094 applyUpdateEventFromKey: function( e ) { 1095 if ( e.which === 13 ) { 1096 this.applyUpdateEvent(); 1097 } 1098 }, 1099 1100 init: function() { 1101 var settings = this.settings; 1102 var main; 1103 1104 if ( this.element.length === 1 ) { 1105 // Instance initialization 1106 if ( $.fn.tcFloatBox.instances.length > 0 ) { 1107 settings.zIndex = 1108 parseInt( 1109 $.fn.tcFloatBox.instances[ 1110 $.fn.tcFloatBox.instances.length - 1 1111 ].zIndex, 1112 10 1113 ) + 100; 1114 } 1115 this.instance = $.fn.tcFloatBox.instances.length; 1116 $.fn.tcFloatBox.instances.push( settings ); 1117 1118 settings.id = settings.id + this.instance; 1119 settings.floatboxID = '#' + $.epoAPI.dom.id( settings.id ); 1120 1121 if ( settings.idMain === settings.id ) { 1122 settings.idMain = 'main-' + settings.idMain; 1123 } 1124 1125 settings.idMain = settings.idMain + this.instance; 1126 settings.floatboxIDMain = '#' + $.epoAPI.dom.id( settings.idMain ); 1127 1128 this.hide(); 1129 1130 main = $( '<div>' ) 1131 .attr( 'id', settings.idMain ) 1132 .addClass( settings.classnameMain ); 1133 1134 $( settings.type ) 1135 .attr( 'id', settings.id ) 1136 .addClass( settings.classname ) 1137 .html( settings.data ) 1138 .appendTo( main ); 1139 1140 main.appendTo( this.element ); 1141 1142 settings.main = main; 1143 1144 if ( settings.leger ) { 1145 $( settings.floatboxIDMain ).css( { 1146 width: settings.width, 1147 height: settings.height 1148 } ); 1149 } else { 1150 $( settings.floatboxID ).css( { 1151 width: settings.width, 1152 height: settings.height 1153 } ); 1154 } 1155 1156 if ( settings.minWidth ) { 1157 $( settings.floatboxID ).css( { 1158 'min-width': settings.minWidth 1159 } ); 1160 } 1161 1162 if ( settings.minHeight ) { 1163 $( settings.floatboxID ).css( { 1164 'min-height': settings.minHeight 1165 } ); 1166 } 1167 1168 if ( settings.maxWidth ) { 1169 $( settings.floatboxID ).css( { 1170 'max-width': settings.maxWidth 1171 } ); 1172 } 1173 1174 if ( settings.maxHeight ) { 1175 $( settings.floatboxID ).css( { 1176 'max-height': settings.maxHeight 1177 } ); 1178 } 1179 1180 $( settings.floatboxIDMain ).css( { 1181 'z-index': settings.zIndex 1182 } ); 1183 1184 this.cancelfunc = settings.cancelfunc; 1185 1186 if ( settings.cancelEvent && settings.cancelClass ) { 1187 $( settings.floatboxID ) 1188 .find( settings.cancelClass ) 1189 .on( 'click', this.applyCancelEvent.bind( this ) ); 1190 if ( settings.isconfirm ) { 1191 $( document ) 1192 .off( 'keyup.escape-' + settings.floatboxID ) 1193 .on( 1194 'keyup.escape-' + settings.floatboxID, 1195 this.applyCancelEventFromKey.bind( this ) 1196 ); 1197 } 1198 } 1199 1200 if ( settings.updateEvent && settings.updateClass ) { 1201 $( settings.floatboxID ) 1202 .find( settings.updateClass ) 1203 .on( 'click', this.applyUpdateEvent.bind( this ) ); 1204 if ( settings.isconfirm ) { 1205 $( document ) 1206 .off( 'keyup.enter-' + settings.floatboxID ) 1207 .on( 1208 'keyup.enter-' + settings.floatboxID, 1209 this.applyUpdateEventFromKey.bind( this ) 1210 ); 1211 } 1212 } 1213 1214 this.show(); 1215 } 1216 } 1217 }; 1218 1219 $.fn.tcFloatBox = function( option ) { 1220 var methodReturn; 1221 var targets = $( this ); 1222 var data = targets.data( 'tcfloatbox' ); 1223 var options; 1224 var ret; 1225 1226 if ( typeof option === 'object' ) { 1227 options = option; 1228 } else { 1229 options = {}; 1230 } 1231 1232 if ( ! data ) { 1233 data = new FloatBox( this, options ); 1234 targets.data( 'tcfloatbox', data ); 1235 } 1236 1237 if ( typeof option === 'string' ) { 1238 methodReturn = data[ option ].apply( data, [] ); 1239 } 1240 1241 if ( methodReturn === undefined ) { 1242 ret = targets; 1243 } else { 1244 ret = methodReturn; 1245 } 1246 1247 return ret; 1248 }; 1249 1250 $.fn.tcFloatBox.defaults = { 1251 idMain: 'floatbox', 1252 classnameMain: 'floatbox', 1253 leger: false, 1254 id: 'flasho', 1255 classname: 'flasho', 1256 type: 'div', 1257 data: '', 1258 width: 'auto', 1259 height: 'auto', 1260 minWidth: 0, 1261 minHeight: 0, 1262 maxWidth: 0, 1263 maxHeight: 0, 1264 closefadeouttime: 1000, 1265 animationBaseClass: 'tm-animated', 1266 animateIn: 'fadein', 1267 animateOut: 'fadeout', 1268 fps: 4, 1269 hideelements: false, 1270 showoverlay: true, 1271 zIndex: 100100, 1272 ismodal: false, 1273 cancelfunc: FloatBox.prototype.hide, 1274 showfunc: null, 1275 cancelEvent: true, 1276 cancelClass: '.floatbox-cancel', 1277 updateEvent: false,
1278 updateClass: false, 1279 unique: true, 1280 isconfirm: false 1281 }; 1282 1283 $.fn.tcFloatBox.instances = []; 1284 1285 $.fn.tcFloatBox.Constructor = FloatBox; 1286 1287 $.tcFloatBox = function( options ) { 1288 var target = $( 'body' ); 1289 var data = false; 1290 var hasAtLeastOneNonToolTip = target 1291 .map( function() { 1292 return $( this ).data( 'tcfloatbox' ) || ''; 1293 } ) 1294 .get() 1295 .some( function( value ) { 1296 return value === ''; 1297 } ); 1298 if ( hasAtLeastOneNonToolTip || options.unique ) { 1299 data = new FloatBox( target, options ); 1300 target.data( 'tcfloatbox', data ); 1301 } else { 1302 data = target.data( 'tcfloatbox' ); 1303 data.init(); 1304 } 1305 return data; 1306 }; 1307}( window.jQuery ) ); 1308; 1309/** 1310 * jquery.tctooltip.js 1311 * 1312 * @param {Window} window - The window object representing the browser window. 1313 * @param {jQuery} $ - The jQuery object. 1314 * @version: v1.1 1315 * @author: themeComplete 1316 * 1317 * Created by themeComplete 1318 * 1319 * Copyright (c) 2021 themeComplete http://themecomplete.com 1320 */ 1321( function( window, $ ) { 1322 'use strict'; 1323 1324 var ToolTip = function( dom, options ) { 1325 this.targets = $( dom ); 1326 1327 this.settings = $.extend( {}, $.fn.tcToolTip.defaults, options ); 1328 1329 if ( this.targets.length > 0 ) { 1330 this.init(); 1331 return this; 1332 } 1333 1334 return false; 1335 }; 1336 1337 var TMEPOJS; 1338 1339 // document ready 1340 $( function() { 1341 TMEPOJS = window.TMEPOJS || { tm_epo_global_tooltip_max_width: '340px' }; 1342 } ); 1343 1344 ToolTip.prototype = { 1345 constructor: ToolTip, 1346 1347 removeTooltip: function( target, tooltip ) { 1348 var settings = this.settings; 1349 1350 if ( target.data( 'is_moving' ) ) { 1351 return; 1352 } 1353 1354 tooltip.removeClass( settings.fadin ).addClass( settings.fadeout ); 1355 1356 tooltip.animate( 1357 { 1358 opacity: 0 1359 }, 1360 settings.speed, 1361 function() { 1362 $( this ).remove(); 1363 } 1364 ); 1365 1366 if ( target.data( 'tmtip-title' ) && target.data( 'tm-tip-html' ) === undefined && ! target.attr( 'data-tm-tooltip-html' ) ) { 1367 target.attr( 'title', target.data( 'tmtip-title' ) ); 1368 } 1369 1370 $( window ).off( 'scroll.tcToolTip resize.tcToolTip' ); 1371 1372 if ( settings.onetime ) { 1373 this.destroy(); 1374 } 1375 }, 1376 1377 initTooltip: function( target, tooltip, nofx ) { 1378 var settings = this.settings; 1379 var tip; 1380 var scroll; 1381 var pos_left; 1382 var pos_top; 1383 var pos_from_top; 1384 var original_pos_left; 1385 1386 if ( target && tooltip && target.length === 1 && tooltip.length === 1 && target.data( 'tm-has-tm-tip' ) === 1 ) { 1387 if ( nofx === 1 ) { 1388 if ( target.data( 'tm-tip-html' ) !== undefined ) { 1389 tip = target.data( 'tm-tip-html' ); 1390 } else if ( target.attr( 'data-tm-tooltip-html' ) ) { 1391 tip = target.attr( 'data-tm-tooltip-html' ); 1392 } else { 1393 tip = target.attr( 'title' ); 1394 } 1395 1396 tooltip.html( tip ); 1397 target.data( 'is_moving', true ); 1398 } 1399 1400 tooltip.find( 'aside' ).hide(); 1401 1402 if ( TMEPOJS.tm_epo_global_tooltip_max_width === '' ) { 1403 // 50: average scrollbar width. Needed to avoid flickering width issues on mobile. 1404 if ( $( window ).width() <= tooltip.outerWidth() * 1.2 ) { 1405 tooltip.css( 'max-width', ( $( window ).width() / 1.2 ) + 'px' ); 1406 } else { 1407 tooltip.css( 'max-width', '340px' ); 1408 } 1409 } else { 1410 if ( TMEPOJS.tm_epo_global_tooltip_max_width.isNumeric() ) { 1411 TMEPOJS.tm_epo_global_tooltip_max_width = TMEPOJS.tm_epo_global_tooltip_max_width + 'px'; 1412 } 1413 tooltip.css( 'max-width', TMEPOJS.tm_epo_global_tooltip_max_width ); 1414 } 1415 1416 tooltip.find( 'aside' ).show(); 1417 1418 tooltip.css( { 1419 left: '', 1420 right: '', 1421 top: '' 1422 } ); 1423 1424 scroll = $.epoAPI.dom.scroll(); 1425 pos_left = target.offset().left + ( target.outerWidth() / 2 ) - ( tooltip.outerWidth() / 2 ); 1426 original_pos_left = pos_left; 1427 1428 if ( pos_left < 0 ) { 1429 pos_left = target.offset().left + ( target.outerWidth() / 2 ) - 20; 1430 tooltip.addClass( 'left' ); 1431 } else { 1432 tooltip.removeClass( 'left' ); 1433 } 1434 if ( original_pos_left >= 0 && pos_left + tooltip.outerWidth() > $( window ).width() ) { 1435 pos_left = target.offset().left - tooltip.outerWidth() + ( target.outerWidth() / 2 ) + 20; 1436 if ( pos_left < 0 ) { 1437 pos_left = pos_left - 10; 1438 tooltip.css( 'max-width', 'calc(' + tooltip.css( 'max-width' ) + ' - ' + Math.abs( pos_left ) + 'px)' ); 1439 pos_left = 10; 1440 } 1441 tooltip.addClass( 'right' ); 1442 } else { 1443 tooltip.removeClass( 'right' ); 1444 } 1445 1446 tooltip.css( { 1447 left: pos_left, 1448 right: 'auto', 1449 top: pos_top 1450 } ); 1451 pos_top = target.offset().top - tooltip.outerHeight() - 10; 1452 pos_from_top = target.offset().top - scroll.top - tooltip.outerHeight() - 10; 1453 1454 if ( pos_top < 0 || pos_from_top < 0 ) { 1455 pos_top = target.offset().top + target.outerHeight() + 10; 1456 tooltip.addClass( 'top' ); 1457 tooltip.removeClass( 'bottom' ); 1458 } else { 1459 tooltip.removeClass( 'top' ); 1460 tooltip.addClass( 'bottom' ); 1461 } 1462 1463 $( window ).trigger( 'tm_tooltip_show' ); 1464 1465 if ( nofx ) { 1466 tooltip.css( { 1467 left: pos_left, 1468 top: pos_top 1469 } ); 1470 target.data( 'is_moving', false ); 1471 } else { 1472 tooltip 1473 .css( { 1474 left: pos_left, 1475 top: pos_top 1476 } ) 1477 .removeClass( settings.fadeout ) 1478 .addClass( settings.fadin ); 1479 } 1480 } 1481 }, 1482 1483 show: function( target ) { 1484 var tooltip; 1485 var tip; 1486 var img; 1487 var settings = this.settings; 1488 1489 if ( target.data( 'is_moving' ) ) { 1490 return; 1491 } 1492 1493 if ( target.data( 'tm-has-tm-tip' ) === 1 ) { 1494 if ( target.data( 'tm-tip-html' ) !== undefined ) { 1495 tip = target.data( 'tm-tip-html' ); 1496 if ( target.attr( 'title' ) ) { 1497 target.data( 'tmtip-title', target.attr( 'title' ) ); 1498 } 1499 target.removeAttr( 'title' ); 1500 } else if ( target.attr( 'data-tm-tooltip-html' ) ) { 1501 tip = target.attr( 'data-tm-tooltip-html' ); 1502 if ( target.attr( 'title' ) ) { 1503 target.data( 'tmtip-title', target.attr( 'title' ) ); 1504 } 1505 target.removeAttr( 'title' ); 1506 } else { 1507 tip = target.attr( 'title' ); 1508 } 1509 1510 if ( tip !== undefined ) { 1511 $( '#tm-tooltip' ).remove(); 1512 if ( ! settings.tipclass ) { 1513 settings.tipclass = ''; 1514 } else { 1515 settings.tipclass = ' ' + settings.tipclass; 1516 } 1517 tooltip = $( '<div id="tm-tooltip" class="tm-tip tm-animated' + settings.tipclass + '"></div>' ); 1518 tooltip.css( 'opacity', 0 ).html( tip ).appendTo( 'body' ); 1519 1520 img = tooltip.find( 'img' ); 1521 if ( img.length > 0 ) { 1522 img.on( 'load', this.initTooltip.bind( this, target, tooltip ) ); 1523 } 1524 1525 this.initTooltip( target, tooltip ); 1526 1527 $( window ).on( 'scroll.tcToolTip resize.tcToolTip', this.initTooltip.bind( this, target, tooltip ) ); 1528 1529 target.data( 'is_moving', false ); 1530 1531 target.on( 'tmmovetooltip', this.initTooltip.bind( this, target, tooltip, 1 ) ); 1532 target.on( 'mouseleave.tc tmhidetooltip', this.removeTooltip.bind( this, target, tooltip ) ); 1533 1534 target.closest( 'label' ).on( 'mouseleave.tc tmhidetooltip', this.removeTooltip.bind( this, target, tooltip ) ); 1535 1536 tooltip.on( 'click', this.removeTooltip.bind( this, target, tooltip ) ); 1537 } 1538 } 1539 1540 return false;
1541 }, 1542 1543 destroy: function() { 1544 if ( this.targets.length > 0 ) { 1545 this.targets.toArray().forEach( function( element ) { 1546 var target = $( element ); 1547 target.closest( 'off' ).on( 'mouseleave.tc tmhidetooltip' ); 1548 target.off( 'tc-tooltip-html-changed tmmovetooltip tmhidetooltip mouseenter.tc mouseleave.tc tmshowtooltip.tc' ); 1549 target.removeData( 'tmtip-title' ); 1550 target.removeData( 'tm-tip-html' ); 1551 } ); 1552 this.targets.removeData( 'tctooltip tm-has-tm-tip is_moving' ); 1553 } 1554 }, 1555 1556 init: function() { 1557 var that = this; 1558 var settings = this.settings; 1559 1560 if ( this.targets.length > 0 ) { 1561 this.targets.toArray().forEach( function( element ) { 1562 var target; 1563 var is_swatch; 1564 var is_swatch_desc; 1565 var is_swatch_lbl_desc; 1566 var is_swatch_img; 1567 var is_swatch_img_lbl; 1568 var is_swatch_img_desc; 1569 var is_swatch_img_lbl_desc; 1570 var tip; 1571 var label; 1572 var desc; 1573 var descHTML; 1574 var get_img_src; 1575 var findlabel; 1576 var is_hide_label; 1577 var findlabelText; 1578 1579 target = $( element ); 1580 tip = settings.tip || undefined; 1581 1582 if ( target.data( 'tm-has-tm-tip' ) === undefined ) { 1583 is_swatch = target.attr( 'data-tm-tooltip-swatch' ); 1584 is_swatch_desc = target.attr( 'data-tm-tooltip-swatch-desc' ); 1585 is_swatch_lbl_desc = target.attr( 'data-tm-tooltip-swatch-lbl-desc' ); 1586 is_swatch_img = target.attr( 'data-tm-tooltip-swatch-img' ); 1587 is_swatch_img_lbl = target.attr( 'data-tm-tooltip-swatch-img-lbl' ); 1588 is_swatch_img_desc = target.attr( 'data-tm-tooltip-swatch-img-desc' ); 1589 is_swatch_img_lbl_desc = target.attr( 'data-tm-tooltip-swatch-img-lbl-desc' ); 1590 1591 target.data( 'tm-has-tm-tip', 1 ); 1592 1593 if ( target.attr( 'data-original' ) !== undefined ) { 1594 get_img_src = target.attr( 'data-original' ); 1595 } else if ( target.attr( 'src' ) !== undefined ) { 1596 if ( target.attr( 'data-src' ) !== undefined ) { 1597 get_img_src = target.attr( 'data-src' ); 1598 } else { 1599 get_img_src = target.attr( 'src' ); 1600 } 1601 } else { 1602 get_img_src = target[ 0 ].src; 1603 } 1604 1605 label = target.closest( '.tmcp-field-wrap' ); 1606 if ( label.is( '.tc-epo-element-product-holder' ) ) { 1607 label = target.closest( '.cpf-element' ); 1608 } 1609 if ( label.length === 0 ) { 1610 label = target.closest( '.cpf-element' ); 1611 } 1612 // If the target is inside a product element and there is a closest section 1613 if ( label.is( '.cpf-type-product' ) && target.closest( '.tm-epo-element-label' ).length === 0 && target.closest( '.cpf-section' ).length ) { 1614 label = target.closest( '.cpf-section' ).find( '.tc-section-inner-wrap .tm-section-description.tm-description' ); 1615 } 1616 if ( label.length === 0 ) { 1617 label = target.closest( '.cpf-section' ).find( '.tc-section-inner-wrap .tm-section-description.tm-description' ); 1618 } 1619 findlabel = label.find( '.tm-tip-html' ); 1620 if ( findlabel.length === 0 ) { 1621 findlabel = label.find( '.checkbox-image-label,.checkbox-image-label-inline,.radio-image-label,.radio-image-label-inline' ); 1622 } 1623 1624 if ( findlabel.length === 0 ) { 1625 findlabel = label.next( '.checkbox-image-label,.checkbox-image-label-inline,.radio-image-label,.radio-image-label-inline,.tm-tip-html' ); 1626 } 1627 if ( findlabel.length === 0 && label.is( '.tm-description' ) ) { 1628 findlabel = label; 1629 } 1630 label = findlabel; 1631 1632 findlabel = $( label ); 1633 findlabelText = findlabel.find( '.tc-label-text' ); 1634 if ( ! findlabelText.length ) { 1635 findlabelText = findlabel; 1636 } 1637 1638 is_hide_label = target.attr( 'data-tm-hide-label' ) === 'yes' || target.attr( 'data-tm-hide-label' ) === undefined || findlabel.is( '.tm-tip-html' ); 1639 1640 descHTML = ''; 1641 desc = target.closest( '.tmcp-field-wrap' ); 1642 desc = desc.find( '[data-tm-tooltip-html]' ); 1643 if ( desc.length === 0 ) { 1644 desc = target.closest( '.tmcp-field-wrap' ).find( '.tc-inline-description' ); 1645 if ( desc.length > 0 ) { 1646 descHTML = desc.html(); 1647 } 1648 } else { 1649 descHTML = desc.attr( 'data-tm-tooltip-html' ); 1650 } 1651 1652 if ( tip === undefined ) { 1653 if ( is_swatch ) { 1654 tip = findlabelText.html(); 1655 } else if ( is_swatch_desc && descHTML !== '' ) { 1656 tip = '<aside>' + descHTML + '</aside>'; 1657 } else if ( is_swatch_lbl_desc && ( findlabelText.html() !== '' || descHTML !== '' ) ) { 1658 tip = '<aside>' + findlabelText.html() + '</aside><aside>' + descHTML + '</aside>'; 1659 } else if ( is_swatch_img && get_img_src !== '' ) { 1660 tip = '<img src="' + get_img_src + '">'; 1661 } else if ( is_swatch_img_lbl && ( findlabelText.html() !== '' || get_img_src !== '' ) ) { 1662 tip = '<img src="' + get_img_src + '"><aside>' + findlabelText.html() + '</aside>'; 1663 } else if ( is_swatch_img_desc && ( get_img_src !== '' || descHTML !== '' ) ) { 1664 tip = '<img src="' + get_img_src + '"><aside>' + descHTML + '</aside>'; 1665 } else if ( is_swatch_img_lbl_desc && ( findlabelText.html() !== '' || get_img_src !== '' || descHTML !== '' ) ) { 1666 tip = '<img src="' + get_img_src + '"><aside>' + findlabelText.html() + '</aside><aside>' + descHTML + '</aside>'; 1667 } 1668 1669 if ( tip !== undefined ) { 1670 target.data( 'tm-tip-html', tip ); 1671 if ( is_hide_label ) { 1672 findlabel.find( '.tm-tooltip' ).remove(); 1673 findlabelText.hide(); 1674 } 1675 } 1676 if ( tip === undefined ) { 1677 // The following two methods are here for dynamic tooltip support 1678 if ( target.attr( 'data-tm-tooltip-html' ) ) { 1679 tip = target.attr( 'data-tm-tooltip-html' ); 1680 } else { 1681 tip = target.attr( 'title' ); 1682 } 1683 } 1684 } else { 1685 target.data( 'tm-tip-html', tip ); 1686 } 1687 1688 target.on( 'tc-tooltip-html-changed', function() { 1689 if ( target.attr( 'data-tm-tooltip-html' ) ) { 1690 target.show(); 1691 } else { 1692 target.hide(); 1693 } 1694 } ); 1695 1696 if ( target.is( 'img' ) ) { 1697 target.closest( 'label' ).on( 'mouseenter tmshowtooltip', that.show.bind( that, target ) ); 1698 } 1699 target.on( 'mouseenter.tc tmshowtooltip.tc', that.show.bind( that, target ) ); 1700 1701 if ( settings.trigger ) { 1702 that.show( target ); 1703 } 1704 } 1705 } ); 1706 } 1707 } 1708 }; 1709 1710 $.fn.tcToolTip = function( option ) { 1711 var methodReturn; 1712 var targets = $( this ); 1713 var data; 1714 var options; 1715 var ret; 1716 var hasAtLeastOneNonToolTip = targets 1717 .map( function() { 1718 return $( this ).data( 'tctooltip' ) || ''; 1719 } ) 1720 .get() 1721 .some( function( value ) { 1722 return value === ''; 1723 } ); 1724 1725 if ( typeof option === 'object' ) { 1726 options = option; 1727 } else { 1728 options = {}; 1729 } 1730 1731 if ( hasAtLeastOneNonToolTip ) { 1732 data = new ToolTip( this, options ); 1733 targets.data( 'tctooltip', data ); 1734 } 1735 1736 if ( typeof option === 'string' ) { 1737 data = targets.data( 'tctooltip' ); 1738 methodReturn = data[ option ].apply( data, [] ); 1739 } 1740 1741 if ( methodReturn === undefined ) { 1742 ret = targets; 1743 } else { 1744 ret = methodReturn; 1745 } 1746 1747 return ret; 1748 }; 1749 1750 $.fn.tcToolTip.defaults = { 1751 fadin: 'fadein', 1752 fadeout: 'fadeout', 1753 speed: 1500 1754 }; 1755 1756 $.fn.tcToolTip.instances = []; 1757 1758 $.fn.tcToolTip.Constructor = ToolTip; 1759 1760 $.tcToolTip = function( targets, options ) { 1761 var data = false;
1762 var hasAtLeastOneNonToolTip; 1763 1764 targets = targets || $( '.tm-tooltip' ); 1765 hasAtLeastOneNonToolTip = targets 1766 .map( function() { 1767 return $( this ).data( 'tctooltip' ) || ''; 1768 } ) 1769 .get() 1770 .some( function( value ) { 1771 return value === ''; 1772 } ); 1773 if ( hasAtLeastOneNonToolTip ) { 1774 data = new ToolTip( targets, options ); 1775 targets.data( 'tctooltip', data ); 1776 } 1777 1778 return data; 1779 }; 1780}( window, window.jQuery ) ); 1781; 1782/*! 1783 * jQuery Validation Plugin v1.19.3 1784 * 1785 * https://jqueryvalidation.org/ 1786 * 1787 * Copyright (c) 2021 Jörn Zaefferer 1788 * Released under the MIT license 1789 * 1790 * Renamed methods for compatibility 1791 * reformatted code by ThemeComplete 1792 */ 1793( function( factory ) { 1794 'use strict'; 1795 if ( typeof window.define === 'function' && window.define.amd ) { 1796 window.define( [ 'jquery' ], factory ); 1797 } else if ( typeof window.module === 'object' && window.module.exports ) { 1798 window.module.exports = factory( window.require( 'jquery' ) ); 1799 } else { 1800 factory( window.jQuery ); 1801 } 1802}( function( $ ) { 1803 'use strict'; 1804 var pendingRequests = {}; 1805 var ajax; 1806 var trim; 1807 1808 $.extend( $.fn, { 1809 // https://jqueryvalidation.org/validate/ 1810 tc_validate: function( options ) { 1811 var tc_validator; 1812 // If nothing is selected, return nothing; can't chain anyway 1813 if ( ! this.length ) { 1814 return; 1815 } 1816 1817 // Check if a tc_validator for this form was already created 1818 tc_validator = $.data( this[ 0 ], 'tc_validator' ); 1819 if ( tc_validator ) { 1820 return tc_validator; 1821 } 1822 1823 // Add novalidate tag if HTML5. 1824 this.attr( 'novalidate', 'novalidate' ); 1825 1826 tc_validator = new $.tc_validator( options, this[ 0 ] ); 1827 $.data( this[ 0 ], 'tc_validator', tc_validator ); 1828 1829 if ( tc_validator.settings.onsubmit ) { 1830 this.on( 'click.tc_validate', ':submit', function( event ) { 1831 // Track the used submit button to properly handle scripted 1832 // submits later. 1833 tc_validator.submitButton = event.currentTarget; 1834 1835 // Allow suppressing validation by adding a cancel class to the submit button 1836 if ( $( this ).hasClass( 'cancel' ) ) { 1837 tc_validator.cancelSubmit = true; 1838 } 1839 1840 // Allow suppressing validation by adding the html5 formnovalidate attribute to the submit button 1841 if ( $( this ).attr( 'formnovalidate' ) !== undefined ) { 1842 tc_validator.cancelSubmit = true; 1843 } 1844 } ); 1845 1846 // Validate the form on submit 1847 this.on( 'submit.tc_validate', function( event ) { 1848 if ( tc_validator.settings.debug ) { 1849 // Prevent form submit to be able to see console output 1850 event.preventDefault(); 1851 } 1852 1853 function handle() { 1854 var hidden; 1855 var result; 1856 1857 // Insert a hidden input as a replacement for the missing submit button 1858 // The hidden input is inserted in two cases: 1859 // - A user defined a `submitHandler` 1860 // - There was a pending request due to `remote` method and `stopRequest()` 1861 // was called to submit the form in case it's valid 1862 if ( tc_validator.submitButton && ( tc_validator.settings.submitHandler || tc_validator.formSubmitted ) ) { 1863 hidden = $( "<input type='hidden'>" ).attr( 'name', tc_validator.submitButton.name ).val( $( tc_validator.submitButton ).val() ).appendTo( tc_validator.currentForm ); 1864 } 1865 1866 if ( tc_validator.settings.submitHandler && ! tc_validator.settings.debug ) { 1867 result = tc_validator.settings.submitHandler.call( tc_validator, tc_validator.currentForm, event ); 1868 if ( hidden ) { 1869 // And clean up afterwards; thanks to no-block-scope, hidden can be referenced 1870 hidden.remove(); 1871 } 1872 if ( result !== undefined ) { 1873 return result; 1874 } 1875 return false; 1876 } 1877 return true; 1878 } 1879 1880 // Prevent submit for invalid forms or custom submit handlers 1881 if ( tc_validator.cancelSubmit ) { 1882 tc_validator.cancelSubmit = false; 1883 return handle(); 1884 } 1885 if ( tc_validator.form() ) { 1886 if ( tc_validator.pendingRequest ) { 1887 tc_validator.formSubmitted = true; 1888 return false; 1889 } 1890 return handle(); 1891 } 1892 tc_validator.focusInvalid(); 1893 return false;
vendor: 5,155 bytes, lines 1894-2076
1894 } ); 1895 } 1896 1897 return tc_validator; 1898 }, 1899 1900 // https://jqueryvalidation.org/valid/ 1901 tc_valid: function() { 1902 var valid; 1903 var tc_validator; 1904 var errorList; 1905 1906 if ( $( this[ 0 ] ).is( 'form' ) ) { 1907 valid = this.tc_validate().form(); 1908 } else { 1909 errorList = []; 1910 valid = true; 1911 tc_validator = $( this[ 0 ].form ).tc_validate(); 1912 this.each( function() { 1913 valid = tc_validator.element( this ) && valid; 1914 if ( ! valid ) { 1915 errorList = errorList.concat( tc_validator.errorList ); 1916 } 1917 } ); 1918 tc_validator.errorList = errorList; 1919 } 1920 return valid; 1921 }, 1922 1923 // https://jqueryvalidation.org/rules/ 1924 tc_rules: function( command, argument ) { 1925 var element = this[ 0 ]; 1926 var isContentEditable = typeof this.attr( 'contenteditable' ) !== 'undefined' && this.attr( 'contenteditable' ) !== 'false'; 1927 var settings; 1928 var staticRules; 1929 var existingRules; 1930 var data; 1931 var param; 1932 var filtered; 1933 1934 // If nothing is selected, return empty object; can't chain anyway 1935 if ( element === null ) { 1936 return; 1937 } 1938 1939 if ( ! element.form && isContentEditable ) { 1940 element.form = this.closest( 'form' )[ 0 ]; 1941 element.name = this.attr( 'name' ); 1942 } 1943 1944 if ( element.form === null ) { 1945 return; 1946 } 1947 1948 if ( command ) { 1949 settings = $.data( element.form, 'tc_validator' ).settings; 1950 staticRules = settings.rules; 1951 existingRules = $.tc_validator.staticRules( element ); 1952 switch ( command ) { 1953 case 'add': 1954 $.extend( existingRules, $.tc_validator.normalizeRule( argument ) ); 1955 1956 // Remove messages from rules, but allow them to be set separately 1957 delete existingRules.messages; 1958 staticRules[ element.name ] = existingRules; 1959 if ( argument.messages ) { 1960 settings.messages[ element.name ] = $.extend( settings.messages[ element.name ], argument.messages ); 1961 } 1962 break; 1963 case 'remove': 1964 if ( ! argument ) { 1965 delete staticRules[ element.name ]; 1966 return existingRules; 1967 } 1968 filtered = {}; 1969 $.each( argument.split( /\s/ ), function( index, method ) { 1970 filtered[ method ] = existingRules[ method ]; 1971 delete existingRules[ method ]; 1972 } ); 1973 return filtered; 1974 } 1975 } 1976 1977 data = $.tc_validator.normalizeRules( $.extend( {}, $.tc_validator.classRules( element ), $.tc_validator.attributeRules( element ), $.tc_validator.dataRules( element ), $.tc_validator.staticRules( element ) ), element ); 1978 1979 // Make sure required is at front 1980 if ( data.required ) { 1981 param = data.required; 1982 delete data.required; 1983 data = $.extend( { required: param }, data ); 1984 } 1985 1986 // Make sure remote is at back 1987 if ( data.remote ) { 1988 param = data.remote; 1989 delete data.remote; 1990 data = $.extend( data, { remote: param } ); 1991 } 1992 1993 return data; 1994 } 1995 } ); 1996 1997 // JQuery trim is deprecated, provide a trim method based on String.prototype.trim 1998 trim = function( str ) { 1999 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim#Polyfill 2000 return str.replace( /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '' ); 2001 }; 2002 // Custom selectors 2003 $.extend( $.expr.pseudos || $.expr[ ':' ], { 2004 // https://jqueryvalidation.org/blank-selector/ 2005 blank: function( a ) { 2006 return ! trim( '' + $( a ).val() ); 2007 }, 2008 2009 // https://jqueryvalidation.org/filled-selector/ 2010 filled: function( a ) { 2011 var val = $( a ).val(); 2012 return val !== null && !! trim( '' + val ); 2013 }, 2014 2015 // https://jqueryvalidation.org/unchecked-selector/ 2016 unchecked: function( a ) { 2017 return ! $( a ).prop( 'checked' ); 2018 } 2019 } ); 2020 2021 // Constructor for tc_validator 2022 $.tc_validator = function( options, form ) { 2023 this.settings = $.extend( true, {}, $.tc_validator.defaults, options ); 2024 this.currentForm = form; 2025 this.init(); 2026 }; 2027 2028 // https://jqueryvalidation.org/jQuery.tc_validator.format/ 2029 $.tc_validator.format = function( source, params ) { 2030 if ( arguments.length === 1 ) { 2031 return function() { 2032 var args = $.makeArray( arguments ); 2033 args.unshift( source ); 2034 return $.tc_validator.format.apply( this, args ); 2035 }; 2036 } 2037 if ( params === undefined ) { 2038 return source; 2039 } 2040 if ( arguments.length > 2 && params.constructor !== Array ) { 2041 params = $.makeArray( arguments ).slice( 1 ); 2042 } 2043 if ( params.constructor !== Array ) { 2044 params = [ params ]; 2045 } 2046 $.each( params, function( i, n ) { 2047 source = source.replace( new RegExp( '\\{' + i + '\\}', 'g' ), function() { 2048 return n; 2049 } ); 2050 } ); 2051 return source; 2052 }; 2053 2054 $.extend( $.tc_validator, { 2055 defaults: { 2056 messages: {}, 2057 groups: {}, 2058 rules: {}, 2059 errorClass: 'error', 2060 pendingClass: 'pending', 2061 validClass: 'valid', 2062 errorElement: 'label', 2063 focusCleanup: false, 2064 focusInvalid: true, 2065 errorContainer: $( [] ), 2066 errorLabelContainer: $( [] ), 2067 onsubmit: true, 2068 ignore: ':hidden', 2069 ignoreTitle: false, 2070 onfocusin: function( element ) { 2071 this.lastActive = element; 2072 2073 // Hide error label and remove error class on focus if enabled 2074 if ( this.settings.focusCleanup ) { 2075 if ( this.settings.unhighlight ) { 2076 this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.val
2076idClass ); 2077 } 2078 this.hideThese( this.errorsFor( element ) ); 2079 } 2080 }, 2081 onfocusout: function( element ) { 2082 if ( ! this.checkable( element ) && ( element.name in this.submitted || ! this.optional( element ) ) ) { 2083 this.element( element ); 2084 } 2085 }, 2086 onkeyup: function( element, event ) { 2087 // Avoid revalidate the field when pressing one of the following keys 2088 // Shift => 16 2089 // Ctrl => 17 2090 // Alt => 18 2091 // Caps lock => 20 2092 // End => 35 2093 // Home => 36 2094 // Left arrow => 37 2095 // Up arrow => 38 2096 // Right arrow => 39 2097 // Down arrow => 40 2098 // Insert => 45 2099 // Num lock => 144 2100 // AltGr key => 225 2101 var excludedKeys = [ 16, 17, 18, 20, 35, 36, 37, 38, 39, 40, 45, 144, 225 ]; 2102 2103 if ( ( event.which === 9 && this.elementValue( element ) === '' ) || $.inArray( event.keyCode, excludedKeys ) !== -1 ) { 2104 2105 } else if ( element.name in this.submitted || element.name in this.invalid ) { 2106 this.element( element ); 2107 } 2108 }, 2109 onclick: function( element ) { 2110 // Click on selects, radiobuttons and checkboxes 2111 if ( element.name in this.submitted ) { 2112 this.element( element ); 2113 2114 // Or option elements, check parent select in that case 2115 } else if ( element.parentNode.name in this.submitted ) { 2116 this.element( element.parentNode ); 2117 } 2118 }, 2119 highlight: function( element, errorClass, validClass ) { 2120 if ( element.type === 'radio' ) { 2121 this.findByName( element.name ).addClass( errorClass ).removeClass( validClass ); 2122 } else { 2123 $( element ).addClass( errorClass ).removeClass( validClass ); 2124 } 2125 }, 2126 unhighlight: function( element, errorClass, validClass ) { 2127 if ( element.type === 'radio' ) { 2128 this.findByName( element.name ).removeClass( errorClass ).addClass( validClass ); 2129 } else { 2130 $( element ).removeClass( errorClass ).addClass( validClass ); 2131 } 2132 } 2133 }, 2134 2135 // https://jqueryvalidation.org/jQuery.tc_validator.setDefaults/ 2136 setDefaults: function( settings ) { 2137 $.extend( $.tc_validator.defaults, settings ); 2138 }, 2139 2140 messages: { 2141 required: 'This field is required.', 2142 remote: 'Please fix this field.', 2143 email: 'Please enter a valid email address.', 2144 url: 'Please enter a valid URL.', 2145 date: 'Please enter a valid date.', 2146 dateISO: 'Please enter a valid date (ISO).', 2147 number: 'Please enter a valid number.', 2148 digits: 'Please enter only digits.', 2149 equalTo: 'Please enter the same value again.', 2150 maxlength: $.tc_validator.format( 'Please enter no more than {0} characters.' ), 2151 maxlengthsingle: $.tc_validator.format( 'Please enter no more than {0} character.' ), 2152 minlength: $.tc_validator.format( 'Please enter at least {0} characters.' ), 2153 minlengthsingle: $.tc_validator.format( 'Please enter at least {0} character.' ), 2154 rangelength: $.tc_validator.format( 'Please enter a value between {0} and {1} characters long.' ), 2155 range: $.tc_validator.format( 'Please enter a value between {0} and {1}.' ), 2156 max: $.tc_validator.format( 'Please enter a value less than or equal to {0}.' ), 2157 min: $.tc_validator.format( 'Please enter a value greater than or equal to {0}.' ), 2158 step: $.tc_validator.format( 'Please enter a multiple of {0}.' ) 2159 }, 2160 2161 autoCreateRanges: false, 2162 2163 prototype: { 2164 init: function() { 2165 var currentForm = this.currentForm; 2166 var groups = {}; 2167 var rules; 2168 2169 this.labelContainer = $( this.settings.errorLabelContainer ); 2170 this.errorContext = ( this.labelContainer.length && this.labelContainer ) || $( this.currentForm ); 2171 this.containers = $( this.settings.errorContainer ).add( this.settings.errorLabelContainer ); 2172 this.submitted = {}; 2173 this.valueCache = {}; 2174 this.pendingRequest = 0; 2175 this.pending = {}; 2176 this.invalid = {}; 2177 this.reset(); 2178 this.groups = {}; 2179 2180 $.each( this.settings.groups, function( key, value ) { 2181 if ( typeof value === 'string' ) { 2182 value = value.split( /\s/ ); 2183 } 2184 $.each( value, function( index, name ) { 2185 groups[ name ] = key; 2186 } ); 2187 } ); 2188 rules = this.settings.rules; 2189 $.each( rules, function( key, value ) { 2190 rules[ key ] = $.tc_validator.normalizeRule( value ); 2191 } ); 2192 2193 function delegate( event ) { 2194 var isContentEditable = typeof $( event.data.that ).attr( 'contenteditable' ) !== 'undefined' && $( event.data.that ).attr( 'contenteditable' ) !== 'false'; 2195 var tc_validator; 2196 var eventType; 2197 var settings; 2198 // Set form expando on contenteditable 2199 if ( ! event.data.that.form && isContentEditable ) { 2200 event.data.that.form = $( event.data.that ).closest( 'form' )[ 0 ]; 2201 event.data.that.name = $( event.data.that ).attr( 'name' ); 2202 } 2203 2204 // Ignore the element if it belongs to another form. This will happen mainly 2205 // when setting the `form` attribute of an input to the id of another form. 2206 if ( currentForm !== event.data.that.form ) { 2207 return; 2208 } 2209 2210 tc_validator = $.data( event.data.that.form, 'tc_validator' ); 2211 eventType = 'on' + event.type.replace( /^validate/, '' ); 2212 settings = tc_validator.settings; 2213 if ( settings[ eventType ] && ! $( event.data.that ).is( settings.ignore ) ) { 2214 settings[ eventType ].call( tc_validator, event.data.that, event ); 2215 } 2216 } 2217 2218 $( this.currentForm ) 2219 .on(
2220 'focusin.tc_validate focusout.tc_validate keyup.tc_validate', 2221 ":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], " + 2222 "[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], " + 2223 "[type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], " + 2224 "[type='radio'], [type='checkbox'], [contenteditable], [type='button']", 2225 { that: this }, 2226 delegate 2227 ) 2228 2229 // Support: Chrome, oldIE 2230 // "select" is provided as event.target when clicking a option 2231 .on( 'click.tc_validate', "select, option, [type='radio'], [type='checkbox']", { that: this }, delegate ); 2232 2233 if ( this.settings.invalidHandler ) { 2234 $( this.currentForm ).on( 'invalid-form.tc_validate', this.settings.invalidHandler ); 2235 } 2236 }, 2237 2238 // https://jqueryvalidation.org/tc_validator.form/ 2239 form: function() { 2240 this.checkForm(); 2241 $.extend( this.submitted, this.errorMap ); 2242 this.invalid = $.extend( {}, this.errorMap ); 2243 if ( ! this.tc_valid() ) { 2244 $( this.currentForm ).triggerHandler( 'invalid-form', [ this ] ); 2245 } 2246 this.showErrors(); 2247 return this.tc_valid(); 2248 }, 2249 2250 checkForm: function() { 2251 var i; 2252 var elements; 2253 this.prepareForm(); 2254 for ( i = 0, elements = this.elements(); elements[ i ]; i += 1 ) { 2255 this.currentElements = elements; 2256 this.check( elements[ i ] ); 2257 } 2258 return this.tc_valid(); 2259 }, 2260 2261 // https://jqueryvalidation.org/tc_validator.element/ 2262 element: function( element ) { 2263 var cleanElement = this.clean( element ), 2264 checkElement = this.validationTargetFor( cleanElement ), 2265 v = this, 2266 result = true, 2267 rs, 2268 group; 2269 2270 if ( checkElement === undefined ) { 2271 delete this.invalid[ cleanElement.name ]; 2272 } else { 2273 this.prepareElement( checkElement ); 2274 this.currentElements = $( checkElement ); 2275 2276 // If this element is grouped, then validate all group elements already 2277 // containing a value 2278 group = this.groups[ checkElement.name ]; 2279 if ( group ) { 2280 $.each( this.groups, function( name, testgroup ) { 2281 if ( testgroup === group && name !== checkElement.name ) { 2282 cleanElement = v.validationTargetFor( v.clean( v.findByName( name ) ) ); 2283 if ( cleanElement && cleanElement.name in v.invalid ) { 2284 v.currentElements.push( cleanElement ); 2285 result = v.check( cleanElement ) && result; 2286 } 2287 } 2288 } ); 2289 } 2290 2291 rs = this.check( checkElement ) !== false; 2292 result = result && rs; 2293 if ( rs ) { 2294 this.invalid[ checkElement.name ] = false; 2295 } else { 2296 this.invalid[ checkElement.name ] = true; 2297 } 2298 2299 if ( ! this.numberOfInvalids() ) { 2300 // Hide error containers on last error 2301 this.toHide = this.toHide.add( this.containers ); 2302 } 2303 this.showErrors(); 2304 2305 // Add aria-invalid status for screen readers 2306 $( element ).attr( 'aria-invalid', ! rs ); 2307 } 2308 2309 return result; 2310 }, 2311 2312 // https://jqueryvalidation.org/tc_validator.showErrors/ 2313 showErrors: function( errors ) { 2314 var tc_validator; 2315 if ( errors ) { 2316 tc_validator = this; 2317 2318 // Add items to error list and map 2319 $.extend( this.errorMap, errors ); 2320 this.errorList = $.map( this.errorMap, function( message, name ) { 2321 return { 2322 message: message, 2323 element: tc_validator.findByName( name )[ 0 ] 2324 }; 2325 } ); 2326 2327 // Remove items from success list 2328 this.successList = $.grep( this.successList, function( element ) { 2329 return ! ( element.name in errors ); 2330 } ); 2331 } 2332 if ( this.settings.showErrors ) { 2333 this.settings.showErrors.call( this, this.errorMap, this.errorList ); 2334 } else { 2335 this.defaultShowErrors(); 2336 } 2337 }, 2338 2339 // https://jqueryvalidation.org/tc_validator.resetForm/ 2340 resetForm: function() { 2341 var elements; 2342 if ( $.fn.resetForm ) { 2343 $( this.currentForm ).resetForm(); 2344 } 2345 this.invalid = {}; 2346 this.submitted = {}; 2347 this.prepareForm(); 2348 this.hideErrors(); 2349 elements = this.elements().removeData( 'previousValue' ).removeAttr( 'aria-invalid' ); 2350 2351 this.resetElements( elements ); 2352 }, 2353 2354 resetElements: function( elements ) { 2355 var i; 2356 2357 if ( this.settings.unhighlight ) { 2358 for ( i = 0; elements[ i ]; i += 1 ) { 2359 this.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, '' ); 2360 this.findByName( elements[ i ].name ).removeClass( this.settings.val
2360idClass ); 2361 } 2362 } else { 2363 elements.removeClass( this.settings.errorClass ).removeClass( this.settings.validClass ); 2364 } 2365 }, 2366 2367 numberOfInvalids: function() { 2368 return this.objectLength( this.invalid ); 2369 }, 2370 2371 objectLength: function( obj ) { 2372 /* jshint unused: false */ 2373 var count = 0, 2374 i; 2375 for ( i in obj ) { 2376 // This check allows counting elements with empty error 2377 // message as invalid elements 2378 if ( obj[ i ] !== undefined && obj[ i ] !== null && obj[ i ] !== false ) { 2379 count += 1; 2380 } 2381 } 2382 return count; 2383 }, 2384 2385 hideErrors: function() { 2386 this.hideThese( this.toHide ); 2387 }, 2388 2389 hideThese: function( errors ) { 2390 errors.not( this.containers ).text( '' ); 2391 this.addWrapper( errors ).hide(); 2392 }, 2393 2394 tc_valid: function() { 2395 return this.size() === 0; 2396 }, 2397 2398 size: function() { 2399 return this.errorList.length; 2400 }, 2401 2402 focusInvalid: function() { 2403 if ( this.settings.focusInvalid ) { 2404 try { 2405 $( this.findLastActive() || ( this.errorList.length && this.errorList[ 0 ].element ) || [] ) 2406 .filter( ':visible' ) 2407 .trigger( 'focus' ) 2408 2409 // Manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find 2410 .trigger( 'focusin' ); 2411 } catch ( e ) { 2412 // Ignore IE throwing errors when focusing hidden elements 2413 } 2414 } 2415 }, 2416 2417 findLastActive: function() { 2418 var lastActive = this.lastActive; 2419 return ( 2420 lastActive && 2421 $.grep( this.errorList, function( n ) { 2422 return n.element.name === lastActive.name; 2423 } ).length === 1 && 2424 lastActive 2425 ); 2426 }, 2427 2428 elements: function() { 2429 var tc_validator = this, 2430 rulesCache = {}; 2431 2432 // Select all valid inputs inside the form (no submit or reset buttons) 2433 return $( this.currentForm ) 2434 .find( 'input, select, textarea, [contenteditable]' ) 2435 .not( ':submit, :reset, :image, :disabled' ) 2436 .not( this.settings.ignore ) 2437 .filter( function() { 2438 var name = this.name || $( this ).attr( 'name' ); // For contenteditable 2439 var isContentEditable = typeof $( this ).attr( 'contenteditable' ) !== 'undefined' && $( this ).attr( 'contenteditable' ) !== 'false'; 2440 2441 // Set form expando on contenteditable 2442 if ( isContentEditable ) { 2443 this.form = $( this ).closest( 'form' )[ 0 ]; 2444 this.name = name; 2445 } 2446 2447 // Ignore elements that belong to other/nested forms 2448 if ( this.form !== tc_validator.currentForm ) { 2449 return false; 2450 } 2451 2452 // Select only the first element for each name, and only those with rules specified 2453 if ( name in rulesCache || ! tc_validator.objectLength( $( this ).tc_rules() ) ) { 2454 return false; 2455 } 2456 2457 rulesCache[ name ] = true; 2458 return true; 2459 } ); 2460 }, 2461 2462 clean: function( selector ) { 2463 return $( selector )[ 0 ]; 2464 }, 2465 2466 errors: function() { 2467 var errorClass = this.settings.errorClass.split( ' ' ).join( '.' ); 2468 return $( this.settings.errorElement + '.' + errorClass, this.errorContext ); 2469 }, 2470 2471 resetInternals: function() { 2472 this.successList = []; 2473 this.errorList = []; 2474 this.errorMap = {}; 2475 this.toShow = $( [] ); 2476 this.toHide = $( [] ); 2477 }, 2478 2479 reset: function() { 2480 this.resetInternals(); 2481 this.currentElements = $( [] ); 2482 }, 2483 2484 prepareForm: function() { 2485 this.reset(); 2486 this.toHide = this.errors().add( this.containers ); 2487 }, 2488 2489 prepareElement: function( element ) { 2490 this.reset(); 2491 this.toHide = this.errorsFor( element ); 2492 }, 2493 2494 elementValue: function( element ) { 2495 var $element = $( element ), 2496 type = element.type, 2497 isContentEditable = typeof $element.attr( 'contenteditable' ) !== 'undefined' && $element.attr( 'contenteditable' ) !== 'false', 2498 val, 2499 idx; 2500 2501 if ( type === 'radio' || type === 'checkbox' ) { 2502 return this.findByName( element.name ).filter( ':checked' ).val(); 2503 } else if ( type === 'number' && typeof element.validity !== 'undefined' ) { 2504 return element.validity.badInput ? 'NaN' : $element.val(); 2505 } 2506 2507 if ( isContentEditable ) { 2508 val = $element.text(); 2509 } else { 2510 val = $element.val(); 2511 } 2512 2513 if ( type === 'file' ) { 2514 // Modern browser (chrome & safari) 2515 if ( val.substring( 0, 12 ) === 'C:\\fakepath\\' ) { 2516 return val.substring( 12 ); 2517 } 2518 2519 // Legacy browsers 2520 // Unix-based path 2521 idx = val.lastIndexOf( '/' ); 2522 if ( idx >= 0 ) { 2523 return val.substring( idx + 1 ); 2524 } 2525 2526 // Windows-based path 2527 idx = val.lastIndexOf( '\\' ); 2528 if ( idx >= 0 ) { 2529 return val.substring( idx + 1 ); 2530 } 2531 2532 // Just the file name 2533 return val; 2534 } 2535 2536 if ( typeof val === 'string' ) { 2537 return val.replace( /\r/g, '' ); 2538 } 2539 return val; 2540 }, 2541 2542 check: function( element ) { 2543 var rules; 2544 var rulesCount; 2545 var dependencyMismatch; 2546 var val; 2547 var result; 2548 var method; 2549 var rule; 2550 var normalizer; 2551 2552 element = this.validationTargetFor( this.clean( element ) ); 2553 2554 rules = $( element ).tc_rules(); 2555 rulesCount = $.map( rules, function( n, i ) { 2556 return i; 2557 } ).length; 2558 dependencyMismatch = false;
2559 val = this.elementValue( element ); 2560 2561 // Prioritize the local normalizer defined for this element over the global one 2562 // if the former exists, otherwise user the global one in case it exists. 2563 if ( typeof rules.normalizer === 'function' ) { 2564 normalizer = rules.normalizer; 2565 } else if ( typeof this.settings.normalizer === 'function' ) { 2566 normalizer = this.settings.normalizer; 2567 } 2568 2569 // If normalizer is defined, then call it to retreive the changed value instead 2570 // of using the real one. 2571 // Note that `this` in the normalizer is `element`. 2572 if ( normalizer ) { 2573 val = normalizer.call( element, val ); 2574 2575 // Delete the normalizer from rules to avoid treating it as a pre-defined method. 2576 delete rules.normalizer; 2577 } 2578 2579 for ( method in rules ) { 2580 if ( method ) { 2581 rule = { method: method, parameters: rules[ method ] }; 2582 try { 2583 result = $.tc_validator.methods[ method ].call( this, val, element, rule.parameters ); 2584 2585 // If a method indicates that the field is optional and therefore valid, 2586 // don't mark it as valid when there are no other rules 2587 if ( result === 'dependency-mismatch' && rulesCount === 1 ) { 2588 dependencyMismatch = true; 2589 continue; 2590 } 2591 dependencyMismatch = false; 2592 2593 if ( result === 'pending' ) { 2594 this.toHide = this.toHide.not( this.errorsFor( element ) ); 2595 return; 2596 } 2597 2598 if ( ! result ) { 2599 this.formatAndAdd( element, rule ); 2600 return false; 2601 } 2602 } catch ( e ) { 2603 if ( e instanceof TypeError ) { 2604 e.message += '. Exception occurred when checking element ' + element.id + ", check the '" + rule.method + "' method."; 2605 } 2606 2607 throw e; 2608 } 2609 } 2610 } 2611 if ( dependencyMismatch ) { 2612 return; 2613 } 2614 if ( this.objectLength( rules ) ) { 2615 this.successList.push( element ); 2616 } 2617 return true; 2618 }, 2619 2620 // Return the custom message for the given element and validation method 2621 // specified in the element's HTML5 data attribute 2622 // return the generic message if present and no method specific message is present 2623 customDataMessage: function( element, method ) { 2624 return $( element ).data( 'msg' + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() ) || $( element ).data( 'msg' ); 2625 }, 2626 2627 // Return the custom message for the given element name and validation method 2628 customMessage: function( name, method ) { 2629 var m = this.settings.messages[ name ]; 2630 return m && ( m.constructor === String ? m : m[ method ] ); 2631 }, 2632 2633 // Return the first defined argument, allowing empty strings 2634 findDefined: function() { 2635 var i; 2636 for ( i = 0; i < arguments.length; i += 1 ) { 2637 if ( arguments[ i ] !== undefined ) { 2638 return arguments[ i ]; 2639 } 2640 } 2641 return undefined; 2642 }, 2643 2644 // The second parameter 'rule' used to be a string, and extended to an object literal 2645 // of the following form: 2646 // rule = { 2647 // method: "method name", 2648 // parameters: "the given method parameters" 2649 // } 2650 // 2651 // The old behavior still supported, kept to maintain backward compatibility with 2652 // old code, and will be removed in the next major release. 2653 defaultMessage: function( element, rule ) { 2654 var message; 2655 var theregex; 2656 var singleCheck = ''; 2657 2658 if ( typeof rule === 'string' ) { 2659 rule = { method: rule }; 2660 } 2661 2662 if ( rule.method === 'minlength' || rule.method === 'maxlength' ) { 2663 if ( rule.parameters === 1 || rule.parameters === '1' ) { 2664 singleCheck = 'single'; 2665 } 2666 } 2667 2668 message = this.findDefined( 2669 this.customMessage( element.name, rule.method + singleCheck ), 2670 this.customDataMessage( element, rule.method + singleCheck ), 2671 2672 // 'title' is never undefined, so handle empty string as undefined 2673 ( ! this.settings.ignoreTitle && element.title ) || undefined, 2674 $.tc_validator.messages[ rule.method + singleCheck ], 2675 '<strong>Warning: No message defined for ' + element.name + '</strong>' 2676 ); 2677 theregex = /\$?\{(\d+)\}/g; 2678 if ( typeof message === 'function' ) { 2679 message = message.call( this, rule.parameters, element ); 2680 } else if ( theregex.test( message ) ) { 2681 message = $.tc_validator.format( message.replace( theregex, '{$1}' ), rule.parameters ); 2682 } 2683 2684 return message; 2685 }, 2686 2687 formatAndAdd: function( element, rule ) { 2688 var message = this.defaultMessage( element, rule ); 2689 2690 this.errorList.push( { 2691 message: message, 2692 element: element, 2693 method: rule.method 2694 } ); 2695 2696 this.errorMap[ element.name ] = message; 2697 this.submitted[ element.name ] = message; 2698 }, 2699 2700 addWrapper: function( toToggle ) { 2701 if ( this.settings.wrapper ) { 2702 toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) ); 2703 } 2704 return toToggle; 2705 }, 2706 2707 defaultShowErrors: function() { 2708 var i, elements, error; 2709 for ( i = 0; this.errorList[ i ]; i += 1 ) { 2710 error = this.errorList[ i ]; 2711 if ( this.settings.highlight ) { 2712 this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.val
2712idClass ); 2713 } 2714 this.showLabel( error.element, error.message ); 2715 } 2716 if ( this.errorList.length ) { 2717 this.toShow = this.toShow.add( this.containers ); 2718 } 2719 if ( this.settings.success ) { 2720 for ( i = 0; this.successList[ i ]; i += 1 ) { 2721 this.showLabel( this.successList[ i ] ); 2722 } 2723 } 2724 if ( this.settings.unhighlight ) { 2725 for ( i = 0, elements = this.validElements(); elements[ i ]; i += 1 ) { 2726 this.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, this.settings.validClass ); 2727 } 2728 } 2729 this.toHide = this.toHide.not( this.toShow ); 2730 this.hideErrors(); 2731 this.addWrapper( this.toShow ).show(); 2732 }, 2733 2734 validElements: function() { 2735 return this.currentElements.not( this.invalidElements() ); 2736 }, 2737 2738 invalidElements: function() { 2739 return $( this.errorList ).map( function() { 2740 return this.element; 2741 } ); 2742 }, 2743 2744 showLabel: function( element, message ) { 2745 var place, 2746 group, 2747 errorID, 2748 v, 2749 error = this.errorsFor( element ), 2750 elementID = this.idOrName( element ), 2751 describedBy = $( element ).attr( 'aria-describedby' ); 2752 2753 if ( error.length ) { 2754 // Refresh error/success class 2755 error.removeClass( this.settings.validClass ).addClass( this.settings.errorClass ); 2756 2757 // Replace message on existing label 2758 error.html( message ); 2759 } else { 2760 // Create error element 2761 error = $( '<' + this.settings.errorElement + '>' ) 2762 .attr( 'id', elementID + '-error' ) 2763 .addClass( this.settings.errorClass ) 2764 .html( message || '' ); 2765 2766 // Maintain reference to the element to be placed into the DOM 2767 place = error; 2768 if ( this.settings.wrapper ) { 2769 // Make sure the element is visible, even in IE 2770 // actually showing the wrapped element is handled elsewhere 2771 place = error 2772 .hide() 2773 .show() 2774 .wrap( '<' + this.settings.wrapper + '/>' ) 2775 .parent(); 2776 } 2777 if ( this.labelContainer.length ) { 2778 this.labelContainer.append( place ); 2779 } else if ( this.settings.errorPlacement ) { 2780 this.settings.errorPlacement.call( this, place, $( element ) ); 2781 } else { 2782 place.insertAfter( element ); 2783 } 2784 2785 // Link error back to the element 2786 if ( error.is( 'label' ) ) { 2787 // If the error is a label, then associate using 'for' 2788 error.attr( 'for', elementID ); 2789 2790 // If the element is not a child of an associated label, then it's necessary 2791 // to explicitly apply aria-describedby 2792 } else if ( error.parents( "label[for='" + this.escapeCssMeta( elementID ) + "']" ).length === 0 ) { 2793 errorID = error.attr( 'id' ); 2794 2795 // Respect existing non-error aria-describedby 2796 if ( ! describedBy ) { 2797 describedBy = errorID; 2798 } else if ( ! describedBy.match( new RegExp( '\\b' + this.escapeCssMeta( errorID ) + '\\b' ) ) ) { 2799 // Add to end of list if not already present 2800 describedBy += ' ' + errorID; 2801 } 2802 $( element ).attr( 'aria-describedby', describedBy ); 2803 2804 // If this element is grouped, then assign to all elements in the same group 2805 group = this.groups[ element.name ]; 2806 if ( group ) { 2807 v = this; 2808 $.each( v.groups, function( name, testgroup ) { 2809 if ( testgroup === group ) { 2810 $( "[name='" + v.escapeCssMeta( name ) + "']", v.currentForm ).attr( 'aria-describedby', error.attr( 'id' ) ); 2811 } 2812 } ); 2813 } 2814 } 2815 } 2816 if ( ! message && this.settings.success ) { 2817 error.text( '' ); 2818 if ( typeof this.settings.success === 'string' ) { 2819 error.addClass( this.settings.success ); 2820 } else { 2821 this.settings.success( error, element ); 2822 } 2823 } 2824 this.toShow = this.toShow.add( error ); 2825 }, 2826 2827 errorsFor: function( element ) { 2828 var name = this.escapeCssMeta( this.idOrName( element ) ), 2829 describer = $( element ).attr( 'aria-describedby' ), 2830 selector = "label[for='" + name + "'], label[for='" + name + "'] *"; 2831 2832 // 'aria-describedby' should directly reference the error element 2833 if ( describer ) { 2834 selector = selector + ', #' + this.escapeCssMeta( describer ).replace( /\s+/g, ', #' ); 2835 } 2836 2837 return this.errors().filter( selector ); 2838 }, 2839 2840 // See https://api.jquery.com/category/selectors/, for CSS 2841 // meta-characters that should be escaped in order to be used with JQuery 2842 // as a literal part of a name/id or any selector. 2843 escapeCssMeta: function( string ) { 2844 // eslint-disable-next-line no-useless-escape 2845 return string.replace( /([\\!"#$%&'()*+,.\/:;<=>?@\[\]\^`{|}~])/g, '\\$1' ); 2846 }, 2847 2848 idOrName: function( element ) { 2849 return this.groups[ element.name ] || ( this.checkable( element ) ? element.name : element.i
2849d || element.name ); 2850 }, 2851 2852 validationTargetFor: function( element ) { 2853 // If radio/checkbox, validate first element in group instead 2854 if ( this.checkable( element ) ) { 2855 element = this.findByName( element.name ); 2856 } 2857 2858 // Always apply ignore filter 2859 return $( element ).not( this.settings.ignore )[ 0 ]; 2860 }, 2861 2862 checkable: function( element ) { 2863 return /radio|checkbox/i.test( element.type ); 2864 }, 2865 2866 findByName: function( name ) { 2867 return $( this.currentForm ).find( "[name='" + this.escapeCssMeta( name ) + "']" ); 2868 }, 2869 2870 getLength: function( value, element ) { 2871 switch ( element.nodeName.toLowerCase() ) { 2872 case 'select': 2873 return $( 'option:selected', element ).length; 2874 case 'input': 2875 if ( this.checkable( element ) ) { 2876 return this.findByName( element.name ).filter( ':checked' ).length; 2877 } 2878 } 2879 return value.length; 2880 }, 2881 2882 depend: function( param, element ) { 2883 return this.dependTypes[ typeof param ] ? this.dependTypes[ typeof param ]( param, element ) : true; 2884 }, 2885 2886 dependTypes: { 2887 boolean: function( param ) { 2888 return param; 2889 }, 2890 string: function( param, element ) { 2891 return !! $( param, element.form ).length; 2892 }, 2893 function: function( param, element ) { 2894 return param( element ); 2895 } 2896 }, 2897 2898 optional: function( element ) { 2899 var val = this.elementValue( element ); 2900 return ! $.tc_validator.methods.required.call( this, val, element ) && 'dependency-mismatch'; 2901 }, 2902 2903 startRequest: function( element ) { 2904 if ( ! this.pending[ element.name ] ) { 2905 this.pendingRequest += 1; 2906 $( element ).addClass( this.settings.pendingClass ); 2907 this.pending[ element.name ] = true; 2908 } 2909 }, 2910 2911 stopRequest: function( element, valid ) { 2912 this.pendingRequest -= 1; 2913 2914 // Sometimes synchronization fails, make sure pendingRequest is never < 0 2915 if ( this.pendingRequest < 0 ) { 2916 this.pendingRequest = 0; 2917 } 2918 delete this.pending[ element.name ]; 2919 $( element ).removeClass( this.settings.pendingClass ); 2920 if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) { 2921 $( this.currentForm ).trigger( 'submit' ); 2922 2923 // Remove the hidden input that was used as a replacement for the 2924 // missing submit button. The hidden input is added by `handle()` 2925 // to ensure that the value of the used submit button is passed on 2926 // for scripted submits triggered by this method 2927 if ( this.submitButton ) { 2928 $( "input:hidden[name='" + this.submitButton.name + "']", this.currentForm ).remove(); 2929 } 2930 2931 this.formSubmitted = false; 2932 } else if ( ! valid && this.pendingRequest === 0 && this.formSubmitted ) { 2933 $( this.currentForm ).triggerHandler( 'invalid-form', [ this ] ); 2934 this.formSubmitted = false; 2935 } 2936 }, 2937 2938 previousValue: function( element, method ) { 2939 method = ( typeof method === 'string' && method ) || 'remote'; 2940 2941 return ( 2942 $.data( element, 'previousValue' ) || 2943 $.data( element, 'previousValue', { 2944 old: null, 2945 valid: true, 2946 message: this.defaultMessage( element, { method: method } ) 2947 } ) 2948 ); 2949 }, 2950 2951 // Cleans up all forms and elements, removes tc_validator-specific events 2952 destroy: function() { 2953 this.resetForm(); 2954 2955 $( this.currentForm ) 2956 .off( '.tc_validate' ) 2957 .removeData( 'tc_validator' ) 2958 .find( '.tc_validate-equalTo-blur' ) 2959 .off( '.tc_validate-equalTo' ) 2960 .removeClass( 'validate-equalTo-blur' ) 2961 .find( '.tc_validate-lessThan-blur' ) 2962 .off( '.tc_validate-lessThan' ) 2963 .removeClass( 'validate-lessThan-blur' ) 2964 .find( '.tc_validate-lessThanEqual-blur' ) 2965 .off( '.tc_validate-lessThanEqual' ) 2966 .removeClass( 'validate-lessThanEqual-blur' ) 2967 .find( '.tc_validate-greaterThanEqual-blur' ) 2968 .off( '.tc_validate-greaterThanEqual' ) 2969 .removeClass( 'validate-greaterThanEqual-blur' ) 2970 .find( '.tc_validate-greaterThan-blur' ) 2971 .off( '.tc_validate-greaterThan' ) 2972 .removeClass( 'validate-greaterThan-blur' ); 2973 } 2974 }, 2975 2976 classRuleSettings: { 2977 required: { required: true }, 2978 email: { email: true }, 2979 url: { url: true }, 2980 date: { date: true }, 2981 dateISO: { dateISO: true }, 2982 number: { number: true }, 2983 digits: { digits: true }, 2984 creditcard: { creditcard: true } 2985 }, 2986 2987 addClassRules: function( className, rules ) { 2988 if ( className.constructor === String ) { 2989 this.classRuleSettings[ className ] = rules; 2990 } else { 2991 $.extend( this.classRuleSettings, className ); 2992 } 2993 }, 2994 2995 classRules: function( element ) { 2996 var rules = {}, 2997 classes = $( element ).attr( 'class' ); 2998 2999 if ( classes ) { 3000 $.each( classes.split( ' ' ), function() { 3001 if ( this in $.tc_validator.classRuleSettings ) { 3002 $.extend( rules, $.tc_validator.classRuleSettings[ this ] ); 3003 } 3004 } ); 3005 } 3006 return rules; 3007 }, 3008 3009 normalizeAttributeRule: function( rules, type, method, value ) { 3010 // Convert the value to a number for number inputs, and for text for backwards compability 3011 // allows type="date" and others to be compared as strings 3012 if ( /min|max|step/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) { 3013 value = Number( value ); 3014
vendor: 4,278 bytes, lines 3015-3166
3015 // Support Opera Mini, which returns NaN for undefined minlength 3016 if ( isNaN( value ) ) { 3017 value = undefined; 3018 } 3019 } 3020 3021 if ( value || value === 0 ) { 3022 rules[ method ] = value; 3023 } else if ( type === method && type !== 'range' ) { 3024 // Exception: the jquery validate 'range' method 3025 // does not test for the html5 'range' type 3026 rules[ method ] = true; 3027 } 3028 }, 3029 3030 attributeRules: function( element ) { 3031 var rules = {}, 3032 $element = $( element ), 3033 type = element.getAttribute( 'type' ), 3034 method, 3035 value; 3036 3037 for ( method in $.tc_validator.methods ) { 3038 if ( method ) { 3039 // Support for <input required> in both html5 and older browsers 3040 if ( method === 'required' ) { 3041 value = element.getAttribute( method ); 3042 3043 // Some browsers return an empty string for the required attribute 3044 // and non-HTML5 browsers might have required="" markup 3045 if ( value === '' ) { 3046 value = true; 3047 } 3048 3049 // Force non-HTML5 browsers to return bool 3050 value = !! value; 3051 } else { 3052 value = $element.attr( method ); 3053 } 3054 3055 this.normalizeAttributeRule( rules, type, method, value ); 3056 } 3057 } 3058 3059 // 'maxlength' may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs 3060 if ( rules.maxlength && /-1|2147483647|524288/.test( rules.maxlength ) ) { 3061 delete rules.maxlength; 3062 } 3063 3064 return rules; 3065 }, 3066 3067 dataRules: function( element ) { 3068 var rules = {}, 3069 $element = $( element ), 3070 type = element.getAttribute( 'type' ), 3071 method, 3072 value; 3073 3074 for ( method in $.tc_validator.methods ) { 3075 if ( method ) { 3076 value = $element.data( 'rule' + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() ); 3077 3078 // Cast empty attributes like `data-rule-required` to `true` 3079 if ( value === '' ) { 3080 value = true; 3081 } 3082 3083 this.normalizeAttributeRule( rules, type, method, value ); 3084 } 3085 } 3086 return rules; 3087 }, 3088 3089 staticRules: function( element ) { 3090 var rules = {}, 3091 tc_validator = $.data( element.form, 'tc_validator' ); 3092 3093 if ( tc_validator.settings.rules ) { 3094 rules = $.tc_validator.normalizeRule( tc_validator.settings.rules[ element.name ] ) || {}; 3095 } 3096 return rules; 3097 }, 3098 3099 normalizeRules: function( rules, element ) { 3100 var keepRule; 3101 // Handle dependency check 3102 $.each( rules, function( prop, val ) { 3103 // Ignore rule when param is explicitly false, eg. required:false 3104 if ( val === false ) { 3105 delete rules[ prop ]; 3106 return; 3107 } 3108 if ( val.param || val.depends ) { 3109 keepRule = true; 3110 switch ( typeof val.depends ) { 3111 case 'string': 3112 keepRule = !! $( val.depends, element.form ).length; 3113 break; 3114 case 'function': 3115 keepRule = val.depends.call( element, element ); 3116 break; 3117 } 3118 if ( keepRule ) { 3119 rules[ prop ] = val.param !== undefined ? val.param : true; 3120 } else { 3121 $.data( element.form, 'tc_validator' ).resetElements( $( element ) ); 3122 delete rules[ prop ]; 3123 } 3124 } 3125 } ); 3126 3127 // Evaluate parameters 3128 $.each( rules, function( rule, parameter ) { 3129 rules[ rule ] = typeof parameter === 'function' && rule !== 'normalizer' ? parameter( element ) : parameter; 3130 } ); 3131 3132 // Clean number parameters 3133 $.each( [ 'minlength', 'maxlength' ], function() { 3134 if ( rules[ this ] ) { 3135 rules[ this ] = Number( rules[ this ] ); 3136 } 3137 } ); 3138 $.each( [ 'rangelength', 'range' ], function() { 3139 var parts; 3140 if ( rules[ this ] ) { 3141 if ( Array.isArray( rules[ this ] ) ) { 3142 rules[ this ] = [ Number( rules[ this ][ 0 ] ), Number( rules[ this ][ 1 ] ) ]; 3143 } else if ( typeof rules[ this ] === 'string' ) { 3144 parts = rules[ this ].replace( /[[\]]/g, '' ).split( /[\s,]+/ ); 3145 rules[ this ] = [ Number( parts[ 0 ] ), Number( parts[ 1 ] ) ]; 3146 } 3147 } 3148 } ); 3149 3150 if ( $.tc_validator.autoCreateRanges ) { 3151 // Auto-create ranges 3152 if ( rules.min !== null && rules.max !== null ) { 3153 rules.range = [ rules.min, rules.max ]; 3154 delete rules.min; 3155 delete rules.max; 3156 } 3157 if ( rules.minlength !== null && rules.maxlength !== null ) { 3158 rules.rangelength = [ rules.minlength, rules.maxlength ]; 3159 delete rules.minlength; 3160 delete rules.maxlength; 3161 } 3162 } 3163 3164 return rules; 3165 }, 3166
3167 // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true} 3168 normalizeRule: function( data ) { 3169 var transformed; 3170 if ( typeof data === 'string' ) { 3171 transformed = {}; 3172 $.each( data.split( /\s/ ), function() { 3173 transformed[ this ] = true; 3174 } ); 3175 data = transformed; 3176 } 3177 return data; 3178 }, 3179 3180 // https://jqueryvalidation.org/jQuery.tc_validator.addMethod/ 3181 addMethod: function( name, method, message ) { 3182 $.tc_validator.methods[ name ] = method; 3183 $.tc_validator.messages[ name ] = message !== undefined ? message : $.tc_validator.messages[ name ]; 3184 if ( method.length < 3 ) { 3185 $.tc_validator.addClassRules( name, $.tc_validator.normalizeRule( name ) ); 3186 } 3187 }, 3188 3189 // https://jqueryvalidation.org/jQuery.tc_validator.methods/ 3190 methods: { 3191 // https://jqueryvalidation.org/required-method/ 3192 required: function( value, element, param ) { 3193 var val; 3194 // Check if dependency is met 3195 if ( ! this.depend( param, element ) ) { 3196 return 'dependency-mismatch'; 3197 } 3198 if ( element.nodeName.toLowerCase() === 'select' ) { 3199 // Could be an array for select-multiple or a string, both are fine this way 3200 val = $( element ).val(); 3201 return val && val.length > 0; 3202 } 3203 if ( this.checkable( element ) ) { 3204 return this.getLength( value, element ) > 0; 3205 } 3206 return value !== undefined && value !== null && value.length > 0; 3207 }, 3208 3209 // https://jqueryvalidation.org/email-method/ 3210 email: function( value, element ) { 3211 // From https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address 3212 // Retrieved 2014-01-14 3213 // If you have a problem with this implementation, report a bug against the above spec 3214 // Or use custom methods to implement your own email validation 3215 // eslint-disable-next-line no-useless-escape 3216 return this.optional( element ) || /^[a-zA-Z0-9.!#$%&'*+\/=?\^_`{|}~\-]+@[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$/.test( value ); 3217 }, 3218 3219 // https://jqueryvalidation.org/url-method/ 3220 url: function( value, element ) { 3221 // Copyright (c) 2010-2013 Diego Perini, MIT licensed 3222 // https://gist.github.com/dperini/729294 3223 // see also https://mathiasbynens.be/demo/url-regex 3224 // modified to allow protocol-relative URLs 3225 return ( 3226 this.optional( element ) || 3227 // eslint-disable-next-line no-useless-escape
3228 /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$/i.test( 3229 value 3230 ) 3231 ); 3232 }, 3233 // https://jqueryvalidation.org/date-method/ 3234 date: function( value, element ) { 3235 /* This method is deprecated and will be removed in version 2.0.0. Please don't use it, since it relies on the Date constructor, which behaves very differently across browsers and locales. Use dateISO instead or one of the locale specific methods (in localizations/ and additional-methods.js). */ 3236 return this.optional( element ) || ! /Invalid|NaN/.test( new Date( value ).toString() ); 3237 }, 3238 3239 // https://jqueryvalidation.org/dateISO-method/ 3240 dateISO: function( value, element ) { 3241 // eslint-disable-next-line no-useless-escape 3242 return this.optional( element ) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test( value ); 3243 }, 3244 3245 // https://jqueryvalidation.org/number-method/ 3246 number: function( value, element ) { 3247 return this.optional( element ) || /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test( value ); 3248 }, 3249 3250 // https://jqueryvalidation.org/digits-method/ 3251 digits: function( value, element ) { 3252 return this.optional( element ) || /^\d+$/.test( value ); 3253 }, 3254 3255 // https://jqueryvalidation.org/minlength-method/ 3256 minlength: function( value, element, param ) { 3257 var length = Array.isArray( value ) ? value.length : this.getLength( value, element ); 3258 return this.optional( element ) || length >= param; 3259 }, 3260 3261 // https://jqueryvalidation.org/maxlength-method/ 3262 maxlength: function( value, element, param ) { 3263 var length = Array.isArray( value ) ? value.length : this.getLength( value, element ); 3264 return this.optional( element ) || length <= param; 3265 }, 3266 3267 // https://jqueryvalidation.org/rangelength-method/ 3268 rangelength: function( value, element, param ) { 3269 var length = Array.isArray( value ) ? value.length : this.getLength( value, element ); 3270 return this.optional( element ) || ( length >= param[ 0 ] && length <= param[ 1 ] ); 3271 }, 3272 3273 // https://jqueryvalidation.org/min-method/ 3274 min: function( value, element, param ) { 3275 return this.optional( element ) || value >= param; 3276 }, 3277 3278 // https://jqueryvalidation.org/max-method/ 3279 max: function( value, element, param ) { 3280 return this.optional( element ) || value <= param; 3281 }, 3282 3283 // https://jqueryvalidation.org/range-method/ 3284 range: function( value, element, param ) { 3285 return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] ); 3286 }, 3287 3288 // https://jqueryvalidation.org/step-method/ 3289 step: function( value, element, param ) { 3290 var type = $( element ).attr( 'type' ), 3291 errorMessage = 'Step attribute on input type ' + type + ' is not supported.', 3292 supportedTypes = [ 'text', 'number', 'range' ], 3293 re = new RegExp( '\\b' + type + '\\b' ), 3294 notSupported = type && ! re.test( supportedTypes.join() ), 3295 decimalPlaces = function( num ) { 3296 var match = ( '' + num ).match( /(?:\.(\d+))?$/ ); 3297 if ( ! match ) { 3298 return 0; 3299 } 3300 3301 // Number of digits right of decimal point. 3302 return match[ 1 ] ? match[ 1 ].length : 0; 3303 }, 3304 decimals, 3305 toInt = function( num ) { 3306 return Math.round( num * Math.pow( 10, decimals ) ); 3307 }, 3308 valid = true; 3309 3310 // Works only for text, number and range input types 3311 // TO-DO find a way to support input types date, datetime, datetime-local, month, time and week 3312 if ( notSupported ) { 3313 throw new Error( errorMessage ); 3314 } 3315 3316 decimals = decimalPlaces( param ); 3317 3318 // Value can't have too many decimals 3319 if ( decimalPlaces( value ) > decimals || toInt( value ) % toInt( param ) !== 0 ) { 3320 valid = false; 3321 } 3322 3323 return this.optional( element ) || valid; 3324 }, 3325 3326 // https://jqueryvalidation.org/equalTo-method/ 3327 equalTo: function( value, element, param ) { 3328 // Bind to the blur event of the target in order to revalidate whenever the target field is updated 3329 var target = $( param ); 3330 if ( this.settings.onfocusout && target.not( '.tc_validate-equalTo-blur' ).length ) { 3331 target.addClass( 'validate-equalTo-blur' ).on( 'blur.tc_validate-equalTo', function() { 3332 $( element ).tc_valid(); 3333 } ); 3334 } 3335 return value === target.val(); 3336 }, 3337 3338 // https://jqueryvalidation.org/remote-method/ 3339 remote: function( value, element, param, method ) { 3340 var previous; 3341 var tc_validator; 3342 var data; 3343 var optionDataString; 3344 3345 if ( this.optional( element ) ) { 3346 return 'dependency-mismatch'; 3347 } 3348 3349 method = ( typeof method === 'string' && method ) || 'remote'; 3350 3351 previous = this.previousValue( element, method ); 3352 3353 if ( ! this.settings.messages[ element.name ] ) { 3354 this.settings.messages[ element.name ] = {}; 3355 } 3356 previous.originalMessage = previous.originalMessage || this.settings.messages[ element.name ][ method ]; 3357 this.settings.messages[ element.name ][ method ] = previous.message; 3358 3359 param = ( typeof param === 'string' && { url: param } ) || param; 3360 optionDataString = $.param( $.extend( { data: value }, param.data ) ); 3361 if ( previous.old === optionDataString ) { 3362 return previous.valid; 3363 } 3364 3365 previous.old = optionDataString; 3366 tc_validator = this;
3367 this.startRequest( element ); 3368 data = {}; 3369 data[ element.name ] = value; 3370 $.ajax( 3371 $.extend( 3372 true, 3373 { 3374 mode: 'abort', 3375 port: 'validate' + element.name, 3376 dataType: 'json', 3377 data: data, 3378 context: tc_validator.currentForm, 3379 success: function( response ) { 3380 var valid = response === true || response === 'true', 3381 errors, 3382 message, 3383 submitted; 3384 3385 tc_validator.settings.messages[ element.name ][ method ] = previous.originalMessage; 3386 if ( valid ) { 3387 submitted = tc_validator.formSubmitted; 3388 tc_validator.resetInternals(); 3389 tc_validator.toHide = tc_validator.errorsFor( element ); 3390 tc_validator.formSubmitted = submitted; 3391 tc_validator.successList.push( element ); 3392 tc_validator.invalid[ element.name ] = false; 3393 tc_validator.showErrors(); 3394 } else { 3395 errors = {}; 3396 message = response || tc_validator.defaultMessage( element, { method: method, parameters: value } ); 3397 previous.message = message; 3398 errors[ element.name ] = message; 3399 tc_validator.invalid[ element.name ] = true; 3400 tc_validator.showErrors( errors ); 3401 } 3402 previous.valid = valid; 3403 tc_validator.stopRequest( element, valid ); 3404 } 3405 }, 3406 param 3407 ) 3408 ); 3409 return 'pending'; 3410 } 3411 } 3412 } ); 3413 3414 // Ajax mode: abort 3415 // usage: $.ajax({ mode: "abort"[, port: "uniqueport"]}); 3416 // if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() 3417 3418 // Use a prefilter if available (1.5+) 3419 if ( $.ajaxPrefilter ) { 3420 $.ajaxPrefilter( function( settings, _, xhr ) { 3421 var port = settings.port; 3422 if ( settings.mode === 'abort' ) { 3423 if ( pendingRequests[ port ] ) { 3424 pendingRequests[ port ].abort(); 3425 } 3426 pendingRequests[ port ] = xhr; 3427 } 3428 } ); 3429 } else { 3430 // Proxy ajax 3431 ajax = $.ajax; 3432 $.ajax = function( settings ) { 3433 var mode = ( 'mode' in settings ? settings : $.ajaxSettings ).mode, 3434 port = ( 'port' in settings ? settings : $.ajaxSettings ).port; 3435 if ( mode === 'abort' ) { 3436 if ( pendingRequests[ port ] ) { 3437 pendingRequests[ port ].abort(); 3438 } 3439 pendingRequests[ port ] = ajax.apply( this, arguments ); 3440 return pendingRequests[ port ]; 3441 } 3442 return ajax.apply( this, arguments ); 3443 }; 3444 } 3445 return $; 3446} ) ); 3447; 3448/** 3449 * Lazy Load XT v1.1.0 2016-01-12 3450 * http://ressio.github.io/lazy-load-xt 3451 * (C) 2016 RESS.io 3452 * Licensed under MIT 3453 * reformatted code by ThemeComplete 3454 */ 3455 3456( function( $, window, document ) { 3457 'use strict'; 3458 3459 // options 3460 var lazyLoadXT = 'lazyLoadXT', 3461 dataLazied = 'lazied', 3462 loadError = 'load error', 3463 classLazyHidden = 'lazy-hidden', 3464 docElement = document.documentElement || document.body, 3465 // force load all images in Opera Mini and some mobile browsers without scroll event or getBoundingClientRect() 3466 forceLoad = 3467 window.onscroll === undefined || 3468 !! window.operamini || 3469 ! docElement.getBoundingClientRect, 3470 options = { 3471 autoInit: true, // auto initialize in document ready 3472 selector: 'img[data-src]', // selector for lazyloading elements 3473 blankImage: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', 3474 throttle: 99, // interval (ms) for changes check 3475 forceLoad: forceLoad, // force auto load all images 3476 3477 loadEvent: 'pageshow', // check AJAX-loaded content in jQueryMobile 3478 updateEvent: 'load orientationchange resize scroll touchmove focus', // page-modified events 3479 forceEvent: 'lazyloadall', // force loading of all elements 3480 3481 //onstart: null, 3482 oninit: { removeClass: 'lazy' }, // init handler 3483 onshow: { addClass: classLazyHidden }, // start loading handler 3484 onload: { removeClass: classLazyHidden, addClass: 'lazy-loaded' }, // load success handler 3485 onerror: { removeClass: classLazyHidden }, // error handler 3486 //oncomplete: null, // complete handler 3487 3488 //scrollContainer: undefined, 3489 checkDuplicates: true 3490 }, 3491 elementOptions = { 3492 srcAttr: 'data-src', 3493 edgeX: 0, 3494 edgeY: 0, 3495 visibleOnly: true 3496 }, 3497 $window = $( window ), 3498 $isFunction = function( f ) { 3499 return typeof f === 'function'; 3500 }, 3501 $extend = $.extend, 3502 $data = 3503 $.data || 3504 function( el, name ) { 3505 return $( el ).data( name ); 3506 }, 3507 elements = [], 3508 topLazy = 0, 3509 /* 3510 waitingMode=0 : no setTimeout 3511 waitingMode=1 : setTimeout, no deferred events 3512 waitingMode=2 : setTimeout, deferred events 3513 */ 3514 waitingMode = 0; 3515 3516 $[ lazyLoadXT ] = $extend( options, elementOptions, $[ lazyLoadXT ] ); 3517 3518 /** 3519 * Return options.prop if obj.prop is undefined, otherwise return obj.prop 3520 * 3521 * @param {*} obj 3522 * @param {*} prop 3523 */ 3524 function getOrDef( obj, prop ) { 3525 return obj[ prop ] === undefined ? options[ prop ] : obj[ prop ]; 3526 } 3527 3528 function scrollTop() { 3529 var scroll = window.pageYOffset; 3530 return scroll === undefined ? docElement.scrollTop : scroll; 3531 } 3532 3533 /** 3534 * Run check of lazy elements after timeout 3535 */ 3536 function timeoutLazyElements() { 3537 if ( waitingMode > 1 ) { 3538 waitingMode = 1; 3539 checkLazyElements(); 3540 setTimeout( timeoutLazyElements, options.throttle ); 3541 } else { 3542 waitingMode = 0; 3543 } 3544 } 3545
3546 /** 3547 * Queue check of lazy elements because of event e 3548 * 3549 * @param {Event} [e] 3550 */ 3551 function queueCheckLazyElements( e ) { 3552 if ( ! elements.length ) { 3553 return; 3554 } 3555 3556 // fast check for scroll event without new visible elements 3557 if ( e && e.type === 'scroll' && e.currentTarget === window ) { 3558 if ( topLazy >= scrollTop() ) { 3559 return; 3560 } 3561 } 3562 3563 if ( ! waitingMode ) { 3564 setTimeout( timeoutLazyElements, 0 ); 3565 } 3566 waitingMode = 2; 3567 } 3568 3569 /** 3570 * Process function/object event handler 3571 * 3572 * @param {string} event suffix 3573 * @param {jQuery} $el 3574 */ 3575 function triggerEvent( event, $el ) { 3576 var handler = options[ 'on' + event ]; 3577 if ( handler ) { 3578 if ( $isFunction( handler ) ) { 3579 handler.call( $el[ 0 ] ); 3580 } else { 3581 if ( handler.addClass ) { 3582 $el.addClass( handler.addClass ); 3583 } 3584 if ( handler.removeClass ) { 3585 $el.removeClass( handler.removeClass ); 3586 } 3587 } 3588 } 3589 3590 $el.trigger( 'lazy' + event, [ $el ] ); 3591 3592 // queue next check as images may be resized after loading of actual file 3593 queueCheckLazyElements(); 3594 } 3595 3596 /** 3597 * Trigger onload/onerror handler 3598 * 3599 * @param {Event} e 3600 */ 3601 function triggerLoadOrError( e ) { 3602 triggerEvent( e.type, $( e.currentTarget ).off( loadError, triggerLoadOrError ) ); 3603 } 3604 3605 /** 3606 * Load visible elements 3607 * 3608 * @param {bool} [force] loading of all elements 3609 */ 3610 function checkLazyElements( force ) { 3611 var viewportTop, viewportHeight, viewportWidth, i, length; 3612 3613 var $el, el, objData, removeNode, visible, topEdge; 3614 3615 var elPos, edgeX, edgeY; 3616 3617 var srcAttr, src; 3618 3619 if ( ! elements.length ) { 3620 return; 3621 } 3622 3623 force = force || options.forceLoad; 3624 3625 topLazy = Infinity; 3626 3627 viewportTop = scrollTop(); 3628 viewportHeight = window.innerHeight || docElement.clientHeight; 3629 viewportWidth = window.innerWidth || docElement.clientWidth; 3630 3631 for ( i = 0, length = elements.length; i < length; i += 1 ) { 3632 $el = elements[ i ]; 3633 el = $el[ 0 ]; 3634 objData = $el[ lazyLoadXT ]; 3635 removeNode = false; 3636 visible = force || $data( el, dataLazied ) < 0; 3637 3638 // remove items that are not in DOM 3639 if ( ! $.contains( docElement, el ) ) { 3640 removeNode = true; 3641 } else if ( force || ! objData.visibleOnly || el.offsetWidth || el.offsetHeight ) { 3642 if ( ! visible ) { 3643 elPos = el.getBoundingClientRect(); 3644 edgeX = objData.edgeX; 3645 edgeY = objData.edgeY; 3646 3647 topEdge = elPos.top + viewportTop - edgeY - viewportHeight; 3648 3649 visible = topEdge <= viewportTop && elPos.bottom > -edgeY && elPos.left <= viewportWidth + edgeX && elPos.right > -edgeX; 3650 } 3651 3652 if ( visible ) { 3653 $el.on( loadError, triggerLoadOrError ); 3654 3655 triggerEvent( 'show', $el ); 3656 3657 srcAttr = objData.srcAttr; 3658 src = $isFunction( srcAttr ) ? srcAttr( $el ) : el.getAttribute( srcAttr ); 3659 3660 if ( src ) { 3661 el.src = src; 3662 } 3663 3664 removeNode = true; 3665 } else if ( topEdge < topLazy ) { 3666 topLazy = topEdge; 3667 } 3668 } 3669 3670 if ( removeNode ) { 3671 $data( el, dataLazied, 0 ); 3672 elements.splice( i, 1 ); 3673 i = i - 1; 3674 length = length - 1; 3675 } 3676 } 3677 3678 if ( ! length ) { 3679 triggerEvent( 'complete', $( docElement ) ); 3680 } 3681 } 3682 3683 /** 3684 * Add new elements to lazy-load list: 3685 * $(elements).lazyLoadXT() or $(window).lazyLoadXT() 3686 * 3687 * @param {Object} [overrides] override global options 3688 */ 3689 $.fn[ lazyLoadXT ] = function( overrides ) { 3690 var blankImage; 3691 var checkDuplicates; 3692 var scrollContainer; 3693 var forceShow; 3694 var elementOptionsOverrides = {}; 3695 3696 overrides = overrides || {}; 3697 3698 blankImage = getOrDef( overrides, 'blankImage' ); 3699 checkDuplicates = getOrDef( overrides, 'checkDuplicates' ); 3700 scrollContainer = getOrDef( overrides, 'scrollContainer' ); 3701 forceShow = getOrDef( overrides, 'show' ); 3702 3703 // empty overrides.scrollContainer is supported by both jQuery and Zepto 3704 $( scrollContainer ).on( 'scroll', queueCheckLazyElements ); 3705 3706 Object.keys( elementOptions ).forEach( function( prop ) { 3707 elementOptionsOverrides[ prop ] = getOrDef( overrides, prop ); 3708 } ); 3709 3710 return this.each( function( index, el ) { 3711 var duplicate; 3712 var $el; 3713 if ( el === window ) { 3714 $( options.selector ).lazyLoadXT( overrides ); 3715 } else { 3716 duplicate = checkDuplicates && $data( el, dataLazied ); 3717 $el = $( el ).data( dataLazied, forceShow ? -1 : 1 ); 3718 3719 // prevent duplicates 3720 if ( duplicate ) { 3721 queueCheckLazyElements(); 3722 return; 3723 } 3724 3725 if ( blankImage && el.tagName === 'IMG' && ! el.src ) { 3726 el.src = blankImage; 3727 } 3728 3729 // clone elementOptionsOverrides object 3730 $el[ lazyLoadXT ] = $extend( {}, elementOptionsOverrides ); 3731 3732 triggerEvent( 'init', $el ); 3733 3734 elements.push( $el ); 3735 queueCheckLazyElements(); 3736 } 3737 } ); 3738 }; 3739 3740 /** 3741 * Initialize list of hidden elements 3742 */ 3743 function initLazyElements() { 3744 $window.lazyLoadXT(); 3745 } 3746 3747 /** 3748 * Loading of all elements 3749 */ 3750 function forceLoadAll() { 3751 checkLazyElements( true ); 3752 } 3753 3754 /** 3755 * Initialization 3756 */ 3757 // document ready 3758 $( function() { 3759 triggerEvent( 'start', $window ); 3760 3761 $window.on( options.updateEvent, queueCheckLazyElements ).on( options.forceEvent, forceLoadAll ); 3762 3763 $( document ).on( options.updateEvent, queueCheckLazyElements ); 3764 3765 if ( options.autoInit ) { 3766 $window.on( options.loadEvent, initLazyElements ); 3767 initLazyElements(); // standard initialization 3768 } 3769 } ); 3770}( window.jQuery || window.Zepto || window.$, window, document ) ); 3771 3772( function( $ ) { 3773 'use strict'; 3774 3775 var options = $.lazyLoadXT; 3776 3777 options.selector += ',video,iframe[data-src]';
3778 options.videoPoster = 'data-poster'; 3779 3780 $( document ).on( 'lazyshow', 'video', function( e, $el ) { 3781 var srcAttr = $el.lazyLoadXT.srcAttr, 3782 isFuncSrcAttr = typeof srcAttr === 'function', 3783 changed = false; 3784 3785 $el.attr( 'poster', $el.attr( options.videoPoster ) ); 3786 $el.children( 'source,track' ).each( function( index, el ) { 3787 var $child = $( el ), 3788 src = isFuncSrcAttr ? srcAttr( $child ) : $child.attr( srcAttr ); 3789 if ( src ) { 3790 $child.attr( 'src', src ); 3791 changed = true; 3792 } 3793 } ); 3794 3795 // reload video 3796 if ( changed ) { 3797 this.load(); 3798 } 3799 } ); 3800}( window.jQuery || window.Zepto || window.$ ) ); 3801; 3802/*! nouislider - 15.7.1 - 6/14/2023 */ 3803// reformatted code by ThemeComplete 3804( function( global, factory ) { 3805 'use strict'; 3806 3807 factory( global.noUiSlider = {} ); 3808}( this, ( function( exports ) { 3809 'use strict'; 3810 3811 var nouislider; 3812 //region Defaults 3813 var defaultFormatter = { 3814 to: function( value ) { 3815 return value === undefined ? '' : value.toFixed( 2 ); 3816 }, 3817 from: Number 3818 }; 3819 var cssClasses = { 3820 target: 'target', 3821 base: 'base', 3822 origin: 'origin', 3823 handle: 'handle', 3824 handleLower: 'handle-lower', 3825 handleUpper: 'handle-upper', 3826 touchArea: 'touch-area', 3827 horizontal: 'horizontal', 3828 vertical: 'vertical', 3829 background: 'background', 3830 connect: 'connect', 3831 connects: 'connects', 3832 ltr: 'ltr', 3833 rtl: 'rtl', 3834 textDirectionLtr: 'txt-dir-ltr', 3835 textDirectionRtl: 'txt-dir-rtl', 3836 draggable: 'draggable', 3837 drag: 'state-drag', 3838 tap: 'state-tap', 3839 active: 'active', 3840 tooltip: 'tooltip', 3841 pips: 'pips', 3842 pipsHorizontal: 'pips-horizontal', 3843 pipsVertical: 'pips-vertical', 3844 marker: 'marker', 3845 markerHorizontal: 'marker-horizontal', 3846 markerVertical: 'marker-vertical', 3847 markerNormal: 'marker-normal', 3848 markerLarge: 'marker-large', 3849 markerSub: 'marker-sub', 3850 value: 'value', 3851 valueHorizontal: 'value-horizontal', 3852 valueVertical: 'value-vertical', 3853 valueNormal: 'value-normal', 3854 valueLarge: 'value-large', 3855 valueSub: 'value-sub' 3856 }; 3857 // Namespaces of internal event listeners 3858 var INTERNAL_EVENT_NS = { 3859 tooltips: '.__tooltips', 3860 aria: '.__aria' 3861 }; 3862 //endregion 3863 //region Spectrum 3864 var Spectrum = /** @class */ ( function() { 3865 function Spectrumc( entry, snap, singleStep ) { 3866 var index; 3867 var ordered = []; 3868 this.xPct = []; 3869 this.xVal = []; 3870 this.xSteps = []; 3871 this.xNumSteps = []; 3872 this.xHighestCompleteStep = []; 3873 this.xSteps = [ singleStep || false ]; 3874 this.xNumSteps = [ false ]; 3875 this.snap = snap; 3876 // Map the object keys to an array. 3877 Object.keys( entry ).forEach( function( iindex ) { 3878 ordered.push( [ asArray( entry[ iindex ] ), iindex ] ); 3879 } ); 3880 // Sort all entries by value (numeric sort). 3881 ordered.sort( function( a, b ) { 3882 return a[ 0 ][ 0 ] - b[ 0 ][ 0 ]; 3883 } ); 3884 // Convert all entries to subranges. 3885 for ( index = 0; index < ordered.length; index++ ) { 3886 this.handleEntryPoint( ordered[ index ][ 1 ], ordered[ index ][ 0 ] ); 3887 } 3888 // Store the actual step values. 3889 // xSteps is sorted in the same order as xPct and xVal. 3890 this.xNumSteps = this.xSteps.slice( 0 ); 3891 // Convert all numeric steps to the percentage of the subrange they represent. 3892 for ( index = 0; index < this.xNumSteps.length; index++ ) { 3893 this.handleStepPoint( index, this.xNumSteps[ index ] ); 3894 } 3895 } 3896 Spectrumc.prototype.getDistance = function( value ) { 3897 var index; 3898 var distances = []; 3899 for ( index = 0; index < this.xNumSteps.length - 1; index++ ) { 3900 distances[ index ] = fromPercentage( this.xVal, value, index ); 3901 } 3902 return distances; 3903 }; 3904 // Calculate the percentual distance over the whole scale of ranges. 3905 // direction: 0 = backwards / 1 = forwards 3906 Spectrumc.prototype.getAbsoluteDistance = function( value, distances, direction ) { 3907 var xPct_index = 0; 3908 var start_factor; 3909 var rest_factor = 1; 3910 var rest_rel_distance; 3911 var range_pct = 0; 3912 var rel_range_distance = 0; 3913 var abs_distance_counter = 0; 3914 var range_counter = 0; 3915 3916 // Calculate range where to start calculation 3917 if ( value < this.xPct[ this.xPct.length - 1 ] ) { 3918 while ( value > this.xPct[ xPct_index + 1 ] ) { 3919 xPct_index++; 3920 } 3921 } else if ( value === this.xPct[ this.xPct.length - 1 ] ) { 3922 xPct_index = this.xPct.length - 2; 3923 } 3924 // If looking backwards and the value is exactly at a range separator then look one range further 3925 if ( ! direction && value === this.xPct[ xPct_index + 1 ] ) { 3926 xPct_index++; 3927 } 3928 if ( distances === null ) { 3929 distances = []; 3930 } 3931 rest_rel_distance = distances[ xPct_index ]; 3932 3933 // Calculate what part of the start range the value is 3934 if ( direction ) { 3935 start_factor = ( value - this.xPct[ xPct_index ] ) / ( this.xPct[ xPct_index + 1 ] - this.xPct[ xPct_index ] ); 3936 } else { 3937 start_factor = ( this.xPct[ xPct_index + 1 ] - value ) / ( this.xPct[ xPct_index + 1 ] - this.xPct[ xPct_index ] ); 3938 } 3939 // Do until the complete distance across ranges is calculated 3940 while ( rest_rel_distance > 0 ) { 3941 // Calculate the percentage of total range 3942 range_pct = this.xPct[ xPct_index + 1 + range_counter ] - this.xPct[ xPct_index + range_counter ]; 3943 // Detect if the margin, padding or limit is larger then the current range and calculate 3944 if ( ( distances[ xPct_index + range_counter ] * rest_factor ) + 100 - ( start_factor * 100 ) > 100 ) { 3945 // If larger then take the percentual distance of the whole range 3946 rel_range_distance = range_pct * start_factor; 3947 // Rest factor of relative percentual distance still to be calculated 3948 rest_factor = ( rest_rel_distance - ( 100 * start_factor ) ) / distances[ xPct_index + range_counter ]; 3949 // Set start factor to 1 as for next range it does not apply. 3950 start_factor = 1; 3951 } else { 3952 // If smaller or equal then take the percentual distance of the calculate percentual part of that range 3953 rel_range_distance = ( ( distances[ xPct_index + range_counter ] * range_pct ) / 100 ) * rest_factor; 3954 // No rest left as the rest fits in current range 3955 rest_factor = 0; 3956 } 3957 if ( direction ) { 3958 abs_distance_counter = abs_distance_counter - rel_range_distance; 3959 // Limit range to first range when distance becomes outside of minimum range 3960 if ( this.xPct.length + range_counter >= 1 ) { 3961 range_counter--; 3962 } 3963 } else { 3964 abs_distance_counter = abs_distance_counter + rel_range_distance; 3965 // Limit range to last range when distance becomes outside of maximum range 3966 if ( this.xPct.length - range_counter >= 1 ) { 3967 range_counter++; 3968 } 3969 } 3970 // Rest of relative percentual distance still to be calculated 3971 rest_rel_distance = distances[ xPct_index + range_counter ] * rest_factor; 3972 } 3973 return value + abs_distance_counter; 3974 }; 3975 Spectrumc.prototype.toStepping = function( value ) { 3976 value = toStepping( this.xVal, this.xPct, value ); 3977 return value; 3978 }; 3979 Spectrumc.prototype.fromStepping = function( value ) { 3980 return fromStepping( this.xVal, this.xPct, value ); 3981 }; 3982 Spectrumc.prototype.getStep = function( value ) { 3983 value = getStep( this.xPct, this.xSteps, this.snap, value ); 3984 return value; 3985 }; 3986 Spectrumc.prototype.getDefaultStep = function( value, isDown, size ) { 3987 var j = getJ( value, this.xPct ); 3988 // When at the top or stepping down, look at the previous sub-range 3989 if ( value === 100 || ( isDown && value === this.xPct[ j - 1 ] ) ) { 3990 j = Math.max( j - 1, 1 ); 3991 } 3992 return ( this.xVal[ j ] - this.xVal[ j - 1 ] ) / size; 3993 }; 3994 Spectrumc.prototype.getNearbySteps = function( value ) { 3995 var j = getJ( value, this.xPct ); 3996 return { 3997 stepBefore: { 3998 startValue: this.xVal[ j - 2 ], 3999 step: this.xNumSteps[ j - 2 ],
4000 highestStep: this.xHighestCompleteStep[ j - 2 ] 4001 }, 4002 thisStep: { 4003 startValue: this.xVal[ j - 1 ], 4004 step: this.xNumSteps[ j - 1 ], 4005 highestStep: this.xHighestCompleteStep[ j - 1 ] 4006 }, 4007 stepAfter: { 4008 startValue: this.xVal[ j ], 4009 step: this.xNumSteps[ j ], 4010 highestStep: this.xHighestCompleteStep[ j ] 4011 } 4012 }; 4013 }; 4014 Spectrumc.prototype.countStepDecimals = function() { 4015 var stepDecimals = this.xNumSteps.map( countDecimals ); 4016 return Math.max.apply( null, stepDecimals ); 4017 }; 4018 Spectrumc.prototype.hasNoSize = function() { 4019 return this.xVal[ 0 ] === this.xVal[ this.xVal.length - 1 ]; 4020 }; 4021 // Outside testing 4022 Spectrumc.prototype.convert = function( value ) { 4023 return this.getStep( this.toStepping( value ) ); 4024 }; 4025 Spectrumc.prototype.handleEntryPoint = function( index, value ) { 4026 var percentage; 4027 var value1; 4028 // Covert min/max syntax to 0 and 100. 4029 if ( index === 'min' ) { 4030 percentage = 0; 4031 } else if ( index === 'max' ) { 4032 percentage = 100; 4033 } else { 4034 percentage = parseFloat( index ); 4035 }
4036 // Check for correct input. 4037 if ( ! isNumeric( percentage ) || ! isNumeric( value[ 0 ] ) ) { 4038 throw new Error( "noUiSlider: 'range' value isn't numeric." ); 4039 } 4040 // Store values. 4041 this.xPct.push( percentage ); 4042 this.xVal.push( value[ 0 ] ); 4043 value1 = Number( value[ 1 ] ); 4044 // NaN will evaluate to false too, but to keep 4045 // logging clear, set step explicitly. Make sure 4046 // not to override the 'step' setting with false. 4047 if ( ! percentage ) { 4048 if ( ! isNaN( value1 ) ) { 4049 this.xSteps[ 0 ] = value1; 4050 } 4051 } else { 4052 this.xSteps.push( isNaN( value1 ) ? false : value1 ); 4053 } 4054 this.xHighestCompleteStep.push( 0 ); 4055 }; 4056 Spectrumc.prototype.handleStepPoint = function( i, n ) { 4057 var totalSteps; 4058 var highestStep; 4059 var step; 4060 // Ignore 'false' stepping. 4061 if ( ! n ) { 4062 return; 4063 } 4064 // Step over zero-length ranges (#948); 4065 if ( this.xVal[ i ] === this.xVal[ i + 1 ] ) { 4066 this.xSteps[ i ] = this.xHighestCompleteStep[ i ] = this.xVal[ i ]; 4067 return; 4068 } 4069 // Factor to range ratio 4070 this.xSteps[ i ] = 4071 fromPercentage( [ this.xVal[ i ], this.xVal[ i + 1 ] ], n, 0 ) / subRangeRatio( this.xPct[ i ], this.xPct[ i + 1 ] ); 4072 totalSteps = ( this.xVal[ i + 1 ] - this.xVal[ i ] ) / this.xNumSteps[ i ]; 4073 highestStep = Math.ceil( Number( totalSteps.toFixed( 3 ) ) - 1 ); 4074 step = this.xVal[ i ] + ( this.xNumSteps[ i ] * highestStep ); 4075 this.xHighestCompleteStep[ i ] = step; 4076 }; 4077 return Spectrumc; 4078 }() ); 4079 //endregion 4080 exports.PipsMode = void 0; 4081 ( function( PipsMode ) { 4082 PipsMode.Range = 'range'; 4083 PipsMode.Steps = 'steps'; 4084 PipsMode.Positions = 'positions'; 4085 PipsMode.Count = 'count'; 4086 PipsMode.Values = 'values'; 4087 }( exports.PipsMode || ( exports.PipsMode = {} ) ) ); 4088 exports.PipsType = void 0; 4089 ( function( PipsType ) { 4090 PipsType[ PipsType.None = -1 ] = 'None'; 4091 PipsType[ PipsType.NoValue = 0 ] = 'NoValue'; 4092 PipsType[ PipsType.LargeValue = 1 ] = 'LargeValue'; 4093 PipsType[ PipsType.SmallValue = 2 ] = 'SmallValue'; 4094 }( exports.PipsType || ( exports.PipsType = {} ) ) ); 4095 //region Helper Methods 4096 function isValidFormatter( entry ) { 4097 return isValidPartialFormatter( entry ) && typeof entry.from === 'function'; 4098 } 4099 function isValidPartialFormatter( entry ) { 4100 // partial formatters only need a to function and not a from function 4101 return typeof entry === 'object' && typeof entry.to === 'function'; 4102 } 4103 function removeElement( el ) { 4104 el.parentElement.removeChild( el ); 4105 } 4106 function isSet( value ) { 4107 return value !== null && value !== undefined; 4108 } 4109 // Bindable version 4110 function preventDefault( e ) { 4111 e.preventDefault(); 4112 } 4113 // Removes duplicates from an array. 4114 function unique( array ) { 4115 return array.filter( function( a ) { 4116 return ! this[ a ] ? ( this[ a ] = true ) : false; 4117 }, {} ); 4118 } 4119 // Round a value to the closest 'to'. 4120 function closest( value, to ) { 4121 return Math.round( value / to ) * to; 4122 } 4123 // Current position of an element relative to the document. 4124 function offset( elem, orientation ) { 4125 var rect = elem.getBoundingClientRect(); 4126 var doc = elem.ownerDocument; 4127 var docElem = doc.documentElement; 4128 var pageOffset = getPageOffset( doc ); 4129 // getBoundingClientRect contains left scroll in Chrome on Android. 4130 // I haven't found a feature detection that proves this. Worst case 4131 // scenario on mis-match: the 'tap' feature on horizontal sliders breaks. 4132 if ( /webkit.*Chrome.*Mobile/i.test( navigator.userAgent ) ) { 4133 pageOffset.x = 0; 4134 } 4135 return orientation ? rect.top + pageOffset.y - docElem.clientTop : rect.left + pageOffset.x - docElem.clientLeft; 4136 } 4137 // Checks whether a value is numerical. 4138 function isNumeric( a ) { 4139 return typeof a === 'number' && ! isNaN( a ) && isFinite( a ); 4140 } 4141 // Sets a class and removes it after [duration] ms. 4142 function addClassFor( element, className, duration ) { 4143 if ( duration > 0 ) { 4144 addClass( element, className ); 4145 setTimeout( function() { 4146 removeClass( element, className ); 4147 }, duration ); 4148 } 4149 } 4150 // Limits a value to 0 - 100 4151 function limit( a ) { 4152 return Math.max( Math.min( a, 100 ), 0 ); 4153 } 4154 // Wraps a variable as an array, if it isn't one yet. 4155 // Note that an input array is returned by reference! 4156 function asArray( a ) { 4157 return Array.isArray( a ) ? a : [ a ]; 4158 } 4159 // Counts decimals 4160 function countDecimals( numStr ) { 4161 var pieces; 4162 numStr = String( numStr ); 4163 pieces = numStr.split( '.' ); 4164 return pieces.length > 1 ? pieces[ 1 ].length : 0; 4165 } 4166 // http://youmightnotneedjquery.com/#add_class 4167 function addClass( el, className ) { 4168 if ( el.classList && ! /\s/.test( className ) ) { 4169 el.classList.add( className ); 4170 } else { 4171 el.className += ' ' + className; 4172 } 4173 } 4174 // http://youmightnotneedjquery.com/#remove_class 4175 function removeClass( el, className ) { 4176 if ( el.classList && ! /\s/.test( className ) ) { 4177 el.classList.remove( className ); 4178 } else { 4179 el.className = el.className.replace( new RegExp( '(^|\\b)' + className.split( ' ' ).join( '|' ) + '(\\b|$)', 'gi' ), ' ' ); 4180 } 4181 } 4182 // https://plainjs.com/javascript/attributes/adding-removing-and-testing-for-classes-9/ 4183 function hasClass( el, className ) { 4184 return el.classList ? el.classList.contains( className ) : new RegExp( '\\b' + className + '\\b' ).test( el.className ); 4185 } 4186 // https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollY#Notes 4187 function getPageOffset( doc ) { 4188 var supportPageOffset = window.pageXOffset !== undefined; 4189 var isCSS1Compat = ( doc.compatMode || '' ) === 'CSS1Compat'; 4190 var x = supportPageOffset ? window.pageXOffset : isCSS1Compat ? doc.documentElement.scrollLeft : doc.body.scrollLeft; 4191 var y = supportPageOffset ? window.pageYOffset : isCSS1Compat ? doc.documentElement.scrollTop : doc.body.scrollTop; 4192 return { 4193 x: x, 4194 y: y 4195 }; 4196 } 4197 // we provide a function to compute constants instead 4198 // of accessing window.* as soon as the module needs it 4199 // so that we do not compute anything if not needed 4200 function getActions() { 4201 // Determine the events to bind. IE11 implements pointerEvents without 4202 // a prefix, which breaks compatibility with the IE10 implementation. 4203 return window.navigator.pointerEnabled ? { 4204 start: 'pointerdown', 4205 move: 'pointermove', 4206 end: 'pointerup' 4207 } : window.navigator.msPointerEnabled ? { 4208 start: 'MSPointerDown', 4209 move: 'MSPointerMove', 4210 end: 'MSPointerUp' 4211 } : { 4212 start: 'mousedown touchstart', 4213 move: 'mousemove touchmove', 4214 end: 'mouseup touchend' 4215 }; 4216 } 4217 // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md 4218 // Issue #785
4219 function getSupportsPassive() { 4220 var supportsPassive = false; 4221 /* eslint-disable */ 4222 try { 4223 var opts = Object.defineProperty({}, "passive", { 4224 get: function () { 4225 supportsPassive = true; 4226 }, 4227 }); 4228 // @ts-ignore 4229 window.addEventListener("test", null, opts); 4230 } 4231 catch (e) { } 4232 /* eslint-enable */ 4233 return supportsPassive; 4234 } 4235 function getSupportsTouchActionNone() { 4236 return window.CSS && CSS.supports && CSS.supports( 'touch-action', 'none' ); 4237 } 4238 //endregion 4239 //region Range Calculation 4240 // Determine the size of a sub-range in relation to a full range. 4241 function subRangeRatio( pa, pb ) { 4242 return 100 / ( pb - pa ); 4243 } 4244 // (percentage) How many percent is this value of this range? 4245 function fromPercentage( range, value, startRange ) { 4246 return ( value * 100 ) / ( range[ startRange + 1 ] - range[ startRange ] ); 4247 } 4248 // (percentage) Where is this value on this range? 4249 function toPercentage( range, value ) { 4250 return fromPercentage( range, range[ 0 ] < 0 ? value + Math.abs( range[ 0 ] ) : value - range[ 0 ], 0 ); 4251 } 4252 // (value) How much is this percentage on this range? 4253 function isPercentage( range, value ) { 4254 return ( ( value * ( range[ 1 ] - range[ 0 ] ) ) / 100 ) + range[ 0 ]; 4255 } 4256 function getJ( value, arr ) { 4257 var j = 1; 4258 while ( value >= arr[ j ] ) { 4259 j += 1; 4260 } 4261 return j; 4262 } 4263 // (percentage) Input a value, find where, on a scale of 0-100, it applies. 4264 function toStepping( xVal, xPct, value ) { 4265 var j; 4266 var va; 4267 var vb; 4268 var pa; 4269 var pb; 4270 if ( value >= xVal.slice( -1 )[ 0 ] ) { 4271 return 100; 4272 } 4273 j = getJ( value, xVal ); 4274 va = xVal[ j - 1 ]; 4275 vb = xVal[ j ]; 4276 pa = xPct[ j - 1 ]; 4277 pb = xPct[ j ]; 4278 return pa + ( toPercentage( [ va, vb ], value ) / subRangeRatio( pa, pb ) ); 4279 } 4280 // (value) Input a percentage, find where it is on the specified range. 4281 function fromStepping( xVal, xPct, value ) { 4282 var j; 4283 var va; 4284 var vb; 4285 var pa; 4286 var pb; 4287 // There is no range group that fits 100 4288 if ( value >= 100 ) { 4289 return xVal.slice( -1 )[ 0 ]; 4290 } 4291 j = getJ( value, xPct ); 4292 va = xVal[ j - 1 ]; 4293 vb = xVal[ j ]; 4294 pa = xPct[ j - 1 ]; 4295 pb = xPct[ j ]; 4296 return isPercentage( [ va, vb ], ( value - pa ) * subRangeRatio( pa, pb ) ); 4297 } 4298 // (percentage) Get the step that applies at a certain value. 4299 function getStep( xPct, xSteps, snap, value ) { 4300 var j; 4301 var a; 4302 var b; 4303 if ( value === 100 ) { 4304 return value; 4305 } 4306 j = getJ( value, xPct ); 4307 a = xPct[ j - 1 ]; 4308 b = xPct[ j ]; 4309 // If 'snap' is set, steps are used as fixed points on the slider. 4310 if ( snap ) { 4311 // Find the closest position, a or b. 4312 if ( value - a > ( b - a ) / 2 ) { 4313 return b; 4314 } 4315 return a; 4316 } 4317 if ( ! xSteps[ j - 1 ] ) { 4318 return value; 4319 } 4320 return xPct[ j - 1 ] + closest( value - xPct[ j - 1 ], xSteps[ j - 1 ] ); 4321 } 4322 //endregion 4323 //region Options 4324 /* Every input option is tested and parsed. This will prevent 4325 endless validation in internal methods. These tests are 4326 structured with an item for every option available. An 4327 option can be marked as required by setting the 'r' flag. 4328 The testing function is provided with three arguments: 4329 - The provided value for the option; 4330 - A reference to the options object; 4331 - The name for the option; 4332 4333 The testing function returns false when an error is detected, 4334 or true when everything is OK. It can also modify the option 4335 object, to make sure all values can be correctly looped elsewhere. */ 4336 4337 function testStep( parsed, entry ) { 4338 if ( ! isNumeric( entry ) ) { 4339 throw new Error( "noUiSlider: 'step' is not numeric." ); 4340 } 4341 // The step option can still be used to set stepping 4342 // for linear sliders. Overwritten if set in 'range'. 4343 parsed.singleStep = entry; 4344 } 4345 function testKeyboardPageMultiplier( parsed, entry ) { 4346 if ( ! isNumeric( entry ) ) { 4347 throw new Error( "noUiSlider: 'keyboardPageMultiplier' is not numeric." ); 4348 } 4349 parsed.keyboardPageMultiplier = entry; 4350 } 4351 function testKeyboardMultiplier( parsed, entry ) { 4352 if ( ! isNumeric( entry ) ) { 4353 throw new Error( "noUiSlider: 'keyboardMultiplier' is not numeric." ); 4354 } 4355 parsed.keyboardMultiplier = entry; 4356 } 4357 function testKeyboardDefaultStep( parsed, entry ) { 4358 if ( ! isNumeric( entry ) ) { 4359 throw new Error( "noUiSlider: 'keyboardDefaultStep' is not numeric." ); 4360 } 4361 parsed.keyboardDefaultStep = entry; 4362 } 4363 function testRange( parsed, entry ) { 4364 // Filter incorrect input. 4365 if ( typeof entry !== 'object' || Array.isArray( entry ) ) { 4366 throw new Error( "noUiSlider: 'range' is not an object." ); 4367 } 4368 // Catch missing start or end. 4369 if ( entry.min === undefined || entry.max === undefined ) { 4370 throw new Error( "noUiSlider: Missing 'min' or 'max' in 'range'." ); 4371 } 4372 parsed.spectrum = new Spectrum( entry, parsed.snap || false, parsed.singleStep ); 4373 } 4374 function testStart( parsed, entry ) { 4375 entry = asArray( entry ); 4376 // Validate input. Values aren't tested, as the public .val method 4377 // will always provide a valid location. 4378 if ( ! Array.isArray( entry ) || ! entry.length ) { 4379 throw new Error( "noUiSlider: 'start' option is incorrect." ); 4380 } 4381 // Store the number of handles. 4382 parsed.handles = entry.length;
vendor: 3,263 bytes, lines 4383-4481
4383 // When the slider is initialized, the .val method will 4384 // be called with the start options. 4385 parsed.start = entry; 4386 } 4387 function testSnap( parsed, entry ) { 4388 if ( typeof entry !== 'boolean' ) { 4389 throw new Error( "noUiSlider: 'snap' option must be a boolean." ); 4390 } 4391 // Enforce 100% stepping within subranges. 4392 parsed.snap = entry; 4393 } 4394 function testAnimate( parsed, entry ) { 4395 if ( typeof entry !== 'boolean' ) { 4396 throw new Error( "noUiSlider: 'animate' option must be a boolean." ); 4397 } 4398 // Enforce 100% stepping within subranges. 4399 parsed.animate = entry; 4400 } 4401 function testAnimationDuration( parsed, entry ) { 4402 if ( typeof entry !== 'number' ) { 4403 throw new Error( "noUiSlider: 'animationDuration' option must be a number." ); 4404 } 4405 parsed.animationDuration = entry; 4406 } 4407 function testConnect( parsed, entry ) { 4408 var connect = [ false ]; 4409 var i; 4410 // Map legacy options 4411 if ( entry === 'lower' ) { 4412 entry = [ true, false ]; 4413 } else if ( entry === 'upper' ) { 4414 entry = [ false, true ]; 4415 } 4416 // Handle boolean options 4417 if ( entry === true || entry === false ) { 4418 for ( i = 1; i < parsed.handles; i++ ) { 4419 connect.push( entry ); 4420 } 4421 connect.push( false ); 4422 } else if ( ! Array.isArray( entry ) || ! entry.length || entry.length !== parsed.handles + 1 ) { // Reject invalid input 4423 throw new Error( "noUiSlider: 'connect' option doesn't match handle count." ); 4424 } else { 4425 connect = entry; 4426 } 4427 parsed.connect = connect; 4428 } 4429 function testOrientation( parsed, entry ) { 4430 // Set orientation to an a numerical value for easy 4431 // array selection. 4432 switch ( entry ) { 4433 case 'horizontal': 4434 parsed.ort = 0; 4435 break; 4436 case 'vertical': 4437 parsed.ort = 1; 4438 break; 4439 default: 4440 throw new Error( "noUiSlider: 'orientation' option is invalid." ); 4441 } 4442 } 4443 function testMargin( parsed, entry ) { 4444 if ( ! isNumeric( entry ) ) { 4445 throw new Error( "noUiSlider: 'margin' option must be numeric." ); 4446 } 4447 // Issue #582 4448 if ( entry === 0 ) { 4449 return; 4450 } 4451 parsed.margin = parsed.spectrum.getDistance( entry ); 4452 } 4453 function testLimit( parsed, entry ) { 4454 if ( ! isNumeric( entry ) ) { 4455 throw new Error( "noUiSlider: 'limit' option must be numeric." ); 4456 } 4457 parsed.limit = parsed.spectrum.getDistance( entry ); 4458 if ( ! parsed.limit || parsed.handles < 2 ) { 4459 throw new Error( "noUiSlider: 'limit' option is only supported on linear sliders with 2 or more handles." ); 4460 } 4461 } 4462 function testPadding( parsed, entry ) { 4463 var index; 4464 var totalPadding; 4465 var firstValue; 4466 var lastValue; 4467 if ( ! isNumeric( entry ) && ! Array.isArray( entry ) ) { 4468 throw new Error( "noUiSlider: 'padding' option must be numeric or array of exactly 2 numbers." ); 4469 } 4470 if ( Array.isArray( entry ) && ! ( entry.length === 2 || isNumeric( entry[ 0 ] ) || isNumeric( entry[ 1 ] ) ) ) { 4471 throw new Error( "noUiSlider: 'padding' option must be numeric or array of exactly 2 numbers." ); 4472 } 4473 if ( entry === 0 ) { 4474 return; 4475 } 4476 if ( ! Array.isArray( entry ) ) { 4477 entry = [ entry, entry ]; 4478 } 4479 // 'getDistance' returns false for invalid values. 4480 parsed.padding = [ parsed.spectrum.getDistance( entry[ 0 ] ), parsed.spectrum.getDistance( entry[ 1 ] ) ]; 4481 for ( index = 0; index < parsed.spectrum.xNumSteps.length - 1; index++ ) {
4482 // last "range" can't contain step size as it is purely an endpoint. 4483 if ( parsed.padding[ 0 ][ index ] < 0 || parsed.padding[ 1 ][ index ] < 0 ) { 4484 throw new Error( "noUiSlider: 'padding' option must be a positive number(s)." ); 4485 } 4486 } 4487 totalPadding = entry[ 0 ] + entry[ 1 ]; 4488 firstValue = parsed.spectrum.xVal[ 0 ]; 4489 lastValue = parsed.spectrum.xVal[ parsed.spectrum.xVal.length - 1 ]; 4490 if ( totalPadding / ( lastValue - firstValue ) > 1 ) { 4491 throw new Error( "noUiSlider: 'padding' option must not exceed 100% of the range." ); 4492 } 4493 } 4494 function testDirection( parsed, entry ) { 4495 // Set direction as a numerical value for easy parsing. 4496 // Invert connection for RTL sliders, so that the proper 4497 // handles get the connect/background classes. 4498 switch ( entry ) { 4499 case 'ltr': 4500 parsed.dir = 0; 4501 break; 4502 case 'rtl': 4503 parsed.dir = 1; 4504 break; 4505 default: 4506 throw new Error( "noUiSlider: 'direction' option was not recognized." ); 4507 } 4508 } 4509 function testBehaviour( parsed, entry ) { 4510 var tap; 4511 var drag; 4512 var fixed; 4513 var snap; 4514 var hover; 4515 var unconstrained; 4516 var dragAll; 4517 var smoothSteps; 4518 // Make sure the input is a string. 4519 if ( typeof entry !== 'string' ) { 4520 throw new Error( "noUiSlider: 'behaviour' must be a string containing options." ); 4521 } 4522 // Check if the string contains any keywords. 4523 // None are required. 4524 tap = entry.indexOf( 'tap' ) >= 0; 4525 drag = entry.indexOf( 'drag' ) >= 0; 4526 fixed = entry.indexOf( 'fixed' ) >= 0; 4527 snap = entry.indexOf( 'snap' ) >= 0; 4528 hover = entry.indexOf( 'hover' ) >= 0; 4529 unconstrained = entry.indexOf( 'unconstrained' ) >= 0; 4530 dragAll = entry.indexOf( 'drag-all' ) >= 0; 4531 smoothSteps = entry.indexOf( 'smooth-steps' ) >= 0; 4532 if ( fixed ) { 4533 if ( parsed.handles !== 2 ) { 4534 throw new Error( "noUiSlider: 'fixed' behaviour must be used with 2 handles" ); 4535 } 4536 // Use margin to enforce fixed state 4537 testMargin( parsed, parsed.start[ 1 ] - parsed.start[ 0 ] ); 4538 } 4539 if ( unconstrained && ( parsed.margin || parsed.limit ) ) { 4540 throw new Error( "noUiSlider: 'unconstrained' behaviour cannot be used with margin or limit" ); 4541 } 4542 parsed.events = { 4543 tap: tap || snap, 4544 drag: drag, 4545 dragAll: dragAll, 4546 smoothSteps: smoothSteps, 4547 fixed: fixed, 4548 snap: snap, 4549 hover: hover, 4550 unconstrained: unconstrained 4551 }; 4552 } 4553 function testTooltips( parsed, entry ) { 4554 var i; 4555 if ( entry === false ) { 4556 return; 4557 } 4558 if ( entry === true || isValidPartialFormatter( entry ) ) { 4559 parsed.tooltips = []; 4560 for ( i = 0; i < parsed.handles; i++ ) { 4561 parsed.tooltips.push( entry ); 4562 } 4563 } else { 4564 entry = asArray( entry ); 4565 if ( entry.length !== parsed.handles ) { 4566 throw new Error( 'noUiSlider: must pass a formatter for all handles.' ); 4567 } 4568 entry.forEach( function( formatter ) { 4569 if ( typeof formatter !== 'boolean' && ! isValidPartialFormatter( formatter ) ) { 4570 throw new Error( "noUiSlider: 'tooltips' must be passed a formatter or 'false'." ); 4571 } 4572 } ); 4573 parsed.tooltips = entry; 4574 } 4575 } 4576 function testHandleAttributes( parsed, entry ) { 4577 if ( entry.length !== parsed.handles ) { 4578 throw new Error( 'noUiSlider: must pass a attributes for all handles.' ); 4579 } 4580 parsed.handleAttributes = entry; 4581 } 4582 function testAriaFormat( parsed, entry ) { 4583 if ( ! isValidPartialFormatter( entry ) ) { 4584 throw new Error( "noUiSlider: 'ariaFormat' requires 'to' method." ); 4585 } 4586 parsed.ariaFormat = entry; 4587 } 4588 function testFormat( parsed, entry ) { 4589 if ( ! isValidFormatter( entry ) ) { 4590 throw new Error( "noUiSlider: 'format' requires 'to' and 'from' methods." ); 4591 } 4592 parsed.format = entry; 4593 } 4594 function testKeyboardSupport( parsed, entry ) { 4595 if ( typeof entry !== 'boolean' ) { 4596 throw new Error( "noUiSlider: 'keyboardSupport' option must be a boolean." ); 4597 } 4598 parsed.keyboardSupport = entry; 4599 } 4600 function testDocumentElement( parsed, entry ) { 4601 // This is an advanced option. Passed values are used without validation. 4602 parsed.documentElement = entry; 4603 } 4604 function testCssPrefix( parsed, entry ) { 4605 if ( typeof entry !== 'string' && entry !== false ) { 4606 throw new Error( "noUiSlider: 'cssPrefix' must be a string or `false`." ); 4607 } 4608 parsed.cssPrefix = entry; 4609 }
4610 function testCssClasses( parsed, entry ) { 4611 if ( typeof entry !== 'object' ) { 4612 throw new Error( "noUiSlider: 'cssClasses' must be an object." ); 4613 } 4614 if ( typeof parsed.cssPrefix === 'string' ) { 4615 parsed.cssClasses = {}; 4616 Object.keys( entry ).forEach( function( key ) { 4617 parsed.cssClasses[ key ] = parsed.cssPrefix + entry[ key ]; 4618 } ); 4619 } else { 4620 parsed.cssClasses = entry; 4621 } 4622 } 4623 // Test all developer settings and parse to assumption-safe values. 4624 function testOptions( options ) { 4625 // To prove a fix for #537, freeze options here. 4626 // If the object is modified, an error will be thrown. 4627 // Object.freeze(options); 4628 var parsed = { 4629 margin: null, 4630 limit: null, 4631 padding: null, 4632 animate: true, 4633 animationDuration: 300, 4634 ariaFormat: defaultFormatter, 4635 format: defaultFormatter 4636 }; 4637 // Tests are executed in the order they are presented here. 4638 var tests = { 4639 step: { r: false, t: testStep }, 4640 keyboardPageMultiplier: { r: false, t: testKeyboardPageMultiplier }, 4641 keyboardMultiplier: { r: false, t: testKeyboardMultiplier }, 4642 keyboardDefaultStep: { r: false, t: testKeyboardDefaultStep }, 4643 start: { r: true, t: testStart }, 4644 connect: { r: true, t: testConnect }, 4645 direction: { r: true, t: testDirection }, 4646 snap: { r: false, t: testSnap }, 4647 animate: { r: false, t: testAnimate }, 4648 animationDuration: { r: false, t: testAnimationDuration }, 4649 range: { r: true, t: testRange }, 4650 orientation: { r: false, t: testOrientation }, 4651 margin: { r: false, t: testMargin }, 4652 limit: { r: false, t: testLimit }, 4653 padding: { r: false, t: testPadding }, 4654 behaviour: { r: true, t: testBehaviour }, 4655 ariaFormat: { r: false, t: testAriaFormat }, 4656 format: { r: false, t: testFormat }, 4657 tooltips: { r: false, t: testTooltips }, 4658 keyboardSupport: { r: true, t: testKeyboardSupport }, 4659 documentElement: { r: false, t: testDocumentElement }, 4660 cssPrefix: { r: true, t: testCssPrefix },
4661 cssClasses: { r: true, t: testCssClasses }, 4662 handleAttributes: { r: false, t: testHandleAttributes } 4663 }; 4664 var defaults = { 4665 connect: false, 4666 direction: 'ltr', 4667 behaviour: 'tap', 4668 orientation: 'horizontal', 4669 keyboardSupport: true, 4670 cssPrefix: 'noui-', 4671 cssClasses: cssClasses, 4672 keyboardPageMultiplier: 5, 4673 keyboardMultiplier: 1, 4674 keyboardDefaultStep: 10 4675 }; 4676 var d; 4677 var msPrefix; 4678 var noPrefix; 4679 var styles; 4680 // AriaFormat defaults to regular format, if any. 4681 if ( options.format && ! options.ariaFormat ) { 4682 options.ariaFormat = options.format; 4683 } 4684 // Run all options through a testing mechanism to ensure correct 4685 // input. It should be noted that options might get modified to 4686 // be handled properly. E.g. wrapping integers in arrays. 4687 Object.keys( tests ).forEach( function( name ) { 4688 // If the option isn't set, but it is required, throw an error. 4689 if ( ! isSet( options[ name ] ) && defaults[ name ] === undefined ) { 4690 if ( tests[ name ].r ) { 4691 throw new Error( "noUiSlider: '" + name + "' is required." ); 4692 } 4693 return; 4694 } 4695 tests[ name ].t( parsed, ! isSet( options[ name ] ) ? defaults[ name ] : options[ name ] ); 4696 } ); 4697 // Forward pips options 4698 parsed.pips = options.pips; 4699 // All recent browsers accept unprefixed transform. 4700 // We need -ms- for IE9 and -webkit- for older Android; 4701 // Assume use of -webkit- if unprefixed and -ms- are not supported. 4702 // https://caniuse.com/#feat=transforms2d 4703 d = document.createElement( 'div' ); 4704 msPrefix = d.style.msTransform !== undefined; 4705 noPrefix = d.style.transform !== undefined; 4706 parsed.transformRule = noPrefix ? 'transform' : msPrefix ? 'msTransform' : 'webkitTransform'; 4707 // Pips don't move, so we can place them using left/top. 4708 styles = [ 4709 [ 'left', 'top' ], 4710 [ 'right', 'bottom' ] 4711 ]; 4712 parsed.style = styles[ parsed.dir ][ parsed.ort ]; 4713 return parsed; 4714 } 4715 //endregion 4716 function scope( target, options, originalOptions ) { 4717 var actions = getActions(); 4718 var supportsTouchActionNone = getSupportsTouchActionNone(); 4719 var supportsPassive = supportsTouchActionNone && getSupportsPassive(); 4720 // All variables local to 'scope' are prefixed with 'scope_' 4721 // Slider DOM Nodes 4722 var scope_Target = target; 4723 var scope_Base; 4724 var scope_Handles; 4725 var scope_Connects; 4726 var scope_Pips; 4727 var scope_Tooltips; 4728 // Slider state values 4729 var scope_Spectrum = options.spectrum; 4730 var scope_Values = []; 4731 var scope_Locations = []; 4732 var scope_HandleNumbers = []; 4733 var scope_ActiveHandlesCount = 0; 4734 var scope_Events = {}; 4735 // Document Nodes 4736 var scope_Document = target.ownerDocument; 4737 var scope_DocumentElement = options.documentElement || scope_Document.documentElement; 4738 var scope_Body = scope_Document.body; 4739 // For horizontal sliders in standard ltr documents, 4740 // make .noUi-origin overflow to the left so the document doesn't scroll. 4741 var scope_DirOffset = scope_Document.dir === 'rtl' || options.ort === 1 ? 0 : 100; 4742 var scope_Self; 4743 // Creates a node, adds it to target, returns the new node. 4744 function addNodeTo( addTarget, className ) { 4745 var div = scope_Document.createElement( 'div' ); 4746 if ( className ) { 4747 addClass( div, className ); 4748 } 4749 addTarget.appendChild( div ); 4750 return div; 4751 } 4752 // Append a origin to the base 4753 function addOrigin( base, handleNumber ) { 4754 var origin = addNodeTo( base, options.cssClasses.origin ); 4755 var handle = addNodeTo( origin, options.cssClasses.handle ); 4756 var attributes_1; 4757 addNodeTo( handle, options.cssClasses.touchArea ); 4758 handle.setAttribute( 'data-handle', String( handleNumber ) ); 4759 if ( options.keyboardSupport ) { 4760 // https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex 4761 // 0 = focusable and reachable 4762 handle.setAttribute( 'tabindex', '0' ); 4763 handle.addEventListener( 'keydown', function( event ) {
vendor: 19,677 bytes, lines 4764-5261
4764 return eventKeydown( event, handleNumber ); 4765 } ); 4766 } 4767 if ( options.handleAttributes !== undefined ) { 4768 attributes_1 = options.handleAttributes[ handleNumber ]; 4769 Object.keys( attributes_1 ).forEach( function( attribute ) { 4770 handle.setAttribute( attribute, attributes_1[ attribute ] ); 4771 } ); 4772 } 4773 handle.setAttribute( 'role', 'slider' ); 4774 handle.setAttribute( 'aria-orientation', options.ort ? 'vertical' : 'horizontal' ); 4775 if ( handleNumber === 0 ) { 4776 addClass( handle, options.cssClasses.handleLower ); 4777 } else if ( handleNumber === options.handles - 1 ) { 4778 addClass( handle, options.cssClasses.handleUpper ); 4779 } 4780 origin.handle = handle; 4781 return origin; 4782 } 4783 // Insert nodes for connect elements 4784 function addConnect( base, add ) { 4785 if ( ! add ) { 4786 return false; 4787 } 4788 return addNodeTo( base, options.cssClasses.connect ); 4789 } 4790 // Add handles to the slider base. 4791 function addElements( connectOptions, base ) { 4792 var connectBase = addNodeTo( base, options.cssClasses.connects ); 4793 var i; 4794 scope_Handles = []; 4795 scope_Connects = []; 4796 scope_Connects.push( addConnect( connectBase, connectOptions[ 0 ] ) ); 4797 // [::::O====O====O====] 4798 // connectOptions = [0, 1, 1, 1] 4799 for ( i = 0; i < options.handles; i++ ) { 4800 // Keep a list of all added handles. 4801 scope_Handles.push( addOrigin( base, i ) ); 4802 scope_HandleNumbers[ i ] = i; 4803 scope_Connects.push( addConnect( connectBase, connectOptions[ i + 1 ] ) ); 4804 } 4805 } 4806 // Initialize a single slider. 4807 function addSlider( addTarget ) { 4808 var textDirection; 4809 // Apply classes and data to the target. 4810 addClass( addTarget, options.cssClasses.target ); 4811 if ( options.dir === 0 ) { 4812 addClass( addTarget, options.cssClasses.ltr ); 4813 } else { 4814 addClass( addTarget, options.cssClasses.rtl ); 4815 } 4816 if ( options.ort === 0 ) { 4817 addClass( addTarget, options.cssClasses.horizontal ); 4818 } else { 4819 addClass( addTarget, options.cssClasses.vertical ); 4820 } 4821 textDirection = getComputedStyle( addTarget ).direction; 4822 if ( textDirection === 'rtl' ) { 4823 addClass( addTarget, options.cssClasses.textDirectionRtl ); 4824 } else { 4825 addClass( addTarget, options.cssClasses.textDirectionLtr ); 4826 } 4827 return addNodeTo( addTarget, options.cssClasses.base ); 4828 } 4829 function addTooltip( handle, handleNumber ) { 4830 if ( ! options.tooltips || ! options.tooltips[ handleNumber ] ) { 4831 return false; 4832 } 4833 return addNodeTo( handle.firstChild, options.cssClasses.tooltip ); 4834 } 4835 function isSliderDisabled() { 4836 return scope_Target.hasAttribute( 'disabled' ); 4837 } 4838 // Disable the slider dragging if any handle is disabled 4839 function isHandleDisabled( handleNumber ) { 4840 var handleOrigin = scope_Handles[ handleNumber ]; 4841 return handleOrigin.hasAttribute( 'disabled' ); 4842 } 4843 function disable( handleNumber ) { 4844 if ( handleNumber !== null && handleNumber !== undefined ) { 4845 scope_Handles[ handleNumber ].setAttribute( 'disabled', '' ); 4846 scope_Handles[ handleNumber ].handle.removeAttribute( 'tabindex' ); 4847 } else { 4848 scope_Target.setAttribute( 'disabled', '' ); 4849 scope_Handles.forEach( function( handle ) { 4850 handle.handle.removeAttribute( 'tabindex' ); 4851 } ); 4852 } 4853 } 4854 function enable( handleNumber ) { 4855 if ( handleNumber !== null && handleNumber !== undefined ) { 4856 scope_Handles[ handleNumber ].removeAttribute( 'disabled' ); 4857 scope_Handles[ handleNumber ].handle.setAttribute( 'tabindex', '0' ); 4858 } else { 4859 scope_Target.removeAttribute( 'disabled' ); 4860 scope_Handles.forEach( function( handle ) { 4861 handle.removeAttribute( 'disabled' ); 4862 handle.handle.setAttribute( 'tabindex', '0' ); 4863 } ); 4864 } 4865 } 4866 function removeTooltips() { 4867 if ( scope_Tooltips ) { 4868 removeEvent( 'update' + INTERNAL_EVENT_NS.tooltips ); 4869 scope_Tooltips.forEach( function( tooltip ) { 4870 if ( tooltip ) { 4871 removeElement( tooltip ); 4872 } 4873 } ); 4874 scope_Tooltips = null; 4875 } 4876 } 4877 // The tooltips option is a shorthand for using the 'update' event. 4878 function tooltips() { 4879 var formattedValue; 4880 removeTooltips(); 4881 // Tooltips are added with options.tooltips in original order. 4882 scope_Tooltips = scope_Handles.map( addTooltip ); 4883 bindEvent( 'update' + INTERNAL_EVENT_NS.tooltips, function( values, handleNumber, unencoded ) { 4884 if ( ! scope_Tooltips || ! options.tooltips ) { 4885 return; 4886 } 4887 if ( scope_Tooltips[ handleNumber ] === false ) { 4888 return; 4889 } 4890 formattedValue = values[ handleNumber ]; 4891 if ( options.tooltips[ handleNumber ] !== true ) { 4892 formattedValue = options.tooltips[ handleNumber ].to( unencoded[ handleNumber ] ); 4893 } 4894 scope_Tooltips[ handleNumber ].innerHTML = formattedValue; 4895 } ); 4896 } 4897 function aria() { 4898 removeEvent( 'update' + INTERNAL_EVENT_NS.aria ); 4899 bindEvent( 'update' + INTERNAL_EVENT_NS.aria, function( values, handleNumber, unencoded, tap, positions ) { 4900 // Update Aria Values for all handles, as a change in one changes min and max values for the next. 4901 scope_HandleNumbers.forEach( function( index ) { 4902 var handle = scope_Handles[ index ]; 4903 var min = checkHandlePosition( scope_Locations, index, 0, true, true, true ); 4904 var max = checkHandlePosition( scope_Locations, index, 100, true, true, true ); 4905 var now = positions[ index ]; 4906 // Formatted value for display 4907 var text = String( options.ariaFormat.to( unencoded[ index ] ) ); 4908 // Map to slider range values 4909 min = scope_Spectrum.fromStepping( min ).toFixed( 1 ); 4910 max = scope_Spectrum.fromStepping( max ).toFixed( 1 ); 4911 now = scope_Spectrum.fromStepping( now ).toFixed( 1 ); 4912 handle.children[ 0 ].setAttribute( 'aria-valuemin', min ); 4913 handle.children[ 0 ].setAttribute( 'aria-valuemax', max ); 4914 handle.children[ 0 ].setAttribute( 'aria-valuenow', now ); 4915 handle.children[ 0 ].setAttribute( 'aria-valuetext', text ); 4916 } ); 4917 } ); 4918 } 4919 function getGroup( ipips ) { 4920 var interval; 4921 var spread; 4922 var values; 4923 // Use the range. 4924 if ( ipips.mode === exports.PipsMode.Range || ipips.mode === exports.PipsMode.Steps ) { 4925 return scope_Spectrum.xVal; 4926 } 4927 if ( ipips.mode === exports.PipsMode.Count ) { 4928 if ( ipips.values < 2 ) { 4929 throw new Error( "noUiSlider: 'values' (>= 2) required for mode 'count'." ); 4930 } 4931 // Divide 0 - 100 in 'count' parts. 4932 interval = ipips.values - 1; 4933 spread = 100 / interval; 4934 values = []; 4935 // List these parts and have them handled as 'positions'. 4936 while ( interval-- ) { 4937 values[ interval ] = interval * spread; 4938 } 4939 values.push( 100 ); 4940 return mapToRange( values, ipips.stepped ); 4941 } 4942 if ( ipips.mode === exports.PipsMode.Positions ) { 4943 // Map all percentages to on-range values. 4944 return mapToRange( ipips.values, ipips.stepped ); 4945 } 4946 if ( ipips.mode === exports.PipsMode.Values ) { 4947 // If the value must be stepped, it needs to be converted to a percentage first. 4948 if ( ipips.stepped ) { 4949 return ipips.values.map( function( value ) { 4950 // Convert to percentage, apply step, return to value. 4951 return scope_Spectrum.fromStepping( scope_Spectrum.getStep( scope_Spectrum.toStepping( value ) ) ); 4952 } ); 4953 } 4954 // Otherwise, we can simply use the values. 4955 return ipips.values; 4956 } 4957 return []; // ipips.mode = never 4958 } 4959 function mapToRange( values, stepped ) { 4960 return values.map( function( value ) { 4961 return scope_Spectrum.fromStepping( stepped ? scope_Spectrum.getStep( value ) : value ); 4962 } ); 4963 } 4964 function generateSpread( ipips ) { 4965 var group = getGroup( ipips ); 4966 var indexes = {}; 4967 var firstInRange = scope_Spectrum.xVal[ 0 ]; 4968 var lastInRange = scope_Spectrum.xVal[ scope_Spectrum.xVal.length - 1 ]; 4969 var ignoreFirst = false; 4970 var ignoreLast = false; 4971 var prevPct = 0; 4972 function safeIncrement( value, increment ) { 4973 // Avoid floating point variance by dropping the smallest decimal places. 4974 return Number( ( value + increment ).toFixed( 7 ) ); 4975 } 4976 // Create a copy of the group, sort it and filter away all duplicates. 4977 group = unique( group.slice().sort( function( a, b ) { 4978 return a - b; 4979 } ) ); 4980 // Make sure the range starts with the first element. 4981 if ( group[ 0 ] !== firstInRange ) { 4982 group.unshift( firstInRange ); 4983 ignoreFirst = true; 4984 } 4985 // Likewise for the last one. 4986 if ( group[ group.length - 1 ] !== lastInRange ) { 4987 group.push( lastInRange ); 4988 ignoreLast = true; 4989 } 4990 group.forEach( function( current, index ) { 4991 // Get the current step and the lower + upper positions. 4992 var step; 4993 var i; 4994 var q; 4995 var low = current; 4996 var high = group[ index + 1 ]; 4997 var newPct; 4998 var pctDifference; 4999 var pctPos; 5000 var type; 5001 var steps; 5002 var realSteps; 5003 var stepSize; 5004 var isSteps = ipips.mode === exports.PipsMode.Steps; 5005 // When using 'steps' mode, use the provided steps. 5006 // Otherwise, we'll step on to the next subrange. 5007 if ( isSteps ) { 5008 step = scope_Spectrum.xNumSteps[ index ]; 5009 } 5010 // Default to a 'full' step. 5011 if ( ! step ) { 5012 step = high - low; 5013 } 5014 // If high is undefined we are at the last subrange. Make sure it iterates once (#1088) 5015 if ( high === undefined ) { 5016 high = low; 5017 } 5018 // Make sure step isn't 0, which would cause an infinite loop (#654) 5019 step = Math.max( step, 0.0000001 ); 5020 // Find all steps in the subrange. 5021 for ( i = low; i <= high; i = safeIncrement( i, step ) ) { 5022 // Get the percentage value for the current step, 5023 // calculate the size for the subrange. 5024 newPct = scope_Spectrum.toStepping( i ); 5025 pctDifference = newPct - prevPct; 5026 steps = pctDifference / ( ipips.density || 1 ); 5027 realSteps = Math.round( steps ); 5028 // This ratio represents the amount of percentage-space a point indicates. 5029 // For a density 1 the points/percentage = 1. For density 2, that percentage needs to be re-divided. 5030 // Round the percentage offset to an even number, then divide by two 5031 // to spread the offset on both sides of the range. 5032 stepSize = pctDifference / realSteps; 5033 // Divide all points evenly, adding the correct number to this subrange. 5034 // Run up to <= so that 100% gets a point, event if ignoreLast is set. 5035 for ( q = 1; q <= realSteps; q += 1 ) { 5036 // The ratio between the rounded value and the actual size might be ~1% off. 5037 // Correct the percentage offset by the number of points 5038 // per subrange. density = 1 will result in 100 points on the 5039 // full range, 2 for 50, 4 for 25, etc. 5040 pctPos = prevPct + ( q * stepSize ); 5041 indexes[ pctPos.toFixed( 5 ) ] = [ scope_Spectrum.fromStepping( pctPos ), 0 ]; 5042 } 5043 // Determine the point type. 5044 type = group.indexOf( i ) > -1 ? exports.PipsType.LargeValue : isSteps ? exports.PipsType.SmallValue : exports.PipsType.NoValue; 5045 // Enforce the 'ignoreFirst' option by overwriting the type for 0. 5046 if ( ! index && ignoreFirst && i !== high ) { 5047 type = 0; 5048 } 5049 if ( ! ( i === high && ignoreLast ) ) { 5050 // Mark the 'type' of this point. 0 = plain, 1 = real value, 2 = step value. 5051 indexes[ newPct.toFixed( 5 ) ] = [ i, type ]; 5052 } 5053 // Update the percentage count. 5054 prevPct = newPct; 5055 } 5056 } ); 5057 return indexes; 5058 } 5059 function addMarking( spread, filterFunc, formatter ) { 5060 var _a, _b; 5061 var element = scope_Document.createElement( 'div' ); 5062 var valueSizeClasses = ( _a = {}, 5063 _a[ exports.PipsType.None ] = '', 5064 _a[ exports.PipsType.NoValue ] = options.cssClasses.valueNormal, 5065 _a[ exports.PipsType.LargeValue ] = options.cssClasses.valueLarge, 5066 _a[ exports.PipsType.SmallValue ] = options.cssClasses.valueSub, 5067 _a ); 5068 var markerSizeClasses = ( _b = {}, 5069 _b[ exports.PipsType.None ] = '', 5070 _b[ exports.PipsType.NoValue ] = options.cssClasses.markerNormal, 5071 _b[ exports.PipsType.LargeValue ] = options.cssClasses.markerLarge, 5072 _b[ exports.PipsType.SmallValue ] = options.cssClasses.markerSub, 5073 _b ); 5074 var valueOrientationClasses = [ options.cssClasses.valueHorizontal, options.cssClasses.valueVertical ]; 5075 var markerOrientationClasses = [ options.cssClasses.markerHorizontal, options.cssClasses.markerVertical ]; 5076 addClass( element, options.cssClasses.pips ); 5077 addClass( element, options.ort === 0 ? options.cssClasses.pipsHorizontal : options.cssClasses.pipsVertical ); 5078 function getClasses( type, source ) { 5079 var a = source === options.cssClasses.value; 5080 var orientationClasses = a ? valueOrientationClasses : markerOrientationClasses; 5081 var sizeClasses = a ? valueSizeClasses : markerSizeClasses; 5082 return source + ' ' + orientationClasses[ options.ort ] + ' ' + sizeClasses[ type ]; 5083 } 5084 function addSpread( key, value, type ) { 5085 var node; 5086 // Apply the filter function, if it is set. 5087 type = filterFunc ? filterFunc( value, type ) : type; 5088 if ( type === exports.PipsType.None ) { 5089 return; 5090 } 5091 // Add a marker for every point 5092 node = addNodeTo( element, false ); 5093 node.className = getClasses( type, options.cssClasses.marker ); 5094 node.style[ options.style ] = key + '%'; 5095 // Values are only appended for points marked '1' or '2'. 5096 if ( type > exports.PipsType.NoValue ) { 5097 node = addNodeTo( element, false ); 5098 node.className = getClasses( type, options.cssClasses.value ); 5099 node.setAttribute( 'data-value', String( value ) ); 5100 node.style[ options.style ] = key + '%'; 5101 node.innerHTML = String( formatter.to( value ) ); 5102 } 5103 } 5104 // Append all points. 5105 Object.keys( spread ).forEach( function( key ) { 5106 addSpread( key, spread[ key ][ 0 ], spread[ key ][ 1 ] ); 5107 } ); 5108 return element; 5109 } 5110 function removePips() { 5111 if ( scope_Pips ) { 5112 removeElement( scope_Pips ); 5113 scope_Pips = null; 5114 } 5115 } 5116 function pips( ipips ) { 5117 var filter; 5118 var spread; 5119 var format; 5120 // Fix #669 5121 removePips(); 5122 spread = generateSpread( ipips ); 5123 filter = ipips.filter; 5124 format = ipips.format || { 5125 to: function( value ) { 5126 return String( Math.round( value ) ); 5127 } 5128 }; 5129 scope_Pips = scope_Target.appendChild( addMarking( spread, filter, format ) ); 5130 return scope_Pips; 5131 } 5132 // Shorthand for base dimensions. 5133 function baseSize() { 5134 var rect = scope_Base.getBoundingClientRect(); 5135 var alt = ( 'offset' + [ 'Width', 'Height' ][ options.ort ] ); 5136 return options.ort === 0 ? rect.width || scope_Base[ alt ] : rect.height || scope_Base[ alt ]; 5137 } 5138 // Handler for attaching events trough a proxy. 5139 function attachEvent( events, element, callback, data ) { 5140 // This function can be used to 'filter' events to the slider. 5141 // element is a node, not a nodeList 5142 var method = function( event ) { 5143 var e = fixEvent( event, data.pageOffset, data.target || element ); 5144 // fixEvent returns false if this event has a different target 5145 // when handling (multi-) touch events; 5146 if ( ! e ) { 5147 return false; 5148 } 5149 // doNotReject is passed by all end events to make sure released touches 5150 // are not rejected, leaving the slider "stuck" to the cursor; 5151 if ( isSliderDisabled() && ! data.doNotReject ) { 5152 return false; 5153 } 5154 // Stop if an active 'tap' transition is taking place. 5155 if ( hasClass( scope_Target, options.cssClasses.tap ) && ! data.doNotReject ) { 5156 return false; 5157 } 5158 // Ignore right or middle clicks on start #454 5159 if ( events === actions.start && e.buttons !== undefined && e.buttons > 1 ) { 5160 return false; 5161 } 5162 // Ignore right or middle clicks on start #454 5163 if ( data.hover && e.buttons ) { 5164 return false; 5165 } 5166 // 'supportsPassive' is only true if a browser also supports touch-action: none in CSS. 5167 // iOS safari does not, so it doesn't get to benefit from passive scrolling. iOS does support 5168 // touch-action: manipulation, but that allows panning, which breaks 5169 // sliders after zooming/on non-responsive pages. 5170 // See: https://bugs.webkit.org/show_bug.cgi?id=133112 5171 if ( ! supportsPassive ) { 5172 e.preventDefault(); 5173 } 5174 e.calcPoint = e.points[ options.ort ]; 5175 // Call the event handler with the event [ and additional data ]. 5176 callback( e, data ); 5177 }; 5178 var methods = []; 5179 // Bind a closure on the target for every event type. 5180 events.split( ' ' ).forEach( function( eventName ) { 5181 element.addEventListener( eventName, method, supportsPassive ? { passive: true } : false ); 5182 methods.push( [ eventName, method ] ); 5183 } ); 5184 return methods; 5185 } 5186 // Provide a clean event with standardized offset values. 5187 function fixEvent( e, pageOffset, eventTarget ) { 5188 // Filter the event to register the type, which can be 5189 // touch, mouse or pointer. Offset changes need to be 5190 // made on an event specific basis. 5191 var touch = e.type.indexOf( 'touch' ) === 0; 5192 var mouse = e.type.indexOf( 'mouse' ) === 0; 5193 var pointer = e.type.indexOf( 'pointer' ) === 0; 5194 var x = 0; 5195 var y = 0; 5196 var isTouchOnTarget; 5197 var targetTouches; 5198 var targetTouch; 5199 // IE10 implemented pointer events with a prefix; 5200 if ( e.type.indexOf( 'MSPointer' ) === 0 ) { 5201 pointer = true; 5202 } 5203 // Erroneous events seem to be passed in occasionally on iOS/iPadOS after user finishes interacting with 5204 // the slider. They appear to be of type MouseEvent, yet they don't have usual properties set. Ignore 5205 // events that have no touches or buttons associated with them. (#1057, #1079, #1095) 5206 if ( e.type === 'mousedown' && ! e.buttons && ! e.touches ) { 5207 return false; 5208 } 5209 // The only thing one handle should be concerned about is the touches that originated on top of it. 5210 if ( touch ) { 5211 // Returns true if a touch originated on the target. 5212 isTouchOnTarget = function( checkTouch ) { 5213 return ( checkTouch.target === eventTarget || 5214 eventTarget.contains( checkTouch.target ) || 5215 ( e.composed && e.composedPath().shift() === eventTarget ) ); 5216 }; 5217 // In the case of touchstart events, we need to make sure there is still no more than one 5218 // touch on the target so we look amongst all touches. 5219 if ( e.type === 'touchstart' ) { 5220 targetTouches = Array.prototype.filter.call( e.touches, isTouchOnTarget ); 5221 // Do not support more than one touch per handle. 5222 if ( targetTouches.length > 1 ) { 5223 return false; 5224 } 5225 x = targetTouches[ 0 ].pageX; 5226 y = targetTouches[ 0 ].pageY; 5227 } else { 5228 // In the other cases, find on changedTouches is enough. 5229 targetTouch = Array.prototype.find.call( e.changedTouches, isTouchOnTarget ); 5230 // Cancel if the target touch has not moved. 5231 if ( ! targetTouch ) { 5232 return false; 5233 } 5234 x = targetTouch.pageX; 5235 y = targetTouch.pageY; 5236 } 5237 } 5238 pageOffset = pageOffset || getPageOffset( scope_Document ); 5239 if ( mouse || pointer ) { 5240 x = e.clientX + pageOffset.x; 5241 y = e.clientY + pageOffset.y; 5242 } 5243 e.pageOffset = pageOffset; 5244 e.points = [ x, y ]; 5245 e.cursor = mouse || pointer; // Fix #435 5246 return e; 5247 } 5248 // Translate a coordinate in the document to a percentage on the slider 5249 function calcPointToPercentage( calcPoint ) { 5250 var location = calcPoint - offset( scope_Base, options.ort ); 5251 var proposal = ( location * 100 ) / baseSize(); 5252 // Clamp proposal between 0% and 100% 5253 // Out-of-bound coordinates may occur when .noUi-base pseudo-elements 5254 // are used (e.g. contained handles feature) 5255 proposal = limit( proposal ); 5256 return options.dir ? 100 - proposal : proposal; 5257 } 5258 // Find handle closest to a certain percentage on the slider 5259 function getClosestHandle( clickedPosition ) { 5260 var smallestDifference = 100; 5261 var handleNumber = false;
5262 scope_Handles.forEach( function( handle, index ) { 5263 var handlePosition; 5264 var differenceWithThisHandle; 5265 var clickAtEdge; 5266 var isCloser; 5267 var isCloserAfter; 5268 // Disabled handles are ignored 5269 if ( isHandleDisabled( index ) ) { 5270 return; 5271 } 5272 handlePosition = scope_Locations[ index ]; 5273 differenceWithThisHandle = Math.abs( handlePosition - clickedPosition ); 5274 // Initial state 5275 clickAtEdge = differenceWithThisHandle === 100 && smallestDifference === 100; 5276 // Difference with this handle is smaller than the previously checked handle 5277 isCloser = differenceWithThisHandle < smallestDifference; 5278 isCloserAfter = differenceWithThisHandle <= smallestDifference && clickedPosition > handlePosition; 5279 if ( isCloser || isCloserAfter || clickAtEdge ) { 5280 handleNumber = index; 5281 smallestDifference = differenceWithThisHandle; 5282 } 5283 } ); 5284 return handleNumber; 5285 } 5286 // Fire 'end' when a mouse or pen leaves the document. 5287 function documentLeave( event, data ) { 5288 if ( event.type === 'mouseout' && 5289 event.target.nodeName === 'HTML' && 5290 event.relatedTarget === null ) { 5291 eventEnd( event, data ); 5292 } 5293 } 5294 // Handle movement on document for handle and range drag. 5295 function eventMove( event, data ) { 5296 var movement; 5297 var proposal; 5298 // Fix #498 5299 // Check value of .buttons in 'start' to work around a bug in IE10 mobile (data.buttonsProperty). 5300 // https://connect.microsoft.com/IE/feedback/details/927005/mobile-ie10-windows-phone-buttons-property-of-pointermove-event-always-zero 5301 // IE9 has .buttons and .which zero on mousemove. 5302 // Firefox breaks the spec MDN defines. 5303 if ( navigator.appVersion.indexOf( 'MSIE 9' ) === -1 && event.buttons === 0 && data.buttonsProperty !== 0 ) { 5304 return eventEnd( event, data ); 5305 } 5306 // Check if we are moving up or down 5307 movement = ( options.dir ? -1 : 1 ) * ( event.calcPoint - data.startCalcPoint ); 5308 // Convert the movement into a percentage of the slider width/height 5309 proposal = ( movement * 100 ) / data.baseSize; 5310 moveHandles( movement > 0, proposal, data.locations, data.handleNumbers, data.connect ); 5311 } 5312 // Unbind move events on document, call callbacks. 5313 function eventEnd( event, data ) { 5314 // The handle is no longer active, so remove the class. 5315 if ( data.handle ) { 5316 removeClass( data.handle, options.cssClasses.active ); 5317 scope_ActiveHandlesCount -= 1; 5318 } 5319 // Unbind the move and end events, which are added on 'start'. 5320 data.listeners.forEach( function( c ) { 5321 scope_DocumentElement.removeEventListener( c[ 0 ], c[ 1 ] ); 5322 } ); 5323 if ( scope_ActiveHandlesCount === 0 ) { 5324 // Remove dragging class. 5325 removeClass( scope_Target, options.cssClasses.drag ); 5326 setZindex(); 5327 // Remove cursor styles and text-selection events bound to the body. 5328 if ( event.cursor ) { 5329 scope_Body.style.cursor = ''; 5330 scope_Body.removeEventListener( 'selectstart', preventDefault ); 5331 } 5332 } 5333 if ( options.events.smoothSteps ) { 5334 data.handleNumbers.forEach( function( handleNumber ) { 5335 setHandle( handleNumber, scope_Locations[ handleNumber ], true, true, false, false ); 5336 } ); 5337 data.handleNumbers.forEach( function( handleNumber ) { 5338 fireEvent( 'update', handleNumber ); 5339 } ); 5340 } 5341 data.handleNumbers.forEach( function( handleNumber ) { 5342 fireEvent( 'change', handleNumber ); 5343 fireEvent( 'set', handleNumber ); 5344 fireEvent( 'end', handleNumber ); 5345 } ); 5346 } 5347 // Bind move events on document. 5348 function eventStart( event, data ) { 5349 var handle; 5350 var handleOrigin; 5351 var listeners; 5352 var moveEvent; 5353 var endEvent; 5354 var outEvent; 5355 // Ignore event if any handle is disabled 5356 if ( data.handleNumbers.some( isHandleDisabled ) ) { 5357 return; 5358 } 5359 if ( data.handleNumbers.length === 1 ) { 5360 handleOrigin = scope_Handles[ data.handleNumbers[ 0 ] ]; 5361 handle = handleOrigin.children[ 0 ]; 5362 scope_ActiveHandlesCount += 1; 5363 // Mark the handle as 'active' so it can be styled. 5364 addClass( handle, options.cssClasses.active ); 5365 } 5366 // A drag should never propagate up to the 'tap' event. 5367 event.stopPropagation(); 5368 // Record the event listeners. 5369 listeners = []; 5370 // Attach the move and end events. 5371 moveEvent = attachEvent( actions.move, scope_DocumentElement, eventMove, { 5372 // The event target has changed so we need to propagate the original one so that we keep 5373 // relying on it to extract target touches. 5374 target: event.target, 5375 handle: handle, 5376 connect: data.connect, 5377 listeners: listeners, 5378 startCalcPoint: event.calcPoint, 5379 baseSize: baseSize(), 5380 pageOffset: event.pageOffset, 5381 handleNumbers: data.handleNumbers, 5382 buttonsProperty: event.buttons, 5383 locations: scope_Locations.slice() 5384 } ); 5385 endEvent = attachEvent( actions.end, scope_DocumentElement, eventEnd, { 5386 target: event.target, 5387 handle: handle, 5388 listeners: listeners, 5389 doNotReject: true, 5390 handleNumbers: data.handleNumbers 5391 } ); 5392 outEvent = attachEvent( 'mouseout', scope_DocumentElement, documentLeave, { 5393 target: event.target, 5394 handle: handle, 5395 listeners: listeners, 5396 doNotReject: true, 5397 handleNumbers: data.handleNumbers 5398 } ); 5399 // We want to make sure we pushed the listeners in the listener list rather than creating 5400 // a new one as it has already been passed to the event handlers. 5401 listeners.push.apply( listeners, moveEvent.concat( endEvent, outEvent ) ); 5402 // Text selection isn't an issue on touch devices, 5403 // so adding cursor styles can be skipped. 5404 if ( event.cursor ) { 5405 // Prevent the 'I' cursor and extend the range-drag cursor. 5406 scope_Body.style.cursor = getComputedStyle( event.target ).cursor; 5407 // Mark the target with a dragging state. 5408 if ( scope_Handles.length > 1 ) {
5409 addClass( scope_Target, options.cssClasses.drag ); 5410 } 5411 // Prevent text selection when dragging the handles. 5412 // In noUiSlider <= 9.2.0, this was handled by calling preventDefault on mouse/touch start/move, 5413 // which is scroll blocking. The selectstart event is supported by FireFox starting from version 52, 5414 // meaning the only holdout is iOS Safari. This doesn't matter: text selection isn't triggered there. 5415 // The 'cursor' flag is false. 5416 // See: http://caniuse.com/#search=selectstart 5417 scope_Body.addEventListener( 'selectstart', preventDefault, false ); 5418 } 5419 data.handleNumbers.forEach( function( handleNumber ) { 5420 fireEvent( 'start', handleNumber ); 5421 } ); 5422 } 5423 // Move closest handle to tapped location. 5424 function eventTap( event ) { 5425 var proposal; 5426 var handleNumber; 5427 // The tap event shouldn't propagate up 5428 event.stopPropagation(); 5429 proposal = calcPointToPercentage( event.calcPoint ); 5430 handleNumber = getClosestHandle( proposal ); 5431 // Tackle the case that all handles are 'disabled'. 5432 if ( handleNumber === false ) { 5433 return; 5434 } 5435 // Flag the slider as it is now in a transitional state. 5436 // Transition takes a configurable amount of ms (default 300). Re-enable the slider after that. 5437 if ( ! options.events.snap ) { 5438 addClassFor( scope_Target, options.cssClasses.tap, options.animationDuration ); 5439 } 5440 setHandle( handleNumber, proposal, true, true ); 5441 setZindex(); 5442 fireEvent( 'slide', handleNumber, true ); 5443 fireEvent( 'update', handleNumber, true ); 5444 if ( ! options.events.snap ) { 5445 fireEvent( 'change', handleNumber, true ); 5446 fireEvent( 'set', handleNumber, true ); 5447 } else { 5448 eventStart( event, { handleNumbers: [ handleNumber ] } ); 5449 } 5450 } 5451 // Fires a 'hover' event for a hovered mouse/pen position. 5452 function eventHover( event ) { 5453 var proposal = calcPointToPercentage( event.calcPoint ); 5454 var to = scope_Spectrum.getStep( proposal ); 5455 var value = scope_Spectrum.fromStepping( to ); 5456 Object.keys( scope_Events ).forEach( function( targetEvent ) { 5457 if ( 'hover' === targetEvent.split( '.' )[ 0 ] ) { 5458 scope_Events[ targetEvent ].forEach( function( callback ) { 5459 callback.call( scope_Self, value ); 5460 } ); 5461 } 5462 } ); 5463 } 5464 // Handles keydown on focused handles 5465 // Don't move the document when pressing arrow keys on focused handles 5466 function eventKeydown( event, handleNumber ) { 5467 var horizontalKeys; 5468 var verticalKeys; 5469 var largeStepKeys; 5470 var edgeKeys; 5471 var key; 5472 var isLargeDown; 5473 var isLargeUp; 5474 var isDown; 5475 var isUp; 5476 var isMin; 5477 var isMax; 5478 var to; 5479 var direction; 5480 var steps; 5481 var step; 5482 if ( isSliderDisabled() || isHandleDisabled( handleNumber ) ) { 5483 return false; 5484 } 5485 horizontalKeys = [ 'Left', 'Right' ]; 5486 verticalKeys = [ 'Down', 'Up' ]; 5487 largeStepKeys = [ 'PageDown', 'PageUp' ]; 5488 edgeKeys = [ 'Home', 'End' ]; 5489 if ( options.dir && ! options.ort ) { 5490 // On an right-to-left slider, the left and right keys act inverted 5491 horizontalKeys.reverse(); 5492 } else if ( options.ort && ! options.dir ) { 5493 // On a top-to-bottom slider, the up and down keys act inverted 5494 verticalKeys.reverse(); 5495 largeStepKeys.reverse(); 5496 } 5497 // Strip "Arrow" for IE compatibility. https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key 5498 key = event.key.replace( 'Arrow', '' ); 5499 isLargeDown = key === largeStepKeys[ 0 ]; 5500 isLargeUp = key === largeStepKeys[ 1 ]; 5501 isDown = key === verticalKeys[ 0 ] || key === horizontalKeys[ 0 ] || isLargeDown; 5502 isUp = key === verticalKeys[ 1 ] || key === horizontalKeys[ 1 ] || isLargeUp; 5503 isMin = key === edgeKeys[ 0 ]; 5504 isMax = key === edgeKeys[ 1 ]; 5505 if ( ! isDown && ! isUp && ! isMin && ! isMax ) { 5506 return true; 5507 } 5508 event.preventDefault(); 5509 if ( isUp || isDown ) { 5510 direction = isDown ? 0 : 1; 5511 steps = getNextStepsForHandle( handleNumber ); 5512 step = steps[ direction ]; 5513 // At the edge of a slider, do nothing 5514 if ( step === null ) { 5515 return false; 5516 } 5517 // No step set, use the default of 10% of the sub-range 5518 if ( step === false ) { 5519 step = scope_Spectrum.getDefaultStep( scope_Locations[ handleNumber ], isDown, options.keyboardDefaultStep ); 5520 } 5521 if ( isLargeUp || isLargeDown ) { 5522 step *= options.keyboardPageMultiplier; 5523 } else { 5524 step *= options.keyboardMultiplier; 5525 } 5526 // Step over zero-length ranges (#948); 5527 step = Math.max( step, 0.0000001 ); 5528 // Decrement for down steps 5529 step = ( isDown ? -1 : 1 ) * step; 5530 to = scope_Values[ handleNumber ] + step; 5531 } else if ( isMax ) { 5532 // End key 5533 to = options.spectrum.xVal[ options.spectrum.xVal.length - 1 ]; 5534 } else { 5535 // Home key 5536 to = options.spectrum.xVal[ 0 ]; 5537 } 5538 setHandle( handleNumber, scope_Spectrum.toStepping( to ), true, true ); 5539 fireEvent( 'slide', handleNumber ); 5540 fireEvent( 'update', handleNumber ); 5541 fireEvent( 'change', handleNumber ); 5542 fireEvent( 'set', handleNumber ); 5543 return false;
vendor: 6,566 bytes, lines 5544-5707
5544 } 5545 // Attach events to several slider parts. 5546 function bindSliderEvents( behaviour ) { 5547 var handleBefore; 5548 var handleAfter; 5549 var eventHolders; 5550 var handlesToDrag; 5551 var handleNumbersToDrag; 5552 // Attach the standard drag event to the handles. 5553 if ( ! behaviour.fixed ) { 5554 scope_Handles.forEach( function( handle, index ) { 5555 // These events are only bound to the visual handle 5556 // element, not the 'real' origin element. 5557 attachEvent( actions.start, handle.children[ 0 ], eventStart, { 5558 handleNumbers: [ index ] 5559 } ); 5560 } ); 5561 } 5562 // Attach the tap event to the slider base. 5563 if ( behaviour.tap ) { 5564 attachEvent( actions.start, scope_Base, eventTap, {} ); 5565 } 5566 // Fire hover events 5567 if ( behaviour.hover ) { 5568 attachEvent( actions.move, scope_Base, eventHover, { 5569 hover: true 5570 } ); 5571 } 5572 // Make the range draggable. 5573 if ( behaviour.drag ) { 5574 scope_Connects.forEach( function( connect, index ) { 5575 if ( connect === false || index === 0 || index === scope_Connects.length - 1 ) { 5576 return; 5577 } 5578 handleBefore = scope_Handles[ index - 1 ]; 5579 handleAfter = scope_Handles[ index ]; 5580 eventHolders = [ connect ]; 5581 handlesToDrag = [ handleBefore, handleAfter ]; 5582 handleNumbersToDrag = [ index - 1, index ]; 5583 addClass( connect, options.cssClasses.draggable ); 5584 // When the range is fixed, the entire range can 5585 // be dragged by the handles. The handle in the first 5586 // origin will propagate the start event upward, 5587 // but it needs to be bound manually on the other. 5588 if ( behaviour.fixed ) { 5589 eventHolders.push( handleBefore.children[ 0 ] ); 5590 eventHolders.push( handleAfter.children[ 0 ] ); 5591 } 5592 if ( behaviour.dragAll ) { 5593 handlesToDrag = scope_Handles; 5594 handleNumbersToDrag = scope_HandleNumbers; 5595 } 5596 eventHolders.forEach( function( eventHolder ) { 5597 attachEvent( actions.start, eventHolder, eventStart, { 5598 handles: handlesToDrag, 5599 handleNumbers: handleNumbersToDrag, 5600 connect: connect 5601 } ); 5602 } ); 5603 } ); 5604 } 5605 } 5606 // Attach an event to this slider, possibly including a namespace 5607 function bindEvent( namespacedEvent, callback ) { 5608 scope_Events[ namespacedEvent ] = scope_Events[ namespacedEvent ] || []; 5609 scope_Events[ namespacedEvent ].push( callback ); 5610 // If the event bound is 'update,' fire it immediately for all handles. 5611 if ( namespacedEvent.split( '.' )[ 0 ] === 'update' ) { 5612 scope_Handles.forEach( function( a, index ) { 5613 fireEvent( 'update', index ); 5614 } ); 5615 } 5616 } 5617 function isInternalNamespace( namespace ) { 5618 return namespace === INTERNAL_EVENT_NS.aria || namespace === INTERNAL_EVENT_NS.tooltips; 5619 } 5620 // Undo attachment of event 5621 function removeEvent( namespacedEvent ) { 5622 var event = namespacedEvent && namespacedEvent.split( '.' )[ 0 ]; 5623 var namespace = event ? namespacedEvent.substring( event.length ) : namespacedEvent; 5624 Object.keys( scope_Events ).forEach( function( bind ) { 5625 var tEvent = bind.split( '.' )[ 0 ]; 5626 var tNamespace = bind.substring( tEvent.length ); 5627 if ( ( ! event || event === tEvent ) && ( ! namespace || namespace === tNamespace ) ) { 5628 // only delete protected internal event if intentional 5629 if ( ! isInternalNamespace( tNamespace ) || namespace === tNamespace ) { 5630 delete scope_Events[ bind ]; 5631 } 5632 } 5633 } ); 5634 } 5635 // External event handling 5636 function fireEvent( eventName, handleNumber, tap ) { 5637 Object.keys( scope_Events ).forEach( function( targetEvent ) { 5638 var eventType = targetEvent.split( '.' )[ 0 ]; 5639 if ( eventName === eventType ) { 5640 scope_Events[ targetEvent ].forEach( function( callback ) { 5641 callback.call( 5642 // Use the slider public API as the scope ('this') 5643 scope_Self, 5644 // Return values as array, so arg_1[arg_2] is always valid. 5645 scope_Values.map( options.format.to ), 5646 // Handle index, 0 or 1 5647 handleNumber, 5648 // Un-formatted slider values 5649 scope_Values.slice(), 5650 // Event is fired by tap, true or false 5651 tap || false, 5652 // Left offset of the handle, in relation to the slider 5653 scope_Locations.slice(), 5654 // add the slider public API to an accessible parameter when this is unavailable 5655 scope_Self ); 5656 } ); 5657 } 5658 } ); 5659 } 5660 // Split out the handle positioning logic so the Move event can use it, too 5661 function checkHandlePosition( reference, handleNumber, to, lookBackward, lookForward, getValue, smoothSteps ) { 5662 var distance; 5663 // For sliders with multiple handles, limit movement to the other handle. 5664 // Apply the margin option by adding it to the handle positions. 5665 if ( scope_Handles.length > 1 && ! options.events.unconstrained ) { 5666 if ( lookBackward && handleNumber > 0 ) { 5667 distance = scope_Spectrum.getAbsoluteDistance( reference[ handleNumber - 1 ], options.margin, false ); 5668 to = Math.max( to, distance ); 5669 } 5670 if ( lookForward && handleNumber < scope_Handles.length - 1 ) { 5671 distance = scope_Spectrum.getAbsoluteDistance( reference[ handleNumber + 1 ], options.margin, true ); 5672 to = Math.min( to, distance ); 5673 } 5674 } 5675 // The limit option has the opposite effect, limiting handles to a 5676 // maximum distance from another. Limit must be > 0, as otherwise 5677 // handles would be unmovable. 5678 if ( scope_Handles.length > 1 && options.limit ) { 5679 if ( lookBackward && handleNumber > 0 ) { 5680 distance = scope_Spectrum.getAbsoluteDistance( reference[ handleNumber - 1 ], options.limit, false ); 5681 to = Math.min( to, distance ); 5682 } 5683 if ( lookForward && handleNumber < scope_Handles.length - 1 ) { 5684 distance = scope_Spectrum.getAbsoluteDistance( reference[ handleNumber + 1 ], options.limit, true ); 5685 to = Math.max( to, distance ); 5686 } 5687 } 5688 // The padding option keeps the handles a certain distance from the 5689 // edges of the slider. Padding must be > 0. 5690 if ( options.padding ) { 5691 if ( handleNumber === 0 ) { 5692 distance = scope_Spectrum.getAbsoluteDistance( 0, options.padding[ 0 ], false ); 5693 to = Math.max( to, distance ); 5694 } 5695 if ( handleNumber === scope_Handles.length - 1 ) { 5696 distance = scope_Spectrum.getAbsoluteDistance( 100, options.padding[ 1 ], true ); 5697 to = Math.min( to, distance ); 5698 } 5699 } 5700 if ( ! smoothSteps ) { 5701 to = scope_Spectrum.getStep( to ); 5702 } 5703 // Limit percentage to the 0 - 100 range 5704 to = limit( to ); 5705 // Return false if handle can't move 5706 if ( to === reference[ handleNumber ] && ! getValue ) { 5707 return false;
5708 } 5709 return to; 5710 } 5711 // Uses slider orientation to create CSS rules. a = base value; 5712 function inRuleOrder( v, a ) { 5713 var o = options.ort; 5714 return ( o ? a : v ) + ', ' + ( o ? v : a ); 5715 } 5716 // Moves handle(s) by a percentage 5717 // (bool, % to move, [% where handle started, ...], [index in scope_Handles, ...]) 5718 function moveHandles( upward, proposal, locations, handleNumbers, connect ) { 5719 var proposals = locations.slice(); 5720 // Store first handle now, so we still have it in case handleNumbers is reversed 5721 var firstHandle = handleNumbers[ 0 ]; 5722 var smoothSteps = options.events.smoothSteps; 5723 var b = [ ! upward, upward ]; 5724 var f = [ upward, ! upward ]; 5725 var state = false; 5726 // Copy handleNumbers so we don't change the dataset 5727 handleNumbers = handleNumbers.slice(); 5728 // Check to see which handle is 'leading'. 5729 // If that one can't move the second can't either. 5730 if ( upward ) { 5731 handleNumbers.reverse(); 5732 } 5733 // Step 1: get the maximum percentage that any of the handles can move 5734 if ( handleNumbers.length > 1 ) { 5735 handleNumbers.forEach( function( handleNumber, o ) { 5736 var to = checkHandlePosition( proposals, handleNumber, proposals[ handleNumber ] + proposal, b[ o ], f[ o ], false, smoothSteps ); 5737 // Stop if one of the handles can't move. 5738 if ( to === false ) { 5739 proposal = 0; 5740 } else { 5741 proposal = to - proposals[ handleNumber ]; 5742 proposals[ handleNumber ] = to; 5743 } 5744 } ); 5745 } else { // If using one handle, check backward AND forward 5746 b = f = [ true ]; 5747 } 5748 // Step 2: Try to set the handles with the found percentage 5749 handleNumbers.forEach( function( handleNumber, o ) { 5750 state = 5751 setHandle( handleNumber, locations[ handleNumber ] + proposal, b[ o ], f[ o ], false, smoothSteps ) || state; 5752 } ); 5753 // Step 3: If a handle moved, fire events 5754 if ( state ) { 5755 handleNumbers.forEach( function( handleNumber ) { 5756 fireEvent( 'update', handleNumber ); 5757 fireEvent( 'slide', handleNumber ); 5758 } ); 5759 // If target is a connect, then fire drag event 5760 if ( connect !== undefined ) { 5761 fireEvent( 'drag', firstHandle ); 5762 } 5763 } 5764 } 5765 // Takes a base value and an offset. This offset is used for the connect bar size. 5766 // In the initial design for this feature, the origin element was 1% wide. 5767 // Unfortunately, a rounding bug in Chrome makes it impossible to implement this feature 5768 // in this manner: https://bugs.chromium.org/p/chromium/issues/detail?id=798223 5769 function transformDirection( a, b ) { 5770 return options.dir ? 100 - a - b : a; 5771 } 5772 // Updates scope_Locations and scope_Values, updates visual state 5773 function updateHandlePosition( handleNumber, to ) { 5774 var translation; 5775 var translateRule; 5776 // Update locations. 5777 scope_Locations[ handleNumber ] = to; 5778 // Convert the value to the slider stepping/range. 5779 scope_Values[ handleNumber ] = scope_Spectrum.fromStepping( to ); 5780 translation = transformDirection( to, 0 ) - scope_DirOffset; 5781 translateRule = 'translate(' + inRuleOrder( translation + '%', '0' ) + ')'; 5782 scope_Handles[ handleNumber ].style[ options.transformRule ] = translateRule; 5783 updateConnect( handleNumber ); 5784 updateConnect( handleNumber + 1 ); 5785 } 5786 // Handles before the slider middle are stacked later = higher, 5787 // Handles after the middle later is lower 5788 // [[7] [8] .......... | .......... [5] [4] 5789 function setZindex() { 5790 scope_HandleNumbers.forEach( function( handleNumber ) { 5791 var dir = scope_Locations[ handleNumber ] > 50 ? -1 : 1; 5792 var zIndex = 3 + ( scope_Handles.length + ( dir * handleNumber ) ); 5793 scope_Handles[ handleNumber ].style.zIndex = String( zIndex ); 5794 } ); 5795 } 5796 // Test suggested values and apply margin, step. 5797 // if exactInput is true, don't run checkHandlePosition, then the handle can be placed in between steps (#436) 5798 function setHandle( handleNumber, to, lookBackward, lookForward, exactInput, smoothSteps ) { 5799 if ( ! exactInput ) { 5800 to = checkHandlePosition( scope_Locations, handleNumber, to, lookBackward, lookForward, false, smoothSteps ); 5801 } 5802 if ( to === false ) { 5803 return false;
5804 } 5805 updateHandlePosition( handleNumber, to ); 5806 return true; 5807 } 5808 // Updates style attribute for connect nodes 5809 function updateConnect( index ) { 5810 var l; 5811 var h; 5812 var connectWidth; 5813 var translateRule; 5814 var scaleRule; 5815 // Skip connects set to false 5816 if ( ! scope_Connects[ index ] ) { 5817 return; 5818 } 5819 l = 0; 5820 h = 100; 5821 if ( index !== 0 ) { 5822 l = scope_Locations[ index - 1 ]; 5823 } 5824 if ( index !== scope_Connects.length - 1 ) { 5825 h = scope_Locations[ index ]; 5826 } 5827 // We use two rules: 5828 // 'translate' to change the left/top offset; 5829 // 'scale' to change the width of the element; 5830 // As the element has a width of 100%, a translation of 100% is equal to 100% of the parent (.noUi-base) 5831 connectWidth = h - l; 5832 translateRule = 'translate(' + inRuleOrder( transformDirection( l, connectWidth ) + '%', '0' ) + ')'; 5833 scaleRule = 'scale(' + inRuleOrder( connectWidth / 100, '1' ) + ')'; 5834 scope_Connects[ index ].style[ options.transformRule ] = 5835 translateRule + ' ' + scaleRule; 5836 } 5837 // Parses value passed to .set method. Returns current value if not parse-able. 5838 function resolveToValue( to, handleNumber ) { 5839 // Setting with null indicates an 'ignore'. 5840 // Inputting 'false' is invalid. 5841 if ( to === null || to === false || to === undefined ) { 5842 return scope_Locations[ handleNumber ]; 5843 } 5844 // If a formatted number was passed, attempt to decode it. 5845 if ( typeof to === 'number' ) { 5846 to = String( to ); 5847 } 5848 to = options.format.from( to ); 5849 if ( to !== false ) { 5850 to = scope_Spectrum.toStepping( to ); 5851 } 5852 // If parsing the number failed, use the current value. 5853 if ( to === false || isNaN( to ) ) { 5854 return scope_Locations[ handleNumber ]; 5855 } 5856 return to; 5857 } 5858 function scope_HandleNumbersCallback( exactInput ) { 5859 return function( handleNumber ) { 5860 setHandle( handleNumber, scope_Locations[ handleNumber ], true, true, exactInput ); 5861 }; 5862 } 5863 // Set the slider value. 5864 function valueSet( input, fireSetEvent, exactInput ) { 5865 var values = asArray( input ); 5866 var isInit = scope_Locations[ 0 ] === undefined; 5867 var i; 5868 var space_1; 5869 // Event fires by default 5870 fireSetEvent = fireSetEvent === undefined ? true : fireSetEvent; 5871 // Animation is optional. 5872 // Make sure the initial values were set before using animated placement. 5873 if ( options.animate && ! isInit ) { 5874 addClassFor( scope_Target, options.cssClasses.tap, options.animationDuration ); 5875 } 5876 // First pass, without lookAhead but with lookBackward. Values are set from left to right. 5877 scope_HandleNumbers.forEach( function( handleNumber ) { 5878 setHandle( handleNumber, resolveToValue( values[ handleNumber ], handleNumber ), true, false, exactInput ); 5879 } ); 5880 i = scope_HandleNumbers.length === 1 ? 0 : 1; 5881 // Spread handles evenly across the slider if the range has no size (min=max) 5882 if ( isInit && scope_Spectrum.hasNoSize() ) { 5883 exactInput = true; 5884 scope_Locations[ 0 ] = 0; 5885 if ( scope_HandleNumbers.length > 1 ) { 5886 space_1 = 100 / ( scope_HandleNumbers.length - 1 ); 5887 scope_HandleNumbers.forEach( function( handleNumber ) { 5888 scope_Locations[ handleNumber ] = handleNumber * space_1; 5889 } ); 5890 } 5891 } 5892 // Secondary passes. Now that all base values are set, apply constraints. 5893 // Iterate all handles to ensure constraints are applied for the entire slider (Issue #1009) 5894 for ( ; i < scope_HandleNumbers.length; ++i ) { 5895 scope_HandleNumbers.forEach( scope_HandleNumbersCallback( exactInput ) ); 5896 } 5897 setZindex(); 5898 scope_HandleNumbers.forEach( function( handleNumber ) { 5899 fireEvent( 'update', handleNumber ); 5900 // Fire the event only for handles that received a new value, as per #579 5901 if ( values[ handleNumber ] !== null && fireSetEvent ) { 5902 fireEvent( 'set', handleNumber ); 5903 } 5904 } ); 5905 } 5906 // Reset slider to initial values 5907 function valueReset( fireSetEvent ) { 5908 valueSet( options.start, fireSetEvent ); 5909 } 5910 // Set value for a single handle 5911 function valueSetHandle( handleNumber, value, fireSetEvent, exactInput ) { 5912 // Ensure numeric input 5913 handleNumber = Number( handleNumber ); 5914 if ( ! ( handleNumber >= 0 && handleNumber < scope_HandleNumbers.length ) ) { 5915 throw new Error( 'noUiSlider: invalid handle number, got: ' + handleNumber ); 5916 } 5917 // Look both backward and forward, since we don't want this handle to "push" other handles (#960); 5918 // The exactInput argument can be used to ignore slider stepping (#436) 5919 setHandle( handleNumber, resolveToValue( value, handleNumber ), true, true, exactInput ); 5920 fireEvent( 'update', handleNumber ); 5921 if ( fireSetEvent ) { 5922 fireEvent( 'set', handleNumber ); 5923 } 5924 } 5925 // Get the slider value. 5926 function valueGet( unencoded ) { 5927 var values; 5928 if ( unencoded === void 0 ) { 5929 unencoded = false;
vendor: 6,568 bytes, lines 5930-6129
5930 } 5931 if ( unencoded ) { 5932 // return a copy of the raw values 5933 return scope_Values.length === 1 ? scope_Values[ 0 ] : scope_Values.slice( 0 ); 5934 } 5935 values = scope_Values.map( options.format.to ); 5936 // If only one handle is used, return a single value. 5937 if ( values.length === 1 ) { 5938 return values[ 0 ]; 5939 } 5940 return values; 5941 } 5942 // Removes classes from the root and empties it. 5943 function destroy() { 5944 // remove protected internal listeners 5945 removeEvent( INTERNAL_EVENT_NS.aria ); 5946 removeEvent( INTERNAL_EVENT_NS.tooltips ); 5947 Object.keys( options.cssClasses ).forEach( function( key ) { 5948 removeClass( scope_Target, options.cssClasses[ key ] ); 5949 } ); 5950 while ( scope_Target.firstChild ) { 5951 scope_Target.removeChild( scope_Target.firstChild ); 5952 } 5953 delete scope_Target.noUiSlider; 5954 } 5955 function getNextStepsForHandle( handleNumber ) { 5956 var location = scope_Locations[ handleNumber ]; 5957 var nearbySteps = scope_Spectrum.getNearbySteps( location ); 5958 var value = scope_Values[ handleNumber ]; 5959 var increment = nearbySteps.thisStep.step; 5960 var decrement = null; 5961 var stepDecimals; 5962 // If snapped, directly use defined step value 5963 if ( options.snap ) { 5964 return [ 5965 value - nearbySteps.stepBefore.startValue || null, 5966 nearbySteps.stepAfter.startValue - value || null 5967 ]; 5968 } 5969 // If the next value in this step moves into the next step, 5970 // the increment is the start of the next step - the current value 5971 if ( increment !== false ) { 5972 if ( value + increment > nearbySteps.stepAfter.startValue ) { 5973 increment = nearbySteps.stepAfter.startValue - value; 5974 } 5975 } 5976 // If the value is beyond the starting point 5977 if ( value > nearbySteps.thisStep.startValue ) { 5978 decrement = nearbySteps.thisStep.step; 5979 } else if ( nearbySteps.stepBefore.step === false ) { 5980 decrement = false; 5981 } else { // If a handle is at the start of a step, it always steps back into the previous step first 5982 decrement = value - nearbySteps.stepBefore.highestStep; 5983 } 5984 // Now, if at the slider edges, there is no in/decrement 5985 if ( location === 100 ) { 5986 increment = null; 5987 } else if ( location === 0 ) { 5988 decrement = null; 5989 } 5990 // As per #391, the comparison for the decrement step can have some rounding issues. 5991 stepDecimals = scope_Spectrum.countStepDecimals(); 5992 // Round per #391 5993 if ( increment !== null && increment !== false ) { 5994 increment = Number( increment.toFixed( stepDecimals ) ); 5995 } 5996 if ( decrement !== null && decrement !== false ) { 5997 decrement = Number( decrement.toFixed( stepDecimals ) ); 5998 } 5999 return [ decrement, increment ]; 6000 } 6001 // Get the current step size for the slider. 6002 function getNextSteps() { 6003 return scope_HandleNumbers.map( getNextStepsForHandle ); 6004 } 6005 // Updatable: margin, limit, padding, step, range, animate, snap 6006 function updateOptions( optionsToUpdate, fireSetEvent ) { 6007 // Spectrum is created using the range, snap, direction and step options. 6008 // 'snap' and 'step' can be updated. 6009 // If 'snap' and 'step' are not passed, they should remain unchanged. 6010 var v = valueGet(); 6011 var updateAble = [ 6012 'margin', 6013 'limit', 6014 'padding', 6015 'range', 6016 'animate', 6017 'snap', 6018 'step', 6019 'format', 6020 'pips', 6021 'tooltips' 6022 ]; 6023 var newOptions; 6024 // Only change options that we're actually passed to update. 6025 updateAble.forEach( function( name ) { 6026 // Check for undefined. null removes the value. 6027 if ( optionsToUpdate[ name ] !== undefined ) { 6028 originalOptions[ name ] = optionsToUpdate[ name ]; 6029 } 6030 } ); 6031 newOptions = testOptions( originalOptions ); 6032 // Load new options into the slider state 6033 updateAble.forEach( function( name ) { 6034 if ( optionsToUpdate[ name ] !== undefined ) { 6035 options[ name ] = newOptions[ name ]; 6036 } 6037 } ); 6038 scope_Spectrum = newOptions.spectrum; 6039 // Limit, margin and padding depend on the spectrum but are stored outside of it. (#677) 6040 options.margin = newOptions.margin; 6041 options.limit = newOptions.limit; 6042 options.padding = newOptions.padding; 6043 // Update pips, removes existing. 6044 if ( options.pips ) { 6045 pips( options.pips ); 6046 } else { 6047 removePips(); 6048 } 6049 // Update tooltips, removes existing. 6050 if ( options.tooltips ) { 6051 tooltips(); 6052 } else { 6053 removeTooltips(); 6054 } 6055 // Invalidate the current positioning so valueSet forces an update. 6056 scope_Locations = []; 6057 valueSet( isSet( optionsToUpdate.start ) ? optionsToUpdate.start : v, fireSetEvent ); 6058 } 6059 // Initialization steps 6060 function setupSlider() { 6061 // Create the base element, initialize HTML and set classes. 6062 // Add handles and connect elements. 6063 scope_Base = addSlider( scope_Target ); 6064 addElements( options.connect, scope_Base ); 6065 // Attach user events. 6066 bindSliderEvents( options.events ); 6067 // Use the public value method to set the start values. 6068 valueSet( options.start ); 6069 if ( options.pips ) { 6070 pips( options.pips ); 6071 } 6072 if ( options.tooltips ) { 6073 tooltips(); 6074 } 6075 aria(); 6076 } 6077 setupSlider(); 6078 scope_Self = { 6079 destroy: destroy, 6080 steps: getNextSteps, 6081 on: bindEvent, 6082 off: removeEvent, 6083 get: valueGet, 6084 set: valueSet, 6085 setHandle: valueSetHandle, 6086 reset: valueReset, 6087 disable: disable, 6088 enable: enable, 6089 // Exposed for unit testing, don't use this in your application. 6090 __moveHandles: function( upward, proposal, handleNumbers ) { 6091 moveHandles( upward, proposal, scope_Locations, handleNumbers ); 6092 }, 6093 options: originalOptions, 6094 updateOptions: updateOptions, 6095 target: scope_Target, 6096 removePips: removePips, 6097 removeTooltips: removeTooltips, 6098 getPositions: function() { 6099 return scope_Locations.slice(); 6100 }, 6101 getTooltips: function() { 6102 return scope_Tooltips; 6103 }, 6104 getOrigins: function() { 6105 return scope_Handles; 6106 }, 6107 pips: pips // Issue #594 6108 }; 6109 return scope_Self; 6110 } 6111 // Run the standard initializer 6112 function initialize( target, originalOptions ) { 6113 var options; 6114 var api; 6115 if ( ! target || ! target.nodeName ) { 6116 throw new Error( 'noUiSlider: create requires a single element, got: ' + target ); 6117 } 6118 // Throw an error if the slider was already initialized. 6119 if ( target.noUiSlider ) { 6120 throw new Error( 'noUiSlider: Slider was already initialized.' ); 6121 } 6122 // Test the options and create the slider environment; 6123 options = testOptions( originalOptions ); 6124 api = scope( target, options, originalOptions ); 6125 target.noUiSlider = api; 6126 return api; 6127 } 6128 nouislider = { 6129 // Exposed for unit testing, don't use this in your application.
6130 __spectrum: Spectrum, 6131 // A reference to the default classes, allows global changes. 6132 // Use the cssClasses option for changes to one slider. 6133 cssClasses: cssClasses, 6134 create: initialize 6135 }; 6136 6137 exports.create = initialize; 6138 exports.cssClasses = cssClasses; 6139 exports.default = nouislider; 6140 6141 Object.defineProperty( exports, '__esModule', { value: true } ); 6142} ) ) ); 6143; 6144/** 6145 * jquery.resizestop (and resizestart) 6146 * by: Fatih Kadir Akın 6147 * https://github.com/f/jquery.resizestop 6148 * License is CC0, published to the public domain. 6149 * @param {jQuery} $ 6150 */ 6151// Used by datepicker when position is top or bottom of the screen 6152( function( $ ) { 6153 'use strict'; 6154 // Slice shortcut 6155 var slice = Array.prototype.slice; 6156 6157 // Special event definition 6158 $.extend( $.event.special, { 6159 // resize stop special event. 6160 resizestop: { 6161 add: function( handle ) { 6162 // shortcut to the event handler. 6163 var handler = handle.handler; 6164 6165 // event modifying 6166 $( this ).on( 'resize', function( e ) { 6167 var _proxy; 6168 // every resize event clears handler's timer. 6169 // and every handler must have a timer. 6170 clearTimeout( handler._timer ); 6171 // change event type text. 6172 e.type = 'resizestop'; 6173 // push the "resize" event to the handler. 6174 _proxy = $.proxy( handler, this, e ); 6175 // if no resize event fired for a time that we decide, 6176 // then it means its stopped. 6177 handler._timer = setTimeout( _proxy, handle.data || 200 ); 6178 } ); 6179 } 6180 }, 6181 // resize start special event 6182 resizestart: { 6183 add: function( handle ) { 6184 // shortcut to the event handler. 6185 var handler = handle.handler; 6186 6187 // event modifying 6188 $( this ).on( 'resize', function( e ) { 6189 // every resize event clears handler's timer. 6190 // and every handler must have a timer. 6191 clearTimeout( handler._timer ); 6192 // we suddenly fire the event, then we can put 6193 // a flag with name _started knows if it's already fired. 6194 if ( ! handler._started ) { 6195 e.type = 'resizestart'; 6196 handler.apply( this, arguments ); 6197 // after firing the handler, put the flag with the value "true" 6198 handler._started = true; 6199 } 6200 handler._timer = setTimeout( 6201 $.proxy( function() { 6202 // after a while, it will make the flag false. 6203 handler._started = false; 6204 }, this ), 6205 handle.data || 300 6206 ); 6207 } ); 6208 } 6209 } 6210 } ); 6211 // binding and currying the shortcuts. 6212 $.extend( $.fn, { 6213 // $(window).resizestop instead of $(window).on('resizestop') 6214 resizestop: function() { 6215 // will push the "resizestop" argument at the beginning of arguments 6216 $( this ).on.apply( this, [ 'resizestop' ].concat( slice.call( arguments ) ) ); 6217 }, 6218 // $(window).resizestart instead of $(window).on('resizestart') 6219 resizestart: function() { 6220 // will push the "resizestart" argument at the beginning of arguments 6221 $( this ).on.apply( this, [ 'resizestart' ].concat( slice.call( arguments ) ) ); 6222 } 6223 } ); 6224}( window.jQuery ) ); 6225; 6226/*! jQuery UI - v1.12.1 - 2019-02-17 6227 * http://jqueryui.com 6228 * Modified version of jQuery Datepicker 6229 * Copyright jQuery Foundation and other contributors; Licensed MIT */ 6230 6231( function( factory ) { 6232 'use strict'; 6233 if ( typeof window.define === 'function' && window.define.amd ) { 6234 // AMD. Register as an anonymous module. 6235 window.define( [ 'jquery' ], factory ); 6236 } else { 6237 // Browser globals 6238 factory( window.jQuery ); 6239 } 6240}( function( $ ) { 6241 'use strict'; 6242 /*! 6243 * jQuery UI Datepicker 1.12.1 (Modified version of jQuery Datepicker) 6244 * http://jqueryui.com 6245 * 6246 * Copyright jQuery Foundation and other contributors 6247 * Released under the MIT license. 6248 * http://jquery.org/license 6249 * 6250 * http://api.jqueryui.com/datepicker/ 6251 */ 6252 6253 var datepicker_instActive; 6254 6255 $.ui.tm_datepicker = $.ui.tm_datepicker || {}; 6256 if ( $.ui.tm_datepicker.version ) { 6257 return; 6258 } 6259 6260 $.extend( $.ui, { tm_datepicker: { version: '1.11.4' } } ); 6261 6262 function datepicker_getZindex( elem ) { 6263 var position, value; 6264 while ( elem.length && elem[ 0 ] !== document ) { 6265 // Ignore z-index if position is set to a value where z-index is ignored by the browser 6266 // This makes behavior of this function consistent across browsers 6267 // WebKit always returns auto if the element is positioned 6268 position = elem.css( 'position' ); 6269 if ( position === 'absolute' || position === 'relative' || position === 'fixed' ) { 6270 // IE returns 0 when zIndex is not specified 6271 // other browsers return a string 6272 // we ignore the case of nested elements with an explicit value of 0 6273 value = parseInt( elem.css( 'zIndex' ), 10 ); 6274 if ( ! isNaN( value ) && value !== 0 ) { 6275 return value; 6276 } 6277 } 6278 elem = elem.parent(); 6279 } 6280 6281 return 0; 6282 } 6283 6284 /* 6285 * Bind hover events for datepicker elements. 6286 * Done via delegate so the binding only occurs once in the lifetime of the parent div. 6287 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. 6288 */ 6289 function datepicker_handleMouseover( that ) { 6290 if ( ! $.tm_datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) { 6291 $( that ).parents( '.ui-tm-datepicker-calendar' ).find( 'a' ).removeClass( 'ui-state-hover' ); 6292 $( that ).addClass( 'ui-state-hover' ); 6293 if ( that.className.indexOf( 'ui-tm-datepicker-prev' ) !== -1 ) { 6294 $( that ).addClass( 'ui-tm-datepicker-prev-hover' ); 6295 } 6296 if ( that.className.indexOf( 'ui-tm-datepicker-next' ) !== -1 ) { 6297 $( that ).addClass( 'ui-tm-datepicker-next-hover' ); 6298 } 6299 } 6300 } 6301 6302 function datepicker_bindHover( dpDiv ) { 6303 var selector = 'button, .ui-tm-datepicker-prev, .ui-tm-datepicker-next, .ui-tm-datepicker-calendar td a'; 6304 return dpDiv 6305 .on( 'mouseout', selector, function() { 6306 $( this ).removeClass( 'ui-state-hover' ); 6307 if ( this.className.indexOf( 'ui-tm-datepicker-prev' ) !== -1 ) { 6308 $( this ).removeClass( 'ui-tm-datepicker-prev-hover' ); 6309 } 6310 if ( this.className.indexOf( 'ui-tm-datepicker-next' ) !== -1 ) { 6311 $( this ).removeClass( 'ui-tm-datepicker-next-hover' ); 6312 } 6313 } ) 6314 .on( 'mouseover', selector, function() { 6315 datepicker_handleMouseover( this ); 6316 } ); 6317 } 6318 6319 /* jQuery extend now ignores nulls! */ 6320 function datepicker_extendRemove( target, props ) { 6321 var name; 6322 6323 $.extend( target, props ); 6324 for ( name in props ) { 6325 if ( props[ name ] === null ) { 6326 target[ name ] = props[ name ]; 6327 } 6328 } 6329 return target; 6330 } 6331 6332 /* Date picker manager. 6333 Use the singleton instance of this class, $.tm_datepicker, to interact with the date picker. 6334 Settings for (groups of) date pickers are maintained in an instance object, 6335 allowing multiple different settings on the same page. */ 6336 6337 function Datepicker() { 6338 this._curInst = null; // The current instance in use 6339 this._keyEvent = false; // If the last event was a key event 6340 this._disabledInputs = []; // List of date picker inputs that have been disabled 6341 this._datepickerShowing = false; // True if the popup picker is showing , false if not 6342 this._inDialog = false; // True if showing within a "dialog", false if not 6343 this._mainDivId = 'ui-tm-datepicker-div'; // The ID of the main datepicker division 6344 this._inlineClass = 'ui-tm-datepicker-inline'; // The name of the inline marker class 6345 this._appendClass = 'ui-tm-datepicker-append'; // The name of the append marker class 6346 this._triggerClass = 'ui-tm-datepicker-trigger'; // The name of the trigger marker class 6347 this._dialogClass = 'ui-tm-datepicker-dialog'; // The name of the dialog marker class 6348 this._disableClass = 'ui-tm-datepicker-disabled'; // The name of the disabled covering marker class 6349 this._unselectableClass = 'ui-tm-datepicker-unselectable'; // The name of the unselectable cell marker class 6350 this._currentClass = 'ui-tm-datepicker-current-day'; // The name of the current day marker class 6351 this._dayOverClass = 'ui-tm-datepicker-days-cell-over'; // The name of the day hover marker class 6352 this.regional = []; // Available regional settings, indexed by language code 6353 this.regional[ '' ] = { 6354 // Default regional settings 6355 closeText: 'Done', // Display text for close link 6356 prevText: 'Prev', // Display text for previous month link 6357 nextText: 'Next', // Display text for next month link 6358 currentText: 'Today', // Display text for current month link 6359 monthNames: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ], // Names of months for drop-down and formatting 6360 monthNamesShort: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ], // For formatting 6361 dayNames: [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ], // For formatting 6362 dayNamesShort: [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ], // For formatting 6363 dayNamesMin: [ 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa' ], // Column headings for days starting at Sunday 6364 weekHeader: 'Wk', // Column header for week of the year 6365 dateFormat: 'mm/dd/yy', // See format options on parseDate 6366 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... 6367 isRTL: false, // True if right-to-left language, false if left-to-right 6368 showMonthAfterYear: false, // True if the year select precedes month, false for month then year 6369 yearSuffix: '' // Additional text to append to the year in the month headers 6370 }; 6371 this._defaults = { 6372 // Global defaults for all the date picker instances 6373 showOn: 'focus', // "focus" for popup on focus, 6374 // "button" for trigger button, or "both" for either
vendor: 10,028 bytes, lines 6375-6607
6375 showAnim: 'fadeIn', // Name of jQuery animation for popup 6376 showOptions: {}, // Options for enhanced animations 6377 defaultDate: null, // Used when field is blank: actual date, 6378 // +/-number for offset from today, null for today 6379 appendText: '', // Display text following the input box, e.g. showing the format 6380 buttonText: '...', // Text for trigger button 6381 buttonImage: '', // URL for trigger button image 6382 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button 6383 hideIfNoPrevNext: false, // True to hide next/previous month links 6384 // if not applicable, false to just disable them 6385 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links 6386 gotoCurrent: false, // True if today link goes back to current selection instead 6387 changeMonth: false, // True if month can be selected directly, false if only prev/next 6388 changeYear: false, // True if year can be selected directly, false if only prev/next 6389 yearRange: 'c-10:c+10', // Range of years to display in drop-down, 6390 // either relative to today's year (-nn:+nn), relative to currently displayed year 6391 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) 6392 showOtherMonths: false, // True to show dates in other months, false to leave blank 6393 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable 6394 showWeek: false, // True to show week of the year, false to not show it 6395 calculateWeek: this.iso8601Week, // How to calculate the week of the year, 6396 // takes a Date and returns the number of the week for it 6397 shortYearCutoff: '+10', // Short year values < this are in the current century, 6398 // > this are in the previous century, 6399 // string value starting with "+" for current year + value 6400 minDate: null, // The earliest selectable date, or null for no limit 6401 maxDate: null, // The latest selectable date, or null for no limit 6402 duration: 'fast', // Duration of display/closure 6403 beforeShowDay: null, // Function that takes a date and returns an array with 6404 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "", 6405 // [2] = cell title (optional), e.g. $.tm_datepicker.noWeekends 6406 beforeShow: null, // Function that takes an input field and 6407 // returns a set of custom settings for the date picker 6408 onSelect: null, // Define a callback function when a date is selected 6409 onChangeMonthYear: null, // Define a callback function when the month or year is changed 6410 onClose: null, // Define a callback function when the datepicker is closed 6411 numberOfMonths: 1, // Number of months to show at a time 6412 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) 6413 stepMonths: 1, // Number of months to step back/forward 6414 stepBigMonths: 12, // Number of months to step back/forward for the big links 6415 altField: '', // Selector for an alternate field to store selected dates into 6416 altFormat: '', // The date format to use for the alternate field 6417 constrainInput: true, // The input is constrained by the current date format 6418 showButtonPanel: false, // True to show button panel, false to not show it 6419 autoSize: false, // True to size the input for the date format, false to leave as is 6420 disabled: false // The initial disabled state 6421 }; 6422 $.extend( this._defaults, this.regional[ '' ] ); 6423 this.regional.en = $.extend( true, {}, this.regional[ '' ] ); 6424 this.regional[ 'en-US' ] = $.extend( true, {}, this.regional.en ); 6425 this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-tm-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ); 6426 } 6427 6428 $.extend( Datepicker.prototype, { 6429 /* Class name added to elements to indicate already configured with a date picker. */ 6430 markerClassName: 'hasDatepicker', 6431 6432 //Keep track of the maximum number of rows displayed (see #7043) 6433 maxRows: 4, 6434 6435 // TODO rename to "widget" when switching to widget factory 6436 _widgetDatepicker: function() { 6437 return this.dpDiv; 6438 }, 6439 6440 /* Override the default settings for all instances of the date picker. 6441 * @param settings object - the new settings to use as defaults (anonymous object) 6442 * @return the manager object 6443 */ 6444 setDefaults: function( settings ) { 6445 datepicker_extendRemove( this._defaults, settings || {} ); 6446 return this; 6447 }, 6448 6449 /* Attach the date picker to a jQuery selection. 6450 * @param target element - the target input field or division or span 6451 * @param settings object - the new settings to use for this date picker instance (anonymous) 6452 */ 6453 _attachDatepicker: function( target, settings ) { 6454 var nodeName, inline, inst; 6455 nodeName = target.nodeName.toLowerCase(); 6456 inline = nodeName === 'div' || nodeName === 'span'; 6457 if ( ! target.id ) { 6458 this.uuid += 1; 6459 target.id = 'dp' + this.uuid; 6460 } 6461 inst = this._newInst( $( target ), inline ); 6462 inst.settings = $.extend( {}, settings || {} ); 6463 if ( nodeName === 'input' ) { 6464 this._connectDatepicker( target, inst ); 6465 } else if ( inline ) { 6466 this._inlineDatepicker( target, inst ); 6467 } 6468 }, 6469 6470 /* Create a new instance object. */ 6471 _newInst: function( target, inline ) { 6472 var id = target[ 0 ].id.replace( /([^A-Za-z0-9_-])/g, '\\\\$1' ); // escape jQuery meta chars 6473 return { 6474 id: id, 6475 input: target, // associated target 6476 selectedDay: 0, 6477 selectedMonth: 0, 6478 selectedYear: 0, // current selection 6479 drawMonth: 0, 6480 drawYear: 0, // month being drawn 6481 inline: inline, // is datepicker inline or not 6482 // presentation div 6483 dpDiv: ! inline ? this.dpDiv : datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-tm-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) 6484 }; 6485 }, 6486 6487 /* Attach the date picker to an input field. */ 6488 _connectDatepicker: function( target, inst ) { 6489 var input = $( target ); 6490 inst.append = $( [] ); 6491 inst.trigger = $( [] ); 6492 if ( input.hasClass( this.markerClassName ) ) { 6493 return; 6494 } 6495 this._attachments( input, inst ); 6496 input.addClass( this.markerClassName ).on( 'keydown', this._doKeyDown ).on( 'keypress', this._doKeyPress ).on( 'keyup', this._doKeyUp ); 6497 this._autoSize( inst ); 6498 $.data( target, 'datepicker', inst ); 6499 6500 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665) 6501 if ( inst.settings.disabled ) { 6502 this._disableDatepicker( target ); 6503 } 6504 }, 6505 6506 /* Make attachments based on settings. */ 6507 _attachments: function( input, inst ) { 6508 var showOn, 6509 buttonText, 6510 buttonImage, 6511 appendText = this._get( inst, 'appendText' ), 6512 isRTL = this._get( inst, 'isRTL' ); 6513 6514 if ( inst.append ) { 6515 inst.append.remove(); 6516 } 6517 if ( appendText ) { 6518 inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + '</span>' ); 6519 input[ isRTL ? 'before' : 'after' ]( inst.append ); 6520 } 6521 6522 input.off( 'focus', this._showDatepicker ); 6523 6524 if ( inst.trigger ) { 6525 inst.trigger.remove(); 6526 } 6527 6528 showOn = this._get( inst, 'showOn' ); 6529 if ( showOn === 'focus' || showOn === 'both' ) { 6530 // pop-up date picker when in the marked field 6531 input.on( 'focus', this._showDatepicker ); 6532 } 6533 if ( showOn === 'button' || showOn === 'both' ) { 6534 // pop-up date picker when button clicked 6535 buttonText = this._get( inst, 'buttonText' ); 6536 buttonImage = this._get( inst, 'buttonImage' ); 6537 inst.trigger = $( 6538 this._get( inst, 'buttonImageOnly' ) 6539 ? $( '<img/>' ).addClass( this._triggerClass ).attr( { src: buttonImage, alt: buttonText, title: buttonText } ) 6540 : $( "<button type='button'></button>" ) 6541 .addClass( this._triggerClass ) 6542 .html( ! buttonImage ? buttonText : $( '<img/>' ).attr( { src: buttonImage, alt: buttonText, title: buttonText } ) ) 6543 ); 6544 input[ isRTL ? 'before' : 'after' ]( inst.trigger ); 6545 inst.trigger.on( 'click', function() { 6546 if ( $.tm_datepicker._datepickerShowing && $.tm_datepicker._lastInput === input[ 0 ] ) { 6547 $.tm_datepicker._hideDatepicker(); 6548 } else if ( $.tm_datepicker._datepickerShowing && $.tm_datepicker._lastInput !== input[ 0 ] ) { 6549 $.tm_datepicker._hideDatepicker(); 6550 $.tm_datepicker._showDatepicker( input[ 0 ] ); 6551 } else { 6552 $.tm_datepicker._showDatepicker( input[ 0 ] ); 6553 } 6554 return false; 6555 } ); 6556 } 6557 }, 6558 6559 /* Apply the maximum length for the date format. */ 6560 _autoSize: function( inst ) { 6561 var findMax; 6562 var max; 6563 var maxI; 6564 var i; 6565 var date; 6566 var dateFormat = this._get( inst, 'dateFormat' ); 6567 6568 if ( this._get( inst, 'autoSize' ) && ! inst.inline ) { 6569 date = new Date( 2009, 12 - 1, 20 ); // Ensure double digits 6570 dateFormat = this._get( inst, 'dateFormat' ); 6571 6572 if ( dateFormat.match( /[DM]/ ) ) { 6573 findMax = function( names ) { 6574 max = 0; 6575 maxI = 0; 6576 for ( i = 0; i < names.length; i += 1 ) { 6577 if ( names[ i ].length > max ) { 6578 max = names[ i ].length; 6579 maxI = i; 6580 } 6581 } 6582 return maxI; 6583 }; 6584 date.setMonth( findMax( this._get( inst, dateFormat.match( /MM/ ) ? 'monthNames' : 'monthNamesShort' ) ) ); 6585 date.setDate( findMax( this._get( inst, dateFormat.match( /DD/ ) ? 'dayNames' : 'dayNamesShort' ) ) + 20 - date.getDay() ); 6586 } 6587 inst.input.attr( 'size', this._formatDate( inst, date ).length ); 6588 } 6589 }, 6590 6591 /* Attach an inline date picker to a div. */ 6592 _inlineDatepicker: function( target, inst ) { 6593 var divSpan = $( target ); 6594 if ( divSpan.hasClass( this.markerClassName ) ) { 6595 return; 6596 } 6597 divSpan.addClass( this.markerClassName ).append( inst.dpDiv ); 6598 $.data( target, 'datepicker', inst ); 6599 this._setDate( inst, this._getDefaultDate( inst ), true ); 6600 this._updateDatepicker( inst ); 6601 this._updateAlternate( inst ); 6602 6603 //If disabled option is true, disable the datepicker before showing it (see ticket #5665) 6604 if ( inst.settings.disabled ) { 6605 this._disableDatepicker( target ); 6606 } 6607
6608 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements 6609 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height 6610 inst.dpDiv.css( 'display', 'block' ); 6611 }, 6612 6613 /* Pop-up the date picker in a "dialog" box. 6614 * @param input element - ignored 6615 * @param date string or Date - the initial date to display 6616 * @param onSelect function - the function to call when a date is selected 6617 * @param settings object - update the dialog date picker instance's settings (anonymous object) 6618 * @param pos int[2] - coordinates for the dialog's position within the screen or 6619 * event - with x/y coordinates or 6620 * leave empty for default (screen centre) 6621 * @return the manager object 6622 */ 6623 _dialogDatepicker: function( input, date, onSelect, settings, pos ) { 6624 var id, 6625 browserWidth, 6626 browserHeight, 6627 scrollX, 6628 scrollY, 6629 inst = this._dialogInst; // internal instance 6630 6631 if ( ! inst ) { 6632 this.uuid += 1; 6633 id = 'dp' + this.uuid; 6634 this._dialogInput = $( "<input type='text' id='" + id + "'>" ); 6635 this._dialogInput.on( 'keydown', this._doKeyDown ); 6636 $( 'body' ).append( this._dialogInput ); 6637 inst = this._newInst( this._dialogInput, false ); 6638 this._dialogInst = inst; 6639 inst.settings = {}; 6640 $.data( this._dialogInput[ 0 ], 'datepicker', inst ); 6641 } 6642 datepicker_extendRemove( inst.settings, settings || {} ); 6643 date = date && date.constructor === Date ? this._formatDate( inst, date ) : date; 6644 this._dialogInput.val( date ); 6645 6646 this._pos = pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null; 6647 if ( ! this._pos ) { 6648 browserWidth = document.documentElement.clientWidth; 6649 browserHeight = document.documentElement.clientHeight; 6650 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; 6651 scrollY = document.documentElement.scrollTop || document.body.scrollTop; 6652 this._pos = 6653 // should use actual width/height below 6654 [ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ]; 6655 } 6656 6657 // Move input on screen for focus, but hidden behind dialog 6658 this._dialogInput.css( 'left', this._pos[ 0 ] + 20 + 'px' ).css( 'top', this._pos[ 1 ] + 'px' ); 6659 inst.settings.onSelect = onSelect; 6660 this._inDialog = true; 6661 this.dpDiv.addClass( this._dialogClass ); 6662 this._showDatepicker( this._dialogInput[ 0 ] ); 6663 if ( $.blockUI ) { 6664 $.blockUI( this.dpDiv ); 6665 } 6666 $.data( this._dialogInput[ 0 ], 'datepicker', inst ); 6667 return this; 6668 }, 6669 6670 /* Detach a datepicker from its control. 6671 * @param target element - the target input field or division or span 6672 */ 6673 _destroyDatepicker: function( target ) { 6674 var nodeName, 6675 $target = $( target ), 6676 inst = $.data( target, 'datepicker' ); 6677 6678 if ( ! $target.hasClass( this.markerClassName ) ) { 6679 return; 6680 } 6681 6682 nodeName = target.nodeName.toLowerCase(); 6683 $.removeData( target, 'datepicker' ); 6684 if ( nodeName === 'input' ) {
vendor: 11,989 bytes, lines 6685-7028
6685 inst.append.remove(); 6686 inst.trigger.remove(); 6687 $target.removeClass( this.markerClassName ).off( 'focus', this._showDatepicker ).off( 'keydown', this._doKeyDown ).off( 'keypress', this._doKeyPress ).off( 'keyup', this._doKeyUp ); 6688 } else if ( nodeName === 'div' || nodeName === 'span' ) { 6689 $target.removeClass( this.markerClassName ).empty(); 6690 } 6691 6692 if ( datepicker_instActive === inst ) { 6693 datepicker_instActive = null; 6694 } 6695 }, 6696 6697 /* Enable the date picker to a jQuery selection. 6698 * @param target element - the target input field or division or span 6699 */ 6700 _enableDatepicker: function( target ) { 6701 var nodeName, 6702 inline, 6703 $target = $( target ), 6704 inst = $.data( target, 'datepicker' ); 6705 6706 if ( ! $target.hasClass( this.markerClassName ) ) { 6707 return; 6708 } 6709 6710 nodeName = target.nodeName.toLowerCase(); 6711 if ( nodeName === 'input' ) { 6712 target.disabled = false; 6713 inst.trigger 6714 .filter( 'button' ) 6715 .each( function() { 6716 this.disabled = false; 6717 } ) 6718 .end() 6719 .filter( 'img' ) 6720 .css( { opacity: '1.0', cursor: '' } ); 6721 } else if ( nodeName === 'div' || nodeName === 'span' ) { 6722 inline = $target.children( '.' + this._inlineClass ); 6723 inline.children().removeClass( 'ui-state-disabled' ); 6724 inline.find( 'select.ui-tm-datepicker-month, select.ui-tm-datepicker-year' ).prop( 'disabled', false ); 6725 } 6726 this._disabledInputs = $.map( this._disabledInputs, function( value ) { 6727 return value === target ? null : value; 6728 } ); // delete entry 6729 }, 6730 6731 /* Disable the date picker to a jQuery selection. 6732 * @param target element - the target input field or division or span 6733 */ 6734 _disableDatepicker: function( target ) { 6735 var nodeName, 6736 inline, 6737 $target = $( target ), 6738 inst = $.data( target, 'datepicker' ); 6739 6740 if ( ! $target.hasClass( this.markerClassName ) ) { 6741 return; 6742 } 6743 6744 nodeName = target.nodeName.toLowerCase(); 6745 if ( nodeName === 'input' ) { 6746 target.disabled = true; 6747 inst.trigger 6748 .filter( 'button' ) 6749 .each( function() { 6750 this.disabled = true; 6751 } ) 6752 .end() 6753 .filter( 'img' ) 6754 .css( { opacity: '0.5', cursor: 'default' } ); 6755 } else if ( nodeName === 'div' || nodeName === 'span' ) { 6756 inline = $target.children( '.' + this._inlineClass ); 6757 inline.children().addClass( 'ui-state-disabled' ); 6758 inline.find( 'select.ui-tm-datepicker-month, select.ui-tm-datepicker-year' ).prop( 'disabled', true ); 6759 } 6760 this._disabledInputs = $.map( this._disabledInputs, function( value ) { 6761 return value === target ? null : value; 6762 } ); // delete entry 6763 this._disabledInputs[ this._disabledInputs.length ] = target; 6764 }, 6765 6766 /* Is the first field in a jQuery collection disabled as a datepicker? 6767 * @param target element - the target input field or division or span 6768 * @return boolean - true if disabled, false if enabled 6769 */ 6770 _isDisabledDatepicker: function( target ) { 6771 var i; 6772 if ( ! target ) { 6773 return false; 6774 } 6775 for ( i = 0; i < this._disabledInputs.length; i += 1 ) { 6776 if ( this._disabledInputs[ i ] === target ) { 6777 return true; 6778 } 6779 } 6780 return false; 6781 }, 6782 6783 /* Retrieve the instance data for the target control. 6784 * @param target element - the target input field or division or span 6785 * @return object - the associated instance data 6786 * @throws error if a jQuery problem getting data 6787 */ 6788 _getInst: function( target ) { 6789 try { 6790 return $.data( target, 'datepicker' ); 6791 } catch ( err ) { 6792 throw 'Missing instance data for this datepicker'; 6793 } 6794 }, 6795 6796 /* Update or retrieve the settings for a date picker attached to an input field or division. 6797 * @param target element - the target input field or division or span 6798 * @param name object - the new settings to update or 6799 * string - the name of the setting to change or retrieve, 6800 * when retrieving also "all" for all instance settings or 6801 * "defaults" for all global defaults 6802 * @param value any - the new value for the setting 6803 * (omit if above is an object or to retrieve a value) 6804 */ 6805 _optionDatepicker: function( target, name, value ) { 6806 var settings, 6807 date, 6808 minDate, 6809 maxDate, 6810 inst = this._getInst( target ); 6811 6812 if ( arguments.length === 2 && typeof name === 'string' ) { 6813 return name === 'defaults' ? $.extend( {}, $.tm_datepicker._defaults ) : inst ? ( name === 'all' ? $.extend( {}, inst.settings ) : this._get( inst, name ) ) : null; 6814 } 6815 6816 settings = name || {}; 6817 if ( typeof name === 'string' ) { 6818 settings = {}; 6819 settings[ name ] = value; 6820 } 6821 6822 if ( inst ) { 6823 if ( this._curInst === inst ) { 6824 this._hideDatepicker(); 6825 } 6826 6827 date = this._getDateDatepicker( target, true ); 6828 minDate = this._getMinMaxDate( inst, 'min' ); 6829 maxDate = this._getMinMaxDate( inst, 'max' ); 6830 datepicker_extendRemove( inst.settings, settings ); 6831 6832 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided 6833 if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) { 6834 inst.settings.minDate = this._formatDate( inst, minDate ); 6835 } 6836 if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) { 6837 inst.settings.maxDate = this._formatDate( inst, maxDate ); 6838 } 6839 if ( 'disabled' in settings ) { 6840 if ( settings.disabled ) { 6841 this._disableDatepicker( target ); 6842 } else { 6843 this._enableDatepicker( target ); 6844 } 6845 } 6846 this._attachments( $( target ), inst ); 6847 this._autoSize( inst ); 6848 this._setDate( inst, date ); 6849 this._updateAlternate( inst ); 6850 this._updateDatepicker( inst ); 6851 } 6852 }, 6853 6854 // Change method deprecated 6855 _changeDatepicker: function( target, name, value ) { 6856 this._optionDatepicker( target, name, value ); 6857 }, 6858 6859 /* Redraw the date picker attached to an input field or division. 6860 * @param target element - the target input field or division or span 6861 */ 6862 _refreshDatepicker: function( target ) { 6863 var inst = this._getInst( target ); 6864 if ( inst ) { 6865 this._updateDatepicker( inst ); 6866 } 6867 }, 6868 6869 /* Set the dates for a jQuery selection. 6870 * @param target element - the target input field or division or span 6871 * @param date Date - the new date 6872 */ 6873 _setDateDatepicker: function( target, date ) { 6874 var inst = this._getInst( target ); 6875 if ( inst ) { 6876 this._setDate( inst, date ); 6877 this._updateDatepicker( inst ); 6878 this._updateAlternate( inst ); 6879 } 6880 }, 6881 6882 /* Get the date(s) for the first entry in a jQuery selection. 6883 * @param target element - the target input field or division or span 6884 * @param noDefault boolean - true if no default date is to be used 6885 * @return Date - the current date 6886 */ 6887 _getDateDatepicker: function( target, noDefault ) { 6888 var inst = this._getInst( target ); 6889 if ( inst && ! inst.inline ) { 6890 this._setDateFromField( inst, noDefault ); 6891 } 6892 return inst ? this._getDate( inst ) : null; 6893 }, 6894 6895 /* Handle keystrokes. */ 6896 _doKeyDown: function( event ) { 6897 var onSelect, 6898 dateStr, 6899 sel, 6900 inst = $.tm_datepicker._getInst( event.target ), 6901 handled = true, 6902 isRTL = inst.dpDiv.is( '.ui-tm-datepicker-rtl' ); 6903 6904 inst._keyEvent = true; 6905 if ( $.tm_datepicker._datepickerShowing ) { 6906 switch ( event.keyCode ) { 6907 case 9: 6908 $.tm_datepicker._hideDatepicker(); 6909 handled = false; 6910 break; // hide on tab out 6911 case 13: 6912 sel = $( 'td.' + $.tm_datepicker._dayOverClass + ':not(.' + $.tm_datepicker._currentClass + ')', inst.dpDiv ); 6913 if ( sel[ 0 ] ) { 6914 $.tm_datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] ); 6915 } 6916 6917 onSelect = $.tm_datepicker._get( inst, 'onSelect' ); 6918 if ( onSelect ) { 6919 dateStr = $.tm_datepicker._formatDate( inst ); 6920 6921 // Trigger custom callback 6922 onSelect.apply( inst.input ? inst.input[ 0 ] : null, [ dateStr, inst ] ); 6923 } else { 6924 $.tm_datepicker._hideDatepicker(); 6925 } 6926 6927 return false; // don't submit the form 6928 case 27: 6929 $.tm_datepicker._hideDatepicker(); 6930 break; // hide on escape 6931 case 33: 6932 $.tm_datepicker._adjustDate( event.target, event.ctrlKey ? -$.tm_datepicker._get( inst, 'stepBigMonths' ) : -$.tm_datepicker._get( inst, 'stepMonths' ), 'M' ); 6933 break; // previous month/year on page up/+ ctrl 6934 case 34: 6935 $.tm_datepicker._adjustDate( event.target, event.ctrlKey ? +$.tm_datepicker._get( inst, 'stepBigMonths' ) : +$.tm_datepicker._get( inst, 'stepMonths' ), 'M' ); 6936 break; // next month/year on page down/+ ctrl 6937 case 35: 6938 if ( event.ctrlKey || event.metaKey ) { 6939 $.tm_datepicker._clearDate( event.target ); 6940 } 6941 handled = event.ctrlKey || event.metaKey; 6942 break; // clear on ctrl or command +end 6943 case 36: 6944 if ( event.ctrlKey || event.metaKey ) { 6945 $.tm_datepicker._gotoToday( event.target ); 6946 } 6947 handled = event.ctrlKey || event.metaKey; 6948 break; // current on ctrl or command +home 6949 case 37: 6950 if ( event.ctrlKey || event.metaKey ) { 6951 $.tm_datepicker._adjustDate( event.target, isRTL ? +1 : -1, 'D' ); 6952 } 6953 handled = event.ctrlKey || event.metaKey; 6954 // -1 day on ctrl or command +left 6955 if ( event.originalEvent.altKey ) { 6956 $.tm_datepicker._adjustDate( event.target, event.ctrlKey ? -$.tm_datepicker._get( inst, 'stepBigMonths' ) : -$.tm_datepicker._get( inst, 'stepMonths' ), 'M' ); 6957 } 6958 // next month/year on alt +left on Mac 6959 break; 6960 case 38: 6961 if ( event.ctrlKey || event.metaKey ) { 6962 $.tm_datepicker._adjustDate( event.target, -7, 'D' ); 6963 } 6964 handled = event.ctrlKey || event.metaKey; 6965 break; // -1 week on ctrl or command +up 6966 case 39: 6967 if ( event.ctrlKey || event.metaKey ) { 6968 $.tm_datepicker._adjustDate( event.target, isRTL ? -1 : +1, 'D' ); 6969 } 6970 handled = event.ctrlKey || event.metaKey; 6971 // +1 day on ctrl or command +right 6972 if ( event.originalEvent.altKey ) { 6973 $.tm_datepicker._adjustDate( event.target, event.ctrlKey ? +$.tm_datepicker._get( inst, 'stepBigMonths' ) : +$.tm_datepicker._get( inst, 'stepMonths' ), 'M' ); 6974 } 6975 // next month/year on alt +right 6976 break; 6977 case 40: 6978 if ( event.ctrlKey || event.metaKey ) { 6979 $.tm_datepicker._adjustDate( event.target, +7, 'D' ); 6980 } 6981 handled = event.ctrlKey || event.metaKey; 6982 break; // +1 week on ctrl or command +down 6983 default: 6984 handled = false; 6985 } 6986 } else if ( event.keyCode === 36 && event.ctrlKey ) { 6987 // display the date picker on ctrl+home 6988 $.tm_datepicker._showDatepicker( this ); 6989 } else { 6990 handled = false; 6991 } 6992 6993 if ( handled ) { 6994 event.preventDefault(); 6995 event.stopPropagation(); 6996 } 6997 }, 6998 6999 /* Filter entered characters - based on date format. */ 7000 _doKeyPress: function( event ) { 7001 var chars, 7002 chr, 7003 inst = $.tm_datepicker._getInst( event.target ); 7004 7005 if ( $.tm_datepicker._get( inst, 'constrainInput' ) ) { 7006 chars = $.tm_datepicker._possibleChars( $.tm_datepicker._get( inst, 'dateFormat' ) ); 7007 chr = String.fromCharCode( event.charCode === null ? event.keyCode : event.charCode ); 7008 return event.ctrlKey || event.metaKey || chr < ' ' || ! chars || chars.indexOf( chr ) > -1; 7009 } 7010 }, 7011 7012 /* Synchronise manual entry and field/alternate field. */ 7013 _doKeyUp: function( event ) { 7014 var date, 7015 inst = $.tm_datepicker._getInst( event.target ); 7016 7017 if ( inst.input.val() !== inst.lastVal ) { 7018 try { 7019 date = $.tm_datepicker.parseDate( $.tm_datepicker._get( inst, 'dateFormat' ), inst.input ? inst.input.val() : null, $.tm_datepicker._getFormatConfig( inst ) ); 7020 7021 if ( date ) { 7022 // only if valid 7023 $.tm_datepicker._setDateFromField( inst ); 7024 $.tm_datepicker._updateAlternate( inst ); 7025 $.tm_datepicker._updateDatepicker( inst ); 7026 } 7027 } catch ( err ) { 7028 return false;
vendor: 4,862 bytes, lines 7029-7170
7029 } 7030 } 7031 return true; 7032 }, 7033 7034 /* Pop-up the date picker for a given input field. 7035 * If false returned from beforeShow event handler do not show. 7036 * @param input element - the input field attached to the date picker or 7037 * event - if triggered by focus 7038 */ 7039 _showDatepicker: function( input ) { 7040 var inst; 7041 var beforeShow; 7042 var beforeShowSettings; 7043 var isFixed; 7044 var offset; 7045 var showAnim; 7046 var duration; 7047 7048 input = input.target || input; 7049 if ( input.nodeName.toLowerCase() !== 'input' ) { 7050 // find from button/image trigger 7051 input = $( 'input', input.parentNode )[ 0 ]; 7052 } 7053 7054 if ( $.tm_datepicker._isDisabledDatepicker( input ) || $.tm_datepicker._lastInput === input ) { 7055 // already here 7056 return; 7057 } 7058 7059 inst = $.tm_datepicker._getInst( input ); 7060 if ( $.tm_datepicker._curInst && $.tm_datepicker._curInst !== inst ) { 7061 $.tm_datepicker._curInst.dpDiv.stop( true, true ); 7062 if ( inst && $.tm_datepicker._datepickerShowing ) { 7063 $.tm_datepicker._hideDatepicker( $.tm_datepicker._curInst.input[ 0 ] ); 7064 } 7065 } 7066 7067 beforeShow = $.tm_datepicker._get( inst, 'beforeShow' ); 7068 beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {}; 7069 if ( beforeShowSettings === false ) { 7070 return; 7071 } 7072 datepicker_extendRemove( inst.settings, beforeShowSettings ); 7073 7074 inst.lastVal = null; 7075 $.tm_datepicker._lastInput = input; 7076 $.tm_datepicker._setDateFromField( inst ); 7077 7078 if ( $.tm_datepicker._inDialog ) { 7079 // hide cursor 7080 input.value = ''; 7081 } 7082 if ( ! $.tm_datepicker._pos ) { 7083 // position below input 7084 $.tm_datepicker._pos = $.tm_datepicker._findPos( input ); 7085 $.tm_datepicker._pos[ 1 ] += input.offsetHeight; // add the height 7086 } 7087 7088 isFixed = false; 7089 $( input ) 7090 .parents() 7091 .each( function() { 7092 isFixed = isFixed || $( this ).css( 'position' ) === 'fixed'; 7093 return ! isFixed; 7094 } ); 7095 7096 offset = { left: $.tm_datepicker._pos[ 0 ], top: $.tm_datepicker._pos[ 1 ] }; 7097 $.tm_datepicker._pos = null; 7098 //to avoid flashes on Firefox 7099 inst.dpDiv.empty(); 7100 // determine sizing offscreen 7101 inst.dpDiv.css( { position: 'absolute', display: 'block', top: '-1000px' } ); 7102 $.tm_datepicker._updateDatepicker( inst ); 7103 // fix width for dynamic number of date pickers 7104 // and adjust position before showing 7105 offset = $.tm_datepicker._checkOffset( inst, offset, isFixed ); 7106 inst.dpDiv.css( { 7107 position: $.tm_datepicker._inDialog && $.blockUI ? 'static' : isFixed ? 'fixed' : 'absolute', 7108 display: 'none', 7109 left: offset.left + 'px', 7110 top: offset.top + 'px' 7111 } ); 7112 7113 if ( ! inst.inline ) { 7114 showAnim = $.tm_datepicker._get( inst, 'showAnim' ); 7115 duration = $.tm_datepicker._get( inst, 'duration' ); 7116 inst.dpDiv.css( 'z-index', datepicker_getZindex( $( input ) ) + 1 ); 7117 $.tm_datepicker._datepickerShowing = true; 7118 7119 if ( $.effects && $.effects.effect[ showAnim ] ) { 7120 inst.dpDiv.show( showAnim, $.tm_datepicker._get( inst, 'showOptions' ), duration ); 7121 } else { 7122 inst.dpDiv[ showAnim || 'show' ]( showAnim ? duration : null ); 7123 } 7124 7125 if ( $.tm_datepicker._shouldFocusInput( inst ) ) { 7126 inst.input.trigger( 'focus' ); 7127 } 7128 7129 $.tm_datepicker._curInst = inst; 7130 } 7131 }, 7132 7133 /* Generate the date picker content. */ 7134 _updateDatepicker: function( inst ) { 7135 var origyearshtml; 7136 var numMonths; 7137 var cols; 7138 var width = 17; 7139 var activeCell; 7140 7141 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) 7142 datepicker_instActive = inst; // for delegate hover events 7143 inst.dpDiv.empty().append( this._generateHTML( inst ) ); 7144 this._attachHandlers( inst ); 7145 7146 numMonths = this._getNumberOfMonths( inst ); 7147 cols = numMonths[ 1 ]; 7148 activeCell = inst.dpDiv.find( '.' + this._dayOverClass + ' a' ); 7149 7150 if ( activeCell.length > 0 ) { 7151 datepicker_handleMouseover.apply( activeCell.get( 0 ), [ activeCell.get( 0 ) ] ); 7152 } 7153 7154 inst.dpDiv.removeClass( 'ui-tm-datepicker-multi-2 ui-tm-datepicker-multi-3 ui-tm-datepicker-multi-4' ).width( '' ); 7155 if ( cols > 1 ) { 7156 inst.dpDiv.addClass( 'ui-tm-datepicker-multi-' + cols ).css( 'width', ( width * cols ) + 'em' ); 7157 } 7158 inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? 'add' : 'remove' ) + 'Class' ]( 'ui-tm-datepicker-multi' ); 7159 inst.dpDiv[ ( this._get( inst, 'isRTL' ) ? 'add' : 'remove' ) + 'Class' ]( 'ui-tm-datepicker-rtl' ); 7160 7161 if ( inst === $.tm_datepicker._curInst && $.tm_datepicker._datepickerShowing && $.tm_datepicker._shouldFocusInput( inst ) ) { 7162 inst.input.trigger( 'focus' ); 7163 } 7164 7165 // deffered render of the years select (to avoid flashes on Firefox) 7166 if ( inst.yearshtml ) { 7167 origyearshtml = inst.yearshtml; 7168 setTimeout( function() { 7169 //assure that inst.yearshtml didn't change. 7170 if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
vendor: 9,356 bytes, lines 7171-7444
7171 inst.dpDiv.find( 'select.ui-tm-datepicker-year:first' ).replaceWith( inst.yearshtml ); 7172 } 7173 origyearshtml = null; 7174 inst.yearshtml = null; 7175 }, 0 ); 7176 } 7177 }, 7178 7179 // #6694 - don't focus the input if it's already focused 7180 // this breaks the change event in IE 7181 // Support: IE and jQuery <1.9 7182 _shouldFocusInput: function( inst ) { 7183 return inst.input && inst.input.is( ':visible' ) && ! inst.input.is( ':disabled' ) && ! inst.input.is( ':focus' ); 7184 }, 7185 7186 /* Check positioning to remain on screen. */ 7187 _checkOffset: function( inst, offset, isFixed ) { 7188 var dpWidth = inst.dpDiv.outerWidth(), 7189 dpHeight = inst.dpDiv.outerHeight(), 7190 inputWidth = inst.input ? inst.input.outerWidth() : 0, 7191 inputHeight = inst.input ? inst.input.outerHeight() : 0, 7192 viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ), 7193 viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() ); 7194 7195 offset.left -= this._get( inst, 'isRTL' ) ? dpWidth - inputWidth : 0; 7196 offset.left -= isFixed && offset.left === inst.input.offset().left ? $( document ).scrollLeft() : 0; 7197 offset.top -= isFixed && offset.top === inst.input.offset().top + inputHeight ? $( document ).scrollTop() : 0; 7198 7199 // Now check if datepicker is showing outside window viewport - move to a better place if so. 7200 offset.left -= Math.min( offset.left, offset.left + dpWidth > viewWidth && viewWidth > dpWidth ? Math.abs( offset.left + dpWidth - viewWidth ) : 0 ); 7201 offset.top -= Math.min( offset.top, offset.top + dpHeight > viewHeight && viewHeight > dpHeight ? Math.abs( dpHeight + inputHeight ) : 0 ); 7202 7203 return offset; 7204 }, 7205 7206 /* Find an object's position on the screen. */ 7207 _findPos: function( obj ) { 7208 var position, 7209 inst = this._getInst( obj ), 7210 isRTL = this._get( inst, 'isRTL' ); 7211 7212 while ( obj && ( obj.type === 'hidden' || obj.nodeType !== 1 || $.expr.pseudos.hidden( obj ) ) ) { 7213 obj = obj[ isRTL ? 'previousSibling' : 'nextSibling' ]; 7214 } 7215 7216 position = $( obj ).offset(); 7217 return [ position.left, position.top ]; 7218 }, 7219 7220 /* Hide the date picker from view. 7221 * @param input element - the input field attached to the date picker 7222 */ 7223 _hideDatepicker: function( input ) { 7224 var showAnim, 7225 duration, 7226 postProcess, 7227 onClose, 7228 inst = this._curInst; 7229 7230 if ( ! inst || ( input && inst !== $.data( input, 'datepicker' ) ) ) { 7231 return; 7232 } 7233 7234 if ( this._datepickerShowing ) { 7235 showAnim = this._get( inst, 'showAnim' ); 7236 duration = this._get( inst, 'duration' ); 7237 postProcess = function() { 7238 $.tm_datepicker._tidyDialog( inst ); 7239 }; 7240 7241 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed 7242 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) { 7243 inst.dpDiv.hide( showAnim, $.tm_datepicker._get( inst, 'showOptions' ), duration, postProcess ); 7244 } else { 7245 inst.dpDiv[ showAnim === 'slideDown' ? 'slideUp' : showAnim === 'fadeIn' ? 'fadeOut' : 'hide' ]( showAnim ? duration : null, postProcess ); 7246 } 7247 7248 if ( ! showAnim ) { 7249 postProcess(); 7250 } 7251 this._datepickerShowing = false; 7252 7253 onClose = this._get( inst, 'onClose' ); 7254 if ( onClose ) { 7255 onClose.apply( inst.input ? inst.input[ 0 ] : null, [ inst.input ? inst.input.val() : '', inst ] ); 7256 } 7257 7258 this._lastInput = null; 7259 if ( this._inDialog ) { 7260 this._dialogInput.css( { position: 'absolute', left: '0', top: '-100px' } ); 7261 if ( $.blockUI ) { 7262 $.unblockUI(); 7263 $( 'body' ).append( this.dpDiv ); 7264 } 7265 } 7266 this._inDialog = false; 7267 } 7268 }, 7269 7270 /* Tidy up after a dialog display. */ 7271 _tidyDialog: function( inst ) { 7272 inst.dpDiv.removeClass( this._dialogClass ).off( '.ui-tm-datepicker-calendar' ); 7273 }, 7274 7275 /* Close date picker if clicked elsewhere. */ 7276 _checkExternalClick: function( event ) { 7277 var $target; 7278 var inst; 7279 7280 if ( ! $.tm_datepicker._curInst ) { 7281 return; 7282 } 7283 7284 $target = $( event.target ); 7285 inst = $.tm_datepicker._getInst( $target[ 0 ] ); 7286 7287 if ( ( $target[ 0 ].id !== $.tm_datepicker._mainDivId && $target.parents( '#' + $.tm_datepicker._mainDivId ).length === 0 && ! $target.hasClass( $.tm_datepicker.markerClassName ) && ! $target.closest( '.' + $.tm_datepicker._triggerClass ).length && $.tm_datepicker._datepickerShowing && ! ( $.tm_datepicker._inDialog && $.blockUI ) ) || ( $target.hasClass( $.tm_datepicker.markerClassName ) && $.tm_datepicker._curInst !== inst ) ) { 7288 $.tm_datepicker._hideDatepicker(); 7289 } 7290 }, 7291 7292 /* Adjust one of the date sub-fields. */ 7293 _adjustDate: function( id, offset, period ) { 7294 var target = $( id ), 7295 inst = this._getInst( target[ 0 ] ); 7296 7297 if ( this._isDisabledDatepicker( target[ 0 ] ) ) { 7298 return; 7299 } 7300 this._adjustInstDate( 7301 inst, 7302 offset + ( period === 'M' ? this._get( inst, 'showCurrentAtPos' ) : 0 ), // undo positioning 7303 period 7304 ); 7305 this._updateDatepicker( inst ); 7306 }, 7307 7308 /* Action for current link. */ 7309 _gotoToday: function( id ) { 7310 var date, 7311 target = $( id ), 7312 inst = this._getInst( target[ 0 ] ); 7313 7314 if ( this._get( inst, 'gotoCurrent' ) && inst.currentDay ) { 7315 inst.selectedDay = inst.currentDay; 7316 inst.drawMonth = inst.currentMonth; 7317 inst.selectedMonth = inst.currentMonth; 7318 inst.drawYear = inst.currentYear; 7319 inst.selectedYear = inst.currentYear; 7320 } else { 7321 date = new Date(); 7322 inst.selectedDay = date.getDate(); 7323 inst.drawMonth = date.getMonth(); 7324 inst.selectedMonth = inst.drawMonth; 7325 inst.drawYear = date.getFullYear(); 7326 inst.selectedYear = inst.drawYear; 7327 } 7328 this._notifyChange( inst ); 7329 this._adjustDate( target ); 7330 }, 7331 7332 /* Action for selecting a new month/year. */ 7333 _selectMonthYear: function( id, select, period ) { 7334 var target = $( id ), 7335 inst = this._getInst( target[ 0 ] ); 7336 7337 inst[ 'selected' + ( period === 'M' ? 'Month' : 'Year' ) ] = parseInt( select.options[ select.selectedIndex ].value, 10 ); 7338 inst[ 'draw' + ( period === 'M' ? 'Month' : 'Year' ) ] = parseInt( select.options[ select.selectedIndex ].value, 10 ); 7339 7340 this._notifyChange( inst ); 7341 this._adjustDate( target ); 7342 }, 7343 7344 /* Action for selecting a day. */ 7345 _selectDay: function( id, month, year, td ) { 7346 var inst, 7347 target = $( id ); 7348 7349 if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) { 7350 return; 7351 } 7352 7353 inst = this._getInst( target[ 0 ] ); 7354 inst.selectedDay = $( 'a', td ).html(); 7355 inst.currentDay = inst.selectedDay; 7356 inst.selectedMonth = month; 7357 inst.currentMonth = month; 7358 inst.selectedYear = year; 7359 inst.currentYear = year; 7360 this._selectDate( id, this._formatDate( inst, inst.currentDay, inst.currentMonth, inst.currentYear ) ); 7361 }, 7362 7363 /* Erase the input field and hide the date picker. */ 7364 _clearDate: function( id ) { 7365 var target = $( id ); 7366 this._selectDate( target, '' ); 7367 }, 7368 7369 /* Update the input field with the selected date. */ 7370 _selectDate: function( id, dateStr ) { 7371 var onSelect, 7372 target = $( id ), 7373 inst = this._getInst( target[ 0 ] ); 7374 7375 dateStr = dateStr !== null ? dateStr : this._formatDate( inst ); 7376 if ( inst.input ) { 7377 inst.input.val( dateStr ); 7378 } 7379 this._updateAlternate( inst ); 7380 7381 onSelect = this._get( inst, 'onSelect' ); 7382 if ( onSelect ) { 7383 onSelect.apply( inst.input ? inst.input[ 0 ] : null, [ dateStr, inst ] ); // trigger custom callback 7384 } else if ( inst.input ) { 7385 inst.input.trigger( 'change' ); // fire the change event 7386 } 7387 7388 if ( inst.inline ) { 7389 this._updateDatepicker( inst ); 7390 } else { 7391 this._hideDatepicker(); 7392 this._lastInput = inst.input[ 0 ]; 7393 if ( typeof inst.input[ 0 ] !== 'object' ) { 7394 inst.input.trigger( 'focus' ); // restore focus 7395 } 7396 this._lastInput = null; 7397 } 7398 }, 7399 7400 /* Update any alternate field to synchronise with the main field. */ 7401 _updateAlternate: function( inst ) { 7402 var altFormat, 7403 date, 7404 dateStr, 7405 altField = this._get( inst, 'altField' ); 7406 7407 if ( altField ) { 7408 // update alternate field too 7409 altFormat = this._get( inst, 'altFormat' ) || this._get( inst, 'dateFormat' ); 7410 date = this._getDate( inst ); 7411 dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) ); 7412 $( altField ).val( dateStr ); 7413 } 7414 }, 7415 7416 /* Set as beforeShowDay function to prevent selection of weekends. 7417 * @param date Date - the date to customise 7418 * @return [boolean, string] - is this date selectable?, what is its CSS class? 7419 */ 7420 noWeekends: function( date ) { 7421 var day = date.getDay(); 7422 return [ day > 0 && day < 6, '' ]; 7423 }, 7424 7425 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. 7426 * @param date Date - the date to get the week for 7427 * @return number - the number of the week within the year that contains this date 7428 */ 7429 iso8601Week: function( date ) { 7430 var time, 7431 checkDate = new Date( date.getTime() ); 7432 7433 // Find Thursday of this week starting on Monday 7434 checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) ); 7435 7436 time = checkDate.getTime(); 7437 checkDate.setMonth( 0 ); // Compare with Jan 1 7438 checkDate.setDate( 1 ); 7439 return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1; 7440 }, 7441 7442 /* Parse a string value into a date object. 7443 * See formatDate below for the possible formats. 7444 *
7445 * @param format string - the expected format of the date 7446 * @param value string - the date in the above format 7447 * @param settings Object - attributes include: 7448 * shortYearCutoff number - the cutoff year for determining the century (optional) 7449 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 7450 * dayNames string[7] - names of the days from Sunday (optional) 7451 * monthNamesShort string[12] - abbreviated names of the months (optional) 7452 * monthNames string[12] - names of the months (optional) 7453 * @return Date - the extracted date value or null if value is blank 7454 */ 7455 parseDate: function( format, value, settings ) { 7456 var iFormat; 7457 var dim; 7458 var extra; 7459 var iValue = 0; 7460 var shortYearCutoffTemp; 7461 var shortYearCutoff; 7462 var dayNamesShort; 7463 var dayNames; 7464 var monthNamesShort; 7465 var monthNames; 7466 var year = -1; 7467 var month = -1; 7468 var day = -1; 7469 var doy = -1; 7470 var literal = false; 7471 var date; 7472 var lookAhead; 7473 var getNumber; 7474 var getName; 7475 var checkLiteral; 7476 var condition; 7477 7478 if ( format === null || value === null ) { 7479 throw 'Invalid arguments'; 7480 } 7481 7482 value = typeof value === 'object' ? value.toString() : value + ''; 7483 if ( value === '' ) { 7484 return null; 7485 } 7486 7487 shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff; 7488 shortYearCutoff = typeof shortYearCutoffTemp !== 'string' ? shortYearCutoffTemp : ( new Date().getFullYear() % 100 ) + parseInt( shortYearCutoffTemp, 10 ); 7489 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort; 7490 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames; 7491 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort; 7492 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames; 7493 7494 // Check whether a format character is doubled 7495 lookAhead = function( match ) { 7496 var matches = iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match; 7497 if ( matches ) { 7498 iFormat = iFormat + 1; 7499 } 7500 return matches; 7501 }; 7502 7503 // Extract a number from the string value 7504 getNumber = function( match ) { 7505 var isDoubled = lookAhead( match ), 7506 size = match === '@' ? 14 : match === '!' ? 20 : match === 'y' && isDoubled ? 4 : match === 'o' ? 3 : 2, 7507 minSize = match === 'y' ? size : 1, 7508 digits = new RegExp( '^\\d{' + minSize + ',' + size + '}' ), 7509 num = value.substring( iValue ).match( digits ); 7510 if ( ! num ) { 7511 throw 'Missing number at position ' + iValue; 7512 } 7513 iValue += num[ 0 ].length; 7514 return parseInt( num[ 0 ], 10 ); 7515 }; 7516 7517 // Extract a name from the string value and convert to an index 7518 getName = function( match, shortNames, longNames ) { 7519 var index = -1, 7520 names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) { 7521 return [ [ k, v ] ]; 7522 } ).sort( function( a, b ) { 7523 return -( a[ 1 ].length - b[ 1 ].length ); 7524 } ); 7525 7526 $.each( names, function( i, pair ) { 7527 var name = pair[ 1 ]; 7528 if ( value.substring( iValue, parseInt( iValue, 10 ) + name.length ).toLowerCase() === name.toLowerCase() ) { 7529 index = pair[ 0 ]; 7530 iValue += name.length; 7531 return false; 7532 } 7533 } ); 7534 if ( index !== -1 ) { 7535 return index + 1; 7536 } 7537 throw 'Unknown name at position ' + iValue; 7538 }; 7539 7540 // Confirm that a literal character matches the string value 7541 checkLiteral = function() { 7542 if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) { 7543 throw 'Unexpected literal at position ' + iValue; 7544 } 7545 iValue = iValue + 1; 7546 }; 7547 7548 for ( iFormat = 0; iFormat < format.length; iFormat += 1 ) { 7549 if ( literal ) { 7550 if ( format.charAt( iFormat ) === "'" && ! lookAhead( "'" ) ) { 7551 literal = false; 7552 } else { 7553 checkLiteral(); 7554 } 7555 } else { 7556 switch ( format.charAt( iFormat ) ) { 7557 case 'd': 7558 day = getNumber( 'd' ); 7559 break; 7560 case 'D': 7561 getName( 'D', dayNamesShort, dayNames ); 7562 break; 7563 case 'o': 7564 doy = getNumber( 'o' ); 7565 break; 7566 case 'm':
7567 month = getNumber( 'm' ); 7568 break; 7569 case 'M': 7570 month = getName( 'M', monthNamesShort, monthNames ); 7571 break; 7572 case 'y': 7573 year = getNumber( 'y' ); 7574 break; 7575 case '@': 7576 date = new Date( getNumber( '@' ) ); 7577 year = date.getFullYear(); 7578 month = date.getMonth() + 1; 7579 day = date.getDate(); 7580 break; 7581 case '!': 7582 date = new Date( ( getNumber( '!' ) - this._ticksTo1970 ) / 10000 ); 7583 year = date.getFullYear(); 7584 month = date.getMonth() + 1; 7585 day = date.getDate(); 7586 break; 7587 case "'": 7588 if ( lookAhead( "'" ) ) { 7589 checkLiteral(); 7590 } else { 7591 literal = true; 7592 } 7593 break; 7594 default: 7595 checkLiteral(); 7596 } 7597 } 7598 } 7599 7600 if ( iValue < value.length ) { 7601 extra = value.substring( iValue ); 7602 if ( ! /^\s+/.test( extra ) ) { 7603 throw 'Extra/unparsed characters found in date: ' + extra; 7604 } 7605 } 7606 7607 if ( year === -1 ) { 7608 year = new Date().getFullYear(); 7609 } else if ( year < 100 ) { 7610 year += new Date().getFullYear() - ( new Date().getFullYear() % 100 ) + ( year <= shortYearCutoff ? 0 : -100 ); 7611 } 7612 7613 if ( doy > -1 ) { 7614 month = 1; 7615 day = doy; 7616 condition = true; 7617 do { 7618 dim = this._getDaysInMonth( year, month - 1 ); 7619 if ( day <= dim ) { 7620 condition = false; 7621 } else { 7622 month = month + 1; 7623 day -= dim; 7624 } 7625 } while ( condition ); 7626 } 7627 7628 date = this._daylightSavingAdjust( new Date( year, month - 1, day ) ); 7629 if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) { 7630 throw 'Invalid date'; // E.g. 31/02/00 7631 } 7632 return date; 7633 }, 7634 7635 /* Standard date formats. */ 7636 ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601) 7637 COOKIE: 'D, dd M yy', 7638 ISO_8601: 'yy-mm-dd', 7639 RFC_822: 'D, d M y', 7640 RFC_850: 'DD, dd-M-y', 7641 RFC_1036: 'D, d M y', 7642 RFC_1123: 'D, d M yy', 7643 RFC_2822: 'D, d M yy', 7644 RSS: 'D, d M y', // RFC 822 7645 TICKS: '!', 7646 TIMESTAMP: '@', 7647 W3C: 'yy-mm-dd', // ISO 8601 7648 7649 _ticksTo1970: ( ( ( 1970 - 1 ) * 365 ) + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) + Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000, 7650 7651 /* Format a date object into a string value. 7652 * The format can be combinations of the following: 7653 * d - day of month (no leading zero) 7654 * dd - day of month (two digit) 7655 * o - day of year (no leading zeros) 7656 * oo - day of year (three digit) 7657 * D - day name short 7658 * DD - day name long 7659 * m - month of year (no leading zero) 7660 * mm - month of year (two digit) 7661 * M - month name short 7662 * MM - month name long 7663 * y - year (two digit) 7664 * yy - year (four digit) 7665 * @ - Unix timestamp (ms since 01/01/1970) 7666 * ! - Windows ticks (100ns since 01/01/0001) 7667 * "..." - literal text 7668 * '' - single quote 7669 * 7670 * @param format string - the desired format of the date 7671 * @param date Date - the date value to format 7672 * @param settings Object - attributes include: 7673 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 7674 * dayNames string[7] - names of the days from Sunday (optional) 7675 * monthNamesShort string[12] - abbreviated names of the months (optional) 7676 * monthNames string[12] - names of the months (optional) 7677 * @return string - the date in the above format 7678 */ 7679 formatDate: function( format, date, settings ) { 7680 var iFormat, 7681 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort, 7682 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames, 7683 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort, 7684 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames, 7685 // Check whether a format character is doubled 7686 lookAhead = function( match ) { 7687 var matches = iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match; 7688 if ( matches ) { 7689 iFormat = iFormat + 1; 7690 } 7691 return matches; 7692 }, 7693 // Format a number, with leading zero if necessary 7694 formatNumber = function( match, value, len ) { 7695 var num = '' + value; 7696 if ( lookAhead( match ) ) { 7697 while ( num.length < len ) { 7698 num = '0' + num; 7699 } 7700 } 7701 return num; 7702 }, 7703 // Format a name, short or long as requested
7704 formatName = function( match, value, shortNames, longNames ) { 7705 return lookAhead( match ) ? longNames[ value ] : shortNames[ value ]; 7706 }, 7707 output = '', 7708 literal = false; 7709 7710 if ( ! date ) { 7711 return ''; 7712 } 7713 7714 if ( date ) { 7715 for ( iFormat = 0; iFormat < format.length; iFormat += 1 ) { 7716 if ( literal ) { 7717 if ( format.charAt( iFormat ) === "'" && ! lookAhead( "'" ) ) { 7718 literal = false; 7719 } else { 7720 output += format.charAt( iFormat ); 7721 } 7722 } else { 7723 switch ( format.charAt( iFormat ) ) { 7724 case 'd': 7725 output += formatNumber( 'd', date.getDate(), 2 ); 7726 break; 7727 case 'D': 7728 output += formatName( 'D', date.getDay(), dayNamesShort, dayNames ); 7729 break; 7730 case 'o': 7731 output += formatNumber( 'o', Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 ); 7732 break; 7733 case 'm': 7734 output += formatNumber( 'm', date.getMonth() + 1, 2 ); 7735 break; 7736 case 'M': 7737 output += formatName( 'M', date.getMonth(), monthNamesShort, monthNames ); 7738 break; 7739 case 'y': 7740 output += lookAhead( 'y' ) ? date.getFullYear() : ( date.getFullYear() % 100 < 10 ? '0' : '' ) + ( date.getFullYear() % 100 ); 7741 break; 7742 case '@': 7743 output += date.getTime(); 7744 break; 7745 case '!': 7746 output += ( date.getTime() * 10000 ) + this._ticksTo1970; 7747 break; 7748 case "'": 7749 if ( lookAhead( "'" ) ) { 7750 output += "'"; 7751 } else { 7752 literal = true; 7753 } 7754 break; 7755 default: 7756 output += format.charAt( iFormat ); 7757 } 7758 } 7759 } 7760 } 7761 return output; 7762 }, 7763 7764 /* Extract all possible characters from the date format. */ 7765 _possibleChars: function( format ) { 7766 var iFormat, 7767 chars = '', 7768 literal = false, 7769 // Check whether a format character is doubled 7770 lookAhead = function( match ) { 7771 var matches = iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match; 7772 if ( matches ) { 7773 iFormat = iFormat + 1; 7774 } 7775 return matches; 7776 }; 7777 7778 for ( iFormat = 0; iFormat < format.length; iFormat += 1 ) { 7779 if ( literal ) { 7780 if ( format.charAt( iFormat ) === "'" && ! lookAhead( "'" ) ) { 7781 literal = false; 7782 } else { 7783 chars += format.charAt( iFormat ); 7784 } 7785 } else { 7786 switch ( format.charAt( iFormat ) ) { 7787 case 'd': 7788 case 'm': 7789 case 'y': 7790 case '@': 7791 chars += '0123456789'; 7792 break; 7793 case 'D': 7794 case 'M': 7795 return null; // Accept anything 7796 case "'": 7797 if ( lookAhead( "'" ) ) { 7798 chars += "'"; 7799 } else { 7800 literal = true; 7801 } 7802 break; 7803 default: 7804 chars += format.charAt( iFormat ); 7805 } 7806 } 7807 } 7808 return chars; 7809 }, 7810 7811 /* Get a setting value, defaulting if necessary. */ 7812 _get: function( inst, name ) { 7813 return inst.settings[ name ] !== undefined ? inst.settings[ name ] : this._defaults[ name ]; 7814 }, 7815 7816 /* Parse existing date and initialise date picker. */ 7817 _setDateFromField: function( inst, noDefault ) { 7818 var dateFormat; 7819 var dates; 7820 var defaultDate; 7821 var date; 7822 var settings; 7823 7824 if ( inst.input.val() === inst.lastVal ) { 7825 return; 7826 } 7827 7828 dateFormat = this._get( inst, 'dateFormat' ); 7829 dates = inst.input ? inst.input.val() : null; 7830 defaultDate = this._getDefaultDate( inst ); 7831 date = defaultDate; 7832 settings = this._getFormatConfig( inst ); 7833 7834 inst.lastVal = dates; 7835 7836 try { 7837 date = this.parseDate( dateFormat, dates, settings ) || defaultDate; 7838 } catch ( event ) { 7839 dates = noDefault ? '' : dates; 7840 } 7841 inst.selectedDay = date.getDate(); 7842 inst.selectedMonth = date.getMonth(); 7843 inst.drawMonth = inst.selectedMonth; 7844 inst.selectedYear = date.getFullYear(); 7845 inst.drawYear = inst.selectedYear; 7846 inst.currentDay = dates ? date.getDate() : 0; 7847 inst.currentMonth = dates ? date.getMonth() : 0; 7848 inst.currentYear = dates ? date.getFullYear() : 0; 7849 this._adjustInstDate( inst ); 7850 }, 7851 7852 /* Retrieve the default date shown on opening. */ 7853 _getDefaultDate: function( inst ) { 7854 return this._restrictMinMax( inst, this._determineDate( inst, this._get( inst, 'defaultDate' ), new Date() ) ); 7855 }, 7856 7857 /* A date may be specified as an exact value or a relative one. */ 7858 _determineDate: function( inst, date, defaultDate ) { 7859 var offsetNumeric = function( offset ) { 7860 var sdate = new Date(); 7861 sdate.setDate( sdate.getDate() + offset ); 7862 return sdate; 7863 }, 7864 offsetString = function( offset ) { 7865 var sdate; 7866 var year; 7867 var month; 7868 var day; 7869 var pattern; 7870 var matches; 7871 7872 try { 7873 return $.tm_datepicker.parseDate( $.tm_datepicker._get( inst, 'dateFormat' ), offset, $.tm_datepicker._getFormatConfig( inst ) ); 7874 } catch ( e ) { 7875 // Ignore 7876 } 7877 7878 sdate = ( offset.toLowerCase().match( /^c/ ) ? $.tm_datepicker._getDate( inst ) : null ) || new Date(); 7879 year = sdate.getFullYear();
7880 month = sdate.getMonth(); 7881 day = sdate.getDate(); 7882 pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g; 7883 matches = pattern.exec( offset ); 7884 7885 while ( matches ) { 7886 switch ( matches[ 2 ] || 'd' ) { 7887 case 'd': 7888 case 'D': 7889 day += parseInt( matches[ 1 ], 10 ); 7890 break; 7891 case 'w': 7892 case 'W': 7893 day += parseInt( matches[ 1 ], 10 ) * 7; 7894 break; 7895 case 'm': 7896 case 'M': 7897 month += parseInt( matches[ 1 ], 10 ); 7898 day = Math.min( day, $.tm_datepicker._getDaysInMonth( year, month ) ); 7899 break; 7900 case 'y': 7901 case 'Y': 7902 year += parseInt( matches[ 1 ], 10 ); 7903 day = Math.min( day, $.tm_datepicker._getDaysInMonth( year, month ) ); 7904 break; 7905 } 7906 matches = pattern.exec( offset ); 7907 } 7908 return new Date( year, month, day ); 7909 }, 7910 newDate = date === null || date === '' ? defaultDate : typeof date === 'string' ? offsetString( date ) : typeof date === 'number' ? ( ! Number.isFinite( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ); 7911 7912 newDate = newDate && newDate.toString() === 'Invalid Date' ? defaultDate : newDate; 7913 if ( newDate ) { 7914 newDate.setHours( 0 ); 7915 newDate.setMinutes( 0 ); 7916 newDate.setSeconds( 0 ); 7917 newDate.setMilliseconds( 0 ); 7918 } 7919 return this._daylightSavingAdjust( newDate ); 7920 }, 7921 7922 /* Handle switch to/from daylight saving. 7923 * Hours may be non-zero on daylight saving cut-over: 7924 * > 12 when midnight changeover, but then cannot generate 7925 * midnight datetime, so jump to 1AM, otherwise reset. 7926 * @param date (Date) the date to check 7927 * @return (Date) the corrected date 7928 */ 7929 _daylightSavingAdjust: function( date ) { 7930 if ( ! date ) { 7931 return null; 7932 } 7933 date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 ); 7934 return date; 7935 }, 7936 7937 /* Set the date(s) directly. */ 7938 _setDate: function( inst, date, noChange ) { 7939 var clear = ! date, 7940 origMonth = inst.selectedMonth, 7941 origYear = inst.selectedYear, 7942 newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) ); 7943 7944 inst.currentDay = newDate.getDate(); 7945 inst.selectedDay = inst.currentDay; 7946 inst.currentMonth = newDate.getMonth(); 7947 inst.drawMonth = inst.currentMonth; 7948 inst.selectedMonth = inst.currentMonth; 7949 inst.currentYear = newDate.getFullYear(); 7950 inst.drawYear = inst.currentYear; 7951 inst.selectedYear = inst.currentYear; 7952 if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && ! noChange ) { 7953 this._notifyChange( inst ); 7954 } 7955 this._adjustInstDate( inst ); 7956 if ( inst.input ) { 7957 inst.input.val( clear ? '' : this._formatDate( inst ) ); 7958 } 7959 }, 7960 7961 /* Retrieve the date(s) directly. */ 7962 _getDate: function( inst ) { 7963 var startDate = ! inst.currentYear || ( inst.input && inst.input.val() === '' ) ? null : this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ); 7964 return startDate; 7965 }, 7966 7967 /* Attach the onxxx handlers. These are declared statically so 7968 * they work with static code transformers like Caja. 7969 */ 7970 _attachHandlers: function( inst ) { 7971 var stepMonths = this._get( inst, 'stepMonths' ), 7972 id = '#' + inst.id.replace( /\\\\/g, '\\' ); 7973 inst.dpDiv.find( '[data-handler]' ).map( function() { 7974 var handler = { 7975 prevM: function() { 7976 $.tm_datepicker._adjustDate( id, -1, 'M' ); 7977 }, 7978 nextM: function() { 7979 $.tm_datepicker._adjustDate( id, +1, 'M' ); 7980 }, 7981 prevY: function() { 7982 $.tm_datepicker._adjustDate( id, -1, 'Y' ); 7983 }, 7984 nextY: function() { 7985 $.tm_datepicker._adjustDate( id, +1, 'Y' ); 7986 }, 7987 prev: function() { 7988 $.tm_datepicker._adjustDate( id, -stepMonths, 'M' ); 7989 }, 7990 next: function() { 7991 $.tm_datepicker._adjustDate( id, +stepMonths, 'M' ); 7992 }, 7993 hide: function() { 7994 $.tm_datepicker._hideDatepicker(); 7995 }, 7996 today: function() { 7997 /*var tempDate = new Date(), 7998 today = $.tm_datepicker._daylightSavingAdjust( 7999 new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())); 8000 $.tm_datepicker._setDate(inst, today); 8001 $.tm_datepicker._gotoToday(id);*/ 8002 }, 8003 selectDay: function() { 8004 $.tm_datepicker._selectDay( id, +this.getAttribute( 'data-month' ), +this.getAttribute( 'data-year' ), this ); 8005 return false;
8006 }, 8007 selectMonth: function() { 8008 $.tm_datepicker._selectMonthYear( id, this, 'M' ); 8009 return false; 8010 }, 8011 selectYear: function() { 8012 $.tm_datepicker._selectMonthYear( id, this, 'Y' ); 8013 return false; 8014 } 8015 }; 8016 $( this ).on( this.getAttribute( 'data-event' ), handler[ this.getAttribute( 'data-handler' ) ] ); 8017 return null; 8018 } ); 8019 }, 8020 /* Determines if we should allow a "next/prev" month display change. */ 8021 _tm_canAdjustMonth: function( inst, offset, curYear, curMonth ) { 8022 var date = this._daylightSavingAdjust( new Date( curYear, curMonth + offset, 1 ) ); 8023 8024 if ( offset < 0 ) { 8025 date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) ); 8026 } 8027 return this._isInRange( inst, date ); 8028 }, 8029 8030 /* Generate the HTML for the current state of the date picker. */ 8031 _generateHTML: function( inst ) { 8032 var maxDraw, 8033 prevText, 8034 prev, 8035 nextText, 8036 next, 8037 currentText, 8038 gotoDate, 8039 firstDay, 8040 showWeek, 8041 dayNames, 8042 dayNamesMin, 8043 monthNames, 8044 beforeShowDay, 8045 showOtherMonths, 8046 selectOtherMonths, 8047 defaultDate, 8048 html, 8049 dow, 8050 row, 8051 group, 8052 col, 8053 selectedDate, 8054 cornerClass, 8055 calender, 8056 thead, 8057 day, 8058 daysInMonth, 8059 leadDays, 8060 curRows, 8061 numRows, 8062 printDate, 8063 dRow, 8064 tbody, 8065 daySettings, 8066 otherMonth, 8067 unselectable, 8068 tempDate = new Date(), 8069 today = this._daylightSavingAdjust( new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time 8070 isRTL = this._get( inst, 'isRTL' ), 8071 showButtonPanel = this._get( inst, 'showButtonPanel' ), 8072 hideIfNoPrevNext = this._get( inst, 'hideIfNoPrevNext' ), 8073 navigationAsDateFormat = this._get( inst, 'navigationAsDateFormat' ), 8074 numMonths = this._getNumberOfMonths( inst ), 8075 showCurrentAtPos = this._get( inst, 'showCurrentAtPos' ), 8076 stepMonths = this._get( inst, 'stepMonths' ), 8077 isMultiMonth = numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1, 8078 currentDate = this._daylightSavingAdjust( ! inst.currentDay ? new Date( 9999, 9, 9 ) : new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ), 8079 minDate = this._getMinMaxDate( inst, 'min' ), 8080 maxDate = this._getMinMaxDate( inst, 'max' ), 8081 drawMonth = inst.drawMonth - showCurrentAtPos, 8082 drawYear = inst.drawYear, 8083 tm_month, 8084 tm_year, 8085 tm_prev_arrow_m, 8086 tm_next_arrow_m, 8087 tm_prev_arrow_y, 8088 tm_next_arrow_y, 8089 tm_controls, 8090 tm_buttonPanel; 8091 var can_adjust_1; 8092 var can_adjust_2; 8093 var can_adjust_3; 8094 var can_adjust_4; 8095 8096 if ( drawMonth < 0 ) { 8097 drawMonth += 12; 8098 drawYear -= 1; 8099 } 8100 if ( maxDate ) { 8101 maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(), maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) ); 8102 maxDraw = minDate && maxDraw < minDate ? minDate : maxDraw; 8103 while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) { 8104 drawMonth -= 1; 8105 if ( drawMonth < 0 ) { 8106 drawMonth = 11; 8107 drawYear -= 1; 8108 } 8109 } 8110 } 8111 inst.drawMonth = drawMonth; 8112 inst.drawYear = drawYear; 8113 8114 prevText = this._get( inst, 'prevText' ); 8115 prevText = ! navigationAsDateFormat ? prevText : this.formatDate( prevText, this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ), this._getFormatConfig( inst ) ); 8116 8117 prev = this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ? "<a class='ui-tm-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" + " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? 'e' : 'w' ) + "'>" + prevText + '</span></a>' : hideIfNoPrevNext ? '' : "<a class='ui-tm-datepicker-prev ui-corner-all ui-state-disabled' title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? 'e' : 'w' ) + "'>" + prevText + '</span></a>'; 8118 8119 nextText = this._get( inst, 'nextText' ); 8120 nextText = ! navigationAsDateFormat ? nextText : this.formatDate( nextText, this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ), this._getFormatConfig( inst ) ); 8121 8122 next = this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ? "<a class='ui-tm-datepicker-next ui-corner-all' data-handler='next' data-event='click'" + " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? 'w' : 'e' ) + "'>" + nextText + '</span></a>' : hideIfNoPrevNext ? '' : "<a class='ui-tm-datepicker-next ui-corner-all ui-state-disabled' title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? 'w' : 'e' ) + "'>" + nextText + '</span></a>'; 8123 8124 currentText = this._get( inst, 'currentText' ); 8125 gotoDate = this._get( inst, 'gotoCurrent' ) && inst.currentDay ? currentDate : today; 8126 currentText = ! navigationAsDateFormat ? currentText : this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ); 8127 8128 tm_controls = ! inst.inline ? "<div class='tm-ui-dp-btn-wrap tm-ui-dp-close'><div role='button' class='tm-ui-dp-btn ui-tm-datepicker-close' data-handler='hide' data-event='click'>" + this._get( inst, 'closeText' ) + '</div></div>' : ''; 8129 8130 tm_buttonPanel = showButtonPanel ? "<div class='tm-ui-dp-buttonpane'>" + ( isRTL ? tm_controls : '' ) + ( this._isInRange( inst, gotoDate ) ? "<div class='tm-ui-dp-btn-wrap tm-ui-dp-current'><div role='button' class='tm-ui-dp-btn ui-tm-datepicker-current' data-handler='today' data-event='click'" + '>' + currentText + '</div></div>' : '' ) + ( isRTL ? '' : tm_controls ) + '</div>' : ''; 8131 8132 firstDay = parseInt( this._get( inst, 'firstDay' ), 10 ); 8133 firstDay = isNaN( firstDay ) ? 0 : firstDay; 8134 8135 showWeek = this._get( inst, 'showWeek' ); 8136 dayNames = this._get( inst, 'dayNames' ); 8137 dayNamesMin = this._get( inst, 'dayNamesMin' ); 8138 monthNames = this._get( inst, 'monthNames' ); 8139 //monthNamesShort = this._get(inst, "monthNamesShort"); 8140 beforeShowDay = this._get( inst, 'beforeShowDay' ); 8141 showOtherMonths = this._get( inst, 'showOtherMonths' ); 8142 selectOtherMonths = this._get( inst, 'selectOtherMonths' ); 8143 defaultDate = this._getDefaultDate( inst ); 8144 html = ''; 8145 8146 can_adjust_1 = this._tm_canAdjustMonth( inst, -1, drawYear, drawMonth ); 8147 can_adjust_2 = this._tm_canAdjustMonth( inst, +1, drawYear, drawMonth ); 8148 can_adjust_3 = this._tm_canAdjustMonth( inst, -12, drawYear, drawMonth ); 8149 can_adjust_4 = this._tm_canAdjustMonth( inst, +12, drawYear, drawMonth ); 8150 8151 tm_prev_arrow_m = '<div class="tm-ui-dp-button-prev tm-ui-dp-button">' + '<div ' + ( can_adjust_1 ? 'data-handler="prevM" data-event="click" ' : '' ) + 'aria-label="' + prevText + '" class="' + ( can_adjust_1 ? '' : 'tm-ui-dp-button-disabled ' ) + 'tm-ui-dp-button-arrow tcfa tcfa-angle-left" tabindex="0" role="button"></div>' + '</div>'; 8152 tm_next_arrow_m = '<div class="tm-ui-dp-button-next tm-ui-dp-button">' + '<div ' + ( can_adjust_2 ? 'data-handler="nextM" data-event="click" ' : '' ) + 'aria-label="' + nextText + '" class="' + ( can_adjust_2 ? '' : 'tm-ui-dp-button-disabled ' ) + 'tm-ui-dp-button-arrow tcfa tcfa-angle-right" tabindex="0" role="button"></div>' + '</div>'; 8153 tm_prev_arrow_y = '<div class="tm-ui-dp-button-prev tm-ui-dp-button">' + '<div ' + ( can_adjust_3 ? 'data-handler="prevY" data-event="click" ' : '' ) + 'aria-label="' + prevText + '" class="' + ( can_adjust_3 ? '' : 'tm-ui-dp-button-disabled ' ) + 'tm-ui-dp-button-arrow tcfa tcfa-angle-left" tabindex="0" role="button"></div>' + '</div>'; 8154 tm_next_arrow_y = '<div class="tm-ui-dp-button-next tm-ui-dp-button">' + '<div ' + ( can_adjust_4 ? 'data-handler="nextY" data-event="click" ' : '' ) + 'aria-label="' + nextText + '" class="' + ( can_adjust_4 ? '' : 'tm-ui-dp-button-disabled ' ) + 'tm-ui-dp-button-arrow tcfa tcfa-angle-right" tabindex="0" role="button"></div>' + '</div>'; 8155
8156 tm_month = hideIfNoPrevNext ? '' : '<div class="tm-ui-dp-title-button">' + ( isRTL ? tm_next_arrow_m : tm_prev_arrow_m ) + '<span aria-label="' + monthNames[ drawMonth ] + '" role="button" class="tm-ui-dp-month">' + monthNames[ drawMonth ] + '</span>' + ( isRTL ? tm_prev_arrow_m : tm_next_arrow_m ) + '</div>'; 8157 8158 tm_year = hideIfNoPrevNext ? '' : '<div class="tm-ui-dp-title-button">' + ( isRTL ? tm_next_arrow_y : tm_prev_arrow_y ) + '<span class="tm-ui-dp-year" role="button" aria-label="' + drawYear + '">' + drawYear + '</span>' + ( isRTL ? tm_prev_arrow_y : tm_next_arrow_y ) + '</div>'; 8159 8160 html += "<div class='tm-ui-dp-wrap'>" + "<div class='tm-ui-dp-overlay'></div>" + "<div class='tm-ui-dp'>" + "<div class='tm-ui-dp-container'>" + "<div class='tm-ui-dp-inner-container'>" + "<div class='tm-ui-dp-ui'>" + "<div class='tm-ui-dp-ui-inner'>" + "<div class='tm-ui-dp-main-wrap'>" + "<div class='tm-ui-dp-main'>"; 8161 8162 for ( row = 0; row < numMonths[ 0 ]; row += 1 ) { 8163 group = ''; 8164 this.maxRows = 4; 8165 for ( col = 0; col < numMonths[ 1 ]; col += 1 ) { 8166 selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) ); 8167 cornerClass = ' ui-corner-all'; 8168 calender = ''; 8169 if ( isMultiMonth ) { 8170 calender += "<div class='ui-tm-datepicker-group"; 8171 if ( numMonths[ 1 ] > 1 ) { 8172 switch ( col ) { 8173 case 0: 8174 calender += ' ui-tm-datepicker-group-first'; 8175 cornerClass = ' ui-corner-' + ( isRTL ? 'right' : 'left' ); 8176 break; 8177 case numMonths[ 1 ] - 1: 8178 calender += ' ui-tm-datepicker-group-last'; 8179 cornerClass = ' ui-corner-' + ( isRTL ? 'left' : 'right' ); 8180 break; 8181 default: 8182 calender += ' ui-tm-datepicker-group-middle'; 8183 cornerClass = ''; 8184 break; 8185 } 8186 } 8187 calender += "'>"; 8188 } 8189 calender += 8190 "<div class='tm-ui-dp-header ui-tm-datepicker-header ui-widget-header ui-helper-clearfix" + 8191 cornerClass + 8192 "'>" + 8193 ( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : '' ) + 8194 ( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : '' ) + 8195 // month headers 8196 8197 '<div class="ui-tm-datepicker-title tm-ui-dp-title">' + 8198 ( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? tm_year + tm_month : tm_month + tm_year ) : '' ) + 8199 '</div>' + 8200 '</div>'; 8201 8202 calender += "<div class='tm-ui-dp-main-content'>"; 8203 8204 /* Days start */ 8205 calender += "<div class='tm-ui-dp-main-header-wrap'><div class='tm-ui-dp-main-header'>"; 8206 calender += "<table class='ui-tm-datepicker-calendar'><tbody>" + '<tr>'; 8207 thead = showWeek ? "<th class='ui-tm-datepicker-week-col'>" + this._get( inst, 'weekHeader' ) + '</th>' : ''; 8208 for ( dow = 0; dow < 7; dow += 1 ) { 8209 // days of the week 8210 day = ( dow + firstDay ) % 7; 8211 thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-tm-datepicker-week-end'" : '' ) + '>
8211' + "<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + '</span></th>'; 8212 } 8213 calender += thead + '</tr></tbody></table>'; 8214 calender += '</div></div>'; 8215 /* Days end */ 8216 8217 calender += "<div class='tm-ui-dp-main-table'>"; 8218 8219 daysInMonth = this._getDaysInMonth( drawYear, drawMonth ); 8220 if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) { 8221 inst.selectedDay = Math.min( inst.selectedDay, daysInMonth ); 8222 } 8223 leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7; 8224 curRows = 6; 8225 numRows = isMultiMonth ? ( this.maxRows > curRows ? this.maxRows : curRows ) : curRows; //If multiple months, use the higher number of rows 8226 // (see #7043) 8227 this.maxRows = numRows; 8228 printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) ); 8229 for ( dRow = 0; dRow < numRows; dRow += 1 ) { 8230 // create date picker rows 8231 calender += "<div class='tm-ui-dp-main-row'>"; 8232 tbody = ! showWeek ? '' : "<div class='ui-tm-datepicker-week-col'>" + this._get( inst, 'calculateWeek' )( printDate ) + '</div>'; 8233 for ( dow = 0; dow < 7; dow += 1 ) { 8234 // create date picker days 8235 daySettings = beforeShowDay ? beforeShowDay.apply( inst.input ? inst.input[ 0 ] : null, [ printDate ] ) : [ true, '' ]; 8236 otherMonth = printDate.getMonth() !== drawMonth; 8237 unselectable = ( otherMonth && ! selectOtherMonths ) || ! daySettings[ 0 ] || ( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate ); 8238 8239 tbody += 8240 "<div class='tm-ui-dp-main-cell " + 8241 ( ( dow + firstDay + 6 ) % 7 >= 5 ? ' ui-tm-datepicker-week-end' : '' ) + // highlight weekends 8242 ( otherMonth ? ' ui-tm-datepicker-other-month' : '' ) + // highlight days from other months 8243 ( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || ( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ? ' ' + this._dayOverClass : '' ) + 8244 ( unselectable ? ' ' + this._unselectableClass + ' ui-state-disabled' : '' ) + // highlight unselectable days 8245 ( otherMonth && ! showOtherMonths ? '' : ' ' + daySettings[ 1 ] + ( printDate.getTime() === currentDate.getTime() ? ' ' + this._currentClass : '' ) + ( printDate.getTime() === today.getTime() ? ' ui-tm-datepicker-today' : '' ) ) + 8246 "'" + // highlight today (if different) 8247 ( ( ! otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, ''' ) + "'" : '' ) + // cell 8248 // title 8249 ( unselectable ? '' : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + 8250 '>' + // actions 8251 "<div class='tm-ui-dp-main-cell-inner'>" + 8252 "<div class='tm-ui-dp-main-cell-content'>" + 8253 ( otherMonth && ! showOtherMonths ? ' ' : unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + '</span>' : "<a class='ui-state-default" + ( printDate.getTime() === today.getTime() ? ' ui-state-highlight' : '' ) + ( printDate.getTime() === currentDate.getTime() ? ' ui-state-active' : '' ) + ( otherMonth ? ' ui-priority-secondary' : '' ) + "' href='#'>" + printDate.getDate() + '</a>' ) + 8254 '</div></div>' + 8255 '</div>'; // display selectable date 8256 printDate.setDate( printDate.getDate() + 1 ); 8257 printDate = this._daylightSavingAdjust( printDate ); 8258 } 8259 calender += tbody + '</div>'; 8260 } 8261 drawMonth += 1; 8262 if ( drawMonth > 11 ) { 8263 drawMonth = 0; 8264 drawYear += 1; 8265 } 8266 8267 calender += '</div>'; 8268 8269 calender += '</div>' + ( isMultiMonth ? '</div>' + ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ? "<div class='ui-tm-datepicker-row-break'></div>" : '' ) : '' ); 8270 group += calender; 8271 } 8272 html += group; 8273 } 8274 html += '</div></div></div></div></div>'; 8275 html += tm_buttonPanel; 8276 html += '</div></div></div>'; 8277 inst._keyEvent = false; 8278 return html; 8279 }, 8280 8281 /* Generate the month and year header. */ 8282 _generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate, secondary, monthNames, monthNamesShort ) { 8283 var inMinYear, 8284 inMaxYear, 8285 month, 8286 years, 8287 thisYear, 8288 determineYear, 8289 year, 8290 endYear, 8291 changeMonth = this._get( inst, 'changeMonth' ), 8292 changeYear = this._get( inst, 'changeYear' ), 8293 showMonthAfterYear = this._get( inst, 'showMonthAfterYear' ), 8294 html = "<div class='ui-tm-datepicker-title'>", 8295 monthHtml = ''; 8296 8297 // month selection 8298 if ( secondary || ! changeMonth ) { 8299 monthHtml += "<span class='ui-tm-datepicker-month'>" + monthNames[ drawMonth ] + '</span>'; 8300 } else { 8301 inMinYear = minDate && minDate.getFullYear() === drawYear; 8302 inMaxYear = maxDate && maxDate.getFullYear() === drawYear; 8303 monthHtml += "<select class='ui-tm-datepicker-month' data-handler='selectMonth' data-event='change'>"; 8304 for ( month = 0; month < 12; month += 1 ) { 8305 if ( ( ! inMinYear || month >= minDate.getMonth() ) && ( ! inMaxYear || month <= maxDate.getMonth() ) ) { 8306 monthHtml += "<option value='" + month + "'" + ( month === drawMonth ? " selected='selected'" : '' ) + '>
vendor: 8,079 bytes, lines 8306-8509
8306' + monthNamesShort[ month ] + '</option>'; 8307 } 8308 } 8309 monthHtml += '</select>'; 8310 } 8311 8312 if ( ! showMonthAfterYear ) { 8313 html += monthHtml + ( secondary || ! ( changeMonth && changeYear ) ? ' ' : '' ); 8314 } 8315 8316 // year selection 8317 if ( ! inst.yearshtml ) { 8318 inst.yearshtml = ''; 8319 if ( secondary || ! changeYear ) { 8320 html += "<span class='ui-tm-datepicker-year'>" + drawYear + '</span>'; 8321 } else { 8322 // determine range of years to display 8323 years = this._get( inst, 'yearRange' ).split( ':' ); 8324 thisYear = new Date().getFullYear(); 8325 determineYear = function( value ) { 8326 var syear = value.match( /c[+-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) : value.match( /[+-].*/ ) ? thisYear + parseInt( value, 10 ) : parseInt( value, 10 ); 8327 return isNaN( syear ) ? thisYear : syear; 8328 }; 8329 year = determineYear( years[ 0 ] ); 8330 endYear = Math.max( year, determineYear( years[ 1 ] || '' ) ); 8331 year = minDate ? Math.max( year, minDate.getFullYear() ) : year; 8332 endYear = maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear; 8333 inst.yearshtml += "<select class='ui-tm-datepicker-year' data-handler='selectYear' data-event='change'>"; 8334 for ( ; year <= endYear; year += 1 ) { 8335 inst.yearshtml += "<option value='" + year + "'" + ( year === drawYear ? " selected='selected'" : '' ) + '>' + year + '</option>'; 8336 } 8337 inst.yearshtml += '</select>'; 8338 8339 html += inst.yearshtml; 8340 inst.yearshtml = null; 8341 } 8342 } 8343 8344 html += this._get( inst, 'yearSuffix' ); 8345 if ( showMonthAfterYear ) { 8346 html += ( secondary || ! ( changeMonth && changeYear ) ? ' ' : '' ) + monthHtml; 8347 } 8348 html += '</div>'; // Close datepicker_header 8349 return html; 8350 }, 8351 8352 /* Adjust one of the date sub-fields. */ 8353 _adjustInstDate: function( inst, offset, period ) { 8354 var year = inst.selectedYear + ( period === 'Y' ? offset : 0 ), 8355 month = inst.selectedMonth + ( period === 'M' ? offset : 0 ), 8356 day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === 'D' ? offset : 0 ), 8357 date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) ); 8358 8359 inst.selectedDay = date.getDate(); 8360 inst.selectedMonth = date.getMonth(); 8361 inst.drawMonth = inst.selectedMonth; 8362 inst.selectedYear = date.getFullYear(); 8363 inst.drawYear = inst.selectedYear; 8364 if ( period === 'M' || period === 'Y' ) { 8365 this._notifyChange( inst ); 8366 } 8367 }, 8368 8369 /* Ensure a date is within any min/max bounds. */ 8370 _restrictMinMax: function( inst, date ) { 8371 var minDate = this._getMinMaxDate( inst, 'min' ), 8372 maxDate = this._getMinMaxDate( inst, 'max' ), 8373 newDate = minDate && date < minDate ? minDate : date; 8374 return maxDate && newDate > maxDate ? maxDate : newDate; 8375 }, 8376 8377 /* Notify change of month/year. */ 8378 _notifyChange: function( inst ) { 8379 var onChange = this._get( inst, 'onChangeMonthYear' ); 8380 if ( onChange ) { 8381 onChange.apply( inst.input ? inst.input[ 0 ] : null, [ inst.selectedYear, inst.selectedMonth + 1, inst ] ); 8382 } 8383 }, 8384 8385 /* Determine the number of months to show. */ 8386 _getNumberOfMonths: function( inst ) { 8387 var numMonths = this._get( inst, 'numberOfMonths' ); 8388 return numMonths === null ? [ 1, 1 ] : typeof numMonths === 'number' ? [ 1, numMonths ] : numMonths; 8389 }, 8390 8391 /* Determine the current maximum date - ensure no time components are set. */ 8392 _getMinMaxDate: function( inst, minMax ) { 8393 return this._determineDate( inst, this._get( inst, minMax + 'Date' ), null ); 8394 }, 8395 8396 /* Find the number of days in a given month. */ 8397 _getDaysInMonth: function( year, month ) { 8398 return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate(); 8399 }, 8400 8401 /* Find the day of the week of the first of a month. */ 8402 _getFirstDayOfMonth: function( year, month ) { 8403 return new Date( year, month, 1 ).getDay(); 8404 }, 8405 8406 /* Determines if we should allow a "next/prev" month display change. */ 8407 _canAdjustMonth: function( inst, offset, curYear, curMonth ) { 8408 var numMonths = this._getNumberOfMonths( inst ), 8409 date = this._daylightSavingAdjust( new Date( curYear, curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) ); 8410 8411 if ( offset < 0 ) { 8412 date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) ); 8413 } 8414 return this._isInRange( inst, date ); 8415 }, 8416 8417 /* Is the given date in the accepted range? */ 8418 _isInRange: function( inst, date ) { 8419 var yearSplit, 8420 currentYear, 8421 minDate = this._getMinMaxDate( inst, 'min' ), 8422 maxDate = this._getMinMaxDate( inst, 'max' ), 8423 minYear = null, 8424 maxYear = null, 8425 years = this._get( inst, 'yearRange' ); 8426 if ( years ) { 8427 yearSplit = years.split( ':' ); 8428 currentYear = new Date().getFullYear(); 8429 minYear = parseInt( yearSplit[ 0 ], 10 ); 8430 maxYear = parseInt( yearSplit[ 1 ], 10 ); 8431 if ( yearSplit[ 0 ].match( /[+-].*/ ) ) { 8432 minYear += currentYear; 8433 } 8434 if ( yearSplit[ 1 ].match( /[+-].*/ ) ) { 8435 maxYear += currentYear; 8436 } 8437 } 8438 8439 return ( ! minDate || date.getTime() >= minDate.getTime() ) && ( ! maxDate || date.getTime() <= maxDate.getTime() ) && ( ! minYear || date.getFullYear() >= minYear ) && ( ! maxYear || date.getFullYear() <= maxYear ); 8440 }, 8441 8442 /* Provide the configuration settings for formatting/parsing. */ 8443 _getFormatConfig: function( inst ) { 8444 var shortYearCutoff = this._get( inst, 'shortYearCutoff' ); 8445 shortYearCutoff = typeof shortYearCutoff !== 'string' ? shortYearCutoff : ( new Date().getFullYear() % 100 ) + parseInt( shortYearCutoff, 10 ); 8446 return { 8447 shortYearCutoff: shortYearCutoff, 8448 dayNamesShort: this._get( inst, 'dayNamesShort' ), 8449 dayNames: this._get( inst, 'dayNames' ), 8450 monthNamesShort: this._get( inst, 'monthNamesShort' ), 8451 monthNames: this._get( inst, 'monthNames' ) 8452 }; 8453 }, 8454 8455 /* Format the given date for display. */ 8456 _formatDate: function( inst, day, month, year ) { 8457 var date; 8458 8459 if ( ! day ) { 8460 inst.currentDay = inst.selectedDay; 8461 inst.currentMonth = inst.selectedMonth; 8462 inst.currentYear = inst.selectedYear; 8463 } 8464 date = day ? ( typeof day === 'object' ? day : this._daylightSavingAdjust( new Date( year, month, day ) ) ) : this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ); 8465 return this.formatDate( this._get( inst, 'dateFormat' ), date, this._getFormatConfig( inst ) ); 8466 } 8467 } ); 8468 8469 /* Invoke the datepicker functionality. 8470 @param options string - a command, optionally followed by additional parameters or 8471 Object - settings for attaching new datepicker functionality 8472 @return jQuery object */ 8473 $.fn.tm_datepicker = function( options ) { 8474 var otherArgs; 8475 8476 /* Verify an empty collection wasn't passed - Fixes #6976 */ 8477 if ( ! this.length ) { 8478 return this; 8479 } 8480 8481 /* Initialise the date picker. */ 8482 if ( ! $.tm_datepicker.initialized ) { 8483 $( document ).on( 'mousedown', $.tm_datepicker._checkExternalClick ); 8484 $.tm_datepicker.initialized = true; 8485 } 8486 8487 /* Append datepicker main container to body if not exist. */ 8488 if ( $( '#' + $.tm_datepicker._mainDivId ).length === 0 ) { 8489 $( 'body' ).append( $.tm_datepicker.dpDiv ); 8490 } 8491 8492 otherArgs = Array.prototype.slice.call( arguments, 1 ); 8493 if ( typeof options === 'string' && ( options === 'isDisabled' || options === 'getDate' || options === 'widget' ) ) { 8494 return $.tm_datepicker[ '_' + options + 'Datepicker' ].apply( $.tm_datepicker, [ this[ 0 ] ].concat( otherArgs ) ); 8495 } 8496 if ( options === 'option' && arguments.length === 2 && typeof arguments[ 1 ] === 'string' ) { 8497 return $.tm_datepicker[ '_' + options + 'Datepicker' ].apply( $.tm_datepicker, [ this[ 0 ] ].concat( otherArgs ) ); 8498 } 8499 return this.each( function() { 8500 if ( typeof options === 'string' ) { 8501 $.tm_datepicker[ '_' + options + 'Datepicker' ].apply( $.tm_datepicker, [ this ].concat( otherArgs ) ); 8502 } else { 8503 $.tm_datepicker._attachDatepicker( this, options ); 8504 } 8505 } ); 8506 }; 8507 8508 $.tm_datepicker = new Datepicker(); // singleton instance 8509 $.tm_datepicker.initialized = false;
8510 $.tm_datepicker.uuid = new Date().getTime(); 8511 $.tm_datepicker.version = '1.11.4'; 8512} ) ); 8513; 8514/*! jQuery Timepicker Addon - v1.6.3 - 2016-04-20 8515 * http://trentrichardson.com/examples/timepicker 8516 * Modified version of jQuery Timepicker 8517 * Copyright (c) 2016 Trent Richardson; Licensed MIT */ 8518( function( factory ) { 8519 'use strict'; 8520 if ( typeof window.define === 'function' && window.define.amd ) { 8521 window.define( [ 'jquery', 'jquery-ui' ], factory ); 8522 } else { 8523 factory( window.jQuery ); 8524 } 8525}( function( $ ) { 8526 'use strict'; 8527 8528 /* 8529 * jQuery extend now ignores nulls! 8530 */ 8531 var extendRemove = function( target, props ) { 8532 var name; 8533 $.extend( target, props ); 8534 for ( name in props ) { 8535 if ( props[ name ] === null || props[ name ] === undefined ) { 8536 target[ name ] = props[ name ]; 8537 } 8538 } 8539 return target; 8540 }; 8541 8542 /* 8543 * jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype, 8544 * it will return false for all objects 8545 */ 8546 var isEmptyObject = function( obj ) { 8547 var prop; 8548 for ( prop in obj ) { 8549 if ( Object.prototype.hasOwnProperty.call( obj, prop ) ) { 8550 return false; 8551 } 8552 } 8553 return true; 8554 }; 8555 8556 /* 8557 * Determine by the time format which units are supported 8558 * Returns an object of booleans for each unit 8559 */ 8560 var detectSupport = function( timeFormat ) { 8561 var tf = timeFormat.replace( /'.*?'/g, '' ).toLowerCase(), // removes literals 8562 isIn = function( f, t ) { 8563 // does the format contain the token? 8564 return f.indexOf( t ) !== -1 ? true : false; 8565 }; 8566 return { 8567 hour: isIn( tf, 'h' ), 8568 minute: isIn( tf, 'm' ), 8569 second: isIn( tf, 's' ), 8570 millisec: isIn( tf, 'l' ), 8571 microsec: isIn( tf, 'c' ), 8572 timezone: isIn( tf, 'z' ), 8573 ampm: isIn( tf, 't' ) && isIn( timeFormat, 'h' ), 8574 iso8601: isIn( timeFormat, 'Z' ) 8575 }; 8576 }; 8577 8578 /* 8579 * Converts 24 hour format into 12 hour 8580 * Returns 12 hour without leading 0 8581 */ 8582 var convert24to12 = function( hour ) { 8583 hour %= 12; 8584 8585 if ( hour === 0 ) { 8586 hour = 12; 8587 } 8588 8589 return String( hour ); 8590 }; 8591 8592 var computeEffectiveSetting = function( settings, property ) { 8593 return settings && settings[ property ] ? settings[ property ] : $.tm_timepicker._defaults[ property ]; 8594 }; 8595 8596 /* 8597 * Splits datetime string into date and time substrings. 8598 * Throws exception when date can't be parsed
8599 * Returns {dateString: dateString, timeString: timeString} 8600 */ 8601 var splitDateTime = function( dateTimeString, timeSettings ) { 8602 // The idea is to get the number separator occurrences in datetime and the time format requested (since time has 8603 // fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split. 8604 var separator = computeEffectiveSetting( timeSettings, 'separator' ), 8605 format = computeEffectiveSetting( timeSettings, 'timeFormat' ), 8606 timeParts = format.split( separator ), // how many occurrences of separator may be in our format? 8607 timePartsLen = timeParts.length, 8608 allParts = dateTimeString.split( separator ), 8609 allPartsLen = allParts.length; 8610 8611 if ( allPartsLen > 1 ) { 8612 return { 8613 dateString: allParts.splice( 0, allPartsLen - timePartsLen ).join( separator ), 8614 timeString: allParts.splice( 0, timePartsLen ).join( separator ) 8615 }; 8616 } 8617 8618 return { 8619 dateString: dateTimeString, 8620 timeString: '' 8621 }; 8622 }; 8623 8624 /* 8625 * Internal function to parse datetime interval 8626 * Returns: {date: Date, timeObj: Object}, where 8627 * date - parsed date without time (type Date) 8628 * timeObj = {hour: , minute: , second: , millisec: , microsec: } - parsed time. Optional 8629 */ 8630 var parseDateTimeInternal = function( dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings ) { 8631 var date, parts, parsedTime; 8632 8633 parts = splitDateTime( dateTimeString, timeSettings ); 8634 date = $.tm_datepicker._base_parseDate( dateFormat, parts.dateString, dateSettings ); 8635 8636 if ( parts.timeString === '' ) { 8637 return { 8638 date: date 8639 }; 8640 } 8641 8642 parsedTime = $.tm_datepicker.parseTime( timeFormat, parts.timeString, timeSettings ); 8643 8644 if ( ! parsedTime ) { 8645 throw 'Wrong time format'; 8646 } 8647 8648 return { 8649 date: date, 8650 timeObj: parsedTime 8651 }; 8652 }; 8653 8654 /* 8655 * Internal function to set timezone_select to the local timezone 8656 */ 8657 var selectLocalTimezone = function( tp_inst, date ) { 8658 var now; 8659 if ( tp_inst && tp_inst.timezone_select ) { 8660 now = date || new Date(); 8661 tp_inst.timezone_select.val( -now.getTimezoneOffset() ); 8662 } 8663 }; 8664 8665 /* 8666 * Timepicker manager. 8667 * Use the singleton instance of this class, $.tm_timepicker, to interact with the time picker. 8668 * Settings for (groups of) time pickers are maintained in an instance object, 8669 * allowing multiple different settings on the same page. 8670 */ 8671 var Timepicker = function() { 8672 this.regional = []; // Available regional settings, indexed by language code 8673 this.regional[ '' ] = { 8674 // Default regional settings 8675 currentText: 'Now', 8676 closeText: 'Done', 8677 amNames: [ 'AM', 'A' ], 8678 pmNames: [ 'PM', 'P' ], 8679 timeFormat: 'HH:mm', 8680 timeSuffix: '', 8681 timeOnlyTitle: 'Choose Time', 8682 timeText: 'Time', 8683 hourText: 'Hour', 8684 minuteText: 'Minute', 8685 secondText: 'Second', 8686 millisecText: 'Millisecond', 8687 microsecText: 'Microsecond', 8688 timezoneText: 'Time Zone', 8689 isRTL: false 8690 }; 8691 this._defaults = { 8692 // Global defaults for all the datetime picker instances 8693 showButtonPanel: true, 8694 timeOnly: false, 8695 timeOnlyShowDate: false, 8696 showHour: null, 8697 showMinute: null, 8698 showSecond: null, 8699 showMillisec: null, 8700 showMicrosec: null, 8701 showTimezone: null, 8702 showTime: true, 8703 stepHour: 1, 8704 stepMinute: 1, 8705 stepSecond: 1, 8706 stepMillisec: 1, 8707 stepMicrosec: 1, 8708 hour: 0, 8709 minute: 0, 8710 second: 0, 8711 millisec: 0, 8712 microsec: 0, 8713 timezone: null, 8714 hourMin: 0, 8715 minuteMin: 0, 8716 secondMin: 0, 8717 millisecMin: 0, 8718 microsecMin: 0, 8719 hourMax: 23, 8720 minuteMax: 59, 8721 secondMax: 59, 8722 millisecMax: 999, 8723 microsecMax: 999, 8724 minDateTime: null, 8725 maxDateTime: null, 8726 maxTime: null, 8727 minTime: null, 8728 onSelect: null, 8729 hourGrid: 0, 8730 minuteGrid: 0, 8731 secondGrid: 0, 8732 millisecGrid: 0, 8733 microsecGrid: 0, 8734 alwaysSetTime: true, 8735 separator: ' ', 8736 altFieldTimeOnly: true, 8737 altTimeFormat: null, 8738 altSeparator: null, 8739 altTimeSuffix: null, 8740 altRedirectFocus: true, 8741 pickerTimeFormat: null, 8742 pickerTimeSuffix: null, 8743 showTimepicker: true, 8744 timezoneList: null, 8745 addSliderAccess: false, 8746 sliderAccessArgs: null, 8747 controlType: 'slider', 8748 oneLine: false, 8749 defaultValue: null, 8750 parse: 'strict', 8751 afterInject: null 8752 }; 8753 $.extend( this._defaults, this.regional[ '' ] ); 8754 }; 8755 8756 /* 8757 * Lets not redefine tm_timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded" 8758 */ 8759 $.ui.tm_timepicker = $.ui.tm_timepicker || {}; 8760 if ( $.ui.tm_timepicker.version ) { 8761 return; 8762 } 8763 8764 /* 8765 * Extend jQueryUI, get it started with our version number 8766 */ 8767 $.extend( $.ui, { 8768 tm_timepicker: { 8769 version: '1.6.3' 8770 } 8771 } ); 8772 8773 $.extend( Timepicker.prototype, { 8774 $input: null, 8775 $altInput: null, 8776 $timeObj: null, 8777 inst: null, 8778 hour_slider: null, 8779 minute_slider: null, 8780 second_slider: null, 8781 millisec_slider: null, 8782 microsec_slider: null, 8783 timezone_select: null, 8784 maxTime: null, 8785 minTime: null, 8786 hour: 0, 8787 minute: 0, 8788 second: 0, 8789 millisec: 0, 8790 microsec: 0, 8791 timezone: null,
8792 hourMinOriginal: null, 8793 minuteMinOriginal: null, 8794 secondMinOriginal: null, 8795 millisecMinOriginal: null, 8796 microsecMinOriginal: null, 8797 hourMaxOriginal: null, 8798 minuteMaxOriginal: null, 8799 secondMaxOriginal: null, 8800 millisecMaxOriginal: null, 8801 microsecMaxOriginal: null, 8802 ampm: '', 8803 formattedDate: '', 8804 formattedTime: '', 8805 formattedDateTime: '', 8806 timezoneList: null, 8807 units: [ 'hour', 'minute', 'second', 'millisec', 'microsec' ], 8808 support: {}, 8809 control: null, 8810 8811 /* 8812 * Override the default settings for all instances of the time picker. 8813 * @param {Object} settings object - the new settings to use as defaults (anonymous object) 8814 * @return {Object} the manager object 8815 */ 8816 setDefaults: function( settings ) { 8817 extendRemove( this._defaults, settings || {} ); 8818 return this; 8819 }, 8820 8821 /* 8822 * Create a new Timepicker instance 8823 */ 8824 _newInst: function( $input, opts ) { 8825 var tp_inst = new Timepicker(), 8826 inlineSettings = {}, 8827 fns = {}, 8828 overrides, 8829 i; 8830 var attrName; 8831 var attrValue; 8832 var timezoneList; 8833 var tzl; 8834 var tzi = 0; 8835 var tzv = null; 8836 8837 for ( attrName in this._defaults ) { 8838 if ( Object.prototype.hasOwnProperty.call( this._defaults, attrName ) ) { 8839 attrValue = $input.attr( 'data-' + attrName ); 8840 if ( attrValue ) { 8841 inlineSettings[ attrName ] = attrValue; 8842 } 8843 } 8844 } 8845 8846 overrides = { 8847 beforeShow: function( input, dp_inst ) { 8848 if ( typeof tp_inst._defaults.evnts.beforeShow === 'function' ) { 8849 return tp_inst._defaults.evnts.beforeShow.call( $input[ 0 ], input, dp_inst, tp_inst ); 8850 } 8851 }, 8852 onChangeMonthYear: function( year, month, dp_inst ) { 8853 // Update the time as well : this prevents the time from disappearing from the $input field. 8854 // tp_inst._updateDateTime(dp_inst); 8855 if ( typeof tp_inst._defaults.evnts.onChangeMonthYear === 'function' ) { 8856 tp_inst._defaults.evnts.onChangeMonthYear.call( $input[ 0 ], year, month, dp_inst, tp_inst ); 8857 } 8858 }, 8859 onClose: function( dateText, dp_inst ) { 8860 if ( tp_inst.timeDefined === true && $input.val() !== '' ) { 8861 tp_inst._updateDateTime( dp_inst ); 8862 } 8863 if ( typeof tp_inst._defaults.evnts.onClose === 'function' ) { 8864 tp_inst._defaults.evnts.onClose.call( $input[ 0 ], dateText, dp_inst, tp_inst ); 8865 } 8866 } 8867 }; 8868 for ( i in overrides ) { 8869 if ( Object.prototype.hasOwnProperty.call( overrides, i ) ) { 8870 fns[ i ] = opts[ i ] || this._defaults[ i ] || null; 8871 } 8872 } 8873 8874 tp_inst._defaults = $.extend( {}, this._defaults, inlineSettings, opts, overrides, { 8875 evnts: fns, 8876 tm_timepicker: tp_inst // add tm_timepicker as a property of tm_datepicker: $.tm_datepicker._get(dp_inst, 'tm_timepicker'); 8877 } ); 8878 tp_inst.amNames = $.map( tp_inst._defaults.amNames, function( val ) { 8879 return val.toUpperCase(); 8880 } ); 8881 tp_inst.pmNames = $.map( tp_inst._defaults.pmNames, function( val ) { 8882 return val.toUpperCase(); 8883 } ); 8884 8885 // detect which units are supported 8886 tp_inst.support = detectSupport( tp_inst._defaults.timeFormat + ( tp_inst._defaults.pickerTimeFormat ? tp_inst._defaults.pickerTimeFormat : '' ) + ( tp_inst._defaults.altTimeFormat ? tp_inst._defaults.altTimeFormat : '' ) ); 8887 8888 // controlType is string - key to our this._controls 8889 if ( typeof tp_inst._defaults.controlType === 'string' ) { 8890 if ( tp_inst._defaults.controlType === 'slider' && typeof $.ui.slider === 'undefined' ) { 8891 tp_inst._defaults.controlType = 'select'; 8892 } 8893 tp_inst.control = tp_inst._controls[ tp_inst._defaults.controlType ]; 8894 } else { 8895 // controlType is an object and must implement create, options, value methods 8896 tp_inst.control = tp_inst._defaults.controlType; 8897 } 8898 8899 // prep the timezone options 8900 timezoneList = [ -720, -660, -600, -570, -540, -480, -420, -360, -300, -270, -240, -210, -180, -120, -60, 0, 60, 120, 180, 210, 240, 270, 300, 330, 345, 360, 390, 420, 480, 525, 540, 570, 600, 630, 660, 690, 720, 765, 780, 840 ]; 8901 if ( tp_inst._defaults.timezoneList !== null ) { 8902 timezoneList = tp_inst._defaults.timezoneList; 8903 } 8904 tzl = timezoneList.length; 8905 8906 if ( tzl > 0 && typeof timezoneList[ 0 ] !== 'object' ) { 8907 for ( ; tzi < tzl; tzi += 1 ) { 8908 tzv = timezoneList[ tzi ]; 8909 timezoneList[ tzi ] = { 8910 value: tzv, 8911 label: $.tm_timepicker.timezoneOffsetString( tzv, tp_inst.support.iso8601 ) 8912 }; 8913 } 8914 } 8915 tp_inst._defaults.timezoneList = timezoneList; 8916 8917 // set the default units 8918 tp_inst.timezone = tp_inst._defaults.timezone !== null ? $.tm_timepicker.timezoneOffsetNumber( tp_inst._defaults.timezone ) : new Date().getTimezoneOffset() * -1; 8919 tp_inst.hour = tp_inst._defaults.hour < tp_inst._defaults.hourMin ? tp_inst._defaults.hourMin : tp_inst._defaults.hour > tp_inst._defaults.hourMax ? tp_inst._defaults.hourMax : tp_inst._defaults.hour; 8920 tp_inst.minute = tp_inst._defaults.minute < tp_inst._defaults.minuteMin ? tp_inst._defaults.minuteMin : tp_inst._defaults.minute > tp_inst._defaults.minuteMax ? tp_inst._defaults.minuteMax : tp_inst._defaults.minute; 8921 tp_inst.second = tp_inst._defaults.second < tp_inst._defaults.secondMin ? tp_inst._defaults.secondMin : tp_inst._defaults.second > tp_inst._defaults.secondMax ? tp_inst._defaults.secondMax : tp_inst._defaults.second; 8922 tp_inst.millisec = 8923 tp_inst._defaults.millisec < tp_inst._defaults.millisecMin ? tp_inst._defaults.millisecMin : tp_inst._defaults.millisec > tp_inst._defaults.millisecMax ? tp_inst._defaults.millisecMax : tp_inst._defaults.millisec; 8924 tp_inst.microsec =
8925 tp_inst._defaults.microsec < tp_inst._defaults.microsecMin ? tp_inst._defaults.microsecMin : tp_inst._defaults.microsec > tp_inst._defaults.microsecMax ? tp_inst._defaults.microsecMax : tp_inst._defaults.microsec; 8926 tp_inst.ampm = ''; 8927 tp_inst.$input = $input; 8928 8929 if ( tp_inst._defaults.altField ) { 8930 tp_inst.$altInput = $( tp_inst._defaults.altField ); 8931 if ( tp_inst._defaults.altRedirectFocus === true ) { 8932 tp_inst.$altInput 8933 .css( { 8934 cursor: 'pointer' 8935 } ) 8936 .on( 'focus', function() { 8937 $input.trigger( 'focus' ); 8938 } ); 8939 } 8940 } 8941 8942 if ( tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0 ) { 8943 tp_inst._defaults.minDate = new Date(); 8944 } 8945 if ( tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0 ) { 8946 tp_inst._defaults.maxDate = new Date(); 8947 } 8948 8949 // tm_datepicker needs minDate/maxDate, tm_timepicker needs minDateTime/maxDateTime.. 8950 if ( tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date ) { 8951 tp_inst._defaults.minDateTime = new Date( tp_inst._defaults.minDate.getTime() ); 8952 } 8953 if ( tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date ) { 8954 tp_inst._defaults.minDate = new Date( tp_inst._defaults.minDateTime.getTime() ); 8955 } 8956 if ( tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date ) { 8957 tp_inst._defaults.maxDateTime = new Date( tp_inst._defaults.maxDate.getTime() ); 8958 } 8959 if ( tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date ) { 8960 tp_inst._defaults.maxDate = new Date( tp_inst._defaults.maxDateTime.getTime() ); 8961 } 8962 tp_inst.$input.on( 'focus', function() { 8963 tp_inst._onFocus(); 8964 } ); 8965 8966 tp_inst.$input.next( '.ui-tm-timepicker-trigger' ).on( 'click', function() { 8967 tp_inst._onFocus(); 8968 /*if ( $.tm_datepicker._datepickerShowing && $.tm_datepicker._lastInput === input[ 0 ] ) { 8969 $.tm_datepicker._hideDatepicker(); 8970 } else if ( $.tm_datepicker._datepickerShowing && $.tm_datepicker._lastInput !== input[ 0 ] ) { 8971 $.tm_datepicker._hideDatepicker(); 8972 $.tm_datepicker._showDatepicker( input[ 0 ] ); 8973 } else { 8974 $.tm_datepicker._showDatepicker( input[ 0 ] ); 8975 }*/ 8976 return false; 8977 } ); 8978 8979 return tp_inst; 8980 }, 8981 8982 /* 8983 * add our sliders to the calendar 8984 */ 8985 _addTimePicker: function( dp_inst ) { 8986 var currDT = $.epoAPI.util.trim( this.$altInput && this._defaults.altFieldTimeOnly ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val() ); 8987 8988 this.timeDefined = this._parseTime( currDT ); 8989 this._limitMinMaxDateTime( dp_inst, false ); 8990 this._injectTimePicker(); 8991 this._afterInject(); 8992 }, 8993 8994 /* 8995 * parse the time string from input value or _setTime 8996 */ 8997 _parseTime: function( timeString, withDate ) { 8998 var dp_dateFormat; 8999 var parseRes; 9000 var timeObj; 9001 9002 if ( ! this.inst ) { 9003 this.inst = $.tm_datepicker._getInst( this.$input[ 0 ] ); 9004 } 9005 9006 if ( withDate || ! this._defaults.timeOnly ) { 9007 dp_dateFormat = $.tm_datepicker._get( this.inst, 'dateFormat' ); 9008 try { 9009 parseRes = parseDateTimeInternal( dp_dateFormat, this._defaults.timeFormat, timeString, $.tm_datepicker._getFormatConfig( this.inst ), this._defaults ); 9010 if ( ! parseRes.timeObj ) { 9011 return false; 9012 } 9013 $.extend( this, parseRes.timeObj ); 9014 } catch ( err ) { 9015 $.tm_timepicker.log( 'Error parsing the date/time string: ' + err + '\ndate/time string = ' + timeString + '\ntimeFormat = ' + this._defaults.timeFormat + '\ndateFormat = ' + dp_dateFormat ); 9016 return false; 9017 } 9018 return true; 9019 } 9020 timeObj = $.tm_datepicker.parseTime( this._defaults.timeFormat, timeString, this._defaults ); 9021 if ( ! timeObj ) { 9022 return false; 9023 } 9024 $.extend( this, timeObj ); 9025 return true; 9026 }, 9027 9028 /* 9029 * Handle callback option after injecting tm_timepicker 9030 */ 9031 _afterInject: function() { 9032 var o = this.inst.settings; 9033 if ( typeof o.afterInject === 'function' ) { 9034 o.afterInject.call( this ); 9035 } 9036 }, 9037 9038 _ui_tpicker_onclick: function( event ) { 9039 var $t = $( event.target ), 9040 h = $t.html(), 9041 n = parseInt( h.replace( /[^0-9]/g ), 10 ), 9042 ap = h.replace( /[^apm]/gi ), 9043 f = $t.data( 'for' ); // loses scope, so we use data-for 9044 9045 if ( f === 'hour' ) { 9046 if ( ap.indexOf( 'p' ) !== -1 && n < 12 ) { 9047 n += 12; 9048 } else if ( ap.indexOf( 'a' ) !== -1 && n === 12 ) { 9049 n = 0; 9050 } 9051 } 9052 9053 event.data.tp_inst.control.value( event.data.tp_inst, event.data.tp_inst[ f + '_slider' ], event.data.litem, n ); 9054 9055 event.data.tp_inst._onTimeChange(); 9056 event.data.tp_inst._onSelectHandler(); 9057 }, 9058 /* 9059 * generate and inject html for tm_timepicker into ui tm_datepicker 9060 */ 9061 _injectTimePicker: function() { 9062 var $dp = this.inst.dpDiv, 9063 o = this.inst.settings, 9064 tp_inst = this, 9065 litem = '', 9066 uitem = '', 9067 show = null, 9068 max = {}, 9069 gridSize = {}, 9070 size = null, 9071 i = 0, 9072 l = 0; 9073 var noDisplay; 9074 var html; 9075 var h; 9076 var tmph; 9077 var m; 9078 var showTz; 9079 var $tp; 9080 var local_timezone; 9081 var $buttonPanel; 9082 var timeDefined; 9083 var sliderAccessArgs; 9084 var rtl; 9085 9086 // Prevent displaying twice 9087 if ( $dp.find( 'div.ui-tm-timepicker-div' ).length === 0 && o.showTimepicker ) { 9088 noDisplay = ' ui_tpicker_unit_hide'; 9089 html = 9090 '<div class="ui-tm-timepicker-div' + 9091 ( o.isRTL ? ' ui-tm-timepicker-rtl' : '' ) + 9092 ( o.oneLine && o.controlType === 'select' ? ' ui-tm-timepicker-oneLine' : '' ) + 9093 '"><dl>' + 9094 '<dt class="ui_tpicker_time_label' + 9095 ( o.showTime ? '' : noDisplay ) + 9096 '">' + 9097 o.timeText + 9098 '</dt>' + 9099 '<dd class="ui_tpicker_time ' + 9100 ( o.showTime ? '' : noDisplay ) + 9101 '"><input class="ui_tpicker_time_input" ' + 9102 ( o.timeInput ? '' : 'disabled' ) + 9103 '></dd>'; 9104 9105 // Create the markup 9106 for ( i = 0, l = this.units.length; i < l; i += 1 ) { 9107 litem = this.units[ i ]; 9108 uitem = litem.substring( 0, 1 ).toUpperCase() + litem.substring( 1 ); 9109 show = o[ 'show' + uitem ] !== null ? o[ 'show' + uitem ] : this.support[ litem ]; 9110 9111 // Added by Peter Medeiros: 9112 // - Figure out what the hour/minute/second max should be based on the step values. 9113 // - Example: if stepMinute is 15, then minMax is 45. 9114 max[ litem ] = parseInt( o[ litem + 'Max' ] - ( ( o[ litem + 'Max' ] - o[ litem + 'Min' ] ) % o[ 'step' + uitem ] ), 10 ); 9115 gridSize[ litem ] = 0; 9116 9117 html += 9118 '<dt class="ui_tpicker_' + 9119 litem + 9120 '_label' + 9121 ( show ? '' : noDisplay ) + 9122 '">' + 9123 o[ litem + 'Text' ] + 9124 '</dt>' + 9125 '<dd class="ui_tpicker_' + 9126 litem + 9127 ( show ? '' : noDisplay ) + 9128 '"><div class="ui_tpicker_' + 9129 litem + 9130 '_slider' + 9131 ( show ? '' : noDisplay ) + 9132 '"></div>'; 9133 9134 if ( show && o[ litem + 'Grid' ] > 0 ) { 9135 html += '<div><table class="ui-tpicker-grid-label"><tr>'; 9136 9137 if ( litem === 'hour' ) { 9138 for ( h = o[ litem + 'Min' ]; h <= max[ litem ]; h += parseInt( o[ litem + 'Grid' ], 10 ) ) { 9139 gridSize[ litem ] += 1; 9140 tmph = $.tm_datepicker.formatTime( this.support.ampm ? 'hht' : 'HH', { hour: h }, o ); 9141 html += '<td data-for="' + litem + '">' + tmph + '</td>'; 9142 } 9143 } else { 9144 for ( m = o[ litem + 'Min' ]; m <= max[ litem ]; m += parseInt( o[ litem + 'Grid' ], 10 ) ) { 9145 gridSize[ litem ] += 1; 9146 html += '<td data-for="' + litem + '">' + ( m < 10 ? '0' : '' ) + m + '</td>'; 9147 } 9148 } 9149 9150 html += '</tr></table></div>'; 9151 } 9152 html += '</dd>'; 9153 } 9154 9155 // Timezone 9156 showTz = o.showTimezone !== null ? o.showTimezone : this.support.timezone; 9157 html += '<dt class="ui_tpicker_timezone_label' + ( showTz ? '' : noDisplay ) + '">' + o.timezoneText + '</dt>'; 9158 html += '<dd class="ui_tpicker_timezone' + ( showTz ? '' : noDisplay ) + '"></dd>'; 9159 9160 // Create the elements from string 9161 html += '</dl></div>'; 9162 $tp = $( html ); 9163 9164 // if we only want time picker... 9165 if ( o.timeOnly === true ) { 9166 $tp.prepend( '<div class="tm-ui-widget-header">' + '<div class="tm-ui-tp-title">' + o.timeOnlyTitle + '</div>' + '</div>' ); 9167 $dp.find( '.tm-ui-dp-inner-container' ).hide(); 9168 } 9169 9170 // add sliders, adjust grids, add events 9171 for ( i = 0, l = tp_inst.units.length; i < l; i += 1 ) { 9172 litem = tp_inst.units[ i ]; 9173 uitem = litem.substring( 0, 1 ).toUpperCase() + litem.substring( 1 ); 9174 show = o[ 'show' + uitem ] !== null ? o[ 'show' + uitem ] : this.support[ litem ]; 9175 9176 // add the slider 9177 tp_inst[ litem + '_slider' ] = tp_inst.control.create( tp_inst, $tp.find( '.ui_tpicker_' + litem + '_slider' ), litem, tp_inst[ litem ], o[ litem + 'Min' ], max[ litem ], o[ 'step' + uitem ] ); 9178 9179 // adjust the grid and add click event 9180 if ( show && o[ litem + 'Grid' ] > 0 ) { 9181 size = ( 100 * gridSize[ litem ] * o[ litem + 'Grid' ] ) / ( max[ litem ] - o[ litem + 'Min' ] ); 9182 $tp.find( '.ui_tpicker_' + litem + ' table' ) 9183 .css( { 9184 width: size + '%', 9185 marginLeft: o.isRTL ? '0' : ( size / ( -2 * gridSize[ litem ] ) ) + '%', 9186 marginRight: o.isRTL ? ( size / ( -2 * gridSize[ litem ] ) ) + '%' : '0', 9187 borderCollapse: 'collapse' 9188 } ) 9189 .find( 'td' ) 9190 .on( 'click', { that: this, tp_inst: tp_inst, litem: litem }, this._ui_tpicker_onclick ) 9191 .css( { 9192 cursor: 'pointer', 9193 width: ( 100 / gridSize[ litem ] ) + '%', 9194 textAlign: 'center', 9195 overflow: 'hidden' 9196 } ); 9197 } // end if grid > 0 9198 } // end for loop 9199 9200 // Add timezone options 9201 this.timezone_select = $tp.find( '.ui_tpicker_timezone' ).append( '<select></select>' ).find( 'select' ); 9202 $.fn.append.apply( 9203 this.timezone_select, 9204 $.map( o.timezoneList, function( val ) { 9205 return $( '<option />' ) 9206 .val( typeof val === 'object' ? val.value : val ) 9207 .text( typeof val === 'object' ? val.label : val ); 9208 } ) 9209 ); 9210 if ( typeof this.timezone !== 'undefined' && this.timezone !== null && this.timezone !== '' ) { 9211 local_timezone = new Date( this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12 ).getTimezoneOffset() * -1; 9212 if ( local_timezone === this.timezone ) { 9213 selectLocalTimezone( tp_inst ); 9214 } else { 9215 this.timezone_select.val( this.timezone ); 9216 } 9217 } else if ( typeof this.hour !== 'undefined' && this.hour !== null && this.hour !== '' ) { 9218 this.timezone_select.val( o.timezone ); 9219 } else { 9220 selectLocalTimezone( tp_inst ); 9221 } 9222 this.timezone_select.on( 'change', function() { 9223 tp_inst._onTimeChange(); 9224 tp_inst._onSelectHandler(); 9225 tp_inst._afterInject(); 9226 } ); 9227 // End timezone options 9228 9229 // inject tm_timepicker into tm_datepicker 9230 $buttonPanel = $dp.find( '.tm-ui-dp-buttonpane' ); 9231 if ( $buttonPanel.length ) { 9232 $buttonPanel.before( $tp ); 9233 } else { 9234 $dp.append( $tp ); 9235 } 9236 9237 this.$timeObj = $tp.find( '.ui_tpicker_time_input' ); 9238 this.$timeObj.on( 'change', function() { 9239 var timeFormat = tp_inst.inst.settings.timeFormat; 9240 var parsedTime = $.tm_datepicker.parseTime( timeFormat, this.value ); 9241 var update = new Date(); 9242 if ( parsedTime ) { 9243 update.setHours( parsedTime.hour ); 9244 update.setMinutes( parsedTime.minute ); 9245 update.setSeconds( parsedTime.second ); 9246 $.datepicker._setTime( tp_inst.inst, update ); 9247 } else { 9248 this.value = tp_inst.formattedTime; 9249 this.trigger( 'blur' ); 9250 } 9251 } ); 9252 9253 if ( this.inst !== null ) { 9254 timeDefined = this.timeDefined; 9255 this._onTimeChange(); 9256 this.timeDefined = timeDefined; 9257 } 9258 9259 // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/ 9260 if ( this._defaults.addSliderAccess ) { 9261 sliderAccessArgs = this._defaults.sliderAccessArgs; 9262 rtl = this._defaults.isRTL; 9263 sliderAccessArgs.isRTL = rtl; 9264 9265 setTimeout( function() { 9266 // fix for inline mode 9267 var sliderAccessWidth; 9268 if ( $tp.find( '.ui-slider-access' ).length === 0 ) { 9269 $tp.find( '.ui-slider:visible' ).sliderAccess( sliderAccessArgs ); 9270 9271 // fix any grids since sliders are shorter 9272 sliderAccessWidth = $tp.find( '.ui-slider-access:eq(0)' ).outerWidth( true ); 9273 if ( sliderAccessWidth ) { 9274 $tp.find( 'table:visible' ).each( function() { 9275 var $g = $( this ), 9276 oldWidth = $g.outerWidth(), 9277 oldMarginLeft = $g 9278 .css( rtl ? 'marginRight' : 'marginLeft' ) 9279 .toString() 9280 .replace( '%', '' ), 9281 newWidth = oldWidth - sliderAccessWidth, 9282 newMarginLeft = ( ( oldMarginLeft * newWidth ) / oldWidth ) + '%', 9283 css = { width: newWidth, marginRight: 0, marginLeft: 0 }; 9284 css[ rtl ? 'marginRight' : 'marginLeft' ] = newMarginLeft; 9285 $g.css( css ); 9286 } ); 9287 } 9288 } 9289 }, 10 ); 9290 } 9291 // end slideAccess integration 9292 9293 tp_inst._limitMinMaxDateTime( this.inst, true ); 9294 } 9295 }, 9296 9297 /* 9298 * This function tries to limit the ability to go outside the 9299 * min/max date range 9300 */ 9301 _limitMinMaxDateTime: function( dp_inst, adjustSliders ) { 9302 var o = this._defaults, 9303 dp_date = new Date( dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay ); 9304 var minDateTime; 9305 var minDateTimeDate; 9306 var maxDateTime; 9307 var maxDateTimeDate; 9308 var tempMinTime; 9309 var tempMaxTime; 9310 var hourMax; 9311 var minMax; 9312 var secMax; 9313 var millisecMax;
vendor: 4,262 bytes, lines 9314-9400
9314 var microsecMax; 9315 9316 if ( ! this._defaults.showTimepicker ) { 9317 return; 9318 } // No time so nothing to check here 9319 9320 if ( $.tm_datepicker._get( dp_inst, 'minDateTime' ) !== null && $.tm_datepicker._get( dp_inst, 'minDateTime' ) !== undefined && dp_date ) { 9321 minDateTime = $.tm_datepicker._get( dp_inst, 'minDateTime' ); 9322 minDateTimeDate = new Date( minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0 ); 9323 9324 if ( this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null || this.microsecMinOriginal === null ) { 9325 this.hourMinOriginal = o.hourMin; 9326 this.minuteMinOriginal = o.minuteMin; 9327 this.secondMinOriginal = o.secondMin; 9328 this.millisecMinOriginal = o.millisecMin; 9329 this.microsecMinOriginal = o.microsecMin; 9330 } 9331 9332 if ( dp_inst.settings.timeOnly || minDateTimeDate.getTime() === dp_date.getTime() ) { 9333 this._defaults.hourMin = minDateTime.getHours(); 9334 if ( this.hour <= this._defaults.hourMin ) { 9335 this.hour = this._defaults.hourMin; 9336 this._defaults.minuteMin = minDateTime.getMinutes(); 9337 if ( this.minute <= this._defaults.minuteMin ) { 9338 this.minute = this._defaults.minuteMin; 9339 this._defaults.secondMin = minDateTime.getSeconds(); 9340 if ( this.second <= this._defaults.secondMin ) { 9341 this.second = this._defaults.secondMin; 9342 this._defaults.millisecMin = minDateTime.getMilliseconds(); 9343 if ( this.millisec <= this._defaults.millisecMin ) { 9344 this.millisec = this._defaults.millisecMin; 9345 this._defaults.microsecMin = minDateTime.getMicroseconds(); 9346 } else { 9347 if ( this.microsec < this._defaults.microsecMin ) { 9348 this.microsec = this._defaults.microsecMin; 9349 } 9350 this._defaults.microsecMin = this.microsecMinOriginal; 9351 } 9352 } else { 9353 this._defaults.millisecMin = this.millisecMinOriginal; 9354 this._defaults.microsecMin = this.microsecMinOriginal; 9355 } 9356 } else { 9357 this._defaults.secondMin = this.secondMinOriginal; 9358 this._defaults.millisecMin = this.millisecMinOriginal; 9359 this._defaults.microsecMin = this.microsecMinOriginal; 9360 } 9361 } else { 9362 this._defaults.minuteMin = this.minuteMinOriginal; 9363 this._defaults.secondMin = this.secondMinOriginal; 9364 this._defaults.millisecMin = this.millisecMinOriginal; 9365 this._defaults.microsecMin = this.microsecMinOriginal; 9366 } 9367 } else { 9368 this._defaults.hourMin = this.hourMinOriginal; 9369 this._defaults.minuteMin = this.minuteMinOriginal; 9370 this._defaults.secondMin = this.secondMinOriginal; 9371 this._defaults.millisecMin = this.millisecMinOriginal; 9372 this._defaults.microsecMin = this.microsecMinOriginal; 9373 } 9374 } 9375 9376 if ( $.tm_datepicker._get( dp_inst, 'maxDateTime' ) !== null && $.tm_datepicker._get( dp_inst, 'maxDateTime' ) !== undefined && dp_date ) { 9377 maxDateTime = $.tm_datepicker._get( dp_inst, 'maxDateTime' ); 9378 maxDateTimeDate = new Date( maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0 ); 9379 9380 if ( this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null || this.millisecMaxOriginal === null ) { 9381 this.hourMaxOriginal = o.hourMax; 9382 this.minuteMaxOriginal = o.minuteMax; 9383 this.secondMaxOriginal = o.secondMax; 9384 this.millisecMaxOriginal = o.millisecMax; 9385 this.microsecMaxOriginal = o.microsecMax; 9386 } 9387 9388 if ( dp_inst.settings.timeOnly || maxDateTimeDate.getTime() === dp_date.getTime() ) { 9389 this._defaults.hourMax = maxDateTime.getHours(); 9390 if ( this.hour >= this._defaults.hourMax ) { 9391 this.hour = this._defaults.hourMax; 9392 this._defaults.minuteMax = maxDateTime.getMinutes(); 9393 if ( this.minute >= this._defaults.minuteMax ) { 9394 this.minute = this._defaults.minuteMax; 9395 this._defaults.secondMax = maxDateTime.getSeconds(); 9396 if ( this.second >= this._defaults.secondMax ) { 9397 this.second = this._defaults.secondMax; 9398 this._defaults.millisecMax = maxDateTime.getMilliseconds(); 9399 if ( this.millisec >= this._defaults.millisecMax ) { 9400 this.millisec = this._defaults.millisecMax;
9401 this._defaults.microsecMax = maxDateTime.getMicroseconds(); 9402 } else { 9403 if ( this.microsec > this._defaults.microsecMax ) { 9404 this.microsec = this._defaults.microsecMax; 9405 } 9406 this._defaults.microsecMax = this.microsecMaxOriginal; 9407 } 9408 } else { 9409 this._defaults.millisecMax = this.millisecMaxOriginal; 9410 this._defaults.microsecMax = this.microsecMaxOriginal; 9411 } 9412 } else { 9413 this._defaults.secondMax = this.secondMaxOriginal; 9414 this._defaults.millisecMax = this.millisecMaxOriginal; 9415 this._defaults.microsecMax = this.microsecMaxOriginal; 9416 } 9417 } else { 9418 this._defaults.minuteMax = this.minuteMaxOriginal; 9419 this._defaults.secondMax = this.secondMaxOriginal; 9420 this._defaults.millisecMax = this.millisecMaxOriginal; 9421 this._defaults.microsecMax = this.microsecMaxOriginal; 9422 } 9423 } else { 9424 this._defaults.hourMax = this.hourMaxOriginal; 9425 this._defaults.minuteMax = this.minuteMaxOriginal; 9426 this._defaults.secondMax = this.secondMaxOriginal; 9427 this._defaults.millisecMax = this.millisecMaxOriginal; 9428 this._defaults.microsecMax = this.microsecMaxOriginal; 9429 } 9430 } 9431 9432 if ( dp_inst.settings.minTime !== null ) { 9433 tempMinTime = new Date( '01/01/1970 ' + dp_inst.settings.minTime ); 9434 if ( parseFloat( dp_inst.settings.minTime ).toString() === dp_inst.settings.minTime ) { 9435 tempMinTime = new Date( Date.now() + parseFloat( dp_inst.settings.minTime ) ); 9436 } 9437 if ( this.hour < tempMinTime.getHours() ) { 9438 this._defaults.hourMin = tempMinTime.getHours(); 9439 this.hour = this._defaults.hourMin; 9440 this._defaults.minuteMin = tempMinTime.getMinutes(); 9441 this.minute = this._defaults.minuteMin; 9442 } else if ( this.hour === tempMinTime.getHours() && this.minute < tempMinTime.getMinutes() ) { 9443 this._defaults.minuteMin = tempMinTime.getMinutes(); 9444 this.minute = this._defaults.minuteMin; 9445 } else if ( this._defaults.hourMin < tempMinTime.getHours() ) { 9446 this._defaults.hourMin = tempMinTime.getHours(); 9447 this._defaults.minuteMin = tempMinTime.getMinutes(); 9448 } else if ( ( this._defaults.hourMin === tempMinTime.getHours() ) === this.hour && this._defaults.minuteMin < tempMinTime.getMinutes() ) { 9449 this._defaults.minuteMin = tempMinTime.getMinutes(); 9450 } else { 9451 this._defaults.minuteMin = 0; 9452 } 9453 } 9454 9455 if ( dp_inst.settings.maxTime !== null ) { 9456 tempMaxTime = new Date( '01/01/1970 ' + dp_inst.settings.maxTime ); 9457 if ( this.hour > tempMaxTime.getHours() ) { 9458 this._defaults.hourMax = tempMaxTime.getHours(); 9459 this.hour = this._defaults.hourMax; 9460 this._defaults.minuteMax = tempMaxTime.getMinutes(); 9461 this.minute = this._defaults.minuteMax; 9462 } else if ( this.hour === tempMaxTime.getHours() && this.minute > tempMaxTime.getMinutes() ) { 9463 this._defaults.minuteMax = tempMaxTime.getMinutes(); 9464 this.minute = this._defaults.minuteMax; 9465 } else if ( this._defaults.hourMax > tempMaxTime.getHours() ) { 9466 this._defaults.hourMax = tempMaxTime.getHours(); 9467 this._defaults.minuteMax = tempMaxTime.getMinutes(); 9468 } else if ( ( this._defaults.hourMax === tempMaxTime.getHours() ) === this.hour && this._defaults.minuteMax > tempMaxTime.getMinutes() ) { 9469 this._defaults.minuteMax = tempMaxTime.getMinutes(); 9470 } else { 9471 this._defaults.minuteMax = 59; 9472 } 9473 } 9474 9475 if ( adjustSliders !== undefined && adjustSliders === true ) { 9476 hourMax = parseInt( this._defaults.hourMax - ( ( this._defaults.hourMax - this._defaults.hourMin ) % this._defaults.stepHour ), 10 ); 9477 minMax = parseInt( this._defaults.minuteMax - ( ( this._defaults.minuteMax - this._defaults.minuteMin ) % this._defaults.stepMinute ), 10 ); 9478 secMax = parseInt( this._defaults.secondMax - ( ( this._defaults.secondMax - this._defaults.secondMin ) % this._defaults.stepSecond ), 10 ); 9479 millisecMax = parseInt( this._defaults.millisecMax - ( ( this._defaults.millisecMax - this._defaults.millisecMin ) % this._defaults.stepMillisec ), 10 );
9480 microsecMax = parseInt( this._defaults.microsecMax - ( ( this._defaults.microsecMax - this._defaults.microsecMin ) % this._defaults.stepMicrosec ), 10 ); 9481 9482 if ( this.hour_slider ) { 9483 this.control.options( this, this.hour_slider, 'hour', { 9484 min: this._defaults.hourMin, 9485 max: hourMax, 9486 step: this._defaults.stepHour 9487 } ); 9488 this.control.value( this, this.hour_slider, 'hour', this.hour - ( this.hour % this._defaults.stepHour ) ); 9489 } 9490 if ( this.minute_slider ) { 9491 this.control.options( this, this.minute_slider, 'minute', { 9492 min: this._defaults.minuteMin, 9493 max: minMax, 9494 step: this._defaults.stepMinute 9495 } ); 9496 this.control.value( this, this.minute_slider, 'minute', this.minute - ( this.minute % this._defaults.stepMinute ) ); 9497 } 9498 if ( this.second_slider ) { 9499 this.control.options( this, this.second_slider, 'second', { 9500 min: this._defaults.secondMin, 9501 max: secMax, 9502 step: this._defaults.stepSecond 9503 } ); 9504 this.control.value( this, this.second_slider, 'second', this.second - ( this.second % this._defaults.stepSecond ) ); 9505 } 9506 if ( this.millisec_slider ) { 9507 this.control.options( this, this.millisec_slider, 'millisec', { 9508 min: this._defaults.millisecMin, 9509 max: millisecMax, 9510 step: this._defaults.stepMillisec 9511 } ); 9512 this.control.value( this, this.millisec_slider, 'millisec', this.millisec - ( this.millisec % this._defaults.stepMillisec ) ); 9513 } 9514 if ( this.microsec_slider ) { 9515 this.control.options( this, this.microsec_slider, 'microsec', { 9516 min: this._defaults.microsecMin, 9517 max: microsecMax, 9518 step: this._defaults.stepMicrosec 9519 } ); 9520 this.control.value( this, this.microsec_slider, 'microsec', this.microsec - ( this.microsec % this._defaults.stepMicrosec ) ); 9521 } 9522 } 9523 }, 9524 9525 /* 9526 * when a slider moves, set the internal time... 9527 * on time change is also called when the time is updated in the text field 9528 */ 9529 _onTimeChange: function() { 9530 var hour = this.hour_slider ? this.control.value( this, this.hour_slider, 'hour' ) : false, 9531 minute = this.minute_slider ? this.control.value( this, this.minute_slider, 'minute' ) : false, 9532 second = this.second_slider ? this.control.value( this, this.second_slider, 'second' ) : false, 9533 millisec = this.millisec_slider ? this.control.value( this, this.millisec_slider, 'millisec' ) : false, 9534 microsec = this.microsec_slider ? this.control.value( this, this.microsec_slider, 'microsec' ) : false, 9535 timezone = this.timezone_select ? this.timezone_select.val() : false, 9536 o = this._defaults, 9537 pickerTimeFormat = o.pickerTimeFormat || o.timeFormat, 9538 pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix; 9539 var ampm; 9540 var hasChanged; 9541 var sPos; 9542 var ePos; 9543 9544 if ( ! this._defaults.showTimepicker ) { 9545 return; 9546 } 9547 9548 if ( typeof hour === 'object' ) { 9549 hour = false;
vendor: 20,658 bytes, lines 9550-10227
9550 } 9551 if ( typeof minute === 'object' ) { 9552 minute = false; 9553 } 9554 if ( typeof second === 'object' ) { 9555 second = false; 9556 } 9557 if ( typeof millisec === 'object' ) { 9558 millisec = false; 9559 } 9560 if ( typeof microsec === 'object' ) { 9561 microsec = false; 9562 } 9563 if ( typeof timezone === 'object' ) { 9564 timezone = false; 9565 } 9566 9567 if ( hour !== false ) { 9568 hour = parseInt( hour, 10 ); 9569 } 9570 if ( minute !== false ) { 9571 minute = parseInt( minute, 10 ); 9572 } 9573 if ( second !== false ) { 9574 second = parseInt( second, 10 ); 9575 } 9576 if ( millisec !== false ) { 9577 millisec = parseInt( millisec, 10 ); 9578 } 9579 if ( microsec !== false ) { 9580 microsec = parseInt( microsec, 10 ); 9581 } 9582 if ( timezone !== false ) { 9583 timezone = timezone.toString(); 9584 } 9585 9586 ampm = o[ hour < 12 ? 'amNames' : 'pmNames' ][ 0 ]; 9587 9588 // If the update was done in the input field, the input field should not be updated. 9589 // If the update was done using the sliders, update the input field. 9590 hasChanged = 9591 hour !== parseInt( this.hour, 10 ) || // sliders should all be numeric 9592 minute !== parseInt( this.minute, 10 ) || 9593 second !== parseInt( this.second, 10 ) || 9594 millisec !== parseInt( this.millisec, 10 ) || 9595 microsec !== parseInt( this.microsec, 10 ) || 9596 ( this.ampm.length > 0 && ( hour < 12 ) !== ( $.inArray( this.ampm.toUpperCase(), this.amNames ) !== -1 ) ) || 9597 ( this.timezone !== null && timezone !== this.timezone.toString() ); // could be numeric or "EST" format, so use toString() 9598 9599 if ( hasChanged ) { 9600 if ( hour !== false ) { 9601 this.hour = hour; 9602 } 9603 if ( minute !== false ) { 9604 this.minute = minute; 9605 } 9606 if ( second !== false ) { 9607 this.second = second; 9608 } 9609 if ( millisec !== false ) { 9610 this.millisec = millisec; 9611 } 9612 if ( microsec !== false ) { 9613 this.microsec = microsec; 9614 } 9615 if ( timezone !== false ) { 9616 this.timezone = timezone; 9617 } 9618 9619 if ( ! this.inst ) { 9620 this.inst = $.tm_datepicker._getInst( this.$input[ 0 ] ); 9621 } 9622 9623 this._limitMinMaxDateTime( this.inst, true ); 9624 } 9625 if ( this.support.ampm ) { 9626 this.ampm = ampm; 9627 } 9628 9629 // Updates the time within the tm_timepicker 9630 this.formattedTime = $.tm_datepicker.formatTime( o.timeFormat, this, o ); 9631 if ( this.$timeObj ) { 9632 if ( pickerTimeFormat === o.timeFormat ) { 9633 this.$timeObj.val( this.formattedTime + pickerTimeSuffix ); 9634 } else { 9635 this.$timeObj.val( $.tm_datepicker.formatTime( pickerTimeFormat, this, o ) + pickerTimeSuffix ); 9636 } 9637 if ( this.$timeObj[ 0 ].setSelectionRange ) { 9638 sPos = this.$timeObj[ 0 ].selectionStart; 9639 ePos = this.$timeObj[ 0 ].selectionEnd; 9640 this.$timeObj[ 0 ].setSelectionRange( sPos, ePos ); 9641 } 9642 } 9643 9644 this.timeDefined = true; 9645 if ( hasChanged ) { 9646 this._updateDateTime(); 9647 //this.$input.trigger(' focus' ); // may automatically open the picker on setDate 9648 } 9649 }, 9650 9651 /* 9652 * call custom onSelect. 9653 * bind to sliders slidestop, and grid click. 9654 */ 9655 _onSelectHandler: function() { 9656 var onSelect = this._defaults.onSelect || this.inst.settings.onSelect; 9657 var inputEl = this.$input ? this.$input[ 0 ] : null; 9658 if ( onSelect && inputEl ) { 9659 onSelect.apply( inputEl, [ this.formattedDateTime, this ] ); 9660 } 9661 }, 9662 9663 /* 9664 * update our input with the new date time.. 9665 */ 9666 _updateDateTime: function( dp_inst ) { 9667 var dtTmp; 9668 var dt; 9669 var dateFmt; 9670 var formatCfg; 9671 var timeAvailable; 9672 var formattedDateTime; 9673 var altFormattedDateTime = ''; 9674 var altSeparator; 9675 var altTimeSuffix; 9676 9677 dp_inst = this.inst || dp_inst; 9678 dtTmp = dp_inst.currentYear > 0 ? new Date( dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay ) : new Date( dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay ); 9679 dt = $.tm_datepicker._daylightSavingAdjust( dtTmp ); 9680 //dt = $.tm_datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)), 9681 //dt = $.tm_datepicker._daylightSavingAdjust(new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay)), 9682 dateFmt = $.tm_datepicker._get( dp_inst, 'dateFormat' ); 9683 formatCfg = $.tm_datepicker._getFormatConfig( dp_inst ); 9684 timeAvailable = dt !== null && this.timeDefined; 9685 this.formattedDate = $.tm_datepicker.formatDate( dateFmt, dt === null ? new Date() : dt, formatCfg ); 9686 formattedDateTime = this.formattedDate; 9687 9688 // if a slider was changed but tm_datepicker doesn't have a value yet, set it 9689 if ( dp_inst.lastVal === '' ) { 9690 dp_inst.currentYear = dp_inst.selectedYear; 9691 dp_inst.currentMonth = dp_inst.selectedMonth; 9692 dp_inst.currentDay = dp_inst.selectedDay; 9693 } 9694 9695 /* 9696 * remove following lines to force every changes in date picker to change the input value 9697 * Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker. 9698 * If the user manually empty the value in the input field, the date picker will never change selected value. 9699 */ 9700 //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) { 9701 //return; 9702 //} 9703 9704 if ( this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === false ) { 9705 formattedDateTime = this.formattedTime; 9706 } else if ( ( this._defaults.timeOnly !== true && ( this._defaults.alwaysSetTime || timeAvailable ) ) || ( this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === true ) ) { 9707 formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix; 9708 } 9709 9710 this.formattedDateTime = formattedDateTime; 9711 9712 if ( ! this._defaults.showTimepicker ) { 9713 this.$input.val( this.formattedDate ); 9714 } else if ( this.$altInput && this._defaults.timeOnly === false && this._defaults.altFieldTimeOnly === true ) { 9715 this.$altInput.val( this.formattedTime ); 9716 this.$input.val( this.formattedDate ); 9717 } else if ( this.$altInput ) { 9718 this.$input.val( formattedDateTime ); 9719 altFormattedDateTime = ''; 9720 altSeparator = this._defaults.altSeparator !== null ? this._defaults.altSeparator : this._defaults.separator; 9721 altTimeSuffix = this._defaults.altTimeSuffix !== null ? this._defaults.altTimeSuffix : this._defaults.timeSuffix; 9722 9723 if ( ! this._defaults.timeOnly ) { 9724 if ( this._defaults.altFormat ) { 9725 altFormattedDateTime = $.tm_datepicker.formatDate( this._defaults.altFormat, dt === null ? new Date() : dt, formatCfg ); 9726 } else { 9727 altFormattedDateTime = this.formattedDate; 9728 } 9729 9730 if ( altFormattedDateTime ) { 9731 altFormattedDateTime += altSeparator; 9732 } 9733 } 9734 9735 if ( this._defaults.altTimeFormat !== null ) { 9736 altFormattedDateTime += $.tm_datepicker.formatTime( this._defaults.altTimeFormat, this, this._defaults ) + altTimeSuffix; 9737 } else { 9738 altFormattedDateTime += this.formattedTime + altTimeSuffix; 9739 } 9740 this.$altInput.val( altFormattedDateTime ); 9741 } else { 9742 this.$input.val( formattedDateTime ); 9743 } 9744 9745 this.$input.trigger( 'change' ); 9746 }, 9747 9748 _onFocus: function() { 9749 var inst; 9750 var tp_inst; 9751 if ( ! this.$input.val() && this._defaults.defaultValue ) { 9752 this.$input.val( this._defaults.defaultValue ); 9753 inst = $.tm_datepicker._getInst( this.$input.get( 0 ) ); 9754 tp_inst = $.tm_datepicker._get( inst, 'tm_timepicker' ); 9755 if ( tp_inst ) { 9756 if ( tp_inst._defaults.timeOnly && inst.input.val() !== inst.lastVal ) { 9757 try { 9758 $.tm_datepicker._updateDatepicker( inst ); 9759 } catch ( err ) { 9760 $.tm_timepicker.log( err ); 9761 } 9762 } 9763 } 9764 } 9765 }, 9766 9767 /* 9768 * Small abstraction to control types 9769 * We can add more, just be sure to follow the pattern: create, options, value 9770 */ 9771 _controls: { 9772 // slider methods 9773 slider: { 9774 create: function( tp_inst, obj, unit, val, min, max, step ) { 9775 var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60 9776 return obj.prop( 'slide', null ).slider( { 9777 orientation: 'horizontal', 9778 value: rtl ? val * -1 : val, 9779 min: rtl ? max * -1 : min, 9780 max: rtl ? min * -1 : max, 9781 step: step, 9782 slide: function( event, ui ) { 9783 tp_inst.control.value( tp_inst, $( this ), unit, rtl ? ui.value * -1 : ui.value ); 9784 tp_inst._onTimeChange(); 9785 }, 9786 stop: function() { 9787 tp_inst._onSelectHandler(); 9788 } 9789 } ); 9790 }, 9791 options: function( tp_inst, obj, unit, opts, val ) { 9792 var min; 9793 var max; 9794 if ( tp_inst._defaults.isRTL ) { 9795 if ( typeof opts === 'string' ) { 9796 if ( opts === 'min' || opts === 'max' ) { 9797 if ( val !== undefined ) { 9798 return obj.slider( opts, val * -1 ); 9799 } 9800 return Math.abs( obj.slider( opts ) ); 9801 } 9802 return obj.slider( opts ); 9803 } 9804 min = opts.min; 9805 max = opts.max; 9806 opts.max = null; 9807 opts.min = null; 9808 if ( min !== undefined ) { 9809 opts.max = min * -1; 9810 } 9811 if ( max !== undefined ) { 9812 opts.min = max * -1; 9813 } 9814 return obj.slider( opts ); 9815 } 9816 if ( typeof opts === 'string' && val !== undefined ) { 9817 return obj.slider( opts, val ); 9818 } 9819 return obj.slider( opts ); 9820 }, 9821 value: function( tp_inst, obj, unit, val ) { 9822 if ( tp_inst._defaults.isRTL ) { 9823 if ( val !== undefined ) { 9824 return obj.slider( 'value', val * -1 ); 9825 } 9826 return Math.abs( obj.slider( 'value' ) ); 9827 } 9828 if ( val !== undefined ) { 9829 return obj.slider( 'value', val ); 9830 } 9831 return obj.slider( 'value' ); 9832 } 9833 }, 9834 // select methods 9835 select: { 9836 create: function( tp_inst, obj, unit, val, min, max, step ) { 9837 var sel = '<select class="ui-tm-timepicker-select ui-state-default ui-corner-all" data-unit="' + unit + '" data-min="' + min + '" data-max="' + max + '" data-step="' + step + '">', 9838 format = tp_inst._defaults.pickerTimeFormat || tp_inst._defaults.timeFormat; 9839 var i; 9840 9841 for ( i = min; i <= max; i += step ) { 9842 sel += '<option value="' + i + '"' + ( i === val ? ' selected' : '' ) + '>'; 9843 if ( unit === 'hour' ) { 9844 sel += $.tm_datepicker.formatTime( $.epoAPI.util.trim( format.replace( /[^ht ]/gi, '' ) ), { hour: i }, tp_inst._defaults ); 9845 } else if ( unit === 'millisec' || unit === 'microsec' || i >= 10 ) { 9846 sel += i; 9847 } else { 9848 sel += '0' + i.toString(); 9849 } 9850 sel += '</option>'; 9851 } 9852 sel += '</select>'; 9853 9854 obj.children( 'select' ).remove(); 9855 9856 $( sel ) 9857 .appendTo( obj ) 9858 .on( 'change', function() { 9859 tp_inst._onTimeChange(); 9860 tp_inst._onSelectHandler(); 9861 tp_inst._afterInject(); 9862 } ); 9863 9864 return obj; 9865 }, 9866 options: function( tp_inst, obj, unit, opts, val ) { 9867 var o = {}, 9868 $t = obj.children( 'select' ); 9869 if ( typeof opts === 'string' ) { 9870 if ( val === undefined ) { 9871 return $t.data( opts ); 9872 } 9873 o[ opts ] = val; 9874 } else { 9875 o = opts; 9876 } 9877 return tp_inst.control.create( tp_inst, obj, $t.data( 'unit' ), $t.val(), o.min >= 0 ? o.min : $t.data( 'min' ), o.max || $t.data( 'max' ), o.step || $t.data( 'step' ) ); 9878 }, 9879 value: function( tp_inst, obj, unit, val ) { 9880 var $t = obj.children( 'select' ); 9881 if ( val !== undefined ) { 9882 return $t.val( val ); 9883 } 9884 return $t.val(); 9885 } 9886 } 9887 } // end _controls 9888 } ); 9889 9890 $.fn.extend( { 9891 /* 9892 * shorthand just to use tm_timepicker. 9893 */ 9894 tm_timepicker: function( o ) { 9895 var tmp_args = Array.prototype.slice.call( arguments ); 9896 o = o || {}; 9897 9898 if ( typeof o === 'object' ) { 9899 tmp_args[ 0 ] = $.extend( o, { 9900 timeOnly: true 9901 } ); 9902 } 9903 9904 return $( this ).each( function() { 9905 $.fn.tm_datetimepicker.apply( $( this ), tmp_args ); 9906 } ); 9907 }, 9908 9909 /* 9910 * extend tm_timepicker to tm_datepicker 9911 */ 9912 tm_datetimepicker: function( o ) { 9913 var tmp_args = arguments; 9914 o = o || {}; 9915 9916 if ( typeof o === 'string' ) { 9917 if ( o === 'getDate' || ( o === 'option' && tmp_args.length === 2 && typeof tmp_args[ 1 ] === 'string' ) ) { 9918 return $.fn.tm_datepicker.apply( $( this[ 0 ] ), tmp_args ); 9919 } 9920 return this.each( function() { 9921 var $t = $( this ); 9922 $t.tm_datepicker.apply( $t, tmp_args ); 9923 } ); 9924 } 9925 return this.each( function() { 9926 var $t = $( this ); 9927 $t.tm_datepicker( $.tm_timepicker._newInst( $t, o )._defaults ); 9928 } ); 9929 } 9930 } ); 9931 9932 /* 9933 * Public Utility to parse date and time 9934 */ 9935 $.tm_datepicker.parseDateTime = function( dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings ) { 9936 var parseRes = parseDateTimeInternal( dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings ); 9937 var t; 9938 if ( parseRes.timeObj ) { 9939 t = parseRes.timeObj; 9940 parseRes.date.setHours( t.hour, t.minute, t.second, t.millisec ); 9941 parseRes.date.setMicroseconds( t.microsec ); 9942 } 9943 9944 return parseRes.date; 9945 }; 9946 9947 /* 9948 * Public utility to parse time 9949 */ 9950 $.tm_datepicker.parseTime = function( timeFormat, timeString, options ) { 9951 var o = extendRemove( extendRemove( {}, $.tm_timepicker._defaults ), options || {} ); 9952 9953 // Strict parse requires the timeString to match the timeFormat exactly 9954 var strictParse = function( f, s, oo ) { 9955 // pattern for standard and localized AM/PM markers 9956 var getPatternAmpm = function( amNames, pmNames ) { 9957 var markers = []; 9958 if ( amNames ) { 9959 $.merge( markers, amNames ); 9960 } 9961 if ( pmNames ) { 9962 $.merge( markers, pmNames ); 9963 } 9964 markers = $.map( markers, function( val ) { 9965 return val.replace( /[.*+?|()[\]{}\\]/g, '\\$&' ); 9966 } ); 9967 return '(' + markers.join( '|' ) + ')?'; 9968 }; 9969 9970 // figure out position of time elements.. cause js cant do named captures 9971 var getFormatPositions = function( formatoftime ) { 9972 var finds = formatoftime.toLowerCase().match( /(h{1,2}|m{1,2}|s{1,2}|l{1}|c{1}|t{1,2}|z|'.*?')/g ), 9973 orders = { 9974 h: -1, 9975 m: -1, 9976 s: -1, 9977 l: -1, 9978 c: -1, 9979 t: -1, 9980 z: -1 9981 }; 9982 var i; 9983 9984 if ( finds ) { 9985 for ( i = 0; i < finds.length; i += 1 ) { 9986 if ( orders[ finds[ i ].toString().charAt( 0 ) ] === -1 ) { 9987 orders[ finds[ i ].toString().charAt( 0 ) ] = i + 1; 9988 } 9989 } 9990 } 9991 return orders; 9992 }; 9993 9994 var regstr = 9995 '^' + 9996 f 9997 .toString() 9998 .replace( /([hH]{1,2}|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function( match ) { 9999 var ml = match.length; 10000 switch ( match.charAt( 0 ).toLowerCase() ) { 10001 case 'h': 10002 return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})'; 10003 case 'm': 10004 return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})'; 10005 case 's': 10006 return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})'; 10007 case 'l': 10008 return '(\\d?\\d?\\d)'; 10009 case 'c': 10010 return '(\\d?\\d?\\d)'; 10011 case 'z': 10012 return '(z|[-+]\\d\\d:?\\d\\d|\\S+)?'; 10013 case 't': 10014 return getPatternAmpm( oo.amNames, oo.pmNames ); 10015 default: 10016 // literal escaped in quotes 10017 return ( 10018 '(' + 10019 match.replace( /'/g, '' ).replace( /(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g, function( m ) { 10020 return '\\' + m; 10021 } ) + 10022 ')?' 10023 ); 10024 } 10025 } ) 10026 .replace( /\s/g, '\\s?' ) + 10027 oo.timeSuffix + 10028 '$', 10029 order = getFormatPositions( f ), 10030 ampm = '', 10031 treg; 10032 10033 var resTime = { 10034 hour: 0, 10035 minute: 0, 10036 second: 0, 10037 millisec: 0, 10038 microsec: 0 10039 }; 10040 10041 treg = s.match( new RegExp( regstr, 'i' ) ); 10042 10043 if ( treg ) { 10044 if ( order.t !== -1 ) { 10045 if ( treg[ order.t ] === undefined || treg[ order.t ].length === 0 ) { 10046 ampm = ''; 10047 resTime.ampm = ''; 10048 } else { 10049 ampm = 10050 $.inArray( 10051 treg[ order.t ].toUpperCase(), 10052 $.map( oo.amNames, function( x ) { 10053 return x.toUpperCase(); 10054 } ) 10055 ) !== -1 10056 ? 'AM' 10057 : 'PM'; 10058 resTime.ampm = oo[ ampm === 'AM' ? 'amNames' : 'pmNames' ][ 0 ]; 10059 } 10060 } 10061 10062 if ( order.h !== -1 ) { 10063 if ( ampm === 'AM' && treg[ order.h ] === '12' ) { 10064 resTime.hour = 0; // 12am = 0 hour 10065 } else if ( ampm === 'PM' && treg[ order.h ] !== '12' ) { 10066 resTime.hour = parseInt( treg[ order.h ], 10 ) + 12; // 12pm = 12 hour, any other pm = hour + 12 10067 } else { 10068 resTime.hour = Number( treg[ order.h ] ); 10069 } 10070 } 10071 10072 if ( order.m !== -1 ) { 10073 resTime.minute = Number( treg[ order.m ] ); 10074 } 10075 if ( order.s !== -1 ) { 10076 resTime.second = Number( treg[ order.s ] ); 10077 } 10078 if ( order.l !== -1 ) { 10079 resTime.millisec = Number( treg[ order.l ] ); 10080 } 10081 if ( order.c !== -1 ) { 10082 resTime.microsec = Number( treg[ order.c ] ); 10083 } 10084 if ( order.z !== -1 && treg[ order.z ] !== undefined ) { 10085 resTime.timezone = $.tm_timepicker.timezoneOffsetNumber( treg[ order.z ] ); 10086 } 10087 10088 return resTime; 10089 } 10090 return false; 10091 }; // end strictParse 10092 10093 // First try JS Date, if that fails, use strictParse 10094 var looseParse = function( f, s, oo ) { 10095 var d; 10096 try { 10097 d = new Date( '2012-01-01 ' + s ); 10098 if ( isNaN( d.getTime() ) ) { 10099 d = new Date( '2012-01-01T' + s ); 10100 if ( isNaN( d.getTime() ) ) { 10101 d = new Date( '01/01/2012 ' + s ); 10102 if ( isNaN( d.getTime() ) ) { 10103 throw 'Unable to parse time with native Date: ' + s; 10104 } 10105 } 10106 } 10107 10108 return { 10109 hour: d.getHours(), 10110 minute: d.getMinutes(), 10111 second: d.getSeconds(), 10112 millisec: d.getMilliseconds(), 10113 microsec: d.getMicroseconds(), 10114 timezone: d.getTimezoneOffset() * -1 10115 }; 10116 } catch ( err ) { 10117 try { 10118 return strictParse( f, s, oo ); 10119 } catch ( err2 ) { 10120 $.tm_timepicker.log( 'Unable to parse \ntimeString: ' + s + '\ntimeFormat: ' + f ); 10121 } 10122 } 10123 return false; 10124 }; // end looseParse 10125 10126 if ( typeof o.parse === 'function' ) { 10127 return o.parse( timeFormat, timeString, o ); 10128 } 10129 if ( o.parse === 'loose' ) { 10130 return looseParse( timeFormat, timeString, o ); 10131 } 10132 return strictParse( timeFormat, timeString, o ); 10133 }; 10134 10135 /** 10136 * Public utility to format the time. 10137 * 10138 * @param {string} format format of the time 10139 * @param {Object} time Object not a Date for timezones 10140 * @param {Object} [options] essentially the regional[].. amNames, pmNames, ampm 10141 * @returns {string} the formatted time 10142 */ 10143 $.tm_datepicker.formatTime = function( format, time, options ) { 10144 var tmptime; 10145 var ampmName; 10146 var hour; 10147 10148 options = options || {}; 10149 options = $.extend( {}, $.tm_timepicker._defaults, options ); 10150 time = $.extend( 10151 { 10152 hour: 0, 10153 minute: 0, 10154 second: 0, 10155 millisec: 0, 10156 microsec: 0, 10157 timezone: null 10158 }, 10159 time 10160 ); 10161 10162 tmptime = format; 10163 ampmName = options.amNames[ 0 ]; 10164 hour = parseInt( time.hour, 10 ); 10165 10166 if ( hour > 11 ) { 10167 ampmName = options.pmNames[ 0 ]; 10168 } 10169 10170 tmptime = tmptime.replace( /(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function( match ) { 10171 switch ( match ) { 10172 case 'HH': 10173 return ( '0' + hour ).slice( -2 ); 10174 case 'H': 10175 return hour; 10176 case 'hh': 10177 return ( '0' + convert24to12( hour ) ).slice( -2 ); 10178 case 'h': 10179 return convert24to12( hour ); 10180 case 'mm': 10181 return ( '0' + time.minute ).slice( -2 ); 10182 case 'm': 10183 return time.minute; 10184 case 'ss': 10185 return ( '0' + time.second ).slice( -2 ); 10186 case 's': 10187 return time.second; 10188 case 'l': 10189 return ( '00' + time.millisec ).slice( -3 ); 10190 case 'c': 10191 return ( '00' + time.microsec ).slice( -3 ); 10192 case 'z': 10193 return $.tm_timepicker.timezoneOffsetString( time.timezone === null ? options.timezone : time.timezone, false ); 10194 case 'Z': 10195 return $.tm_timepicker.timezoneOffsetString( time.timezone === null ? options.timezone : time.timezone, true ); 10196 case 'T': 10197 return ampmName.charAt( 0 ).toUpperCase(); 10198 case 'TT': 10199 return ampmName.toUpperCase(); 10200 case 't': 10201 return ampmName.charAt( 0 ).toLowerCase(); 10202 case 'tt': 10203 return ampmName.toLowerCase(); 10204 default: 10205 return match.replace( /'/g, '' ); 10206 } 10207 } ); 10208 10209 return tmptime; 10210 }; 10211 10212 /* 10213 * the bad hack :/ override tm_datepicker so it doesn't close on select 10214 // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378 10215 */ 10216 $.tm_datepicker._base_selectDate = $.tm_datepicker._selectDate; 10217 $.tm_datepicker._selectDate = function( id, dateStr ) { 10218 var inst = this._getInst( $( id )[ 0 ] ), 10219 tp_inst = this._get( inst, 'tm_timepicker' ), 10220 was_inline; 10221 10222 if ( tp_inst && inst.settings.showTimepicker ) { 10223 tp_inst._limitMinMaxDateTime( inst, true ); 10224 was_inline = inst.inline; 10225 inst.stay_open = true; 10226 inst.inline = true; 10227 //This way the onSelect handler called from calendarpicker get the full dateTime
10228 this._base_selectDate( id, dateStr ); 10229 inst.inline = was_inline; 10230 inst.stay_open = false; 10231 this._notifyChange( inst ); 10232 this._updateDatepicker( inst ); 10233 } else { 10234 this._base_selectDate( id, dateStr ); 10235 } 10236 }; 10237 10238 /* 10239 * second bad hack :/ override tm_datepicker so it triggers an event when changing the input field 10240 * and does not redraw the tm_datepicker on every selectDate event 10241 */ 10242 $.tm_datepicker._base_updateDatepicker = $.tm_datepicker._updateDatepicker; 10243 $.tm_datepicker._updateDatepicker = function( inst ) { 10244 // don't popup the tm_datepicker if there is another instance already opened 10245 var input = inst.input[ 0 ]; 10246 var tp_inst; 10247 if ( $.tm_datepicker._curInst && $.tm_datepicker._curInst !== inst && $.tm_datepicker._datepickerShowing && $.tm_datepicker._lastInput !== input ) { 10248 return; 10249 } 10250 10251 if ( typeof inst.stay_open !== 'boolean' || inst.stay_open === false ) { 10252 this._base_updateDatepicker( inst ); 10253 10254 // Reload the time control when changing something in the input text field. 10255 tp_inst = this._get( inst, 'tm_timepicker' ); 10256 if ( tp_inst ) { 10257 tp_inst._addTimePicker( inst ); 10258 } 10259 } 10260 }; 10261 10262 /* 10263 * third bad hack :/ override tm_datepicker so it allows spaces and colon in the input field 10264 */ 10265 $.tm_datepicker._base_doKeyPress = $.tm_datepicker._doKeyPress; 10266 $.tm_datepicker._doKeyPress = function( event ) { 10267 var inst = $.tm_datepicker._getInst( event.target ), 10268 tp_inst = $.tm_datepicker._get( inst, 'tm_timepicker' ); 10269 var ampm; 10270 var tz; 10271 var dateChars; 10272 var datetimeChars; 10273 var chr; 10274 10275 if ( tp_inst ) { 10276 if ( $.tm_datepicker._get( inst, 'constrainInput' ) ) { 10277 ampm = tp_inst.support.ampm; 10278 tz = tp_inst._defaults.showTimezone !== null ? tp_inst._defaults.showTimezone : tp_inst.support.timezone; 10279 dateChars = $.tm_datepicker._possibleChars( $.tm_datepicker._get( inst, 'dateFormat' ) ); 10280 datetimeChars = 10281 tp_inst._defaults.timeFormat 10282 .toString() 10283 .replace( /[hms]/g, '' ) 10284 .replace( /TT/g, ampm ? 'APM' : '' ) 10285 .replace( /Tt/g, ampm ? 'AaPpMm' : '' ) 10286 .replace( /tT/g, ampm ? 'AaPpMm' : '' ) 10287 .replace( /T/g, ampm ? 'AP' : '' ) 10288 .replace( /tt/g, ampm ? 'apm' : '' ) 10289 .replace( /t/g, ampm ? 'ap' : '' ) + 10290 ' ' + 10291 tp_inst._defaults.separator + 10292 tp_inst._defaults.timeSuffix + 10293 ( tz ? tp_inst._defaults.timezoneList.join( '' ) : '' ) + 10294 tp_inst._defaults.amNames.join( '' ) + 10295 tp_inst._defaults.pmNames.join( '' ) + 10296 dateChars; 10297 chr = String.fromCharCode( event.charCode === undefined ? event.keyCode : event.charCode ); 10298 return event.ctrlKey || chr < ' ' || ! dateChars || datetimeChars.indexOf( chr ) > -1; 10299 } 10300 } 10301 10302 return $.tm_datepicker._base_doKeyPress( event ); 10303 }; 10304 10305 /* 10306 * Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField 10307 * Update any alternate field to synchronise with the main field. 10308 */ 10309 $.tm_datepicker._base_updateAlternate = $.tm_datepicker._updateAlternate; 10310 $.tm_datepicker._updateAlternate = function( inst ) { 10311 var tp_inst = this._get( inst, 'tm_timepicker' ); 10312 var altField; 10313 var date; 10314 var formatCfg; 10315 var altFormattedDateTime; 10316 var altSeparator; 10317 var altTimeSuffix; 10318 var altTimeFormat; 10319 if ( tp_inst ) { 10320 altField = tp_inst._defaults.altField; 10321 if ( altField ) { 10322 // update alternate field too 10323 date = this._getDate( inst ); 10324 formatCfg = $.tm_datepicker._getFormatConfig( inst ); 10325 altFormattedDateTime = ''; 10326 altSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator; 10327 altTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix; 10328 altTimeFormat = tp_inst._defaults.altTimeFormat !== null ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat; 10329 10330 altFormattedDateTime += $.tm_datepicker.formatTime( altTimeFormat, tp_inst, tp_inst._defaults ) + altTimeSuffix; 10331 if ( ! tp_inst._defaults.timeOnly && ! tp_inst._defaults.altFieldTimeOnly && date !== null ) { 10332 if ( tp_inst._defaults.altFormat ) { 10333 altFormattedDateTime = $.tm_datepicker.formatDate( tp_inst._defaults.altFormat, date, formatCfg ) + altSeparator + altFormattedDateTime; 10334 } else { 10335 altFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime; 10336 } 10337 } 10338 $( altField ).val( inst.input.val() ? altFormattedDateTime : '' ); 10339 } 10340 } else { 10341 $.tm_datepicker._base_updateAlternate( inst ); 10342 } 10343 }; 10344 10345 /* 10346 * Override key up event to sync manual input changes. 10347 */ 10348 $.tm_datepicker._base_doKeyUp = $.tm_datepicker._doKeyUp; 10349 $.tm_datepicker._doKeyUp = function( event ) { 10350 var inst = $.tm_datepicker._getInst( event.target ), 10351 tp_inst = $.tm_datepicker._get( inst, 'tm_timepicker' ); 10352 10353 if ( tp_inst ) { 10354 if ( tp_inst._defaults.timeOnly && inst.input.val() !== inst.lastVal ) { 10355 try { 10356 $.tm_datepicker._updateDatepicker( inst ); 10357 } catch ( err ) { 10358 $.tm_timepicker.log( err ); 10359 } 10360 } 10361 } 10362 10363 return $.tm_datepicker._base_doKeyUp( event ); 10364 }; 10365 10366 /* 10367 * override "Today" button to also grab the time and set it to input field. 10368 */ 10369 $.tm_datepicker._base_gotoToday = $.tm_datepicker._gotoToday; 10370 $.tm_datepicker._gotoToday = function( id ) { 10371 var inst = this._getInst( $( id )[ 0 ] ); 10372 var tp_inst; 10373 var tzoffset; 10374 var now; 10375 this._base_gotoToday( id ); 10376 tp_inst = this._get( inst, 'timepicker' ); 10377 if ( ! tp_inst ) { 10378 return; 10379 } 10380 10381 tzoffset = $.tm_timepicker.timezoneOffsetNumber( tp_inst.timezone ); 10382 now = new Date(); 10383 now.setMinutes( now.getMinutes() + now.getTimezoneOffset() + parseInt( tzoffset, 10 ) ); 10384 this._setTime( inst, now ); 10385 this._setDate( inst, now ); 10386 tp_inst._onSelectHandler(); 10387 }; 10388 10389 /* 10390 * Disable & enable the Time in the datetimepicker 10391 */ 10392 $.tm_datepicker._disableTimepickerDatepicker = function( target ) { 10393 var inst = this._getInst( target ); 10394 var tp_inst; 10395 if ( ! inst ) { 10396 return; 10397 } 10398 10399 tp_inst = this._get( inst, 'tm_timepicker' ); 10400 $( target ).tm_datepicker( 'getDate' ); // Init selected[Year|Month|Day] 10401 if ( tp_inst ) { 10402 inst.settings.showTimepicker = false;
10403 tp_inst._defaults.showTimepicker = false; 10404 tp_inst._updateDateTime( inst ); 10405 } 10406 }; 10407 10408 $.tm_datepicker._enableTimepickerDatepicker = function( target ) { 10409 var inst = this._getInst( target ); 10410 var tp_inst; 10411 if ( ! inst ) { 10412 return; 10413 } 10414 10415 tp_inst = this._get( inst, 'tm_timepicker' ); 10416 $( target ).tm_datepicker( 'getDate' ); // Init selected[Year|Month|Day] 10417 if ( tp_inst ) { 10418 inst.settings.showTimepicker = true; 10419 tp_inst._defaults.showTimepicker = true; 10420 tp_inst._addTimePicker( inst ); // Could be disabled on page load 10421 tp_inst._updateDateTime( inst ); 10422 } 10423 }; 10424 10425 /* 10426 * Create our own set time function 10427 */ 10428 $.tm_datepicker._setTime = function( inst, date ) { 10429 var tp_inst = this._get( inst, 'tm_timepicker' ); 10430 var defaults; 10431 if ( tp_inst ) { 10432 defaults = tp_inst._defaults; 10433 10434 // calling _setTime with no date sets time to defaults 10435 tp_inst.hour = date ? date.getHours() : defaults.hour; 10436 tp_inst.minute = date ? date.getMinutes() : defaults.minute; 10437 tp_inst.second = date ? date.getSeconds() : defaults.second; 10438 tp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec; 10439 tp_inst.microsec = date ? date.getMicroseconds() : defaults.microsec; 10440 10441 //check if within min/max times.. 10442 tp_inst._limitMinMaxDateTime( inst, true ); 10443 10444 tp_inst._onTimeChange(); 10445 tp_inst._updateDateTime( inst ); 10446 } 10447 }; 10448 10449 /* 10450 * Create new public method to set only time, callable as $().tm_datepicker('setTime', date) 10451 */ 10452 $.tm_datepicker._setTimeDatepicker = function( target, date, withDate ) { 10453 var inst = this._getInst( target ); 10454 var tp_inst; 10455 var tp_date; 10456 10457 if ( ! inst ) { 10458 return; 10459 } 10460 10461 tp_inst = this._get( inst, 'tm_timepicker' ); 10462 10463 if ( tp_inst ) { 10464 this._setDateFromField( inst ); 10465 10466 if ( date ) { 10467 if ( typeof date === 'string' ) { 10468 tp_inst._parseTime( date, withDate ); 10469 tp_date = new Date(); 10470 tp_date.setHours( tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec ); 10471 tp_date.setMicroseconds( tp_inst.microsec ); 10472 } else { 10473 tp_date = new Date( date.getTime() ); 10474 tp_date.setMicroseconds( date.getMicroseconds() ); 10475 } 10476 if ( tp_date.toString() === 'Invalid Date' ) { 10477 tp_date = undefined; 10478 } 10479 this._setTime( inst, tp_date ); 10480 } 10481 } 10482 }; 10483 10484 /* 10485 * override setDate() to allow setting time too within Date object 10486 */ 10487 $.tm_datepicker._base_setDateDatepicker = $.tm_datepicker._setDateDatepicker; 10488 $.tm_datepicker._setDateDatepicker = function( target, _date ) { 10489 var inst = this._getInst( target ); 10490 var date = _date; 10491 var tp_inst; 10492 var tp_date; 10493 if ( ! inst ) { 10494 return; 10495 } 10496 10497 if ( typeof _date === 'string' ) { 10498 date = new Date( _date ); 10499 if ( ! date.getTime() ) { 10500 this._base_setDateDatepicker.apply( this, arguments ); 10501 date = $( target ).tm_datepicker( 'getDate' ); 10502 } 10503 } 10504 10505 tp_inst = this._get( inst, 'tm_timepicker' ); 10506 if ( date instanceof Date ) { 10507 tp_date = new Date( date.getTime() ); 10508 tp_date.setMicroseconds( date.getMicroseconds() ); 10509 } else { 10510 tp_date = date; 10511 } 10512 10513 // This is important if you are using the timezone option, javascript's Date 10514 // object will only return the timezone offset for the current locale, so we 10515 // adjust it accordingly. If not using timezone option this won't matter.. 10516 // If a timezone is different in tp, keep the timezone as is 10517 if ( tp_inst && tp_date ) { 10518 // look out for DST if tz wasn't specified 10519 if ( ! tp_inst.support.timezone && tp_inst._defaults.timezone === null ) { 10520 tp_inst.timezone = tp_date.getTimezoneOffset() * -1; 10521 } 10522 date = $.tm_timepicker.timezoneAdjust( date, $.tm_timepicker.timezoneOffsetString( -date.getTimezoneOffset() ), tp_inst.timezone ); 10523 tp_date = $.tm_timepicker.timezoneAdjust( tp_date, $.tm_timepicker.timezoneOffsetString( -tp_date.getTimezoneOffset() ), tp_inst.timezone ); 10524 } 10525 10526 this._updateDatepicker( inst ); 10527 this._base_setDateDatepicker.apply( this, arguments ); 10528 this._setTimeDatepicker( target, tp_date, true ); 10529 }; 10530 10531 /* 10532 * override getDate() to allow getting time too within Date object 10533 */ 10534 $.tm_datepicker._base_getDateDatepicker = $.tm_datepicker._getDateDatepicker; 10535 $.tm_datepicker._getDateDatepicker = function( target, noDefault ) { 10536 var inst = this._getInst( target ); 10537 var tp_inst; 10538 var date; 10539 var currDT; 10540 10541 if ( ! inst ) { 10542 return; 10543 } 10544 10545 tp_inst = this._get( inst, 'tm_timepicker' ); 10546 10547 if ( tp_inst ) { 10548 // if it hasn't yet been defined, grab from field 10549 if ( inst.lastVal === undefined ) { 10550 this._setDateFromField( inst, noDefault ); 10551 } 10552 10553 date = this._getDate( inst ); 10554 10555 currDT = null; 10556 10557 if ( tp_inst.$altInput && tp_inst._defaults.altFieldTimeOnly ) { 10558 currDT = tp_inst.$input.val() + ' ' + tp_inst.$altInput.val(); 10559 } else if ( tp_inst.$input.get( 0 ).tagName !== 'INPUT' && tp_inst.$altInput ) { 10560 /** 10561 * in case the datetimepicker has been applied to a non-input tag for inline UI, 10562 * and the user has not configured the plugin to display only time in altInput, 10563 * pick current date time from the altInput (and hope for the best, for now, until "ER1" is applied) 10564 * 10565 * @todo ER1. Since altInput can have a totally difference format, convert it to standard format by reading input format from "altFormat" and "altTimeFormat" option values 10566 */ 10567 currDT = tp_inst.$altInput.val(); 10568 } else { 10569 currDT = tp_inst.$input.val(); 10570 } 10571 10572 if ( date && tp_inst._parseTime( currDT, ! inst.settings.timeOnly ) ) {
vendor: 7,140 bytes, lines 10573-10790
10573 date.setHours( tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec ); 10574 date.setMicroseconds( tp_inst.microsec ); 10575 10576 // This is important if you are using the timezone option, javascript's Date 10577 // object will only return the timezone offset for the current locale, so we 10578 // adjust it accordingly. If not using timezone option this won't matter.. 10579 if ( tp_inst.timezone !== null ) { 10580 // look out for DST if tz wasn't specified 10581 if ( ! tp_inst.support.timezone && tp_inst._defaults.timezone === null ) { 10582 tp_inst.timezone = date.getTimezoneOffset() * -1; 10583 } 10584 date = $.tm_timepicker.timezoneAdjust( date, tp_inst.timezone, $.tm_timepicker.timezoneOffsetString( -date.getTimezoneOffset() ) ); 10585 } 10586 } 10587 return date; 10588 } 10589 return this._base_getDateDatepicker( target, noDefault ); 10590 }; 10591 10592 /* 10593 * override parseDate() because UI 1.8.14 throws an error about "Extra characters" 10594 * An option in datapicker to ignore extra format characters would be nicer. 10595 */ 10596 $.tm_datepicker._base_parseDate = $.tm_datepicker.parseDate; 10597 $.tm_datepicker.parseDate = function( format, value, settings ) { 10598 var date; 10599 try { 10600 date = this._base_parseDate( format, value, settings ); 10601 } catch ( err ) { 10602 // Hack! The error message ends with a colon, a space, and 10603 // the "extra" characters. We rely on that instead of 10604 // attempting to perfectly reproduce the parsing algorithm. 10605 if ( err.indexOf( ':' ) >= 0 ) { 10606 date = this._base_parseDate( format, value.substring( 0, value.length - ( err.length - err.indexOf( ':' ) - 2 ) ), settings ); 10607 $.tm_timepicker.log( 'Error parsing the date string: ' + err + '\ndate string = ' + value + '\ndate format = ' + format ); 10608 } else { 10609 throw err; 10610 } 10611 } 10612 return date; 10613 }; 10614 10615 /* 10616 * override formatDate to set date with time to the input 10617 */ 10618 $.tm_datepicker._base_formatDate = $.tm_datepicker._formatDate; 10619 $.tm_datepicker._formatDate = function( inst ) { 10620 var tp_inst = this._get( inst, 'tm_timepicker' ); 10621 if ( tp_inst ) { 10622 tp_inst._updateDateTime( inst ); 10623 return tp_inst.$input.val(); 10624 } 10625 return this._base_formatDate( inst ); 10626 }; 10627 10628 /* 10629 * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate 10630 */ 10631 $.tm_datepicker._base_optionDatepicker = $.tm_datepicker._optionDatepicker; 10632 $.tm_datepicker._optionDatepicker = function( target, name, value ) { 10633 var inst = this._getInst( target ), 10634 name_clone; 10635 var tp_inst; 10636 var min, max, onselect, overrides, fns, prop, ret, oldVal, $target; 10637 10638 if ( ! inst ) { 10639 return null; 10640 } 10641 10642 tp_inst = this._get( inst, 'tm_timepicker' ); 10643 if ( tp_inst ) { 10644 min = null; 10645 max = null; 10646 onselect = null; 10647 overrides = tp_inst._defaults.evnts; 10648 fns = {}; 10649 10650 if ( typeof name === 'string' ) { 10651 // if min/max was set with the string 10652 if ( name === 'minDate' || name === 'minDateTime' ) { 10653 min = value; 10654 } else if ( name === 'maxDate' || name === 'maxDateTime' ) { 10655 max = value; 10656 } else if ( name === 'onSelect' ) { 10657 onselect = value; 10658 } else if ( Object.prototype.hasOwnProperty.call( overrides, name ) ) { 10659 if ( typeof value === 'undefined' ) { 10660 return overrides[ name ]; 10661 } 10662 fns[ name ] = value; 10663 name_clone = {}; //empty results in exiting function after overrides updated 10664 } 10665 } else if ( typeof name === 'object' ) { 10666 //if min/max was set with the JSON 10667 if ( name.minDate ) { 10668 min = name.minDate; 10669 } else if ( name.minDateTime ) { 10670 min = name.minDateTime; 10671 } else if ( name.maxDate ) { 10672 max = name.maxDate; 10673 } else if ( name.maxDateTime ) { 10674 max = name.maxDateTime; 10675 } 10676 for ( prop in overrides ) { 10677 if ( Object.prototype.hasOwnProperty.call( overrides, prop ) && name[ prop ] ) { 10678 fns[ prop ] = name[ prop ]; 10679 } 10680 } 10681 } 10682 for ( prop in fns ) { 10683 if ( Object.prototype.hasOwnProperty.call( fns, prop ) ) { 10684 overrides[ prop ] = fns[ prop ]; 10685 if ( ! name_clone ) { 10686 name_clone = $.extend( {}, name ); 10687 } 10688 delete name_clone[ prop ]; 10689 } 10690 } 10691 if ( name_clone && isEmptyObject( name_clone ) ) { 10692 return; 10693 } 10694 if ( min ) { 10695 //if min was set 10696 if ( min === 0 ) { 10697 min = new Date(); 10698 } else { 10699 min = new Date( min ); 10700 } 10701 tp_inst._defaults.minDate = min; 10702 tp_inst._defaults.minDateTime = min; 10703 } else if ( max ) { 10704 //if max was set 10705 if ( max === 0 ) { 10706 max = new Date(); 10707 } else { 10708 max = new Date( max ); 10709 } 10710 tp_inst._defaults.maxDate = max; 10711 tp_inst._defaults.maxDateTime = max; 10712 } else if ( onselect ) { 10713 tp_inst._defaults.onSelect = onselect; 10714 } 10715 10716 // Datepicker will override our date when we call _base_optionDatepicker when 10717 // calling minDate/maxDate, so we will first grab the value, call 10718 // _base_optionDatepicker, then set our value back. 10719 if ( min || max ) { 10720 $target = $( target ); 10721 oldVal = $target.tm_datetimepicker( 'getDate' ); 10722 ret = this._base_optionDatepicker.call( $.tm_datepicker, target, name_clone || name, value ); 10723 $target.tm_datetimepicker( 'setDate', oldVal ); 10724 return ret; 10725 } 10726 } 10727 if ( value === undefined ) { 10728 return this._base_optionDatepicker.call( $.tm_datepicker, target, name ); 10729 } 10730 return this._base_optionDatepicker.call( $.tm_datepicker, target, name_clone || name, value ); 10731 }; 10732 10733 /* 10734 * Create a Singleton Instance 10735 */ 10736 $.tm_timepicker = new Timepicker(); 10737 10738 /** 10739 * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5) 10740 * 10741 * @param {number} tzMinutes if not a number, less than -720 (-1200), or greater than 840 (+1400) this value is returned 10742 * @param {boolean} iso8601 if true formats in accordance to iso8601 "+12:45" 10743 * @return {string} timezone Offset 10744 */ 10745 $.tm_timepicker.timezoneOffsetString = function( tzMinutes, iso8601 ) { 10746 var off, minutes, hours, iso, tz; 10747 10748 if ( isNaN( tzMinutes ) || tzMinutes > 840 || tzMinutes < -720 ) { 10749 return tzMinutes; 10750 } 10751 10752 off = tzMinutes; 10753 minutes = off % 60; 10754 hours = ( off - minutes ) / 60; 10755 iso = iso8601 ? ':' : ''; 10756 tz = ( off >= 0 ? '+' : '-' ) + ( '0' + Math.abs( hours ) ).slice( -2 ) + iso + ( '0' + Math.abs( minutes ) ).slice( -2 ); 10757 10758 if ( tz === '+00:00' ) { 10759 return 'Z'; 10760 } 10761 return tz; 10762 }; 10763 10764 /** 10765 * Get the number in minutes that represents a timezone string 10766 * 10767 * @param {string} tzString formatted like "+0500", "-1245", "Z" 10768 * @return {number} the offset minutes or the original string if it doesn't match expectations 10769 */ 10770 $.tm_timepicker.timezoneOffsetNumber = function( tzString ) { 10771 var normalized = tzString.toString().replace( ':', '' ); // excuse any iso8601, end up with "+1245" 10772 10773 if ( normalized.toUpperCase() === 'Z' ) { 10774 // if iso8601 with Z, its 0 minute offset 10775 return 0; 10776 } 10777 10778 if ( ! /^(-|\+)\d{4}$/.test( normalized ) ) { 10779 // possibly a user defined tz, so just give it back 10780 return parseInt( tzString, 10 ); 10781 } 10782 10783 return ( 10784 ( normalized.substring( 0, 1 ) === '-' ? -1 : 1 ) * // plus or minus 10785 ( ( parseInt( normalized.substring( 1, 3 ), 10 ) * 60 ) + // hours (converted to minutes) 10786 parseInt( normalized.substring( 3, 5 ), 10 ) ) 10787 ); // minutes 10788 }; 10789 10790 /**
10791 * No way to set timezone in js Date, so we must adjust the minutes to compensate. 10792 * (think setDate, getDate) 10793 * 10794 * @param {Date} date 10795 * @param {string} fromTimezone formatted like "+0500", "-1245" 10796 * @param {string} toTimezone formatted like "+0500", "-1245" 10797 * @return {Date} Date 10798 */ 10799 $.tm_timepicker.timezoneAdjust = function( date, fromTimezone, toTimezone ) { 10800 var fromTz = $.timepicker.timezoneOffsetNumber( fromTimezone ); 10801 var toTz = $.tm_timepicker.timezoneOffsetNumber( toTimezone ); 10802 if ( ! isNaN( toTz ) ) { 10803 date.setMinutes( date.getMinutes() + -fromTz - -toTz ); 10804 } 10805 return date; 10806 }; 10807 10808 /** 10809 * Calls `tm_timepicker()` on the `startTime` and `endTime` elements, and configures them to 10810 * enforce date range limits. 10811 * n.b. The input value must be correctly formatted (reformatting is not supported) 10812 * 10813 * @param {Element} startTime 10814 * @param {Element} endTime 10815 * @param {Object} options Options for the tm_timepicker() call 10816 * @return {jQuery} time range 10817 */ 10818 $.tm_timepicker.timeRange = function( startTime, endTime, options ) { 10819 return $.tm_timepicker.handleRange( 'tm_timepicker', startTime, endTime, options ); 10820 }; 10821 10822 /** 10823 * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to 10824 * enforce date range limits. 10825 * 10826 * @param {Element} startTime 10827 * @param {Element} endTime 10828 * @param {Object} options Options for the `tm_timepicker()` call. Also supports `reformat`, 10829 * a boolean value that can be used to reformat the input values to the `dateFormat`. 10830 */ 10831 $.tm_timepicker.datetimeRange = function( startTime, endTime, options ) { 10832 $.tm_timepicker.handleRange( 'tm_datetimepicker', startTime, endTime, options ); 10833 }; 10834 10835 /** 10836 * Calls `tm_datepicker` on the `startTime` and `endTime` elements, and configures them to 10837 * enforce date range limits. 10838 * 10839 * @param {Element} startTime 10840 * @param {Element} endTime 10841 * @param {Object} options Options for the `tm_timepicker()` call. Also supports `reformat`, 10842 * a boolean value that can be used to reformat the input values to the `dateFormat`. 10843 */ 10844 $.tm_timepicker.dateRange = function( startTime, endTime, options ) { 10845 $.tm_timepicker.handleRange( 'tm_datepicker', startTime, endTime, options ); 10846 }; 10847 10848 /** 10849 * Calls `method` on the `startTime` and `endTime` elements, and configures them to 10850 * enforce date range limits. 10851 * 10852 * @param {string} method Can be used to specify the type of picker to be added 10853 * @param {Element} startTime 10854 * @param {Element} endTime 10855 * @param {Object} options Options for the `tm_timepicker()` call. Also supports `reformat`, 10856 * a boolean value that can be used to reformat the input values to the `dateFormat`. 10857 * @return {jQuery} range 10858 */ 10859 $.tm_timepicker.handleRange = function( method, startTime, endTime, options ) { 10860 var timeOnly = false; 10861 options = $.extend( 10862 {}, 10863 { 10864 minInterval: 0, // min allowed interval in milliseconds 10865 maxInterval: 0, // max allowed interval in milliseconds 10866 start: {}, // options for start picker 10867 end: {} // options for end picker 10868 }, 10869 options 10870 ); 10871 10872 // for the mean time this fixes an issue with calling getDate with tm_timepicker() 10873 10874 if ( method === 'tm_timepicker' ) { 10875 timeOnly = true; 10876 method = 'tm_datetimepicker'; 10877 } 10878 10879 function checkDates( changed, other ) { 10880 var startdt = startTime[ method ]( 'getDate' ), 10881 enddt = endTime[ method ]( 'getDate' ), 10882 changeddt = changed[ method ]( 'getDate' ); 10883 var minDate; 10884 var maxDate; 10885 10886 if ( startdt !== null ) { 10887 minDate = new Date( startdt.getTime() ); 10888 maxDate = new Date( startdt.getTime() ); 10889 10890 minDate.setMilliseconds( minDate.getMilliseconds() + options.minInterval ); 10891 maxDate.setMilliseconds( maxDate.getMilliseconds() + options.maxInterval ); 10892 10893 if ( options.minInterval > 0 && minDate > enddt ) { 10894 // minInterval check 10895 endTime[ method ]( 'setDate', minDate ); 10896 } else if ( options.maxInterval > 0 && maxDate < enddt ) { 10897 // max interval check 10898 endTime[ method ]( 'setDate', maxDate ); 10899 } else if ( startdt > enddt ) { 10900 other[ method ]( 'setDate', changeddt ); 10901 } 10902 } 10903 } 10904 10905 function selected( changed, other, option ) { 10906 var date; 10907 if ( ! changed.val() ) { 10908 return; 10909 } 10910 date = changed[ method ].call( changed, 'getDate' ); 10911 if ( date !== null && options.minInterval > 0 ) { 10912 if ( option === 'minDate' ) { 10913 date.setMilliseconds( date.getMilliseconds() + options.minInterval ); 10914 } 10915 if ( option === 'maxDate' ) { 10916 date.setMilliseconds( date.getMilliseconds() - options.minInterval ); 10917 } 10918 } 10919 10920 if ( date.getTime ) { 10921 other[ method ].call( other, 'option', option, date ); 10922 } 10923 } 10924 10925 $.fn[ method ].call( 10926 startTime, 10927 $.extend( 10928 { 10929 timeOnly: timeOnly, 10930 onClose: function() { 10931 checkDates( $( this ), endTime ); 10932 }, 10933 onSelect: function() { 10934 selected( $( this ), endTime, 'minDate' ); 10935 } 10936 }, 10937 options, 10938 options.start 10939 ) 10940 ); 10941 $.fn[ method ].call( 10942 endTime, 10943 $.extend( 10944 { 10945 timeOnly: timeOnly, 10946 onClose: function() { 10947 checkDates( $( this ), startTime ); 10948 }, 10949 onSelect: function() { 10950 selected( $( this ), startTime, 'maxDate' ); 10951 } 10952 }, 10953 options, 10954 options.end 10955 ) 10956 ); 10957 10958 checkDates( startTime, endTime ); 10959 10960 selected( startTime, endTime, 'minDate' ); 10961 selected( endTime, startTime, 'maxDate' ); 10962 10963 return $( [ startTime.get( 0 ), endTime.get( 0 ) ] ); 10964 }; 10965 10966 /** 10967 * Log error or data to the console during error or debugging 10968 * 10969 * @return {void} 10970 */ 10971 $.tm_timepicker.log = function() { 10972 // Older IE (9, maybe 10) throw error on accessing `window.console.log.apply`, so check first. 10973 if ( window.console && window.console.log && window.console.log.apply ) { 10974 window.console.log.apply( window.console, Array.prototype.slice.call( arguments ) ); 10975 } 10976 }; 10977 10978 /* 10979 * Add util object to allow access to private methods for testability. 10980 */ 10981 $.tm_timepicker._util = { 10982 _extendRemove: extendRemove, 10983 _isEmptyObject: isEmptyObject, 10984 _convert24to12: convert24to12, 10985 _detectSupport: detectSupport, 10986 _selectLocalTimezone: selectLocalTimezone, 10987 _computeEffectiveSetting: computeEffectiveSetting, 10988 _splitDateTime: splitDateTime, 10989 _parseDateTimeInternal: parseDateTimeInternal 10990 }; 10991 10992 /* 10993 * Microsecond support 10994 */ 10995 if ( ! Date.prototype.getMicroseconds ) { 10996 Object.defineProperty( Date.prototype, 'microseconds', { 10997 value: 0, 10998 writable: true 10999 } ); 11000 11001 Object.defineProperty( Date.prototype, 'getMicroseconds', { 11002 value: function() { 11003 return this.microseconds; 11004 } 11005 } ); 11006 11007 Object.defineProperty( Date.prototype, 'setMicroseconds', { 11008 value: function( m ) { 11009 this.setMilliseconds( this.getMilliseconds() + Math.floor( m / 1000 ) ); 11010 this.microseconds = m % 1000; 11011 return this; 11012 } 11013 } ); 11014 } 11015 11016 /* 11017 * Keep up with the version 11018 */ 11019 $.tm_timepicker.version = '1.6.3'; 11020} ) ); 11021; 11022/** 11023 * Owl Carousel v2.3.4 11024 * Copyright 2013-2018 David Deutsch 11025 * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE 11026 * reformatted code by ThemeComplete 11027 */ 11028/** 11029 * Owl carousel
11030 * 11031 * @param {jQuery} $ 11032 * @param {Window} window 11033 * @param {Document} document 11034 * @version 2.3.4 11035 * @author Bartosz Wojciechowski 11036 * @author David Deutsch 11037 * @license The MIT License (MIT) 11038 * @todo Lazy Load Icon 11039 * @todo prevent animationend bubling 11040 * @todo itemsScaleUp 11041 * @todo Test Zepto 11042 * @todo stagePadding calculate wrong active classes 11043 */ 11044( function( $, window, document ) { 11045 'use strict'; 11046 11047 /** 11048 * Creates a carousel. 11049 * 11050 * @class The Owl Carousel. 11051 * @public 11052 * @param {HTMLElement|jQuery} element - The element to create the carousel for. 11053 * @param {Object} [options] - The options 11054 */ 11055 function Owl( element, options ) { 11056 /** 11057 * Current settings for the carousel. 11058 * 11059 * @public 11060 */ 11061 this.settings = null; 11062 11063 /** 11064 * Current options set by the caller including defaults. 11065 * 11066 * @public 11067 */ 11068 this.options = $.extend( {}, Owl.Defaults, options ); 11069 11070 /** 11071 * Plugin element. 11072 * 11073 * @public 11074 */ 11075 this.$element = $( element ); 11076 11077 /** 11078 * Proxied event handlers. 11079 * 11080 * @protected 11081 */ 11082 this._handlers = {}; 11083 11084 /** 11085 * References to the running plugins of this carousel. 11086 * 11087 * @protected 11088 */ 11089 this._plugins = {}; 11090 11091 /** 11092 * Currently suppressed events to prevent them from being retriggered. 11093 * 11094 * @protected 11095 */ 11096 this._supress = {}; 11097 11098 /** 11099 * Absolute current position. 11100 * 11101 * @protected 11102 */ 11103 this._current = null; 11104 11105 /** 11106 * Animation speed in milliseconds. 11107 * 11108 * @protected 11109 */ 11110 this._speed = null; 11111 11112 /** 11113 * Coordinates of all items in pixel. 11114 * 11115 * @todo The name of this member is missleading. 11116 * @protected 11117 */ 11118 this._coordinates = []; 11119 11120 /** 11121 * Current breakpoint. 11122 * 11123 * @todo Real media queries would be nice. 11124 * @protected 11125 */ 11126 this._breakpoint = null; 11127 11128 /** 11129 * Current width of the plugin element. 11130 */ 11131 this._width = null; 11132 11133 /** 11134 * All real items. 11135 * 11136 * @protected 11137 */ 11138 this._items = []; 11139 11140 /** 11141 * All cloned items. 11142 * 11143 * @protected 11144 */ 11145 this._clones = []; 11146 11147 /** 11148 * Merge values of all items. 11149 * 11150 * @todo Maybe this could be part of a plugin. 11151 * @protected 11152 */ 11153 this._mergers = []; 11154 11155 /** 11156 * Widths of all items. 11157 */ 11158 this._widths = []; 11159 11160 /** 11161 * Invalidated parts within the update process. 11162 * 11163 * @protected 11164 */ 11165 this._invalidated = {}; 11166 11167 /** 11168 * Ordered list of workers for the update process. 11169 * 11170 * @protected 11171 */ 11172 this._pipe = []; 11173 11174 /** 11175 * Current state information for the drag operation. 11176 * 11177 * @todo #261 11178 * @protected 11179 */ 11180 this._drag = { 11181 time: null, 11182 target: null, 11183 pointer: null, 11184 stage: { 11185 start: null, 11186 current: null 11187 }, 11188 direction: null 11189 }; 11190 11191 /** 11192 * Current state information and their tags. 11193 * 11194 * @type {Object} 11195 * @protected 11196 */ 11197 this._states = { 11198 current: {}, 11199 tags: { 11200 initializing: [ 'busy' ], 11201 animating: [ 'busy' ], 11202 dragging: [ 'interacting' ] 11203 } 11204 }; 11205 11206 $.each( 11207 [ 'onResize', 'onThrottledResize' ], 11208 $.proxy( function( i, handler ) { 11209 this._handlers[ handler ] = $.proxy( this[ handler ], this ); 11210 }, this ) 11211 ); 11212 11213 $.each( 11214 Owl.Plugins, 11215 $.proxy( function( key, Plugin ) { 11216 this._plugins[ key.charAt( 0 ).toLowerCase() + key.slice( 1 ) ] = new Plugin( this ); 11217 }, this ) 11218 ); 11219 11220 $.each( 11221 Owl.Workers, 11222 $.proxy( function( priority, worker ) { 11223 this._pipe.push( { 11224 filter: worker.filter, 11225 run: $.proxy( worker.run, this ) 11226 } ); 11227 }, this ) 11228 ); 11229 11230 this.setup(); 11231 this.initialize(); 11232 } 11233 11234 /** 11235 * Default options for the carousel. 11236 * 11237 * @public 11238 */ 11239 Owl.Defaults = { 11240 items: 3, 11241 loop: false, 11242 center: false, 11243 rewind: false, 11244 checkVisibility: true, 11245 11246 mouseDrag: true, 11247 touchDrag: true, 11248 pullDrag: true, 11249 freeDrag: false, 11250 11251 margin: 0, 11252 stagePadding: 0, 11253 11254 merge: false, 11255 mergeFit: true, 11256 autoWidth: false, 11257 11258 startPosition: 0, 11259 rtl: false, 11260 11261 smartSpeed: 250, 11262 fluidSpeed: false, 11263 dragEndSpeed: false, 11264 11265 responsive: {}, 11266 responsiveRefreshRate: 200, 11267 responsiveBaseElement: window, 11268 11269 fallbackEasing: 'linear', 11270 slideTransition: '', 11271 11272 info: false, 11273 11274 nestedItemSelector: false, 11275 itemElement: 'div', 11276 stageElement: 'div', 11277 11278 refreshClass: 'owl-refresh', 11279 loadedClass: 'owl-loaded', 11280 loadingClass: 'owl-loading', 11281 rtlClass: 'owl-rtl', 11282 responsiveClass: 'owl-responsive', 11283 dragClass: 'owl-drag', 11284 itemClass: 'owl-item', 11285 stageClass: 'owl-stage', 11286 stageOuterClass: 'owl-stage-outer', 11287 grabClass: 'owl-grab' 11288 }; 11289 11290 /** 11291 * Enumeration for width. 11292 * 11293 * @public 11294 * @readonly 11295 * @enum {string} 11296 */ 11297 Owl.Width = { 11298 Default: 'default', 11299 Inner: 'inner', 11300 Outer: 'outer' 11301 }; 11302 11303 /** 11304 * Enumeration for types. 11305 * 11306 * @public 11307 * @readonly 11308 * @enum {string} 11309 */ 11310 Owl.Type = { 11311 Event: 'event', 11312 State: 'state' 11313 }; 11314 11315 /** 11316 * Contains all registered plugins. 11317 * 11318 * @public 11319 */ 11320 Owl.Plugins = {}; 11321 11322 /** 11323 * List of workers involved in the update process. 11324 */ 11325 Owl.Workers = [ 11326 { 11327 filter: [ 'width', 'settings' ], 11328 run: function() { 11329 this._width = this.$element.width(); 11330 } 11331 }, 11332 { 11333 filter: [ 'width', 'items', 'settings' ], 11334 run: function( cache ) { 11335 cache.current = this._items && this._items[ this.relative( this._current ) ]; 11336 } 11337 }, 11338 { 11339 filter: [ 'items', 'settings' ], 11340 run: function() { 11341 this.$stage.children( '.cloned' ).remove(); 11342 } 11343 }, 11344 { 11345 filter: [ 'width', 'items', 'settings' ], 11346 run: function( cache ) { 11347 var margin = this.settings.margin || '', 11348 grid = ! this.settings.autoWidth, 11349 rtl = this.settings.rtl, 11350 css = { 11351 width: 'auto', 11352 'margin-left': rtl ? margin : '', 11353 'margin-right': rtl ? '' : margin 11354 }; 11355 11356 if ( ! grid ) { 11357 this.$stage.children().css( css ); 11358 } 11359 11360 cache.css = css; 11361 } 11362 }, 11363 { 11364 filter: [ 'width', 'items', 'settings' ], 11365 run: function( cache ) { 11366 var width = ( this.width() / this.settings.items ).toFixed( 3 ) - this.settings.margin, 11367 merge = null, 11368 iterator = this._items.length, 11369 grid = ! this.settings.autoWidth, 11370 widths = []; 11371
11372 cache.items = { 11373 merge: false, 11374 width: width 11375 }; 11376 11377 while ( iterator > 0 ) { 11378 iterator = iterator - 1; 11379 merge = this._mergers[ iterator ]; 11380 merge = ( this.settings.mergeFit && Math.min( merge, this.settings.items ) ) || merge; 11381 11382 cache.items.merge = merge > 1 || cache.items.merge; 11383 11384 widths[ iterator ] = ! grid ? this._items[ iterator ].width() : width * merge; 11385 } 11386 11387 this._widths = widths; 11388 } 11389 }, 11390 { 11391 filter: [ 'items', 'settings' ], 11392 run: function() { 11393 var clones = [], 11394 items = this._items, 11395 settings = this.settings, 11396 // TODO: Should be computed from number of min width items in stage 11397 view = Math.max( settings.items * 2, 4 ), 11398 size = Math.ceil( items.length / 2 ) * 2, 11399 repeat = settings.loop && items.length ? ( settings.rewind ? view : Math.max( view, size ) ) : 0, 11400 append = '', 11401 prepend = ''; 11402 11403 repeat /= 2; 11404 11405 while ( repeat > 0 ) { 11406 // Switch to only using appended clones 11407 clones.push( this.normalize( clones.length / 2, true ) ); 11408 append = append + items[ clones[ clones.length - 1 ] ][ 0 ].outerHTML; 11409 clones.push( this.normalize( items.length - 1 - ( ( clones.length - 1 ) / 2 ), true ) ); 11410 prepend = items[ clones[ clones.length - 1 ] ][ 0 ].outerHTML + prepend; 11411 repeat -= 1; 11412 } 11413 11414 this._clones = clones; 11415 11416 $( append ).addClass( 'cloned' ).appendTo( this.$stage ); 11417 $( prepend ).addClass( 'cloned' ).prependTo( this.$stage ); 11418 } 11419 }, 11420 { 11421 filter: [ 'width', 'items', 'settings' ], 11422 run: function() { 11423 var rtl = this.settings.rtl ? 1 : -1, 11424 size = this._clones.length + this._items.length, 11425 iterator = 0, 11426 previous = 0, 11427 current = 0, 11428 coordinates = []; 11429 11430 while ( iterator < size ) { 11431 previous = coordinates[ iterator - 1 ] || 0; 11432 current = this._widths[ this.relative( iterator ) ] + this.settings.margin; 11433 coordinates.push( previous + ( current * rtl ) ); 11434 iterator = iterator + 1; 11435 } 11436 11437 this._coordinates = coordinates; 11438 } 11439 }, 11440 { 11441 filter: [ 'width', 'items', 'settings' ], 11442 run: function() { 11443 var padding = this.settings.stagePadding, 11444 coordinates = this._coordinates, 11445 css = { 11446 width: Math.ceil( Math.abs( coordinates[ coordinates.length - 1 ] ) ) + ( padding * 2 ), 11447 'padding-left': padding || '', 11448 'padding-right': padding || '' 11449 }; 11450 11451 this.$stage.css( css ); 11452 } 11453 }, 11454 { 11455 filter: [ 'width', 'items', 'settings' ], 11456 run: function( cache ) { 11457 var iterator = this._coordinates.length, 11458 grid = ! this.settings.autoWidth, 11459 items = this.$stage.children(); 11460 11461 if ( grid && cache.items.merge ) { 11462 while ( iterator > 0 ) { 11463 iterator = iterator - 1; 11464 cache.css.width = this._widths[ this.relative( iterator ) ]; 11465 items.eq( iterator ).css( cache.css ); 11466 } 11467 } else if ( grid ) { 11468 cache.css.width = cache.items.width; 11469 items.css( cache.css ); 11470 } 11471 } 11472 }, 11473 { 11474 filter: [ 'items' ], 11475 run: function() { 11476 if ( this._coordinates.length < 1 ) { 11477 this.$stage.removeAttr( 'style' ); 11478 } 11479 } 11480 }, 11481 { 11482 filter: [ 'width', 'items', 'settings' ], 11483 run: function( cache ) { 11484 cache.current = cache.current ? this.$stage.children().index( cache.current ) : 0; 11485 cache.current = Math.max( this.minimum(), Math.min( this.maximum(), cache.current ) ); 11486 this.reset( cache.current ); 11487 } 11488 }, 11489 { 11490 filter: [ 'position' ], 11491 run: function() { 11492 this.animate( this.coordinates( this._current ) ); 11493 } 11494 }, 11495 { 11496 filter: [ 'width', 'position', 'items', 'settings' ], 11497 run: function() { 11498 var rtl = this.settings.rtl ? 1 : -1, 11499 padding = this.settings.stagePadding * 2, 11500 begin = this.coordinates( this.current() ) + padding, 11501 end = begin + ( this.width() * rtl ), 11502 inner, 11503 outer, 11504 matches = [], 11505 i, 11506 n; 11507 11508 for ( i = 0, n = this._coordinates.length; i < n; i += 1 ) { 11509 inner = this._coordinates[ i - 1 ] || 0; 11510 outer = Math.abs( this._coordinates[ i ] ) + ( padding * rtl ); 11511 11512 if ( ( this.op( inner, '<=', begin ) && this.op( inner, '>', end ) ) || ( this.op( outer, '<', begin ) && this.op( outer, '>', end ) ) ) { 11513 matches.push( i ); 11514 } 11515 } 11516 11517 this.$stage.children( '.active' ).removeClass( 'active' ); 11518 this.$stage.children( ':eq(' + matches.join( '), :eq(' ) + ')' ).addClass( 'active' ); 11519 11520 this.$stage.children( '.center' ).removeClass( 'center' ); 11521 if ( this.settings.center ) { 11522 this.$stage.children().eq( this.current() ).addClass( 'center' ); 11523 } 11524 } 11525 } 11526 ]; 11527 11528 /** 11529 * Create the stage DOM element 11530 */ 11531 Owl.prototype.initializeStage = function() { 11532 this.$stage = this.$element.find( '.' + this.settings.stageClass ); 11533 11534 // if the stage is already in the DOM, grab it and skip stage initialization 11535 if ( this.$stage.length ) { 11536 return; 11537 } 11538 11539 this.$element.addClass( this.options.loadingClass ); 11540 11541 // create stage 11542 this.$stage = $( '<' + this.settings.stageElement + '>', { 11543 class: this.settings.stageClass 11544 } ).wrap( 11545 $( '<div/>', { 11546 class: this.settings.stageOuterClass 11547 } ) 11548 ); 11549 11550 // append stage 11551 this.$element.append( this.$stage.parent() ); 11552 }; 11553 11554 /** 11555 * Create item DOM elements 11556 */ 11557 Owl.prototype.initializeItems = function() { 11558 var $items = this.$element.find( '.owl-item' ); 11559 11560 // if the items are already in the DOM, grab them and skip item initialization 11561 if ( $items.length ) { 11562 this._items = $items.get().map( function( item ) { 11563 return $( item ); 11564 } ); 11565 11566 this._mergers = this._items.map( function() { 11567 return 1; 11568 } ); 11569 11570 this.refresh(); 11571 11572 return; 11573 } 11574 11575 // append content 11576 this.replace( this.$element.children().not( this.$stage.parent() ) ); 11577 11578 // check visibility 11579 if ( this.isVisible() ) { 11580 // update view 11581 this.refresh(); 11582 } else { 11583 // invalidate width 11584 this.invalidate( 'width' ); 11585 } 11586 11587 this.$element.removeClass( this.options.loadingClass ).addClass( this.options.loadedClass ); 11588 }; 11589 11590 /** 11591 * Initializes the carousel. 11592 * 11593 * @protected 11594 */ 11595 Owl.prototype.initialize = function() { 11596 var imgs, nestedSelector, width; 11597 this.enter( 'initializing' ); 11598 this.trigger( 'initialize' ); 11599 11600 this.$element.toggleClass( this.settings.rtlClass, this.settings.rtl ); 11601 11602 if ( this.settings.autoWidth && ! this.is( 'pre-loading' ) ) {
vendor: 4,759 bytes, lines 11603-11791
11603 imgs = this.$element.find( 'img' ); 11604 nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined; 11605 width = this.$element.children( nestedSelector ).width(); 11606 11607 if ( imgs.length && width <= 0 ) { 11608 this.preloadAutoWidthImages( imgs ); 11609 } 11610 } 11611 11612 this.initializeStage(); 11613 this.initializeItems(); 11614 11615 // register event handlers 11616 this.registerEventHandlers(); 11617 11618 this.leave( 'initializing' ); 11619 this.trigger( 'initialized' ); 11620 }; 11621 11622 /** 11623 * @returns {boolean} visibility of $element 11624 * if you know the carousel will always be visible you can set `checkVisibility` to `false` to 11625 * prevent the expensive browser layout forced reflow the $element.is(':visible') does 11626 */ 11627 Owl.prototype.isVisible = function() { 11628 return this.settings.checkVisibility ? this.$element.is( ':visible' ) : true; 11629 }; 11630 11631 /** 11632 * Setups the current settings. 11633 * 11634 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8? 11635 * @todo Support for media queries by using `matchMedia` would be nice. 11636 * @public 11637 */ 11638 Owl.prototype.setup = function() { 11639 var viewport = this.viewport(), 11640 overwrites = this.options.responsive, 11641 match = -1, 11642 settings = null; 11643 11644 if ( ! overwrites ) { 11645 settings = $.extend( {}, this.options ); 11646 } else { 11647 $.each( overwrites, function( breakpoint ) { 11648 if ( breakpoint <= viewport && breakpoint > match ) { 11649 match = Number( breakpoint ); 11650 } 11651 } ); 11652 11653 settings = $.extend( {}, this.options, overwrites[ match ] ); 11654 if ( typeof settings.stagePadding === 'function' ) { 11655 settings.stagePadding = settings.stagePadding(); 11656 } 11657 delete settings.responsive; 11658 11659 // responsive class 11660 if ( settings.responsiveClass ) { 11661 this.$element.attr( 'class', this.$element.attr( 'class' ).replace( new RegExp( '(' + this.options.responsiveClass + '-)\\S+\\s', 'g' ), '$1' + match ) ); 11662 } 11663 } 11664 11665 this.trigger( 'change', { property: { name: 'settings', value: settings } } ); 11666 this._breakpoint = match; 11667 this.settings = settings; 11668 this.invalidate( 'settings' ); 11669 this.trigger( 'changed', { property: { name: 'settings', value: this.settings } } ); 11670 }; 11671 11672 /** 11673 * Updates option logic if necessery. 11674 * 11675 * @protected 11676 */ 11677 Owl.prototype.optionsLogic = function() { 11678 if ( this.settings.autoWidth ) { 11679 this.settings.stagePadding = false; 11680 this.settings.merge = false; 11681 } 11682 }; 11683 11684 /** 11685 * Prepares an item before add. 11686 * 11687 * @param {mixed} item 11688 * @todo Rename event parameter `content` to `item`. 11689 * @protected 11690 * @returns {jQuery|HTMLElement} - The item container. 11691 */ 11692 Owl.prototype.prepare = function( item ) { 11693 var event = this.trigger( 'prepare', { content: item } ); 11694 11695 if ( ! event.data ) { 11696 event.data = $( '<' + this.settings.itemElement + '/>' ) 11697 .addClass( this.options.itemClass ) 11698 .append( item ); 11699 } 11700 11701 this.trigger( 'prepared', { content: event.data } ); 11702 11703 return event.data; 11704 }; 11705 11706 /** 11707 * Updates the view. 11708 * 11709 * @public 11710 */ 11711 Owl.prototype.update = function() { 11712 var i = 0, 11713 n = this._pipe.length, 11714 filter = $.proxy( function( p ) { 11715 return this[ p ]; 11716 }, this._invalidated ), 11717 cache = {}; 11718 11719 while ( i < n ) { 11720 if ( this._invalidated.all || $.grep( this._pipe[ i ].filter, filter ).length > 0 ) { 11721 this._pipe[ i ].run( cache ); 11722 } 11723 i += 1; 11724 } 11725 11726 this._invalidated = {}; 11727 11728 if ( ! this.is( 'valid' ) ) { 11729 this.enter( 'valid' ); 11730 } 11731 }; 11732 11733 /** 11734 * Gets the width of the view. 11735 * 11736 * @public 11737 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return. 11738 * @returns {number} - The width of the view in pixel. 11739 */ 11740 Owl.prototype.width = function( dimension ) { 11741 dimension = dimension || Owl.Width.Default; 11742 switch ( dimension ) { 11743 case Owl.Width.Inner: 11744 case Owl.Width.Outer: 11745 return this._width; 11746 default: 11747 return this._width - ( this.settings.stagePadding * 2 ) + this.settings.margin; 11748 } 11749 }; 11750 11751 /** 11752 * Refreshes the carousel primarily for adaptive purposes. 11753 * 11754 * @public 11755 */ 11756 Owl.prototype.refresh = function() { 11757 this.enter( 'refreshing' ); 11758 this.trigger( 'refresh' ); 11759 11760 this.setup(); 11761 11762 this.optionsLogic(); 11763 11764 this.$element.addClass( this.options.refreshClass ); 11765 11766 this.update(); 11767 11768 this.$element.removeClass( this.options.refreshClass ); 11769 11770 this.leave( 'refreshing' ); 11771 this.trigger( 'refreshed' ); 11772 }; 11773 11774 /** 11775 * Checks window `resize` event. 11776 * 11777 * @protected 11778 */ 11779 Owl.prototype.onThrottledResize = function() { 11780 window.clearTimeout( this.resizeTimer ); 11781 this.resizeTimer = window.setTimeout( this._handlers.onResize, this.settings.responsiveRefreshRate ); 11782 }; 11783 11784 /** 11785 * Checks window `resize` event. 11786 * 11787 * @protected 11788 */ 11789 Owl.prototype.onResize = function() { 11790 if ( ! this._items.length ) { 11791 return false;
vendor: 5,296 bytes, lines 11792-11988
11792 } 11793 11794 if ( this._width === this.$element.width() ) { 11795 return false; 11796 } 11797 11798 if ( ! this.isVisible() ) { 11799 return false; 11800 } 11801 11802 this.enter( 'resizing' ); 11803 11804 if ( this.trigger( 'resize' ).isDefaultPrevented() ) { 11805 this.leave( 'resizing' ); 11806 return false; 11807 } 11808 11809 this.invalidate( 'width' ); 11810 11811 this.refresh(); 11812 11813 this.leave( 'resizing' ); 11814 this.trigger( 'resized' ); 11815 }; 11816 11817 /** 11818 * Registers event handlers. 11819 * 11820 * @todo Check `msPointerEnabled` 11821 * @todo #261 11822 * @protected 11823 */ 11824 Owl.prototype.registerEventHandlers = function() { 11825 if ( $.support.transition ) { 11826 this.$stage.on( $.support.transition.end + '.owl.core', $.proxy( this.onTransitionEnd, this ) ); 11827 } 11828 11829 if ( this.settings.responsive !== false ) { 11830 this.on( window, 'resize', this._handlers.onThrottledResize ); 11831 } 11832 11833 if ( this.settings.mouseDrag ) { 11834 this.$element.addClass( this.options.dragClass ); 11835 this.$stage.on( 'mousedown.owl.core', $.proxy( this.onDragStart, this ) ); 11836 this.$stage.on( 'dragstart.owl.core selectstart.owl.core', function() { 11837 return false; 11838 } ); 11839 } 11840 11841 if ( this.settings.touchDrag ) { 11842 this.$stage.on( 'touchstart.owl.core', $.proxy( this.onDragStart, this ) ); 11843 this.$stage.on( 'touchcancel.owl.core', $.proxy( this.onDragEnd, this ) ); 11844 } 11845 }; 11846 11847 /** 11848 * Handles `touchstart` and `mousedown` events. 11849 * 11850 * @todo Horizontal swipe threshold as option 11851 * @todo #261 11852 * @protected 11853 * @param {Event} event - The event arguments. 11854 */ 11855 Owl.prototype.onDragStart = function( event ) { 11856 var stage = null; 11857 11858 if ( event.which === 3 ) { 11859 return; 11860 } 11861 11862 if ( $.support.transform ) { 11863 stage = this.$stage 11864 .css( 'transform' ) 11865 .replace( /.*\(|\)| /g, '' ) 11866 .split( ',' ); 11867 stage = { 11868 x: stage[ stage.length === 16 ? 12 : 4 ], 11869 y: stage[ stage.length === 16 ? 13 : 5 ] 11870 }; 11871 } else { 11872 stage = this.$stage.position(); 11873 stage = { 11874 x: this.settings.rtl ? stage.left + this.$stage.width() - this.width() + this.settings.margin : stage.left, 11875 y: stage.top 11876 }; 11877 } 11878 11879 if ( this.is( 'animating' ) ) { 11880 if ( $.support.transform ) { 11881 this.animate( stage.x ); 11882 } else { 11883 this.$stage.stop(); 11884 } 11885 11886 this.invalidate( 'position' ); 11887 } 11888 11889 this.$element.toggleClass( this.options.grabClass, event.type === 'mousedown' ); 11890 11891 this.speed( 0 ); 11892 11893 this._drag.time = new Date().getTime(); 11894 this._drag.target = $( event.target ); 11895 this._drag.stage.start = stage; 11896 this._drag.stage.current = stage; 11897 this._drag.pointer = this.pointer( event ); 11898 11899 $( document ).on( 'mouseup.owl.core touchend.owl.core', $.proxy( this.onDragEnd, this ) ); 11900 11901 $( document ).one( 11902 'mousemove.owl.core touchmove.owl.core', 11903 $.proxy( function( e ) { 11904 var delta = this.difference( this._drag.pointer, this.pointer( e ) ); 11905 11906 $( document ).on( 'mousemove.owl.core touchmove.owl.core', $.proxy( this.onDragMove, this ) ); 11907 11908 if ( Math.abs( delta.x ) < Math.abs( delta.y ) && this.is( 'valid' ) ) { 11909 return; 11910 } 11911 11912 e.preventDefault(); 11913 11914 this.enter( 'dragging' ); 11915 this.trigger( 'drag' ); 11916 }, this ) 11917 ); 11918 }; 11919 11920 /** 11921 * Handles the `touchmove` and `mousemove` events. 11922 * 11923 * @todo #261 11924 * @protected 11925 * @param {Event} event - The event arguments. 11926 */ 11927 Owl.prototype.onDragMove = function( event ) { 11928 var minimum = null, 11929 maximum = null, 11930 pull = null, 11931 delta = this.difference( this._drag.pointer, this.pointer( event ) ), 11932 stage = this.difference( this._drag.stage.start, delta ); 11933 11934 if ( ! this.is( 'dragging' ) ) { 11935 return; 11936 } 11937 11938 event.preventDefault(); 11939 11940 if ( this.settings.loop ) { 11941 minimum = this.coordinates( this.minimum() ); 11942 maximum = this.coordinates( this.maximum() + 1 ) - minimum; 11943 stage.x = ( ( ( ( stage.x - minimum ) % maximum ) + maximum ) % maximum ) + minimum; 11944 } else { 11945 minimum = this.settings.rtl ? this.coordinates( this.maximum() ) : this.coordinates( this.minimum() ); 11946 maximum = this.settings.rtl ? this.coordinates( this.minimum() ) : this.coordinates( this.maximum() ); 11947 pull = this.settings.pullDrag ? ( -1 * delta.x ) / 5 : 0; 11948 stage.x = Math.max( Math.min( stage.x, minimum + pull ), maximum + pull ); 11949 } 11950 11951 this._drag.stage.current = stage; 11952 11953 this.animate( stage.x ); 11954 }; 11955 11956 /** 11957 * Handles the `touchend` and `mouseup` events. 11958 * 11959 * @todo #261 11960 * @todo Threshold for click event 11961 * @protected 11962 * @param {Event} event - The event arguments. 11963 */ 11964 Owl.prototype.onDragEnd = function( event ) { 11965 var delta = this.difference( this._drag.pointer, this.pointer( event ) ), 11966 stage = this._drag.stage.current, 11967 direction, 11968 isdeltax = delta.x > 0; 11969 if ( ( isdeltax && ! this.settings.rtl ) || ( this.settings.rtl && ! isdeltax ) ) { 11970 direction = 'left'; 11971 } else { 11972 direction = 'right'; 11973 } 11974 $( document ).off( '.owl.core' ); 11975 11976 this.$element.removeClass( this.options.grabClass ); 11977 11978 if ( ( delta.x !== 0 && this.is( 'dragging' ) ) || ! this.is( 'valid' ) ) { 11979 this.speed( this.settings.dragEndSpeed || this.settings.smartSpeed ); 11980 this.current( this.closest( stage.x, delta.x !== 0 ? direction : this._drag.direction ) ); 11981 this.invalidate( 'position' ); 11982 this.update(); 11983 11984 this._drag.direction = direction; 11985 11986 if ( Math.abs( delta.x ) > 3 || new Date().getTime() - this._drag.time > 300 ) { 11987 this._drag.target.one( 'click.owl.core', function() { 11988 return false;
11989 } ); 11990 } 11991 } 11992 11993 if ( ! this.is( 'dragging' ) ) { 11994 return; 11995 } 11996 11997 this.leave( 'dragging' ); 11998 this.trigger( 'dragged' ); 11999 }; 12000 12001 /** 12002 * Gets absolute position of the closest item for a coordinate. 12003 * 12004 * @todo Setting `freeDrag` makes `closest` not reusable. See #165. 12005 * @protected 12006 * @param {number} coordinate - The coordinate in pixel. 12007 * @param {string} direction - The direction to check for the closest item. Ether `left` or `right`. 12008 * @return {number} - The absolute position of the closest item. 12009 */ 12010 Owl.prototype.closest = function( coordinate, direction ) { 12011 var position = -1, 12012 pull = 30, 12013 width = this.width(), 12014 coordinates = this.coordinates(); 12015 12016 if ( ! this.settings.freeDrag ) { 12017 // check closest item 12018 $.each( 12019 coordinates, 12020 $.proxy( function( index, value ) { 12021 // on a left pull, check on current index 12022 if ( direction === 'left' && coordinate > value - pull && coordinate < value + pull ) { 12023 position = index; 12024 // on a right pull, check on previous index 12025 // to do so, subtract width from value and set position = index + 1 12026 } else if ( direction === 'right' && coordinate > value - width - pull && coordinate < value - width + pull ) { 12027 position = index + 1; 12028 } else if ( this.op( coordinate, '<', value ) && this.op( coordinate, '>', coordinates[ index + 1 ] !== undefined ? coordinates[ index + 1 ] : value - width ) ) { 12029 position = direction === 'left' ? index + 1 : index; 12030 } 12031 return position === -1; 12032 }, this ) 12033 ); 12034 } 12035 12036 if ( ! this.settings.loop ) { 12037 // non loop boundries 12038 if ( this.op( coordinate, '>', coordinates[ this.minimum() ] ) ) { 12039 coordinate = this.minimum(); 12040 position = coordinate; 12041 } else if ( this.op( coordinate, '<', coordinates[ this.maximum() ] ) ) { 12042 coordinate = this.maximum(); 12043 position = coordinate; 12044 } 12045 } 12046 12047 return position; 12048 }; 12049 12050 /** 12051 * Animates the stage. 12052 * 12053 * @todo #270 12054 * @public 12055 * @param {number} coordinate - The coordinate in pixels. 12056 */ 12057 Owl.prototype.animate = function( coordinate ) { 12058 var animate = this.speed() > 0; 12059 12060 if ( this.is( 'animating' ) ) { 12061 this.onTransitionEnd(); 12062 } 12063 12064 if ( animate ) { 12065 this.enter( 'animating' ); 12066 this.trigger( 'translate' ); 12067 } 12068 12069 if ( $.support.transform3d && $.support.transition ) { 12070 this.$stage.css( { 12071 transform: 'translate3d(' + coordinate + 'px,0px,0px)', 12072 transition: ( this.speed() / 1000 ) + 's' + ( this.settings.slideTransition ? ' ' + this.settings.slideTransition : '' ) 12073 } ); 12074 } else if ( animate ) { 12075 this.$stage.animate( 12076 { 12077 left: coordinate + 'px' 12078 }, 12079 this.speed(), 12080 this.settings.fallbackEasing, 12081 $.proxy( this.onTransitionEnd, this ) 12082 ); 12083 } else { 12084 this.$stage.css( { 12085 left: coordinate + 'px' 12086 } ); 12087 } 12088 }; 12089 12090 /** 12091 * Checks whether the carousel is in a specific state or not. 12092 * 12093 * @param {string} state - The state to check. 12094 * @returns {boolean} - The flag which indicates if the carousel is busy. 12095 */ 12096 Owl.prototype.is = function( state ) { 12097 return this._states.current[ state ] && this._states.current[ state ] > 0; 12098 }; 12099 12100 /** 12101 * Sets the absolute position of the current item. 12102 * 12103 * @public 12104 * @param {number} [position] - The new absolute position or nothing to leave it unchanged. 12105 * @returns {number} - The absolute position of the current item. 12106 */ 12107 Owl.prototype.current = function( position ) { 12108 var event; 12109 if ( position === undefined ) { 12110 return this._current; 12111 } 12112 12113 if ( this._items.length === 0 ) { 12114 return undefined; 12115 } 12116 12117 position = this.normalize( position ); 12118 12119 if ( this._current !== position ) { 12120 event = this.trigger( 'change', { property: { name: 'position', value: position } } ); 12121 12122 if ( event.data !== undefined ) { 12123 position = this.normalize( event.data ); 12124 } 12125 12126 this._current = position; 12127 12128 this.invalidate( 'position' ); 12129 12130 this.trigger( 'changed', { property: { name: 'position', value: this._current } } ); 12131 } 12132 12133 return this._current; 12134 }; 12135 12136 /** 12137 * Invalidates the given part of the update routine. 12138 * 12139 * @param {string} [part] - The part to invalidate. 12140 * @returns {Array.<string>} - The invalidated parts. 12141 */ 12142 Owl.prototype.invalidate = function( part ) { 12143 if ( typeof part === 'string' ) { 12144 this._invalidated[ part ] = true; 12145 if ( this.is( 'valid' ) ) { 12146 this.leave( 'valid' ); 12147 } 12148 } 12149 return $.map( this._invalidated, function( v, i ) { 12150 return i; 12151 } ); 12152 }; 12153 12154 /** 12155 * Resets the absolute position of the current item. 12156 * 12157 * @public 12158 * @param {number} position - The absolute position of the new item. 12159 */ 12160 Owl.prototype.reset = function( position ) { 12161 position = this.normalize( position ); 12162 12163 if ( position === undefined ) { 12164 return; 12165 } 12166 12167 this._speed = 0; 12168 this._current = position; 12169 12170 this.suppress( [ 'translate', 'translated' ] ); 12171 12172 this.animate( this.coordinates( position ) ); 12173 12174 this.release( [ 'translate', 'translated' ] ); 12175 }; 12176 12177 /** 12178 * Normalizes an absolute or a relative position of an item. 12179 * 12180 * @public 12181 * @param {number} position - The absolute or relative position to normalize. 12182 * @param {boolean} [relative=false] - Whether the given position is relative or not. 12183 * @returns {number} - The normalized position. 12184 */ 12185 Owl.prototype.normalize = function( position, relative ) { 12186 var n = this._items.length, 12187 m = relative ? 0 : this._clones.length; 12188 12189 if ( ! this.isNumeric( position ) || n < 1 ) { 12190 position = undefined; 12191 } else if ( position < 0 || position >= n + m ) { 12192 position = ( ( ( ( position - ( m / 2 ) ) % n ) + n ) % n ) + ( m / 2 ); 12193 } 12194 12195 return position; 12196 }; 12197 12198 /** 12199 * Converts an absolute position of an item into a relative one. 12200 * 12201 * @public 12202 * @param {number} position - The absolute position to convert. 12203 * @returns {number} - The converted position. 12204 */ 12205 Owl.prototype.relative = function( position ) { 12206 position -= this._clones.length / 2; 12207 return this.normalize( position, true ); 12208 }; 12209 12210 /** 12211 * Gets the maximum position for the current item. 12212 * 12213 * @public 12214 * @param {boolean} [relative=false] - Whether to return an absolute position or a relative position. 12215 * @returns {number} 12216 */ 12217 Owl.prototype.maximum = function( relative ) { 12218 var settings = this.settings, 12219 maximum = this._coordinates.length, 12220 iterator, 12221 reciprocalItemsWidth, 12222 elementWidth; 12223 12224 if ( settings.loop ) { 12225 maximum = ( this._clones.length / 2 ) + this._items.length - 1; 12226 } else if ( settings.autoWidth || settings.merge ) { 12227 iterator = this._items.length; 12228 if ( iterator ) { 12229 iterator = iterator - 1; 12230 reciprocalItemsWidth = this._items[ iterator ].width(); 12231 elementWidth = this.$element.width(); 12232 while ( iterator > 0 ) { 12233 reciprocalItemsWidth += this._items[ iterator ].width() + this.settings.margin; 12234 if ( reciprocalItemsWidth > elementWidth ) { 12235 break; 12236 } 12237 iterator = iterator - 1; 12238 } 12239 } 12240 maximum = iterator + 1; 12241 } else if ( settings.center ) { 12242 maximum = this._items.length - 1; 12243 } else { 12244 maximum = this._items.length - settings.items; 12245 } 12246 12247 if ( relative ) { 12248 maximum -= this._clones.length / 2; 12249 } 12250 12251 return Math.max( maximum, 0 ); 12252 }; 12253 12254 /** 12255 * Gets the minimum position for the current item. 12256 * 12257 * @public 12258 * @param {boolean} [relative=false] - Whether to return an absolute position or a relative position. 12259 * @returns {number} 12260 */ 12261 Owl.prototype.minimum = function( relative ) { 12262 return relative ? 0 : this._clones.length / 2; 12263 }; 12264 12265 /** 12266 * Gets an item at the specified relative position. 12267 * 12268 * @public 12269 * @param {number} [position] - The relative position of the item. 12270 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given. 12271 */ 12272 Owl.prototype.items = function( position ) { 12273 if ( position === undefined ) { 12274 return this._items.slice(); 12275 } 12276 12277 position = this.normalize( position, true ); 12278 return this._items[ position ]; 12279 }; 12280 12281 /** 12282 * Gets an item at the specified relative position. 12283 * 12284 * @public 12285 * @param {number} [position] - The relative position of the item. 12286 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given. 12287 */ 12288 Owl.prototype.mergers = function( position ) { 12289 if ( position === undefined ) { 12290 return this._mergers.slice(); 12291 } 12292 12293 position = this.normalize( position, true ); 12294 return this._mergers[ position ]; 12295 }; 12296 12297 /** 12298 * Gets the absolute positions of clones for an item. 12299 * 12300 * @public 12301 * @param {number} [position] - The relative position of the item. 12302 * @returns {Array.<number>} - The absolute positions of clones for the item or all if no position was given. 12303 */ 12304 Owl.prototype.clones = function( position ) { 12305 var odd = this._clones.length / 2, 12306 even = odd + this._items.length, 12307 map = function( index ) { 12308 return index % 2 === 0 ? even + ( index / 2 ) : odd - ( ( index + 1 ) / 2 ); 12309 }; 12310 12311 if ( position === undefined ) { 12312 return $.map( this._clones, function( v, i ) { 12313 return map( i ); 12314 } ); 12315 } 12316 12317 return $.map( this._clones, function( v, i ) { 12318 return v === position ? map( i ) : null; 12319 } ); 12320 }; 12321 12322 /** 12323 * Sets the current animation speed. 12324 * 12325 * @public 12326 * @param {number}
12326 [speed] - The animation speed in milliseconds or nothing to leave it unchanged. 12327 * @returns {number} - The current animation speed in milliseconds. 12328 */ 12329 Owl.prototype.speed = function( speed ) { 12330 if ( speed !== undefined ) { 12331 this._speed = speed; 12332 } 12333 12334 return this._speed; 12335 }; 12336 12337 /** 12338 * Gets the coordinate of an item. 12339 * 12340 * @todo The name of this method is missleanding. 12341 * @public 12342 * @param {number} position - The absolute position of the item within `minimum()` and `maximum()`. 12343 * @returns {number|Array.<number>} - The coordinate of the item in pixel or all coordinates. 12344 */ 12345 Owl.prototype.coordinates = function( position ) { 12346 var multiplier = 1, 12347 newPosition = position - 1, 12348 coordinate; 12349 12350 if ( position === undefined ) { 12351 return $.map( 12352 this._coordinates, 12353 $.proxy( function( scoordinate, index ) { 12354 return this.coordinates( index ); 12355 }, this ) 12356 ); 12357 } 12358 12359 if ( this.settings.center ) { 12360 if ( this.settings.rtl ) { 12361 multiplier = -1; 12362 newPosition = position + 1; 12363 } 12364 12365 coordinate = this._coordinates[ position ]; 12366 coordinate += ( ( this.width() - coordinate + ( this._coordinates[ newPosition ] || 0 ) ) / 2 ) * multiplier; 12367 } else { 12368 coordinate = this._coordinates[ newPosition ] || 0; 12369 } 12370 12371 coordinate = Math.ceil( coordinate ); 12372 12373 return coordinate; 12374 }; 12375 12376 /** 12377 * Calculates the speed for a translation. 12378 * 12379 * @protected 12380 * @param {number} from - The absolute position of the start item. 12381 * @param {number} to - The absolute position of the target item. 12382 * @param {number} [factor=undefined] - The time factor in milliseconds. 12383 * @returns {number} - The time in milliseconds for the translation. 12384 */ 12385 Owl.prototype.duration = function( from, to, factor ) { 12386 if ( factor === 0 ) { 12387 return 0; 12388 } 12389 12390 return Math.min( Math.max( Math.abs( to - from ), 1 ), 6 ) * Math.abs( factor || this.settings.smartSpeed ); 12391 }; 12392 12393 /** 12394 * Slides to the specified item. 12395 * 12396 * @public 12397 * @param {number} position - The position of the item. 12398 * @param {number} [speed] - The time in milliseconds for the transition. 12399 */ 12400 Owl.prototype.to = function( position, speed ) { 12401 var current = this.current(), 12402 revert = null, 12403 distance = position - this.relative( current ), 12404 direction = ( distance > 0 ) - ( distance < 0 ), 12405 items = this._items.length, 12406 minimum = this.minimum(), 12407 maximum = this.maximum(); 12408 12409 if ( this.settings.loop ) { 12410 if ( ! this.settings.rewind && Math.abs( distance ) > items / 2 ) { 12411 distance += direction * -1 * items; 12412 } 12413 12414 position = current + distance; 12415 revert = ( ( ( ( position - minimum ) % items ) + items ) % items ) + minimum; 12416 12417 if ( revert !== position && revert - distance <= maximum && revert - distance > 0 ) { 12418 current = revert - distance; 12419 position = revert; 12420 this.reset( current ); 12421 } 12422 } else if ( this.settings.rewind ) { 12423 maximum += 1; 12424 position = ( ( position % maximum ) + maximum ) % maximum; 12425 } else { 12426 position = Math.max( minimum, Math.min( maximum, position ) ); 12427 } 12428 12429 this.speed( this.duration( current, position, speed ) ); 12430 this.current( position ); 12431 12432 if ( this.isVisible() ) { 12433 this.update(); 12434 } 12435 }; 12436 12437 /** 12438 * Slides to the next item. 12439 * 12440 * @public 12441 * @param {number} [speed] - The time in milliseconds for the transition. 12442 */ 12443 Owl.prototype.next = function( speed ) { 12444 speed = speed || false; 12445 this.to( this.relative( this.current() ) + 1, speed ); 12446 }; 12447 12448 /** 12449 * Slides to the previous item. 12450 * 12451 * @public 12452 * @param {number} [speed] - The time in milliseconds for the transition. 12453 */ 12454 Owl.prototype.prev = function( speed ) { 12455 speed = speed || false; 12456 this.to( this.relative( this.current() ) - 1, speed ); 12457 }; 12458 12459 /** 12460 * Handles the end of an animation. 12461 * 12462 * @protected 12463 * @param {Event} event - The event arguments. 12464 */ 12465 Owl.prototype.onTransitionEnd = function( event ) { 12466 // if css2 animation then event object is undefined 12467 if ( event !== undefined ) { 12468 event.stopPropagation(); 12469 12470 // Catch only owl-stage transitionEnd event 12471 if ( ( event.target || event.srcElement || event.originalTarget ) !== this.$stage.get( 0 ) ) { 12472 return false;
12473 } 12474 } 12475 12476 this.leave( 'animating' ); 12477 this.trigger( 'translated' ); 12478 }; 12479 12480 /** 12481 * Gets viewport width. 12482 * 12483 * @protected 12484 * @return {number} - The width in pixel. 12485 */ 12486 Owl.prototype.viewport = function() { 12487 var width; 12488 if ( this.options.responsiveBaseElement !== window ) { 12489 width = $( this.options.responsiveBaseElement ).width(); 12490 } else if ( window.innerWidth ) { 12491 width = window.innerWidth; 12492 } else if ( document.documentElement && document.documentElement.clientWidth ) { 12493 width = document.documentElement.clientWidth; 12494 } else { 12495 //Cannot detect viewport width 12496 return width; 12497 } 12498 return width; 12499 }; 12500 12501 /** 12502 * Replaces the current content. 12503 * 12504 * @public 12505 * @param {HTMLElement|jQuery|string} content - The new content. 12506 */ 12507 Owl.prototype.replace = function( content ) { 12508 this.$stage.empty(); 12509 this._items = []; 12510 12511 if ( content ) { 12512 content = content instanceof window.jQuery ? content : $( content ); 12513 } 12514 12515 if ( this.settings.nestedItemSelector ) { 12516 content = content.find( '.' + this.settings.nestedItemSelector ); 12517 } 12518 12519 content 12520 .filter( function() { 12521 return this.nodeType === 1; 12522 } ) 12523 .each( 12524 $.proxy( function( index, item ) { 12525 item = this.prepare( item ); 12526 this.$stage.append( item ); 12527 this._items.push( item ); 12528 this._mergers.push( item.find( '[data-merge]' ).addBack( '[data-merge]' ).attr( 'data-merge' ) * 1 || 1 ); 12529 }, this ) 12530 ); 12531 12532 this.reset( this.isNumeric( this.settings.startPosition ) ? this.settings.startPosition : 0 ); 12533 12534 this.invalidate( 'items' ); 12535 }; 12536 12537 /** 12538 * Adds an item. 12539 * 12540 * @todo Use `item` instead of `content` for the event arguments. 12541 * @public 12542 * @param {HTMLElement|jQuery|string} content - The item content to add. 12543 * @param {number} [position] - The relative position at which to insert the item otherwise the item will be added to the end. 12544 */ 12545 Owl.prototype.add = function( content, position ) { 12546 var current = this.relative( this._current ); 12547 12548 position = position === undefined ? this._items.length : this.normalize( position, true ); 12549 content = content instanceof window.jQuery ? content : $( content ); 12550 12551 this.trigger( 'add', { content: content, position: position } ); 12552 12553 content = this.prepare( content ); 12554 12555 if ( this._items.length === 0 || position === this._items.length ) { 12556 if ( this._items.length === 0 ) { 12557 this.$stage.append( content ); 12558 } 12559 if ( this._items.length !== 0 ) { 12560 this._items[ position - 1 ].after( content ); 12561 } 12562 this._items.push( content ); 12563 this._mergers.push( content.find( '[data-merge]' ).addBack( '[data-merge]' ).attr( 'data-merge' ) * 1 || 1 ); 12564 } else { 12565 this._items[ position ].before( content ); 12566 this._items.splice( position, 0, content ); 12567 this._mergers.splice( position, 0, content.find( '[data-merge]' ).addBack( '[data-merge]' ).attr( 'data-merge' ) * 1 || 1 ); 12568 } 12569 12570 if ( this._items[ current ] ) { 12571 this.reset( this._items[ current ].index() ); 12572 } 12573 12574 this.invalidate( 'items' ); 12575 12576 this.trigger( 'added', { content: content, position: position } ); 12577 }; 12578 12579 /** 12580 * Removes an item by its position. 12581 * 12582 * @todo Use `item` instead of `content` for the event arguments. 12583 * @public 12584 * @param {number} position - The relative position of the item to remove. 12585 */ 12586 Owl.prototype.remove = function( position ) { 12587 position = this.normalize( position, true ); 12588 12589 if ( position === undefined ) { 12590 return; 12591 } 12592 12593 this.trigger( 'remove', { content: this._items[ position ], position: position } ); 12594 12595 this._items[ position ].remove(); 12596 this._items.splice( position, 1 ); 12597 this._mergers.splice( position, 1 ); 12598 12599 this.invalidate( 'items' ); 12600 12601 this.trigger( 'removed', { content: null, position: position } ); 12602 }; 12603 12604 /** 12605 * Preloads images with auto width. 12606 * 12607 * @param {mixed} images 12608 * @todo Replace by a more generic approach 12609 * @protected 12610 */ 12611 Owl.prototype.preloadAutoWidthImages = function( images ) { 12612 images.each( 12613 $.proxy( function( i, element ) { 12614 this.enter( 'pre-loading' ); 12615 element = $( element ); 12616 $( new Image() ) 12617 .one( 12618 'load', 12619 $.proxy( function( e ) { 12620 element.attr( 'src', e.target.src ); 12621 element.css( 'opacity', 1 ); 12622 this.leave( 'pre-loading' ); 12623 if ( ! this.is( 'pre-loading' ) && ! this.is( 'initializing' ) ) { 12624 this.refresh(); 12625 } 12626 }, this ) 12627 ) 12628 .attr( 'src', element.attr( 'src' ) || element.attr( 'data-src' ) || element.attr( 'data-src-retina' ) ); 12629 }, this ) 12630 ); 12631 }; 12632 12633 /** 12634 * Destroys the carousel. 12635 * 12636 * @public 12637 */ 12638 Owl.prototype.destroy = function() { 12639 this.$element.off( '.owl.core' ); 12640 this.$stage.off( '.owl.core' ); 12641 $( document ).off( '.owl.core' ); 12642 12643 if ( this.settings.responsive !== false ) { 12644 window.clearTimeout( this.resizeTimer ); 12645 this.off( window, 'resize', this._handlers.onThrottledResize ); 12646 } 12647 12648 $.map( this._plugins, function( value ) { 12649 return value; 12650 } ).forEach( function( inst ) { 12651 if ( inst ) { 12652 inst.destroy(); 12653 } 12654 } ); 12655 12656 this.$stage.children( '.cloned' ).remove(); 12657 12658 this.$stage.unwrap(); 12659 this.$stage.children().contents().unwrap(); 12660 this.$stage.children().unwrap(); 12661 this.$stage.remove(); 12662 this.$element 12663 .removeClass( this.options.refreshClass ) 12664 .removeClass( this.options.loadingClass ) 12665 .removeClass( this.options.loadedClass ) 12666 .removeClass( this.options.rtlClass ) 12667 .removeClass( this.options.dragClass ) 12668 .removeClass( this.options.grabClass ) 12669 .attr( 'class', this.$element.attr( 'class' ).replace( new RegExp( this.options.responsiveClass + '-\\S+\\s', 'g' ), '' ) ) 12670 .removeData( 'owl.carousel' ); 12671 }; 12672 12673 /** 12674 * Operators to calculate right-to-left and left-to-right. 12675 * 12676 * @protected 12677 * @param {number} [a] - The left side operand. 12678 * @param {string} [o] - The operator. 12679 * @param {number} [b] - The right side operand. 12680 */ 12681 Owl.prototype.op = function( a, o, b ) { 12682 var rtl = this.settings.rtl; 12683 switch ( o ) { 12684 case '<': 12685 return rtl ? a > b : a < b; 12686 case '>': 12687 return rtl ? a < b : a > b; 12688 case '>=': 12689 return rtl ? a <= b : a >= b; 12690 case '<=': 12691 return rtl ? a >= b : a <= b; 12692 default: 12693 break; 12694 } 12695 }; 12696 12697 /** 12698 * Attaches to an internal event. 12699 * 12700 * @protected 12701 * @param {HTMLElement} element - The event source. 12702 * @param {string} event - The event name. 12703 * @param {Function} listener - The event handler to attach. 12704 * @param {boolean}
vendor: 6,218 bytes, lines 12704-12928
12704 capture - Wether the event should be handled at the capturing phase or not. 12705 */ 12706 Owl.prototype.on = function( element, event, listener, capture ) { 12707 if ( element.addEventListener ) { 12708 element.addEventListener( event, listener, capture ); 12709 } else if ( element.attachEvent ) { 12710 element.attachEvent( 'on' + event, listener ); 12711 } 12712 }; 12713 12714 /** 12715 * Detaches from an internal event. 12716 * 12717 * @protected 12718 * @param {HTMLElement} element - The event source. 12719 * @param {string} event - The event name. 12720 * @param {Function} listener - The attached event handler to detach. 12721 * @param {boolean} capture - Wether the attached event handler was registered as a capturing listener or not. 12722 */ 12723 Owl.prototype.off = function( element, event, listener, capture ) { 12724 if ( element.removeEventListener ) { 12725 element.removeEventListener( event, listener, capture ); 12726 } else if ( element.detachEvent ) { 12727 element.detachEvent( 'on' + event, listener ); 12728 } 12729 }; 12730 12731 /** 12732 * Triggers a public event. 12733 * 12734 * @todo Remove `status`, `relatedTarget` should be used instead. 12735 * @protected 12736 * @param {string} name - The event name. 12737 * @param {*} [data=null] - The event data. 12738 * @param {string} [namespace=carousel] - The event namespace. 12739 * @returns {Event} - The event arguments. 12740 */ 12741 Owl.prototype.trigger = function( name, data, namespace ) { 12742 var status = { 12743 item: { count: this._items.length, index: this.current() } 12744 }, 12745 handler = $.camelCase( 12746 $.grep( [ 'on', name, namespace ], function( v ) { 12747 return v; 12748 } ) 12749 .join( '-' ) 12750 .toLowerCase() 12751 ), 12752 /*eslint new-cap: [2, {capIsNewExceptions: ["Event"]}]*/ 12753 event = $.Event( [ name, 'owl', namespace || 'carousel' ].join( '.' ).toLowerCase(), $.extend( { relatedTarget: this }, status, data ) ); 12754 12755 if ( ! this._supress[ name ] ) { 12756 $.each( this._plugins, function( sname, plugin ) { 12757 if ( plugin.onTrigger ) { 12758 plugin.onTrigger( event ); 12759 } 12760 } ); 12761 12762 this.register( { type: Owl.Type.Event, name: name } ); 12763 this.$element.trigger( event ); 12764 12765 if ( this.settings && typeof this.settings[ handler ] === 'function' ) { 12766 this.settings[ handler ].call( this, event ); 12767 } 12768 } 12769 12770 return event; 12771 }; 12772 12773 /** 12774 * Enters a state. 12775 * 12776 * @param {mixed} name - The state name. 12777 */ 12778 Owl.prototype.enter = function( name ) { 12779 $.each( 12780 [ name ].concat( this._states.tags[ name ] || [] ), 12781 $.proxy( function( i, sname ) { 12782 if ( this._states.current[ sname ] === undefined ) { 12783 this._states.current[ sname ] = 0; 12784 } 12785 12786 this._states.current[ sname ] += 1; 12787 }, this ) 12788 ); 12789 }; 12790 12791 /** 12792 * Leaves a state. 12793 * 12794 * @param {mixed} name - The state name. 12795 */ 12796 Owl.prototype.leave = function( name ) { 12797 $.each( 12798 [ name ].concat( this._states.tags[ name ] || [] ), 12799 $.proxy( function( i, sname ) { 12800 this._states.current[ sname ] -= 1; 12801 }, this ) 12802 ); 12803 }; 12804 12805 /** 12806 * Registers an event or state. 12807 * 12808 * @public 12809 * @param {Object} object - The event or state to register. 12810 */ 12811 Owl.prototype.register = function( object ) { 12812 var _default; 12813 if ( object.type === Owl.Type.Event ) { 12814 if ( ! $.event.special[ object.name ] ) { 12815 $.event.special[ object.name ] = {}; 12816 } 12817 12818 if ( ! $.event.special[ object.name ].owl ) { 12819 _default = $.event.special[ object.name ]._default; 12820 $.event.special[ object.name ]._default = function( e ) { 12821 if ( _default && _default.apply && ( ! e.namespace || e.namespace.indexOf( 'owl' ) === -1 ) ) { 12822 return _default.apply( this, arguments ); 12823 } 12824 return e.namespace && e.namespace.indexOf( 'owl' ) > -1; 12825 }; 12826 $.event.special[ object.name ].owl = true; 12827 } 12828 } else if ( object.type === Owl.Type.State ) { 12829 if ( ! this._states.tags[ object.name ] ) { 12830 this._states.tags[ object.name ] = object.tags; 12831 } else { 12832 this._states.tags[ object.name ] = this._states.tags[ object.name ].concat( object.tags ); 12833 } 12834 12835 this._states.tags[ object.name ] = $.grep( 12836 this._states.tags[ object.name ], 12837 $.proxy( function( tag, i ) { 12838 return $.inArray( tag, this._states.tags[ object.name ] ) === i; 12839 }, this ) 12840 ); 12841 } 12842 }; 12843 12844 /** 12845 * Suppresses events. 12846 * 12847 * @protected 12848 * @param {Array.<string>} events - The events to suppress. 12849 */ 12850 Owl.prototype.suppress = function( events ) { 12851 $.each( 12852 events, 12853 $.proxy( function( index, event ) { 12854 this._supress[ event ] = true; 12855 }, this ) 12856 ); 12857 }; 12858 12859 /** 12860 * Releases suppressed events. 12861 * 12862 * @protected 12863 * @param {Array.<string>} events - The events to release. 12864 */ 12865 Owl.prototype.release = function( events ) { 12866 $.each( 12867 events, 12868 $.proxy( function( index, event ) { 12869 delete this._supress[ event ]; 12870 }, this ) 12871 ); 12872 }; 12873 12874 /** 12875 * Gets unified pointer coordinates from event. 12876 * 12877 * @todo #261 12878 * @protected 12879 * @param {Event} event The `mousedown` or `touchstart` event. 12880 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position. 12881 */ 12882 Owl.prototype.pointer = function( event ) { 12883 var result = { x: null, y: null }; 12884 12885 event = event.originalEvent || event || window.event; 12886 12887 event = event.touches && event.touches.length ? event.touches[ 0 ] : event.changedTouches && event.changedTouches.length ? event.changedTouches[ 0 ] : event; 12888 12889 if ( event.pageX ) { 12890 result.x = event.pageX; 12891 result.y = event.pageY; 12892 } else { 12893 result.x = event.clientX; 12894 result.y = event.clientY; 12895 } 12896 12897 return result; 12898 }; 12899 12900 /** 12901 * Determines if the input is a Number or something that can be coerced to a Number 12902 * 12903 * @protected 12904 * @param {number|string|Object|Array|boolean|RegExp|Function|symbol} number The input to be tested 12905 * @returns {boolean} - An indication if the input is a Number or can be coerced to a Number 12906 */ 12907 Owl.prototype.isNumeric = function( number ) { 12908 return ! isNaN( parseFloat( number ) ); 12909 }; 12910 12911 /** 12912 * Gets the difference of two vectors. 12913 * 12914 * @todo #261 12915 * @protected 12916 * @param {Object} first The first vector. 12917 * @param {Object} second The second vector. 12918 * @returns {Object} - The difference. 12919 */ 12920 Owl.prototype.difference = function( first, second ) { 12921 return { 12922 x: first.x - second.x, 12923 y: first.y - second.y 12924 }; 12925 }; 12926 12927 /** 12928 * The jQuery Plugin for the Owl Carousel
12929 * 12930 * @param {mixed} option 12931 * @todo Navigation plugin `next` and `prev` 12932 * @public 12933 */ 12934 $.fn.tmowlCarousel = function( option ) { 12935 var args = Array.prototype.slice.call( arguments, 1 ); 12936 12937 return this.each( function() { 12938 var $this = $( this ), 12939 data = $this.data( 'owl.carousel' ); 12940 12941 if ( ! data ) { 12942 data = new Owl( this, typeof option === 'object' && option ); 12943 $this.data( 'owl.carousel', data ); 12944 12945 $.each( [ 'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove' ], function( i, event ) { 12946 data.register( { type: Owl.Type.Event, name: event } ); 12947 data.$element.on( 12948 event + '.owl.carousel.core', 12949 $.proxy( function( e ) { 12950 if ( e.namespace && e.relatedTarget !== this ) { 12951 this.suppress( [ event ] ); 12952 data[ event ].apply( this, [].slice.call( arguments, 1 ) ); 12953 this.release( [ event ] ); 12954 } 12955 }, data ) 12956 ); 12957 } ); 12958 } 12959 12960 if ( typeof option === 'string' && option.charAt( 0 ) !== '_' ) { 12961 data[ option ].apply( data, args ); 12962 } 12963 } ); 12964 }; 12965 12966 /** 12967 * The constructor for the jQuery Plugin 12968 * 12969 * @public 12970 */ 12971 $.fn.tmowlCarousel.Constructor = Owl; 12972}( window.Zepto || window.jQuery, window, document ) ); 12973 12974/** 12975 * AutoRefresh Plugin 12976 * 12977 * @param {jQuery} $ 12978 * @param {Window} window 12979 * @version 2.3.4 12980 * @author Artus Kolanowski 12981 * @author David Deutsch 12982 * @license The MIT License (MIT) 12983 */ 12984( function( $, window ) { 12985 'use strict'; 12986 /** 12987 * Creates the auto refresh plugin. 12988 * 12989 * @class The Auto Refresh Plugin 12990 * @param {Owl} carousel - The Owl Carousel 12991 */ 12992 var AutoRefresh = function( carousel ) { 12993 /** 12994 * Reference to the core. 12995 * 12996 * @protected 12997 * @type {Owl} 12998 */ 12999 this._core = carousel; 13000 13001 /** 13002 * Refresh interval. 13003 * 13004 * @protected 13005 * @type {number} 13006 */ 13007 this._interval = null; 13008 13009 /** 13010 * Whether the element is currently visible or not. 13011 * 13012 * @protected 13013 * @type {boolean} 13014 */ 13015 this._visible = null; 13016 13017 /** 13018 * All event handlers. 13019 * 13020 * @protected 13021 * @type {Object} 13022 */ 13023 this._handlers = { 13024 'initialized.owl.carousel': $.proxy( function( e ) { 13025 if ( e.namespace && this._core.settings.autoRefresh ) { 13026 this.watch(); 13027 } 13028 }, this ) 13029 }; 13030 13031 // set default options 13032 this._core.options = $.extend( {}, AutoRefresh.Defaults, this._core.options ); 13033 13034 // register event handlers 13035 this._core.$element.on( this._handlers ); 13036 }; 13037 13038 /** 13039 * Default options. 13040 * 13041 * @public 13042 */ 13043 AutoRefresh.Defaults = { 13044 autoRefresh: true, 13045 autoRefreshInterval: 500 13046 }; 13047 13048 /** 13049 * Watches the element. 13050 */ 13051 AutoRefresh.prototype.watch = function() { 13052 if ( this._interval ) { 13053 return; 13054 } 13055 13056 this._visible = this._core.isVisible(); 13057 this._interval = window.setInterval( $.proxy( this.refresh, this ), this._core.settings.autoRefreshInterval ); 13058 }; 13059 13060 /** 13061 * Refreshes the element. 13062 */ 13063 AutoRefresh.prototype.refresh = function() { 13064 if ( this._core.isVisible() === this._visible ) { 13065 return; 13066 } 13067 13068 this._visible = ! this._visible; 13069 13070 this._core.$element.toggleClass( 'owl-hidden', ! this._visible ); 13071 13072 if ( this._visible && this._core.invalidate( 'width' ) ) { 13073 this._core.refresh(); 13074 } 13075 }; 13076 13077 /** 13078 * Destroys the plugin. 13079 */ 13080 AutoRefresh.prototype.destroy = function() { 13081 var handler, property; 13082 13083 window.clearInterval( this._interval ); 13084 13085 for ( handler in this._handlers ) { 13086 if ( handler ) { 13087 this._core.$element.off( handler, this._handlers[ handler ] ); 13088 } 13089 } 13090 for ( property in Object.getOwnPropertyNames( this ) ) { 13091 if ( typeof this[ property ] !== 'function' ) { 13092 this[ property ] = null; 13093 } 13094 } 13095 }; 13096 13097 $.fn.tmowlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh; 13098}( window.Zepto || window.jQuery, window ) ); 13099 13100/** 13101 * Lazy Plugin 13102 * 13103 * @param {jQuery} $ 13104 * @param {Window} window 13105 * @version 2.3.4 13106 * @author Bartosz Wojciechowski 13107 * @author David Deutsch 13108 * @license The MIT License (MIT) 13109 */ 13110( function( $, window ) { 13111 'use strict'; 13112 /** 13113 * Creates the lazy plugin. 13114 * 13115 * @class The Lazy Plugin 13116 * @param {Owl} carousel - The Owl Carousel 13117 */ 13118 var Lazy = function( carousel ) { 13119 /** 13120 * Reference to the core. 13121 * 13122 * @protected 13123 * @type {Owl} 13124 */ 13125 this._core = carousel; 13126 13127 /** 13128 * Already loaded items. 13129 * 13130 * @protected 13131 * @type {Array.<jQuery>} 13132 */ 13133 this._loaded = []; 13134 13135 /** 13136 * Event handlers. 13137 * 13138 * @protected 13139 * @type {Object} 13140 */ 13141 this._handlers = { 13142 'initialized.owl.carousel change.owl.carousel resized.owl.carousel': $.proxy( function( e ) { 13143 var settings; 13144 var n; 13145 var i; 13146 var position; 13147 var clones; 13148 var load; 13149 13150 if ( ! e.namespace ) { 13151 return; 13152 } 13153 13154 if ( ! this._core.settings || ! this._core.settings.lazyLoad ) { 13155 return; 13156 } 13157 13158 if ( ( e.property && e.property.name === 'position' ) || e.type === 'initialized' ) { 13159 settings = this._core.settings; 13160 n = ( settings.center && Math.ceil( settings.items / 2 ) ) || settings.items; 13161 i = ( settings.center && n * -1 ) || 0; 13162 position = ( e.property && e.property.value !== undefined ? e.property.value : this._core.current() ) + i; 13163 clones = this._core.clones().length; 13164 load = $.proxy( function( ii, v ) { 13165 this.load( v ); 13166 }, this ); 13167 //TODO: Need documentation for this new option 13168 if ( settings.lazyLoadEager > 0 ) { 13169 n += settings.lazyLoadEager; 13170 // If the carousel is looping also preload images that are to the "left" 13171 if ( settings.loop ) { 13172 position -= settings.lazyLoadEager; 13173 n += 1; 13174 } 13175 } 13176 13177 while ( i < n ) { 13178 i += 1; 13179 this.load( ( clones / 2 ) + this._core.relative( position ) ); 13180 if ( clones ) { 13181 $.each( this._core.clones( this._core.relative( position ) ), load ); 13182 } 13183 position += 1; 13184 } 13185 } 13186 }, this ) 13187 }; 13188 13189 // set the default options 13190 this._core.options = $.extend( {}, Lazy.Defaults, this._core.options ); 13191 13192 // register event handler 13193 this._core.$element.on( this._handlers ); 13194 }; 13195 13196 /** 13197 * Default options. 13198 * 13199 * @public 13200 */ 13201 Lazy.Defaults = { 13202 lazyLoad: false, 13203 lazyLoadEager: 0 13204 }; 13205 13206 /** 13207 * Loads all resources of an item at the specified position. 13208 * 13209 * @param {number} position - The absolute position of the item. 13210 * @protected 13211 */ 13212 Lazy.prototype.load = function( position ) { 13213 var $item = this._core.$stage.children().eq( position ), 13214 $elements = $item && $item.find( '.owl-lazy' ); 13215 13216 if ( ! $elements || $.inArray( $item.get( 0 ), this._loaded ) > -1 ) { 13217 return; 13218 } 13219 13220 $elements.each( 13221 $.proxy( function( index, element ) { 13222 var $element = $( element ), 13223 image, 13224 url = ( window.devicePixelRatio > 1 && $element.attr( 'data-src-retina' ) ) || $element.attr( 'data-src' ) || $element.attr( 'data-srcset' ); 13225 13226 this._core.trigger( 'load', { element: $element, url: url }, 'lazy' ); 13227 13228 if ( $element.is( 'img' ) ) { 13229 $element 13230 .one( 13231 'load.owl.lazy', 13232 $.proxy( function() { 13233 $element.css( 'opacity', 1 ); 13234 this._core.trigger( 'loaded', { element: $element, url: url }, 'lazy' ); 13235 }, this ) 13236 ) 13237 .attr( 'src', url ); 13238 } else if ( $element.is( 'source' ) ) { 13239 $element 13240 .one( 13241 'load.owl.lazy', 13242 $.proxy( function() { 13243 this._core.trigger( 'loaded', { element: $element, url: url }, 'lazy' ); 13244 }, this ) 13245 ) 13246 .attr( 'srcset', url ); 13247 } else { 13248 image = new Image(); 13249 image.onload = $.proxy( function() { 13250 $element.css( { 13251 'background-image': 'url("' + url + '")', 13252 opacity: '1' 13253 } ); 13254 this._core.trigger( 'loaded', { element: $element, url: url }, 'lazy' ); 13255 }, this ); 13256 image.src = url; 13257 } 13258 }, this ) 13259 ); 13260 13261 this._loaded.push( $item.get( 0 ) ); 13262 }; 13263 13264 /** 13265 * Destroys the plugin. 13266 * 13267 * @public 13268 */ 13269 Lazy.prototype.destroy = function() { 13270 var handler, property; 13271 13272 for ( handler in this.handlers ) { 13273 if ( handler ) { 13274 this._core.$element.off( handler, this.handlers[ handler ] ); 13275 } 13276 } 13277 for ( property in Object.getOwnPropertyNames( this ) ) { 13278 if ( typeof this[ property ] !== 'function' ) { 13279 this[ property ] = null; 13280 } 13281 } 13282 }; 13283
13284 $.fn.tmowlCarousel.Constructor.Plugins.Lazy = Lazy; 13285}( window.Zepto || window.jQuery, window ) ); 13286 13287/** 13288 * AutoHeight Plugin 13289 * 13290 * @param {jQuery} $ 13291 * @param {Window} window 13292 * @version 2.3.4 13293 * @author Bartosz Wojciechowski 13294 * @author David Deutsch 13295 * @license The MIT License (MIT) 13296 */ 13297( function( $, window ) { 13298 'use strict'; 13299 /** 13300 * Creates the auto height plugin. 13301 * 13302 * @class The Auto Height Plugin 13303 * @param {Owl} carousel - The Owl Carousel 13304 */ 13305 var AutoHeight = function( carousel ) { 13306 var refThis = this; 13307 /** 13308 * Reference to the core. 13309 * 13310 * @protected 13311 * @type {Owl} 13312 */ 13313 this._core = carousel; 13314 13315 this._previousHeight = null; 13316 13317 /** 13318 * All event handlers. 13319 * 13320 * @protected 13321 * @type {Object} 13322 */ 13323 this._handlers = { 13324 'initialized.owl.carousel refreshed.owl.carousel': $.proxy( function( e ) { 13325 if ( e.namespace && this._core.settings.autoHeight ) { 13326 this.update(); 13327 } 13328 }, this ), 13329 'changed.owl.carousel': $.proxy( function( e ) { 13330 if ( e.namespace && this._core.settings.autoHeight && e.property.name === 'position' ) { 13331 this.update(); 13332 } 13333 }, this ), 13334 'loaded.owl.lazy': $.proxy( function( e ) { 13335 if ( e.namespace && this._core.settings.autoHeight && e.element.closest( '.' + this._core.settings.itemClass ).index() === this._core.current() ) { 13336 this.update(); 13337 } 13338 }, this ) 13339 }; 13340 13341 // set default options 13342 this._core.options = $.extend( {}, AutoHeight.Defaults, this._core.options ); 13343 13344 // register event handlers 13345 this._core.$element.on( this._handlers ); 13346 this._intervalId = null; 13347 13348 // These changes have been taken from a PR by gavrochelegnou proposed in #1575 13349 // and have been made compatible with the latest jQuery version 13350 $( window ).on( 'load', function() { 13351 if ( refThis._core.settings.autoHeight ) { 13352 refThis.update(); 13353 } 13354 } ); 13355 13356 // Autoresize the height of the carousel when window is resized 13357 // When carousel has images, the height is dependent on the width 13358 // and should also change on resize 13359 $( window ).on( 'resize', function() { 13360 if ( refThis._core.settings.autoHeight ) { 13361 if ( refThis._intervalId !== null ) { 13362 clearTimeout( refThis._intervalId ); 13363 } 13364 13365 refThis._intervalId = setTimeout( function() { 13366 refThis.update(); 13367 }, 250 ); 13368 } 13369 } ); 13370 }; 13371 13372 /** 13373 * Default options. 13374 * 13375 * @public 13376 */ 13377 AutoHeight.Defaults = { 13378 autoHeight: false, 13379 autoHeightClass: 'owl-height' 13380 }; 13381 13382 /** 13383 * Updates the view. 13384 */ 13385 AutoHeight.prototype.update = function() { 13386 var start = this._core._current, 13387 end = start + this._core.settings.items, 13388 lazyLoadEnabled = this._core.settings.lazyLoad, 13389 visible = this._core.$stage.children().toArray().slice( start, end ), 13390 heights = [], 13391 maxheight = 0; 13392 13393 $.each( visible, function( index, item ) { 13394 heights.push( $( item ).height() ); 13395 } ); 13396 13397 maxheight = Math.max.apply( null, heights ); 13398 13399 if ( maxheight <= 1 && lazyLoadEnabled && this._previousHeight ) { 13400 maxheight = this._previousHeight; 13401 } 13402 13403 this._previousHeight = maxheight; 13404 13405 this._core.$stage.parent().height( maxheight ).addClass( this._core.settings.autoHeightClass ); 13406 }; 13407 13408 AutoHeight.prototype.destroy = function() { 13409 var handler, property; 13410 13411 for ( handler in this._handlers ) { 13412 if ( handler ) { 13413 this._core.$element.off( handler, this._handlers[ handler ] ); 13414 } 13415 } 13416 for ( property in Object.getOwnPropertyNames( this ) ) { 13417 if ( typeof this[ property ] !== 'function' ) { 13418 this[ property ] = null; 13419 } 13420 } 13421 }; 13422 13423 $.fn.tmowlCarousel.Constructor.Plugins.AutoHeight = AutoHeight; 13424}( window.Zepto || window.jQuery ) ); 13425 13426/** 13427 * Video Plugin 13428 * 13429 * @param {jQuery} $ 13430 * @param {Window} window 13431 * @param {Document} document 13432 * @version 2.3.4 13433 * @author Bartosz Wojciechowski 13434 * @author David Deutsch 13435 * @license The MIT License (MIT) 13436 */ 13437( function( $, window, document ) { 13438 'use strict'; 13439 /** 13440 * Creates the video plugin. 13441 * 13442 * @class The Video Plugin 13443 * @param {Owl} carousel - The Owl Carousel 13444 */ 13445 var Video = function( carousel ) { 13446 /** 13447 * Reference to the core. 13448 * 13449 * @protected 13450 * @type {Owl} 13451 */ 13452 this._core = carousel; 13453 13454 /** 13455 * Cache all video URLs.
vendor: 4,085 bytes, lines 13456-13598
13456 * 13457 * @protected 13458 * @type {Object} 13459 */ 13460 this._videos = {}; 13461 13462 /** 13463 * Current playing item. 13464 * 13465 * @protected 13466 * @type {jQuery} 13467 */ 13468 this._playing = null; 13469 13470 /** 13471 * All event handlers. 13472 * 13473 * @todo The cloned content removale is too late 13474 * @protected 13475 * @type {Object} 13476 */ 13477 this._handlers = { 13478 'initialized.owl.carousel': $.proxy( function( e ) { 13479 if ( e.namespace ) { 13480 this._core.register( { type: 'state', name: 'playing', tags: [ 'interacting' ] } ); 13481 } 13482 }, this ), 13483 'resize.owl.carousel': $.proxy( function( e ) { 13484 if ( e.namespace && this._core.settings.video && this.isInFullScreen() ) { 13485 e.preventDefault(); 13486 } 13487 }, this ), 13488 'refreshed.owl.carousel': $.proxy( function( e ) { 13489 if ( e.namespace && this._core.is( 'resizing' ) ) { 13490 this._core.$stage.find( '.cloned .owl-video-frame' ).remove(); 13491 } 13492 }, this ), 13493 'changed.owl.carousel': $.proxy( function( e ) { 13494 if ( e.namespace && e.property.name === 'position' && this._playing ) { 13495 this.stop(); 13496 } 13497 }, this ), 13498 'prepared.owl.carousel': $.proxy( function( e ) { 13499 var $element; 13500 if ( ! e.namespace ) { 13501 return; 13502 } 13503 13504 $element = $( e.content ).find( '.owl-video' ); 13505 13506 if ( $element.length ) { 13507 $element.css( 'display', 'none' ); 13508 this.fetch( $element, $( e.content ) ); 13509 } 13510 }, this ) 13511 }; 13512 13513 // set default options 13514 this._core.options = $.extend( {}, Video.Defaults, this._core.options ); 13515 13516 // register event handlers 13517 this._core.$element.on( this._handlers ); 13518 13519 this._core.$element.on( 13520 'click.owl.video', 13521 '.owl-video-play-icon', 13522 $.proxy( function( e ) { 13523 this.play( e ); 13524 }, this ) 13525 ); 13526 }; 13527 13528 /** 13529 * Default options. 13530 * 13531 * @public 13532 */ 13533 Video.Defaults = { 13534 video: false, 13535 videoHeight: false, 13536 videoWidth: false 13537 }; 13538 13539 /** 13540 * Gets the video ID and the type (YouTube/Vimeo/vzaar only). 13541 * 13542 * @protected 13543 * @param {jQuery} target - The target containing the video data. 13544 * @param {jQuery} item - The item containing the video. 13545 */ 13546 Video.prototype.fetch = function( target, item ) { 13547 var type = ( function() { 13548 if ( target.attr( 'data-vimeo-id' ) ) { 13549 return 'vimeo'; 13550 } else if ( target.attr( 'data-vzaar-id' ) ) { 13551 return 'vzaar'; 13552 } 13553 return 'youtube'; 13554 }() ), 13555 id = target.attr( 'data-vimeo-id' ) || target.attr( 'data-youtube-id' ) || target.attr( 'data-vzaar-id' ), 13556 width = target.attr( 'data-width' ) || this._core.settings.videoWidth, 13557 height = target.attr( 'data-height' ) || this._core.settings.videoHeight, 13558 url = target.attr( 'href' ); 13559 13560 if ( url ) { 13561 /* 13562 Parses the id's out of the following urls (and probably more): 13563 https://www.youtube.com/watch?v=:id 13564 https://youtu.be/:id 13565 https://vimeo.com/:id 13566 https://vimeo.com/channels/:channel/:id 13567 https://vimeo.com/groups/:group/videos/:id 13568 https://app.vzaar.com/videos/:id 13569 13570 Visual example: https://regexper.com/#(http%3A%7Chttps%3A%7C)%5C%2F%5C%2F(player.%7Cwww.%7Capp.)%3F(vimeo%5C.com%7Cyoutu(be%5C.com%7C%5C.be%7Cbe%5C.googleapis%5C.com)%7Cvzaar%5C.com)%5C%2F(video%5C%2F%7Cvideos%5C%2F%7Cembed%5C%2F%7Cchannels%5C%2F.%2B%5C%2F%7Cgroups%5C%2F.%2B%5C%2F%7Cwatch%5C%3Fv%3D%7Cv%5C%2F)%3F(%5BA-Za-z0-9._%25-%5D*)(%5C%26%5CS%2B)%3F 13571 */ 13572 13573 id = url.match( 13574 // eslint-disable-next-line no-useless-escape 13575 /(http:|https:|)\/\/(player.|www.|app.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com|be\-nocookie\.com)|vzaar\.com)\/(video\/|videos\/|embed\/|channels\/.+\/|groups\/.+\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/ 13576 ); 13577 13578 if ( id[ 3 ].indexOf( 'youtu' ) > -1 ) { 13579 type = 'youtube'; 13580 } else if ( id[ 3 ].indexOf( 'vimeo' ) > -1 ) { 13581 type = 'vimeo'; 13582 } else if ( id[ 3 ].indexOf( 'vzaar' ) > -1 ) { 13583 type = 'vzaar'; 13584 } else { 13585 throw new Error( 'Video URL not supported.' ); 13586 } 13587 id = id[ 6 ]; 13588 } else { 13589 throw new Error( 'Missing video URL.' ); 13590 } 13591 13592 this._videos[ url ] = { 13593 type: type, 13594 id: id, 13595 width: width, 13596 height: height 13597 }; 13598
13599 item.attr( 'data-video', url ); 13600 13601 this.thumbnail( target, this._videos[ url ] ); 13602 }; 13603 13604 /** 13605 * Creates video thumbnail. 13606 * 13607 * @protected 13608 * @param {jQuery} target The target containing the video data. 13609 * @param {Object} video The video info object. 13610 * @see `fetch` 13611 */ 13612 Video.prototype.thumbnail = function( target, video ) { 13613 var tnLink, 13614 icon, 13615 path, 13616 dimensions = video.width && video.height ? 'width:' + video.width + 'px;height:' + video.height + 'px;' : '', 13617 customTn = target.find( 'img' ), 13618 srcType = 'src', 13619 lazyClass = '', 13620 settings = this._core.settings, 13621 create = function( thispath ) { 13622 icon = '<div class="owl-video-play-icon"></div>'; 13623 13624 if ( settings.lazyLoad ) { 13625 tnLink = $( '<div/>', { 13626 class: 'owl-video-tn ' + lazyClass, 13627 srcType: thispath 13628 } ); 13629 } else { 13630 tnLink = $( '<div/>', { 13631 class: 'owl-video-tn', 13632 style: 'opacity:1;background-image:url(' + thispath + ')' 13633 } ); 13634 } 13635 target.after( tnLink ); 13636 target.after( icon ); 13637 }; 13638 13639 // wrap video content into owl-video-wrapper div 13640 target.wrap( 13641 $( '<div/>', { 13642 class: 'owl-video-wrapper', 13643 style: dimensions 13644 } ) 13645 ); 13646 13647 if ( this._core.settings.lazyLoad ) { 13648 srcType = 'data-src'; 13649 lazyClass = 'owl-lazy'; 13650 } 13651 13652 // custom thumbnail 13653 if ( customTn.length ) { 13654 create( customTn.attr( srcType ) ); 13655 customTn.remove(); 13656 return false; 13657 } 13658 13659 if ( video.type === 'youtube' ) { 13660 path = '//img.youtube.com/vi/' + video.id + '/hqdefault.jpg'; 13661 create( path ); 13662 } else if ( video.type === 'vimeo' ) { 13663 $.ajax( { 13664 type: 'GET', 13665 url: '//vimeo.com/api/v2/video/' + video.id + '.json', 13666 jsonp: 'callback', 13667 dataType: 'jsonp', 13668 success: function( data ) { 13669 path = data[ 0 ].thumbnail_large; 13670 create( path ); 13671 } 13672 } ); 13673 } else if ( video.type === 'vzaar' ) { 13674 $.ajax( { 13675 type: 'GET', 13676 url: '//vzaar.com/api/videos/' + video.id + '.json', 13677 jsonp: 'callback', 13678 dataType: 'jsonp', 13679 success: function( data ) { 13680 path = data.framegrab_url; 13681 create( path ); 13682 } 13683 } ); 13684 } 13685 }; 13686 13687 /** 13688 * Stops the current video. 13689 * 13690 * @public 13691 */ 13692 Video.prototype.stop = function() { 13693 this._core.trigger( 'stop', null, 'video' ); 13694 this._playing.find( '.owl-video-frame' ).remove(); 13695 this._playing.removeClass( 'owl-video-playing' ); 13696 this._playing = null; 13697 this._core.leave( 'playing' ); 13698 this._core.trigger( 'stopped', null, 'video' ); 13699 }; 13700 13701 /** 13702 * Starts the current video. 13703 * 13704 * @public 13705 * @param {Event} event - The event arguments. 13706 */ 13707 Video.prototype.play = function( event ) { 13708 var target = $( event.target ), 13709 item = target.closest( '.' + this._core.settings.itemClass ), 13710 video = this._videos[ item.attr( 'data-video' ) ], 13711 width = video.width || '100%', 13712 height = video.height || this._core.$stage.height(), 13713 html; 13714 13715 if ( this._playing ) { 13716 return; 13717 } 13718 13719 this._core.enter( 'playing' ); 13720 this._core.trigger( 'play', null, 'video' ); 13721 13722 item = this._core.items( this._core.relative( item.index() ) ); 13723 13724 this._core.reset( item.index() ); 13725 13726 html = $( '<iframe frameborder="0" allowfullscreen mozallowfullscreen webkitAllowFullScreen ></iframe>' ); 13727 html.attr( 'height', height ); 13728 html.attr( 'width', width ); 13729 if ( video.type === 'youtube' ) { 13730 html.attr( 'src', '//www.youtube.com/embed/' + video.id + '?autoplay=1&rel=0&v=' + video.id ); 13731 } else if ( video.type === 'vimeo' ) { 13732 html.attr( 'src', '//player.vimeo.com/video/' + video.id + '?autoplay=1' ); 13733 } else if ( video.type === 'vzaar' ) { 13734 html.attr( 'src', '//view.vzaar.com/' + video.id + '/player?autoplay=true' ); 13735 } 13736 13737 $( html ).wrap( '<div class="owl-video-frame" />' ).insertAfter( item.find( '.owl-video' ) ); 13738 13739 this._playing = item.addClass( 'owl-video-playing' ); 13740 }; 13741 13742 /** 13743 * Checks whether an video is currently in full screen mode or not. 13744 * 13745 * @todo Bad style because looks like a readonly method but changes members. 13746 * @protected 13747 * @returns {boolean} 13748 */ 13749 Video.prototype.isInFullScreen = function() { 13750 var element = document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement; 13751 13752 return element && $( element ).parent().hasClass( 'owl-video-frame' ); 13753 }; 13754 13755 /** 13756 * Destroys the plugin. 13757 */ 13758 Video.prototype.destroy = function() { 13759 var handler, property; 13760 13761 this._core.$element.off( 'click.owl.video' ); 13762 13763 for ( handler in this._handlers ) { 13764 if ( handler ) { 13765 this._core.$element.off( handler, this._handlers[ handler ] ); 13766 } 13767 } 13768 for ( property in Object.getOwnPropertyNames( this ) ) { 13769 if ( typeof this[ property ] !== 'function' ) { 13770 this[ property ] = null; 13771 } 13772 } 13773 }; 13774 13775 $.fn.tmowlCarousel.Constructor.Plugins.Video = Video; 13776}( window.Zepto || window.jQuery, window, document ) ); 13777 13778/** 13779 * Animate Plugin 13780 * 13781 * @param {jQuery} $ 13782 * @version 2.3.4 13783 * @author Bartosz Wojciechowski 13784 * @author David Deutsch 13785 * @license The MIT License (MIT) 13786 */ 13787( function( $ ) { 13788 'use strict'; 13789 /** 13790 * Creates the animate plugin. 13791 * 13792 * @class The Navigation Plugin 13793 * @param {Owl} scope - The Owl Carousel
13794 */ 13795 var Animate = function( scope ) { 13796 this.core = scope; 13797 this.core.options = $.extend( {}, Animate.Defaults, this.core.options ); 13798 this.swapping = true; 13799 this.previous = undefined; 13800 this.next = undefined; 13801 13802 this.handlers = { 13803 'change.owl.carousel': $.proxy( function( e ) { 13804 if ( e.namespace && e.property.name === 'position' ) { 13805 this.previous = this.core.current(); 13806 this.next = e.property.value; 13807 } 13808 }, this ), 13809 'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy( function( e ) { 13810 if ( e.namespace ) { 13811 this.swapping = e.type === 'translated'; 13812 } 13813 }, this ), 13814 'translate.owl.carousel': $.proxy( function( e ) { 13815 if ( e.namespace && this.swapping && ( this.core.options.animateOut || this.core.options.animateIn ) ) { 13816 this.swap(); 13817 } 13818 }, this ) 13819 }; 13820 13821 this.core.$element.on( this.handlers ); 13822 }; 13823 13824 /** 13825 * Default options. 13826 * 13827 * @public 13828 */ 13829 Animate.Defaults = { 13830 animateOut: false, 13831 animateIn: false 13832 }; 13833 13834 /** 13835 * Toggles the animation classes whenever an translations starts. 13836 * 13837 * @protected 13838 * @returns {boolean|undefined} 13839 */ 13840 Animate.prototype.swap = function() { 13841 var left, clear, previous, next, incoming, outgoing; 13842 if ( this.core.settings.items !== 1 ) { 13843 return; 13844 } 13845 13846 if ( ! $.support.animation || ! $.support.transition ) { 13847 return; 13848 } 13849 13850 this.core.speed( 0 ); 13851 13852 clear = $.proxy( this.clear, this ); 13853 previous = this.core.$stage.children().eq( this.previous ); 13854 next = this.core.$stage.children().eq( this.next ); 13855 incoming = this.core.settings.animateIn; 13856 outgoing = this.core.settings.animateOut; 13857 13858 if ( this.core.current() === this.previous ) { 13859 return; 13860 } 13861 13862 if ( outgoing ) { 13863 left = this.core.coordinates( this.previous ) - this.core.coordinates( this.next ); 13864 previous 13865 .one( $.support.animation.end, clear ) 13866 .css( { left: left + 'px' } ) 13867 .addClass( 'animated owl-animated-out' ) 13868 .addClass( outgoing ); 13869 } 13870 13871 if ( incoming ) { 13872 next.one( $.support.animation.end, clear ).addClass( 'animated owl-animated-in' ).addClass( incoming ); 13873 } 13874 }; 13875 13876 Animate.prototype.clear = function( e ) { 13877 $( e.target ).css( { left: '' } ).removeClass( 'animated owl-animated-out owl-animated-in' ).removeClass( this.core.settings.animateIn ).removeClass( this.core.settings.animateOut ); 13878 this.core.onTransitionEnd(); 13879 }; 13880 13881 /** 13882 * Destroys the plugin. 13883 * 13884 * @public 13885 */ 13886 Animate.prototype.destroy = function() { 13887 var handler, property; 13888 13889 for ( handler in this.handlers ) { 13890 if ( handler ) { 13891 this.core.$element.off( handler, this.handlers[ handler ] ); 13892 } 13893 } 13894 for ( property in Object.getOwnPropertyNames( this ) ) { 13895 if ( typeof this[ property ] !== 'function' ) { 13896 this[ property ] = null; 13897 } 13898 } 13899 }; 13900 13901 $.fn.tmowlCarousel.Constructor.Plugins.Animate = Animate; 13902}( window.Zepto || window.jQuery ) ); 13903 13904/** 13905 * Autoplay Plugin 13906 * 13907 * @param {jQuery} $ 13908 * @param {Window} window 13909 * @param {Document} document 13910 * @version 2.3.4 13911 * @author Bartosz Wojciechowski 13912 * @author Artus Kolanowski 13913 * @author David Deutsch 13914 * @author Tom De Caluwé 13915 * @license The MIT License (MIT) 13916 */ 13917( function( $, window, document ) { 13918 'use strict'; 13919 /** 13920 * Creates the autoplay plugin. 13921 * 13922 * @class The Autoplay Plugin 13923 * @param {Owl} carousel The Owl Carousel 13924 */ 13925 var Autoplay = function( carousel ) { 13926 /** 13927 * Reference to the core. 13928 * 13929 * @protected 13930 * @type {Owl} 13931 */ 13932 this._core = carousel; 13933 13934 /** 13935 * The autoplay timeout id. 13936 * 13937 * @type {number} 13938 */ 13939 this._call = null; 13940 13941 /** 13942 * Depending on the state of the plugin, this variable contains either 13943 * the start time of the timer or the current timer value if it's 13944 * paused. Since we start in a paused state we initialize the timer 13945 * value. 13946 * 13947 * @type {number} 13948 */ 13949 this._time = 0; 13950 13951 /** 13952 * Stores the timeout currently used. 13953 * 13954 * @type {number} 13955 */ 13956 this._timeout = 0; 13957 13958 /** 13959 * Indicates whenever the autoplay is paused. 13960 * 13961 * @type {boolean} 13962 */ 13963 this._paused = true; 13964 13965 /** 13966 * All event handlers. 13967 * 13968 * @protected 13969 * @type {Object} 13970 */ 13971 this._handlers = { 13972 'changed.owl.carousel': $.proxy( function( e ) { 13973 if ( e.namespace && e.property.name === 'settings' ) { 13974 if ( this._core.settings.autoplay ) { 13975 this.play(); 13976 } else { 13977 this.stop(); 13978 } 13979 } else if ( e.namespace && e.property.name === 'position' && this._paused ) { 13980 // Reset the timer. This code is triggered when the position 13981 // of the carousel was changed through user interaction. 13982 this._time = 0; 13983 } 13984 }, this ), 13985 'initialized.owl.carousel': $.proxy( function( e ) { 13986 if ( e.namespace && this._core.settings.autoplay ) { 13987 this.play(); 13988 } 13989 }, this ), 13990 'play.owl.autoplay': $.proxy( function( e, t, s ) { 13991 if ( e.namespace ) { 13992 this.play( t, s ); 13993 } 13994 }, this ), 13995 'stop.owl.autoplay': $.proxy( function( e ) { 13996 if ( e.namespace ) { 13997 this.stop(); 13998 } 13999 }, this ), 14000 'mouseover.owl.autoplay': $.proxy( function() { 14001 if ( this._core.settings.autoplayHoverPause && this._core.is( 'rotating' ) ) { 14002 this.pause(); 14003 } 14004 }, this ), 14005 'mouseleave.owl.autoplay': $.proxy( function() { 14006 if ( this._core.settings.autoplayHoverPause && this._core.is( 'rotating' ) ) { 14007 this.play(); 14008 } 14009 }, this ), 14010 'touchstart.owl.core': $.proxy( function() { 14011 if ( this._core.settings.autoplayHoverPause && this._core.is( 'rotating' ) ) { 14012 this.pause(); 14013 } 14014 }, this ), 14015 'touchend.owl.core': $.proxy( function() { 14016 if ( this._core.settings.autoplayHoverPause ) { 14017 this.play(); 14018 } 14019 }, this ) 14020 }; 14021 14022 // register event handlers 14023 this._core.$element.on( this._handlers ); 14024 14025 // set default options 14026 this._core.options = $.extend( {}, Autoplay.Defaults, this._core.options ); 14027 }; 14028 14029 /** 14030 * Default options. 14031 * 14032 * @public 14033 */ 14034 Autoplay.Defaults = { 14035 autoplay: false, 14036 autoplayTimeout: 5000, 14037 autoplayHoverPause: false, 14038 autoplaySpeed: false 14039 }; 14040 14041 /** 14042 * Transition to the next slide and set a timeout for the next transition. 14043 * 14044 * @private 14045 * @param {number}
vendor: 7,927 bytes, lines 14045-14358
14045 [speed] - The animation speed for the animations. 14046 */ 14047 Autoplay.prototype._next = function( speed ) { 14048 this._call = window.setTimeout( $.proxy( this._next, this, speed ), ( this._timeout * ( Math.round( this.read() / this._timeout ) + 1 ) ) - this.read() ); 14049 14050 if ( this._core.is( 'interacting' ) || document.hidden ) { 14051 return; 14052 } 14053 this._core.next( speed || this._core.settings.autoplaySpeed ); 14054 }; 14055 14056 /** 14057 * Reads the current timer value when the timer is playing. 14058 * 14059 * @public 14060 */ 14061 Autoplay.prototype.read = function() { 14062 return new Date().getTime() - this._time; 14063 }; 14064 14065 /** 14066 * Starts the autoplay. 14067 * 14068 * @public 14069 * @param {number} [timeout] - The interval before the next animation starts. 14070 * @param {number} [speed] - The animation speed for the animations. 14071 */ 14072 Autoplay.prototype.play = function( timeout, speed ) { 14073 var elapsed; 14074 14075 if ( ! this._core.is( 'rotating' ) ) { 14076 this._core.enter( 'rotating' ); 14077 } 14078 14079 timeout = timeout || this._core.settings.autoplayTimeout; 14080 14081 // Calculate the elapsed time since the last transition. If the carousel 14082 // wasn't playing this calculation will yield zero. 14083 elapsed = Math.min( this._time % ( this._timeout || timeout ), timeout ); 14084 14085 if ( this._paused ) { 14086 // Start the clock. 14087 this._time = this.read(); 14088 this._paused = false; 14089 } else { 14090 // Clear the active timeout to allow replacement. 14091 window.clearTimeout( this._call ); 14092 } 14093 14094 // Adjust the origin of the timer to match the new timeout value. 14095 this._time += ( this.read() % timeout ) - elapsed; 14096 14097 this._timeout = timeout; 14098 this._call = window.setTimeout( $.proxy( this._next, this, speed ), timeout - elapsed ); 14099 }; 14100 14101 /** 14102 * Stops the autoplay. 14103 * 14104 * @public 14105 */ 14106 Autoplay.prototype.stop = function() { 14107 if ( this._core.is( 'rotating' ) ) { 14108 // Reset the clock. 14109 this._time = 0; 14110 this._paused = true; 14111 14112 window.clearTimeout( this._call ); 14113 this._core.leave( 'rotating' ); 14114 } 14115 }; 14116 14117 /** 14118 * Pauses the autoplay. 14119 * 14120 * @public 14121 */ 14122 Autoplay.prototype.pause = function() { 14123 if ( this._core.is( 'rotating' ) && ! this._paused ) { 14124 // Pause the clock. 14125 this._time = this.read(); 14126 this._paused = true; 14127 14128 window.clearTimeout( this._call ); 14129 } 14130 }; 14131 14132 /** 14133 * Destroys the plugin. 14134 */ 14135 Autoplay.prototype.destroy = function() { 14136 var handler, property; 14137 14138 this.stop(); 14139 14140 for ( handler in this._handlers ) { 14141 if ( handler ) { 14142 this._core.$element.off( handler, this._handlers[ handler ] ); 14143 } 14144 } 14145 for ( property in Object.getOwnPropertyNames( this ) ) { 14146 if ( typeof this[ property ] !== 'function' ) { 14147 this[ property ] = null; 14148 } 14149 } 14150 }; 14151 14152 $.fn.tmowlCarousel.Constructor.Plugins.autoplay = Autoplay; 14153}( window.Zepto || window.jQuery, window, document ) ); 14154 14155/** 14156 * Navigation Plugin 14157 * 14158 * @param {jQuery} $ 14159 * @version 2.3.4 14160 * @author Artus Kolanowski 14161 * @author David Deutsch 14162 * @license The MIT License (MIT) 14163 */ 14164( function( $ ) { 14165 'use strict'; 14166 14167 /** 14168 * Creates the navigation plugin. 14169 * 14170 * @class The Navigation Plugin 14171 * @param {Owl} carousel - The Owl Carousel. 14172 */ 14173 var Navigation = function( carousel ) { 14174 /** 14175 * Reference to the core. 14176 * 14177 * @protected 14178 * @type {Owl} 14179 */ 14180 this._core = carousel; 14181 14182 /** 14183 * Indicates whether the plugin is initialized or not. 14184 * 14185 * @protected 14186 * @type {boolean} 14187 */ 14188 this._initialized = false; 14189 14190 /** 14191 * The current paging indexes. 14192 * 14193 * @protected 14194 * @type {Array} 14195 */ 14196 this._pages = []; 14197 14198 /** 14199 * All DOM elements of the user interface. 14200 * 14201 * @protected 14202 * @type {Object} 14203 */ 14204 this._controls = {}; 14205 14206 /** 14207 * Markup for an indicator. 14208 * 14209 * @protected 14210 * @type {Array.<string>} 14211 */ 14212 this._templates = []; 14213 14214 /** 14215 * The carousel element. 14216 * 14217 * @type {jQuery} 14218 */ 14219 this.$element = this._core.$element; 14220 14221 /** 14222 * Overridden methods of the carousel. 14223 * 14224 * @protected 14225 * @type {Object} 14226 */ 14227 this._overrides = { 14228 next: this._core.next, 14229 prev: this._core.prev, 14230 to: this._core.to 14231 }; 14232 14233 /** 14234 * All event handlers. 14235 * 14236 * @protected 14237 * @type {Object} 14238 */ 14239 this._handlers = { 14240 'prepared.owl.carousel': $.proxy( function( e ) { 14241 if ( e.namespace && this._core.settings.dotsData ) { 14242 this._templates.push( '<div class="' + this._core.settings.dotClass + '">' + $( e.content ).find( '[data-dot]' ).addBack( '[data-dot]' ).attr( 'data-dot' ) + '</div>' ); 14243 } 14244 }, this ), 14245 'added.owl.carousel': $.proxy( function( e ) { 14246 if ( e.namespace && this._core.settings.dotsData ) { 14247 this._templates.splice( e.position, 0, this._templates.pop() ); 14248 } 14249 }, this ), 14250 'remove.owl.carousel': $.proxy( function( e ) { 14251 if ( e.namespace && this._core.settings.dotsData ) { 14252 this._templates.splice( e.position, 1 ); 14253 } 14254 }, this ), 14255 'changed.owl.carousel': $.proxy( function( e ) { 14256 if ( e.namespace && e.property.name === 'position' ) { 14257 this.draw(); 14258 } 14259 }, this ), 14260 'initialized.owl.carousel': $.proxy( function( e ) { 14261 if ( e.namespace && ! this._initialized ) { 14262 this._core.trigger( 'initialize', null, 'navigation' ); 14263 this.initialize(); 14264 this.update(); 14265 this.draw(); 14266 this._initialized = true; 14267 this._core.trigger( 'initialized', null, 'navigation' ); 14268 } 14269 }, this ), 14270 'refreshed.owl.carousel': $.proxy( function( e ) { 14271 if ( e.namespace && this._initialized ) { 14272 this._core.trigger( 'refresh', null, 'navigation' ); 14273 this.update(); 14274 this.draw(); 14275 this._core.trigger( 'refreshed', null, 'navigation' ); 14276 } 14277 }, this ) 14278 }; 14279 14280 // set default options 14281 this._core.options = $.extend( {}, Navigation.Defaults, this._core.options ); 14282 14283 // register event handlers 14284 this.$element.on( this._handlers ); 14285 }; 14286 14287 /** 14288 * Default options. 14289 * 14290 * @public 14291 * @todo Rename `slideBy` to `navBy` 14292 */ 14293 Navigation.Defaults = { 14294 nav: false, 14295 navText: [ '<span aria-label="' + 'Previous' + '">‹</span>', '<span aria-label="' + 'Next' + '">›</span>' ], 14296 navSpeed: false, 14297 navElement: 'button type="button" role="presentation"', 14298 navContainer: false, 14299 navContainerClass: 'owl-nav', 14300 navClass: [ 'owl-prev', 'owl-next' ], 14301 slideBy: 1, 14302 dotClass: 'owl-dot', 14303 dotsClass: 'owl-dots', 14304 dots: true, 14305 dotsEach: false, 14306 dotsData: false, 14307 dotsSpeed: false, 14308 dotsContainer: false 14309 }; 14310 14311 /** 14312 * Initializes the layout of the plugin and extends the carousel. 14313 * 14314 * @protected 14315 */ 14316 Navigation.prototype.initialize = function() { 14317 var override, 14318 settings = this._core.settings; 14319 14320 // create DOM structure for relative navigation 14321 this._controls.$relative = ( settings.navContainer ? $( settings.navContainer ) : $( '<div>' ).addClass( settings.navContainerClass ).appendTo( this.$element ) ).addClass( 'disabled' ); 14322 14323 this._controls.$previous = $( '<' + settings.navElement + '>' ) 14324 .addClass( settings.navClass[ 0 ] ) 14325 .html( settings.navText[ 0 ] ) 14326 .prependTo( this._controls.$relative ) 14327 .on( 14328 'click', 14329 $.proxy( function() { 14330 this.prev( settings.navSpeed ); 14331 }, this ) 14332 ); 14333 this._controls.$next = $( '<' + settings.navElement + '>' ) 14334 .addClass( settings.navClass[ 1 ] ) 14335 .html( settings.navText[ 1 ] ) 14336 .appendTo( this._controls.$relative ) 14337 .on( 14338 'click', 14339 $.proxy( function() { 14340 this.next( settings.navSpeed ); 14341 }, this ) 14342 ); 14343 14344 // create DOM structure for absolute navigation 14345 if ( ! settings.dotsData ) { 14346 this._templates = [ $( '<button role="button">' ).addClass( settings.dotClass ).append( $( '<span>' ) ).prop( 'outerHTML' ) ]; 14347 } 14348 14349 this._controls.$absolute = ( settings.dotsContainer ? $( settings.dotsContainer ) : $( '<div>' ).addClass( settings.dotsClass ).appendTo( this.$element ) ).addClass( 'disabled' ); 14350 14351 this._controls.$absolute.on( 14352 'click', 14353 'button', 14354 $.proxy( function( e ) { 14355 var index = $( e.target ).parent().is( this._controls.$absolute ) ? $( e.target ).index() : $( e.target ).parent().index(); 14356 14357 e.preventDefault(); 14358
14359 this.to( index, settings.dotsSpeed ); 14360 }, this ) 14361 ); 14362 14363 /*$el.on('focusin', function() { 14364 $(document).off(".carousel"); 14365 14366 $(document).on('keydown.carousel', function(e) { 14367 if(e.keyCode == 37) { 14368 $el.trigger('prev.owl') 14369 } 14370 if(e.keyCode == 39) { 14371 $el.trigger('next.owl') 14372 } 14373 }); 14374 });*/ 14375 14376 // override public methods of the carousel 14377 for ( override in this._overrides ) { 14378 if ( override ) { 14379 this._core[ override ] = $.proxy( this[ override ], this ); 14380 } 14381 } 14382 }; 14383 14384 /** 14385 * Destroys the plugin. 14386 * 14387 * @protected 14388 */ 14389 Navigation.prototype.destroy = function() { 14390 var handler, control, property, override, settings; 14391 settings = this._core.settings; 14392 14393 for ( handler in this._handlers ) { 14394 if ( handler ) { 14395 this.$element.off( handler, this._handlers[ handler ] ); 14396 } 14397 } 14398 for ( control in this._controls ) { 14399 if ( control === '$relative' && settings.navContainer ) { 14400 this._controls[ control ].html( '' ); 14401 } else { 14402 this._controls[ control ].remove(); 14403 } 14404 } 14405 for ( override in this.overides ) { 14406 if ( override ) { 14407 this._core[ override ] = this._overrides[ override ]; 14408 } 14409 } 14410 for ( property in Object.getOwnPropertyNames( this ) ) { 14411 if ( typeof this[ property ] !== 'function' ) { 14412 this[ property ] = null; 14413 } 14414 } 14415 }; 14416 14417 /** 14418 * Updates the internal state. 14419 * 14420 * @protected 14421 */ 14422 Navigation.prototype.update = function() { 14423 var i, 14424 j, 14425 lower = this._core.clones().length / 2, 14426 upper = lower + this._core.items().length, 14427 maximum = this._core.maximum( true ), 14428 settings = this._core.settings, 14429 size = settings.center || settings.autoWidth || settings.dotsData ? 1 : settings.dotsEach || settings.items; 14430 14431 if ( settings.slideBy !== 'page' ) { 14432 settings.slideBy = Math.min( settings.slideBy, settings.items ); 14433 } 14434 14435 if ( settings.dots || settings.slideBy === 'page' ) { 14436 this._pages = []; 14437 14438 for ( i = lower, j = 0; i < upper; i += 1 ) { 14439 if ( j >= size || j === 0 ) { 14440 this._pages.push( { 14441 start: Math.min( maximum, i - lower ), 14442 end: i - lower + size - 1 14443 } ); 14444 if ( Math.min( maximum, i - lower ) === maximum ) { 14445 break; 14446 } 14447 j = 0; 14448 } 14449 j += this._core.mergers( this._core.relative( i ) ); 14450 } 14451 } 14452 }; 14453 14454 /** 14455 * Draws the user interface. 14456 * 14457 * @todo The option `dotsData` wont work. 14458 * @protected 14459 */ 14460 Navigation.prototype.draw = function() { 14461 var difference, 14462 settings = this._core.settings, 14463 disabled = this._core.items().length <= settings.items, 14464 index = this._core.relative( this._core.current() ), 14465 loop = settings.loop || settings.rewind; 14466 14467 this._controls.$relative.toggleClass( 'disabled', ! settings.nav || disabled ); 14468 14469 if ( settings.nav ) { 14470 this._controls.$previous.toggleClass( 'disabled', ! loop && index <= this._core.minimum( true ) ); 14471 this._controls.$next.toggleClass( 'disabled', ! loop && index >= this._core.maximum( true ) ); 14472 } 14473 14474 this._controls.$absolute.toggleClass( 'disabled', ! settings.dots || disabled ); 14475 14476 if ( settings.dots ) { 14477 difference = this._pages.length - this._controls.$absolute.children().length; 14478 14479 if ( settings.dotsData && difference !== 0 ) { 14480 this._controls.$absolute.html( this._templates.join( '' ) ); 14481 } else if ( difference > 0 ) { 14482 this._controls.$absolute.append( new Array( difference + 1 ).join( this._templates[ 0 ] ) ); 14483 } else if ( difference < 0 ) { 14484 this._controls.$absolute.children().slice( difference ).remove(); 14485 } 14486 14487 this._controls.$absolute.find( '.active' ).removeClass( 'active' ); 14488 this._controls.$absolute.children().eq( $.inArray( this.current(), this._pages ) ).addClass( 'active' ); 14489 } 14490 }; 14491 14492 /** 14493 * Extends event data. 14494 * 14495 * @protected 14496 * @param {Event} event - The event object which gets thrown. 14497 */ 14498 Navigation.prototype.onTrigger = function( event ) { 14499 var settings = this._core.settings; 14500 14501 event.page = { 14502 index: $.inArray( this.current(), this._pages ), 14503 count: this._pages.length, 14504 size: settings && ( settings.center || settings.autoWidth || settings.dotsData ? 1 : settings.dotsEach || settings.items ) 14505 }; 14506 }; 14507 14508 /** 14509 * Gets the current page position of the carousel. 14510 * 14511 * @protected 14512 * @returns {number} 14513 */ 14514 Navigation.prototype.current = function() { 14515 var current = this._core.relative( this._core.current() ); 14516 return $.grep( 14517 this._pages, 14518 $.proxy( function( page ) { 14519 return page.start <= current && page.end >= current; 14520 }, this ) 14521 ).pop(); 14522 }; 14523 14524 /** 14525 * Gets the current succesor/predecessor position. 14526 * 14527 * @param {mixed} successor 14528 * @protected 14529 * @returns {number} 14530 */ 14531 Navigation.prototype.getPosition = function( successor ) { 14532 var position, 14533 length, 14534 settings = this._core.settings; 14535 14536 if ( settings.slideBy === 'page' ) { 14537 position = $.inArray( this.current(), this._pages ); 14538 length = this._pages.length; 14539 if ( successor ) { 14540 position = position + 1; 14541 } else { 14542 position = position - 1; 14543 } 14544 position = this._pages[ ( ( position % length ) + length ) % length ].start; 14545 } else { 14546 position = this._core.relative( this._core.current() ); 14547 length = this._core.items().length; 14548 if ( successor ) { 14549 position += settings.slideBy; 14550 } else { 14551 position -= settings.slideBy; 14552 } 14553 } 14554 14555 return position; 14556 }; 14557 14558 /** 14559 * Retry logic. 14560 * 14561 * @public 14562 * @param {number} [speed=false] - The time in milliseconds for the transition. 14563 * @param {boolean} [nextprev=false] - Determines whether to navigate to the next or previous slide. 14564 * `true` for next slide, `false` for previous slide. 14565 */ 14566 Navigation.prototype.getAvailableSlide = function( speed, nextprev ) { 14567 var maxTries = this._core._items.length - this._core._current || 100; // Maximum number of attempts to avoid infinite loops 14568 var retryInterval = 50; // Milliseconds between retries 14569 var attempts = 0; 14570 14571 // Define the retry logic as a regular function 14572 var tryNext = function() { 14573 var position = this.getPosition( nextprev ); 14574 if ( this._core._items[ position ] && this._core._items[ position ].is( '.tc-hidden-visibility' ) ) { 14575 if ( attempts < maxTries ) { 14576 attempts++; 14577 this._core.current( position ); 14578 // Target is still hidden, retrying... 14579 setTimeout( function() { 14580 tryNext.call( this ); // Explicitly bind the `this` context when retrying 14581 }.bind( this ), retryInterval ); // Use .bind(this) to ensure `this` is Navigation 14582 } else { 14583 // Max attempts reached. Navigation failed. 14584 } 14585 } else { 14586 // If the target item is visible, proceed with the navigation 14587 $.proxy( this._overrides.to, this._core )( position, speed ); 14588 } 14589 }; 14590 // Start the retry logic 14591 tryNext.call( this ); // Ensure the `this` context refers to the correct object 14592 }; 14593 14594 /** 14595 * Slides to the next item or page. 14596 * 14597 * @public 14598 * @param {number} [speed=false] - The time in milliseconds for the transition. 14599 */ 14600 Navigation.prototype.next = function( speed ) { 14601 this.getAvailableSlide( speed, true ); 14602 }; 14603 14604 /** 14605 * Slides to the previous item or page. 14606 * 14607 * @public 14608 * @param {number} [speed=false] - The time in milliseconds for the transition. 14609 */ 14610 Navigation.prototype.prev = function( speed ) { 14611 this.getAvailableSlide( speed, false ); 14612 }; 14613 14614 /** 14615 * Slides to the specified item or page. 14616 * 14617 * @public 14618 * @param {number} position - The position of the item or page. 14619 * @param {number} [speed] - The time in milliseconds for the transition. 14620 * @param {boolean} [standard=false] - Whether to use the standard behaviour or not. 14621 */ 14622 Navigation.prototype.to = function( position, speed, standard ) { 14623 var length; 14624 14625 if ( ! standard && this._pages.length ) { 14626 length = this._pages.length; 14627 $.proxy( this._overrides.to, this._core )( this._pages[ ( ( position % length ) + length ) % length ].start, speed ); 14628 } else { 14629 $.proxy( this._overrides.to, this._core )( position, speed ); 14630 } 14631 }; 14632 14633 $.fn.tmowlCarousel.Constructor.Plugins.Navigation = Navigation; 14634}( window.Zepto || window.jQuery ) ); 14635 14636/** 14637 * Hash Plugin 14638 * 14639 * @param {jQuery} $ 14640 * @param {Window} window 14641 * @version 2.3.4 14642 * @author Artus Kolanowski 14643 * @author David Deutsch 14644 * @license The MIT License (MIT) 14645 */ 14646( function( $, window ) { 14647 'use strict'; 14648 14649 /** 14650 * Creates the hash plugin. 14651 * 14652 * @class The Hash Plugin 14653 * @param {Owl} carousel - The Owl Carousel
14654 */ 14655 var Hash = function( carousel ) { 14656 /** 14657 * Reference to the core. 14658 * 14659 * @protected 14660 * @type {Owl} 14661 */ 14662 this._core = carousel; 14663 14664 /** 14665 * Hash index for the items. 14666 * 14667 * @protected 14668 * @type {Object} 14669 */ 14670 this._hashes = {}; 14671 14672 /** 14673 * The carousel element. 14674 * 14675 * @type {jQuery} 14676 */ 14677 this.$element = this._core.$element; 14678 14679 /** 14680 * All event handlers. 14681 * 14682 * @protected 14683 * @type {Object} 14684 */ 14685 this._handlers = { 14686 'initialized.owl.carousel': $.proxy( function( e ) { 14687 if ( e.namespace && this._core.settings.startPosition === 'URLHash' ) { 14688 $( window ).trigger( 'hashchange.owl.navigation' ); 14689 } 14690 }, this ), 14691 'prepared.owl.carousel': $.proxy( function( e ) { 14692 var hash; 14693 if ( e.namespace ) { 14694 hash = $( e.content ).find( '[data-hash]' ).addBack( '[data-hash]' ).attr( 'data-hash' ); 14695 14696 if ( ! hash ) { 14697 return; 14698 } 14699 14700 this._hashes[ hash ] = e.content; 14701 } 14702 }, this ), 14703 'changed.owl.carousel': $.proxy( function( e ) { 14704 var current; 14705 var hash; 14706 if ( e.namespace && e.property.name === 'position' ) { 14707 current = this._core.items( this._core.relative( this._core.current() ) ); 14708 hash = $.map( this._hashes, function( item, thishash ) { 14709 return item === current ? thishash : null; 14710 } ).join(); 14711 14712 if ( ! hash || window.location.hash.slice( 1 ) === hash ) { 14713 return; 14714 } 14715 14716 window.location.hash = hash; 14717 } 14718 }, this ) 14719 }; 14720 14721 // set default options 14722 this._core.options = $.extend( {}, Hash.Defaults, this._core.options ); 14723 14724 // register the event handlers 14725 this.$element.on( this._handlers ); 14726 14727 // register event listener for hash navigation 14728 $( window ).on( 14729 'hashchange.owl.navigation', 14730 $.proxy( function() { 14731 var hash = window.location.hash.substring( 1 ), 14732 items = this._core.$stage.children(), 14733 position = this._hashes[ hash ] && items.index( this._hashes[ hash ] ); 14734 14735 if ( position === undefined || position === this._core.current() ) { 14736 return; 14737 } 14738 14739 this._core.to( this._core.relative( position ), false, true ); 14740 }, this ) 14741 ); 14742 }; 14743 14744 /** 14745 * Default options. 14746 * 14747 * @public 14748 */ 14749 Hash.Defaults = { 14750 URLhashListener: false 14751 }; 14752 14753 /** 14754 * Destroys the plugin. 14755 * 14756 * @public 14757 */ 14758 Hash.prototype.destroy = function() { 14759 var handler, property; 14760 14761 $( window ).off( 'hashchange.owl.navigation' ); 14762 14763 for ( handler in this._handlers ) { 14764 if ( handler ) { 14765 this._core.$element.off( handler, this._handlers[ handler ] ); 14766 } 14767 } 14768 for ( property in Object.getOwnPropertyNames( this ) ) { 14769 if ( typeof this[ property ] !== 'function' ) { 14770 this[ property ] = null; 14771 } 14772 } 14773 }; 14774 14775 $.fn.tmowlCarousel.Constructor.Plugins.Hash = Hash; 14776}( window.Zepto || window.jQuery, window ) ); 14777 14778/** 14779 * Support Plugin 14780 * 14781 * @param {jQuery} $ 14782 * @version 2.3.4 14783 * @author Vivid Planet Software GmbH 14784 * @author Artus Kolanowski 14785 * @author David Deutsch 14786 * @license The MIT License (MIT) 14787 */ 14788( function( $ ) { 14789 'use strict'; 14790 var style = $( '<support>' ).get( 0 ).style, 14791 prefixes = 'Webkit Moz O ms'.split( ' ' ), 14792 events = { 14793 transition: { 14794 end: { 14795 WebkitTransition: 'webkitTransitionEnd', 14796 MozTransition: 'transitionend', 14797 OTransition: 'oTransitionEnd', 14798 transition: 'transitionend' 14799 } 14800 }, 14801 animation: { 14802 end: { 14803 WebkitAnimation: 'webkitAnimationEnd', 14804 MozAnimation: 'animationend', 14805 OAnimation: 'oAnimationEnd', 14806 animation: 'animationend' 14807 } 14808 } 14809 }, 14810 tests; 14811 14812 function test( property, thisprefixed ) { 14813 var result = false, 14814 upper = property.charAt( 0 ).toUpperCase() + property.slice( 1 ); 14815 14816 $.each( ( property + ' ' + prefixes.join( upper + ' ' ) + upper ).split( ' ' ), function( i, thisproperty ) { 14817 if ( style[ thisproperty ] !== undefined ) { 14818 result = thisprefixed ? thisproperty : true; 14819 return false; 14820 } 14821 } ); 14822 14823 return result; 14824 } 14825 14826 function prefixed( property ) { 14827 return test( property, true ); 14828 } 14829 14830 tests = { 14831 csstransforms: function() { 14832 return !! test( 'transform' ); 14833 }, 14834 csstransforms3d: function() { 14835 return !! test( 'perspective' ); 14836 }, 14837 csstransitions: function() { 14838 return !! test( 'transition' ); 14839 }, 14840 cssanimations: function() { 14841 return !! test( 'animation' ); 14842 } 14843 }; 14844 if ( tests.csstransitions() ) { 14845 /* jshint -W053 */ 14846 $.support.transition = new String( prefixed( 'transition' ) ); 14847 $.support.transition.end = events.transition.end[ $.support.transition ]; 14848 } 14849 14850 if ( tests.cssanimations() ) { 14851 /* jshint -W053 */ 14852 $.support.animation = new String( prefixed( 'animation' ) ); 14853 $.support.animation.end = events.animation.end[ $.support.animation ]; 14854 } 14855 14856 if ( tests.csstransforms() ) { 14857 /* jshint -W053 */ 14858 $.support.transform = new String( prefixed( 'transform' ) ); 14859 $.support.transform3d = tests.csstransforms3d(); 14860 } 14861}( window.Zepto || window.jQuery ) ); 14862; 14863/**! 14864 * Sortable 1.15.6 14865 * @author RubaXa <[email protected]> 14866 * @author owenm <[email protected]> 14867 * @license MIT 14868 */ 14869 14870/* global define, require, module */ 14871( function( global, factory ) { 14872 'use strict'; 14873 if ( typeof exports === 'object' && typeof module !== 'undefined' ) { 14874 module.exports = factory(); 14875 } else if ( typeof define === 'function' && define.amd ) { 14876 define( factory ); 14877 } else { 14878 global = global || self; 14879 global.Sortable = factory(); 14880 } 14881}( this, ( function() { 14882 'use strict'; 14883 14884 var version = '1.15.6'; 14885 var IE11OrLess = userAgent( /(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i ); 14886 var Edge = userAgent( /Edge/i ); 14887 var FireFox = userAgent( /firefox/i ); 14888 var Safari = userAgent( /safari/i ) && ! userAgent( /chrome/i ) && ! userAgent( /android/i );
14889 var IOS = userAgent( /iP(ad|od|hone)/i ); 14890 var ChromeForAndroid = userAgent( /chrome/i ) && userAgent( /android/i ); 14891 var captureMode = { 14892 capture: false, 14893 passive: false 14894 }; 14895 var R_SPACE = /\s+/g; 14896 var _throttleTimeout; 14897 var expando = 'Sortable' + new Date().getTime(); 14898 var plugins = []; 14899 var defaults = { 14900 initializeByDefault: true 14901 }; 14902 var PluginManager = { 14903 mount: function mount( plugin ) { 14904 var option; 14905 // Set default static properties 14906 for ( option in defaults ) { 14907 if ( defaults.hasOwnProperty( option ) && ! ( option in plugin ) ) { 14908 plugin[ option ] = defaults[ option ]; 14909 } 14910 } 14911 plugins.forEach( function( p ) { 14912 if ( p.pluginName === plugin.pluginName ) { 14913 throw 'Sortable: Cannot mount plugin '.concat( plugin.pluginName, ' more than once' ); 14914 } 14915 } ); 14916 plugins.push( plugin ); 14917 }, 14918 pluginEvent: function pluginEvent( eventName, sortable, evt ) { 14919 var _this = this; 14920 var eventNameGlobal = eventName + 'Global'; 14921 this.eventCanceled = false; 14922 evt.cancel = function() { 14923 _this.eventCanceled = true; 14924 }; 14925 plugins.forEach( function( plugin ) { 14926 if ( ! sortable[ plugin.pluginName ] ) { 14927 return; 14928 } 14929 // Fire global events if it exists in this sortable 14930 if ( sortable[ plugin.pluginName ][ eventNameGlobal ] ) { 14931 sortable[ plugin.pluginName ][ eventNameGlobal ]( _objectSpread2( { 14932 sortable: sortable 14933 }, evt ) ); 14934 } 14935 14936 // Only fire plugin event if plugin is enabled in this sortable, 14937 // and plugin has event defined 14938 if ( sortable.options[ plugin.pluginName ] && sortable[ plugin.pluginName ][ eventName ] ) { 14939 sortable[ plugin.pluginName ][ eventName ]( _objectSpread2( { 14940 sortable: sortable 14941 }, evt ) ); 14942 } 14943 } ); 14944 }, 14945 initializePlugins: function initializePlugins( sortable, el, _defaults ) { 14946 var option; 14947 var modified; 14948 plugins.forEach( function( plugin ) { 14949 var pluginName = plugin.pluginName; 14950 var initialized; 14951 if ( ! sortable.options[ pluginName ] && ! plugin.initializeByDefault ) { 14952 return; 14953 } 14954 initialized = new plugin( sortable, el, sortable.options ); 14955 initialized.sortable = sortable; 14956 initialized.options = sortable.options; 14957 sortable[ pluginName ] = initialized; 14958 14959 // Add default options from plugin 14960 _extends( _defaults, initialized.defaults ); 14961 } ); 14962 for ( option in sortable.options ) { 14963 if ( ! sortable.options.hasOwnProperty( option ) ) { 14964 continue; 14965 } 14966 modified = this.modifyOption( sortable, option, sortable.options[ option ] ); 14967 if ( typeof modified !== 'undefined' ) { 14968 sortable.options[ option ] = modified; 14969 } 14970 } 14971 }, 14972 getEventProperties: function getEventProperties( name, sortable ) { 14973 var eventProperties = {}; 14974 plugins.forEach( function( plugin ) { 14975 if ( typeof plugin.eventProperties !== 'function' ) { 14976 return; 14977 } 14978 _extends( eventProperties, plugin.eventProperties.call( sortable[ plugin.pluginName ], name ) ); 14979 } ); 14980 return eventProperties; 14981 }, 14982 modifyOption: function modifyOption( sortable, name, value ) { 14983 var modifiedValue; 14984 plugins.forEach( function( plugin ) { 14985 // Plugin must exist on the Sortable 14986 if ( ! sortable[ plugin.pluginName ] ) { 14987 return; 14988 } 14989 14990 // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin 14991 if ( plugin.optionListeners && typeof plugin.optionListeners[ name ] === 'function' ) { 14992 modifiedValue = plugin.optionListeners[ name ].call( sortable[ plugin.pluginName ], value ); 14993 } 14994 } ); 14995 return modifiedValue; 14996 } 14997 }; 14998 var _excluded = [ 'evt' ]; 14999 var pluginEvent = function pluginEvent( eventName, sortable ) { 15000 var _ref = arguments.length > 2 && arguments[ 2 ] !== undefined ? arguments[ 2 ] : {}, 15001 originalEvent = _ref.evt, 15002 data = _objectWithoutProperties( _ref, _excluded ); 15003 PluginManager.pluginEvent.bind( Sortable )( eventName, sortable, _objectSpread2( { 15004 dragEl: dragEl, 15005 parentEl: parentEl, 15006 ghostEl: ghostEl, 15007 rootEl: rootEl, 15008 nextEl: nextEl, 15009 lastDownEl: lastDownEl, 15010 cloneEl: cloneEl, 15011 cloneHidden: cloneHidden, 15012 dragStarted: moved, 15013 putSortable: putSortable, 15014 activeSortable: Sortable.active, 15015 originalEvent: originalEvent, 15016 oldIndex: oldIndex, 15017 oldDraggableIndex: oldDraggableIndex, 15018 newIndex: newIndex, 15019 newDraggableIndex: newDraggableIndex, 15020 hideGhostForTarget: _hideGhostForTarget, 15021 unhideGhostForTarget: _unhideGhostForTarget, 15022 cloneNowHidden: function cloneNowHidden() { 15023 cloneHidden = true; 15024 }, 15025 cloneNowShown: function cloneNowShown() { 15026 cloneHidden = false;
15027 }, 15028 dispatchSortableEvent: function dispatchSortableEvent( name ) { 15029 _dispatchEvent( { 15030 sortable: sortable, 15031 name: name, 15032 originalEvent: originalEvent 15033 } ); 15034 } 15035 }, data ) ); 15036 }; 15037 var dragEl, 15038 parentEl, 15039 ghostEl, 15040 rootEl, 15041 nextEl, 15042 lastDownEl, 15043 cloneEl, 15044 cloneHidden, 15045 oldIndex, 15046 newIndex, 15047 oldDraggableIndex, 15048 newDraggableIndex, 15049 activeGroup, 15050 putSortable, 15051 awaitingDragStarted = false, 15052 ignoreNextClick = false, 15053 sortables = [], 15054 tapEvt, 15055 touchEvt, 15056 lastDx, 15057 lastDy, 15058 tapDistanceLeft, 15059 tapDistanceTop, 15060 moved, 15061 lastTarget, 15062 lastDirection, 15063 pastFirstInvertThresh = false, 15064 isCircumstantialInvert = false, 15065 targetMoveDistance, 15066 // For positioning ghost absolutely 15067 ghostRelativeParent, 15068 ghostRelativeParentInitialScroll = [], 15069 // (left, top) 15070 15071 _silent = false, 15072 savedInputChecked = []; 15073 15074 var documentExists = typeof document !== 'undefined', 15075 PositionGhostAbsolutely = IOS, 15076 CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float', 15077 // This will not pass for IE9, because IE9 DnD only works on anchors 15078 supportDraggable = documentExists && ! ChromeForAndroid && ! IOS && 'draggable' in document.createElement( 'div' ), 15079 supportCssPointerEvents = ( function() { 15080 var el; 15081 if ( ! documentExists ) { 15082 return; 15083 } 15084 // false when <= IE11 15085 if ( IE11OrLess ) { 15086 return false; 15087 } 15088 el = document.createElement( 'x' ); 15089 el.style.cssText = 'pointer-events:auto'; 15090 return el.style.pointerEvents === 'auto'; 15091 }() ), 15092 _detectDirection = function _detectDirection( el, options ) { 15093 var elCSS = css( el ), 15094 elWidth = parseInt( elCSS.width, 10 ) - parseInt( elCSS.paddingLeft, 10 ) - parseInt( elCSS.paddingRight, 10 ) - parseInt( elCSS.borderLeftWidth, 10 ) - parseInt( elCSS.borderRightWidth, 10 ), 15095 child1 = getChild( el, 0, options ), 15096 child2 = getChild( el, 1, options ), 15097 touchingSideChild2, 15098 firstChildCSS = child1 && css( child1 ), 15099 secondChildCSS = child2 && css( child2 ), 15100 firstChildWidth = firstChildCSS && parseInt( firstChildCSS.marginLeft, 10 ) + parseInt( firstChildCSS.marginRight, 10 ) + getRect( child1 ).width, 15101 secondChildWidth = secondChildCSS && parseInt( secondChildCSS.marginLeft, 10 ) + parseInt( secondChildCSS.marginRight, 10 ) + getRect( child2 ).width; 15102 if ( elCSS.display === 'flex' ) { 15103 return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' ? 'vertical' : 'horizontal'; 15104 } 15105 if ( elCSS.display === 'grid' ) { 15106 return elCSS.gridTemplateColumns.split( ' ' ).length <= 1 ? 'vertical' : 'horizontal'; 15107 } 15108 if ( child1 && firstChildCSS.float && firstChildCSS.float !== 'none' ) { 15109 touchingSideChild2 = firstChildCSS.float === 'left' ? 'left' : 'right'; 15110 return child2 && ( secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2 ) ? 'vertical' : 'horizontal'; 15111 } 15112 return child1 && ( firstChildCSS.display === 'block' || firstChildCSS.display === 'flex' || firstChildCSS.display === 'table' || firstChildCSS.display === 'grid' || firstChildWidth >= elWidth && elCSS[ CSSFloatProperty ] === 'none' || child2 && elCSS[ CSSFloatProperty ] === 'none' && firstChildWidth + secondChildWidth > elWidth ) ? 'vertical' : 'horizontal'; 15113 }, 15114 _dragElInRowColumn = function _dragElInRowColumn( dragRect, targetRect, vertical ) { 15115 var dragElS1Opp = vertical ? dragRect.left : dragRect.top, 15116 dragElS2Opp = vertical ? dragRect.right : dragRect.bottom, 15117 dragElOppLength = vertical ? dragRect.width : dragRect.height, 15118 targetS1Opp = vertical ? targetRect.left : targetRect.top, 15119 targetS2Opp = vertical ? targetRect.right : targetRect.bottom, 15120 targetOppLength = vertical ? targetRect.width : targetRect.height; 15121 return dragElS1Opp === targetS1Opp || dragElS2Opp === targetS2Opp || dragElS1Opp + dragElOppLength / 2 === targetS1Opp + targetOppLength / 2; 15122 }, 15123 /** 15124 * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold. 15125 * @param {number} x X position 15126 * @param {number} y Y position 15127 * @return {HTMLElement} Element of the first found nearest Sortable 15128 */ 15129 _detectNearestEmptySortable = function _detectNearestEmptySortable( x, y ) { 15130 var ret; 15131 sortables.some( function( sortable ) { 15132 var threshold = sortable[ expando ].options.emptyInsertThreshold; 15133 var rect; 15134 var insideHorizontally; 15135 var insideVertically; 15136 if ( ! threshold || lastChild( sortable ) ) { 15137 return false; // Explicitly continue searching 15138 } 15139 rect = getRect( sortable ); 15140 insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold; 15141 insideVertically = y >
15141= rect.top - threshold && y <= rect.bottom + threshold; 15142 if ( insideHorizontally && insideVertically ) { 15143 ret = sortable; // Store the matched sortable 15144 return true; // Stop iteration (found a match) 15145 } 15146 return false; // Continue searching 15147 } ); 15148 return ret; 15149 }, 15150 _prepareGroup = function _prepareGroup( options ) { 15151 var group = {}; 15152 var originalGroup = options.group; 15153 function toFn( value, pull ) { 15154 return function( to, from, _dragEl, evt ) { 15155 var otherGroup; 15156 var sameGroup = to.options.group.name && from.options.group.name && to.options.group.name === from.options.group.name; 15157 if ( ( value === null || value === undefined ) && ( pull || sameGroup ) ) { 15158 // Default pull value 15159 // Default pull and put value if same group 15160 return true; 15161 } else if ( value === null || value === undefined || value === false ) { 15162 return false; 15163 } else if ( pull && value === 'clone' ) { 15164 return value; 15165 } else if ( typeof value === 'function' ) { 15166 return toFn( value( to, from, _dragEl, evt ), pull )( to, from, _dragEl, evt ); 15167 } 15168 otherGroup = ( pull ? to : from ).options.group.name; 15169 return ( value === true ) || ( typeof value === 'string' && value === otherGroup ) || ( value.join && value.indexOf( otherGroup ) > -1 ); 15170 }; 15171 } 15172 if ( ! originalGroup || typeof originalGroup !== 'object' ) { 15173 originalGroup = { 15174 name: originalGroup 15175 }; 15176 } 15177 group.name = originalGroup.name; 15178 group.checkPull = toFn( originalGroup.pull, true ); 15179 group.checkPut = toFn( originalGroup.put ); 15180 group.revertClone = originalGroup.revertClone; 15181 options.group = group; 15182 }, 15183 _hideGhostForTarget = function _hideGhostForTarget() { 15184 if ( ! supportCssPointerEvents && ghostEl ) { 15185 css( ghostEl, 'display', 'none' ); 15186 } 15187 }, 15188 _unhideGhostForTarget = function _unhideGhostForTarget() { 15189 if ( ! supportCssPointerEvents && ghostEl ) { 15190 css( ghostEl, 'display', '' ); 15191 } 15192 }; 15193 var autoScrolls = [], 15194 scrollEl, 15195 scrollRootEl, 15196 scrolling = false, 15197 lastAutoScrollX, 15198 lastAutoScrollY, 15199 touchEvt$1, 15200 pointerElemChangedInterval; 15201 var autoScroll = throttle( function( evt, options, _rootEl, isFallback ) { 15202 var x; 15203 var y; 15204 var sens; 15205 var speed; 15206 var winScroller; 15207 var scrollThisInstance; 15208 var scrollCustomFn; 15209 var layersOut; 15210 var currentParent; 15211 var el, rect, 15212 top, 15213 bottom, 15214 left, 15215 right, 15216 width, 15217 height, 15218 canScrollX, 15219 canScrollY, 15220 scrollWidth, 15221 scrollHeight, 15222 elCSS, 15223 scrollPosX, 15224 scrollPosY, 15225 vx, 15226 vy, 15227 i, 15228 scrollOffsetY, 15229 scrollOffsetX; 15230 // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521 15231 if ( ! options.scroll ) { 15232 return; 15233 } 15234 x = ( evt.touches ? evt.touches[ 0 ] : evt ).clientX; 15235 y = ( evt.touches ? evt.touches[ 0 ] : evt ).clientY; 15236 sens = options.scrollSensitivity; 15237 speed = options.scrollSpeed; 15238 winScroller = getWindowScrollingElement(); 15239 scrollThisInstance = false; 15240 layersOut = 0; 15241 currentParent = scrollEl; 15242 15243 // New scroll root, set scrollEl 15244 if ( scrollRootEl !== _rootEl ) { 15245 scrollRootEl = _rootEl; 15246 clearAutoScrolls(); 15247 scrollEl = options.scroll; 15248 scrollCustomFn = options.scrollFn; 15249 if ( scrollEl === true ) { 15250 scrollEl = getParentAutoScrollElement( _rootEl, true ); 15251 } 15252 } 15253 do { 15254 el = currentParent; 15255 if ( ! el ) { 15256 continue; 15257 } 15258 rect = getRect( el ); 15259 top = rect.top; 15260 bottom = rect.bottom; 15261 left = rect.left; 15262 right = rect.right; 15263 width = rect.width; 15264 height = rect.height; 15265 canScrollX = void 0; 15266 canScrollY = void 0; 15267 scrollWidth = el.scrollWidth; 15268 scrollHeight = el.scrollHeight; 15269 elCSS = css( el ); 15270 scrollPosX = el.scrollLeft; 15271 scrollPosY = el.scrollTop; 15272 if ( el === winScroller ) { 15273 canScrollX = width < scrollWidth && ( elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible' ); 15274 canScrollY = height < scrollHeight && ( elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible' ); 15275 } else { 15276 canScrollX = width < scrollWidth && ( elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' ); 15277 canScrollY = height < scrollHeight && ( elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' ); 15278 } 15279 vx = canScrollX && ( Math.abs( right - x ) <= sens && scrollPosX + width < scrollWidth ) - ( Math.abs( left - x ) <= sens && !! scrollPosX ); 15280 vy = canScrollY && ( Math.abs( bottom - y ) <= sens && scrollPosY + height < scrollHeight ) - ( Math.abs( top - y ) <= sens && !! scrollPosY ); 15281 if ( ! autoScrolls[ layersOut ] ) { 15282 for ( i = 0; i <= layersOut; i++ ) { 15283 if ( ! autoScrolls[ i ] ) { 15284 autoScrolls[ i ] = {}; 15285 } 15286 } 15287 } 15288 if ( autoScrolls[ layersOut ].vx != vx || autoScrolls[ layersOut ].vy != vy || autoScrolls[ layersOut ].el !== el ) { 15289 autoScrolls[ layersOut ].el = el; 15290 autoScrolls[ layersOut ].vx = vx; 15291 autoScrolls[ layersOut ].vy = vy; 15292 clearInterval( autoScrolls[ layersOut ].pid ); 15293 if ( vx !== 0 || vy !== 0 ) { 15294 scrollThisInstance = true; 15295 autoScrolls[ layersOut ].pid = setInterval( function() { 15296 // emulate drag over during autoscroll (fallback), emulating native DnD behaviour 15297 if ( isFallback && this.layer === 0 ) { 15298 Sortable.active._onTouchMove( touchEvt$1 ); // To move ghost if it is positioned absolutely 15299 } 15300 scrollOffsetY = autoScrolls[ this.layer ].vy ? autoScrolls[ this.layer ].vy * speed : 0; 15301 scrollOffsetX = autoScrolls[ this.layer ].vx ? autoScrolls[ this.layer ].vx * speed : 0; 15302 if ( typeof scrollCustomFn === 'function' ) { 15303 if ( scrollCustomFn.call( Sortable.dragged.parentNode[ expando ], scrollOffsetX, scrollOffsetY, evt, touchEvt$1, autoScrolls[ this.layer ].el ) !== 'continue' ) { 15304 return; 15305 } 15306 } 15307 scrollBy( autoScrolls[ this.layer ].el, scrollOffsetX, scrollOffsetY ); 15308 }.bind( { 15309 layer: layersOut 15310 } ), 24 ); 15311 } 15312 } 15313 layersOut++; 15314 } while ( options.bubbleScroll && currentParent !== winScroller && ( currentParent = getParentAutoScrollElement( currentParent, false ) ) ); 15315 scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not 15316 }, 30 ); 15317 15318 var drop = function drop( _ref ) { 15319 var originalEvent = _ref.originalEvent, 15320 _putSortable = _ref.putSortable, 15321 _dragEl = _ref.dragEl, 15322 activeSortable = _ref.activeSortable, 15323 dispatchSortableEvent = _ref.dispatchSortableEvent, 15324 hideGhostForTarget = _ref.hideGhostForTarget, 15325 unhideGhostForTarget = _ref.unhideGhostForTarget; 15326 var toSortable; 15327 var touch; 15328 var target; 15329 if ( ! originalEvent ) { 15330 return; 15331 } 15332 toSortable = _putSortable || activeSortable; 15333 hideGhostForTarget(); 15334 touch = originalEvent.changedTouches && originalEvent.changedTouches.length ? originalEvent.changedTouches[ 0 ] : originalEvent; 15335 target = document.elementFromPoint( touch.clientX, touch.clientY ); 15336 unhideGhostForTarget(); 15337 if ( toSortable && ! toSortable.el.contains( target ) ) { 15338 dispatchSortableEvent( 'spill' ); 15339 this.onSpill( { 15340 dragEl: _dragEl, 15341 putSortable: _putSortable 15342 } ); 15343 } 15344 }; 15345 var lastSwapEl; 15346 var multiDragElements = [], 15347 multiDragClones = [], 15348 lastMultiDragSelect, 15349 // for selection with modifier key down (SHIFT) 15350 multiDragSortable, 15351 initialFolding = false, 15352 // Initial multi-drag fold when drag started 15353 folding = false, 15354 // Folding any other time 15355 dragStarted = false, 15356 dragEl$1, 15357 clonesFromRect, 15358 clonesHidden; 15359 var nearestEmptyInsertDetectEvent = function nearestEmptyInsertDetectEvent( evt ) { 15360 var nearest; 15361 var event; 15362 var i; 15363 if ( dragEl ) { 15364 evt = evt.touches ? evt.touches[ 0 ] : evt; 15365 nearest = _detectNearestEmptySortable( evt.clientX, evt.clientY ); 15366 if ( nearest ) { 15367 // Create imitation event 15368 event = {}; 15369 for ( i in evt ) { 15370 if ( evt.hasOwnProperty( i ) ) { 15371 event[ i ] = evt[ i ]; 15372 } 15373 } 15374 event.target = event.rootEl = nearest; 15375 event.preventDefault = void 0; 15376 event.stopPropagation = void 0; 15377 nearest[ expando ]._onDragOver( event ); 15378 } 15379 } 15380 }; 15381 var _checkOutsideTargetEl = function _checkOutsideTargetEl( evt ) { 15382 if ( dragEl ) { 15383 dragEl.parentNode[ expando ]._isOutsideThisEl( evt.target ); 15384 } 15385 }; 15386 function ownKeys( object, enumerableOnly ) { 15387 var keys = Object.keys( object ); 15388 var symbols; 15389 if ( Object.getOwnPropertySymbols ) { 15390 symbols = Object.getOwnPropertySymbols( object ); 15391 if ( enumerableOnly ) { 15392 symbols = symbols.filter( function( sym ) { 15393 return Object.getOwnPropertyDescriptor( object, sym ).enumerable; 15394 } ); 15395 } 15396 keys.push.apply( keys, symbols ); 15397 } 15398 return keys; 15399 }
15400 function _objectSpread2( target ) { 15401 var i, source; 15402 for ( i = 1; i < arguments.length; i++ ) { 15403 source = ( arguments[ i ] !== undefined && arguments[ i ] !== null ) ? arguments[ i ] : {}; 15404 if ( i % 2 ) { 15405 ownKeys( Object( source ), true ).forEach( function( key ) { 15406 _defineProperty( target, key, source[ key ] ); 15407 } ); 15408 } else if ( Object.getOwnPropertyDescriptors ) { 15409 Object.defineProperties( target, Object.getOwnPropertyDescriptors( source ) ); 15410 } else { 15411 ownKeys( Object( source ) ).forEach( function( key ) { 15412 Object.defineProperty( target, key, Object.getOwnPropertyDescriptor( source, key ) ); 15413 } ); 15414 } 15415 } 15416 return target; 15417 } 15418 15419 function _defineProperty( obj, key, value ) { 15420 if ( key in obj ) { 15421 Object.defineProperty( obj, key, { 15422 value: value, 15423 enumerable: true, 15424 configurable: true, 15425 writable: true 15426 } ); 15427 } else { 15428 obj[ key ] = value; 15429 } 15430 return obj; 15431 } 15432 function _extends() { 15433 var i; 15434 var source; 15435 var key; 15436 _extends = Object.assign || function( target ) { 15437 for ( i = 1; i < arguments.length; i++ ) { 15438 source = arguments[ i ]; 15439 for ( key in source ) { 15440 if ( Object.prototype.hasOwnProperty.call( source, key ) ) { 15441 target[ key ] = source[ key ]; 15442 } 15443 } 15444 } 15445 return target; 15446 }; 15447 return _extends.apply( this, arguments ); 15448 } 15449 function _objectWithoutPropertiesLoose( source, excluded ) { 15450 var target; 15451 var sourceKeys; 15452 var key, i; 15453 if ( source == null ) { 15454 return {}; 15455 } 15456 target = {}; 15457 sourceKeys = Object.keys( source ); 15458 for ( i = 0; i < sourceKeys.length; i++ ) { 15459 key = sourceKeys[ i ]; 15460 if ( excluded.indexOf( key ) >= 0 ) { 15461 continue; 15462 } 15463 target[ key ] = source[ key ]; 15464 } 15465 return target; 15466 } 15467 function _objectWithoutProperties( source, excluded ) { 15468 var target; 15469 var key, i; 15470 var sourceSymbolKeys; 15471 if ( source == null ) { 15472 return {}; 15473 } 15474 target = _objectWithoutPropertiesLoose( source, excluded ); 15475 if ( Object.getOwnPropertySymbols ) { 15476 sourceSymbolKeys = Object.getOwnPropertySymbols( source ); 15477 for ( i = 0; i < sourceSymbolKeys.length; i++ ) { 15478 key = sourceSymbolKeys[ i ]; 15479 if ( excluded.indexOf( key ) >= 0 ) { 15480 continue; 15481 } 15482 if ( ! Object.prototype.propertyIsEnumerable.call( source, key ) ) { 15483 continue; 15484 } 15485 target[ key ] = source[ key ]; 15486 } 15487 } 15488 return target; 15489 } 15490 function _toConsumableArray( arr ) { 15491 return _arrayWithoutHoles( arr ) || _iterableToArray( arr ) || _unsupportedIterableToArray( arr ) || _nonIterableSpread(); 15492 } 15493 function _arrayWithoutHoles( arr ) { 15494 if ( Array.isArray( arr ) ) { 15495 return _arrayLikeToArray( arr ); 15496 } 15497 } 15498 function _iterableToArray( iter ) { 15499 if ( iter !== undefined && iter !== null && typeof iter[ Symbol.iterator ] === 'function' ) { 15500 return Array.from( iter ); 15501 } 15502 } 15503 function _unsupportedIterableToArray( o, minLen ) { 15504 var n; 15505 if ( ! o ) { 15506 return; 15507 } 15508 if ( typeof o === 'string' ) { 15509 return _arrayLikeToArray( o, minLen ); 15510 } 15511 n = Object.prototype.toString.call( o ).slice( 8, -1 ); 15512 if ( n === 'Object' && o.constructor ) { 15513 n = o.constructor.name; 15514 } 15515 if ( n === 'Map' || n === 'Set' ) { 15516 return Array.from( o ); 15517 } 15518 if ( n === 'Arguments' || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test( n ) ) { 15519 return _arrayLikeToArray( o, minLen ); 15520 } 15521 } 15522 function _arrayLikeToArray( arr, len ) { 15523 var i; 15524 var arr2; 15525 if ( len === undefined || len === null || len > arr.length ) { 15526 len = arr.length; 15527 } 15528 arr2 = new Array( len ); 15529 for ( i = 0; i < len; i++ ) { 15530 arr2[ i ] = arr[ i ]; 15531 } 15532 return arr2; 15533 } 15534 function _nonIterableSpread() { 15535 throw new TypeError( 'Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.' ); 15536 } 15537 15538 function userAgent( pattern ) { 15539 if ( typeof window !== 'undefined' && window.navigator ) { 15540 return !! /*@__PURE__*/navigator.userAgent.match( pattern ); 15541 } 15542 } 15543 function on( el, event, fn ) { 15544 el.addEventListener( event, fn, ! IE11OrLess && captureMode ); 15545 } 15546 function off( el, event, fn ) { 15547 el.removeEventListener( event, fn, ! IE11OrLess && captureMode ); 15548 } 15549 function matches( /**HTMLElement*/el, /**String*/selector ) { 15550 if ( ! selector ) { 15551 return; 15552 } 15553 if ( selector[ 0 ] === '>' ) { 15554 selector = selector.substring( 1 ); 15555 } 15556 if ( el ) { 15557 try { 15558 if ( el.matches ) { 15559 return el.matches( selector ); 15560 } else if ( el.msMatchesSelector ) { 15561 return el.msMatchesSelector( selector ); 15562 } else if ( el.webkitMatchesSelector ) { 15563 return el.webkitMatchesSelector( selector ); 15564 } 15565 } catch ( _ ) { 15566 return false;
15567 } 15568 } 15569 return false; 15570 } 15571 function getParentOrHost( el ) { 15572 return el.host && el !== document && el.host.nodeType ? el.host : el.parentNode; 15573 } 15574 function closest( /**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx, includeCTX ) { 15575 if ( el ) { 15576 ctx = ctx || document; 15577 do { 15578 if ( ( selector !== undefined && selector !== null && ( selector[ 0 ] === '>' ? el.parentNode === ctx && matches( el, selector ) : matches( el, selector ) ) ) || ( includeCTX && el === ctx ) ) { 15579 return el; 15580 } 15581 if ( el === ctx ) { 15582 break; 15583 } 15584 } while ( ( el = getParentOrHost( el ) ) ); 15585 } 15586 return null; 15587 } 15588 function toggleClass( el, name, state ) { 15589 var className; 15590 if ( el && name ) { 15591 if ( el.classList ) { 15592 el.classList[ state ? 'add' : 'remove' ]( name ); 15593 } else { 15594 className = ( ' ' + el.className + ' ' ).replace( R_SPACE, ' ' ).replace( ' ' + name + ' ', ' ' ); 15595 el.className = ( className + ( state ? ' ' + name : '' ) ).replace( R_SPACE, ' ' ); 15596 } 15597 } 15598 } 15599 function css( el, prop, val ) { 15600 var style = el && el.style; 15601 if ( style ) { 15602 if ( val === void 0 ) { 15603 if ( document.defaultView && document.defaultView.getComputedStyle ) { 15604 val = document.defaultView.getComputedStyle( el, '' ); 15605 } else if ( el.currentStyle ) { 15606 val = el.currentStyle; 15607 } 15608 return prop === void 0 ? val : val[ prop ]; 15609 } 15610 if ( ! ( prop in style ) && prop.indexOf( 'webkit' ) === -1 ) { 15611 prop = '-webkit-' + prop; 15612 } 15613 style[ prop ] = val + ( typeof val === 'string' ? '' : 'px' ); 15614 } 15615 } 15616 function matrix( el, selfOnly ) { 15617 var appliedTransforms = ''; 15618 var transform; 15619 var matrixFn; 15620 if ( typeof el === 'string' ) { 15621 appliedTransforms = el; 15622 } else { 15623 do { 15624 transform = css( el, 'transform' ); 15625 if ( transform && transform !== 'none' ) { 15626 appliedTransforms = transform + ' ' + appliedTransforms; 15627 } 15628 } while ( ! selfOnly && ( el = el.parentNode ) ); 15629 } 15630 matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix || window.MSCSSMatrix; 15631 return matrixFn && new matrixFn( appliedTransforms ); 15632 } 15633 function find( ctx, tagName, iterator ) { 15634 if ( ctx ) { 15635 var list = ctx.getElementsByTagName( tagName ), 15636 i = 0, 15637 n = list.length; 15638 if ( iterator ) { 15639 for ( ; i < n; i++ ) { 15640 iterator( list[ i ], i ); 15641 } 15642 } 15643 return list; 15644 } 15645 return []; 15646 } 15647 function getWindowScrollingElement() { 15648 var scrollingElement = document.scrollingElement; 15649 if ( scrollingElement ) { 15650 return scrollingElement; 15651 } 15652 return document.documentElement; 15653 } 15654 15655 /** 15656 * Returns the "bounding client rect" of given element 15657 * @param {HTMLElement} el The element whose boundingClientRect is wanted 15658 * @param {[boolean]} relativeToContainingBlock Whether the rect should be relative to the containing block of (including) the container 15659 * @param {[boolean]} relativeToNonStaticParent Whether the rect should be relative to the relative parent of (including) the contaienr 15660 * @param {[boolean]} undoScale Whether the container's scale() should be undone 15661 * @param {[HTMLElement]} container The parent the element will be placed in 15662 * @return {Object} The boundingClientRect of el, with specified adjustments 15663 */ 15664 function getRect( el, relativeToContainingBlock, relativeToNonStaticParent, undoScale, container ) { 15665 if ( ! el || ( ! el.getBoundingClientRect && el !== window ) ) { 15666 return; 15667 } 15668 var elRect, top, left, bottom, right, height, width; 15669 if ( el !== window && el.parentNode && el !== getWindowScrollingElement() ) { 15670 elRect = el.getBoundingClientRect(); 15671 top = elRect.top; 15672 left = elRect.left; 15673 bottom = elRect.bottom; 15674 right = elRect.right; 15675 height = elRect.height; 15676 width = elRect.width; 15677 } else { 15678 top = 0; 15679 left = 0; 15680 bottom = window.innerHeight; 15681 right = window.innerWidth; 15682 height = window.innerHeight; 15683 width = window.innerWidth; 15684 } 15685 if ( ( relativeToContainingBlock || relativeToNonStaticParent ) && el !== window ) { 15686 // Adjust for translate() 15687 container = container || el.parentNode; 15688 15689 // solves #1123 (see: https://stackoverflow.com/a/37953806/6088312) 15690 // Not needed on <= IE11 15691 if ( ! IE11OrLess ) { 15692 do { 15693 if ( container && container.getBoundingClientRect && ( css( container, 'transform' ) !== 'none' || relativeToNonStaticParent && css( container, 'position' ) !== 'static' ) ) { 15694 var containerRect = container.getBoundingClientRect(); 15695 15696 // Set relative to edges of padding box of container 15697 top -= containerRect.top + parseInt( css( container, 'border-top-width' ), 10 ); 15698 left -= containerRect.left + parseInt( css( container, 'border-left-width' ), 10 ); 15699 bottom = top + elRect.height; 15700 right = left + elRect.width; 15701 break; 15702 } 15703 } while ( container = container.parentNode ); 15704 } 15705 } 15706 if ( undoScale && el !== window ) { 15707 // Adjust for scale() 15708 var elMatrix = matrix( container || el ), 15709 scaleX = elMatrix && elMatrix.a, 15710 scaleY = elMatrix && elMatrix.d; 15711 if ( elMatrix ) { 15712 top /= scaleY; 15713 left /= scaleX; 15714 width /= scaleX; 15715 height /= scaleY; 15716 bottom = top + height; 15717 right = left + width; 15718 } 15719 } 15720 return { 15721 top: top, 15722 left: left, 15723 bottom: bottom, 15724 right: right, 15725 width: width, 15726 height: height 15727 }; 15728 } 15729 15730 /** 15731 * Checks if a side of an element is scrolled past a side of its parents 15732 * @param {HTMLElement} el The element who's side being scrolled out of view is in question 15733 * @param {string} elSide Side of the element in question ('top', 'left', 'right', 'bottom') 15734 * @param {string} parentSide Side of the parent in question ('top', 'left', 'right', 'bottom') 15735 * @return {HTMLElement} The parent scroll element that the el's side is scrolled past, or null if there is no such element 15736 */ 15737 function isScrolledPast( el, elSide, parentSide ) { 15738 var parent = getParentAutoScrollElement( el, true ), 15739 elSideVal = getRect( el )[ elSide ]; 15740 15741 while ( parent ) { 15742 var parentSideVal = getRect( parent )[ parentSide ], 15743 visible = void 0; 15744 if ( parentSide === 'top' || parentSide === 'left' ) { 15745 visible = elSideVal >= parentSideVal; 15746 } else { 15747 visible = elSideVal <= parentSideVal; 15748 } 15749 if ( ! visible ) { 15750 return parent; 15751 }
15752 if ( parent === getWindowScrollingElement() ) { 15753 break; 15754 } 15755 parent = getParentAutoScrollElement( parent, false ); 15756 } 15757 return false; 15758 } 15759 15760 /** 15761 * Gets nth child of el, ignoring hidden children, sortable's elements (does not ignore clone if it's visible) 15762 * and non-draggable elements 15763 * @param {HTMLElement} el The parent element 15764 * @param {number} childNum The index of the child 15765 * @param {Object} options Parent Sortable's options 15766 * @param {boolean} [includeDragEl=false] - If `true`, includes the dragged element in the search. 15767 * @return {HTMLElement} The child at index childNum, or null if not found 15768 */ 15769 function getChild( el, childNum, options, includeDragEl ) { 15770 var currentChild = 0, 15771 i = 0, 15772 children = el.children; 15773 while ( i < children.length ) { 15774 if ( children[ i ].style.display !== 'none' && children[ i ] !== Sortable.ghost && ( includeDragEl || children[ i ] !== Sortable.dragged ) && closest( children[ i ], options.draggable, el, false ) ) { 15775 if ( currentChild === childNum ) { 15776 return children[ i ]; 15777 } 15778 currentChild++; 15779 } 15780 i++; 15781 } 15782 return null; 15783 } 15784 15785 /** 15786 * Gets the last child in the el, ignoring ghostEl or invisible elements (clones) 15787 * @param {HTMLElement} el Parent element 15788 * @param {selector} selector Any other elements that should be ignored 15789 * @return {HTMLElement} The last child, ignoring ghostEl 15790 */ 15791 function lastChild( el, selector ) { 15792 var last = el.lastElementChild; 15793 while ( last && ( last === Sortable.ghost || css( last, 'display' ) === 'none' || selector && ! matches( last, selector ) ) ) { 15794 last = last.previousElementSibling; 15795 } 15796 return last || null; 15797 } 15798 15799 /** 15800 * Returns the index of an element within its parent for a selected set of 15801 * elements 15802 * @param {HTMLElement} el 15803 * @param {selector} selector 15804 * @return {number} 15805 */ 15806 function index( el, selector ) { 15807 var _index = 0; 15808 if ( ! el || ! el.parentNode ) { 15809 return -1; 15810 } 15811 15812 while ( ( el = el.previousElementSibling ) ) { 15813 if ( el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable.clone && ( ! selector || matches( el, selector ) ) ) { 15814 _index++; 15815 } 15816 } 15817 return _index; 15818 } 15819 15820 /** 15821 * Returns the scroll offset of the given element, added with all the scroll offsets of parent elements. 15822 * The value is returned in real pixels. 15823 * @param {HTMLElement} el 15824 * @return {Array} Offsets in the format of [left, top] 15825 */ 15826 function getRelativeScrollOffset( el ) { 15827 var offsetLeft = 0, 15828 offsetTop = 0, 15829 winScroller = getWindowScrollingElement(); 15830 if ( el ) { 15831 do { 15832 var elMatrix = matrix( el ), 15833 scaleX = elMatrix.a, 15834 scaleY = elMatrix.d; 15835 offsetLeft += el.scrollLeft * scaleX; 15836 offsetTop += el.scrollTop * scaleY; 15837 } while ( el !== winScroller && ( el = el.parentNode ) ); 15838 } 15839 return [ offsetLeft, offsetTop ]; 15840 } 15841 15842 /** 15843 * Returns the index of the object within the given array 15844 * @param {Array} arr Array that may or may not hold the object 15845 * @param {Object} obj An object that has a key-value pair unique to and identical to a key-value pair in the object you want to find 15846 * @return {number} The index of the object in the array, or -1 15847 */ 15848 function indexOfObject( arr, obj ) { 15849 for ( var i in arr ) { 15850 if ( ! arr.hasOwnProperty( i ) ) { 15851 continue; 15852 } 15853 for ( var key in obj ) { 15854 if ( obj.hasOwnProperty( key ) && obj[ key ] === arr[ i ][ key ] ) { 15855 return Number( i ); 15856 } 15857 } 15858 } 15859 return -1; 15860 } 15861 function getParentAutoScrollElement( el, includeSelf ) { 15862 // skip to window 15863 if ( ! el || ! el.getBoundingClientRect ) { 15864 return getWindowScrollingElement(); 15865 } 15866 var elem = el; 15867 var gotSelf = false; 15868 do { 15869 // we don't need to get elem css if it isn't even overflowing in the first place (performance) 15870 if ( elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight ) { 15871 var elemCSS = css( elem ); 15872 if ( elem.clientWidth < elem.scrollWidth && ( elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll' ) || elem.clientHeight < elem.scrollHeight && ( elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll' ) ) { 15873 if ( ! elem.getBoundingClientRect || elem === document.body ) { 15874 return getWindowScrollingElement(); 15875 } 15876 if ( gotSelf || includeSelf ) { 15877 return elem; 15878 } 15879 gotSelf = true; 15880 } 15881 } 15882 } while ( ( elem = elem.parentNode ) ); 15883 return getWindowScrollingElement(); 15884 } 15885 function extend( dst, src ) { 15886 var key; 15887 if ( dst && src ) { 15888 for ( key in src ) { 15889 if ( src.hasOwnProperty( key ) ) { 15890 dst[ key ] = src[ key ]; 15891 } 15892 } 15893 } 15894 return dst; 15895 } 15896 function isRectEqual( rect1, rect2 ) { 15897 return Math.round( rect1.top ) === Math.round( rect2.top ) && Math.round( rect1.left ) === Math.round( rect2.left ) && Math.round( rect1.height ) === Math.round( rect2.height ) && Math.round( rect1.width ) === Math.round( rect2.width ); 15898 } 15899 function throttle( callback, ms ) { 15900 return function() { 15901 var args = arguments, 15902 _this = this; 15903 if ( ! _throttleTimeout ) { 15904 if ( args.length === 1 ) { 15905 callback.call( _this, args[ 0 ] ); 15906 } else { 15907 callback.apply( _this, args ); 15908 } 15909 _throttleTimeout = setTimeout( function() { 15910 _throttleTimeout = void 0; 15911 }, ms ); 15912 } 15913 }; 15914 } 15915 function cancelThrottle() { 15916 clearTimeout( _throttleTimeout ); 15917 _throttleTimeout = void 0; 15918 } 15919 function scrollBy( el, x, y ) { 15920 el.scrollLeft += x; 15921 el.scrollTop += y; 15922 } 15923 function clone( el ) { 15924 var Polymer = window.Polymer; 15925 var $ = window.jQuery || window.Zepto; 15926 if ( Polymer && Polymer.dom ) { 15927 return Polymer.dom( el ).cloneNode( true ); 15928 } else if ( $ ) { 15929 return $( el ).clone( true )[ 0 ]; 15930 } 15931 return el.cloneNode( true ); 15932 } 15933 function setRect( el, rect ) { 15934 css( el, 'position', 'absolute' ); 15935 css( el, 'top', rect.top ); 15936 css( el, 'left', rect.left ); 15937 css( el, 'width', rect.width ); 15938 css( el, 'height', rect.height ); 15939 } 15940 function unsetRect( el ) { 15941 css( el, 'position', '' ); 15942 css( el, 'top', '' ); 15943 css( el, 'left', '' ); 15944 css( el, 'width', '' ); 15945 css( el, 'height', '' ); 15946 } 15947 function getChildContainingRectFromElement( container, options, ghostEl ) { 15948 var rect = {}; 15949 Array.from( container.children ).forEach( function( child ) { 15950 var _rect$left, _rect$top, _rect$right, _rect$bottom; 15951 if ( ! closest( child, options.draggable, container, false ) || child.animated || child === ghostEl ) { 15952 return; 15953 } 15954 var childRect = getRect( child ); 15955 rect.left = Math.min( ( _rect$left = rect.left ) !== null && _rect$left !== void 0 ? _rect$left : Infinity, childRect.left ); 15956 rect.top = Math.min( ( _rect$top = rect.top ) !== null && _rect$top !== void 0 ? _rect$top : Infinity, childRect.top ); 15957 rect.right = Math.max( ( _rect$right = rect.right ) !== null && _rect$right !== void 0 ? _rect$right : -Infinity, childRect.right ); 15958 rect.bottom = Math.max( ( _rect$bottom = rect.bottom ) !== null && _rect$bottom !== void 0 ? _rect$bottom : -Infinity, childRect.bottom ); 15959 } ); 15960 rect.width = rect.right - rect.left; 15961 rect.height = rect.bottom - rect.top; 15962 rect.x = rect.left; 15963 rect.y = rect.top; 15964 return rect; 15965 } 15966 15967 function AnimationStateManager() { 15968 var animationStates = [], 15969 animationCallbackId; 15970 return { 15971 captureAnimationState: function captureAnimationState() { 15972 animationStates = []; 15973 if ( ! this.options.animation ) { 15974 return; 15975 } 15976 var children = [].slice.call( this.el.children );
vendor: 4,201 bytes, lines 15977-16093
15977 children.forEach( function( child ) { 15978 if ( css( child, 'display' ) === 'none' || child === Sortable.ghost ) { 15979 return; 15980 } 15981 animationStates.push( { 15982 target: child, 15983 rect: getRect( child ) 15984 } ); 15985 var fromRect = _objectSpread2( {}, animationStates[ animationStates.length - 1 ].rect ); 15986 15987 // If animating: compensate for current animation 15988 if ( child.thisAnimationDuration ) { 15989 var childMatrix = matrix( child, true ); 15990 if ( childMatrix ) { 15991 fromRect.top -= childMatrix.f; 15992 fromRect.left -= childMatrix.e; 15993 } 15994 } 15995 child.fromRect = fromRect; 15996 } ); 15997 }, 15998 addAnimationState: function addAnimationState( state ) { 15999 animationStates.push( state ); 16000 }, 16001 removeAnimationState: function removeAnimationState( target ) { 16002 animationStates.splice( indexOfObject( animationStates, { 16003 target: target 16004 } ), 1 ); 16005 }, 16006 animateAll: function animateAll( callback ) { 16007 var _this = this; 16008 if ( ! this.options.animation ) { 16009 clearTimeout( animationCallbackId ); 16010 if ( typeof callback === 'function' ) { 16011 callback(); 16012 } 16013 return; 16014 } 16015 var animating = false, 16016 animationTime = 0; 16017 animationStates.forEach( function( state ) { 16018 var time = 0, 16019 target = state.target, 16020 fromRect = target.fromRect, 16021 toRect = getRect( target ), 16022 prevFromRect = target.prevFromRect, 16023 prevToRect = target.prevToRect, 16024 animatingRect = state.rect, 16025 targetMatrix = matrix( target, true ); 16026 if ( targetMatrix ) { 16027 // Compensate for current animation 16028 toRect.top -= targetMatrix.f; 16029 toRect.left -= targetMatrix.e; 16030 } 16031 target.toRect = toRect; 16032 if ( target.thisAnimationDuration ) { 16033 // Could also check if animatingRect is between fromRect and toRect 16034 if ( isRectEqual( prevFromRect, toRect ) && ! isRectEqual( fromRect, toRect ) && 16035 // Make sure animatingRect is on line between toRect & fromRect 16036 ( animatingRect.top - toRect.top ) / ( animatingRect.left - toRect.left ) === ( fromRect.top - toRect.top ) / ( fromRect.left - toRect.left ) ) { 16037 // If returning to same place as started from animation and on same axis 16038 time = calculateRealTime( animatingRect, prevFromRect, prevToRect, _this.options ); 16039 } 16040 } 16041 16042 // if fromRect != toRect: animate 16043 if ( ! isRectEqual( toRect, fromRect ) ) { 16044 target.prevFromRect = fromRect; 16045 target.prevToRect = toRect; 16046 if ( ! time ) { 16047 time = _this.options.animation; 16048 } 16049 _this.animate( target, animatingRect, toRect, time ); 16050 } 16051 if ( time ) { 16052 animating = true; 16053 animationTime = Math.max( animationTime, time ); 16054 clearTimeout( target.animationResetTimer ); 16055 target.animationResetTimer = setTimeout( function() { 16056 target.animationTime = 0; 16057 target.prevFromRect = null; 16058 target.fromRect = null; 16059 target.prevToRect = null; 16060 target.thisAnimationDuration = null; 16061 }, time ); 16062 target.thisAnimationDuration = time; 16063 } 16064 } ); 16065 clearTimeout( animationCallbackId ); 16066 if ( ! animating ) { 16067 if ( typeof callback === 'function' ) { 16068 callback(); 16069 } 16070 } else { 16071 animationCallbackId = setTimeout( function() { 16072 if ( typeof callback === 'function' ) { 16073 callback(); 16074 } 16075 }, animationTime ); 16076 } 16077 animationStates = []; 16078 }, 16079 animate: function animate( target, currentRect, toRect, duration ) { 16080 if ( duration ) { 16081 css( target, 'transition', '' ); 16082 css( target, 'transform', '' ); 16083 var elMatrix = matrix( this.el ), 16084 scaleX = elMatrix && elMatrix.a, 16085 scaleY = elMatrix && elMatrix.d, 16086 translateX = ( currentRect.left - toRect.left ) / ( scaleX || 1 ), 16087 translateY = ( currentRect.top - toRect.top ) / ( scaleY || 1 ); 16088 target.animatingX = !! translateX; 16089 target.animatingY = !! translateY; 16090 css( target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)' ); 16091 this.forRepaintDummy = repaint( target ); // repaint 16092 16093 css( target, 'transition', 'transform ' + duration + 'ms' + ( this.options.easing ? ' ' + this.options.easing : '' ) );
vendor: 15,223 bytes, lines 16094-16557
16094 css( target, 'transform', 'translate3d(0,0,0)' ); 16095 typeof target.animated === 'number' && clearTimeout( target.animated ); 16096 target.animated = setTimeout( function() { 16097 css( target, 'transition', '' ); 16098 css( target, 'transform', '' ); 16099 target.animated = false; 16100 target.animatingX = false; 16101 target.animatingY = false; 16102 }, duration ); 16103 } 16104 } 16105 }; 16106 } 16107 function repaint( target ) { 16108 return target.offsetWidth; 16109 } 16110 function calculateRealTime( animatingRect, fromRect, toRect, options ) { 16111 return Math.sqrt( Math.pow( fromRect.top - animatingRect.top, 2 ) + Math.pow( fromRect.left - animatingRect.left, 2 ) ) / Math.sqrt( Math.pow( fromRect.top - toRect.top, 2 ) + Math.pow( fromRect.left - toRect.left, 2 ) ) * options.animation; 16112 } 16113 16114 function dispatchEvent( _ref ) { 16115 var sortable = _ref.sortable, 16116 rootEl = _ref.rootEl, 16117 name = _ref.name, 16118 targetEl = _ref.targetEl, 16119 cloneEl = _ref.cloneEl, 16120 toEl = _ref.toEl, 16121 fromEl = _ref.fromEl, 16122 oldIndex = _ref.oldIndex, 16123 newIndex = _ref.newIndex, 16124 oldDraggableIndex = _ref.oldDraggableIndex, 16125 newDraggableIndex = _ref.newDraggableIndex, 16126 originalEvent = _ref.originalEvent, 16127 putSortable = _ref.putSortable, 16128 extraEventProperties = _ref.extraEventProperties; 16129 sortable = sortable || rootEl && rootEl[ expando ]; 16130 if ( ! sortable ) { 16131 return; 16132 } 16133 var evt, 16134 options = sortable.options, 16135 onName = 'on' + name.charAt( 0 ).toUpperCase() + name.substr( 1 ); 16136 // Support for new CustomEvent feature 16137 if ( window.CustomEvent && ! IE11OrLess && ! Edge ) { 16138 evt = new CustomEvent( name, { 16139 bubbles: true, 16140 cancelable: true 16141 } ); 16142 } else { 16143 evt = document.createEvent( 'Event' ); 16144 evt.initEvent( name, true, true ); 16145 } 16146 evt.to = toEl || rootEl; 16147 evt.from = fromEl || rootEl; 16148 evt.item = targetEl || rootEl; 16149 evt.clone = cloneEl; 16150 evt.oldIndex = oldIndex; 16151 evt.newIndex = newIndex; 16152 evt.oldDraggableIndex = oldDraggableIndex; 16153 evt.newDraggableIndex = newDraggableIndex; 16154 evt.originalEvent = originalEvent; 16155 evt.pullMode = putSortable ? putSortable.lastPutMode : undefined; 16156 var allEventProperties = _objectSpread2( _objectSpread2( {}, extraEventProperties ), PluginManager.getEventProperties( name, sortable ) ); 16157 for ( var option in allEventProperties ) { 16158 evt[ option ] = allEventProperties[ option ]; 16159 } 16160 if ( rootEl ) { 16161 rootEl.dispatchEvent( evt ); 16162 } 16163 if ( options[ onName ] ) { 16164 options[ onName ].call( sortable, evt ); 16165 } 16166 } 16167 16168 function _dispatchEvent( info ) { 16169 dispatchEvent( _objectSpread2( { 16170 putSortable: putSortable, 16171 cloneEl: cloneEl, 16172 targetEl: dragEl, 16173 rootEl: rootEl, 16174 oldIndex: oldIndex, 16175 oldDraggableIndex: oldDraggableIndex, 16176 newIndex: newIndex, 16177 newDraggableIndex: newDraggableIndex 16178 }, info ) ); 16179 } 16180 16181 // #1184 fix - Prevent click event on fallback if dragged but item not changed position 16182 if ( documentExists && ! ChromeForAndroid ) { 16183 document.addEventListener( 'click', function( evt ) { 16184 if ( ignoreNextClick ) { 16185 evt.preventDefault(); 16186 evt.stopPropagation && evt.stopPropagation(); 16187 evt.stopImmediatePropagation && evt.stopImmediatePropagation(); 16188 ignoreNextClick = false; 16189 return false; 16190 } 16191 }, true ); 16192 } 16193 16194 /** 16195 * @class Sortable 16196 * @param {HTMLElement} el 16197 * @param {Object} [options] 16198 */ 16199 function Sortable( el, options ) { 16200 var _defaults; 16201 var name; 16202 var fn; 16203 if ( ! ( el && el.nodeType && el.nodeType === 1 ) ) { 16204 throw 'Sortable: `el` must be an HTMLElement, not '.concat( {}.toString.call( el ) ); 16205 } 16206 this.el = el; // root element 16207 this.options = options = _extends( {}, options ); 16208 16209 // Export instance 16210 el[ expando ] = this; 16211 _defaults = { 16212 group: null, 16213 sort: true, 16214 disabled: false, 16215 store: null, 16216 handle: null, 16217 draggable: /^[uo]l$/i.test( el.nodeName ) ? '>li' : '>*', 16218 swapThreshold: 1, 16219 // percentage; 0 <= x <= 1 16220 invertSwap: false, 16221 // invert always 16222 invertedSwapThreshold: null, 16223 // will be set to same as swapThreshold if default 16224 removeCloneOnHide: true, 16225 direction: function direction() { 16226 return _detectDirection( el, this.options ); 16227 }, 16228 ghostClass: 'sortable-ghost', 16229 chosenClass: 'sortable-chosen', 16230 dragClass: 'sortable-drag', 16231 ignore: 'a, img', 16232 filter: null, 16233 preventOnFilter: true, 16234 animation: 0, 16235 easing: null, 16236 setData: function setData( dataTransfer, dragEl ) { 16237 dataTransfer.setData( 'Text', dragEl.textContent ); 16238 }, 16239 dropBubble: false, 16240 dragoverBubble: false, 16241 dataIdAttr: 'data-id', 16242 delay: 0, 16243 delayOnTouchOnly: false, 16244 touchStartThreshold: ( Number.parseInt ? Number : window ).parseInt( window.devicePixelRatio, 10 ) || 1, 16245 forceFallback: false, 16246 fallbackClass: 'sortable-fallback', 16247 fallbackOnBody: false, 16248 fallbackTolerance: 0, 16249 fallbackOffset: { 16250 x: 0, 16251 y: 0 16252 }, 16253 // Disabled on Safari: #1571; Enabled on Safari IOS: #2244 16254 supportPointer: Sortable.supportPointer !== false && 'PointerEvent' in window && ( ! Safari || IOS ), 16255 emptyInsertThreshold: 5 16256 }; 16257 PluginManager.initializePlugins( this, el, _defaults ); 16258 16259 // Set default options 16260 for ( name in _defaults ) { 16261 if ( ! ( name in options ) ) { 16262 options[ name ] = _defaults[ name ]; 16263 } 16264 } 16265 _prepareGroup( options ); 16266 16267 // Bind all private methods 16268 for ( fn in this ) { 16269 if ( fn.charAt( 0 ) === '_' && typeof this[ fn ] === 'function' ) { 16270 this[ fn ] = this[ fn ].bind( this ); 16271 } 16272 } 16273 16274 // Setup drag mode 16275 this.nativeDraggable = options.forceFallback ? false : supportDraggable; 16276 if ( this.nativeDraggable ) { 16277 // Touch start threshold cannot be greater than the native dragstart threshold 16278 this.options.touchStartThreshold = 1; 16279 } 16280 16281 // Bind events 16282 if ( options.supportPointer ) { 16283 on( el, 'pointerdown', this._onTapStart ); 16284 } else { 16285 on( el, 'mousedown', this._onTapStart ); 16286 on( el, 'touchstart', this._onTapStart ); 16287 } 16288 if ( this.nativeDraggable ) { 16289 on( el, 'dragover', this ); 16290 on( el, 'dragenter', this ); 16291 } 16292 sortables.push( this.el ); 16293 16294 // Restore sorting 16295 if ( options.store && options.store.get ) { 16296 this.sort( options.store.get( this ) || [] ); 16297 } 16298 16299 // Add animation state manager 16300 _extends( this, AnimationStateManager() ); 16301 } 16302 Sortable.prototype = /** @lends Sortable.prototype */{ 16303 constructor: Sortable, 16304 _isOutsideThisEl: function _isOutsideThisEl( target ) { 16305 if ( ! this.el.contains( target ) && target !== this.el ) { 16306 lastTarget = null; 16307 } 16308 }, 16309 _getDirection: function _getDirection( evt, target ) { 16310 return typeof this.options.direction === 'function' ? this.options.direction.call( this, evt, target, dragEl ) : this.options.direction; 16311 }, 16312 _onTapStart: function _onTapStart( /** Event|TouchEvent */evt ) { 16313 if ( ! evt.cancelable ) { 16314 return; 16315 } 16316 var _this = this, 16317 el = this.el, 16318 options = this.options, 16319 preventOnFilter = options.preventOnFilter, 16320 type = evt.type, 16321 touch = evt.touches && evt.touches[ 0 ] || evt.pointerType && evt.pointerType === 'touch' && evt, 16322 target = ( touch || evt ).target, 16323 originalTarget = evt.target.shadowRoot && ( evt.path && evt.path[ 0 ] || evt.composedPath && evt.composedPath()[ 0 ] ) || target, 16324 filter = options.filter; 16325 _saveInputCheckedState( el ); 16326 16327 // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group. 16328 if ( dragEl ) { 16329 return; 16330 } 16331 if ( /mousedown|pointerdown/.test( type ) && evt.button !== 0 || options.disabled ) { 16332 return; // only left button and enabled 16333 } 16334 16335 // cancel dnd if original target is content editable 16336 if ( originalTarget.isContentEditable ) { 16337 return; 16338 } 16339 16340 // Safari ignores further event handling after mousedown 16341 if ( ! this.nativeDraggable && Safari && target && target.tagName.toUpperCase() === 'SELECT' ) { 16342 return; 16343 } 16344 target = closest( target, options.draggable, el, false ); 16345 if ( target && target.animated ) { 16346 return; 16347 } 16348 if ( lastDownEl === target ) { 16349 // Ignoring duplicate `down` 16350 return; 16351 } 16352 16353 // Get the index of the dragged element within its parent 16354 oldIndex = index( target ); 16355 oldDraggableIndex = index( target, options.draggable ); 16356 16357 // Check filter 16358 if ( typeof filter === 'function' ) { 16359 if ( filter.call( this, evt, target, this ) ) { 16360 _dispatchEvent( { 16361 sortable: _this, 16362 rootEl: originalTarget, 16363 name: 'filter', 16364 targetEl: target, 16365 toEl: el, 16366 fromEl: el 16367 } ); 16368 pluginEvent( 'filter', _this, { 16369 evt: evt 16370 } ); 16371 preventOnFilter && evt.preventDefault(); 16372 return; // cancel dnd 16373 } 16374 } else if ( filter ) { 16375 filter = filter.split( ',' ).some( function( criteria ) { 16376 criteria = closest( originalTarget, criteria.trim(), el, false ); 16377 if ( criteria ) { 16378 _dispatchEvent( { 16379 sortable: _this, 16380 rootEl: criteria, 16381 name: 'filter', 16382 targetEl: target, 16383 fromEl: el, 16384 toEl: el 16385 } ); 16386 pluginEvent( 'filter', _this, { 16387 evt: evt 16388 } ); 16389 return true; 16390 } 16391 } ); 16392 if ( filter ) { 16393 preventOnFilter && evt.preventDefault(); 16394 return; // cancel dnd 16395 } 16396 } 16397 if ( options.handle && ! closest( originalTarget, options.handle, el, false ) ) { 16398 return; 16399 } 16400 16401 // Prepare `dragstart` 16402 this._prepareDragStart( evt, touch, target ); 16403 }, 16404 _prepareDragStart: function _prepareDragStart( /** Event */evt, /** Touch */touch, /** HTMLElement */target ) { 16405 var _this = this, 16406 el = _this.el, 16407 options = _this.options, 16408 ownerDocument = el.ownerDocument, 16409 dragStartFn; 16410 if ( target && ! dragEl && target.parentNode === el ) { 16411 var dragRect = getRect( target ); 16412 rootEl = el; 16413 dragEl = target; 16414 parentEl = dragEl.parentNode; 16415 nextEl = dragEl.nextSibling; 16416 lastDownEl = target; 16417 activeGroup = options.group; 16418 Sortable.dragged = dragEl; 16419 tapEvt = { 16420 target: dragEl, 16421 clientX: ( touch || evt ).clientX, 16422 clientY: ( touch || evt ).clientY 16423 }; 16424 tapDistanceLeft = tapEvt.clientX - dragRect.left; 16425 tapDistanceTop = tapEvt.clientY - dragRect.top; 16426 this._lastX = ( touch || evt ).clientX; 16427 this._lastY = ( touch || evt ).clientY; 16428 dragEl.style[ 'will-change' ] = 'all'; 16429 dragStartFn = function dragStartFn() { 16430 pluginEvent( 'delayEnded', _this, { 16431 evt: evt 16432 } ); 16433 if ( Sortable.eventCanceled ) { 16434 _this._onDrop(); 16435 return; 16436 } 16437 // Delayed drag has been triggered 16438 // we can re-enable the events: touchmove/mousemove 16439 _this._disableDelayedDragEvents(); 16440 if ( ! FireFox && _this.nativeDraggable ) { 16441 dragEl.draggable = true; 16442 } 16443 16444 // Bind the events: dragstart/dragend 16445 _this._triggerDragStart( evt, touch ); 16446 16447 // Drag start event 16448 _dispatchEvent( { 16449 sortable: _this, 16450 name: 'choose', 16451 originalEvent: evt 16452 } ); 16453 16454 // Chosen item 16455 toggleClass( dragEl, options.chosenClass, true ); 16456 }; 16457 16458 // Disable "draggable" 16459 options.ignore.split( ',' ).forEach( function( criteria ) { 16460 find( dragEl, criteria.trim(), _disableDraggable ); 16461 } ); 16462 on( ownerDocument, 'dragover', nearestEmptyInsertDetectEvent ); 16463 on( ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent ); 16464 on( ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent ); 16465 if ( options.supportPointer ) { 16466 on( ownerDocument, 'pointerup', _this._onDrop ); 16467 // Native D&D triggers pointercancel 16468 ! this.nativeDraggable && on( ownerDocument, 'pointercancel', _this._onDrop ); 16469 } else { 16470 on( ownerDocument, 'mouseup', _this._onDrop ); 16471 on( ownerDocument, 'touchend', _this._onDrop ); 16472 on( ownerDocument, 'touchcancel', _this._onDrop ); 16473 } 16474 16475 // Make dragEl draggable (must be before delay for FireFox) 16476 if ( FireFox && this.nativeDraggable ) { 16477 this.options.touchStartThreshold = 4; 16478 dragEl.draggable = true; 16479 } 16480 pluginEvent( 'delayStart', this, { 16481 evt: evt 16482 } ); 16483 16484 // Delay is impossible for native DnD in Edge or IE 16485 if ( options.delay && ( ! options.delayOnTouchOnly || touch ) && ( ! this.nativeDraggable || ! ( Edge || IE11OrLess ) ) ) { 16486 if ( Sortable.eventCanceled ) { 16487 this._onDrop(); 16488 return; 16489 } 16490 // If the user moves the pointer or let go the click or touch 16491 // before the delay has been reached: 16492 // disable the delayed drag 16493 if ( options.supportPointer ) { 16494 on( ownerDocument, 'pointerup', _this._disableDelayedDrag ); 16495 on( ownerDocument, 'pointercancel', _this._disableDelayedDrag ); 16496 } else { 16497 on( ownerDocument, 'mouseup', _this._disableDelayedDrag ); 16498 on( ownerDocument, 'touchend', _this._disableDelayedDrag ); 16499 on( ownerDocument, 'touchcancel', _this._disableDelayedDrag ); 16500 } 16501 on( ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler ); 16502 on( ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler ); 16503 options.supportPointer && on( ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler ); 16504 _this._dragStartTimer = setTimeout( dragStartFn, options.delay ); 16505 } else { 16506 dragStartFn(); 16507 } 16508 } 16509 }, 16510 _delayedDragTouchMoveHandler: function _delayedDragTouchMoveHandler( /** TouchEvent|PointerEvent */e ) { 16511 var touch = e.touches ? e.touches[ 0 ] : e; 16512 if ( Math.max( Math.abs( touch.clientX - this._lastX ), Math.abs( touch.clientY - this._lastY ) ) >= Math.floor( this.options.touchStartThreshold / ( this.nativeDraggable && window.devicePixelRatio || 1 ) ) ) { 16513 this._disableDelayedDrag(); 16514 } 16515 }, 16516 _disableDelayedDrag: function _disableDelayedDrag() { 16517 dragEl && _disableDraggable( dragEl ); 16518 clearTimeout( this._dragStartTimer ); 16519 this._disableDelayedDragEvents(); 16520 }, 16521 _disableDelayedDragEvents: function _disableDelayedDragEvents() { 16522 var ownerDocument = this.el.ownerDocument; 16523 off( ownerDocument, 'mouseup', this._disableDelayedDrag ); 16524 off( ownerDocument, 'touchend', this._disableDelayedDrag ); 16525 off( ownerDocument, 'touchcancel', this._disableDelayedDrag ); 16526 off( ownerDocument, 'pointerup', this._disableDelayedDrag ); 16527 off( ownerDocument, 'pointercancel', this._disableDelayedDrag ); 16528 off( ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler ); 16529 off( ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler ); 16530 off( ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler ); 16531 }, 16532 _triggerDragStart: function _triggerDragStart( /** Event */evt, /** Touch */touch ) { 16533 touch = touch || evt.pointerType == 'touch' && evt; 16534 if ( ! this.nativeDraggable || touch ) { 16535 if ( this.options.supportPointer ) { 16536 on( document, 'pointermove', this._onTouchMove ); 16537 } else if ( touch ) { 16538 on( document, 'touchmove', this._onTouchMove ); 16539 } else { 16540 on( document, 'mousemove', this._onTouchMove ); 16541 } 16542 } else { 16543 on( dragEl, 'dragend', this ); 16544 on( rootEl, 'dragstart', this._onDragStart ); 16545 } 16546 try { 16547 if ( document.selection ) { 16548 _nextTick( function() { 16549 document.selection.empty(); 16550 } ); 16551 } else { 16552 window.getSelection().removeAllRanges(); 16553 } 16554 } catch ( err ) {} 16555 }, 16556 _dragStarted: function _dragStarted( fallback, evt ) { 16557 awaitingDragStarted = false;
vendor: 5,416 bytes, lines 16558-16701
16558 if ( rootEl && dragEl ) { 16559 pluginEvent( 'dragStarted', this, { 16560 evt: evt 16561 } ); 16562 if ( this.nativeDraggable ) { 16563 on( document, 'dragover', _checkOutsideTargetEl ); 16564 } 16565 var options = this.options; 16566 16567 // Apply effect 16568 ! fallback && toggleClass( dragEl, options.dragClass, false ); 16569 toggleClass( dragEl, options.ghostClass, true ); 16570 Sortable.active = this; 16571 fallback && this._appendGhost(); 16572 16573 // Drag start event 16574 _dispatchEvent( { 16575 sortable: this, 16576 name: 'start', 16577 originalEvent: evt 16578 } ); 16579 } else { 16580 this._nulling(); 16581 } 16582 }, 16583 _emulateDragOver: function _emulateDragOver() { 16584 if ( touchEvt ) { 16585 this._lastX = touchEvt.clientX; 16586 this._lastY = touchEvt.clientY; 16587 _hideGhostForTarget(); 16588 var target = document.elementFromPoint( touchEvt.clientX, touchEvt.clientY ); 16589 var parent = target; 16590 while ( target && target.shadowRoot ) { 16591 target = target.shadowRoot.elementFromPoint( touchEvt.clientX, touchEvt.clientY ); 16592 if ( target === parent ) { 16593 break; 16594 } 16595 parent = target; 16596 } 16597 dragEl.parentNode[ expando ]._isOutsideThisEl( target ); 16598 if ( parent ) { 16599 do { 16600 if ( parent[ expando ] ) { 16601 var inserted = void 0; 16602 inserted = parent[ expando ]._onDragOver( { 16603 clientX: touchEvt.clientX, 16604 clientY: touchEvt.clientY, 16605 target: target, 16606 rootEl: parent 16607 } ); 16608 if ( inserted && ! this.options.dragoverBubble ) { 16609 break; 16610 } 16611 } 16612 target = parent; // store last element 16613 } 16614 while ( ( parent = getParentOrHost( parent ) ) ); 16615 } 16616 _unhideGhostForTarget(); 16617 } 16618 }, 16619 _onTouchMove: function _onTouchMove( /**TouchEvent*/evt ) { 16620 if ( tapEvt ) { 16621 var options = this.options, 16622 fallbackTolerance = options.fallbackTolerance, 16623 fallbackOffset = options.fallbackOffset, 16624 touch = evt.touches ? evt.touches[ 0 ] : evt, 16625 ghostMatrix = ghostEl && matrix( ghostEl, true ), 16626 scaleX = ghostEl && ghostMatrix && ghostMatrix.a, 16627 scaleY = ghostEl && ghostMatrix && ghostMatrix.d, 16628 relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset( ghostRelativeParent ), 16629 dx = ( touch.clientX - tapEvt.clientX + fallbackOffset.x ) / ( scaleX || 1 ) + ( relativeScrollOffset ? relativeScrollOffset[ 0 ] - ghostRelativeParentInitialScroll[ 0 ] : 0 ) / ( scaleX || 1 ), 16630 dy = ( touch.clientY - tapEvt.clientY + fallbackOffset.y ) / ( scaleY || 1 ) + ( relativeScrollOffset ? relativeScrollOffset[ 1 ] - ghostRelativeParentInitialScroll[ 1 ] : 0 ) / ( scaleY || 1 ); 16631 16632 // only set the status to dragging, when we are actually dragging 16633 if ( ! Sortable.active && ! awaitingDragStarted ) { 16634 if ( fallbackTolerance && Math.max( Math.abs( touch.clientX - this._lastX ), Math.abs( touch.clientY - this._lastY ) ) < fallbackTolerance ) { 16635 return; 16636 } 16637 this._onDragStart( evt, true ); 16638 } 16639 if ( ghostEl ) { 16640 if ( ghostMatrix ) { 16641 ghostMatrix.e += dx - ( lastDx || 0 ); 16642 ghostMatrix.f += dy - ( lastDy || 0 ); 16643 } else { 16644 ghostMatrix = { 16645 a: 1, 16646 b: 0, 16647 c: 0, 16648 d: 1, 16649 e: dx, 16650 f: dy 16651 }; 16652 } 16653 var cssMatrix = 'matrix('.concat( ghostMatrix.a, ',' ).concat( ghostMatrix.b, ',' ).concat( ghostMatrix.c, ',' ).concat( ghostMatrix.d, ',' ).concat( ghostMatrix.e, ',' ).concat( ghostMatrix.f, ')' ); 16654 css( ghostEl, 'webkitTransform', cssMatrix ); 16655 css( ghostEl, 'mozTransform', cssMatrix ); 16656 css( ghostEl, 'msTransform', cssMatrix ); 16657 css( ghostEl, 'transform', cssMatrix ); 16658 lastDx = dx; 16659 lastDy = dy; 16660 touchEvt = touch; 16661 } 16662 evt.cancelable && evt.preventDefault(); 16663 } 16664 }, 16665 _appendGhost: function _appendGhost() { 16666 // Bug if using scale(): https://stackoverflow.com/questions/2637058 16667 // Not being adjusted for 16668 if ( ! ghostEl ) { 16669 var container = this.options.fallbackOnBody ? document.body : rootEl, 16670 rect = getRect( dragEl, true, PositionGhostAbsolutely, true, container ), 16671 options = this.options; 16672 16673 // Position absolutely 16674 if ( PositionGhostAbsolutely ) { 16675 // Get relatively positioned parent 16676 ghostRelativeParent = container; 16677 while ( css( ghostRelativeParent, 'position' ) === 'static' && css( ghostRelativeParent, 'transform' ) === 'none' && ghostRelativeParent !== document ) { 16678 ghostRelativeParent = ghostRelativeParent.parentNode; 16679 } 16680 if ( ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement ) { 16681 if ( ghostRelativeParent === document ) { 16682 ghostRelativeParent = getWindowScrollingElement(); 16683 } 16684 rect.top += ghostRelativeParent.scrollTop; 16685 rect.left += ghostRelativeParent.scrollLeft; 16686 } else { 16687 ghostRelativeParent = getWindowScrollingElement(); 16688 } 16689 ghostRelativeParentInitialScroll = getRelativeScrollOffset( ghostRelativeParent ); 16690 } 16691 ghostEl = dragEl.cloneNode( true ); 16692 toggleClass( ghostEl, options.ghostClass, false ); 16693 toggleClass( ghostEl, options.fallbackClass, true ); 16694 toggleClass( ghostEl, options.dragClass, true ); 16695 css( ghostEl, 'transition', '' ); 16696 css( ghostEl, 'transform', '' ); 16697 css( ghostEl, 'box-sizing', 'border-box' ); 16698 css( ghostEl, 'margin', 0 ); 16699 css( ghostEl, 'top', rect.top ); 16700 css( ghostEl, 'left', rect.left ); 16701 css( ghostEl, 'width', rect.width );
vendor: 4,303 bytes, lines 16702-16839
16702 css( ghostEl, 'height', rect.height ); 16703 css( ghostEl, 'opacity', '0.8' ); 16704 css( ghostEl, 'position', PositionGhostAbsolutely ? 'absolute' : 'fixed' ); 16705 css( ghostEl, 'zIndex', '100000' ); 16706 css( ghostEl, 'pointerEvents', 'none' ); 16707 Sortable.ghost = ghostEl; 16708 container.appendChild( ghostEl ); 16709 16710 // Set transform-origin 16711 css( ghostEl, 'transform-origin', ( tapDistanceLeft / parseInt( ghostEl.style.width, 10 ) * 100 ) + '% ' + ( tapDistanceTop / parseInt( ghostEl.style.height, 10 ) * 100 ) + '%' ); 16712 } 16713 }, 16714 _onDragStart: function _onDragStart( /**Event*/evt, /**boolean*/fallback ) { 16715 var _this = this; 16716 var dataTransfer = evt.dataTransfer; 16717 var options = _this.options; 16718 pluginEvent( 'dragStart', this, { 16719 evt: evt 16720 } ); 16721 if ( Sortable.eventCanceled ) { 16722 this._onDrop(); 16723 return; 16724 } 16725 pluginEvent( 'setupClone', this ); 16726 if ( ! Sortable.eventCanceled ) { 16727 cloneEl = clone( dragEl ); 16728 cloneEl.removeAttribute( 'id' ); 16729 cloneEl.draggable = false; 16730 cloneEl.style[ 'will-change' ] = ''; 16731 this._hideClone(); 16732 toggleClass( cloneEl, this.options.chosenClass, false ); 16733 Sortable.clone = cloneEl; 16734 } 16735 16736 // #1143: IFrame support workaround 16737 _this.cloneId = _nextTick( function() { 16738 pluginEvent( 'clone', _this ); 16739 if ( Sortable.eventCanceled ) { 16740 return; 16741 } 16742 if ( ! _this.options.removeCloneOnHide ) { 16743 rootEl.insertBefore( cloneEl, dragEl ); 16744 } 16745 _this._hideClone(); 16746 _dispatchEvent( { 16747 sortable: _this, 16748 name: 'clone' 16749 } ); 16750 } ); 16751 ! fallback && toggleClass( dragEl, options.dragClass, true ); 16752 16753 // Set proper drop events 16754 if ( fallback ) { 16755 ignoreNextClick = true; 16756 _this._loopId = setInterval( _this._emulateDragOver, 50 ); 16757 } else { 16758 // Undo what was set in _prepareDragStart before drag started 16759 off( document, 'mouseup', _this._onDrop ); 16760 off( document, 'touchend', _this._onDrop ); 16761 off( document, 'touchcancel', _this._onDrop ); 16762 if ( dataTransfer ) { 16763 dataTransfer.effectAllowed = 'move'; 16764 options.setData && options.setData.call( _this, dataTransfer, dragEl ); 16765 } 16766 on( document, 'drop', _this ); 16767 16768 // #1276 fix: 16769 css( dragEl, 'transform', 'translateZ(0)' ); 16770 } 16771 awaitingDragStarted = true; 16772 _this._dragStartId = _nextTick( _this._dragStarted.bind( _this, fallback, evt ) ); 16773 on( document, 'selectstart', _this ); 16774 moved = true; 16775 window.getSelection().removeAllRanges(); 16776 if ( Safari ) { 16777 css( document.body, 'user-select', 'none' ); 16778 } 16779 }, 16780 // Returns true - if no further action is needed (either inserted or another condition) 16781 _onDragOver: function _onDragOver( /**Event*/evt ) { 16782 var el = this.el, 16783 target = evt.target, 16784 dragRect, 16785 targetRect, 16786 revert, 16787 options = this.options, 16788 group = options.group, 16789 activeSortable = Sortable.active, 16790 isOwner = activeGroup === group, 16791 canSort = options.sort, 16792 fromSortable = putSortable || activeSortable, 16793 vertical, 16794 _this = this, 16795 completedFired = false; 16796 if ( _silent ) { 16797 return; 16798 } 16799 function dragOverEvent( name, extra ) { 16800 pluginEvent( name, _this, _objectSpread2( { 16801 evt: evt, 16802 isOwner: isOwner, 16803 axis: vertical ? 'vertical' : 'horizontal', 16804 revert: revert, 16805 dragRect: dragRect, 16806 targetRect: targetRect, 16807 canSort: canSort, 16808 fromSortable: fromSortable, 16809 target: target, 16810 completed: completed, 16811 onMove: function onMove( target, after ) { 16812 return _onMove( rootEl, el, dragEl, dragRect, target, getRect( target ), evt, after ); 16813 }, 16814 changed: changed 16815 }, extra ) ); 16816 } 16817 16818 // Capture animation state 16819 function capture() { 16820 dragOverEvent( 'dragOverAnimationCapture' ); 16821 _this.captureAnimationState(); 16822 if ( _this !== fromSortable ) { 16823 fromSortable.captureAnimationState(); 16824 } 16825 } 16826 16827 // Return invocation when dragEl is inserted (or completed) 16828 function completed( insertion ) { 16829 dragOverEvent( 'dragOverCompleted', { 16830 insertion: insertion 16831 } ); 16832 if ( insertion ) { 16833 // Clones must be hidden before folding animation to capture dragRectAbsolute properly 16834 if ( isOwner ) { 16835 activeSortable._hideClone(); 16836 } else { 16837 activeSortable._showClone( _this ); 16838 } 16839 if ( _this !== fromSortable ) {
vendor: 5,070 bytes, lines 16840-16979
16840 // Set ghost class to new sortable's ghost class 16841 toggleClass( dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false ); 16842 toggleClass( dragEl, options.ghostClass, true ); 16843 } 16844 if ( putSortable !== _this && _this !== Sortable.active ) { 16845 putSortable = _this; 16846 } else if ( _this === Sortable.active && putSortable ) { 16847 putSortable = null; 16848 } 16849 16850 // Animation 16851 if ( fromSortable === _this ) { 16852 _this._ignoreWhileAnimating = target; 16853 } 16854 _this.animateAll( function() { 16855 dragOverEvent( 'dragOverAnimationComplete' ); 16856 _this._ignoreWhileAnimating = null; 16857 } ); 16858 if ( _this !== fromSortable ) { 16859 fromSortable.animateAll(); 16860 fromSortable._ignoreWhileAnimating = null; 16861 } 16862 } 16863 16864 // Null lastTarget if it is not inside a previously swapped element 16865 if ( target === dragEl && ! dragEl.animated || target === el && ! target.animated ) { 16866 lastTarget = null; 16867 } 16868 16869 // no bubbling and not fallback 16870 if ( ! options.dragoverBubble && ! evt.rootEl && target !== document ) { 16871 dragEl.parentNode[ expando ]._isOutsideThisEl( evt.target ); 16872 16873 // Do not detect for empty insert if already inserted 16874 ! insertion && nearestEmptyInsertDetectEvent( evt ); 16875 } 16876 ! options.dragoverBubble && evt.stopPropagation && evt.stopPropagation(); 16877 return completedFired = true; 16878 } 16879 16880 // Call when dragEl has been inserted 16881 function changed() { 16882 newIndex = index( dragEl ); 16883 newDraggableIndex = index( dragEl, options.draggable ); 16884 _dispatchEvent( { 16885 sortable: _this, 16886 name: 'change', 16887 toEl: el, 16888 newIndex: newIndex, 16889 newDraggableIndex: newDraggableIndex, 16890 originalEvent: evt 16891 } ); 16892 } 16893 if ( evt.preventDefault !== void 0 ) { 16894 evt.cancelable && evt.preventDefault(); 16895 } 16896 target = closest( target, options.draggable, el, true ); 16897 dragOverEvent( 'dragOver' ); 16898 if ( Sortable.eventCanceled ) { 16899 return completedFired; 16900 } 16901 if ( dragEl.contains( evt.target ) || target.animated && target.animatingX && target.animatingY || _this._ignoreWhileAnimating === target ) { 16902 return completed( false ); 16903 } 16904 ignoreNextClick = false; 16905 if ( activeSortable && ! options.disabled && ( isOwner ? canSort || ( revert = parentEl !== rootEl ) // Reverting item into the original list 16906 : putSortable === this || ( this.lastPutMode = activeGroup.checkPull( this, activeSortable, dragEl, evt ) ) && group.checkPut( this, activeSortable, dragEl, evt ) ) ) { 16907 vertical = this._getDirection( evt, target ) === 'vertical'; 16908 dragRect = getRect( dragEl ); 16909 dragOverEvent( 'dragOverValid' ); 16910 if ( Sortable.eventCanceled ) { 16911 return completedFired; 16912 } 16913 if ( revert ) { 16914 parentEl = rootEl; // actualization 16915 capture(); 16916 this._hideClone(); 16917 dragOverEvent( 'revert' ); 16918 if ( ! Sortable.eventCanceled ) { 16919 if ( nextEl ) { 16920 rootEl.insertBefore( dragEl, nextEl ); 16921 } else { 16922 rootEl.appendChild( dragEl ); 16923 } 16924 } 16925 return completed( true ); 16926 } 16927 var elLastChild = lastChild( el, options.draggable ); 16928 if ( ! elLastChild || _ghostIsLast( evt, vertical, this ) && ! elLastChild.animated ) { 16929 // Insert to end of list 16930 16931 // If already at end of list: Do not insert 16932 if ( elLastChild === dragEl ) { 16933 return completed( false ); 16934 } 16935 16936 // if there is a last element, it is the target 16937 if ( elLastChild && el === evt.target ) { 16938 target = elLastChild; 16939 } 16940 if ( target ) { 16941 targetRect = getRect( target ); 16942 } 16943 if ( _onMove( rootEl, el, dragEl, dragRect, target, targetRect, evt, !! target ) !== false ) { 16944 capture(); 16945 if ( elLastChild && elLastChild.nextSibling ) { 16946 // the last draggable element is not the last node 16947 el.insertBefore( dragEl, elLastChild.nextSibling ); 16948 } else { 16949 el.appendChild( dragEl ); 16950 } 16951 parentEl = el; // actualization 16952 16953 changed(); 16954 return completed( true ); 16955 } 16956 } else if ( elLastChild && _ghostIsFirst( evt, vertical, this ) ) { 16957 // Insert to start of list 16958 var firstChild = getChild( el, 0, options, true ); 16959 if ( firstChild === dragEl ) { 16960 return completed( false ); 16961 } 16962 target = firstChild; 16963 targetRect = getRect( target ); 16964 if ( _onMove( rootEl, el, dragEl, dragRect, target, targetRect, evt, false ) !== false ) { 16965 capture(); 16966 el.insertBefore( dragEl, firstChild ); 16967 parentEl = el; // actualization 16968 16969 changed(); 16970 return completed( true ); 16971 } 16972 } else if ( target.parentNode === el ) { 16973 targetRect = getRect( target ); 16974 var direction = 0, 16975 targetBeforeFirstSwap, 16976 differentLevel = dragEl.parentNode !== el, 16977 differentRowCol = ! _dragElInRowColumn( dragEl.animated && dragEl.toRect || dragRect, target.animated && target.toRect || targetRect, vertical ), 16978 side1 = vertical ? 'top' : 'left', 16979 scrolledPastTop = isScrolledPast( target, 'top', 'top' ) || isScrolledPast( dragEl, 'top', 'top' ),
vendor: 1,709 bytes, lines 16980-17018
16980 scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0; 16981 if ( lastTarget !== target ) { 16982 targetBeforeFirstSwap = targetRect[ side1 ]; 16983 pastFirstInvertThresh = false; 16984 isCircumstantialInvert = ! differentRowCol && options.invertSwap || differentLevel; 16985 } 16986 direction = _getSwapDirection( evt, target, targetRect, vertical, differentRowCol ? 1 : options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target ); 16987 var sibling; 16988 if ( direction !== 0 ) { 16989 // Check if target is beside dragEl in respective direction (ignoring hidden elements) 16990 var dragIndex = index( dragEl ); 16991 do { 16992 dragIndex -= direction; 16993 sibling = parentEl.children[ dragIndex ]; 16994 } while ( sibling && ( css( sibling, 'display' ) === 'none' || sibling === ghostEl ) ); 16995 } 16996 // If dragEl is already beside target: Do not insert 16997 if ( direction === 0 || sibling === target ) { 16998 return completed( false ); 16999 } 17000 lastTarget = target; 17001 lastDirection = direction; 17002 var nextSibling = target.nextElementSibling, 17003 after = false; 17004 after = direction === 1; 17005 var moveVector = _onMove( rootEl, el, dragEl, dragRect, target, targetRect, evt, after ); 17006 if ( moveVector !== false ) { 17007 if ( moveVector === 1 || moveVector === -1 ) { 17008 after = moveVector === 1; 17009 } 17010 _silent = true; 17011 setTimeout( _unsilent, 30 ); 17012 capture(); 17013 if ( after && ! nextSibling ) { 17014 el.appendChild( dragEl ); 17015 } else { 17016 target.parentNode.insertBefore( dragEl, after ? nextSibling : target ); 17017 } 17018
vendor: 5,178 bytes, lines 17019-17196
17019 // Undo chrome's scroll adjustment (has no effect on other browsers) 17020 if ( scrolledPastTop ) { 17021 scrollBy( scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop ); 17022 } 17023 parentEl = dragEl.parentNode; // actualization 17024 17025 // must be done before animation 17026 if ( targetBeforeFirstSwap !== undefined && ! isCircumstantialInvert ) { 17027 targetMoveDistance = Math.abs( targetBeforeFirstSwap - getRect( target )[ side1 ] ); 17028 } 17029 changed(); 17030 return completed( true ); 17031 } 17032 } 17033 if ( el.contains( dragEl ) ) { 17034 return completed( false ); 17035 } 17036 } 17037 return false; 17038 }, 17039 _ignoreWhileAnimating: null, 17040 _offMoveEvents: function _offMoveEvents() { 17041 off( document, 'mousemove', this._onTouchMove ); 17042 off( document, 'touchmove', this._onTouchMove ); 17043 off( document, 'pointermove', this._onTouchMove ); 17044 off( document, 'dragover', nearestEmptyInsertDetectEvent ); 17045 off( document, 'mousemove', nearestEmptyInsertDetectEvent ); 17046 off( document, 'touchmove', nearestEmptyInsertDetectEvent ); 17047 }, 17048 _offUpEvents: function _offUpEvents() { 17049 var ownerDocument = this.el.ownerDocument; 17050 off( ownerDocument, 'mouseup', this._onDrop ); 17051 off( ownerDocument, 'touchend', this._onDrop ); 17052 off( ownerDocument, 'pointerup', this._onDrop ); 17053 off( ownerDocument, 'pointercancel', this._onDrop ); 17054 off( ownerDocument, 'touchcancel', this._onDrop ); 17055 off( document, 'selectstart', this ); 17056 }, 17057 _onDrop: function _onDrop( /**Event*/evt ) { 17058 var el = this.el, 17059 options = this.options; 17060 17061 // Get the index of the dragged element within its parent 17062 newIndex = index( dragEl ); 17063 newDraggableIndex = index( dragEl, options.draggable ); 17064 pluginEvent( 'drop', this, { 17065 evt: evt 17066 } ); 17067 parentEl = dragEl && dragEl.parentNode; 17068 17069 // Get again after plugin event 17070 newIndex = index( dragEl ); 17071 newDraggableIndex = index( dragEl, options.draggable ); 17072 if ( Sortable.eventCanceled ) { 17073 this._nulling(); 17074 return; 17075 } 17076 awaitingDragStarted = false; 17077 isCircumstantialInvert = false; 17078 pastFirstInvertThresh = false; 17079 clearInterval( this._loopId ); 17080 clearTimeout( this._dragStartTimer ); 17081 _cancelNextTick( this.cloneId ); 17082 _cancelNextTick( this._dragStartId ); 17083 17084 // Unbind events 17085 if ( this.nativeDraggable ) { 17086 off( document, 'drop', this ); 17087 off( el, 'dragstart', this._onDragStart ); 17088 } 17089 this._offMoveEvents(); 17090 this._offUpEvents(); 17091 if ( Safari ) { 17092 css( document.body, 'user-select', '' ); 17093 } 17094 css( dragEl, 'transform', '' ); 17095 if ( evt ) { 17096 if ( moved ) { 17097 evt.cancelable && evt.preventDefault(); 17098 ! options.dropBubble && evt.stopPropagation(); 17099 } 17100 ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild( ghostEl ); 17101 if ( rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone' ) { 17102 // Remove clone(s) 17103 cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild( cloneEl ); 17104 } 17105 if ( dragEl ) { 17106 if ( this.nativeDraggable ) { 17107 off( dragEl, 'dragend', this ); 17108 } 17109 _disableDraggable( dragEl ); 17110 dragEl.style[ 'will-change' ] = ''; 17111 17112 // Remove classes 17113 // ghostClass is added in dragStarted 17114 if ( moved && ! awaitingDragStarted ) { 17115 toggleClass( dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false ); 17116 } 17117 toggleClass( dragEl, this.options.chosenClass, false ); 17118 17119 // Drag stop event 17120 _dispatchEvent( { 17121 sortable: this, 17122 name: 'unchoose', 17123 toEl: parentEl, 17124 newIndex: null, 17125 newDraggableIndex: null, 17126 originalEvent: evt 17127 } ); 17128 if ( rootEl !== parentEl ) { 17129 if ( newIndex >= 0 ) { 17130 // Add event 17131 _dispatchEvent( { 17132 rootEl: parentEl, 17133 name: 'add', 17134 toEl: parentEl, 17135 fromEl: rootEl, 17136 originalEvent: evt 17137 } ); 17138 17139 // Remove event 17140 _dispatchEvent( { 17141 sortable: this, 17142 name: 'remove', 17143 toEl: parentEl, 17144 originalEvent: evt 17145 } ); 17146 17147 // drag from one list and drop into another 17148 _dispatchEvent( { 17149 rootEl: parentEl, 17150 name: 'sort', 17151 toEl: parentEl, 17152 fromEl: rootEl, 17153 originalEvent: evt 17154 } ); 17155 _dispatchEvent( { 17156 sortable: this, 17157 name: 'sort', 17158 toEl: parentEl, 17159 originalEvent: evt 17160 } ); 17161 } 17162 putSortable && putSortable.save(); 17163 } else if ( newIndex !== oldIndex ) { 17164 if ( newIndex >= 0 ) { 17165 // drag & drop within the same list 17166 _dispatchEvent( { 17167 sortable: this, 17168 name: 'update', 17169 toEl: parentEl, 17170 originalEvent: evt 17171 } ); 17172 _dispatchEvent( { 17173 sortable: this, 17174 name: 'sort', 17175 toEl: parentEl, 17176 originalEvent: evt 17177 } ); 17178 } 17179 } 17180 if ( Sortable.active ) { 17181 if ( newIndex == null || newIndex === -1 ) { 17182 newIndex = oldIndex; 17183 newDraggableIndex = oldDraggableIndex; 17184 } 17185 _dispatchEvent( { 17186 sortable: this, 17187 name: 'end', 17188 toEl: parentEl, 17189 originalEvent: evt 17190 } ); 17191 17192 // Save sorting 17193 this.save(); 17194 } 17195 } 17196 }
vendor: 4,930 bytes, lines 17197-17363
17197 this._nulling(); 17198 }, 17199 _nulling: function _nulling() { 17200 pluginEvent( 'nulling', this ); 17201 rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = lastDownEl = cloneHidden = tapEvt = touchEvt = moved = newIndex = newDraggableIndex = oldIndex = oldDraggableIndex = lastTarget = lastDirection = putSortable = activeGroup = Sortable.dragged = Sortable.ghost = Sortable.clone = Sortable.active = null; 17202 savedInputChecked.forEach( function( el ) { 17203 el.checked = true; 17204 } ); 17205 savedInputChecked.length = lastDx = lastDy = 0; 17206 }, 17207 handleEvent: function handleEvent( /**Event*/evt ) { 17208 switch ( evt.type ) { 17209 case 'drop': 17210 case 'dragend': 17211 this._onDrop( evt ); 17212 break; 17213 case 'dragenter': 17214 case 'dragover': 17215 if ( dragEl ) { 17216 this._onDragOver( evt ); 17217 _globalDragOver( evt ); 17218 } 17219 break; 17220 case 'selectstart': 17221 evt.preventDefault(); 17222 break; 17223 } 17224 }, 17225 /** 17226 * Serializes the item into an array of string. 17227 * @returns {string[]} 17228 */ 17229 toArray: function toArray() { 17230 var order = [], 17231 el, 17232 children = this.el.children, 17233 i = 0, 17234 n = children.length, 17235 options = this.options; 17236 for ( ; i < n; i++ ) { 17237 el = children[ i ]; 17238 if ( closest( el, options.draggable, this.el, false ) ) { 17239 order.push( el.getAttribute( options.dataIdAttr ) || _generateId( el ) ); 17240 } 17241 } 17242 return order; 17243 }, 17244 /** 17245 * Sorts the elements according to the array. 17246 * @param {string[]} order Order of the items 17247 * @param {boolean} useAnimation Whether to use animations 17248 */ 17249 sort: function sort( order, useAnimation ) { 17250 var items = {}, 17251 rootEl = this.el; 17252 this.toArray().forEach( function( id, i ) { 17253 var el = rootEl.children[ i ]; 17254 if ( closest( el, this.options.draggable, rootEl, false ) ) { 17255 items[ id ] = el; 17256 } 17257 }, this ); 17258 useAnimation && this.captureAnimationState(); 17259 order.forEach( function( id ) { 17260 if ( items[ id ] ) { 17261 rootEl.removeChild( items[ id ] ); 17262 rootEl.appendChild( items[ id ] ); 17263 } 17264 } ); 17265 useAnimation && this.animateAll(); 17266 }, 17267 /** 17268 * Save the current sorting 17269 */ 17270 save: function save() { 17271 var store = this.options.store; 17272 store && store.set && store.set( this ); 17273 }, 17274 /** 17275 * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. 17276 * @param {HTMLElement} el 17277 * @param {string} [selector] default: `options.draggable` 17278 * @returns {HTMLElement|null} 17279 */ 17280 closest: function closest$1( el, selector ) { 17281 return closest( el, selector || this.options.draggable, this.el, false ); 17282 }, 17283 /** 17284 * Set/get option 17285 * @param {string} name 17286 * @param {*} [value] 17287 * @returns {*} 17288 */ 17289 option: function option( name, value ) { 17290 var options = this.options; 17291 if ( value === void 0 ) { 17292 return options[ name ]; 17293 } 17294 var modifiedValue = PluginManager.modifyOption( this, name, value ); 17295 if ( typeof modifiedValue !== 'undefined' ) { 17296 options[ name ] = modifiedValue; 17297 } else { 17298 options[ name ] = value; 17299 } 17300 if ( name === 'group' ) { 17301 _prepareGroup( options ); 17302 } 17303 }, 17304 /** 17305 * Destroy 17306 */ 17307 destroy: function destroy() { 17308 pluginEvent( 'destroy', this ); 17309 var el = this.el; 17310 el[ expando ] = null; 17311 off( el, 'mousedown', this._onTapStart ); 17312 off( el, 'touchstart', this._onTapStart ); 17313 off( el, 'pointerdown', this._onTapStart ); 17314 if ( this.nativeDraggable ) { 17315 off( el, 'dragover', this ); 17316 off( el, 'dragenter', this ); 17317 } 17318 // Remove draggable attributes 17319 Array.prototype.forEach.call( el.querySelectorAll( '[draggable]' ), function( el ) { 17320 el.removeAttribute( 'draggable' ); 17321 } ); 17322 this._onDrop(); 17323 this._disableDelayedDragEvents(); 17324 sortables.splice( sortables.indexOf( this.el ), 1 ); 17325 this.el = el = null; 17326 }, 17327 _hideClone: function _hideClone() { 17328 if ( ! cloneHidden ) { 17329 pluginEvent( 'hideClone', this ); 17330 if ( Sortable.eventCanceled ) { 17331 return; 17332 } 17333 css( cloneEl, 'display', 'none' ); 17334 if ( this.options.removeCloneOnHide && cloneEl.parentNode ) { 17335 cloneEl.parentNode.removeChild( cloneEl ); 17336 } 17337 cloneHidden = true; 17338 } 17339 }, 17340 _showClone: function _showClone( putSortable ) { 17341 if ( putSortable.lastPutMode !== 'clone' ) { 17342 this._hideClone(); 17343 return; 17344 } 17345 if ( cloneHidden ) { 17346 pluginEvent( 'showClone', this ); 17347 if ( Sortable.eventCanceled ) { 17348 return; 17349 } 17350 17351 // show clone at dragEl or original position 17352 if ( dragEl.parentNode == rootEl && ! this.options.group.revertClone ) { 17353 rootEl.insertBefore( cloneEl, dragEl ); 17354 } else if ( nextEl ) { 17355 rootEl.insertBefore( cloneEl, nextEl ); 17356 } else { 17357 rootEl.appendChild( cloneEl ); 17358 } 17359 if ( this.options.group.revertClone ) { 17360 this.animate( dragEl, cloneEl ); 17361 } 17362 css( cloneEl, 'display', '' ); 17363 cloneHidden = false;
vendor: 5,091 bytes, lines 17364-17491
17364 } 17365 } 17366 }; 17367 function _globalDragOver( /**Event*/evt ) { 17368 if ( evt.dataTransfer ) { 17369 // evt.dataTransfer.dropEffect = 'move'; 17370 } 17371 evt.cancelable && evt.preventDefault(); 17372 } 17373 function _onMove( fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter ) { 17374 var evt, 17375 sortable = fromEl[ expando ], 17376 onMoveFn = sortable.options.onMove, 17377 retVal; 17378 // Support for new CustomEvent feature 17379 if ( window.CustomEvent && ! IE11OrLess && ! Edge ) { 17380 evt = new CustomEvent( 'move', { 17381 bubbles: true, 17382 cancelable: true 17383 } ); 17384 } else { 17385 evt = document.createEvent( 'Event' ); 17386 evt.initEvent( 'move', true, true ); 17387 } 17388 evt.to = toEl; 17389 evt.from = fromEl; 17390 evt.dragged = dragEl; 17391 evt.draggedRect = dragRect; 17392 evt.related = targetEl || toEl; 17393 evt.relatedRect = targetRect || getRect( toEl ); 17394 evt.willInsertAfter = willInsertAfter; 17395 evt.originalEvent = originalEvent; 17396 fromEl.dispatchEvent( evt ); 17397 if ( onMoveFn ) { 17398 retVal = onMoveFn.call( sortable, evt, originalEvent ); 17399 } 17400 return retVal; 17401 } 17402 function _disableDraggable( el ) { 17403 el.draggable = false; 17404 } 17405 function _unsilent() { 17406 _silent = false; 17407 } 17408 function _ghostIsFirst( evt, vertical, sortable ) { 17409 var firstElRect = getRect( getChild( sortable.el, 0, sortable.options, true ) ); 17410 var childContainingRect = getChildContainingRectFromElement( sortable.el, sortable.options, ghostEl ); 17411 var spacer = 10; 17412 return vertical ? evt.clientX < childContainingRect.left - spacer || evt.clientY < firstElRect.top && evt.clientX < firstElRect.right : evt.clientY < childContainingRect.top - spacer || evt.clientY < firstElRect.bottom && evt.clientX < firstElRect.left; 17413 } 17414 function _ghostIsLast( evt, vertical, sortable ) { 17415 var lastElRect = getRect( lastChild( sortable.el, sortable.options.draggable ) ); 17416 var childContainingRect = getChildContainingRectFromElement( sortable.el, sortable.options, ghostEl ); 17417 var spacer = 10; 17418 return vertical ? evt.clientX > childContainingRect.right + spacer || evt.clientY > lastElRect.bottom && evt.clientX > lastElRect.left : evt.clientY > childContainingRect.bottom + spacer || evt.clientX > lastElRect.right && evt.clientY > lastElRect.top; 17419 } 17420 function _getSwapDirection( evt, target, targetRect, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget ) { 17421 var mouseOnAxis = vertical ? evt.clientY : evt.clientX, 17422 targetLength = vertical ? targetRect.height : targetRect.width, 17423 targetS1 = vertical ? targetRect.top : targetRect.left, 17424 targetS2 = vertical ? targetRect.bottom : targetRect.right, 17425 invert = false; 17426 if ( ! invertSwap ) { 17427 // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold 17428 if ( isLastTarget && targetMoveDistance < targetLength * swapThreshold ) { 17429 // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2 17430 // check if past first invert threshold on side opposite of lastDirection 17431 if ( ! pastFirstInvertThresh && ( lastDirection === 1 ? mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 : mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2 ) ) { 17432 // past first invert threshold, do not restrict inverted threshold to dragEl shadow 17433 pastFirstInvertThresh = true; 17434 } 17435 if ( ! pastFirstInvertThresh ) { 17436 // dragEl shadow (target move distance shadow) 17437 if ( lastDirection === 1 ? mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow 17438 : mouseOnAxis > targetS2 - targetMoveDistance ) { 17439 return -lastDirection; 17440 } 17441 } else { 17442 invert = true; 17443 } 17444 } else { 17445 // Regular 17446 if ( mouseOnAxis > targetS1 + targetLength * ( 1 - swapThreshold ) / 2 && mouseOnAxis < targetS2 - targetLength * ( 1 - swapThreshold ) / 2 ) { 17447 return _getInsertDirection( target ); 17448 } 17449 } 17450 } 17451 invert = invert || invertSwap; 17452 if ( invert ) { 17453 // Invert of regular 17454 if ( mouseOnAxis < targetS1 + targetLength * invertedSwapThreshold / 2 || mouseOnAxis > targetS2 - targetLength * invertedSwapThreshold / 2 ) { 17455 return mouseOnAxis > targetS1 + targetLength / 2 ? 1 : -1; 17456 } 17457 } 17458 return 0; 17459 } 17460 17461 /** 17462 * Gets the direction dragEl must be swapped relative to target in order to make it 17463 * seem that dragEl has been "inserted" into that element's position 17464 * @param {HTMLElement} target The target whose position dragEl is being inserted at 17465 * @return {number} Direction dragEl must be swapped 17466 */ 17467 function _getInsertDirection( target ) { 17468 if ( index( dragEl ) < index( target ) ) { 17469 return 1; 17470 } 17471 return -1; 17472 } 17473 17474 /** 17475 * Generate id 17476 * @param {HTMLElement} el 17477 * @returns {string} 17478 * @private 17479 */ 17480 function _generateId( el ) { 17481 var str = el.tagName + el.className + el.src + el.href + el.textContent, 17482 i = str.length, 17483 sum = 0; 17484 while ( i-- ) { 17485 sum += str.charCodeAt( i ); 17486 } 17487 return sum.toString( 36 ); 17488 } 17489 function _saveInputCheckedState( root ) { 17490 savedInputChecked.length = 0; 17491 var inputs = root.getElementsByTagName( 'input' );
vendor: 3,647 bytes, lines 17492-17625
17492 var idx = inputs.length; 17493 while ( idx-- ) { 17494 var el = inputs[ idx ]; 17495 el.checked && savedInputChecked.push( el ); 17496 } 17497 } 17498 function _nextTick( fn ) { 17499 return setTimeout( fn, 0 ); 17500 } 17501 function _cancelNextTick( id ) { 17502 return clearTimeout( id ); 17503 } 17504 17505 // Fixed #973: 17506 if ( documentExists ) { 17507 on( document, 'touchmove', function( evt ) { 17508 if ( ( Sortable.active || awaitingDragStarted ) && evt.cancelable ) { 17509 evt.preventDefault(); 17510 } 17511 } ); 17512 } 17513 17514 // Export utils 17515 Sortable.utils = { 17516 on: on, 17517 off: off, 17518 css: css, 17519 find: find, 17520 is: function is( el, selector ) { 17521 return !! closest( el, selector, el, false ); 17522 }, 17523 extend: extend, 17524 throttle: throttle, 17525 closest: closest, 17526 toggleClass: toggleClass, 17527 clone: clone, 17528 index: index, 17529 nextTick: _nextTick, 17530 cancelNextTick: _cancelNextTick, 17531 detectDirection: _detectDirection, 17532 getChild: getChild, 17533 expando: expando 17534 }; 17535 17536 /** 17537 * Get the Sortable instance of an element 17538 * @param {HTMLElement} element The element 17539 * @return {Sortable|undefined} The instance of Sortable 17540 */ 17541 Sortable.get = function( element ) { 17542 return element[ expando ]; 17543 }; 17544 17545 /** 17546 * Mount a plugin to Sortable 17547 */ 17548 Sortable.mount = function() { 17549 var _plugins = Array.from( arguments ); 17550 17551 if ( _plugins[ 0 ].constructor === Array ) { 17552 _plugins = _plugins[ 0 ]; 17553 } 17554 _plugins.forEach( function( plugin ) { 17555 if ( ! plugin.prototype || ! plugin.prototype.constructor ) { 17556 throw 'Sortable: Mounted plugin must be a constructor function, not '.concat( {}.toString.call( plugin ) ); 17557 } 17558 if ( plugin.utils ) { 17559 Sortable.utils = _objectSpread2( _objectSpread2( {}, Sortable.utils ), plugin.utils ); 17560 } 17561 PluginManager.mount( plugin ); 17562 } ); 17563 }; 17564 17565 /** 17566 * Create sortable instance 17567 * @param {HTMLElement} el 17568 * @param {Object} [options] 17569 */ 17570 Sortable.create = function( el, options ) { 17571 return new Sortable( el, options ); 17572 }; 17573 17574 // Export 17575 Sortable.version = version; 17576 17577 function AutoScrollPlugin() { 17578 function AutoScroll() { 17579 this.defaults = { 17580 scroll: true, 17581 forceAutoScrollFallback: false, 17582 scrollSensitivity: 30, 17583 scrollSpeed: 10, 17584 bubbleScroll: true 17585 }; 17586 17587 // Bind all private methods 17588 for ( var fn in this ) { 17589 if ( fn.charAt( 0 ) === '_' && typeof this[ fn ] === 'function' ) { 17590 this[ fn ] = this[ fn ].bind( this ); 17591 } 17592 } 17593 } 17594 AutoScroll.prototype = { 17595 dragStarted: function dragStarted( _ref ) { 17596 var originalEvent = _ref.originalEvent; 17597 if ( this.sortable.nativeDraggable ) { 17598 on( document, 'dragover', this._handleAutoScroll ); 17599 } else if ( this.options.supportPointer ) { 17600 on( document, 'pointermove', this._handleFallbackAutoScroll ); 17601 } else if ( originalEvent.touches ) { 17602 on( document, 'touchmove', this._handleFallbackAutoScroll ); 17603 } else { 17604 on( document, 'mousemove', this._handleFallbackAutoScroll ); 17605 } 17606 }, 17607 dragOverCompleted: function dragOverCompleted( _ref2 ) { 17608 var originalEvent = _ref2.originalEvent; 17609 // For when bubbling is canceled and using fallback (fallback 'touchmove' always reached) 17610 if ( ! this.options.dragOverBubble && ! originalEvent.rootEl ) { 17611 this._handleAutoScroll( originalEvent ); 17612 } 17613 }, 17614 drop: function drop() { 17615 if ( this.sortable.nativeDraggable ) { 17616 off( document, 'dragover', this._handleAutoScroll ); 17617 } else { 17618 off( document, 'pointermove', this._handleFallbackAutoScroll ); 17619 off( document, 'touchmove', this._handleFallbackAutoScroll ); 17620 off( document, 'mousemove', this._handleFallbackAutoScroll ); 17621 } 17622 clearPointerElemChangedInterval(); 17623 clearAutoScrolls(); 17624 cancelThrottle(); 17625 },
vendor: 4,190 bytes, lines 17626-17750
17626 nulling: function nulling() { 17627 touchEvt$1 = scrollRootEl = scrollEl = scrolling = pointerElemChangedInterval = lastAutoScrollX = lastAutoScrollY = null; 17628 autoScrolls.length = 0; 17629 }, 17630 _handleFallbackAutoScroll: function _handleFallbackAutoScroll( evt ) { 17631 this._handleAutoScroll( evt, true ); 17632 }, 17633 _handleAutoScroll: function _handleAutoScroll( evt, fallback ) { 17634 var _this = this; 17635 var x = ( evt.touches ? evt.touches[ 0 ] : evt ).clientX, 17636 y = ( evt.touches ? evt.touches[ 0 ] : evt ).clientY, 17637 elem = document.elementFromPoint( x, y ); 17638 touchEvt$1 = evt; 17639 17640 // IE does not seem to have native autoscroll, 17641 // Edge's autoscroll seems too conditional, 17642 // MACOS Safari does not have autoscroll, 17643 // Firefox and Chrome are good 17644 if ( fallback || this.options.forceAutoScrollFallback || Edge || IE11OrLess || Safari ) { 17645 autoScroll( evt, this.options, elem, fallback ); 17646 17647 // Listener for pointer element change 17648 var ogElemScroller = getParentAutoScrollElement( elem, true ); 17649 if ( scrolling && ( ! pointerElemChangedInterval || x !== lastAutoScrollX || y !== lastAutoScrollY ) ) { 17650 pointerElemChangedInterval && clearPointerElemChangedInterval(); 17651 // Detect for pointer elem change, emulating native DnD behaviour 17652 pointerElemChangedInterval = setInterval( function() { 17653 var newElem = getParentAutoScrollElement( document.elementFromPoint( x, y ), true ); 17654 if ( newElem !== ogElemScroller ) { 17655 ogElemScroller = newElem; 17656 clearAutoScrolls(); 17657 } 17658 autoScroll( evt, _this.options, newElem, fallback ); 17659 }, 10 ); 17660 lastAutoScrollX = x; 17661 lastAutoScrollY = y; 17662 } 17663 } else { 17664 // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll 17665 if ( ! this.options.bubbleScroll || getParentAutoScrollElement( elem, true ) === getWindowScrollingElement() ) { 17666 clearAutoScrolls(); 17667 return; 17668 } 17669 autoScroll( evt, this.options, getParentAutoScrollElement( elem, false ), false ); 17670 } 17671 } 17672 }; 17673 return _extends( AutoScroll, { 17674 pluginName: 'scroll', 17675 initializeByDefault: true 17676 } ); 17677 } 17678 function clearAutoScrolls() { 17679 autoScrolls.forEach( function( _autoScroll ) { 17680 clearInterval( _autoScroll.pid ); 17681 } ); 17682 autoScrolls = []; 17683 } 17684 function clearPointerElemChangedInterval() { 17685 clearInterval( pointerElemChangedInterval ); 17686 } 17687 function Revert() {} 17688 Revert.prototype = { 17689 startIndex: null, 17690 dragStart: function dragStart( _ref2 ) { 17691 var oldDraggableIndex = _ref2.oldDraggableIndex; 17692 this.startIndex = oldDraggableIndex; 17693 }, 17694 onSpill: function onSpill( _ref3 ) { 17695 var dragEl = _ref3.dragEl, 17696 putSortable = _ref3.putSortable; 17697 this.sortable.captureAnimationState(); 17698 if ( putSortable ) { 17699 putSortable.captureAnimationState(); 17700 } 17701 var nextSibling = getChild( this.sortable.el, this.startIndex, this.options ); 17702 if ( nextSibling ) { 17703 this.sortable.el.insertBefore( dragEl, nextSibling ); 17704 } else { 17705 this.sortable.el.appendChild( dragEl ); 17706 } 17707 this.sortable.animateAll(); 17708 if ( putSortable ) { 17709 putSortable.animateAll(); 17710 } 17711 }, 17712 drop: drop 17713 }; 17714 _extends( Revert, { 17715 pluginName: 'revertOnSpill' 17716 } ); 17717 function Remove() {} 17718 Remove.prototype = { 17719 onSpill: function onSpill( _ref4 ) { 17720 var dragEl = _ref4.dragEl, 17721 putSortable = _ref4.putSortable; 17722 var parentSortable = putSortable || this.sortable; 17723 parentSortable.captureAnimationState(); 17724 dragEl.parentNode && dragEl.parentNode.removeChild( dragEl ); 17725 parentSortable.animateAll(); 17726 }, 17727 drop: drop 17728 }; 17729 _extends( Remove, { 17730 pluginName: 'removeOnSpill' 17731 } ); 17732 17733 function SwapPlugin() { 17734 function Swap() { 17735 this.defaults = { 17736 swapClass: 'sortable-swap-highlight' 17737 }; 17738 } 17739 Swap.prototype = { 17740 dragStart: function dragStart( _ref ) { 17741 var dragEl = _ref.dragEl; 17742 lastSwapEl = dragEl; 17743 }, 17744 dragOverValid: function dragOverValid( _ref2 ) { 17745 var completed = _ref2.completed, 17746 target = _ref2.target, 17747 onMove = _ref2.onMove, 17748 activeSortable = _ref2.activeSortable, 17749 changed = _ref2.changed, 17750 cancel = _ref2.cancel;
17751 if ( ! activeSortable.options.swap ) { 17752 return; 17753 } 17754 var el = this.sortable.el, 17755 options = this.options; 17756 if ( target && target !== el ) { 17757 var prevSwapEl = lastSwapEl; 17758 if ( onMove( target ) !== false ) { 17759 toggleClass( target, options.swapClass, true ); 17760 lastSwapEl = target; 17761 } else { 17762 lastSwapEl = null; 17763 } 17764 if ( prevSwapEl && prevSwapEl !== lastSwapEl ) { 17765 toggleClass( prevSwapEl, options.swapClass, false ); 17766 } 17767 } 17768 changed(); 17769 completed( true ); 17770 cancel(); 17771 }, 17772 drop: function drop( _ref3 ) { 17773 var activeSortable = _ref3.activeSortable, 17774 putSortable = _ref3.putSortable, 17775 dragEl = _ref3.dragEl; 17776 var toSortable = putSortable || this.sortable; 17777 var options = this.options; 17778 if ( lastSwapEl ) { 17779 toggleClass( lastSwapEl, options.swapClass, false ); 17780 } 17781 if ( lastSwapEl && ( options.swap || putSortable && putSortable.options.swap ) ) { 17782 if ( dragEl !== lastSwapEl ) { 17783 toSortable.captureAnimationState(); 17784 if ( toSortable !== activeSortable ) { 17785 activeSortable.captureAnimationState(); 17786 } 17787 swapNodes( dragEl, lastSwapEl ); 17788 toSortable.animateAll(); 17789 if ( toSortable !== activeSortable ) { 17790 activeSortable.animateAll(); 17791 } 17792 } 17793 } 17794 },
vendor: 3,449 bytes, lines 17795-17909
17795 nulling: function nulling() { 17796 lastSwapEl = null; 17797 } 17798 }; 17799 return _extends( Swap, { 17800 pluginName: 'swap', 17801 eventProperties: function eventProperties() { 17802 return { 17803 swapItem: lastSwapEl 17804 }; 17805 } 17806 } ); 17807 } 17808 function swapNodes( n1, n2 ) { 17809 var p1 = n1.parentNode, 17810 p2 = n2.parentNode, 17811 i1, 17812 i2; 17813 if ( ! p1 || ! p2 || p1.isEqualNode( n2 ) || p2.isEqualNode( n1 ) ) { 17814 return; 17815 } 17816 i1 = index( n1 ); 17817 i2 = index( n2 ); 17818 if ( p1.isEqualNode( p2 ) && i1 < i2 ) { 17819 i2++; 17820 } 17821 p1.insertBefore( n2, p1.children[ i1 ] ); 17822 p2.insertBefore( n1, p2.children[ i2 ] ); 17823 } 17824 17825 function MultiDragPlugin() { 17826 function MultiDrag( sortable ) { 17827 // Bind all private methods 17828 for ( var fn in this ) { 17829 if ( fn.charAt( 0 ) === '_' && typeof this[ fn ] === 'function' ) { 17830 this[ fn ] = this[ fn ].bind( this ); 17831 } 17832 } 17833 if ( ! sortable.options.avoidImplicitDeselect ) { 17834 if ( sortable.options.supportPointer ) { 17835 on( document, 'pointerup', this._deselectMultiDrag ); 17836 } else { 17837 on( document, 'mouseup', this._deselectMultiDrag ); 17838 on( document, 'touchend', this._deselectMultiDrag ); 17839 } 17840 } 17841 on( document, 'keydown', this._checkKeyDown ); 17842 on( document, 'keyup', this._checkKeyUp ); 17843 this.defaults = { 17844 selectedClass: 'sortable-selected', 17845 multiDragKey: null, 17846 avoidImplicitDeselect: false, 17847 setData: function setData( dataTransfer, dragEl ) { 17848 var data = ''; 17849 if ( multiDragElements.length && multiDragSortable === sortable ) { 17850 multiDragElements.forEach( function( multiDragElement, i ) { 17851 data += ( ! i ? '' : ', ' ) + multiDragElement.textContent; 17852 } ); 17853 } else { 17854 data = dragEl.textContent; 17855 } 17856 dataTransfer.setData( 'Text', data ); 17857 } 17858 }; 17859 } 17860 MultiDrag.prototype = { 17861 multiDragKeyDown: false, 17862 isMultiDrag: false, 17863 delayStartGlobal: function delayStartGlobal( _ref ) { 17864 var dragged = _ref.dragEl; 17865 dragEl$1 = dragged; 17866 }, 17867 delayEnded: function delayEnded() { 17868 this.isMultiDrag = multiDragElements.indexOf( dragEl$1 ) !== -1; 17869 }, 17870 setupClone: function setupClone( _ref2 ) { 17871 var sortable = _ref2.sortable, 17872 cancel = _ref2.cancel; 17873 if ( ! this.isMultiDrag ) { 17874 return; 17875 } 17876 for ( var i = 0; i < multiDragElements.length; i++ ) { 17877 multiDragClones.push( clone( multiDragElements[ i ] ) ); 17878 multiDragClones[ i ].sortableIndex = multiDragElements[ i ].sortableIndex; 17879 multiDragClones[ i ].draggable = false; 17880 multiDragClones[ i ].style[ 'will-change' ] = ''; 17881 toggleClass( multiDragClones[ i ], this.options.selectedClass, false ); 17882 multiDragElements[ i ] === dragEl$1 && toggleClass( multiDragClones[ i ], this.options.chosenClass, false ); 17883 } 17884 sortable._hideClone(); 17885 cancel(); 17886 }, 17887 clone: function clone( _ref3 ) { 17888 var sortable = _ref3.sortable, 17889 rootEl = _ref3.rootEl, 17890 dispatchSortableEvent = _ref3.dispatchSortableEvent, 17891 cancel = _ref3.cancel; 17892 if ( ! this.isMultiDrag ) { 17893 return; 17894 } 17895 if ( ! this.options.removeCloneOnHide ) { 17896 if ( multiDragElements.length && multiDragSortable === sortable ) { 17897 insertMultiDragClones( true, rootEl ); 17898 dispatchSortableEvent( 'clone' ); 17899 cancel(); 17900 } 17901 } 17902 }, 17903 showClone: function showClone( _ref4 ) { 17904 var cloneNowShown = _ref4.cloneNowShown, 17905 rootEl = _ref4.rootEl, 17906 cancel = _ref4.cancel; 17907 if ( ! this.isMultiDrag ) { 17908 return; 17909 }
17910 insertMultiDragClones( false, rootEl ); 17911 multiDragClones.forEach( function( _clone ) { 17912 css( _clone, 'display', '' ); 17913 } ); 17914 cloneNowShown(); 17915 clonesHidden = false; 17916 cancel(); 17917 }, 17918 hideClone: function hideClone( _ref5 ) { 17919 var _this = this; 17920 var sortable = _ref5.sortable, 17921 cloneNowHidden = _ref5.cloneNowHidden, 17922 cancel = _ref5.cancel; 17923 if ( ! this.isMultiDrag ) { 17924 return; 17925 } 17926 multiDragClones.forEach( function( _clone ) { 17927 css( _clone, 'display', 'none' ); 17928 if ( _clone.options.removeCloneOnHide && _clone.parentNode ) { 17929 clone.parentNode.removeChild( _clone ); 17930 } 17931 } ); 17932 cloneNowHidden(); 17933 clonesHidden = true; 17934 cancel(); 17935 }, 17936 dragStartGlobal: function dragStartGlobal( _ref6 ) { 17937 var sortable = _ref6.sortable; 17938 if ( ! this.isMultiDrag && multiDragSortable ) { 17939 multiDragSortable.multiDrag._deselectMultiDrag(); 17940 } 17941 multiDragElements.forEach( function( multiDragElement ) { 17942 multiDragElement.sortableIndex = index( multiDragElement ); 17943 } ); 17944 17945 // Sort multi-drag elements 17946 multiDragElements = multiDragElements.sort( function( a, b ) { 17947 return a.sortableIndex - b.sortableIndex; 17948 } ); 17949 dragStarted = true; 17950 }, 17951 dragStarted: function( _ref7 ) { 17952 var _this2 = this; 17953 var sortable = _ref7.sortable; 17954 var dragRect; 17955 if ( ! this.isMultiDrag ) { 17956 return; 17957 } 17958 if ( this.options.sort ) { 17959 // Capture rects, 17960 // hide multi drag elements (by positioning them absolute), 17961 // set multi drag elements rects to dragRect, 17962 // show multi drag elements, 17963 // animate to rects, 17964 // unset rects & remove from DOM 17965 17966 sortable.captureAnimationState(); 17967 if ( this.options.animation ) { 17968 multiDragElements.forEach( function( multiDragElement ) { 17969 if ( multiDragElement === dragEl$1 ) { 17970 return; 17971 } 17972 css( multiDragElement, 'position', 'absolute' ); 17973 } ); 17974 dragRect = getRect( dragEl$1, false, true, true ); 17975 multiDragElements.forEach( function( multiDragElement ) { 17976 if ( multiDragElement === dragEl$1 ) { 17977 return; 17978 } 17979 setRect( multiDragElement, dragRect ); 17980 } ); 17981 folding = true; 17982 initialFolding = true; 17983 } 17984 } 17985 sortable.animateAll( function() { 17986 folding = false; 17987 initialFolding = false; 17988 if ( _this2.options.animation ) { 17989 multiDragElements.forEach( function( multiDragElement ) { 17990 unsetRect( multiDragElement ); 17991 } ); 17992 } 17993 17994 // Remove all auxiliary multidrag items from el, if sorting enabled 17995 if ( _this2.options.sort ) { 17996 removeMultiDragElements(); 17997 } 17998 } ); 17999 }, 18000 dragOver: function dragOver( _ref8 ) { 18001 var target = _ref8.target, 18002 completed = _ref8.completed, 18003 cancel = _ref8.cancel; 18004 if ( folding && multiDragElements.indexOf( target ) !== -1 ) { 18005 completed( false ); 18006 cancel(); 18007 } 18008 }, 18009 revert: function revert( _ref9 ) { 18010 var fromSortable = _ref9.fromSortable, 18011 _rootEl = _ref9.rootEl, 18012 sortable = _ref9.sortable, 18013 dragRect = _ref9.dragRect; 18014 if ( multiDragElements.length > 1 ) { 18015 // Setup unfold animation 18016 multiDragElements.forEach( function( multiDragElement ) { 18017 sortable.addAnimationState( { 18018 target: multiDragElement, 18019 rect: folding ? getRect( multiDragElement ) : dragRect 18020 } ); 18021 unsetRect( multiDragElement ); 18022 multiDragElement.fromRect = dragRect; 18023 fromSortable.removeAnimationState( multiDragElement ); 18024 } ); 18025 folding = false; 18026 insertMultiDragElements( ! this.options.removeCloneOnHide, _rootEl ); 18027 } 18028 }, 18029 dragOverCompleted: function dragOverCompleted( _ref10 ) { 18030 var sortable = _ref10.sortable, 18031 isOwner = _ref10.isOwner, 18032 insertion = _ref10.insertion, 18033 activeSortable = _ref10.activeSortable, 18034 _parentEl = _ref10.parentEl, 18035 _putSortable = _ref10.putSortable; 18036 var options = this.options; 18037 var dragRectAbsolute; 18038 var clonesHiddenBefore; 18039 if ( insertion ) { 18040 // Clones must be hidden before folding animation to capture dragRectAbsolute properly 18041 if ( isOwner ) { 18042 activeSortable._hideClone(); 18043 } 18044 initialFolding = false;
18045 // If leaving sort:false root, or already folding - Fold to new location 18046 if ( options.animation && multiDragElements.length > 1 && ( folding || ( ! isOwner && ! activeSortable.options.sort && ! _putSortable ) ) ) { 18047 // Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible 18048 dragRectAbsolute = getRect( dragEl$1, false, true, true ); 18049 multiDragElements.forEach( function( multiDragElement ) { 18050 if ( multiDragElement === dragEl$1 ) { 18051 return; 18052 } 18053 setRect( multiDragElement, dragRectAbsolute ); 18054 18055 // Move element(s) to end of _parentEl so that it does not interfere with multi-drag clones insertion if they are inserted 18056 // while folding, and so that we can capture them again because old sortable will no longer be fromSortable 18057 _parentEl.appendChild( multiDragElement ); 18058 } ); 18059 folding = true; 18060 } 18061 18062 // Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out 18063 if ( ! isOwner ) { 18064 // Only remove if not folding (folding will remove them anyways) 18065 if ( ! folding ) { 18066 removeMultiDragElements(); 18067 } 18068 if ( multiDragElements.length > 1 ) { 18069 clonesHiddenBefore = clonesHidden; 18070 activeSortable._showClone( sortable ); 18071 18072 // Unfold animation for clones if showing from hidden 18073 if ( activeSortable.options.animation && ! clonesHidden && clonesHiddenBefore ) { 18074 multiDragClones.forEach( function( _clone ) { 18075 activeSortable.addAnimationState( { 18076 target: _clone, 18077 rect: clonesFromRect 18078 } ); 18079 _clone.fromRect = clonesFromRect; 18080 _clone.thisAnimationDuration = null; 18081 } ); 18082 } 18083 } else { 18084 activeSortable._showClone( sortable ); 18085 } 18086 } 18087 } 18088 }, 18089 dragOverAnimationCapture: function dragOverAnimationCapture( _ref11 ) { 18090 var dragRect = _ref11.dragRect, 18091 isOwner = _ref11.isOwner, 18092 activeSortable = _ref11.activeSortable, 18093 dragMatrix; 18094 multiDragElements.forEach( function( multiDragElement ) { 18095 multiDragElement.thisAnimationDuration = null; 18096 } ); 18097 if ( activeSortable.options.animation && ! isOwner && activeSortable.multiDrag.isMultiDrag ) { 18098 clonesFromRect = _extends( {}, dragRect ); 18099 dragMatrix = matrix( dragEl$1, true ); 18100 clonesFromRect.top -= dragMatrix.f; 18101 clonesFromRect.left -= dragMatrix.e; 18102 } 18103 }, 18104 dragOverAnimationComplete: function dragOverAnimationComplete() { 18105 if ( folding ) { 18106 folding = false; 18107 removeMultiDragElements(); 18108 } 18109 }, 18110 drop: function( _ref12 ) { 18111 var evt = _ref12.originalEvent, 18112 _rootEl = _ref12.rootEl, 18113 _parentEl = _ref12.parentEl, 18114 sortable = _ref12.sortable, 18115 dispatchSortableEvent = _ref12.dispatchSortableEvent, 18116 _oldIndex = _ref12.oldIndex, 18117 _putSortable = _ref12.putSortable; 18118 var toSortable = _putSortable || this.sortable; 18119 var options; 18120 var children; 18121 var update; 18122 var lastIndex; 18123 var currentIndex; 18124 var filter; 18125 var filtered; 18126 var dragRect; 18127 var multiDragIndex; 18128 var rect; 18129 if ( ! evt ) { 18130 return; 18131 } 18132 options = this.options; 18133 children = _parentEl.children; 18134 18135 // Multi-drag selection 18136 if ( ! dragStarted ) { 18137 if ( options.multiDragKey && ! this.multiDragKeyDown ) { 18138 this._deselectMultiDrag(); 18139 } 18140 toggleClass( dragEl$1, options.selectedClass, multiDragElements.indexOf( dragEl$1 ) === -1 ); 18141 if ( multiDragElements.indexOf( dragEl$1 ) === -1 ) { 18142 multiDragElements.push( dragEl$1 ); 18143 dispatchEvent( { 18144 sortable: sortable, 18145 rootEl: _rootEl, 18146 name: 'select', 18147 targetEl: dragEl$1, 18148 originalEvent: evt 18149 } ); 18150 18151 // Modifier activated, select from last to dragEl 18152 if ( evt.shiftKey && lastMultiDragSelect && sortable.el.contains( lastMultiDragSelect ) ) { 18153 lastIndex = index( lastMultiDragSelect ); 18154 currentIndex = index( dragEl$1 ); 18155 if ( lastIndex !== -1 && currentIndex !== -1 && lastIndex !== currentIndex ) { 18156 ( function() { 18157 // Must include lastMultiDragSelect (select it), in case modified selection from no selection 18158 // (but previous selection existed) 18159 var n, i; 18160 if ( currentIndex > lastIndex ) { 18161 i = lastIndex; 18162 n = currentIndex; 18163 } else { 18164 i = currentIndex; 18165 n = lastIndex + 1; 18166 } 18167 filter = options.filter; 18168 for ( ; i < n; i++ ) { 18169 if ( multiDragElements.indexOf( children[ i ] ) !== -1 ) { 18170 continue; 18171 } 18172 // Check if element is draggable 18173 if ( ! closest( children[ i ], options.draggable, _parentEl, false ) ) { 18174 continue; 18175 } 18176 // Check if element is filtered 18177 filtered = filter && ( typeof filter === 'function' ? filter.call( sortable, evt, children[ i ], sortable ) : filter.split( ',' ).some( function( criteria ) { 18178 return closest( children[ i ], criteria.trim(), _parentEl, false ); 18179 } ) ); 18180 if ( filtered ) { 18181 continue; 18182 } 18183 toggleClass( children[ i ], options.selectedClass, true ); 18184 multiDragElements.push( children[ i ] ); 18185 dispatchEvent( {
18186 sortable: sortable, 18187 rootEl: _rootEl, 18188 name: 'select', 18189 targetEl: children[ i ], 18190 originalEvent: evt 18191 } ); 18192 } 18193 }() ); 18194 } 18195 } else { 18196 lastMultiDragSelect = dragEl$1; 18197 } 18198 multiDragSortable = toSortable; 18199 } else { 18200 multiDragElements.splice( multiDragElements.indexOf( dragEl$1 ), 1 ); 18201 lastMultiDragSelect = null; 18202 dispatchEvent( { 18203 sortable: sortable, 18204 rootEl: _rootEl, 18205 name: 'deselect', 18206 targetEl: dragEl$1, 18207 originalEvent: evt 18208 } ); 18209 } 18210 } 18211 18212 // Multi-drag drop 18213 if ( dragStarted && this.isMultiDrag ) { 18214 folding = false; 18215 // Do not "unfold" after around dragEl if reverted 18216 if ( ( _parentEl[ expando ].options.sort || _parentEl !== _rootEl ) && multiDragElements.length > 1 ) { 18217 dragRect = getRect( dragEl$1 ); 18218 multiDragIndex = index( dragEl$1, ':not(.' + this.options.selectedClass + ')' ); 18219 if ( ! initialFolding && options.animation ) { 18220 dragEl$1.thisAnimationDuration = null; 18221 } 18222 toSortable.captureAnimationState(); 18223 if ( ! initialFolding ) { 18224 if ( options.animation ) { 18225 dragEl$1.fromRect = dragRect; 18226 multiDragElements.forEach( function( multiDragElement ) { 18227 multiDragElement.thisAnimationDuration = null; 18228 if ( multiDragElement !== dragEl$1 ) { 18229 rect = folding ? getRect( multiDragElement ) : dragRect; 18230 multiDragElement.fromRect = rect; 18231 18232 // Prepare unfold animation 18233 toSortable.addAnimationState( { 18234 target: multiDragElement, 18235 rect: rect 18236 } ); 18237 } 18238 } ); 18239 } 18240 18241 // Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert 18242 // properly they must all be removed 18243 removeMultiDragElements(); 18244 multiDragElements.forEach( function( multiDragElement ) { 18245 if ( children[ multiDragIndex ] ) { 18246 _parentEl.insertBefore( multiDragElement, children[ multiDragIndex ] ); 18247 } else { 18248 _parentEl.appendChild( multiDragElement ); 18249 } 18250 multiDragIndex++; 18251 } ); 18252 18253 // If initial folding is done, the elements may have changed position because they are now 18254 // unfolding around dragEl, even though dragEl may not have his index changed, so update event 18255 // must be fired here as Sortable will not. 18256 if ( _oldIndex === index( dragEl$1 ) ) { 18257 update = false; 18258 multiDragElements.forEach( function( multiDragElement ) { 18259 if ( multiDragElement.sortableIndex !== index( multiDragElement ) ) { 18260 update = true; 18261 } 18262 } ); 18263 if ( update ) { 18264 dispatchSortableEvent( 'update' ); 18265 dispatchSortableEvent( 'sort' ); 18266 } 18267 } 18268 } 18269 18270 // Must be done after capturing individual rects (scroll bar) 18271 multiDragElements.forEach( function( multiDragElement ) { 18272 unsetRect( multiDragElement ); 18273 } ); 18274 toSortable.animateAll(); 18275 } 18276 multiDragSortable = toSortable; 18277 } 18278 18279 // Remove clones if necessary 18280 if ( _rootEl === _parentEl || ( _putSortable && _putSortable.lastPutMode !== 'clone' ) ) { 18281 multiDragClones.forEach( function( _clone ) { 18282 if ( _clone.parentNode ) { 18283 _clone.parentNode.removeChild( _clone ); 18284 } 18285 } ); 18286 } 18287 }, 18288 nullingGlobal: function nullingGlobal() { 18289 this.isMultiDrag = dragStarted = false; 18290 multiDragClones.length = 0; 18291 }, 18292 destroyGlobal: function destroyGlobal() { 18293 this._deselectMultiDrag(); 18294 off( document, 'pointerup', this._deselectMultiDrag ); 18295 off( document, 'mouseup', this._deselectMultiDrag ); 18296 off( document, 'touchend', this._deselectMultiDrag ); 18297 off( document, 'keydown', this._checkKeyDown ); 18298 off( document, 'keyup', this._checkKeyUp ); 18299 }, 18300 _deselectMultiDrag: function _deselectMultiDrag( evt ) { 18301 var el; 18302 if ( typeof dragStarted !== 'undefined' && dragStarted ) { 18303 return; 18304 } 18305 18306 // Only deselect if selection is in this sortable 18307 if ( multiDragSortable !== this.sortable ) { 18308 return; 18309 } 18310 18311 // Only deselect if target is not item in this sortable 18312 if ( evt && closest( evt.target, this.options.draggable, this.sortable.el, false ) ) { 18313 return; 18314 } 18315 18316 // Only deselect if left click 18317 if ( evt && evt.button !== 0 ) { 18318 return; 18319 } 18320 while ( multiDragElements.length ) { 18321 el = multiDragElements[ 0 ]; 18322 toggleClass( el, this.options.selectedClass, false ); 18323 multiDragElements.shift(); 18324 dispatchEvent( { 18325 sortable: this.sortable, 18326 rootEl: this.sortable.el, 18327 name: 'deselect', 18328 targetEl: el, 18329 originalEvent: evt 18330 } ); 18331 } 18332 }, 18333 _checkKeyDown: function _checkKeyDown( evt ) { 18334 if ( evt.key === this.options.multiDragKey ) { 18335 this.multiDragKeyDown = true; 18336 } 18337 }, 18338 _checkKeyUp: function _checkKeyUp( evt ) { 18339 if ( evt.key === this.options.multiDragKey ) { 18340 this.multiDragKeyDown = false;
18341 } 18342 } 18343 }; 18344 return _extends( MultiDrag, { 18345 // Static methods & properties 18346 pluginName: 'multiDrag', 18347 utils: { 18348 /** 18349 * Selects the provided multi-drag item 18350 * @param {HTMLElement} el The element to be selected 18351 */ 18352 select: function select( el ) { 18353 var sortable = el.parentNode[ expando ]; 18354 if ( ! sortable || ! sortable.options.multiDrag || multiDragElements.indexOf( el ) !== -1 ) { 18355 return; 18356 } 18357 if ( multiDragSortable && multiDragSortable !== sortable ) { 18358 multiDragSortable.multiDrag._deselectMultiDrag(); 18359 multiDragSortable = sortable; 18360 } 18361 toggleClass( el, sortable.options.selectedClass, true ); 18362 multiDragElements.push( el ); 18363 }, 18364 /** 18365 * Deselects the provided multi-drag item 18366 * @param {HTMLElement} el The element to be deselected 18367 */ 18368 deselect: function deselect( el ) { 18369 var sortable = el.parentNode[ expando ], 18370 _index = multiDragElements.indexOf( el ); 18371 if ( ! sortable || ! sortable.options.multiDrag || _index === -1 ) { 18372 return; 18373 } 18374 toggleClass( el, sortable.options.selectedClass, false ); 18375 multiDragElements.splice( _index, 1 ); 18376 } 18377 }, 18378 eventProperties: function eventProperties() { 18379 var _this3 = this; 18380 var oldIndicies = [], 18381 newIndicies = []; 18382 var _newIndex; 18383 multiDragElements.forEach( function( multiDragElement ) { 18384 oldIndicies.push( { 18385 multiDragElement: multiDragElement, 18386 index: multiDragElement.sortableIndex 18387 } ); 18388 18389 // multiDragElements will already be sorted if folding 18390 if ( folding && multiDragElement !== dragEl$1 ) { 18391 _newIndex = -1; 18392 } else if ( folding ) { 18393 _newIndex = index( multiDragElement, ':not(.' + _this3.options.selectedClass + ')' ); 18394 } else { 18395 _newIndex = index( multiDragElement ); 18396 } 18397 newIndicies.push( { 18398 multiDragElement: multiDragElement, 18399 index: _newIndex 18400 } ); 18401 } ); 18402 return { 18403 items: _toConsumableArray( multiDragElements ), 18404 clones: [].concat( multiDragClones ), 18405 oldIndicies: oldIndicies, 18406 newIndicies: newIndicies 18407 }; 18408 }, 18409 optionListeners: { 18410 multiDragKey: function multiDragKey( key ) { 18411 key = key.toLowerCase(); 18412 if ( key === 'ctrl' ) { 18413 key = 'Control'; 18414 } else if ( key.length > 1 ) { 18415 key = key.charAt( 0 ).toUpperCase() + key.substr( 1 ); 18416 } 18417 return key; 18418 } 18419 } 18420 } ); 18421 } 18422 function insertMultiDragElements( clonesInserted, _rootEl ) { 18423 multiDragElements.forEach( function( multiDragElement, i ) { 18424 var target = _rootEl.children[ multiDragElement.sortableIndex + ( clonesInserted ? Number( i ) : 0 ) ]; 18425 if ( target ) { 18426 _rootEl.insertBefore( multiDragElement, target ); 18427 } else { 18428 _rootEl.appendChild( multiDragElement ); 18429 } 18430 } ); 18431 } 18432 18433 /** 18434 * Insert multi-drag clones 18435 * @param {[boolean]} elementsInserted Whether the multi-drag elements are inserted 18436 * @param {HTMLElement} _rootEl 18437 */ 18438 function insertMultiDragClones( elementsInserted, _rootEl ) { 18439 multiDragClones.forEach( function( _clone, i ) { 18440 var target = _rootEl.children[ clone.sortableIndex + ( elementsInserted ? Number( i ) : 0 ) ]; 18441 if ( target ) { 18442 _rootEl.insertBefore( _clone, target ); 18443 } else { 18444 _rootEl.appendChild( _clone ); 18445 } 18446 } ); 18447 } 18448 function removeMultiDragElements() { 18449 multiDragElements.forEach( function( multiDragElement ) { 18450 if ( multiDragElement === dragEl$1 ) { 18451 return; 18452 } 18453 if ( multiDragElement && multiDragElement.parentNode ) { 18454 multiDragElement.parentNode.removeChild( multiDragElement ); 18455 } 18456 } ); 18457 } 18458 18459 Sortable.mount( new AutoScrollPlugin() ); 18460 Sortable.mount( Remove, Revert ); 18461 18462 Sortable.mount( new SwapPlugin() ); 18463 Sortable.mount( new MultiDragPlugin() ); 18464 18465 return Sortable; 18466} ) ) ); 18467 18468( function( factory ) { 18469 'use strict'; 18470 var sortable, 18471 jq; 18472 18473 if ( typeof define === 'function' && define.amd ) { 18474 try { 18475 define( [ 'sortablejs', 'jquery' ], function( Sortable, $ ) { 18476 sortable = Sortable; 18477 jq = $; 18478 checkErrors(); 18479 factory( Sortable, $ ); 18480 } ); 18481 } catch ( err ) { 18482 checkErrors(); 18483 } 18484 return; 18485 } else if ( typeof exports === 'object' ) { 18486 try { 18487 sortable = require( 'sortablejs' ); 18488 jq = require( 'jquery' ); 18489 } catch ( err ) { } 18490 } 18491 18492 if ( typeof window.jQuery === 'function' || typeof $ === 'function' ) { 18493 jq = window.jQuery || window.$; 18494 } 18495 18496 if ( typeof window.Sortable !== 'undefined' ) { 18497 sortable = window.Sortable; 18498 } 18499 18500 function checkErrors() { 18501 if ( ! jq ) { 18502 throw new Error( 'jQuery is required for jquery-sortablejs' ); 18503 } 18504 18505 if ( ! sortable ) { 18506 throw new Error( 'SortableJS is required for jquery-sortablejs (https://github.com/SortableJS/Sortable)' ); 18507 } 18508 } 18509 checkErrors(); 18510 factory( sortable, jq ); 18511}( function( Sortable, $ ) { 18512 'use strict'; 18513 18514 $.fn.sortablejs = function( options ) { 18515 var retVal, 18516 args = arguments; 18517 18518 this.each( function() { 18519 var $el = $( this ), 18520 sortable = $el.data( 'sortable' ); 18521 18522 if ( ! sortable && ( options instanceof Object || ! options ) ) { 18523 sortable = new Sortable( this, options ); 18524 $el.data( 'sortable', sortable ); 18525 $el.addClass( 'ui-sortable' ); 18526 } else if ( sortable ) { 18527 if ( options === 'destroy' ) { 18528 sortable.destroy(); 18529 $el.removeData( 'sortable' ); 18530 $el.removeClass( 'ui-sortable' ); 18531 } else if ( options === 'widget' ) { 18532 retVal = sortable; 18533 } else if ( typeof sortable[ options ] === 'function' ) { 18534 retVal = sortable[ options ].apply( sortable, [].slice.call( args, 1 ) ); 18535 }
18535 else if ( options in sortable.options ) { 18536 retVal = sortable.option.apply( sortable, args ); 18537 } 18538 } 18539 } ); 18540 18541 return ( retVal === void 0 ) ? this : retVal; 18542 }; 18543} ) ); 18544; 18545/** 18546 * jQuery Tabs plugin 18547 * Creates a tabular interface 18548 * 18549 * @param {Object} $ The jQuery object 18550 * @version: v1.1 18551 * @author: ThemeComplete 18552 * 18553 * Copyright 2022 ThemeComplete 18554 */ 18555( function( $ ) { 18556 'use strict'; 18557 18558 var localStorage = $.epoAPI.util.getStorage( 'localStorage' ); 18559 var confirm = window.confirm; 18560 18561 var Tabs = function( dom, options ) { 18562 this.elements = $( dom ); 18563 this.last = []; 18564 this.current = []; 18565 this.enableEvents = true; 18566 this.backup = []; 18567 18568 this.options = $.extend( {}, $.fn.tcTabs.defaults, options ); 18569 18570 if ( this.elements.length > 0 ) { 18571 this.init(); 18572 return this; 18573 } 18574 18575 return false; 18576 }; 18577 18578 Tabs.prototype = { 18579 constructor: Tabs, 18580 18581 set: function( options ) { 18582 this.options = $.extend( {}, this.options, options ); 18583 this.init( true ); 18584 }, 18585 18586 addHeaderEvents: function( t, index, tc, header, theaderswrap, theaders, scrollLeftButton, scrollRightButton, state ) { 18587 var additional_events = ''; 18588 var ithis = this; 18589 18590 header.off( 'closetab.tmtabs' ).on( 'closetab.tmtabs', function() { 18591 var $this = $( this ); 18592 var _tab = t.find( $this.data( 'tab' ) ); 18593 18594 $this.removeClass( 'closed open' ).addClass( 'closed' ); 18595 $this 18596 .find( '.tm-arrow' ) 18597 .removeClass( ithis.options.classdown + ' ' + ithis.options.classup ) 18598 .addClass( ithis.options.classdown ); 18599 if ( ithis.options.useclasstohide ) { 18600 _tab.addClass( 'tm-hide' ).removeClass( 'tm-show' ); 18601 } else { 18602 _tab.hide(); 18603 } 18604 _tab.removeClass( 'tm-animated ' + ithis.options.animationclass ); 18605 $( window ).trigger( 'tc-closetab.tmtabs', { 18606 header: $this, 18607 tab: _tab 18608 } ); 18609 } ); 18610 18611 header.off( 'opentab.tmtabs' ).on( 'opentab.tmtabs', function() { 18612 var $this = $( this ); 18613 var _tab = t.find( $this.data( 'tab' ) ); 18614 18615 $this.removeClass( 'closed open' ).addClass( 'open' ); 18616 $this 18617 .find( '.tm-arrow' ) 18618 .removeClass( ithis.options.classdown + ' ' + ithis.options.classup ) 18619 .addClass( ithis.options.classup ); 18620 18621 if ( ithis.options.useclasstohide ) { 18622 _tab.removeClass( 'tm-hide' ).addClass( 'tm-show' ); 18623 } else { 18624 _tab.show(); 18625 } 18626 _tab.removeClass( 'tm-animated ' + ithis.options.animationclass ).addClass( 'tm-animated ' + ithis.options.animationclass ); 18627 ithis.current[ index ] = $this.data( 'tab' ); 18628 $( window ).trigger( 'tc-opentab.tmtabs', { 18629 header: $this, 18630 tab: ithis.current[ index ], 18631 table: _tab 18632 } ); 18633 ithis.scrollIntoView( t, $this, state ); 18634 } ); 18635 18636 if ( ithis.options.showonhover === true || typeof ithis.options.showonhover === 'function' ) { 18637 additional_events = ' mouseover'; 18638 } 18639 18640 header.off( 'keydown.tmtabs' ).on( 'keydown.tmtabs', function( e ) { 18641 var $this = $( this ); 18642 var prevnext; 18643 18644 if ( e.keyCode === 13 ) { 18645 $this.trigger( 'click.tmtabs' ); 18646 } 18647 if ( e.keyCode === 40 ) { 18648 prevnext = $this.closest( '.tm-box' ).next().find( '.' + ithis.options.header ); 18649 } 18650 if ( e.keyCode === 38 ) { 18651 prevnext = $this.closest( '.tm-box' ).prev().find( '.' + ithis.options.header ); 18652 } 18653 if ( prevnext && prevnext.length ) { 18654 $this.trigger( 'blur' ); 18655 prevnext.trigger( ' focus' ).trigger( 'click' ); 18656 e.preventDefault(); 18657 } 18658 } ); 18659 18660 header.off( 'click.tmtabs' ).on( 'click.tmtabs' + additional_events, function( e ) { 18661 var $this = $( this ); 18662 e.preventDefault(); 18663 if ( e.type === 'mouseover' && typeof ithis.options.showonhover === 'function' && ! ithis.options.showonhover.call() ) { 18664 return; 18665 } 18666 if ( ithis.current[ index ] === $this.data( 'tab' ) ) { 18667 $( window ).trigger( 'tc-isopentab.tmtabs', { 18668 header: $this, 18669 tab: ithis.current[ index ], 18670 table: t.find( ithis.current[ index ] ) 18671 } ); 18672 return; 18673 } 18674 if ( ithis.last[ index ] ) { 18675 $( ithis.last[ index ] ).trigger( 'closetab.tmtabs' ); 18676 } 18677 $this.trigger( 'opentab.tmtabs' ); 18678 ithis.last[ index ] = $this; 18679 if ( localStorage ) { 18680 localStorage.setItem( 'tmadmintab-' + tc, $this.attr( ithis.options.dataopenattribute ) ); 18681 } 18682 $( window ).trigger( 'tc-tmtabs-clicked', { 18683 tc: tc, 18684 options: ithis.options, 18685 header: $this, 18686 tab: ithis.current[ index ], 18687 table: t.find( ithis.current[ index ] ) 18688 } ); 18689 } ); 18690 18691 header.find( '.' + this.options.deleteheader ).remove(); 18692 if ( this.options.deletebutton ) { 18693 header.append( this.options.deletebuttonhtml ); 18694 header 18695 .find( '.' + this.options.deleteheader ) 18696 .off( 'click.tmtabs' ) 18697 .on( 'click.tmtabs', function( e ) { 18698 var $t = $( this ); 18699 var $tmbox = $t.closest( '.tm-box' ); 18700 var $header = $tmbox.find( '.' + ithis.options.header ); 18701 var $tab = t.find( '.' + $header.attr( ithis.options.dataattribute ) ); 18702 18703 e.stopPropagation(); 18704 18705 if ( t.find( '.' + ithis.options.headers + ' ' + '.' + ithis.options.header ).length < 2 ) { 18706 return; 18707 } 18708 if ( ithis.options.deleteconfirm ) { 18709 if ( ! confirm( window.TMEPOGLOBALADMINJS.i18n_builder_delete ) ) { 18710 return; 18711 } 18712 } 18713 18714 if ( typeof ithis.options.beforedeletetab === 'function' ) { 18715 ithis.options.beforedeletetab.call( t, $t, $tab ); 18716 } 18717 18718 $tab.remove(); 18719 if ( $header.is( '.open' ) ) { 18720 if ( $tmbox.next().find( '.' + ithis.options.header ).is( '.closed' ) ) { 18721 $tmbox.next().find( '.' + ithis.options.header ).trigger( 'click.tmtabs' ); 18722 } else if ( $tmbox.prev().find( '.' + ithis.options.header ).is( '.closed' ) ) { 18723 $tmbox.prev().find( '.' + ithis.options.header ).trigger( 'click.tmtabs' ); 18724 } 18725 } 18726 $tmbox.remove(); 18727 18728 ithis.checkSize( theaderswrap, theaders, scrollLeftButton, scrollRightButton, state, true ); 18729 if ( typeof ithis.options.afterdeletetab === 'function' ) { 18730 ithis.options.afterdeletetab.call( t ); 18731 } 18732 } ); 18733 } 18734 18735 header.find( '.' + this.options.editheader ).remove(); 18736 if ( this.options.editbutton ) {
18737 header.append( ithis.options.editbuttonhtml ); 18738 header 18739 .find( '.' + ithis.options.editheader ) 18740 .off( 'click.tmtabs' ) 18741 .on( 'click.tmtabs', function( event ) { 18742 var $t; 18743 var $tab; 18744 if ( ithis.enableEvents && typeof ithis.options.oneditbutton === 'function' ) { 18745 event.stopPropagation(); 18746 $t = $( this ); 18747 $tab = t.find( '.' + $t.closest( '.tm-box' ).find( '.' + ithis.options.header ).attr( ithis.options.dataattribute ) ); 18748 ithis.options.oneditbutton.call( t, $t, $tab ); 18749 } 18750 } ); 18751 } 18752 }, 18753 18754 initHeader: function( header, t, index, theaderswrap, theaders, scrollLeftButton, scrollRightButton, state ) { 18755 var id; 18756 var init_open = 0; 18757 var tc = t.attr( 'class' ); 18758 18759 header = $( header ); 18760 id = '.' + header.attr( this.options.dataattribute ); 18761 header.data( 'tab', id ); 18762 if ( this.options.useclasstohide ) { 18763 t.find( id ).addClass( 'tm-hide' ).removeClass( 'tm-show' ); 18764 } else { 18765 t.find( id ).hide(); 18766 } 18767 t.find( id ).data( 'state', 'closed' ); 18768 if ( ! init_open && header.is( '.open' ) ) { 18769 header.removeClass( 'closed open' ).addClass( 'open' ).data( 'state', 'open' ); 18770 header 18771 .find( '.tm-arrow' ) 18772 .removeClass( this.options.classdown + ' ' + this.options.classup ) 18773 .addClass( this.options.classup ); 18774 if ( this.options.useclasstohide ) { 18775 t.find( id ).removeClass( 'tm-hide' ).addClass( 'tm-show' ); 18776 } else { 18777 t.find( id ).show(); 18778 } 18779 t.find( id ).data( 'state', 'open' ); 18780 init_open = 1; 18781 this.current[ index ] = id; 18782 this.last[ index ] = header; 18783 } else { 18784 header.removeClass( 'closed open' ).addClass( 'closed' ).data( 'state', 'closed' ); 18785 } 18786 18787 this.addHeaderEvents( t, index, tc, header, theaderswrap, theaders, scrollLeftButton, scrollRightButton, state ); 18788 }, 18789 18790 checkSize: function( theaderswrap, theaders, scrollLeftButton, scrollRightButton, state, setScrollWidth ) { 18791 var panelWidth; 18792 var openedHeader; 18793 var props = []; 18794 var hiddenParents = theaders.parents().addBack().not( ':visible' ); 18795 18796 // When tabs element is hidden its width cannot be calcualted 18797 // so we revert the visibility for this procedure only 18798 hiddenParents.each( function() { 18799 var $this = $( this ); 18800 var styleDisplay = this.style.display; 18801 var cssDisplay = $this.css( 'display' ); 18802 var styleVisibility = this.style.visibility; 18803 var cssVisibility = $this.css( 'visibility' ); 18804 var obj; 18805 var did = false; 18806 obj = { 18807 styleDisplay: styleDisplay, 18808 cssDisplay: cssDisplay, 18809 styleVisibility: styleVisibility, 18810 cssVisibility: cssVisibility, 18811 display: null, 18812 visibility: null, 18813 element: $this 18814 }; 18815 if ( styleDisplay === 'none' ) { 18816 this.style.display = ''; 18817 obj.display = true; 18818 if ( $this.css( 'display' ) === 'none' ) { 18819 this.style.display = 'block'; 18820 } 18821 did = true; 18822 } 18823 if ( styleVisibility === 'hidden' ) { 18824 this.style.visibility = ''; 18825 obj.visibility = true; 18826 if ( $this.css( 'visibility' ) === 'hidden' ) { 18827 this.style.visibility = 'visible'; 18828 } 18829 did = true; 18830 } 18831 18832 if ( did ) { 18833 props.push( obj ); 18834 } 18835 } ); 18836 18837 panelWidth = Math.round( theaders.outerWidth() ); 18838 18839 if ( theaders.is( '.has-scroll-arrows' ) ) { 18840 theaders.removeClass( '.has-scroll-arrows' ); 18841 panelWidth = Math.round( theaderswrap.outerWidth() ); 18842 } 18843 18844 if ( setScrollWidth ) { 18845 openedHeader = theaders.find( '.' + this.options.header + '.open' ); 18846 if ( openedHeader.length ) { 18847 openedHeader.removeClass( 'open' ); 18848 } 18849 state.scrollWidth = theaders[ 0 ].scrollWidth; 18850 if ( openedHeader.length ) { 18851 openedHeader.addClass( 'open' ); 18852 } 18853 } 18854 18855 if ( state.scrollWidth > panelWidth ) { 18856 scrollRightButton.addClass( 'scroll-arrow-show' ); 18857 scrollLeftButton.addClass( 'scroll-arrow-show' ); 18858 theaders.addClass( 'has-scroll-arrows' ); 18859 18860 if ( state.scrollWidth - panelWidth === theaders.scrollLeft() ) { 18861 scrollRightButton.addClass( 'scroll-arrow-disabled scroll-arrow-right-disabled' ); 18862 } else { 18863 scrollRightButton.removeClass( 'scroll-arrow-disabled scroll-arrow-right-disabled' ); 18864 } 18865 if ( theaders.scrollLeft() === 0 ) { 18866 scrollLeftButton.addClass( 'scroll-arrow-disabled scroll-arrow-left-disabled' ); 18867 } else { 18868 scrollLeftButton.removeClass( 'scroll-arrow-disabled scroll-arrow-left-disabled' ); 18869 } 18870 } else { 18871 scrollRightButton.removeClass( 'scroll-arrow-show' ); 18872 scrollLeftButton.removeClass( 'scroll-arrow-show' ); 18873 theaders[ 0 ].scrollLeft = 0; 18874 theaders.removeClass( 'has-scroll-arrows' ); 18875 } 18876 18877 props.forEach( function( o ) { 18878 if ( o.display ) { 18879 o.element[ 0 ].style.display = o.styleDisplay; 18880 } 18881 if ( o.visibility ) { 18882 o.element[ 0 ].style.visibility = o.styleVisibility; 18883 } 18884 } ); 18885 }, 18886 18887 scrollIntoView: function( t, header, state ) { 18888 var left = state.scrollPos; 18889 var theaders = t.find( '.' + this.options.headers ); 18890 var scrollWidth = theaders.width(); 18891 18892 if ( theaders.is( '.has-scroll-arrows' ) && header && typeof ( header ) !== 'undefined' && header.position() && typeof ( header.position() ) !== 'undefined' ) { 18893 if ( header.position().left < 0 ) { 18894 state.scrollPos = Math.max( left + header.position().left + 1, 0 ); 18895 theaders.animate( { scrollLeft: ( state.scrollPos + 1 ) + 'px' }, this.options.scrollDuration ); 18896 } else if ( ( header.position().left + header.outerWidth() ) > scrollWidth ) { 18897 state.scrollPos = Math.min( left + ( ( header.position().left + header.outerWidth() ) - scrollWidth ), theaders[ 0 ].scrollWidth - theaders.outerWidth() ); 18898 theaders.animate( { scrollLeft: ( state.scrollPos - 1 ) + 'px' }, this.options.scrollDuration ); 18899 } 18900 } 18901 }, 18902 18903 initElement: function( t, index, state, uniqid ) { 18904 var ithis = this; 18905 var tc = t.attr( 'class' ); 18906 var sortableHeader; 18907 var theaders; 18908 var theaderswrap; 18909 var scrollLeftButton; 18910 var scrollRightButton; 18911 var headers = t.find( '.' + this.options.headers + ' ' + '.' + this.options.header ); 18912 var ohp = 0; 18913 var ohpid = ''; 18914 var _selected_tab; 18915 var vars = {}; 18916 var initialIndex; 18917 var pressHoldTimeout; 18918 18919 if ( headers.length === 0 ) { 18920 return; 18921 } 18922 18923 theaders = t.find( '.' + this.options.headers ); 18924 theaders.wrap( '<div class="' + this.options.headersWrap + '"></div>' ); 18925 theaderswrap = t.find( '.' + this.options.headersWrap ); 18926 18927 if ( this.options.scroll ) { 18928 theaderswrap.html( '<div class="tc-scroll-left-arrow"></div>' + theaderswrap.html() + '<div class="tc-scroll-right-arrow"></div>' ); 18929 headers = t.find( '.' + this.options.headers + ' ' + '.' + this.options.header ); 18930 theaders = t.find( '.' + this.options.headers ); 18931 scrollLeftButton = t.find( '.tc-scroll-left-arrow' ); 18932 scrollRightButton = t.find( '.tc-scroll-right-arrow' ); 18933 18934 // Mousewheel support, if present. 18935 if ( typeof $.fn.mousewheel === 'function' ) { 18936 theaders.mousewheel( function( event, delta ) { 18937 // Only do mousewheel scrolling if scrolling is necessary 18938 if ( scrollRightButton.css( 'display' ) !== 'none' ) { 18939 this.scrollLeft -= ( delta * 30 ); 18940 state.scrollPos = this.scrollLeft; 18941 event.preventDefault(); 18942 } 18943 } ); 18944 } 18945 18946 // Set initial scroll position 18947 theaders.animate( { scrollLeft: state.scrollPos + 'px' }, 0 ); 18948 18949 this.checkSize( theaderswrap, theaders, scrollLeftButton, scrollRightButton, state, true ); 18950 $( window ).off( 'resize.tmtabs' + uniqid ).on( 'resize.tmtabs' + uniqid, function() { 18951 ithis.checkSize( theaderswrap, theaders, scrollLeftButton, scrollRightButton, state, true ); 18952 } ); 18953 18954 t.off( 'refresh.tmtabs' + uniqid ).on( 'refresh.tmtabs' + uniqid, function() { 18955 ithis.checkSize( theaderswrap, theaders, scrollLeftButton, scrollRightButton, state, true ); 18956 } ); 18957 18958 // Document load 18959 $( function() { 18960 ithis.checkSize( theaderswrap, theaders, scrollLeftButton, scrollRightButton, state, true ); 18961 } ); 18962 18963 scrollRightButton.off( 'mousedown.tmtabs mouseup.tmtabs mouseleave.tmtabs mouseover.tmtabs mouseout.tmtabs' ) 18964 .on( 'mousedown.tmtabs', function( e ) { 18965 var scrollRightFunc = function() { 18966 var left = theaders.scrollLeft(); 18967 state.scrollPos = Math.min( left + ithis.options.scrollDistance, state.scrollWidth - theaders.outerWidth() ); 18968 theaders.animate( 18969 { 18970 scrollLeft: state.scrollPos + 'px' 18971 }, 18972 ithis.options.scrollDuration, 18973 function() { 18974 ithis.checkSize( theaderswrap, theaders, scrollLeftButton, scrollRightButton, state ); 18975 } 18976 ); 18977 }; 18978 e.stopPropagation(); 18979 scrollRightFunc(); 18980 18981 pressHoldTimeout = setInterval( function() { 18982 scrollRightFunc(); 18983 }, ithis.options.scrollDuration ); 18984 } ).on( 'mouseup.tmtabs mouseleave.tmtabs', function() { 18985 clearInterval( pressHoldTimeout ); 18986 } ).on( 'mouseover.tmtabs', function() { 18987 $( this ).addClass( 'scroll-arrow-over scroll-arrow-right-over' ); 18988 } ).on( 'mouseout.tmtabs', function() { 18989 $( this ).removeClass( 'scroll-arrow-over scroll-arrow-right-over' ); 18990 } ); 18991 18992 scrollLeftButton.off( 'mousedown.tmtabs mouseup.tmtabs mouseleave.tmtabs mouseover.tmtabs mouseout.tmtabs' ) 18993 .on( 'mousedown.tmtabs', function( e ) {
18994 var scrollLeftFunc = function() { 18995 var left = theaders.scrollLeft(); 18996 state.scrollPos = Math.max( left - ithis.options.scrollDistance, 0 ); 18997 theaders.animate( 18998 { 18999 scrollLeft: state.scrollPos + 'px' 19000 }, 19001 ithis.options.scrollDuration, 19002 function() { 19003 ithis.checkSize( theaderswrap, theaders, scrollLeftButton, scrollRightButton, state ); 19004 } 19005 ); 19006 }; 19007 e.stopPropagation(); 19008 scrollLeftFunc(); 19009 19010 pressHoldTimeout = setInterval( function() { 19011 scrollLeftFunc(); 19012 }, ithis.options.scrollDuration ); 19013 } ).on( 'mouseup.tmtabs mouseleave.tmtabs', function() { 19014 clearInterval( pressHoldTimeout ); 19015 } ).on( 'mouseover.tmtabs', function() { 19016 $( this ).addClass( 'scroll-arrow-over scroll-arrow-left-over' ); 19017 } ).on( 'mouseout.tmtabs', function() { 19018 $( this ).removeClass( 'scroll-arrow-over scroll-arrow-left-over' ); 19019 } ); 19020 } 19021 19022 window.location.href.replace( /[?&]+([^=&]+)=([^&]*)/gi, function( m, key, value ) { 19023 vars[ key ] = value; 19024 } ); 19025 19026 this.last[ index ] = false; 19027 this.current[ index ] = ''; 19028 19029 t.data( 'tm-has-tmtabs', 1 ); 19030 19031 headers.each( function( i, header ) { 19032 ithis.initHeader( header, t, index, theaderswrap, theaders, scrollLeftButton, scrollRightButton, state ); 19033 } ); 19034 19035 if ( this.options.sortabletabs ) { 19036 sortableHeader = '.' + this.options.headers; 19037 if ( t.find( sortableHeader + ' .' + this.options.headers + '-inner' ).length ) { 19038 sortableHeader = '.' + this.options.headers + '-inner'; 19039 } 19040 t.find( sortableHeader + ':not(.section_elements ' + sortableHeader + ',.tm-settings-wrap ' + sortableHeader + ',.builder-element-wrap ' + sortableHeader + ')' ).sortablejs( { 19041 draggable: '.tm-box:not(.tm-add-box)', 19042 handle: '.tm-box:not(.tm-add-box)', 19043 onStart: function( evt ) { 19044 var ui = $( evt.item ); 19045 var $tab; 19046 $tab = t.find( '.' + ui.closest( '.tm-box' ).find( '.' + ithis.options.header ).attr( ithis.options.dataattribute ) ); 19047 ohp = ui.index(); 19048 ohpid = ui.find( '.' + ithis.options.header ).attr( ithis.options.dataopenattribute ); 19049 19050 initialIndex = $.tmEPOAdmin.find_index( true, $tab.find( '.bitem' ).first() ); 19051 19052 if ( typeof ithis.options.beforemovetab === 'function' ) { 19053 ithis.options.beforemovetab.call( this, ohp, $tab, initialIndex ); 19054 } 19055 ithis.enableEvents = false; 19056 }, 19057 onEnd: function( evt ) { 19058 var ui = $( evt.item ); 19059 var original_item; 19060 var new_index; 19061 var replaced_item; 19062 var $tab; 19063 var originalItemCopy; 19064 19065 $tab = t.find( '.' + ui.closest( '.tm-box' ).find( '.' + ithis.options.header ).attr( ithis.options.dataattribute ) ); 19066 original_item = t.find( '.' + ithis.options.slide + '.' + ohpid ); 19067 new_index = t 19068 .find( '.' + ithis.options.headers + ' ' + '.' + ithis.options.header + '[' + ithis.options.dataopenattribute + '=\'' + ohpid + '\']' ) 19069 .parent() 19070 .index(); 19071 if ( new_index !== ohp ) { 19072 replaced_item = t.find( '.' + ithis.options.slide ).eq( new_index ); 19073 originalItemCopy = original_item.tcClone(); 19074 originalItemCopy.find( '.bitem' ).remove(); 19075 if ( new_index > ohp ) { 19076 replaced_item.after( originalItemCopy ); 19077 } else if ( new_index < ohp ) { 19078 replaced_item.before( originalItemCopy ); 19079 } 19080 original_item.find( '.bitem' ).toArray().forEach( function( el ) { 19081 el = $( el ); 19082 if ( typeof ithis.options.beforemovebitem === 'function' ) { 19083 ithis.options.beforemovebitem.call( this, new_index, ohp, $tab, initialIndex, el ); 19084 } 19085 originalItemCopy.append( el ); 19086 if ( typeof ithis.options.aftermovebitem === 'function' ) { 19087 ithis.options.aftermovebitem.call( this, new_index, ohp, $tab, initialIndex, el ); 19088 } 19089 } ); 19090 original_item.remove(); 19091 if ( typeof ithis.options.aftermovetab === 'function' ) { 19092 ithis.options.aftermovetab.call( this, new_index, ohp, $tab, initialIndex ); 19093 } 19094 } 19095 ithis.enableEvents = true; 19096 }, 19097 filter: '.tm-add-box', 19098 ghostClass: 'sortable-ghost', 19099 dragClass: 'sortable-drag' 19100 19101 } ); 19102 } 19103 19104 if ( this.options.addbutton ) { 19105 theaderswrap.append( this.options.addbuttonhtml ); 19106 t.addClass( 'has-add-button' ).find( '.' + this.options.addheader ).off( 'click.tmtabs' ).on( 'click.tmtabs', function( e ) { 19107 var allHeaders = t.find( '.' + ithis.options.headers + ' ' + '.' + ithis.options.header ); 19108 var last_header = allHeaders.last(); 19109 var id = last_header.attr( ithis.options.dataattribute ); 19110 var last_tab = t.find( '.' + id ); 19111 var new_header = last_header.tcClone().off( 'closetab.tmtabs opentab.tmtabs click.tmtabs' ); 19112 var new_tab = last_tab.tcClone().empty(); 19113 var newid = ithis.options.slide + allHeaders.length; 19114 19115 e.preventDefault(); 19116 19117 new_header 19118 .html( '<span class="tab-text">' + ( t.find( '.' + ithis.options.headers + ' ' + '.' + ithis.options.header ).length + 1 ) + '</span>' ) 19119 .removeClass( 'closed open' ) 19120 .addClass( 'closed' ) 19121 .data( 'tab', '.' + newid ) 19122 .data( 'state', 'closed' ) 19123 .attr( ithis.options.dataattribute, newid ); 19124 new_tab.removeClass( id ).addClass( newid ); 19125 if ( ithis.options.useclasstohide ) { 19126 new_tab.addClass( 'tm-hide' ).removeClass( '.tm-show' ); 19127 } else { 19128 new_tab.hide(); 19129 } 19130 new_tab.removeClass( 'tm-animated ' + ithis.options.animationclass ); 19131 19132 last_header.closest( '.tm-box' ).after( new_header ); 19133 19134 new_header.wrap( '<div class="tm-box"></div>' ); 19135 19136 ithis.addHeaderEvents( t, index, tc, new_header, theaderswrap, theaders, scrollLeftButton, scrollRightButton, state ); 19137 last_tab.after( new_tab ); 19138 if ( ithis.options.scroll ) { 19139 theaders.animate( 19140 { 19141 scrollLeft: new_header.width() + 'px' 19142 }, 19143 ithis.options.scrollDuration, 19144 function() { 19145 ithis.checkSize( theaderswrap, theaders, scrollLeftButton, scrollRightButton, state, true ); 19146 } 19147 ); 19148 } 19149 if ( typeof ithis.options.afteraddtab === 'function' ) { 19150 ithis.options.afteraddtab.call( this, new_header, new_tab ); 19151 } 19152 } ); 19153 } else { 19154 theaderswrap.find( '.' + this.options.addheader ).remove(); 19155 } 19156 19157 if ( this.options.selectedtab === 'auto' ) { 19158 if ( localStorage ) { 19159 _selected_tab = localStorage.getItem( 'tmadmintab-' + tc ); 19160 } 19161 if ( vars.selected_tab !== undefined ) { 19162 _selected_tab = vars.selected_tab; 19163 } 19164 if ( vars.menu !== undefined ) { 19165 _selected_tab = vars.menu; 19166 } 19167 if ( _selected_tab === undefined || _selected_tab === null ) { 19168 _selected_tab = t.find( '.' + this.options.header ).eq( 0 ).attr( this.options.dataopenattribute ); 19169 } 19170 if ( ! t.find( '.' + this.options.header + '[' + this.options.dataopenattribute + '="' + _selected_tab + '"]' ).is( ':visible' ) ) { 19171 t.find( '.' + this.options.header ).eq( 0 ).trigger( 'click.tmtabs' ); 19172 } else { 19173 t.find( '.' + this.options.header + '[' + this.options.dataopenattribute + '="' + _selected_tab + '"]' ).trigger( 'click.tmtabs' ); 19174 } 19175 } else if ( this.options.selectedtab !== false ) { 19176 _selected_tab = parseInt( this.options.selectedtab, 10 ); 19177 t.find( '.' + this.options.header + ':eq(' + _selected_tab + ')' ).trigger( 'click.tmtabs' ); 19178 } 19179 }, 19180 19181 init: function( nobackup ) { 19182 var ithis = this; 19183 this.elements.each( function( index ) { 19184 var t = $( this ); 19185 var display; 19186 var state = {}; 19187 var backup = t.html(); 19188 var tmSettingsWrap = $( ithis.options.animateDiv ); 19189 19190 if ( ! nobackup && ithis.backup[ index ] ) { 19191 t.html( ithis.backup[ index ] ); 19192 } else { 19193 ithis.backup[ index ] = backup; 19194 } 19195 state.scrollPos = 0; 19196 state.scrollWidth = 0; 19197 display = t.css( 'display' ); 19198 tmSettingsWrap.show(); 19199 t.show(); 19200 ithis.initElement( t, index, state, $.epoAPI.math.uniqueid( '' ) ); 19201 t.css( 'display', display );
19202 tmSettingsWrap.addClass( 'appear' ); 19203 } ); 19204 } 19205 }; 19206 19207 $.fn.tcTabs = function( option ) { 19208 var methodReturn; 19209 var targets = $( this ); 19210 var data = targets.data( 'tctabs' ); 19211 var options; 19212 var ret; 19213 var args = $.makeArray( arguments ); 19214 args.splice( 0, 1 ); 19215 19216 if ( typeof option === 'object' ) { 19217 options = option; 19218 } else { 19219 options = {}; 19220 } 19221 19222 if ( ! data ) { 19223 data = new Tabs( this, options ); 19224 targets.data( 'tctabs', data ); 19225 } 19226 19227 if ( typeof option === 'string' ) { 19228 methodReturn = data[ option ].apply( data, args ); 19229 } 19230 19231 if ( methodReturn === undefined ) { 19232 ret = targets; 19233 } else { 19234 ret = methodReturn; 19235 } 19236 19237 return ret; 19238 }; 19239 19240 $.fn.tcTabs.defaults = { 19241 headers: 'tm-tab-headers', 19242 headersWrap: 'tc-tab-headers-wrap', 19243 header: 'tab-header', 19244 slide: 'tc-tab-slide', 19245 19246 classdown: 'tcfa-angle-down', 19247 classup: 'tcfa-angle-up', 19248 animationclass: 'appear', 19249 19250 dataattribute: 'data-id', 19251 dataopenattribute: 'data-id', 19252 selectedtab: 'auto', 19253 showonhover: false, 19254 useclasstohide: true, 19255 sortabletabs: true, 19256 19257 addbutton: false, 19258 addheader: 'tm-add-tab', 19259 addbuttonhtml: '<div class="tm-add-tab"><span class="tmicon tcfa tcfa-plus"></span></div>', 19260 afteraddtab: null, 19261 19262 beforemovetab: null, 19263 aftermovetab: null, 19264 beforemovebitem: null, 19265 aftermovebitem: null, 19266 19267 deletebutton: false, 19268 deletebuttonhtml: '<div class="tm-del-tab"><span class="tcfa tcfa-times"></span></div>', 19269 deleteheader: 'tm-del-tab', 19270 deleteconfirm: false, 19271 beforedeletetab: null, 19272 afterdeletetab: null, 19273 19274 editbutton: false, 19275 editbuttonhtml: '<span class="tm-edit-tab"><span class="tcfa tcfa-edit"></span></span>', 19276 editheader: 'tm-edit-tab', 19277 oneditbutton: null, 19278 19279 scroll: true, 19280 scrollDistance: 300, 19281 scrollDuration: 300, 19282 animateDiv: '' 19283 }; 19284 19285 $.fn.tcTabs.Constructor = Tabs; 19286 19287 $.fn.tmtabs = $.fn.tcTabs; 19288}( window.jQuery ) ); 19289; 19290// TinyColor v1.4.1 19291// https://github.com/bgrins/TinyColor 19292// Brian Grinstead, MIT License 19293// reformatted code by ThemeComplete 19294( function( Math ) { 19295 'use strict'; 19296 19297 var trimLeft = /^\s+/, 19298 trimRight = /\s+$/, 19299 tinyCounter = 0, 19300 mathRound = Math.round, 19301 mathMin = Math.min, 19302 mathMax = Math.max, 19303 mathRandom = Math.random; 19304 19305 var names = { 19306 aliceblue: 'f0f8ff', 19307 antiquewhite: 'faebd7', 19308 aqua: '0ff', 19309 aquamarine: '7fffd4', 19310 azure: 'f0ffff', 19311 beige: 'f5f5dc', 19312 bisque: 'ffe4c4', 19313 black: '000', 19314 blanchedalmond: 'ffebcd', 19315 blue: '00f', 19316 blueviolet: '8a2be2', 19317 brown: 'a52a2a', 19318 burlywood: 'deb887', 19319 burntsienna: 'ea7e5d', 19320 cadetblue: '5f9ea0', 19321 chartreuse: '7fff00', 19322 chocolate: 'd2691e', 19323 coral: 'ff7f50', 19324 cornflowerblue: '6495ed', 19325 cornsilk: 'fff8dc', 19326 crimson: 'dc143c', 19327 cyan: '0ff', 19328 darkblue: '00008b', 19329 darkcyan: '008b8b', 19330 darkgoldenrod: 'b8860b', 19331 darkgray: 'a9a9a9', 19332 darkgreen: '006400', 19333 darkgrey: 'a9a9a9', 19334 darkkhaki: 'bdb76b', 19335 darkmagenta: '8b008b', 19336 darkolivegreen: '556b2f', 19337 darkorange: 'ff8c00', 19338 darkorchid: '9932cc', 19339 darkred: '8b0000', 19340 darksalmon: 'e9967a', 19341 darkseagreen: '8fbc8f', 19342 darkslateblue: '483d8b', 19343 darkslategray: '2f4f4f', 19344 darkslategrey: '2f4f4f', 19345 darkturquoise: '00ced1', 19346 darkviolet: '9400d3', 19347 deeppink: 'ff1493', 19348 deepskyblue: '00bfff', 19349 dimgray: '696969', 19350 dimgrey: '696969', 19351 dodgerblue: '1e90ff', 19352 firebrick: 'b22222', 19353 floralwhite: 'fffaf0', 19354 forestgreen: '228b22', 19355 fuchsia: 'f0f', 19356 gainsboro: 'dcdcdc', 19357 ghostwhite: 'f8f8ff', 19358 gold: 'ffd700', 19359 goldenrod: 'daa520', 19360 gray: '808080', 19361 green: '008000', 19362 greenyellow: 'adff2f', 19363 grey: '808080', 19364 honeydew: 'f0fff0', 19365 hotpink: 'ff69b4', 19366 indianred: 'cd5c5c', 19367 indigo: '4b0082', 19368 ivory: 'fffff0', 19369 khaki: 'f0e68c', 19370 lavender: 'e6e6fa', 19371 lavenderblush: 'fff0f5', 19372 lawngreen: '7cfc00', 19373 lemonchiffon: 'fffacd', 19374 lightblue: 'add8e6', 19375 lightcoral: 'f08080', 19376 lightcyan: 'e0ffff', 19377 lightgoldenrodyellow: 'fafad2', 19378 lightgray: 'd3d3d3', 19379 lightgreen: '90ee90', 19380 lightgrey: 'd3d3d3', 19381 lightpink: 'ffb6c1', 19382 lightsalmon: 'ffa07a', 19383 lightseagreen: '20b2aa', 19384 lightskyblue: '87cefa', 19385 lightslategray: '789', 19386 lightslategrey: '789', 19387 lightsteelblue: 'b0c4de', 19388 lightyellow: 'ffffe0', 19389 lime: '0f0', 19390 limegreen: '32cd32', 19391 linen: 'faf0e6', 19392 magenta: 'f0f', 19393 maroon: '800000', 19394 mediumaquamarine: '66cdaa', 19395 mediumblue: '0000cd', 19396 mediumorchid: 'ba55d3', 19397 mediumpurple: '9370db', 19398 mediumseagreen: '3cb371', 19399 mediumslateblue: '7b68ee', 19400 mediumspringgreen: '00fa9a', 19401 mediumturquoise: '48d1cc', 19402 mediumvioletred: 'c71585', 19403 midnightblue: '191970', 19404 mintcream: 'f5fffa', 19405 mistyrose: 'ffe4e1', 19406 moccasin: 'ffe4b5', 19407 navajowhite: 'ffdead', 19408 navy: '000080', 19409 oldlace: 'fdf5e6',
19410 olive: '808000', 19411 olivedrab: '6b8e23', 19412 orange: 'ffa500', 19413 orangered: 'ff4500', 19414 orchid: 'da70d6', 19415 palegoldenrod: 'eee8aa', 19416 palegreen: '98fb98', 19417 paleturquoise: 'afeeee', 19418 palevioletred: 'db7093', 19419 papayawhip: 'ffefd5', 19420 peachpuff: 'ffdab9', 19421 peru: 'cd853f', 19422 pink: 'ffc0cb', 19423 plum: 'dda0dd', 19424 powderblue: 'b0e0e6', 19425 purple: '800080', 19426 rebeccapurple: '663399', 19427 red: 'f00', 19428 rosybrown: 'bc8f8f', 19429 royalblue: '4169e1', 19430 saddlebrown: '8b4513', 19431 salmon: 'fa8072', 19432 sandybrown: 'f4a460', 19433 seagreen: '2e8b57', 19434 seashell: 'fff5ee', 19435 sienna: 'a0522d', 19436 silver: 'c0c0c0', 19437 skyblue: '87ceeb', 19438 slateblue: '6a5acd', 19439 slategray: '708090', 19440 slategrey: '708090', 19441 snow: 'fffafa', 19442 springgreen: '00ff7f', 19443 steelblue: '4682b4', 19444 tan: 'd2b48c', 19445 teal: '008080', 19446 thistle: 'd8bfd8', 19447 tomato: 'ff6347', 19448 turquoise: '40e0d0', 19449 violet: 'ee82ee', 19450 wheat: 'f5deb3', 19451 white: 'fff', 19452 whitesmoke: 'f5f5f5', 19453 yellow: 'ff0', 19454 yellowgreen: '9acd32' 19455 }; 19456 19457 // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` 19458 var flip = function( o ) { 19459 var flipped = {}; 19460 var i; 19461 for ( i in o ) { 19462 if ( Object.prototype.hasOwnProperty.call( o, i ) ) { 19463 flipped[ o[ i ] ] = i; 19464 } 19465 } 19466 return flipped; 19467 }; 19468 19469 var hexNames = flip( names ); 19470 19471 var matchers = ( function() { 19472 // <http://www.w3.org/TR/css3-values/#integers> 19473 var CSS_INTEGER = '[-\\+]?\\d+%?'; 19474 19475 // <http://www.w3.org/TR/css3-values/#number-value> 19476 var CSS_NUMBER = '[-\\+]?\\d*\\.\\d+%?'; 19477 19478 // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. 19479 var CSS_UNIT = '(?:' + CSS_NUMBER + ')|(?:' + CSS_INTEGER + ')'; 19480 19481 // Actual matching. 19482 // Parentheses and commas are optional, but not required. 19483 // Whitespace can take the place of commas or opening paren 19484 var PERMISSIVE_MATCH3 = '[\\s|\\(]+(' + CSS_UNIT + ')[,|\\s]+(' + CSS_UNIT + ')[,|\\s]+(' + CSS_UNIT + ')\\s*\\)?'; 19485 var PERMISSIVE_MATCH4 = '[\\s|\\(]+(' + CSS_UNIT + ')[,|\\s]+(' + CSS_UNIT + ')[,|\\s]+(' + CSS_UNIT + ')[,|\\s]+(' + CSS_UNIT + ')\\s*\\)?'; 19486 19487 return { 19488 CSS_UNIT: new RegExp( CSS_UNIT ), 19489 rgb: new RegExp( 'rgb' + PERMISSIVE_MATCH3 ), 19490 rgba: new RegExp( 'rgba' + PERMISSIVE_MATCH4 ), 19491 hsl: new RegExp( 'hsl' + PERMISSIVE_MATCH3 ), 19492 hsla: new RegExp( 'hsla' + PERMISSIVE_MATCH4 ), 19493 hsv: new RegExp( 'hsv' + PERMISSIVE_MATCH3 ), 19494 hsva: new RegExp( 'hsva' + PERMISSIVE_MATCH4 ), 19495 hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, 19496 hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/, 19497 hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, 19498 hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ 19499 }; 19500 }() ); 19501 19502 // `isValidCSSUnit` 19503 // Take in a single string / number and check to see if it looks like a CSS unit 19504 // (see `matchers` above for definition). 19505 function isValidCSSUnit( color ) { 19506 return !! matchers.CSS_UNIT.exec( color ); 19507 } 19508 19509 // Parse a base-16 hex value into a base-10 integer 19510 function parseIntFromHex( val ) { 19511 return parseInt( val, 16 ); 19512 } 19513 19514 // Converts a hex value to a decimal 19515 function convertHexToDecimal( h ) { 19516 return parseIntFromHex( h ) / 255; 19517 } 19518 19519 // `stringInputToObject` 19520 // Permissive string parsing. Take in a number of formats, and output an object 19521 // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` 19522 function stringInputToObject( color ) { 19523 var named = false; 19524 var match; 19525 color = color.replace( trimLeft, '' ).replace( trimRight, '' ).toLowerCase(); 19526 19527 if ( names[ color ] ) { 19528 color = names[ color ]; 19529 named = true; 19530 } else if ( color === 'transparent' ) { 19531 return { r: 0, g: 0, b: 0, a: 0, format: 'name' }; 19532 } 19533 19534 // Try to match string input using regular expressions. 19535 // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] 19536 // Just return an object and let the conversion functions handle that. 19537 // This way the result will be the same whether the TinyColor is initialized with string or object. 19538 19539 if ( ( match = matchers.rgb.exec( color ) ) ) { 19540 return { r: match[ 1 ], g: match[ 2 ], b: match[ 3 ] }; 19541 } 19542 if ( ( match = matchers.rgba.exec( color ) ) ) { 19543 return { r: match[ 1 ], g: match[ 2 ], b: match[ 3 ], a: match[ 4 ] }; 19544 } 19545 if ( ( match = matchers.hsl.exec( color ) ) ) { 19546 return { h: match[ 1 ], s: match[ 2 ], l: match[ 3 ] }; 19547 } 19548 if ( ( match = matchers.hsla.exec( color ) ) ) { 19549 return { h: match[ 1 ], s: match[ 2 ], l: match[ 3 ], a: match[ 4 ] }; 19550 } 19551 if ( ( match = matchers.hsv.exec( color ) ) ) { 19552 return { h: match[ 1 ], s: match[ 2 ], v: match[ 3 ] }; 19553 } 19554 if ( ( match = matchers.hsva.exec( color ) ) ) { 19555 return { h: match[ 1 ], s: match[ 2 ], v: match[ 3 ], a: match[ 4 ] }; 19556 } 19557 if ( ( match = matchers.hex8.exec( color ) ) ) { 19558 return { 19559 r: parseIntFromHex( match[ 1 ] ), 19560 g: parseIntFromHex( match[ 2 ] ), 19561 b: parseIntFromHex( match[ 3 ] ), 19562 a: convertHexToDecimal( match[ 4 ] ), 19563 format: named ? 'name' : 'hex8' 19564 }; 19565 } 19566 if ( ( match = matchers.hex6.exec( color ) ) ) { 19567 return { 19568 r: parseIntFromHex( match[ 1 ] ), 19569 g: parseIntFromHex( match[ 2 ] ), 19570 b: parseIntFromHex( match[ 3 ] ), 19571 format: named ? 'name' : 'hex' 19572 }; 19573 } 19574 if ( ( match = matchers.hex4.exec( color ) ) ) { 19575 return { 19576 r: parseIntFromHex( match[ 1 ] + '' + match[ 1 ] ), 19577 g: parseIntFromHex( match[ 2 ] + '' + match[ 2 ] ), 19578 b: parseIntFromHex( match[ 3 ] + '' + match[ 3 ] ), 19579 a: convertHexToDecimal( match[ 4 ] + '' + match[ 4 ] ), 19580 format: named ? 'name' : 'hex8' 19581 }; 19582 } 19583 if ( ( match = matchers.hex3.exec( color ) ) ) { 19584 return { 19585 r: parseIntFromHex( match[ 1 ] + '' + match[ 1 ] ), 19586 g: parseIntFromHex( match[ 2 ] + '' + match[ 2 ] ), 19587 b: parseIntFromHex( match[ 3 ] + '' + match[ 3 ] ), 19588 format: named ? 'name' : 'hex' 19589 }; 19590 } 19591 19592 return false;
19593 } 19594 19595 function validateWCAG2Parms( parms ) { 19596 // return valid WCAG2 parms for isReadable. 19597 // If input parms are invalid, return {"level":"AA", "size":"small"} 19598 var level, size; 19599 parms = parms || { level: 'AA', size: 'small' }; 19600 level = ( parms.level || 'AA' ).toUpperCase(); 19601 size = ( parms.size || 'small' ).toLowerCase(); 19602 if ( level !== 'AA' && level !== 'AAA' ) { 19603 level = 'AA'; 19604 } 19605 if ( size !== 'small' && size !== 'large' ) { 19606 size = 'small'; 19607 } 19608 return { level: level, size: size }; 19609 } 19610 19611 // Utilities 19612 // --------- 19613 19614 // Return a valid alpha value [0,1] with all invalid values being set to 1 19615 function boundAlpha( a ) { 19616 a = parseFloat( a ); 19617 19618 if ( isNaN( a ) || a < 0 || a > 1 ) { 19619 a = 1; 19620 } 19621 19622 return a; 19623 } 19624 19625 // Check to see if string passed in is a percentage 19626 function isPercentage( n ) { 19627 return typeof n === 'string' && n.indexOf( '%' ) !== -1; 19628 } 19629 19630 // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 19631 // <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0> 19632 function isOnePointZero( n ) { 19633 return typeof n === 'string' && n.indexOf( '.' ) !== -1 && parseFloat( n ) === 1; 19634 } 19635 19636 // Take input from [0, n] and return it as [0, 1] 19637 function bound01( n, max ) { 19638 var processPercent; 19639 if ( isOnePointZero( n ) ) { 19640 n = '100%'; 19641 } 19642 19643 processPercent = isPercentage( n ); 19644 n = mathMin( max, mathMax( 0, parseFloat( n ) ) ); 19645 19646 // Automatically convert percentage into number 19647 if ( processPercent ) { 19648 n = parseInt( n * max, 10 ) / 100; 19649 } 19650 19651 // Handle floating point rounding errors 19652 if ( Math.abs( n - max ) < 0.000001 ) { 19653 return 1; 19654 } 19655 19656 // Convert into [0, 1] range if it isn't already 19657 return ( n % max ) / parseFloat( max ); 19658 } 19659 19660 // Force a number between 0 and 1 19661 function clamp01( val ) { 19662 return mathMin( 1, mathMax( 0, val ) ); 19663 } 19664 19665 // Force a hex value to have 2 characters 19666 function pad2( c ) { 19667 return c.length === 1 ? '0' + c : '' + c; 19668 } 19669 19670 // Replace a decimal with it's percentage value 19671 function convertToPercentage( n ) { 19672 if ( n <= 1 ) { 19673 n = ( n * 100 ) + '%'; 19674 } 19675 19676 return n; 19677 } 19678 19679 // Converts a decimal to a hex value 19680 function convertDecimalToHex( d ) { 19681 return Math.round( parseFloat( d ) * 255 ).toString( 16 ); 19682 } 19683 19684 // Conversion Functions 19685 // -------------------- 19686 19687 // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: 19688 // <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript> 19689 19690 // `rgbToRgb` 19691 // Handle bounds / percentage checking to conform to CSS color spec 19692 // <http://www.w3.org/TR/css3-color/> 19693 // *Assumes:* r, g, b in [0, 255] or [0, 1] 19694 // *Returns:* { r, g, b } in [0, 255] 19695 function rgbToRgb( r, g, b ) { 19696 return { 19697 r: bound01( r, 255 ) * 255, 19698 g: bound01( g, 255 ) * 255, 19699 b: bound01( b, 255 ) * 255 19700 }; 19701 } 19702 19703 // `rgbToHsl` 19704 // Converts an RGB color value to HSL. 19705 // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] 19706 // *Returns:* { h, s, l } in [0,1] 19707 function rgbToHsl( r, g, b ) { 19708 var max; 19709 var min; 19710 var h; 19711 var s; 19712 var l; 19713 var d; 19714 19715 r = bound01( r, 255 ); 19716 g = bound01( g, 255 ); 19717 b = bound01( b, 255 ); 19718 19719 max = mathMax( r, g, b ); 19720 min = mathMin( r, g, b ); 19721 l = ( max + min ) / 2; 19722 19723 if ( max === min ) { 19724 h = s = 0; // achromatic 19725 } else { 19726 d = max - min; 19727 s = l > 0.5 ? d / ( 2 - max - min ) : d / ( max + min ); 19728 switch ( max ) { 19729 case r: 19730 h = ( ( g - b ) / d ) + ( g < b ? 6 : 0 ); 19731 break; 19732 case g: 19733 h = ( ( b - r ) / d ) + 2; 19734 break; 19735 case b: 19736 h = ( ( r - g ) / d ) + 4; 19737 break; 19738 } 19739 19740 h /= 6; 19741 } 19742 19743 return { h: h, s: s, l: l }; 19744 } 19745 19746 // `hslToRgb` 19747 // Converts an HSL color value to RGB. 19748 // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] 19749 // *Returns:* { r, g, b } in the set [0, 255] 19750 function hslToRgb( h, s, l ) { 19751 var r; 19752 var g; 19753 var b; 19754 var q; 19755 var p; 19756 19757 h = bound01( h, 360 ); 19758 s = bound01( s, 100 ); 19759 l = bound01( l, 100 ); 19760 19761 function hue2rgb( pp, qq, t ) { 19762 if ( t < 0 ) { 19763 t += 1; 19764 } 19765 if ( t > 1 ) { 19766 t -= 1; 19767 } 19768 if ( t < 1 / 6 ) { 19769 return pp + ( ( qq - pp ) * 6 * t ); 19770 } 19771 if ( t < 1 / 2 ) { 19772 return qq; 19773 } 19774 if ( t < 2 / 3 ) { 19775 return pp + ( ( qq - pp ) * ( ( 2 / 3 ) - t ) * 6 ); 19776 } 19777 return pp; 19778 } 19779 19780 if ( s === 0 ) { 19781 r = g = b = l; // achromatic 19782 } else { 19783 q = l < 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); 19784 p = ( 2 * l ) - q; 19785 r = hue2rgb( p, q, h + ( 1 / 3 ) ); 19786 g = hue2rgb( p, q, h ); 19787 b = hue2rgb( p, q, h - ( 1 / 3 ) ); 19788 } 19789 19790 return { r: r * 255, g: g * 255, b: b * 255 }; 19791 } 19792 19793 // `rgbToHsv` 19794 // Converts an RGB color value to HSV 19795 // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] 19796 // *Returns:* { h, s, v } in [0,1] 19797 function rgbToHsv( r, g, b ) { 19798 var max; 19799 var min; 19800 var h; 19801 var s; 19802 var v; 19803 var d; 19804 19805 r = bound01( r, 255 ); 19806 g = bound01( g, 255 ); 19807 b = bound01( b, 255 ); 19808 19809 max = mathMax( r, g, b ); 19810 min = mathMin( r, g, b ); 19811 v = max; 19812 19813 d = max - min; 19814 s = max === 0 ? 0 : d / max; 19815 19816 if ( max === min ) { 19817 h = 0; // achromatic 19818 } else { 19819 switch ( max ) { 19820 case r: 19821 h = ( ( g - b ) / d ) + ( g < b ? 6 : 0 ); 19822 break; 19823 case g: 19824 h = ( ( b - r ) / d ) + 2; 19825 break; 19826 case b: 19827 h = ( ( r - g ) / d ) + 4; 19828 break; 19829 } 19830 h /= 6; 19831 } 19832 return { h: h, s: s, v: v }; 19833 } 19834 19835 // `hsvToRgb` 19836 // Converts an HSV color value to RGB. 19837 // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] 19838 // *Returns:* { r, g, b } in the set [0, 255] 19839 function hsvToRgb( h, s, v ) { 19840 var i; 19841 var f; 19842 var p; 19843 var q; 19844 var t; 19845 var mod; 19846 var r; 19847 var g; 19848 var b; 19849 19850 h = bound01( h, 360 ) * 6; 19851 s = bound01( s, 100 ); 19852 v = bound01( v, 100 ); 19853 19854 i = Math.floor( h ); 19855 f = h - i; 19856 p = v * ( 1 - s ); 19857 q = v * ( 1 - ( f * s ) ); 19858 t = v * ( 1 - ( ( 1 - f ) * s ) ); 19859 mod = i % 6; 19860 r = [ v, q, p, p, t, v ][ mod ]; 19861 g = [ t, v, v, q, p, p ][ mod ]; 19862 b = [ p, p, t, v, v, q ][ mod ]; 19863 19864 return { r: r * 255, g: g * 255, b: b * 255 }; 19865 } 19866 19867 // `rgbToHex` 19868 // Converts an RGB color to hex 19869 // Assumes r, g, and b are contained in the set [0, 255] 19870 // Returns a 3 or 6 character hex 19871 function rgbToHex( r, g, b, allow3Char ) { 19872 var hex = [ pad2( mathRound( r ).toString( 16 ) ), pad2( mathRound( g ).toString( 16 ) ), pad2( mathRound( b ).toString( 16 ) ) ]; 19873 19874 // Return a 3 character hex if possible 19875 if ( allow3Char && hex[ 0 ].charAt( 0 ) === hex[ 0 ].charAt( 1 ) && hex[ 1 ].charAt( 0 ) === hex[ 1 ].charAt( 1 ) && hex[ 2 ].charAt( 0 ) === hex[ 2 ].charAt( 1 ) ) { 19876 return hex[ 0 ].charAt( 0 ) + hex[ 1 ].charAt( 0 ) + hex[ 2 ].charAt( 0 ); 19877 } 19878 19879 return hex.join( '' ); 19880 } 19881 19882 // `rgbaToHex` 19883 // Converts an RGBA color plus alpha transparency to hex 19884 // Assumes r, g, b are contained in the set [0, 255] and 19885 // a in [0, 1]. Returns a 4 or 8 character rgba hex 19886 function rgbaToHex( r, g, b, a, allow4Char ) { 19887 var hex = [ pad2( mathRound( r ).toString( 16 ) ), pad2( mathRound( g ).toString( 16 ) ), pad2( mathRound( b ).toString( 16 ) ), pad2( convertDecimalToHex( a ) ) ]; 19888 19889 // Return a 4 character hex if possible 19890 if ( allow4Char && hex[ 0 ].charAt( 0 ) === hex[ 0 ].charAt( 1 ) && hex[ 1 ].charAt( 0 ) === hex[ 1 ].charAt( 1 ) && hex[ 2 ].charAt( 0 ) === hex[ 2 ].charAt( 1 ) && hex[ 3 ].charAt( 0 ) === hex[ 3 ].charAt( 1 ) ) { 19891 return hex[ 0 ].charAt( 0 ) + hex[ 1 ].charAt( 0 ) + hex[ 2 ].charAt( 0 ) + hex[ 3 ].charAt( 0 ); 19892 } 19893 19894 return hex.join( '' ); 19895 } 19896 19897 // `rgbaToArgbHex` 19898 // Converts an RGBA color to an ARGB Hex8 string 19899 // Rarely used, but required for "toFilter()" 19900 function rgbaToArgbHex( r, g, b, a ) { 19901 var hex = [ pad2( convertDecimalToHex( a ) ), pad2( mathRound( r ).toString( 16 ) ), pad2( mathRound( g ).toString( 16 ) ), pad2( mathRound( b ).toString( 16 ) ) ]; 19902 19903 return hex.join( '' ); 19904 } 19905 19906 // Given a string or object, convert that input to RGB
19907 // Possible string inputs: 19908 // 19909 // "red" 19910 // "#f00" or "f00" 19911 // "#ff0000" or "ff0000" 19912 // "#ff000000" or "ff000000" 19913 // "rgb 255 0 0" or "rgb (255, 0, 0)" 19914 // "rgb 1.0 0 0" or "rgb (1, 0, 0)" 19915 // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" 19916 // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" 19917 // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" 19918 // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" 19919 // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" 19920 // 19921 function inputToRGB( color ) { 19922 var rgb = { r: 0, g: 0, b: 0 }; 19923 var a = 1; 19924 var s = null; 19925 var v = null; 19926 var l = null; 19927 var ok = false; 19928 var format = false; 19929 19930 if ( typeof color === 'string' ) { 19931 color = stringInputToObject( color ); 19932 } 19933 19934 if ( typeof color === 'object' ) { 19935 if ( isValidCSSUnit( color.r ) && isValidCSSUnit( color.g ) && isValidCSSUnit( color.b ) ) { 19936 rgb = rgbToRgb( color.r, color.g, color.b ); 19937 ok = true; 19938 format = String( color.r ).substring( String( color.r ).length - 1 ) === '%' ? 'prgb' : 'rgb'; 19939 } else if ( isValidCSSUnit( color.h ) && isValidCSSUnit( color.s ) && isValidCSSUnit( color.v ) ) { 19940 s = convertToPercentage( color.s ); 19941 v = convertToPercentage( color.v ); 19942 rgb = hsvToRgb( color.h, s, v ); 19943 ok = true; 19944 format = 'hsv'; 19945 } else if ( isValidCSSUnit( color.h ) && isValidCSSUnit( color.s ) && isValidCSSUnit( color.l ) ) { 19946 s = convertToPercentage( color.s ); 19947 l = convertToPercentage( color.l ); 19948 rgb = hslToRgb( color.h, s, l ); 19949 ok = true; 19950 format = 'hsl'; 19951 } 19952 19953 if ( Object.prototype.hasOwnProperty.call( color, 'a' ) ) { 19954 a = color.a; 19955 } 19956 } 19957 19958 a = boundAlpha( a ); 19959 19960 return { 19961 ok: ok, 19962 format: color.format || format, 19963 r: mathMin( 255, mathMax( rgb.r, 0 ) ), 19964 g: mathMin( 255, mathMax( rgb.g, 0 ) ), 19965 b: mathMin( 255, mathMax( rgb.b, 0 ) ), 19966 a: a 19967 }; 19968 } 19969 19970 function TinyColor( color, opts ) { 19971 var rgb; 19972 color = color ? color : ''; 19973 opts = opts || {}; 19974 19975 // If input is already a TinyColor, return itself 19976 if ( color instanceof TinyColor ) { 19977 return color; 19978 } 19979 // If we are called as a function, call using new instead 19980 if ( ! ( this instanceof TinyColor ) ) { 19981 return new TinyColor( color, opts ); 19982 } 19983 19984 rgb = inputToRGB( color ); 19985 this._originalInput = color; 19986 this._r = rgb.r; 19987 this._g = rgb.g; 19988 this._b = rgb.b; 19989 this._a = rgb.a; 19990 this._roundA = mathRound( 100 * this._a ) / 100; 19991 if ( opts.format ) { 19992 this._format = opts.format; 19993 } else { 19994 this._format = rgb.format; 19995 } 19996 19997 this._gradientType = opts.gradientType; 19998 19999 // Don't let the range of [0,255] come back in [0,1]. 20000 // Potentially lose a little bit of precision here, but will fix issues where 20001 // .5 gets interpreted as half of the total, instead of half of 1 20002 // If it was supposed to be 128, this was already taken care of by `inputToRgb` 20003 if ( this._r < 1 ) { 20004 this._r = mathRound( this._r ); 20005 } 20006 if ( this._g < 1 ) { 20007 this._g = mathRound( this._g ); 20008 } 20009 if ( this._b < 1 ) { 20010 this._b = mathRound( this._b ); 20011 } 20012 20013 this._ok = rgb.ok; 20014 tinyCounter = tinyCounter + 1; 20015 this._tc_id = tinyCounter; 20016 } 20017 20018 function newTinyColor( color, opts ) { 20019 return new TinyColor( color, opts ); 20020 } 20021 20022 // Modification Functions 20023 // ---------------------- 20024 // Thanks to less.js for some of the basics here 20025 // <https://github.com/cloudhead/less.js/blob/master/lib/less/functions.js> 20026 20027 function desaturate( color, amount ) { 20028 var hsl; 20029 amount = amount === 0 ? 0 : amount || 10; 20030 hsl = newTinyColor( color ).toHsl(); 20031 hsl.s -= amount / 100; 20032 hsl.s = clamp01( hsl.s ); 20033 return newTinyColor( hsl ); 20034 } 20035 20036 function saturate( color, amount ) { 20037 var hsl; 20038 amount = amount === 0 ? 0 : amount || 10; 20039 hsl = newTinyColor( color ).toHsl(); 20040 hsl.s += amount / 100; 20041 hsl.s = clamp01( hsl.s ); 20042 return newTinyColor( hsl ); 20043 } 20044 20045 function greyscale( color ) { 20046 return newTinyColor( color ).desaturate( 100 ); 20047 } 20048 20049 function lighten( color, amount ) { 20050 var hsl; 20051 amount = amount === 0 ? 0 : amount || 10; 20052 hsl = newTinyColor( color ).toHsl(); 20053 hsl.l += amount / 100; 20054 hsl.l = clamp01( hsl.l ); 20055 return newTinyColor( hsl ); 20056 } 20057 20058 function brighten( color, amount ) { 20059 var rgb; 20060 amount = amount === 0 ? 0 : amount || 10; 20061 rgb = newTinyColor( color ).toRgb(); 20062 rgb.r = mathMax( 0, mathMin( 255, rgb.r - mathRound( 255 * -( amount / 100 ) ) ) ); 20063 rgb.g = mathMax( 0, mathMin( 255, rgb.g - mathRound( 255 * -( amount / 100 ) ) ) ); 20064 rgb.b = mathMax( 0, mathMin( 255, rgb.b - mathRound( 255 * -( amount / 100 ) ) ) ); 20065 return newTinyColor( rgb ); 20066 } 20067 20068 function darken( color, amount ) { 20069 var hsl; 20070 amount = amount === 0 ? 0 : amount || 10; 20071 hsl = newTinyColor( color ).toHsl(); 20072 hsl.l -= amount / 100; 20073 hsl.l = clamp01( hsl.l ); 20074 return newTinyColor( hsl ); 20075 } 20076 20077 // Spin takes a positive or negative amount within [-360, 360] indicating the change of hue. 20078 // Values outside of this range will be wrapped into this range. 20079 function spin( color, amount ) { 20080 var hsl = newTinyColor( color ).toHsl(); 20081 var hue = ( hsl.h + amount ) % 360; 20082 hsl.h = hue < 0 ? 360 + hue : hue; 20083 return newTinyColor( hsl ); 20084 } 20085 20086 // Combination Functions 20087 // --------------------- 20088 // Thanks to jQuery xColor for some of the ideas behind these 20089 // <https://github.com/infusion/jQuery-xcolor/blob/master/jquery.xcolor.js> 20090 20091 function complement( color ) { 20092 var hsl = newTinyColor( color ).toHsl(); 20093 hsl.h = ( hsl.h + 180 ) % 360; 20094 return newTinyColor( hsl ); 20095 } 20096 20097 function triad( color ) { 20098 var hsl = newTinyColor( color ).toHsl();
vendor: 5,466 bytes, lines 20099-20265
20099 var h = hsl.h; 20100 return [ newTinyColor( color ), newTinyColor( { h: ( h + 120 ) % 360, s: hsl.s, l: hsl.l } ), newTinyColor( { h: ( h + 240 ) % 360, s: hsl.s, l: hsl.l } ) ]; 20101 } 20102 20103 function tetrad( color ) { 20104 var hsl = newTinyColor( color ).toHsl(); 20105 var h = hsl.h; 20106 return [ newTinyColor( color ), newTinyColor( { h: ( h + 90 ) % 360, s: hsl.s, l: hsl.l } ), newTinyColor( { h: ( h + 180 ) % 360, s: hsl.s, l: hsl.l } ), newTinyColor( { h: ( h + 270 ) % 360, s: hsl.s, l: hsl.l } ) ]; 20107 } 20108 20109 function splitcomplement( color ) { 20110 var hsl = newTinyColor( color ).toHsl(); 20111 var h = hsl.h; 20112 return [ newTinyColor( color ), newTinyColor( { h: ( h + 72 ) % 360, s: hsl.s, l: hsl.l } ), newTinyColor( { h: ( h + 216 ) % 360, s: hsl.s, l: hsl.l } ) ]; 20113 } 20114 20115 /*function analogous(color, results, slices) { 20116 results = results || 6; 20117 slices = slices || 30; 20118 20119 var hsl = newTinyColor(color).toHsl(); 20120 var part = 360 / slices; 20121 var ret = [newTinyColor(color)]; 20122 20123 for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results;) { 20124 hsl.h = (hsl.h + part) % 360; 20125 ret.push(newTinyColor(hsl)); 20126 } 20127 return ret; 20128 } 20129 20130 function monochromatic(color, results) { 20131 var hsv; 20132 var h; 20133 var s; 20134 var v; 20135 var ret; 20136 var modification; 20137 results = results || 6; 20138 hsv = newTinyColor(color).toHsv(); 20139 h = hsv.h; 20140 s = hsv.s; 20141 v = hsv.v; 20142 ret = []; 20143 modification = 1 / results; 20144 20145 while (results--) { 20146 ret.push(newTinyColor({h: h, s: s, v: v})); 20147 v = (v + modification) % 1; 20148 } 20149 20150 return ret; 20151 }*/ 20152 20153 TinyColor.prototype = { 20154 isDark: function() { 20155 return this.getBrightness() < 128; 20156 }, 20157 isLight: function() { 20158 return ! this.isDark(); 20159 }, 20160 isValid: function() { 20161 return this._ok; 20162 }, 20163 getOriginalInput: function() { 20164 return this._originalInput; 20165 }, 20166 getFormat: function() { 20167 return this._format; 20168 }, 20169 getAlpha: function() { 20170 return this._a; 20171 }, 20172 getBrightness: function() { 20173 //http://www.w3.org/TR/AERT#color-contrast 20174 var rgb = this.toRgb(); 20175 return ( ( rgb.r * 299 ) + ( rgb.g * 587 ) + ( rgb.b * 114 ) ) / 1000; 20176 }, 20177 getLuminance: function() { 20178 //http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef 20179 var rgb = this.toRgb(); 20180 var RsRGB, GsRGB, BsRGB, R, G, B; 20181 RsRGB = rgb.r / 255; 20182 GsRGB = rgb.g / 255; 20183 BsRGB = rgb.b / 255; 20184 20185 if ( RsRGB <= 0.03928 ) { 20186 R = RsRGB / 12.92; 20187 } else { 20188 R = Math.pow( ( RsRGB + 0.055 ) / 1.055, 2.4 ); 20189 } 20190 if ( GsRGB <= 0.03928 ) { 20191 G = GsRGB / 12.92; 20192 } else { 20193 G = Math.pow( ( GsRGB + 0.055 ) / 1.055, 2.4 ); 20194 } 20195 if ( BsRGB <= 0.03928 ) { 20196 B = BsRGB / 12.92; 20197 } else { 20198 B = Math.pow( ( BsRGB + 0.055 ) / 1.055, 2.4 ); 20199 } 20200 return ( 0.2126 * R ) + ( 0.7152 * G ) + ( 0.0722 * B ); 20201 }, 20202 setAlpha: function( value ) { 20203 this._a = boundAlpha( value ); 20204 this._roundA = mathRound( 100 * this._a ) / 100; 20205 return this; 20206 }, 20207 toHsv: function() { 20208 var hsv = rgbToHsv( this._r, this._g, this._b ); 20209 return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: this._a }; 20210 }, 20211 toHsvString: function() { 20212 var hsv = rgbToHsv( this._r, this._g, this._b ); 20213 var h = mathRound( hsv.h * 360 ), 20214 s = mathRound( hsv.s * 100 ), 20215 v = mathRound( hsv.v * 100 ); 20216 return this._a === 1 ? 'hsv(' + h + ', ' + s + '%, ' + v + '%)' : 'hsva(' + h + ', ' + s + '%, ' + v + '%, ' + this._roundA + ')'; 20217 }, 20218 toHsl: function() { 20219 var hsl = rgbToHsl( this._r, this._g, this._b ); 20220 return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: this._a }; 20221 }, 20222 toHslString: function() { 20223 var hsl = rgbToHsl( this._r, this._g, this._b ); 20224 var h = mathRound( hsl.h * 360 ), 20225 s = mathRound( hsl.s * 100 ), 20226 l = mathRound( hsl.l * 100 ); 20227 return this._a === 1 ? 'hsl(' + h + ', ' + s + '%, ' + l + '%)' : 'hsla(' + h + ', ' + s + '%, ' + l + '%, ' + this._roundA + ')'; 20228 }, 20229 toHex: function( allow3Char ) { 20230 return rgbToHex( this._r, this._g, this._b, allow3Char ); 20231 }, 20232 toHexString: function( allow3Char ) { 20233 return '#' + this.toHex( allow3Char ); 20234 }, 20235 toHex8: function( allow4Char ) { 20236 return rgbaToHex( this._r, this._g, this._b, this._a, allow4Char ); 20237 }, 20238 toHex8String: function( allow4Char ) { 20239 return '#' + this.toHex8( allow4Char ); 20240 }, 20241 toRgb: function() { 20242 return { r: mathRound( this._r ), g: mathRound( this._g ), b: mathRound( this._b ), a: this._a }; 20243 }, 20244 toRgbString: function() { 20245 return this._a === 1 ? 'rgb(' + mathRound( this._r ) + ', ' + mathRound( this._g ) + ', ' + mathRound( this._b ) + ')' : 'rgba(' + mathRound( this._r ) + ', ' + mathRound( this._g ) + ', ' + mathRound( this._b ) + ', ' + this._roundA + ')'; 20246 }, 20247 toPercentageRgb: function() { 20248 return { 20249 r: mathRound( bound01( this._r, 255 ) * 100 ) + '%', 20250 g: mathRound( bound01( this._g, 255 ) * 100 ) + '%', 20251 b: mathRound( bound01( this._b, 255 ) * 100 ) + '%', 20252 a: this._a 20253 }; 20254 }, 20255 toPercentageRgbString: function() { 20256 return this._a === 1 ? 'rgb(' + mathRound( bound01( this._r, 255 ) * 100 ) + '%, ' + mathRound( bound01( this._g, 255 ) * 100 ) + '%, ' + mathRound( bound01( this._b, 255 ) * 100 ) + '%)' 20257 : 'rgba(' + mathRound( bound01( this._r, 255 ) * 100 ) + '%, ' + mathRound( bound01( this._g, 255 ) * 100 ) + '%, ' + mathRound( bound01( this._b, 255 ) * 100 ) + '%, ' + this._roundA + ')'; 20258 }, 20259 toName: function() { 20260 if ( this._a === 0 ) { 20261 return 'transparent'; 20262 } 20263 20264 if ( this._a < 1 ) { 20265 return false;
20266 } 20267 20268 return hexNames[ rgbToHex( this._r, this._g, this._b, true ) ] || false; 20269 }, 20270 toFilter: function( secondColor ) { 20271 var hex8String = '#' + rgbaToArgbHex( this._r, this._g, this._b, this._a ); 20272 var secondHex8String = hex8String; 20273 var gradientType = this._gradientType ? 'GradientType = 1, ' : ''; 20274 var s; 20275 if ( secondColor ) { 20276 s = newTinyColor( secondColor ); 20277 secondHex8String = '#' + rgbaToArgbHex( s._r, s._g, s._b, s._a ); 20278 } 20279 20280 return 'progid:DXImageTransform.Microsoft.gradient(' + gradientType + 'startColorstr=' + hex8String + ',endColorstr=' + secondHex8String + ')'; 20281 }, 20282 toString: function( format ) { 20283 var formatSet = !! format; 20284 var formattedString; 20285 var hasAlpha; 20286 var needsAlphaFormat; 20287 format = format || this._format; 20288 20289 formattedString = false; 20290 hasAlpha = this._a < 1 && this._a >= 0; 20291 needsAlphaFormat = ! formatSet && hasAlpha && ( format === 'hex' || format === 'hex6' || format === 'hex3' || format === 'hex4' || format === 'hex8' || format === 'name' ); 20292 20293 if ( needsAlphaFormat ) { 20294 // Special case for "transparent", all other non-alpha formats 20295 // will return rgba when there is transparency. 20296 if ( format === 'name' && this._a === 0 ) { 20297 return this.toName(); 20298 } 20299 return this.toRgbString(); 20300 } 20301 if ( format === 'rgb' ) { 20302 formattedString = this.toRgbString(); 20303 } 20304 if ( format === 'prgb' ) { 20305 formattedString = this.toPercentageRgbString(); 20306 } 20307 if ( format === 'hex' || format === 'hex6' ) { 20308 formattedString = this.toHexString(); 20309 } 20310 if ( format === 'hex3' ) { 20311 formattedString = this.toHexString( true ); 20312 } 20313 if ( format === 'hex4' ) { 20314 formattedString = this.toHex8String( true ); 20315 } 20316 if ( format === 'hex8' ) { 20317 formattedString = this.toHex8String(); 20318 } 20319 if ( format === 'name' ) { 20320 formattedString = this.toName(); 20321 } 20322 if ( format === 'hsl' ) { 20323 formattedString = this.toHslString(); 20324 } 20325 if ( format === 'hsv' ) { 20326 formattedString = this.toHsvString(); 20327 } 20328 20329 return formattedString || this.toHexString(); 20330 }, 20331 clone: function() { 20332 return newTinyColor( this.toString() ); 20333 }, 20334 20335 _applyModification: function( fn, args ) { 20336 var color = fn.apply( null, [ this ].concat( [].slice.call( args ) ) ); 20337 this._r = color._r; 20338 this._g = color._g; 20339 this._b = color._b; 20340 this.setAlpha( color._a ); 20341 return this; 20342 }, 20343 lighten: function() { 20344 return this._applyModification( lighten, arguments ); 20345 }, 20346 brighten: function() { 20347 return this._applyModification( brighten, arguments ); 20348 }, 20349 darken: function() { 20350 return this._applyModification( darken, arguments ); 20351 }, 20352 desaturate: function() { 20353 return this._applyModification( desaturate, arguments ); 20354 }, 20355 saturate: function() { 20356 return this._applyModification( saturate, arguments ); 20357 }, 20358 greyscale: function() { 20359 return this._applyModification( greyscale, arguments ); 20360 }, 20361 spin: function() { 20362 return this._applyModification( spin, arguments ); 20363 }, 20364 20365 _applyCombination: function( fn, args ) { 20366 return fn.apply( null, [ this ].concat( [].slice.call( args ) ) ); 20367 }, 20368 /*analogous: function () { 20369 return this._applyCombination(analogous, arguments); 20370 },*/ 20371 complement: function() { 20372 return this._applyCombination( complement, arguments ); 20373 }, 20374 /*monochromatic: function () { 20375 return this._applyCombination(monochromatic, arguments); 20376 },*/ 20377 splitcomplement: function() { 20378 return this._applyCombination( splitcomplement, arguments ); 20379 }, 20380 triad: function() { 20381 return this._applyCombination( triad, arguments ); 20382 }, 20383 tetrad: function() { 20384 return this._applyCombination( tetrad, arguments ); 20385 } 20386 }; 20387 20388 // If input is an object, force 1 into "1.0" to handle ratios properly 20389 // String input requires "1.0" as input, so 1 will be treated as 1 20390 TinyColor.fromRatio = function( color, opts ) { 20391 var newColor; 20392 var i; 20393 if ( typeof color === 'object' ) { 20394 newColor = {}; 20395 for ( i in color ) { 20396 if ( Object.prototype.hasOwnProperty.call( color, i ) ) { 20397 if ( i === 'a' ) { 20398 newColor[ i ] = color[ i ]; 20399 } else { 20400 newColor[ i ] = convertToPercentage( color[ i ] ); 20401 } 20402 } 20403 } 20404 color = newColor; 20405 } 20406 20407 return newTinyColor( color, opts ); 20408 }; 20409 20410 // `equals` 20411 // Can be called with any TinyColor input 20412 TinyColor.equals = function( color1, color2 ) { 20413 if ( ! color1 || ! color2 ) { 20414 return false;
20415 } 20416 return newTinyColor( color1 ).toRgbString() === newTinyColor( color2 ).toRgbString(); 20417 }; 20418 20419 TinyColor.random = function() { 20420 return TinyColor.fromRatio( { 20421 r: mathRandom(), 20422 g: mathRandom(), 20423 b: mathRandom() 20424 } ); 20425 }; 20426 20427 // Utility Functions 20428 // --------------------- 20429 20430 TinyColor.mix = function( color1, color2, amount ) { 20431 var rgb1; 20432 var rgb2; 20433 var p; 20434 var rgba; 20435 20436 amount = amount === 0 ? 0 : amount || 50; 20437 20438 rgb1 = newTinyColor( color1 ).toRgb(); 20439 rgb2 = newTinyColor( color2 ).toRgb(); 20440 20441 p = amount / 100; 20442 20443 rgba = { 20444 r: ( ( rgb2.r - rgb1.r ) * p ) + rgb1.r, 20445 g: ( ( rgb2.g - rgb1.g ) * p ) + rgb1.g, 20446 b: ( ( rgb2.b - rgb1.b ) * p ) + rgb1.b, 20447 a: ( ( rgb2.a - rgb1.a ) * p ) + rgb1.a 20448 }; 20449 20450 return newTinyColor( rgba ); 20451 }; 20452 20453 // Readability Functions 20454 // --------------------- 20455 // <http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2) 20456 20457 // `contrast` 20458 // Analyze the 2 colors and returns the color contrast defined by (WCAG Version 2) 20459 TinyColor.readability = function( color1, color2 ) { 20460 var c1 = newTinyColor( color1 ); 20461 var c2 = newTinyColor( color2 ); 20462 return ( Math.max( c1.getLuminance(), c2.getLuminance() ) + 0.05 ) / ( Math.min( c1.getLuminance(), c2.getLuminance() ) + 0.05 ); 20463 }; 20464 20465 // `isReadable` 20466 // Ensure that foreground and background color combinations meet WCAG2 guidelines. 20467 // The third argument is an optional Object. 20468 // the 'level' property states 'AA' or 'AAA' - if missing or invalid, it defaults to 'AA'; 20469 // the 'size' property states 'large' or 'small' - if missing or invalid, it defaults to 'small'. 20470 // If the entire object is absent, isReadable defaults to {level:"AA",size:"small"}. 20471 20472 // *Example* 20473 // TinyColor.isReadable("#000", "#111") => false 20474 // TinyColor.isReadable("#000", "#111",{level:"AA",size:"large"}) => false 20475 TinyColor.isReadable = function( color1, color2, wcag2 ) { 20476 var readability = TinyColor.readability( color1, color2 ); 20477 var wcag2Parms, out; 20478 20479 out = false; 20480 20481 wcag2Parms = validateWCAG2Parms( wcag2 ); 20482 switch ( wcag2Parms.level + wcag2Parms.size ) { 20483 case 'AAsmall': 20484 case 'AAAlarge': 20485 out = readability >= 4.5; 20486 break; 20487 case 'AAlarge': 20488 out = readability >= 3; 20489 break; 20490 case 'AAAsmall': 20491 out = readability >= 7; 20492 break; 20493 } 20494 return out; 20495 }; 20496 20497 // `mostReadable` 20498 // Given a base color and a list of possible foreground or background 20499 // colors for that base, returns the most readable color. 20500 // Optionally returns Black or White if the most readable color is unreadable. 20501 // *Example* 20502 // TinyColor.mostReadable(TinyColor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:false}).toHexString(); // "#112255" 20503 // TinyColor.mostReadable(TinyColor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:true}).toHexString(); // "#ffffff" 20504 // TinyColor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"large"}).toHexString(); // "#faf3f3" 20505 // TinyColor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"small"}).toHexString(); // "#ffffff" 20506 TinyColor.mostReadable = function( baseColor, colorList, args ) { 20507 var bestColor = null; 20508 var bestScore = 0; 20509 var readability; 20510 var includeFallbackColors; 20511 var level; 20512 var size; 20513 var i; 20514 args = args || {}; 20515 includeFallbackColors = args.includeFallbackColors; 20516 level = args.level; 20517 size = args.size; 20518 20519 for ( i = 0; i < colorList.length; i += 1 ) { 20520 readability = TinyColor.readability( baseColor, colorList[ i ] ); 20521 if ( readability > bestScore ) { 20522 bestScore = readability; 20523 bestColor = newTinyColor( colorList[ i ] ); 20524 } 20525 } 20526 20527 if ( TinyColor.isReadable( baseColor, bestColor, { level: level, size: size } ) || ! includeFallbackColors ) { 20528 return bestColor; 20529 } 20530 args.includeFallbackColors = false; 20531 return TinyColor.mostReadable( baseColor, [ '#fff', '#000' ], args ); 20532 }; 20533 20534 // Big List of Colors 20535 // ------------------ 20536 // <http://www.w3.org/TR/css3-color/#svg-color> 20537 TinyColor.names = names; 20538 20539 // Make it easy to access colors via `hexNames[hex]` 20540 TinyColor.hexNames = hexNames; 20541 20542 // Node: Export function 20543 if ( typeof window.module !== 'undefined' && window.module.exports ) { 20544 window.module.exports = TinyColor; 20545 } else if ( typeof window.define === 'function' && window.define.amd ) { // AMD/requirejs: Define the module 20546 window.define( function() { 20547 return TinyColor; 20548 } ); 20549 } else { // Browser: Expose to window 20550 window.tinycolor = TinyColor; 20551 } 20552}( Math ) ); 20553 20554// Spectrum Colorpicker v2.0.10 20555// https://github.com/seballot/spectrum 20556// Author: Brian Grinstead 20557// License: MIT 20558 20559( function( factory ) { 20560 'use strict'; 20561 20562 if ( typeof window.define === 'function' && window.define.amd ) { 20563 // AMD 20564 window.define( [ 'jquery' ], factory ); 20565 } else if ( typeof exports === 'object' && typeof module === 'object' ) { 20566 // CommonJS 20567 window.module.exports = factory( window.require( 'jquery' ) ); 20568 } else { 20569 // Browser 20570 factory( window.jQuery ); 20571 } 20572}( function( $ ) { 20573 'use strict'; 20574 20575 var dataID = 'spectrum.id'; 20576 var tinycolor = window.tinycolor; 20577 var defaultOpts = { 20578 // Callbacks 20579 beforeShow: noop, 20580 move: noop, 20581 change: noop, 20582 show: noop, 20583 hide: noop, 20584 20585 // Options 20586 color: false, 20587 flat: false, // Deprecated - use type instead 20588 type: 'color', // text, color, component or flat 20589 showInput: false, 20590 allowEmpty: false, 20591 showButtons: true, 20592 clickoutFiresChange: true, 20593 showInitial: false, 20594 showPalette: false, 20595 showPaletteOnly: false, 20596 hideAfterPaletteSelect: false, 20597 togglePaletteOnly: false, 20598 showSelectionPalette: true, 20599 localStorageKey: false, 20600 appendTo: 'body', 20601 maxSelectionSize: 8, 20602 locale: 'en', 20603 cancelText: 'cancel', 20604 chooseText: 'choose', 20605 togglePaletteMoreText: 'more', 20606 togglePaletteLessText: 'less',
20607 clearText: 'Clear Color Selection', 20608 preferredFormat: 'hex', 20609 className: '', // Deprecated - use containerClassName and replacerClassName instead. 20610 containerClassName: '', 20611 replacerClassName: '', 20612 showAlpha: false, 20613 theme: 'epo', 20614 palette: [ 20615 [ '#000000', '#444444', '#5b5b5b', '#999999', '#bcbcbc', '#eeeeee', '#f3f6f4', '#ffffff' ], 20616 [ '#f44336', '#744700', '#ce7e00', '#8fce00', '#2986cc', '#16537e', '#6a329f', '#c90076' ], 20617 [ '#f4cccc', '#fce5cd', '#fff2cc', '#d9ead3', '#d0e0e3', '#cfe2f3', '#d9d2e9', '#ead1dc' ], 20618 [ '#ea9999', '#f9cb9c', '#ffe599', '#b6d7a8', '#a2c4c9', '#9fc5e8', '#b4a7d6', '#d5a6bd' ], 20619 [ '#e06666', '#f6b26b', '#ffd966', '#93c47d', '#76a5af', '#6fa8dc', '#8e7cc3', '#c27ba0' ], 20620 [ '#cc0000', '#e69138', '#f1c232', '#6aa84f', '#45818e', '#3d85c6', '#674ea7', '#a64d79' ], 20621 [ '#990000', '#b45f06', '#bf9000', '#38761d', '#134f5c', '#0b5394', '#351c75', '#741b47' ], 20622 [ '#660000', '#783f04', '#7f6000', '#274e13', '#0c343d', '#073763', '#20124d', '#4c1130' ] 20623 ], 20624 selectionPalette: [], 20625 disabled: false, 20626 offset: null 20627 }, 20628 spectrums = [], 20629 IE = !! /msie/i.exec( window.navigator.userAgent ), 20630 rgbaSupport = ( function() { 20631 var contains = function( str, substr ) { 20632 return ( '' + str ).indexOf( substr ) !== 1; 20633 }; 20634 var elem = document.createElement( 'div' ); 20635 var style = elem.style; 20636 style.cssText = 'background-color:rgba(0,0,0,.5)'; 20637 return contains( style.backgroundColor, 'rgba' ) || contains( style.backgroundColor, 'hsla' ); 20638 }() ), 20639 replaceInput = [ 20640 '<button type="button" class="sp-replacer">', 20641 '<span class="sp-preview"><span class="sp-preview-inner"></span></span>', 20642 '<span class="sp-dd">▼</span>', 20643 '</button>' 20644 ].join( '' ), 20645 markup = ( function() { 20646 var i; 20647 // IE does not support gradients with multiple stops, so we need to simulate 20648 // that for the rainbow slider with 8 divs that each have a single gradient 20649 var gradientFix = ''; 20650 if ( IE ) { 20651 for ( i = 1; i <= 6; i++ ) { 20652 gradientFix += "<div class='sp-" + i + "'></div>"; 20653 } 20654 } 20655 20656 return [ 20657 "<div class='sp-container sp-hidden'>", 20658 "<div class='sp-palette-container'>", 20659 "<div class='sp-palette sp-thumb sp-cf'></div>", 20660 "<div class='sp-palette-button-container sp-cf'>", 20661 "<button type='button' class='sp-palette-toggle'></button>", 20662 '</div>', 20663 '</div>', 20664 "<div class='sp-picker-container'>", 20665 "<div class='sp-top sp-cf'>", 20666 "<div class='sp-fill'></div>", 20667 "<div class='sp-top-inner'>", 20668 "<div class='sp-color'>", 20669 "<div class='sp-sat'>", 20670 "<div class='sp-val'>", 20671 "<div class='sp-dragger' tabindex='0'></div>", 20672 '</div>', 20673 '</div>', 20674 '</div>', 20675 "<div class='sp-clear sp-clear-display'>", 20676 '</div>', 20677 "<div class='sp-hue'>", 20678 "<div class='sp-slider' tabindex='0'></div>", 20679 gradientFix, 20680 '</div>', 20681 '</div>', 20682 "<div class='sp-alpha'><div class='sp-alpha-inner'><div class='sp-alpha-handle' tabindex='0'></div></div></div>", 20683 '</div>', 20684 "<div class='sp-input-container sp-cf'>", 20685 "<input class='sp-input' type='text' spellcheck='false'>", 20686 '</div>', 20687 "<div class='sp-initial sp-thumb sp-cf'></div>", 20688 "<div class='sp-button-container sp-cf'>", 20689 "<button type='button' class='sp-cancel'></button>", 20690 "<button type='button' class='sp-choose'></button>", 20691 '</div>', 20692 '</div>', 20693 '</div>' 20694 ].join( '' ); 20695 }() ); 20696 20697 function paletteTemplate( p, color, className, opts ) { 20698 var html = []; 20699 var i; 20700 var current; 20701 var tiny; 20702 var c; 20703 var formattedString; 20704 var swatchStyle; 20705 for ( i = 0; i < p.length; i++ ) { 20706 current = p[ i ]; 20707 if ( current ) { 20708 tiny = tinycolor( current ); 20709 c = tiny.toHsl().l < 0.5 ? 'sp-thumb-el sp-thumb-dark' : 'sp-thumb-el sp-thumb-light'; 20710 c += tinycolor.equals( color, current ) ? ' sp-thumb-active' : ''; 20711 formattedString = tiny.toString( opts.preferredFormat || 'rgb' ); 20712 swatchStyle = rgbaSupport ? 'background-color:' + tiny.toRgbString() : 'filter:' + tiny.toFilter(); 20713 html.push( '<span title="' + formattedString + '" data-color="' + tiny.toRgbString() + '" class="' + c + '" role="button" tabindex="0"><span class="sp-thumb-inner" style="' + swatchStyle + ';"></span></span>' ); 20714 } else { 20715 html.push( '<span class="sp-thumb-el sp-clear-display" role="button" tabindex="0"><span class="sp-clear-palette-only" style="background-color: transparent;"></span></span>' ); 20716 } 20717 } 20718 return "<div class='sp-cf " + className + "'>" + html.join( '' ) + '</div>'; 20719 } 20720 20721 function hideAll() { 20722 var i; 20723 for ( i = 0; i < spectrums.length; i++ ) { 20724 if ( spectrums[ i ] ) { 20725 spectrums[ i ].hide(); 20726 } 20727 } 20728 } 20729 20730 function instanceOptions( o, callbackContext ) { 20731 var opts; 20732 o.locale = o.locale || window.navigator.language; 20733 if ( o.locale ) { 20734 o.locale = o.locale.split( '-' )[ 0 ].toLowerCase(); 20735 } // handle locale like "fr-FR" 20736 if ( o.locale !== 'en' && $.spectrum.localization[ o.locale ] ) { 20737 o = $.extend( {}, $.spectrum.localization[ o.locale ], o ); 20738 } 20739 opts = $.extend( {}, defaultOpts, o ); 20740 20741 opts.callbacks = { 20742 move: bind( opts.move, callbackContext ), 20743 change: bind( opts.change, callbackContext ), 20744 show: bind( opts.show, callbackContext ), 20745 hide: bind( opts.hide, callbackContext ), 20746 beforeShow: bind( opts.beforeShow, callbackContext ) 20747 }; 20748 20749 return opts; 20750 } 20751 20752 function spectrum( element, o ) { 20753 var spect; 20754 20755 var opts = instanceOptions( o, element ), 20756 type = opts.type, 20757 flat = type === 'flat', 20758 showSelectionPalette = opts.showSelectionPalette, 20759 localStorageKey = opts.localStorageKey, 20760 theme = opts.theme, 20761 callbacks = opts.callbacks, 20762 resize = throttle( reflow, 10 ), 20763 visible = false, 20764 isDragging = false, 20765 dragWidth = 0, 20766 dragHeight = 0,
20767 dragHelperHeight = 0, 20768 slideHeight = 0, 20769 alphaWidth = 0, 20770 alphaSlideHelperWidth = 0, 20771 slideHelperHeight = 0, 20772 currentHue = 0, 20773 currentSaturation = 0, 20774 currentValue = 0, 20775 currentAlpha = 1, 20776 palette = [], 20777 paletteArray = [], 20778 paletteLookup = {}, 20779 selectionPalette = opts.selectionPalette.slice( 0 ), 20780 maxSelectionSize = opts.maxSelectionSize, 20781 draggingClass = 'sp-dragging', 20782 abortNextInputChange = false, 20783 shiftMovementDirection = null; 20784 20785 var doc = element.ownerDocument, 20786 boundElement = $( element ), 20787 disabled = false, 20788 container = $( markup, doc ).addClass( theme ), 20789 pickerContainer = container.find( '.sp-picker-container' ), 20790 dragger = container.find( '.sp-color' ), 20791 dragHelper = container.find( '.sp-dragger' ), 20792 slider = container.find( '.sp-hue' ), 20793 slideHelper = container.find( '.sp-slider' ), 20794 alphaSliderInner = container.find( '.sp-alpha-inner' ), 20795 alphaSlider = container.find( '.sp-alpha' ), 20796 alphaSlideHelper = container.find( '.sp-alpha-handle' ), 20797 textInput = container.find( '.sp-input' ), 20798 paletteContainer = container.find( '.sp-palette' ), 20799 initialColorContainer = container.find( '.sp-initial' ), 20800 cancelButton = container.find( '.sp-cancel' ), 20801 clearButton = container.find( '.sp-clear' ), 20802 chooseButton = container.find( '.sp-choose' ), 20803 toggleButton = container.find( '.sp-palette-toggle' ), 20804 isInput = boundElement.is( 'input' ), 20805 shouldReplace = isInput && type === 'color', 20806 replacer = shouldReplace ? $( replaceInput ).addClass( theme ).addClass( opts.className ).addClass( opts.replacerClassName ) : $( [] ), 20807 offsetElement = shouldReplace ? replacer : boundElement, 20808 previewElement = replacer.find( '.sp-preview-inner' ), 20809 initialColor = opts.color || ( isInput && boundElement.val() ), 20810 colorOnShow = false, 20811 currentPreferredFormat = opts.preferredFormat, 20812 clickoutFiresChange = ! opts.showButtons || opts.clickoutFiresChange, 20813 isEmpty = ! initialColor, 20814 allowEmpty = opts.allowEmpty; 20815 20816 // Element to be updated with the input color. Populated in initialize method 20817 var originalInputContainer = null, 20818 colorizeElement = null, 20819 colorizeElementInitialColor = null, 20820 colorizeElementInitialBackground = null; 20821 20822 //If there is a label for this element, when clicked on, show the colour picker 20823 var thisId = boundElement.attr( 'id' ); 20824 var label; 20825 20826 if ( thisId !== undefined && thisId.length > 0 ) { 20827 label = $( 'label[for="' + thisId + '"]' ); 20828 if ( label.length ) { 20829 label.on( 'click', function( e ) { 20830 e.preventDefault(); 20831 boundElement.spectrum( 'show' ); 20832 return false; 20833 } ); 20834 } 20835 } 20836 20837 function applyOptions() { 20838 var i; 20839 var j; 20840 var rgb; 20841 20842 if ( opts.showPaletteOnly ) { 20843 opts.showPalette = true; 20844 } 20845 20846 toggleButton.text( opts.showPaletteOnly ? opts.togglePaletteMoreText : opts.togglePaletteLessText ); 20847 20848 if ( opts.palette ) { 20849 palette = opts.palette.slice( 0 ); 20850 paletteArray = Array.isArray( palette[ 0 ] ) ? palette : [ palette ]; 20851 paletteLookup = {}; 20852 for ( i = 0; i < paletteArray.length; i++ ) { 20853 for ( j = 0; j < paletteArray[ i ].length; j++ ) { 20854 rgb = tinycolor( paletteArray[ i ][ j ] ).toRgbString(); 20855 paletteLookup[ rgb ] = true; 20856 } 20857 } 20858 20859 // if showPaletteOnly and didn't set initialcolor 20860 // set initialcolor to first palette 20861 if ( opts.showPaletteOnly && ! initialColor ) { 20862 initialColor = palette[ 0 ][ 0 ] === '' ? palette[ 0 ][ 0 ] : Object.keys( paletteLookup )[ 0 ]; 20863 } 20864 } 20865 20866 container.toggleClass( 'sp-flat', flat ); 20867 container.toggleClass( 'sp-input-disabled', ! opts.showInput ); 20868 container.toggleClass( 'sp-alpha-enabled', opts.showAlpha ); 20869 container.toggleClass( 'sp-clear-enabled', allowEmpty ); 20870 container.toggleClass( 'sp-buttons-disabled', ! opts.showButtons ); 20871 container.toggleClass( 'sp-palette-buttons-disabled', ! opts.togglePaletteOnly ); 20872 container.toggleClass( 'sp-palette-disabled', ! opts.showPalette ); 20873 container.toggleClass( 'sp-palette-only', opts.showPaletteOnly ); 20874 container.toggleClass( 'sp-initial-disabled', ! opts.showInitial );
20875 container.addClass( opts.className ).addClass( opts.containerClassName ); 20876 20877 reflow(); 20878 } 20879 20880 function initialize() { 20881 var addOn; 20882 var appendTo; 20883 var paletteEvent; 20884 20885 if ( IE ) { 20886 container.find( '*:not(input)' ).attr( 'unselectable', 'on' ); 20887 } 20888 20889 applyOptions(); 20890 20891 originalInputContainer = $( '<span class="sp-original-input-container"></span>' ); 20892 [ 'margin' ].forEach( function( cssProp ) { 20893 originalInputContainer.css( cssProp, boundElement.css( cssProp ) ); 20894 } ); 20895 // inline-flex by default, switching to flex if needed 20896 if ( boundElement.css( 'display' ) === 'block' ) { 20897 originalInputContainer.css( 'display', 'flex' ); 20898 } 20899 20900 if ( shouldReplace ) { 20901 boundElement.after( replacer ).hide(); 20902 } else if ( type === 'text' ) { 20903 originalInputContainer.addClass( 'sp-colorize-container' ); 20904 boundElement.addClass( 'spectrum sp-colorize' ).wrap( originalInputContainer ); 20905 } else if ( type === 'component' ) { 20906 boundElement.addClass( 'spectrum' ).wrap( originalInputContainer ); 20907 addOn = $( [ "<div class='sp-colorize-container sp-add-on'>", "<div class='sp-colorize'></div> ", '</div>' ].join( '' ) ); 20908 addOn 20909 .width( boundElement.outerHeight() + 'px' ) 20910 .css( 'border-radius', boundElement.css( 'border-radius' ) ) 20911 .css( 'border', boundElement.css( 'border' ) ); 20912 boundElement.addClass( 'with-add-on' ).before( addOn ); 20913 } 20914 20915 colorizeElement = boundElement.parent().find( '.sp-colorize' ); 20916 colorizeElementInitialColor = colorizeElement.css( 'color' ); 20917 colorizeElementInitialBackground = colorizeElement.css( 'background-color' ); 20918 20919 if ( ! allowEmpty ) { 20920 clearButton.hide(); 20921 } 20922 20923 if ( flat ) { 20924 boundElement.after( container ).hide(); 20925 } else { 20926 appendTo = opts.appendTo === 'parent' ? boundElement.parent() : $( opts.appendTo ); 20927 if ( appendTo.length !== 1 ) { 20928 appendTo = $( 'body' ); 20929 } 20930 20931 appendTo.append( container ); 20932 } 20933 20934 updateSelectionPaletteFromStorage(); 20935 20936 offsetElement.on( 'click.spectrum touchstart.spectrum', function( e ) { 20937 if ( ! disabled ) { 20938 show(); 20939 } 20940 20941 e.stopPropagation(); 20942 20943 if ( ! $( e.target ).is( 'input' ) ) { 20944 e.preventDefault(); 20945 } 20946 } ); 20947 20948 if ( boundElement.is( ':disabled' ) || opts.disabled === true ) { 20949 disable(); 20950 } 20951 20952 // Prevent clicks from bubbling up to document. This would cause it to be hidden. 20953 container.on( 'click', stopPropagation ); 20954 20955 container.on( 'keydown', 'div[role="button"]', function( e ) { 20956 if ( e.keyCode === 13 ) { 20957 e.preventDefault(); 20958 $( this ).click(); 20959 } 20960 } ); 20961 20962 // Handle user typed input 20963 [ textInput, boundElement ].forEach( function( input ) { 20964 input.on( 'change', function() { 20965 setFromTextInput( input.val() ); 20966 } ); 20967 input.on( 'paste', function() { 20968 setTimeout( function() { 20969 setFromTextInput( input.val() ); 20970 }, 1 ); 20971 } ); 20972 input.on( 'keydown', function( e ) { 20973 if ( e.keyCode === 13 ) { 20974 setFromTextInput( $( input ).val() ); 20975 // eslint-disable-next-line eqeqeq 20976 if ( input == boundElement ) { 20977 hide(); 20978 } 20979 } 20980 } ); 20981 } ); 20982 20983 cancelButton.text( opts.cancelText ); 20984 cancelButton.on( 'click.spectrum', function( e ) { 20985 e.stopPropagation(); 20986 e.preventDefault(); 20987 revert(); 20988 hide(); 20989 } ); 20990 20991 clearButton.attr( 'title', opts.clearText ); 20992 clearButton.on( 'click.spectrum', function( e ) { 20993 e.stopPropagation(); 20994 e.preventDefault(); 20995 isEmpty = true; 20996 move(); 20997 20998 if ( flat ) { 20999 //for the flat style, this is a change event 21000 updateOriginalInput( true ); 21001 } 21002 } ); 21003 21004 chooseButton.text( opts.chooseText ); 21005 chooseButton.on( 'click.spectrum', function( e ) { 21006 e.stopPropagation(); 21007 e.preventDefault(); 21008 21009 if ( IE && textInput.is( ':focus' ) ) { 21010 textInput.trigger( 'change' ); 21011 } 21012 21013 if ( isValid() ) { 21014 updateOriginalInput( true ); 21015 hide(); 21016 } 21017 } ); 21018 21019 toggleButton.text( opts.showPaletteOnly ? opts.togglePaletteMoreText : opts.togglePaletteLessText ); 21020 toggleButton.on( 'click.spectrum', function( e ) { 21021 e.stopPropagation(); 21022 e.preventDefault(); 21023 21024 opts.showPaletteOnly = ! opts.showPaletteOnly; 21025 21026 // To make sure the Picker area is drawn on the right, next to the 21027 // Palette area (and not below the palette), first move the Palette 21028 // to the left to make space for the picker, plus 5px extra. 21029 // The 'applyOptions' function puts the whole container back into place 21030 // and takes care of the button-text and the sp-palette-only CSS class. 21031 if ( ! opts.showPaletteOnly && ! flat ) { 21032 container.css( 'left', '-=' + ( pickerContainer.outerWidth( true ) + 5 ) ); 21033 } 21034 applyOptions(); 21035 } ); 21036 21037 draggable( 21038 alphaSlider, 21039 function( dragX, dragY, e ) { 21040 currentAlpha = dragX / alphaWidth; 21041 isEmpty = false;
21042 if ( e.shiftKey ) { 21043 currentAlpha = Math.round( currentAlpha * 10 ) / 10; 21044 } 21045 21046 move(); 21047 }, 21048 dragStart, 21049 dragStop 21050 ); 21051 21052 draggable( 21053 slider, 21054 function( dragX, dragY ) { 21055 currentHue = parseFloat( dragY / slideHeight ); 21056 isEmpty = false; 21057 if ( ! opts.showAlpha ) { 21058 currentAlpha = 1; 21059 } 21060 move(); 21061 }, 21062 dragStart, 21063 dragStop 21064 ); 21065 21066 draggable( 21067 dragger, 21068 function( dragX, dragY, e ) { 21069 var oldDragX; 21070 var oldDragY; 21071 var furtherFromX; 21072 var setSaturation; 21073 var setValue; 21074 // shift+drag should snap the movement to either the x or y axis. 21075 if ( ! e.shiftKey ) { 21076 shiftMovementDirection = null; 21077 } else if ( ! shiftMovementDirection ) { 21078 oldDragX = currentSaturation * dragWidth; 21079 oldDragY = dragHeight - ( currentValue * dragHeight ); 21080 furtherFromX = Math.abs( dragX - oldDragX ) > Math.abs( dragY - oldDragY ); 21081 21082 shiftMovementDirection = furtherFromX ? 'x' : 'y'; 21083 } 21084 21085 setSaturation = ! shiftMovementDirection || shiftMovementDirection === 'x'; 21086 setValue = ! shiftMovementDirection || shiftMovementDirection === 'y'; 21087 21088 if ( setSaturation ) { 21089 currentSaturation = parseFloat( dragX / dragWidth ); 21090 } 21091 if ( setValue ) { 21092 currentValue = parseFloat( ( dragHeight - dragY ) / dragHeight ); 21093 } 21094 21095 isEmpty = false; 21096 if ( ! opts.showAlpha ) { 21097 currentAlpha = 1; 21098 } 21099 21100 move(); 21101 }, 21102 dragStart, 21103 dragStop 21104 ); 21105 21106 if ( initialColor !== false && initialColor !== '' ) { 21107 set( initialColor ); 21108 21109 // In case color was black - update the preview UI and set the format 21110 // since the set function will not run (default color is black). 21111 updateUI(); 21112 currentPreferredFormat = tinycolor( initialColor ).format || opts.preferredFormat; 21113 addColorToSelectionPalette( initialColor ); 21114 } else if ( initialColor === '' ) { 21115 set( initialColor ); 21116 updateUI(); 21117 } else { 21118 updateUI(); 21119 } 21120 21121 if ( flat ) { 21122 show(); 21123 } 21124 21125 function paletteElementClick( e ) { 21126 if ( e.data && e.data.ignore ) { 21127 set( $( e.target ).closest( '.sp-thumb-el' ).data( 'color' ) ); 21128 move(); 21129 } else { 21130 set( $( e.target ).closest( '.sp-thumb-el' ).data( 'color' ) ); 21131 move(); 21132 21133 // If the picker is going to close immediately, a palette selection 21134 // is a change. Otherwise, it's a move only. 21135 if ( opts.hideAfterPaletteSelect ) { 21136 updateOriginalInput( true ); 21137 hide(); 21138 } else { 21139 updateOriginalInput(); 21140 } 21141 } 21142 21143 return false; 21144 } 21145 21146 paletteEvent = IE ? 'mousedown.spectrum' : 'click.spectrum touchstart.spectrum'; 21147 paletteContainer.on( paletteEvent, '.sp-thumb-el', paletteElementClick ); 21148 initialColorContainer.on( paletteEvent, '.sp-thumb-el:nth-child(1)', { ignore: true }, paletteElementClick ); 21149 } 21150 21151 function updateSelectionPaletteFromStorage() { 21152 var localStorage; 21153 var oldPalette; 21154 21155 if ( localStorageKey ) { 21156 // Migrate old palettes over to new format. May want to remove this eventually. 21157 try { 21158 localStorage = window.localStorage; 21159 oldPalette = localStorage[ localStorageKey ].split( ',#' ); 21160 if ( oldPalette.length > 1 ) { 21161 delete localStorage[ localStorageKey ]; 21162 $.each( oldPalette, function( i, c ) { 21163 addColorToSelectionPalette( c ); 21164 } ); 21165 } 21166 } catch ( e ) { 21167 window.console.log( e ); 21168 } 21169 21170 try { 21171 selectionPalette = window.localStorage[ localStorageKey ].split( ';' ); 21172 } catch ( e ) { 21173 window.console.log( e ); 21174 } 21175 } 21176 } 21177 21178 function addColorToSelectionPalette( color ) { 21179 var rgb; 21180 if ( showSelectionPalette ) { 21181 rgb = tinycolor( color ).toRgbString(); 21182 if ( ! paletteLookup[ rgb ] && $.inArray( rgb, selectionPalette ) === -1 ) { 21183 selectionPalette.push( rgb ); 21184 while ( selectionPalette.length > maxSelectionSize ) { 21185 selectionPalette.shift(); 21186 } 21187 } 21188 21189 if ( localStorageKey ) { 21190 try { 21191 window.localStorage[ localStorageKey ] = selectionPalette.join( ';' ); 21192 } catch ( e ) { 21193 window.console.log( e ); 21194 } 21195 } 21196 } 21197 } 21198 21199 function getUniqueSelectionPalette() { 21200 var unique = []; 21201 var i; 21202 var rgb; 21203 if ( opts.showPalette ) { 21204 for ( i = 0; i < selectionPalette.length; i++ ) { 21205 rgb = tinycolor( selectionPalette[ i ] ).toRgbString(); 21206 21207 if ( ! paletteLookup[ rgb ] ) { 21208 unique.push( selectionPalette[ i ] ); 21209 } 21210 } 21211 } 21212 21213 return unique.reverse().slice( 0, opts.maxSelectionSize ); 21214 } 21215 21216 function drawPalette() { 21217 var currentColor = get(); 21218 21219 var html = $.map( paletteArray, function( thispalette, i ) { 21220 return paletteTemplate( thispalette, currentColor, 'sp-palette-row sp-palette-row-' + i, opts ); 21221 } ); 21222 21223 updateSelectionPaletteFromStorage(); 21224 21225 if ( selectionPalette ) { 21226 html.push( paletteTemplate( getUniqueSelectionPalette(), currentColor, 'sp-palette-row sp-palette-row-selection', opts ) ); 21227 } 21228 21229 paletteContainer.html( html.join( '' ) ); 21230 } 21231 21232 function drawInitial() { 21233 var initial; 21234 var current; 21235 if ( opts.showInitial ) { 21236 initial = colorOnShow; 21237 current = get(); 21238 initialColorContainer.html( paletteTemplate( [ initial, current ], current, 'sp-palette-row-initial', opts ) ); 21239 } 21240 } 21241 21242 function dragStart() { 21243 if ( dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0 ) { 21244 reflow(); 21245 } 21246 isDragging = true; 21247 container.addClass( draggingClass ); 21248 shiftMovementDirection = null; 21249 boundElement.trigger( 'dragstart.spectrum', [ get() ] ); 21250 } 21251 21252 function dragStop() { 21253 isDragging = false;
vendor: 5,558 bytes, lines 21254-21488
21254 container.removeClass( draggingClass ); 21255 boundElement.trigger( 'dragstop.spectrum', [ get() ] ); 21256 } 21257 21258 function setFromTextInput( value ) { 21259 var tiny; 21260 if ( abortNextInputChange ) { 21261 abortNextInputChange = false; 21262 return; 21263 } 21264 if ( ( value === null || value === '' ) && allowEmpty ) { 21265 set( null ); 21266 move(); 21267 updateOriginalInput(); 21268 } else { 21269 tiny = tinycolor( value ); 21270 if ( tiny.isValid() ) { 21271 set( tiny ); 21272 move(); 21273 updateOriginalInput(); 21274 } else { 21275 textInput.addClass( 'sp-validation-error' ); 21276 } 21277 } 21278 } 21279 21280 function toggle() { 21281 if ( visible ) { 21282 hide(); 21283 } else { 21284 show(); 21285 } 21286 } 21287 21288 function show() { 21289 // debugger; 21290 var event = $.Event( 'beforeShow.spectrum' ); 21291 21292 if ( visible ) { 21293 reflow(); 21294 return; 21295 } 21296 21297 boundElement.trigger( event, [ get() ] ); 21298 21299 if ( callbacks.beforeShow( get() ) === false || event.isDefaultPrevented() ) { 21300 return; 21301 } 21302 21303 hideAll(); 21304 visible = true; 21305 21306 $( doc ).on( 'keydown.spectrum', onkeydown ); 21307 $( doc ).on( 'click.spectrum', clickout ); 21308 $( window ).on( 'resize.spectrum', resize ); 21309 replacer.attr( 'aria-expanded', true ); 21310 replacer.addClass( 'sp-active' ); 21311 container.removeClass( 'sp-hidden' ); 21312 21313 reflow(); 21314 updateUI(); 21315 21316 colorOnShow = get(); 21317 21318 drawInitial(); 21319 callbacks.show( colorOnShow ); 21320 boundElement.trigger( 'show.spectrum', [ colorOnShow ] ); 21321 } 21322 21323 function onkeydown( e ) { 21324 // Close on ESC 21325 if ( e.keyCode === 27 ) { 21326 hide(); 21327 } 21328 } 21329 21330 function clickout( e ) { 21331 // Return on right click. 21332 if ( e.button === 2 ) { 21333 return; 21334 } 21335 21336 // If a drag event was happening during the mouseup, don't hide 21337 // on click. 21338 if ( isDragging ) { 21339 return; 21340 } 21341 21342 if ( clickoutFiresChange ) { 21343 updateOriginalInput( true ); 21344 } else { 21345 revert(); 21346 } 21347 hide(); 21348 } 21349 21350 function hide() { 21351 // Return if hiding is unnecessary 21352 if ( ! visible || flat ) { 21353 return; 21354 } 21355 visible = false; 21356 21357 $( doc ).off( 'keydown.spectrum', onkeydown ); 21358 $( doc ).off( 'click.spectrum', clickout ); 21359 $( window ).off( 'resize.spectrum', resize ); 21360 21361 replacer.attr( 'aria-expanded', false ); 21362 replacer.removeClass( 'sp-active' ); 21363 container.addClass( 'sp-hidden' ); 21364 21365 callbacks.hide( get() ); 21366 boundElement.trigger( 'hide.spectrum', [ get() ] ); 21367 } 21368 21369 function revert() { 21370 set( colorOnShow, true ); 21371 updateOriginalInput( true ); 21372 } 21373 21374 function set( color, ignoreFormatChange ) { 21375 var newColor, newHsv; 21376 if ( tinycolor.equals( color, get() ) ) { 21377 // Update UI just in case a validation error needs 21378 // to be cleared. 21379 updateUI(); 21380 return; 21381 } 21382 21383 if ( ( ! color || color === undefined ) && allowEmpty ) { 21384 isEmpty = true; 21385 } else { 21386 isEmpty = false; 21387 newColor = tinycolor( color ); 21388 newHsv = newColor.toHsv(); 21389 21390 currentHue = ( newHsv.h % 360 ) / 360; 21391 currentSaturation = newHsv.s; 21392 currentValue = newHsv.v; 21393 currentAlpha = newHsv.a; 21394 } 21395 updateUI(); 21396 21397 if ( newColor && newColor.isValid() && ! ignoreFormatChange ) { 21398 currentPreferredFormat = opts.preferredFormat || newColor.getFormat(); 21399 } 21400 } 21401 21402 function get( thisopts ) { 21403 thisopts = thisopts || {}; 21404 21405 if ( allowEmpty && isEmpty ) { 21406 return null; 21407 } 21408 21409 return tinycolor.fromRatio( 21410 { 21411 h: currentHue, 21412 s: currentSaturation, 21413 v: currentValue, 21414 a: Math.round( currentAlpha * 1000 ) / 1000 21415 }, 21416 { format: thisopts.format || currentPreferredFormat } 21417 ); 21418 } 21419 21420 function isValid() { 21421 return ! textInput.hasClass( 'sp-validation-error' ); 21422 } 21423 21424 function move() { 21425 updateUI(); 21426 21427 callbacks.move( get() ); 21428 boundElement.trigger( 'move.spectrum', [ get() ] ); 21429 } 21430 21431 function updateUI() { 21432 var flatColor; 21433 var format; 21434 var realColor; 21435 var displayColor; 21436 var realHex; 21437 var realRgb; 21438 var rgb; 21439 var realAlpha; 21440 var gradient; 21441 var color; 21442 var textColor; 21443 21444 textInput.removeClass( 'sp-validation-error' ); 21445 21446 updateHelperLocations(); 21447 21448 // Update dragger background color (gradients take care of saturation and value). 21449 flatColor = tinycolor.fromRatio( { h: currentHue, s: 1, v: 1 } ); 21450 dragger.css( 'background-color', flatColor.toHexString() ); 21451 21452 // Get a format that alpha will be included in (hex and names ignore alpha) 21453 format = currentPreferredFormat; 21454 if ( currentAlpha < 1 && ! ( currentAlpha === 0 && format === 'name' ) ) { 21455 if ( format === 'hex' || format === 'hex3' || format === 'hex6' || format === 'name' ) { 21456 format = 'rgb'; 21457 } 21458 } 21459 21460 realColor = get( { format: format } ); 21461 displayColor = ''; 21462 21463 //reset background info for preview element 21464 previewElement.removeClass( 'sp-clear-display' ); 21465 previewElement.css( 'background-color', 'transparent' ); 21466 21467 if ( ! realColor && allowEmpty ) { 21468 // Update the replaced elements background with icon indicating no color selection 21469 previewElement.addClass( 'sp-clear-display' ); 21470 } else { 21471 realHex = realColor.toHexString(); 21472 realRgb = realColor.toRgbString(); 21473 21474 // Update the replaced elements background color (with actual selected color) 21475 if ( rgbaSupport || realColor.alpha === 1 ) { 21476 previewElement.css( 'background-color', realRgb ); 21477 } else { 21478 previewElement.css( 'background-color', 'transparent' ); 21479 previewElement.css( 'filter', realColor.toFilter() ); 21480 } 21481 21482 if ( opts.showAlpha ) { 21483 rgb = realColor.toRgb(); 21484 rgb.a = 0; 21485 realAlpha = tinycolor( rgb ).toRgbString(); 21486 gradient = 'linear-gradient(left, ' + realAlpha + ', ' + realHex + ')'; 21487 21488 if ( IE ) {
21489 alphaSliderInner.css( 'filter', tinycolor( realAlpha ).toFilter( { gradientType: 1 }, realHex ) ); 21490 } else { 21491 alphaSliderInner.css( 'background', '-webkit-' + gradient ); 21492 alphaSliderInner.css( 'background', '-moz-' + gradient ); 21493 alphaSliderInner.css( 'background', '-ms-' + gradient ); 21494 // Use current syntax gradient on unprefixed property. 21495 alphaSliderInner.css( 'background', 'linear-gradient(to right, ' + realAlpha + ', ' + realHex + ')' ); 21496 } 21497 } 21498 21499 displayColor = realColor.toString( format ); 21500 } 21501 21502 // Update the text entry input as it changes happen 21503 if ( opts.showInput ) { 21504 textInput.val( displayColor ); 21505 } 21506 boundElement.val( displayColor ); 21507 if ( opts.type === 'text' || opts.type === 'component' ) { 21508 color = realColor; 21509 if ( color && colorizeElement ) { 21510 textColor = color.isLight() || color.getAlpha() < 0.4 ? 'black' : 'white'; 21511 colorizeElement.css( 'background-color', color.toRgbString() ).css( 'color', textColor ); 21512 } else { 21513 colorizeElement.css( 'background-color', colorizeElementInitialBackground ).css( 'color', colorizeElementInitialColor ); 21514 } 21515 } 21516 21517 if ( opts.showPalette ) { 21518 drawPalette(); 21519 } 21520 21521 drawInitial(); 21522 } 21523 21524 function updateHelperLocations() { 21525 var s = currentSaturation; 21526 var v = currentValue; 21527 var dragX; 21528 var dragY; 21529 var alphaX; 21530 var slideY; 21531 21532 if ( allowEmpty && isEmpty ) { 21533 //if selected color is empty, hide the helpers 21534 alphaSlideHelper.hide(); 21535 slideHelper.hide(); 21536 dragHelper.hide(); 21537 } else { 21538 //make sure helpers are visible 21539 alphaSlideHelper.show(); 21540 slideHelper.show(); 21541 dragHelper.show(); 21542 21543 // Where to show the little circle in that displays your current selected color 21544 dragX = s * dragWidth; 21545 dragY = dragHeight - ( v * dragHeight ); 21546 dragX = Math.max( -dragHelperHeight, Math.min( dragWidth - dragHelperHeight, dragX - dragHelperHeight ) ); 21547 dragY = Math.max( -dragHelperHeight, Math.min( dragHeight - dragHelperHeight, dragY - dragHelperHeight ) ); 21548 dragHelper.css( { 21549 top: dragY + 'px', 21550 left: dragX + 'px' 21551 } ); 21552 21553 alphaX = currentAlpha * alphaWidth; 21554 alphaSlideHelper.css( { 21555 left: alphaX - ( alphaSlideHelperWidth / 2 ) + 'px' 21556 } ); 21557 21558 // Where to show the bar that displays your current selected hue 21559 slideY = currentHue * slideHeight; 21560 slideHelper.css( { 21561 top: slideY - slideHelperHeight + 'px' 21562 } ); 21563 } 21564 } 21565 21566 function updateOriginalInput( fireCallback ) { 21567 var color = get(), 21568 hasChanged = ! tinycolor.equals( color, colorOnShow ); 21569 21570 if ( color ) { 21571 // Update the selection palette with the current color 21572 addColorToSelectionPalette( color ); 21573 } 21574 21575 if ( fireCallback && hasChanged ) { 21576 callbacks.change( color ); 21577 // we trigger the change event or input, but the input change event is also binded 21578 // to some spectrum processing, that we do no need 21579 abortNextInputChange = true; 21580 boundElement.trigger( 'change', [ color ] ); 21581 } 21582 } 21583 21584 function reflow() { 21585 if ( ! visible ) { 21586 return; // Calculations would be useless and wouldn't be reliable anyways 21587 } 21588 dragWidth = dragger.width(); 21589 dragHeight = dragger.height(); 21590 dragHelperHeight = dragHelper.height(); 21591 slideHeight = slider.height(); 21592 slideHelperHeight = slideHelper.height(); 21593 alphaWidth = alphaSlider.width(); 21594 alphaSlideHelperWidth = alphaSlideHelper.width(); 21595 21596 if ( ! flat ) { 21597 container.attr( 'aria-haspopup', true ); 21598 container.css( 'position', 'absolute' ); 21599 if ( opts.offset ) { 21600 container.offset( opts.offset ); 21601 } else { 21602 container.offset( getOffset( container, offsetElement ) ); 21603 } 21604 } 21605 21606 updateHelperLocations(); 21607 21608 if ( opts.showPalette ) { 21609 drawPalette(); 21610 } 21611 21612 boundElement.trigger( 'reflow.spectrum' ); 21613 } 21614 21615 function destroy() { 21616 var oInputContainer; 21617 boundElement.show().removeClass( 'spectrum with-add-on sp-colorize' ); 21618 offsetElement.off( 'click.spectrum touchstart.spectrum' ); 21619 container.remove(); 21620 replacer.remove(); 21621 if ( colorizeElement ) { 21622 colorizeElement.css( 'background-color', colorizeElementInitialBackgroun
21622d ).css( 'color', colorizeElementInitialColor ); 21623 } 21624 oInputContainer = boundElement.closest( '.sp-original-input-container' ); 21625 if ( oInputContainer.length > 0 ) { 21626 oInputContainer.after( boundElement ).remove(); 21627 } 21628 spectrums[ spect.id ] = null; 21629 } 21630 21631 function option( optionName, optionValue ) { 21632 if ( optionName === undefined ) { 21633 return $.extend( {}, opts ); 21634 } 21635 if ( optionValue === undefined ) { 21636 return opts[ optionName ]; 21637 } 21638 21639 opts[ optionName ] = optionValue; 21640 21641 if ( optionName === 'preferredFormat' ) { 21642 currentPreferredFormat = opts.preferredFormat; 21643 } 21644 applyOptions(); 21645 } 21646 21647 function enable() { 21648 disabled = false; 21649 boundElement.attr( 'disabled', false ); 21650 offsetElement.removeClass( 'sp-disabled' ); 21651 } 21652 21653 function disable() { 21654 hide(); 21655 disabled = true; 21656 boundElement.attr( 'disabled', true ); 21657 offsetElement.addClass( 'sp-disabled' ); 21658 } 21659 21660 function setOffset( coord ) { 21661 opts.offset = coord; 21662 reflow(); 21663 } 21664 21665 initialize(); 21666 21667 spect = { 21668 show: show, 21669 hide: hide, 21670 toggle: toggle, 21671 reflow: reflow, 21672 option: option, 21673 enable: enable, 21674 disable: disable, 21675 offset: setOffset, 21676 set: function( c ) { 21677 set( c ); 21678 updateOriginalInput(); 21679 }, 21680 get: get, 21681 destroy: destroy, 21682 container: container 21683 }; 21684 21685 spect.id = spectrums.push( spect ) - 1; 21686 21687 return spect; 21688 } 21689 21690 // checkOffset - get the offset below/above and left/right element depending on screen position 21691 // Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js 21692 function getOffset( picker, input ) { 21693 var extraY = 0; 21694 var dpWidth = picker.outerWidth(); 21695 var dpHeight = picker.outerHeight(); 21696 var inputHeight = input.outerHeight(); 21697 var doc = picker[ 0 ].ownerDocument; 21698 var docElem = doc.documentElement; 21699 var viewWidth = docElem.clientWidth + $( doc ).scrollLeft(); 21700 var viewHeight = docElem.clientHeight + $( doc ).scrollTop(); 21701 var offset = input.offset(); 21702 var offsetLeft = offset.left; 21703 var offsetTop = offset.top; 21704 21705 offsetTop += inputHeight; 21706 21707 offsetLeft -= Math.min( offsetLeft, offsetLeft + dpWidth > viewWidth && viewWidth > dpWidth ? Math.abs( offsetLeft + dpWidth - viewWidth ) : 0 ); 21708 21709 offsetTop -= Math.min( offsetTop, offsetTop + dpHeight > viewHeight && viewHeight > dpHeight ? Math.abs( dpHeight + inputHeight - extraY ) : extraY ); 21710 21711 return { 21712 top: offsetTop, 21713 bottom: offset.bottom, 21714 left: offsetLeft, 21715 right: offset.right, 21716 width: offset.width, 21717 height: offset.height 21718 }; 21719 } 21720 21721 // noop - do nothing 21722 function noop() {} 21723 21724 // stopPropagation - makes the code only doing this a little easier to read in line 21725 function stopPropagation( e ) { 21726 e.stopPropagation(); 21727 } 21728 21729 // Create a function bound to a given object 21730 // Thanks to underscore.js 21731 function bind( func, obj ) { 21732 var slice = Array.prototype.slice; 21733 var args = slice.call( arguments, 2 ); 21734 return function() { 21735 return func.apply( obj, args.concat( slice.call( arguments ) ) ); 21736 }; 21737 } 21738 21739 // Lightweight drag helper. Handles containment within the element, so that 21740 // when dragging, the x is within [0,element.width] and y is within [0,element.height] 21741 function draggable( element, onmove, onstart, onstop ) { 21742 var doc = document; 21743 var dragging = false; 21744 var offset = {}; 21745 var maxHeight = 0; 21746 var maxWidth = 0; 21747 var hasTouch = 'ontouchstart' in window; 21748 var duringDragEvents = {}; 21749 21750 onmove = onmove || function() {}; 21751 onstart = onstart || function() {}; 21752 onstop = onstop || function() {}; 21753 21754 duringDragEvents.selectstart = prevent; 21755 duringDragEvents.dragstart = prevent; 21756 duringDragEvents[ 'touchmove mousemove' ] = move; 21757 duringDragEvents[ 'touchend mouseup' ] = stop; 21758 21759 function prevent( e ) { 21760 if ( e.stopPropagation ) { 21761 e.stopPropagation(); 21762 } 21763 if ( e.preventDefault ) { 21764 e.preventDefault(); 21765 } 21766 e.returnValue = false; 21767 } 21768 21769 function move( e ) { 21770 var t0; 21771 var pageX; 21772 var pageY; 21773 var dragX; 21774 var dragY; 21775 if ( dragging ) { 21776 // Mouseup happened outside of window 21777 if ( IE && doc.documentMode < 9 && ! e.button ) { 21778 return stop(); 21779 } 21780 21781 t0 = e.originalEvent && e.originalEvent.touches && e.originalEvent.touches[ 0 ]; 21782 pageX = ( t0 && t0.pageX ) || e.pageX; 21783 pageY = ( t0 && t0.pageY ) || e.pageY; 21784 21785 dragX = Math.max( 0, Math.min( pageX - offset.left, maxWidth ) ); 21786 dragY = Math.max( 0, Math.min( pageY - offset.top, maxHeight ) ); 21787 21788 if ( hasTouch ) { 21789 // Stop scrolling in iOS 21790 prevent( e ); 21791 } 21792 21793 onmove.apply( element, [ dragX, dragY, e ] ); 21794 } 21795 } 21796 21797 function start( e ) { 21798 var rightclick = e.which ? e.which === 3 : e.button === 2; 21799 21800 if ( ! rightclick && ! dragging ) { 21801 if ( onstart.apply( element, arguments ) !== false ) { 21802 dragging = true; 21803 maxHeight = $( element ).height(); 21804 maxWidth = $( element ).width(); 21805 offset = $( element ).offset(); 21806 21807 $( doc ).on( duringDragEvents ); 21808 $( doc.body ).addClass( 'sp-dragging' ); 21809 21810 move( e ); 21811 21812 prevent( e ); 21813 } 21814 } 21815 } 21816 21817 function stop() { 21818 if ( dragging ) { 21819 $( doc ).off( duringDragEvents ); 21820 $( doc.body ).removeClass( 'sp-dragging' ); 21821 21822 // Wait a tick before notifying observers to allow the click event 21823 // to fire in Chrome. 21824 setTimeout( function() { 21825 onstop.apply( element, arguments ); 21826 }, 0 ); 21827 } 21828 dragging = false;
21829 } 21830 21831 $( element ).on( 'touchstart mousedown', start ); 21832 } 21833 21834 function throttle( func, wait, debounce ) { 21835 var timeout; 21836 return function() { 21837 var context = this, 21838 args = arguments; 21839 var throttler = function() { 21840 timeout = null; 21841 func.apply( context, args ); 21842 }; 21843 if ( debounce ) { 21844 clearTimeout( timeout ); 21845 } 21846 if ( debounce || ! timeout ) { 21847 timeout = setTimeout( throttler, wait ); 21848 } 21849 }; 21850 } 21851 21852 function inputTypeColorSupport() { 21853 return $.fn.spectrum.inputTypeColorSupport(); 21854 } 21855 21856 // Define a jQuery plugin 21857 $.fn.spectrum = function( opts ) { 21858 var returnValue; 21859 var args; 21860 var spect; 21861 var method; 21862 21863 if ( typeof opts === 'string' ) { 21864 returnValue = this; 21865 args = Array.prototype.slice.call( arguments, 1 ); 21866 21867 this.each( function() { 21868 spect = spectrums[ $( this ).data( dataID ) ]; 21869 if ( spect ) { 21870 method = spect[ opts ]; 21871 if ( ! method ) { 21872 throw new Error( "Spectrum: no such method: '" + opts + "'" ); 21873 } 21874 21875 if ( opts === 'get' ) { 21876 returnValue = spect.get(); 21877 } else if ( opts === 'container' ) { 21878 returnValue = spect.container; 21879 } else if ( opts === 'option' ) { 21880 returnValue = spect.option.apply( spect, args ); 21881 } else if ( opts === 'destroy' ) { 21882 spect.destroy(); 21883 $( this ).removeData( dataID ); 21884 } else { 21885 method.apply( spect, args ); 21886 } 21887 } 21888 } ); 21889 21890 return returnValue; 21891 } 21892 21893 // Initializing a new instance of spectrum 21894 return this.spectrum( 'destroy' ).each( function() { 21895 var options = $.extend( {}, $( this ).data(), opts ); 21896 var thisspect; 21897 // Infer default type from input params and deprecated options 21898 if ( ! $( this ).is( 'input' ) ) { 21899 options.type = 'noInput'; 21900 } else if ( options.flat || options.type === 'flat' ) { 21901 options.type = 'flat'; 21902 } else if ( $( this ).attr( 'type' ) === 'color' ) { 21903 options.type = 'color'; 21904 } 21905 21906 thisspect = spectrum( this, options ); 21907 $( this ).data( dataID, thisspect.id ); 21908 } ); 21909 }; 21910 21911 $.fn.spectrum.load = true; 21912 $.fn.spectrum.loadOpts = {}; 21913 $.fn.spectrum.draggable = draggable; 21914 $.fn.spectrum.defaults = defaultOpts; 21915 $.fn.spectrum.inputTypeColorSupport = function() { 21916 var colorInput; 21917 if ( typeof inputTypeColorSupport._cachedResult === 'undefined' ) { 21918 colorInput = $( "<input type='color'>" )[ 0 ]; // if color element is supported, value will default to not null 21919 inputTypeColorSupport._cachedResult = colorInput.type === 'color' && colorInput.value !== ''; 21920 } 21921 return inputTypeColorSupport._cachedResult; 21922 }; 21923 21924 $.spectrum = {}; 21925 $.spectrum.localization = {}; 21926 $.spectrum.palettes = {}; 21927 21928 $.fn.spectrum.processNativeColorInputs = function() { 21929 var colorInputs = $( 'input[type=color]' ); 21930 if ( colorInputs.length && ! inputTypeColorSupport() ) { 21931 colorInputs.spectrum( { 21932 preferredFormat: 'hex6' 21933 } ); 21934 } 21935 }; 21936 21937 $( function() { 21938 if ( $.fn.spectrum.load ) { 21939 $.fn.spectrum.processNativeColorInputs(); 21940 } 21941 } ); 21942} ) ); 21943; 21944/** 21945 * jquery.mask.js 21946 * 21947 * @version: v1.14.16 21948 * @author: Igor Escobar 21949 * 21950 * Created by Igor Escobar on 2012-03-10. Please report any bug at github.com/igorescobar/jQuery-Mask-Plugin 21951 * 21952 * Copyright (c) 2012 Igor Escobar http://igorescobar.com 21953 * 21954 * The MIT License (http://www.opensource.org/licenses/mit-license.php) 21955 * 21956 * Permission is hereby granted, free of charge, to any person 21957 * obtaining a copy of this software and associated documentation 21958 * files (the "Software"), to deal in the Software without 21959 * restriction, including without limitation the rights to use, 21960 * copy, modify, merge, publish, distribute, sublicense, and/or sell 21961 * copies of the Software, and to permit persons to whom the 21962 * Software is furnished to do so, subject to the following 21963 * conditions: 21964 * 21965 * The above copyright notice and this permission notice shall be 21966 * included in all copies or substantial portions of the Software. 21967 * 21968 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21969 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21970 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21971 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21972 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21973 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21974 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21975 * OTHER DEALINGS IN THE SOFTWARE. 21976 */ 21977 21978/* jshint laxbreak: true */ 21979/* jshint maxcomplexity:17 */ 21980/* global define */ 21981 21982// UMD (Universal Module Definition) patterns for JavaScript modules that work everywhere. 21983// https://github.com/umdjs/umd/blob/master/templates/jqueryPlugin.js 21984// reformatted code by ThemeComplete 21985( function( factory, jQuery, Zepto ) { 21986 'use strict'; 21987 21988 if ( typeof define === 'function' && define.amd ) { 21989 define( [ 'jquery' ], factory ); 21990 } else if ( typeof exports === 'object' && typeof Meteor === 'undefined' ) { 21991 window.module.exports = factory( window.require( 'jquery' ) ); 21992 } else { 21993 factory( jQuery || Zepto ); 21994 } 21995}( 21996 function( $ ) { 21997 'use strict'; 21998 21999 var JSON = window.JSON; 22000 var globals; 22001 var Mask = function( el, mask, options ) { 22002 var jMask = this; 22003 var regexMask; 22004 var oldValue; 22005 22006 var p = { 22007 invalid: [], 22008 getCaret: function() { 22009 var sel, 22010 pos = 0, 22011 ctrl, 22012 dSel, 22013 cSelStart; 22014 try { 22015 ctrl = el.get( 0 ); 22016 dSel = document.selection; 22017 cSelStart = ctrl.selectionStart; 22018 22019 // IE Support 22020 if ( dSel && navigator.appVersion.indexOf( 'MSIE 10' ) === -1 ) { 22021 sel = dSel.createRange(); 22022 sel.moveStart( 'character', -p.val().length ); 22023 pos = sel.text.length; 22024 } else if ( cSelStart || cSelStart === '0' ) { // Firefox support 22025 pos = cSelStart; 22026 } 22027 22028 return pos; 22029 } catch ( err ) { 22030 window.console.log( err ); 22031 } 22032 }, 22033 setCaret: function( pos ) { 22034 var range; 22035 var ctrl; 22036 try { 22037 if ( el.is( ':focus' ) ) { 22038 ctrl = el.get( 0 ); 22039 22040 // Firefox, WebKit, etc.. 22041 if ( ctrl.setSelectionRange ) { 22042 ctrl.setSelectionRange( pos, pos ); 22043 } else { 22044 // IE 22045 range = ctrl.createTextRange(); 22046 range.collapse( true ); 22047 range.moveEnd( 'character', pos ); 22048 range.moveStart( 'character', pos ); 22049 range.select(); 22050 } 22051 } 22052 } catch ( err ) { 22053 window.console.log( err ); 22054 } 22055 }, 22056 events: function() { 22057 el.on( 'keydown.mask', function( e ) { 22058 el.data( 'mask-keycode', e.keyCode || e.which );
22059 el.data( 'mask-previus-value', el.val() ); 22060 el.data( 'mask-previus-caret-pos', p.getCaret() ); 22061 p.maskDigitPosMapOld = p.maskDigitPosMap; 22062 } ) 22063 .on( $.jMaskGlobals.useInput ? 'input.mask' : 'keyup.mask', p.behaviour ) 22064 .on( 'paste.mask drop.mask', function() { 22065 setTimeout( function() { 22066 el.keydown().keyup(); 22067 }, 100 ); 22068 } ) 22069 .on( 'change.mask', function() { 22070 el.data( 'changed', true ); 22071 } ) 22072 .on( 'blur.mask', function() { 22073 if ( oldValue !== p.val() && ! el.data( 'changed' ) ) { 22074 el.trigger( 'change' ); 22075 } 22076 el.data( 'changed', false ); 22077 } ) 22078 // it's very important that this callback remains in this position 22079 // otherwhise oldValue it's going to work buggy 22080 .on( 'blur.mask', function() { 22081 oldValue = p.val(); 22082 } ) 22083 // select all text on focus 22084 .on( 'focus.mask', function( e ) { 22085 if ( options.selectOnFocus === true ) { 22086 $( e.target ).select(); 22087 } 22088 } ) 22089 // clear the value if it not complete the mask 22090 .on( 'focusout.mask', function() { 22091 if ( options.clearIfNotMatch && ! regexMask.test( p.val() ) ) { 22092 p.val( '' ); 22093 } 22094 } ); 22095 }, 22096 getRegexMask: function() { 22097 var maskChunks = [], 22098 translation, 22099 pattern, 22100 optional, 22101 recursive, 22102 oRecursive, 22103 r; 22104 var i; 22105 22106 for ( i = 0; i < mask.length; i += 1 ) { 22107 translation = jMask.translation[ mask.charAt( i ) ]; 22108 22109 if ( translation ) { 22110 pattern = translation.pattern.toString().replace( /.{1}$|^.{1}/g, '' ); 22111 optional = translation.optional; 22112 recursive = translation.recursive; 22113 22114 if ( recursive ) { 22115 maskChunks.push( mask.charAt( i ) ); 22116 oRecursive = { 22117 digit: mask.charAt( i ), 22118 pattern: pattern 22119 }; 22120 } else { 22121 maskChunks.push( ! optional && ! recursive ? pattern : pattern + '?' ); 22122 } 22123 } else { 22124 // eslint-disable-next-line no-useless-escape 22125 maskChunks.push( mask.charAt( i ).replace( /[-\/\\^$*+?.()|[\]{}]/g, '\\$&' ) ); 22126 } 22127 } 22128 22129 r = maskChunks.join( '' ); 22130 22131 if ( oRecursive ) { 22132 r = r.replace( new RegExp( '(' + oRecursive.digit + '(.*' + oRecursive.digit + ')?)' ), '($1)?' ).replace( new RegExp( oRecursive.digit, 'g' ), oRecursive.pattern ); 22133 } 22134 22135 return new RegExp( r ); 22136 }, 22137 destroyEvents: function() { 22138 el.off( [ 'input', 'keydown', 'keyup', 'paste', 'drop', 'blur', 'focusout', '' ].join( '.mask ' ) ); 22139 }, 22140 val: function( v ) { 22141 var isInput = el.is( 'input' ), 22142 method = isInput ? 'val' : 'text', 22143 r; 22144 22145 if ( arguments.length > 0 ) { 22146 if ( el[ method ]() !== v ) { 22147 el[ method ]( v ); 22148 } 22149 r = el; 22150 } else { 22151 r = el[ method ](); 22152 } 22153 22154 return r; 22155 }, 22156 calculateCaretPosition: function( oldVal ) { 22157 var newVal = p.getMasked(), 22158 caretPosNew = p.getCaret(); 22159 var caretPosOld, 22160 newValL, 22161 oldValL, 22162 maskDigitsBeforeCaret = 0, 22163 maskDigitsAfterCaret = 0, 22164 maskDigitsBeforeCaretAll = 0, 22165 maskDigitsBeforeCaretAllOld = 0, 22166 i = 0; 22167 var caretPos; 22168 if ( oldVal !== newVal ) { 22169 caretPosOld = el.data( 'mask-previus-caret-pos' ) || 0; 22170 newValL = newVal.length; 22171 oldValL = oldVal.length; 22172 22173 for ( i = caretPosNew; i < newValL; i += 1 ) { 22174 if ( ! p.maskDigitPosMap[ i ] ) { 22175 break; 22176 } 22177 maskDigitsAfterCaret = maskDigitsAfterCaret + 1; 22178 } 22179 22180 for ( i = caretPosNew - 1; i >= 0; i -= 1 ) { 22181 if ( ! p.maskDigitPosMap[ i ] ) { 22182 break; 22183 } 22184 maskDigitsBeforeCaret = maskDigitsBeforeCaret + 1; 22185 } 22186 22187 for ( i = caretPosNew - 1; i >= 0; i -= 1 ) { 22188 if ( p.maskDigitPosMap[ i ] ) { 22189 maskDigitsBeforeCaretAll = maskDigitsBeforeCaretAll + 1; 22190 } 22191 } 22192 22193 for ( i = caretPosOld - 1; i >= 0; i -= 1 ) { 22194 if ( p.maskDigitPosMapOld[ i ] ) { 22195 maskDigitsBeforeCaretAllOld = maskDigitsBeforeCaretAllOld + 1; 22196 } 22197 } 22198 22199 // if the cursor is at the end keep it there 22200 if ( caretPosNew > oldValL ) { 22201 caretPosNew = newValL * 10; 22202 } else if ( caretPosOld >
22202= caretPosNew && caretPosOld !== oldValL ) { 22203 if ( ! p.maskDigitPosMapOld[ caretPosNew ] ) { 22204 caretPos = caretPosNew; 22205 caretPosNew -= maskDigitsBeforeCaretAllOld - maskDigitsBeforeCaretAll; 22206 caretPosNew -= maskDigitsBeforeCaret; 22207 if ( p.maskDigitPosMap[ caretPosNew ] ) { 22208 caretPosNew = caretPos; 22209 } 22210 } 22211 } else if ( caretPosNew > caretPosOld ) { 22212 caretPosNew += maskDigitsBeforeCaretAll - maskDigitsBeforeCaretAllOld; 22213 caretPosNew += maskDigitsAfterCaret; 22214 } 22215 } 22216 return caretPosNew; 22217 }, 22218 behaviour: function( e ) { 22219 var keyCode = el.data( 'mask-keycode' ); 22220 var newVal; 22221 var oldVal; 22222 var caretPos; 22223 e = e || window.event; 22224 p.invalid = []; 22225 22226 if ( $.inArray( keyCode, jMask.byPassKeys ) === -1 ) { 22227 newVal = p.getMasked(); 22228 caretPos = p.getCaret(); 22229 oldVal = el.data( 'mask-previus-value' ) || ''; 22230 22231 // this is a compensation to devices/browsers that don't compensate 22232 // caret positioning the right way 22233 setTimeout( function() { 22234 p.setCaret( p.calculateCaretPosition( oldVal ) ); 22235 }, $.jMaskGlobals.keyStrokeCompensation ); 22236 22237 p.val( newVal ); 22238 p.setCaret( caretPos ); 22239 return p.callbacks( e ); 22240 } 22241 }, 22242 getMasked: function( skipMaskChars, val ) { 22243 var buf = [], 22244 value = val === undefined ? p.val() : val + '', 22245 m = 0, 22246 maskLen = mask.length, 22247 v = 0, 22248 valLen = value.length, 22249 offset = 1, 22250 addMethod = 'push', 22251 resetPos = -1, 22252 maskDigitCount = 0, 22253 maskDigitPosArr = [], 22254 lastMaskChar, 22255 check; 22256 var lastUntranslatedMaskChar; 22257 var maskDigit; 22258 var valDigit; 22259 var translation; 22260 var lastMaskCharDigit; 22261 var newVal; 22262 if ( options.reverse ) { 22263 addMethod = 'unshift'; 22264 offset = -1; 22265 lastMaskChar = 0; 22266 m = maskLen - 1; 22267 v = valLen - 1; 22268 check = function() { 22269 return m > -1 && v > -1; 22270 }; 22271 } else { 22272 lastMaskChar = maskLen - 1; 22273 check = function() { 22274 return m < maskLen && v < valLen; 22275 }; 22276 } 22277 22278 while ( check() ) { 22279 maskDigit = mask.charAt( m ); 22280 valDigit = value.charAt( v ); 22281 translation = jMask.translation[ maskDigit ]; 22282 22283 if ( translation ) { 22284 if ( valDigit.match( translation.pattern ) ) { 22285 buf[ addMethod ]( valDigit ); 22286 if ( translation.recursive ) { 22287 if ( resetPos === -1 ) { 22288 resetPos = m; 22289 } else if ( m === lastMaskChar && m !== resetPos ) { 22290 m = resetPos - offset; 22291 } 22292 22293 if ( lastMaskChar === resetPos ) { 22294 m -= offset; 22295 } 22296 } 22297 m += offset; 22298 } else if ( valDigit === lastUntranslatedMaskChar ) { 22299 // matched the last untranslated (raw) mask character that we encountered 22300 // likely an insert offset the mask character from the last entry; fall 22301 // through and only increment v 22302 maskDigitCount = maskDigitCount - 1; 22303 lastUntranslatedMaskChar = undefined; 22304 } else if ( translation.optional ) { 22305 m += offset; 22306 v -= offset; 22307 } else if ( translation.fallback ) { 22308 buf[ addMethod ]( translation.fallback ); 22309 m += offset; 22310 v -= offset; 22311 } else { 22312 p.invalid.push( { 22313 p: v, 22314 v: valDigit, 22315 e: translation.pattern 22316 } ); 22317 } 22318 v += offset; 22319 } else { 22320 if ( ! skipMaskChars ) { 22321 buf[ addMethod ]( maskDigit ); 22322 } 22323 22324 if ( valDigit === maskDigit ) { 22325 maskDigitPosArr.push( v ); 22326 v += offset; 22327 } else { 22328 lastUntranslatedMaskChar = maskDigit; 22329 maskDigitPosArr.push( v + maskDigitCount ); 22330 maskDigitCount = maskDigitCount + 1; 22331 } 22332 22333 m += offset; 22334 } 22335 } 22336 22337 lastMaskCharDigit = mask.charAt( lastMaskChar ); 22338 if ( maskLen === valLen + 1 && ! jMask.translation[ lastMaskCharDigit ] ) { 22339 buf.push( lastMaskCharDigit ); 22340 } 22341 22342 newVal = buf.join( '' ); 22343 p.mapMaskdigitPositions( newVal, maskDigitPosArr, valLen ); 22344 return newVal; 22345 }, 22346 mapMaskdigitPositions: function( newVal, maskDigitPosArr, valLen ) { 22347 var maskDiff = options.reverse ? newVal.length - valLen : 0; 22348 var i; 22349 p.maskDigitPosMap = {}; 22350 for ( i = 0; i < maskDigitPosArr.length; i += 1 ) { 22351 p.maskDigitPosMap[ maskDigitPosArr[ i ] + maskDiff ] = 1; 22352 } 22353 }, 22354 callbacks: function( e ) { 22355 var val = p.val(), 22356 changed = val !== oldValue, 22357 defaultArgs = [ val, e, el, options ], 22358 callback = function( name, criteria, args ) { 22359 if ( typeof options[ name ] === 'function' && criteria ) { 22360 options[ name ].apply( this, args ); 22361 } 22362 }; 22363 22364 callback( 'onChange', changed === true, defaultArgs ); 22365 callback( 'onKeyPress', changed === true, defaultArgs ); 22366 callback( 'onComplete', val.length === mask.length, defaultArgs ); 22367 callback( 'onInvalid', p.invalid.length > 0, [ val, e, el, p.invalid, options ] ); 22368 } 22369 }; 22370 22371 el = $( el ); 22372 22373 oldValue = p.val(); 22374 22375 mask = typeof mask === 'function' ? mask( p.val(), undefined, el, options ) : mask; 22376 22377 // public methods 22378 jMask.mask = mask; 22379 jMask.options = options; 22380 jMask.remove = function() { 22381 var caret = p.getCaret(); 22382 if ( jMask.options.placeholder ) { 22383 el.removeAttr( 'placeholder' ); 22384 } 22385 if ( el.data( 'mask-maxlength' ) ) { 22386 el.removeAttr( 'maxlength' ); 22387 } 22388 p.destroyEvents(); 22389 p.val( jMask.getCleanVal() ); 22390 p.setCaret( caret ); 22391 return el; 22392 }; 22393 22394 // get value without mask 22395 jMask.getCleanVal = function() { 22396 return p.getMasked( true ); 22397 }; 22398 22399 // get masked value without the value being in the input or element 22400 jMask.getMaskedVal = function( val ) { 22401 return p.getMasked( false, val ); 22402 }; 22403 22404 jMask.init = function( onlyMask ) { 22405 var i; 22406 var translation; 22407 var caret; 22408 var maxlength; 22409 22410 onlyMask = onlyMask || false; 22411 options = options || {}; 22412 22413 jMask.clearIfNotMatch = $.jMaskGlobals.clearIfNotMatch; 22414 jMask.byPassKeys = $.jMaskGlobals.byPassKeys; 22415 jMask.translation = $.extend( {}, $.jMaskGlobals.translation, options.translation ); 22416 22417 jMask = $.extend( true, {}
22417, jMask, options ); 22418 22419 regexMask = p.getRegexMask(); 22420 22421 if ( onlyMask ) { 22422 p.events(); 22423 p.val( p.getMasked() ); 22424 } else { 22425 if ( options.placeholder ) { 22426 el.attr( 'placeholder', options.placeholder ); 22427 } 22428 22429 // this is necessary, otherwise if the user submit the form 22430 // and then press the "back" button, the autocomplete will erase 22431 // the data. Works fine on IE9+, FF, Opera, Safari. 22432 if ( el.data( 'mask' ) ) { 22433 el.attr( 'autocomplete', 'off' ); 22434 } 22435 22436 // detect if is necessary let the user type freely. 22437 // for is a lot faster than forEach. 22438 for ( i = 0, maxlength = true; i < mask.length; i += 1 ) { 22439 translation = jMask.translation[ mask.charAt( i ) ]; 22440 if ( translation && translation.recursive ) { 22441 maxlength = false; 22442 break; 22443 } 22444 } 22445 22446 if ( maxlength ) { 22447 el.attr( 'maxlength', mask.length ).data( 'mask-maxlength', true ); 22448 } 22449 22450 p.destroyEvents(); 22451 p.events(); 22452 22453 caret = p.getCaret(); 22454 p.val( p.getMasked() ); 22455 p.setCaret( caret ); 22456 } 22457 }; 22458 22459 jMask.init( ! el.is( 'input' ) ); 22460 }; 22461 22462 var notSameMaskObject = function( field, mask, options ) { 22463 var maskObject = $( field ).data( 'mask' ), 22464 stringify = JSON.stringify, 22465 value = $( field ).val() || $( field ).text(); 22466 options = options || {}; 22467 try { 22468 if ( typeof mask === 'function' ) { 22469 mask = mask( value ); 22470 } 22471 return typeof maskObject !== 'object' || stringify( maskObject.options ) !== stringify( options ) || maskObject.mask !== mask; 22472 } catch ( err ) { 22473 window.console.log( err ); 22474 } 22475 }, 22476 HTMLAttributes = function() { 22477 var input = $( this ), 22478 options = {}, 22479 prefix = 'data-mask-', 22480 mask = input.attr( 'data-mask' ); 22481 22482 if ( input.attr( prefix + 'reverse' ) ) { 22483 options.reverse = true; 22484 } 22485 22486 if ( input.attr( prefix + 'clearifnotmatch' ) ) { 22487 options.clearIfNotMatch = true; 22488 } 22489 22490 if ( input.attr( prefix + 'selectonfocus' ) === 'true' ) { 22491 options.selectOnFocus = true; 22492 } 22493 22494 if ( input.attr( prefix + 'placeholder' ) ) { 22495 options.placeholder = input.attr( prefix + 'placeholder' ); 22496 } 22497 22498 if ( notSameMaskObject( input, mask, options ) ) { 22499 return input.data( 'mask', new Mask( this, mask, options ) ); 22500 } 22501 }, 22502 eventSupported = function( eventName ) { 22503 var el = document.createElement( 'div' ), 22504 isSupported; 22505 22506 eventName = 'on' + eventName; 22507 isSupported = eventName in el; 22508 22509 if ( ! isSupported ) { 22510 el.setAttribute( eventName, 'return;' ); 22511 isSupported = typeof el[ eventName ] === 'function'; 22512 } 22513 el = null; 22514 22515 return isSupported; 22516 }; 22517 22518 $.maskWatchers = {}; 22519 22520 $.fn.mask = function( mask, options ) { 22521 var selector = this.selector, 22522 maskGlobals = $.jMaskGlobals, 22523 interval = maskGlobals.watchInterval, 22524 watchInputs, 22525 maskFunction; 22526 options = options || {}; 22527 22528 watchInputs = options.watchInputs || maskGlobals.watchInputs; 22529 maskFunction = function() { 22530 if ( notSameMaskObject( this, mask, options ) ) { 22531 return $( this ).data( 'mask', new Mask( this, mask, options ) ); 22532 } 22533 }; 22534 22535 $( this ).each( maskFunction ); 22536 22537 if ( selector && selector !== '' && watchInputs ) { 22538 clearInterval( $.maskWatchers[ selector ] ); 22539 $.maskWatchers[ selector ] = setInterval( function() { 22540 $( document ).find( selector ).each( maskFunction ); 22541 }, interval ); 22542 } 22543 return this; 22544 }; 22545 22546 $.fn.masked = function( val ) { 22547 return this.data( 'mask' ).getMaskedVal( val ); 22548 }; 22549 22550 $.fn.unmask = function() { 22551 clearInterval( $.maskWatchers[ this.selector ] ); 22552 delete $.maskWatchers[ this.selector ]; 22553 return this.each( function() { 22554 var dataMask = $( this ).data( 'mask' ); 22555 if ( dataMask ) { 22556 dataMask.remove().removeData( 'mask' ); 22557 } 22558 } ); 22559 }; 22560 22561 $.fn.cleanVal = function() { 22562 return this.data( 'mask' ).getCleanVal(); 22563 }; 22564 22565 $.applyDataMask = function( selector ) { 22566 var $selector; 22567 selector = selector || $.jMaskGlobals.maskElements; 22568 $selector = selector instanceof $ ? selector : $( selector ); 22569 $selector.filter( $.jMaskGlobals.dataMaskAttr ).each( HTMLAttributes ); 22570 }; 22571 22572 globals = { 22573 maskElements: 'input,td,span,div', 22574 dataMaskAttr: '*[data-mask]', 22575 dataMask: true, 22576 watchInterval: 300, 22577 watchInputs: true, 22578 keyStrokeCompensation: 10, 22579 // old versions of chrome dont work great with input event 22580 useInput: ! /Chrome\/[2-4][0-9]|SamsungBrowser/.test( window.navigator.userAgent ) && eventSupported( 'input' ), 22581 watchDataMask: false, 22582 byPassKeys: [ 9, 16, 17, 18, 36, 37, 38, 39, 40, 91 ], 22583 translation: { 22584 0: { pattern: /\d/ }, 22585 9: { pattern: /\d/, optional: true }, 22586 '#': { pattern: /\d/, recursive: true }, 22587 A: { pattern: /[a-zA-Z0-9]/ }, 22588 S: { pattern: /[a-zA-Z]/ } 22589 } 22590 }; 22591 22592 $.jMaskGlobals = $.jMaskGlobals || {}; 22593 globals = $.jMaskGlobals = $.extend( true, {}, globals, $.jMaskGlobals ); 22594 22595 // looking for inputs with data-mask attribute 22596 if ( globals.dataMask ) { 22597 $.applyDataMask(); 22598 } 22599 22600 setInterval( function() { 22601 if ( $.jMaskGlobals.watchDataMask ) { 22602 $.applyDataMask(); 22603 } 22604 }, globals.watchInterval ); 22605 }, 22606 window.jQuery, 22607 window.Zepto 22608) ); 22609; 22610 22611/*jshint esversion: 6 */ 22612( function( window ) { 22613 'use strict'; 22614 22615 var isNumber = function( str ) { 22616 return String( str ).isNumeric() && ! String( str ).startsWith( '0' ); 22617 }; 22618 22619 var empty = function( mixedVar ) { 22620 var undef; 22621 var key; 22622 var i; 22623 var len; 22624 var emptyValues = [ undef, null, false, 0, '', '0' ]; 22625 for ( i = 0, len = emptyValues.length; i < len; i++ ) { 22626 if ( mixedVar === emptyValues[ i ] ) { 22627 return true; 22628 } 22629 } 22630 if ( typeof mixedVar === 'object' ) { 22631 for ( key in mixedVar ) { 22632 if ( mixedVar.hasOwnProperty( key ) ) { 22633 return false;
22634 } 22635 } 22636 return true; 22637 } 22638 return false; 22639 }; 22640 22641 var array_key_exists = function( key, search ) { 22642 if ( ! search || ( search.constructor !== Array && search.constructor !== Object ) ) { 22643 return false; 22644 } 22645 return key in search; 22646 }; 22647 22648 var getNumberOfParameters = function( func ) { 22649 const ARROW = true; 22650 const FUNC_ARGS = ARROW ? /^(function)?\s*[^\(]*\(\s*([^\)]*)\)/m : /^(function)\s*[^\(]*\(\s*([^\)]*)\)/m; 22651 const FUNC_ARG_SPLIT = /,/; 22652 const FUNC_ARG = /^\s*(_?)(.+?)\1\s*$/; 22653 const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; 22654 22655 return ( ( func || '' ) 22656 .toString() 22657 .replace( STRIP_COMMENTS, '' ) 22658 .match( FUNC_ARGS ) || [ '', '', '' ] )[ 2 ] 22659 .split( FUNC_ARG_SPLIT ) 22660 .map( function( arg ) { 22661 return arg.replace( FUNC_ARG, function( all, underscore, name ) { 22662 return name.split( '=' )[ 0 ].trim(); 22663 } ); 22664 } ) 22665 .filter( String ) 22666 .length; 22667 }; 22668 22669 var getNumberOfRequiredParameters = function( func ) { 22670 return func.length; 22671 }; 22672 22673 var is_scalar = function( mixedVar ) { 22674 return ( /boolean|number|string/ ).test( typeof mixedVar ); 22675 }; 22676 22677 var gettype = function( obj ) { 22678 return window.jQuery.epoAPI.util.getType( obj ); 22679 }; 22680 22681 var floatval = function( s, d ) { 22682 var n; 22683 22684 if ( ! ( typeof s === 'string' || typeof s === 'number' ) || isNaN( s ) ) { 22685 if ( d !== undefined ) { 22686 return d; 22687 } 22688 return 0; 22689 } 22690 n = parseFloat( s ); 22691 if ( isNaN( n ) ) { 22692 if ( d !== undefined ) { 22693 return d; 22694 } 22695 return s; 22696 } 22697 22698 return n; 22699 }; 22700 22701 var strcmp = function( str1, str2 ) { 22702 return ( ( str1 === str2 ) ? 0 : ( ( str1 > str2 ) ? 1 : -1 ) ); 22703 }; 22704 22705 var bindec = function( binaryString ) { 22706 binaryString = ( binaryString + '' ).replace( /[^01]/gi, '' ); 22707 return parseInt( binaryString, 2 ); 22708 }; 22709 22710 var decbin = function( number ) { 22711 if ( number < 0 ) { 22712 number = 0xFFFFFFFF + number + 1; 22713 } 22714 return parseInt( number, 10 ).toString( 2 ); 22715 }; 22716 22717 var dechex = function( number ) { 22718 if ( number < 0 ) { 22719 number = 0xFFFFFFFF + number + 1; 22720 } 22721 return parseInt( number, 10 ).toString( 16 ); 22722 }; 22723 22724 var decoct = function( number ) { 22725 if ( number < 0 ) { 22726 number = 0xFFFFFFFF + number + 1; 22727 } 22728 return parseInt( number, 10 ).toString( 8 ); 22729 }; 22730 22731 var deg2rad = function( angle ) { 22732 return angle * 0.017453292519943295; // (angle / 180) * Math.PI; 22733 }; 22734 22735 var roundWithPrecision = function( num, dec = 0 ) { 22736 var num_sign = num >= 0 ? 1 : -1; 22737 return dec === 0 ? Math.round( num ) : parseFloat( ( Math.round( ( num * Math.pow( 10, dec ) ) + ( num_sign * 0.0001 ) ) / Math.pow( 10, dec ) ).toFixed( dec ) ); 22738 }; 22739 22740 var hexdec = function( hexString ) { 22741 hexString = ( hexString + '' ).replace( /[^a-f0-9]/gi, '' ); 22742 return parseInt( hexString, 16 ); 22743 }; 22744 22745 var octdec = function( octString ) { 22746 octString = ( octString + '' ).replace( /[^0-7]/gi, '' ); 22747 return parseInt( octString, 8 ); 22748 }; 22749 22750 var hypot = function( x, y ) { 22751 var t; 22752 x = Math.abs( x ); 22753 y = Math.abs( y ); 22754 t = Math.min( x, y ); 22755 x = Math.max( x, y ); 22756 t = t / x; 22757 return x * Math.sqrt( 1 + ( t * t ) ) || null; 22758 }; 22759 22760 var THEMECOMPLETE_EPO_MATH = { 22761 variables: {}, 22762 on_var_not_found: undefined,
22763 on_var_validation: undefined, 22764 operators: {}, 22765 functions: {}, 22766 cache: {}, 22767 construct: function() { 22768 this.add_defaults(); 22769 this.set_division_by_zero_to_zero(); 22770 return this; 22771 }, 22772 add_operator: function( $operator ) { 22773 this.operators[ $operator.operator ] = $operator; 22774 return this; 22775 }, 22776 evaluate: function( $expression, $cache = true ) { 22777 return this.execute( $expression, $cache ); 22778 }, 22779 parse: function( $expression ) { 22780 var $tokens; 22781 var result; 22782 var $calculator; 22783 var count = 0; 22784 var char; 22785 22786 for ( char of $expression ) { 22787 if ( char === '(' ) { 22788 count++; 22789 } else if ( char === ')' ) { 22790 count--; 22791 } 22792 22793 // If count becomes negative at any point, return false 22794 if ( count < 0 ) { 22795 return false; 22796 } 22797 } 22798 22799 // If count is not zero at the end, parentheses are not balanced 22800 if ( count !== 0 ) { 22801 return false; 22802 } 22803 22804 $tokens = new THEMECOMPLETE_EPO_MATH_Tokenizer( $expression, this.operators ); 22805 $tokens = $tokens.tokenize().build_reverse_polish_notation(); 22806 $calculator = new THEMECOMPLETE_EPO_MATH_Calculator( this.functions, this.operators ); 22807 22808 result = $calculator.calculate( $tokens, this.variables, this.on_var_not_found, this ); 22809 if ( 'number' !== gettype( result ) || isNaN( result ) ) { 22810 return false; 22811 } 22812 return result; 22813 }, 22814 execute: function( $expression, $cache = true, $canreturnstring = false ) { 22815 var $cache_key = $expression; 22816 var $calculator; 22817 var $tokens; 22818 var result; 22819 22820 if ( ! array_key_exists( $cache_key, this.cache ) ) { 22821 $tokens = new THEMECOMPLETE_EPO_MATH_Tokenizer( $expression, this.operators ); 22822 $tokens = $tokens.tokenize().build_reverse_polish_notation(); 22823 if ( $cache ) { 22824 this.cache[ $cache_key ] = $tokens; 22825 } 22826 } else { 22827 $tokens = this.cache[ $cache_key ]; 22828 } 22829 22830 $calculator = new THEMECOMPLETE_EPO_MATH_Calculator( this.functions, this.operators ); 22831 22832 result = $calculator.calculate( $tokens, this.variables, this.on_var_not_found, this ); 22833 22834 if ( false === $canreturnstring && ( 'number' !== gettype( result ) || isNaN( result ) ) ) { 22835 result = 0; 22836 } 22837 22838 return result; 22839 }, 22840 add_function: function( $name, $function ) { 22841 this.functions[ $name ] = new THEMECOMPLETE_EPO_MATH_CustomFunction( $name, $function ); 22842 return this; 22843 }, 22844 get_vars: function() { 22845 return this.variables; 22846 }, 22847 get_var: function( $variable ) { 22848 if ( ! array_key_exists( $variable, this.variables ) ) { 22849 if ( this.on_var_not_found && 'function' === typeof this.on_var_not_found ) { 22850 this.on_var_not_found( $variable ); 22851 } 22852 return THEMECOMPLETE_EPO_MATH_Error.trigger( 'Variable (' + $variable + ') not set', 'UnknownVariableError', 0 ); 22853 } 22854 return this.variables[ $variable ]; 22855 }, 22856 set_var: function( $variable, $value ) {
22857 if ( this.on_var_validation && 'function' === typeof this.on_var_validation ) { 22858 $value = this.on_var_validation( $variable, $value ); 22859 } 22860 this.variables[ $variable ] = $value; 22861 return this; 22862 }, 22863 var_exists: function( $variable ) { 22864 return array_key_exists( $variable, this.variables ); 22865 }, 22866 set_vars: function( $variables, $clear = true ) { 22867 var $this = this; 22868 if ( $clear ) { 22869 this.remove_vars(); 22870 } 22871 $variables.forFach( function( $value, $name ) { 22872 $this.set_var( $name, $value ); 22873 } ); 22874 return this; 22875 }, 22876 set_var_not_found_handler: function( $handler ) { 22877 this.on_var_not_found = $handler; 22878 return this; 22879 }, 22880 set_var_validation_handler: function( $handler ) { 22881 this.on_var_validation = $handler; 22882 return this; 22883 }, 22884 remove_var: function( $variable ) { 22885 delete this.variables[ $variable ]; 22886 return this; 22887 }, 22888 remove_vars: function() { 22889 this.variables = {}; 22890 this.on_var_not_found = null; 22891 return this; 22892 }, 22893 get_operators: function() { 22894 return this.operators; 22895 }, 22896 get_functions: function() { 22897 return this.functions; 22898 }, 22899 remove_operator: function( $operator ) { 22900 delete this.operators[ $operator ]; 22901 }, 22902 set_division_by_zero_to_zero: function() { 22903 this.add_operator( 22904 new THEMECOMPLETE_EPO_MATH_Operator( 22905 '/', 22906 false, 22907 180, 22908 function( $a, $b ) { 22909 $a = Number( $a ); 22910 $b = Number( $b ); 22911 return 0 == $b ? 0 : $a / $b; // eslint-disable-line eqeqeq 22912 } 22913 ) 22914 ); 22915 return this; 22916 }, 22917 get_cache: function() { 22918 return this.cache; 22919 }, 22920 clear_cache: function() { 22921 this.cache = []; 22922 }, 22923 add_defaults: function() { 22924 var $this = this; 22925 var default_operators = this.default_operators(); 22926 var default_functions = this.default_functions(); 22927 Object.keys( default_operators ).forEach( function( $name ) { 22928 var $operator = default_operators[ $name ]; 22929 $this.add_operator( new THEMECOMPLETE_EPO_MATH_Operator( $name, $operator[ 2 ], $operator[ 1 ], $operator[ 0 ] ) ); 22930 } ); 22931 Object.keys( default_functions ).forEach( function( $name ) { 22932 var $callable = default_functions[ $name ]; 22933 $this.add_function( $name, $callable ); 22934 } );
22935 this.on_var_validation = this.default_var_validation; 22936 this.variables = this.default_vars(); 22937 return this; 22938 }, 22939 default_operators: function() { 22940 return { 22941 '+': [ 22942 function( $a, $b ) { 22943 $a = floatval( $a, 0 ); 22944 $b = floatval( $b, 0 ); 22945 return $a + $b; 22946 }, 22947 170, 22948 false 22949 ], 22950 '-': [ 22951 function( $a, $b ) { 22952 $a = floatval( $a, 0 ); 22953 $b = floatval( $b, 0 ); 22954 return $a - $b; 22955 }, 22956 170, 22957 false 22958 ], 22959 // unary positive token. 22960 uPos: [ 22961 function( $a ) { 22962 $a = floatval( $a, 0 ); 22963 return $a; 22964 }, 22965 200, 22966 false 22967 ], 22968 // unary minus token. 22969 uNeg: [ 22970 function( $a ) { 22971 $a = floatval( $a, 0 ); 22972 return 0 - $a; 22973 }, 22974 200, 22975 false 22976 ], 22977 '*': [ 22978 function( $a, $b ) { 22979 $a = floatval( $a, 0 ); 22980 $b = floatval( $b, 0 ); 22981 return $a * $b; 22982 }, 22983 180, 22984 false 22985 ], 22986 '/': [ 22987 function( $a, $b ) { 22988 $a = floatval( $a, 0 ); 22989 $b = floatval( $b, 0 ); 22990 if ( empty( $b ) ) { 22991 return THEMECOMPLETE_EPO_MATH_Error.trigger( 'Division By Zero', 'DivisionByZeroError', 0 ); 22992 } 22993 return $a / $b; 22994 }, 22995 180, 22996 false 22997 ], 22998 '^': [ 22999 function( $a, $b ) { 23000 $a = floatval( $a, 0 ); 23001 $b = floatval( $b, 0 ); 23002 return Math.pow( $a, $b ); 23003 }, 23004 220, 23005 true 23006 ], 23007 '%': [ 23008 function( $a, $b ) { 23009 $a = floatval( $a, 0 ); 23010 $b = floatval( $b, 0 ); 23011 return $a % $b; 23012 }, 23013 180, 23014 false 23015 ], 23016 '&&': [ 23017 function( $a, $b ) { 23018 $a = String( $a ); 23019 $b = String( $b ); 23020 if ( $a.isNumeric() ) { 23021 $a = floatval( $a, 0 ); 23022 } 23023 if ( $b.isNumeric() ) { 23024 $b = floatval( $b, 0 ); 23025 } 23026 return $a && $b ? 1 : 0; 23027 }, 23028 100, 23029 false 23030 ], 23031 '||': [ 23032 function( $a, $b ) { 23033 $a = String( $a ); 23034 $b = String( $b ); 23035 if ( $a.isNumeric() ) { 23036 $a = floatval( $a, 0 ); 23037 } 23038 if ( $b.isNumeric() ) { 23039 $b = floatval( $b, 0 ); 23040 } 23041 return $a || $b ? 1 : 0; 23042 }, 23043 90, 23044 false 23045 ], 23046 '==': [ 23047 function( $a, $b ) { 23048 $a = String( $a ); 23049 $b = String( $b ); 23050 if ( $a.isNumeric() && $b.isNumeric() ) { 23051 return floatval( $a ) === floatval( $b ) ? 1 : 0; 23052 } 23053 return 0 === strcmp( $a, $b ) ? 1 : 0; 23054 }, 23055 140, 23056 false 23057 ], 23058 '!=': [ 23059 function( $a, $b ) { 23060 $a = String( $a ); 23061 $b = String( $b ); 23062 if ( $a.isNumeric() && $b.isNumeric() ) { 23063 return floatval( $a ) !== floatval( $b ) ? 1 : 0; 23064 } 23065 return 0 !== strcmp( $a, $b ) ? 1 : 0; 23066 }, 23067 140, 23068 false 23069 ], 23070 '>=': [ 23071 function( $a, $b ) { 23072 $a = String( $a ); 23073 $b = String( $b ); 23074 if ( $a.isNumeric() ) { 23075 $a = floatval( $a, 0 ); 23076 } 23077 if ( $b.isNumeric() ) { 23078 $b = floatval( $b, 0 ); 23079 } 23080 return $a >= $b ? 1 : 0; 23081 }, 23082 150, 23083 false 23084 ], 23085 '>': [ 23086 function( $a, $b ) { 23087 $a = String( $a ); 23088 $b = String( $b ); 23089 if ( $a.isNumeric() ) { 23090 $a = floatval( $a, 0 ); 23091 } 23092 if ( $b.isNumeric() ) { 23093 $b = floatval( $b, 0 ); 23094 } 23095 return $a > $b ? 1 : 0; 23096 }, 23097 150, 23098 false 23099 ], 23100 '<=': [ 23101 function( $a, $b ) { 23102 $a = String( $a ); 23103 $b = String( $b ); 23104 if ( $a.isNumeric() ) { 23105 $a = floatval( $a, 0 ); 23106 } 23107 if ( $b.isNumeric() ) { 23108 $b = floatval( $b, 0 ); 23109 } 23110 return $a <= $b ? 1 : 0; 23111 }, 23112 150, 23113 false 23114 ], 23115 '<': [ 23116 function( $a, $b ) { 23117 $a = String( $a ); 23118 $b = String( $b ); 23119 if ( $a.isNumeric() ) { 23120 $a = floatval( $a, 0 ); 23121 } 23122 if ( $b.isNumeric() ) { 23123 $b = floatval( $b, 0 ); 23124 } 23125 return $a < $b ? 1 : 0; 23126 }, 23127 150, 23128 false 23129 ] 23130 }; 23131 }, 23132 default_functions: function() { 23133 var $this = this; 23134 return { 23135 abs: Math.abs, 23136 acos: Math.acos, 23137 acosh: Math.acosh, 23138 arcsin: Math.asin, 23139 arcctg: function( $arg ) { 23140 return ( Math.PI / 2 ) - Math.atan( $arg ); 23141 }, 23142 arccot: function( $arg ) { 23143 return ( Math.PI / 2 ) - Math.atan( $arg ); 23144 }, 23145 arccotan: function( $arg ) { 23146 return ( Math.PI / 2 ) - Math.atan( $arg ); 23147 }, 23148 arcsec: function( $arg ) { 23149 return Math.acos( 1 / $arg ); 23150 }, 23151 arccosec: function( $arg ) { 23152 return Math.asin( 1 / $arg ); 23153 }, 23154 arccsc: function( $arg ) { 23155 return Math.asin( 1 / $arg ); 23156 }, 23157 arccos: Math.acos, 23158 arctan: Math.atan, 23159 arctg: Math.atan, 23160 array: function( ...$args ) { 23161 return $args; 23162 }, 23163 asin: Math.asin, 23164 atan: Math.atan, 23165 atan2: Math.atan2, 23166 atanh: Math.atanh, 23167 atn: Math.atan, 23168 23169 avg: function( $arg1, ...$args ) { 23170 var sum; 23171 if ( Array.isArray( $arg1 ) ) { 23172 if ( 0 === $arg1.length ) { 23173 return THEMECOMPLETE_EPO_MATH_Error.trigger( 'Array must contain at least one element!', 'InvalidArgumentError', 0 ); 23174 } 23175 } 23176 $args = [].concat.apply( [], [ $arg1, ...$args ] ); 23177 23178 sum = $args.reduce( function( previousValue, currentValue ) { 23179 return floatval( currentValue, 0 ) + floatval( previousValue, 0 ); 23180 } ); 23181 return sum / $args.length; 23182 }, 23183 average: function( $arg1, ...$args ) { 23184 var sum; 23185 if ( Array.isArray( $arg1 ) ) { 23186 if ( 0 === $arg1.length ) { 23187 return THEMECOMPLETE_EPO_MATH_Error.trigger( 'Array must contain at least one element!', 'InvalidArgumentError', 0 ); 23188 } 23189 } 23190 $args = [].concat.apply( [], [ $arg1, ...$args ] ); 23191 23192 sum = $args.reduce( function( previousValue, currentValue ) { 23193 return floatval( currentValue, 0 ) + floatval( previousValue, 0 ); 23194 } ); 23195 return sum / $args.length; 23196 }, 23197 bindec: bindec, 23198 ceil: Math.ceil, 23199 cos: Math.cos, 23200 cosec: function( $arg ) { 23201 return Math.sin( 1 / $arg ); 23202 }, 23203 csc: function( $arg ) { 23204 return Math.sin( 1 / $arg ); 23205 }, 23206 cosh: Math.cosh, 23207 ctg: function( $arg ) { 23208 return Math.cos( $arg ) / Math.sin( $arg ); 23209 }, 23210 cot: function( $arg ) { 23211 return Math.cos( $arg ) / Math.sin( $arg ); 23212 }, 23213 cotan: function( $arg ) { 23214 return Math.cos( $arg ) / Math.sin( $arg ); 23215 }, 23216 cotg: function( $arg ) { 23217 return Math.cos( $arg ) / Math.sin( $arg ); 23218 }, 23219 ctn: function( $arg ) { 23220 return Math.cos( $arg ) / Math.sin( $arg ); 23221 }, 23222 decbin: decbin, 23223 dechex: dechex, 23224 decoct: decoct, 23225 deg2rad: deg2rad, 23226 exp: Math.exp, 23227 expm1: Math.expm1, 23228 floor: Math.floor, 23229 int: Math.floor, 23230 fmod: function( $arg1, $arg2 ) { 23231 return $arg1 % $arg2; 23232 }, 23233 hexdec: hexdec, 23234 hypot: hypot, 23235 if: function( ...$args ) { 23236 var $exres; 23237 var $expr; 23238 var $trueval; 23239 var $falseval; 23240 var $canreturnstring; 23241 $expr = $args[ 0 ]; 23242 $trueval = $args[ 1 ]; 23243 $falseval = $args[ 2 ]; 23244 if ( 'string' === gettype( $trueval ) ) { 23245 $trueval = "'" + $trueval.replace( /'/g, "\\'" ) + "'"; 23246 }
23247 if ( 'string' === gettype( $falseval ) ) { 23248 $falseval = "'" + $falseval.replace( /'/g, "\\'" ) + "'"; 23249 } 23250 $canreturnstring = $args[ 3 ] !== undefined ? $args[ 3 ] : false; 23251 if ( 0 === $expr || 1 === $expr || true === $expr || false === $expr ) { 23252 $exres = $expr; 23253 } else { 23254 $exres = $this.execute( $expr, true, $canreturnstring ); 23255 } 23256 if ( $exres ) { 23257 return $this.execute( $trueval, true, $canreturnstring ); 23258 } 23259 return $this.execute( $falseval, true, $canreturnstring ); 23260 }, 23261 intdiv: function( $arg1, $arg2 ) { 23262 return Math.trunc( Math.trunc( $arg1 ) / Math.trunc( $arg2 ) ); 23263 }, 23264 ln: Math.log, 23265 lg: Math.log10, 23266 log: Math.log, 23267 log1p: Math.log1p, 23268 max: function( $arg1, ...$args ) { 23269 var $array; 23270 if ( Array.isArray( $arg1 ) && 0 === $arg1.length ) { 23271 return THEMECOMPLETE_EPO_MATH_Error.trigger( 'Array must contain at least one element!', 'InvalidArgumentError', 0 ); 23272 } 23273 $array = Array.isArray( $arg1 ) ? $arg1 : [ $arg1, ...$args ]; 23274 $array = $array.map( floatval ); 23275 23276 return Math.max( ...$array ); 23277 }, 23278 min: function( $arg1, ...$args ) { 23279 var $array; 23280 if ( Array.isArray( $arg1 ) && 0 === $arg1.length ) { 23281 return THEMECOMPLETE_EPO_MATH_Error.trigger( 'Array must contain at least one element!', 'InvalidArgumentError', 0 ); 23282 } 23283 $array = Array.isArray( $arg1 ) ? $arg1 : [ $arg1, ...$args ]; 23284 $array = $array.map( floatval ); 23285 23286 return Math.min( ...$array ); 23287 }, 23288 octdec: octdec, 23289 pi: function() { 23290 return Math.PI; 23291 }, 23292 pow: Math.pow, 23293 rad2deg: function( angle ) { 23294 return angle * 57.29577951308232; // angle / Math.PI * 180 23295 }, 23296 round: roundWithPrecision, 23297 sin: Math.sin, 23298 sinh: Math.sinh, 23299 sec: function( $arg ) { 23300 return 1 / Math.cos( $arg ); 23301 }, 23302 sqrt: Math.sqrt, 23303 tan: Math.tan, 23304 tanh: Math.tanh, 23305 tn: Math.tan, 23306 tg: Math.tan, 23307 lookuptable: function( field, lookupTableId ) { 23308 var lookupTables; 23309 var x; 23310 var y; 23311 var table; 23312 var xColumn; 23313 var price = 0; 23314 var tableNum = 0; 23315 var TMEPOJS = window.TMEPOJS; 23316 23317 if ( TMEPOJS ) { 23318 lookupTables = window.jQuery.epoAPI.util.parseJSON( TMEPOJS.lookupTables ); 23319 if ( lookupTables ) { 23320 if ( Array.isArray( lookupTableId ) ) { 23321 tableNum = lookupTableId[ 1 ]; 23322 lookupTableId = lookupTableId[ 0 ]; 23323 } 23324 if ( empty( lookupTableId ) ) { 23325 return 0; 23326 } 23327 if ( empty( tableNum ) ) { 23328 tableNum = 0; 23329 } 23330 if ( Array.isArray( field ) ) { 23331 x = String( field[ 0 ] ); 23332 y = String( field[ 1 ] ); 23333 } else { 23334 x = String( field ); 23335 y = ''; 23336 } 23337 23338 table = lookupTables[ lookupTableId ]; 23339 if ( table ) { 23340 table = table[ tableNum ]; 23341 if ( table ) { 23342 table = table.data; 23343 xColumn = table[ x ]; 23344 if ( xColumn === undefined && x && x !== undefined ) { 23345 if ( x.isNumeric() && floatval( x ) === 0 ) { 23346 xColumn = table[ Object.keys( table )[ 0 ] ]; 23347 } else if ( x ) { 23348 x = $this.find_lookup_table_index( x, table ); 23349 xColumn = table[ x ]; 23350 } 23351 } 23352 if ( xColumn !== undefined ) { 23353 if ( y && y !== undefined ) { 23354 y = $this.find_lookup_table_index( y, xColumn ); 23355 } else { 23356 // fetch the first row since this means we want 23357 // a single row result 23358 y = Object.keys( xColumn )[ 0 ]; 23359 } 23360 if ( y === 'max' ) { 23361 price = floatval( xColumn[ Object.keys( xColumn )[ Object.keys( xColumn ).length - 1 ] ] ); 23362 } else { 23363 price = floatval( xColumn[ y ] ); 23364 } 23365 } 23366 } 23367 } 23368 } 23369 } 23370 return price; 23371 }, 23372 concat: function( $arg1, ...$args ) { 23373 var $array; 23374 if ( Array.isArray( $arg1 ) && 0 === $arg1.length ) { 23375 return THEMECOMPLETE_EPO_MATH_Error.trigger( 'Array must contain at least one element!', 'InvalidArgumentError', 0 ); 23376 } 23377 $array = Array.isArray( $arg1 ) ? $arg1 : [ $arg1, ...$args ]; 23378 23379 return $array.join( '' ); 23380 } 23381 }; 23382 }, 23383 find_lookup_table_index: function( value, table ) { 23384 var r; 23385 var keys = Object.keys( table ); 23386 var hasNumericValuesOrMaxLast = function( arr ) { 23387 var lastElement = arr[ arr.length - 1 ]; 23388 var areAllNumericValues = arr.every( function( val ) { 23389 return String( val ).isNumeric(); 23390 } ); 23391 return areAllNumericValues || lastElement === 'max'; 23392 }; 23393 23394 if ( hasNumericValuesOrMaxLast( keys ) ) { 23395 value = isNumber( value ) ? floatval( value ) : value; 23396 r = keys.map( function( n ) { 23397 return isNumber( n ) ? floatval( n ) : n; 23398 } ).reduce( function( a, b ) { 23399 if ( b === 'max' && value > a ) { 23400 return b; 23401 } 23402 if ( a === 'max' && value > b ) { 23403 return a; 23404 } 23405 if ( a < b ) { 23406 if ( value > a && value <= b ) { 23407 return b; 23408 } 23409 } else { 23410 if ( ( value > b && value <= a ) || ( value > a || b === 'max' ) ) { 23411 return a; 23412 } 23413 return b; 23414 } 23415 if ( value > b ) { 23416 return b; 23417 } 23418 return a; 23419 } ); 23420 keys = keys.map( function( n ) { 23421 return isNumber( n ) ? floatval( n ) : n; 23422 } ); 23423 23424 if ( value > Math.max( ...keys ) || value < Math.min( ...keys ) ) { 23425 return false;
23426 } 23427 } else { 23428 r = value; 23429 } 23430 23431 return r; 23432 }, 23433 default_vars: function() { 23434 return { 23435 pi: 3.141592653589793, 23436 e: 2.718281828459045 23437 }; 23438 }, 23439 default_var_validation: function( $variable, $value ) { 23440 if ( ! is_scalar( $value ) && ! Array.isArray( $value ) && undefined !== $value ) { 23441 return THEMECOMPLETE_EPO_MATH_Error.trigger( 'Variable (' + $variable + ') type (' + gettype( $value ) + ') is not scalar or array!', 0 ); 23442 } 23443 return $value; 23444 } 23445 }; 23446 23447 var THEMECOMPLETE_EPO_MATH_Tokenizer = function( $input, $operators ) { 23448 var node = { 23449 tokens: [], 23450 input: '', 23451 operators: {}, 23452 number_buffer: '', 23453 string_buffer: '', 23454 allow_negative: true, 23455 in_single_quoted_string: false, 23456 in_double_quoted_string: false, 23457 is_number: function( ch ) { 23458 return ch >= '0' && ch <= '9'; 23459 }, 23460 is_alpha: function( ch ) { 23461 return ( ch >= 'a' && ch <= 'z' ) || ( ch >= 'A' && ch <= 'Z' ) || '_' === ch; 23462 }, 23463 is_dot: function( ch ) { 23464 return '.' === ch; 23465 }, 23466 is_lp: function( ch ) { 23467 return '(' === ch; 23468 }, 23469 is_rp: function( ch ) { 23470 return ')' === ch; 23471 }, 23472 is_comma: function( ch ) { 23473 return ',' === ch; 23474 }, 23475 empty_number_buffer_as_literal: function() { 23476 if ( this.number_buffer.length ) { 23477 this.tokens.push( THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.LITERAL, this.number_buffer ) ); 23478 this.number_buffer = ''; 23479 } 23480 }, 23481 empty_str_buffer_as_variable: function() { 23482 if ( '' !== this.string_buffer ) { 23483 this.tokens.push( THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.VARIABLE, this.string_buffer ) ); 23484 this.string_buffer = ''; 23485 } 23486 }, 23487 tokenize: function() { 23488 var is_last_char_escape = false;
23489 var $this = this; 23490 var $token_test = []; 23491 23492 this.tokens = []; 23493 23494 this.input.toString().split( '' ).forEach( function( ch ) { 23495 switch ( true ) { 23496 case $this.in_single_quoted_string: 23497 if ( '\\' === ch ) { 23498 if ( is_last_char_escape ) { 23499 $this.string_buffer += '\\'; 23500 is_last_char_escape = false; 23501 } else { 23502 is_last_char_escape = true; 23503 } 23504 break; 23505 } else if ( "'" === ch ) { 23506 if ( is_last_char_escape ) { 23507 $this.string_buffer += "'"; 23508 is_last_char_escape = false; 23509 } else { 23510 $this.tokens.push( THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.STRING, $this.string_buffer ) ); 23511 $this.in_single_quoted_string = false; 23512 $this.string_buffer = ''; 23513 } 23514 break; 23515 } 23516 if ( is_last_char_escape ) { 23517 $this.string_buffer += '\\'; 23518 is_last_char_escape = false; 23519 } 23520 $this.string_buffer += ch; 23521 break; 23522 case $this.in_double_quoted_string: 23523 if ( '\\' === ch ) { 23524 if ( is_last_char_escape ) { 23525 $this.string_buffer += '\\'; 23526 is_last_char_escape = false;
23527 } else { 23528 is_last_char_escape = true; 23529 } 23530 break; 23531 } else if ( '"' === ch ) { 23532 if ( is_last_char_escape ) { 23533 $this.string_buffer += '"'; 23534 is_last_char_escape = false; 23535 } else { 23536 $this.tokens.push( THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.STRING, $this.string_buffer ) ); 23537 $this.in_double_quoted_string = false; 23538 $this.string_buffer = ''; 23539 } 23540 break; 23541 } 23542 if ( is_last_char_escape ) { 23543 $this.string_buffer += '\\'; 23544 is_last_char_escape = false; 23545 } 23546 $this.string_buffer += ch; 23547 break; 23548 case '[' === ch: 23549 $this.tokens.push( THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.FUNCTION, 'array' ) ); 23550 $this.allow_negative = true; 23551 $this.tokens.push( THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.LEFTPARENTHESIS, '' ) ); 23552 break; 23553 case ' ' === ch || '\n' === ch || '\r' === ch || '\t' === ch: 23554 /** 23555 * In case those tokens must not be ingored use the following 23556 * 23557 * $this.empty_number_buffer_as_literal(); 23558 * $this.empty_str_buffer_as_variable(); 23559 * $this.tokens.push( THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.SPACE, '' ) ); 23560 */ 23561 break; 23562 case $this.is_number( ch ): 23563 if ( '' !== $this.string_buffer ) { 23564 $this.string_buffer += ch; 23565 break; 23566 } 23567 $this.number_buffer += ch; 23568 $this.allow_negative = false; 23569 break; 23570 case 'e' === ch.toLowerCase(): 23571 if ( $this.number_buffer.length && -1 !== $this.number_buffer.indexOf( '.' ) ) { 23572 $this.number_buffer += 'e'; 23573 $this.allow_negative = false; 23574 break; 23575 } 23576 /* falls through */ 23577 case $this.is_alpha( ch ): 23578 if ( $this.number_buffer.length ) { 23579 $this.empty_number_buffer_as_literal(); 23580 $this.tokens.push( THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.OPERATOR, '*' ) ); 23581 } 23582 $this.allow_negative = false; 23583 $this.string_buffer += ch; 23584 break; 23585 case '"' === ch: 23586 $this.in_double_quoted_string = true; 23587 break; 23588 case "'" === ch: 23589 $this.in_single_quoted_string = true; 23590 break; 23591 case $this.is_dot( ch ): 23592 $this.number_buffer += ch; 23593 $this.allow_negative = false; 23594 break; 23595 case $this.is_lp( ch ): 23596 if ( '' !== $this.string_buffer ) { 23597 $this.tokens.push( THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.FUNCTION, $this.string_buffer ) ); 23598 $this.string_buffer = ''; 23599 } else if ( $this.number_buffer.length ) { 23600 $this.empty_number_buffer_as_literal(); 23601 $this.tokens.push( THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.OPERATOR, '*' ) ); 23602 } 23603 $this.allow_negative = true; 23604 $this.tokens.push( THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.LEFTPARENTHESIS, ch ) ); 23605 break; 23606 case $this.is_rp( ch ) || ']' === ch : 23607 $this.empty_number_buffer_as_literal(); 23608 $this.empty_str_buffer_as_variable(); 23609 $this.allow_negative = false; 23610 $this.tokens.push( THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.RIGHTPARENTHESIS, ch ) ); 23611 break; 23612 case $this.is_comma( ch ): 23613 $this.empty_number_buffer_as_literal(); 23614 $this.empty_str_buffer_as_variable(); 23615 $this.allow_negative = true; 23616 $this.tokens.push( THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.PARAMSEPARATOR, ch ) ); 23617 break; 23618 default: 23619 // special case for unary operations. 23620 if ( '-' === ch || '+' === ch ) { 23621 if ( $this.allow_negative ) { 23622 $this.allow_negative = false; 23623 $this.tokens.push( THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.OPERATOR, '-' === ch ? 'uNeg' : 'uPos' ) ); 23624 break; 23625 } 23626 // could be in exponent, in which case negative should be added to the number_buffer. 23627 if ( $this.number_buffer && 'e' === $this.number_buffer[ $this.number_buffer.length - 1 ] ) { 23628 $this.number_buffer += ch; 23629 break; 23630 } 23631 } 23632 $this.empty_number_buffer_as_literal(); 23633 $this.empty_str_buffer_as_variable(); 23634 23635 if ( '$' !== ch ) { 23636 if ( $this.tokens.length > 0 ) { 23637 if ( THEMECOMPLETE_EPO_MATH_Constants.OPERATOR === $this.tokens[ $this.tokens.length - 1 ].type ) { 23638 $this.tokens[ $this.tokens.length - 1 ].value += ch; 23639 } else { 23640 $this.tokens.push( THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.OPERATOR, ch ) ); 23641 } 23642 } else { 23643 $this.tokens.push( THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.OPERATOR, ch ) ); 23644 } 23645 } 23646 $this.allow_negative = true; 23647 } 23648 } ); 23649 this.empty_number_buffer_as_literal(); 23650 this.empty_str_buffer_as_variable(); 23651 23652 this.tokens.forEach( function( $token, $key ) { 23653 $token_test[ $key ] = $token.type; 23654 } ); 23655 $token_test.forEach( function( $type, $key ) { 23656 if ( $key > 0 && 'space' === $type && 'variable' === $token_test[ $key + 1 ] && 'variable' === $token_test[ $key - 1 ] ) { 23657 $this.tokens[ $key ] = new THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.LITERAL, 0 ); 23658 $this.tokens.splice( $key + 1, 1 ); 23659 $this.tokens.splice( $key - 1, 1 ); 23660 } 23661 } ); 23662 return this; 23663 }, 23664 build_reverse_polish_notation: function() { 23665 var $tokens = []; 23666 var $stack = []; 23667 var $param_counter = []; 23668 var $ctoken; 23669 var $f; 23670 var $op1; 23671 var $op2; 23672 var $this = this; 23673 23674 try { 23675 this.tokens.forEach( function( $token ) { 23676 switch ( $token.type ) { 23677 case THEMECOMPLETE_EPO_MATH_Constants.LITERAL: 23678 case THEMECOMPLETE_EPO_MATH_Constants.VARIABLE: 23679 case THEMECOMPLETE_EPO_MATH_Constants.STRING: 23680 $tokens.push( $token ); 23681 23682 if ( $param_counter.length > 0 && 0 === $param_counter[ $param_counter.length - 1 ] ) { 23683 $param_counter.push( $param_counter.pop() + 1 ); 23684 } 23685 23686 break; 23687 23688 case THEMECOMPLETE_EPO_MATH_Constants.FUNCTION: 23689 if ( $param_counter.length > 0 && 0 === $param_counter[ $param_counter.length - 1 ] ) { 23690 $param_counter.push( $param_counter.pop() + 1 ); 23691 } 23692 $stack.push( $token ); 23693 $param_counter.push( 0 ); 23694 23695 break; 23696 23697 case THEMECOMPLETE_EPO_MATH_Constants.LEFTPARENTHESIS: 23698 $stack.push( $token ); 23699 23700 break; 23701 23702 case THEMECOMPLETE_EPO_MATH_Constants.PARAMSEPARATOR: 23703 while ( THEMECOMPLETE_EPO_MATH_Constants.LEFTPARENTHESIS !== $stack[ $stack.length - 1 ].type ) { 23704 if ( 0 === $stack.length ) { 23705 return THEMECOMPLETE_EPO_MATH_Error.trigger( 'Incorrect Brackets', 'IncorrectBracketsError', $tokens ); 23706 } 23707 $tokens.push( $stack.pop() ); 23708 } 23709 $param_counter.push( $param_counter.pop() + 1 ); 23710 23711 break; 23712 23713 case THEMECOMPLETE_EPO_MATH_Constants.OPERATOR: 23714 if ( ! array_key_exists( $token.value, $this.operators ) ) { 23715 return THEMECOMPLETE_EPO_MATH_Error.trigger( $token.value, 'UnknownOperatorError', $tokens ); 23716 } 23717 $op1 = $this.operators[ $token.value ]; 23718 23719 while ( $stack.length > 0 && THEMECOMPLETE_EPO_MATH_Constants.OPERATOR === $stack[ $stack.length - 1 ].type ) { 23720 if ( ! array_key_exists( $stack[ $stack.length - 1 ].value, $this.operators ) ) {
23721 return THEMECOMPLETE_EPO_MATH_Error.trigger( $stack[ $stack.length - 1 ].value, 'UnknownOperatorError', $tokens ); 23722 } 23723 $op2 = $this.operators[ $stack[ $stack.length - 1 ].value ]; 23724 23725 if ( $op2.priority >= $op1.priority ) { 23726 $tokens.push( $stack.pop() ); 23727 23728 continue; 23729 } 23730 23731 break; 23732 } 23733 $stack.push( $token ); 23734 23735 break; 23736 23737 case THEMECOMPLETE_EPO_MATH_Constants.RIGHTPARENTHESIS: 23738 while ( true ) { 23739 try { 23740 $ctoken = $stack.pop(); 23741 23742 if ( THEMECOMPLETE_EPO_MATH_Constants.LEFTPARENTHESIS === $ctoken.type ) { 23743 break; 23744 } 23745 $tokens.push( $ctoken ); 23746 } catch ( $e ) { 23747 return THEMECOMPLETE_EPO_MATH_Error.trigger( 'Incorrect Brackets', 'IncorrectBracketsError', $tokens ); 23748 } 23749 } 23750 23751 if ( $stack.length > 0 && THEMECOMPLETE_EPO_MATH_Constants.FUNCTION === $stack[ $stack.length - 1 ].type ) { 23752 $f = $stack.pop(); 23753 $f.param_count = $param_counter.pop(); 23754 $tokens.push( $f ); 23755 } 23756 23757 break; 23758 23759 case THEMECOMPLETE_EPO_MATH_Constants.SPACE: 23760 // do nothing. 23761 } 23762 } ); 23763 } catch ( $e ) { 23764 $tokens = []; 23765 return THEMECOMPLETE_EPO_MATH_Error.trigger( $e, 'Error', $tokens ); 23766 } 23767 23768 while ( 0 !== $stack.length ) { 23769 if ( THEMECOMPLETE_EPO_MATH_Constants.LEFTPARENTHESIS === $stack[ $stack.length - 1 ].type || THEMECOMPLETE_EPO_MATH_Constants.RIGHTPARENTHESIS === $stack[ $stack.length - 1 ].type ) { 23770 return THEMECOMPLETE_EPO_MATH_Error.trigger( 'Incorrect Brackets', 'IncorrectBracketsError', $tokens ); 23771 } 23772 23773 if ( THEMECOMPLETE_EPO_MATH_Constants.SPACE === $stack[ $stack.length - 1 ].type ) { 23774 $stack.pop(); 23775 continue; 23776 } 23777 $tokens.push( $stack.pop() ); 23778 } 23779 23780 return $tokens; 23781 } 23782 }; 23783 node.input = $input; 23784 node.operators = $operators; 23785 return node; 23786 }; 23787 23788 var THEMECOMPLETE_EPO_MATH_Constants = { 23789 LITERAL: 'literal', 23790 VARIABLE: 'variable', 23791 OPERATOR: 'operator', 23792 LEFTPARENTHESIS: 'LP', 23793 RIGHTPARENTHESIS: 'RP', 23794 FUNCTION: 'function', 23795 PARAMSEPARATOR: 'separator', 23796 STRING: 'string', 23797 SPACE: 'space' 23798 23799 }; 23800 23801 var THEMECOMPLETE_EPO_MATH_Token = function( $type, $value, $name ) { 23802 var node = { 23803 type: THEMECOMPLETE_EPO_MATH_Constants.LITERAL, 23804 value: undefined, 23805 name: undefined, 23806 param_count: null 23807 }; 23808 node.type = $type; 23809 node.value = $value; 23810 node.name = $name; 23811 return node; 23812 }; 23813 23814 var THEMECOMPLETE_EPO_MATH_Operator = function( $operator, $is_right_assoc, $priority, $function ) { 23815 var node = { 23816 operator: '', 23817 is_right_assoc: false, 23818 priority: 0, 23819 function: null, 23820 places: 0 23821 }; 23822 node.operator = $operator; 23823 node.is_right_assoc = $is_right_assoc; 23824 node.priority = $priority; 23825 node.function = $function; 23826 node.places = getNumberOfParameters( $function ); 23827 23828 node.execute = function( $stack ) { 23829 var $args = []; 23830 var $i; 23831 var $result; 23832 23833 if ( $stack.length < this.places ) { 23834 // Empty the $stack 23835 $stack.splice( 0, $stack.length ); 23836 return THEMECOMPLETE_EPO_MATH_Error.trigger( 'Incorrect Expression', 'IncorrectExpressionError', new THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.LITERAL, 0 ) ); 23837 } 23838 23839 for ( $i = 0; $i < this.places; $i++ ) { 23840 $args.unshift( $stack.pop().value ); 23841 } 23842 23843 $result = this.function.apply( null, $args ); 23844 if ( 'number' !== gettype( $result ) && 'string' !== gettype( $result ) ) { 23845 $result = 0; 23846 } 23847 23848 return new THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.LITERAL, $result ); 23849 }; 23850 23851 return node; 23852 }; 23853 23854 var THEMECOMPLETE_EPO_MATH_CustomFunction = function( $name, $function ) { 23855 var node = { 23856 name: '', 23857 function: undefined, 23858 required_param_count: undefined 23859 }; 23860 23861 node.name = $name; 23862 node.function = $function; 23863 node.required_param_count = getNumberOfRequiredParameters( $function ); 23864 23865 node.execute = function( $stack, $param_count_in_stack ) { 23866 var $args = []; 23867 var $i; 23868 var $argument; 23869 var $result; 23870 if ( $param_count_in_stack < this.required_param_count ) { 23871 $param_count_in_stack = this.required_param_count; 23872 }
23873 // We skip this section. 23874 if ( $param_count_in_stack < this.required_param_count ) { 23875 // Empty the $stack 23876 $stack.splice( 0, $stack.length ); 23877 return THEMECOMPLETE_EPO_MATH_Error.trigger( this.name, 'IncorrectNumberOfFunctionParametersError', new THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.LITERAL, 0 ) ); 23878 } 23879 23880 if ( $param_count_in_stack > 0 ) { 23881 for ( $i = 0; $i < $param_count_in_stack; $i++ ) { 23882 $argument = $stack.length ? $stack.pop().value : 0; 23883 if ( null === $argument ) { 23884 $argument = '0'; 23885 $args.push( $argument ); 23886 } else { 23887 $args.unshift( $argument ); 23888 } 23889 } 23890 } 23891 23892 $result = this.function.apply( null, $args ); 23893 23894 if ( $result === Infinity || $result === -Infinity ) { 23895 $result = 0; 23896 } 23897 23898 return THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.LITERAL, $result ); 23899 }; 23900 23901 return node; 23902 }; 23903 23904 var THEMECOMPLETE_EPO_MATH_Calculator = function( $functions, $operators ) { 23905 var node = { 23906 functions: {}, 23907 operators: {} 23908 }; 23909 node.functions = $functions; 23910 node.operators = $operators; 23911 23912 node.calculate = function( $tokens, $variables, $on_var_not_found = null, $math_object = false ) { 23913 var $this = this; 23914 /** Array of THEMECOMPLETE_EPO_MATH_Token */ 23915 var $stack = []; 23916 var $result; 23917 23918 if ( empty( $tokens ) ) { 23919 return 0; 23920 } 23921 try { 23922 $tokens.forEach( function( $token ) { 23923 var $variable; 23924 var $value; 23925 if ( THEMECOMPLETE_EPO_MATH_Constants.LITERAL === $token.type || THEMECOMPLETE_EPO_MATH_Constants.STRING === $token.type ) { 23926 $stack.push( $token ); 23927 } else if ( THEMECOMPLETE_EPO_MATH_Constants.VARIABLE === $token.type ) { 23928 $variable = $token.value; 23929 23930 $value = null; 23931 23932 if ( array_key_exists( $variable, $variables ) ) { 23933 $value = $variables[ $variable ]; 23934 } else if ( $on_var_not_found && 'function' === typeof $on_var_not_found ) { 23935 $value = $on_var_not_found( $variable ); 23936 } else { 23937 $value = $variable; 23938 $math_object.variables[ $variable ] = $value; 23939 $variables[ $variable ] = $value; 23940 } 23941 $stack.push( THEMECOMPLETE_EPO_MATH_Token( THEMECOMPLETE_EPO_MATH_Constants.LITERAL, $value, $variable ) ); 23942 } else if ( THEMECOMPLETE_EPO_MATH_Constants.FUNCTION === $token.type ) { 23943 if ( ! array_key_exists( $token.value, $this.functions ) ) { 23944 $math_object.add_function( 23945 $token.value, 23946 function() { 23947 return 0; 23948 } 23949 ); 23950 $this.functions = $math_object.functions; 23951 if ( ! array_key_exists( $token.value, $this.functions ) ) { 23952 return THEMECOMPLETE_EPO_MATH_Error.trigger( $token.value, 'UnknownFunctionError', 0 ); 23953 } 23954 THEMECOMPLETE_EPO_MATH_Error.trigger( $token.value, 'UnknownFunctionError', 0 ); 23955 } 23956 $stack.push( $this.functions[ $token.value ].execute( $stack, $token.param_count ) ); 23957 } else if ( THEMECOMPLETE_EPO_MATH_Constants.OPERATOR === $token.type ) { 23958 if ( ! array_key_exists( $token.value, $this.operators ) ) { 23959 return THEMECOMPLETE_EPO_MATH_Error.trigger( $token.value, 'UnknownOperatorError', 0 ); 23960 } 23961 $stack.push( $this.operators[ $token.value ].execute( $stack ) ); 23962 } 23963 } ); 23964 } catch ( $e ) { 23965 if ( window.TMEPOJS && window.TMEPOJS.WP_DEBUG ) { 23966 window.console.log( $e ); 23967 } 23968 } 23969 $result = $stack.pop(); 23970 23971 if ( undefined === $result || null === $result || ! empty( $stack ) ) { 23972 return THEMECOMPLETE_EPO_MATH_Error.trigger( 'Stack must be empty', 'IncorrectExpressionError', 0 ); 23973 } 23974 23975 if ( false === $result.value ) { 23976 $result.value = 0; 23977 } 23978 23979 if ( true === $result.value ) { 23980 $result.value = 1; 23981 } 23982 23983 if ( 'string' === gettype( $result.value ) && $result.value.isNumeric() ) { 23984 $result.value = floatval( $result.value ); 23985 } 23986 23987 return $result.value; 23988 }; 23989 return node; 23990 }; 23991 23992 var THEMECOMPLETE_EPO_MATH_Error = { 23993 trigger: function( $msg, $code = '', $return = false ) { 23994 if ( window.TMEPOJS && window.TMEPOJS.WP_DEBUG ) { 23995 window.console.log( $code + '\n' + $msg ); 23996 window.console.trace(); 23997 } 23998 if ( window.TMEPOGLOBALADMINJS && window.TMEPOGLOBALADMINJS.WP_DEBUG ) { 23999 return $msg; 24000 } 24001 return $return; 24002 } 24003 }; 24004 24005 window.tcmexp = THEMECOMPLETE_EPO_MATH.construct(); 24006}( window ) ); 24007; 24008( function( window, document, $ ) { 24009 'use strict'; 24010 24011 var tcAPI = {}; 24012 var TMEPOJS = window.TMEPOJS; 24013 var wp = window.wp; 24014 var TMEPOQTRANSLATEXJS = window.TMEPOQTRANSLATEXJS; 24015 var noUiSlider = window.noUiSlider; 24016 var ClipboardEvent = window.ClipboardEvent; 24017 var DataTransfer = window.DataTransfer; 24018 var lateVariationEvent = []; 24019 var latecpflogicactions = []; 24020 var tmLazyloadContainer = false;
24021 var variationsFormIsLoaded = false; 24022 var jBody = $( 'body' ); 24023 var jWindow = $( window ); 24024 var jDocument = $( document ); 24025 var errorObject; 24026 var FloatingTotalsBox; 24027 var currentAjaxButton; 24028 var currentAddToCartButton; 24029 var errorContainer = $( window ); 24030 var tcmexp = window.tcmexp; 24031 var _ = window._; 24032 var priceCache = false; 24033 24034 var getLocalInputDecimalSeparator = function() { 24035 if ( TMEPOJS.tm_epo_global_input_decimal_separator === '' ) { 24036 return TMEPOJS.currency_format_decimal_sep; 24037 } 24038 return $.epoAPI.locale.getSystemDecimalSeparator(); 24039 }; 24040 24041 var getLocalDecimalSeparator = function() { 24042 if ( TMEPOJS.tm_epo_global_displayed_decimal_separator === '' ) { 24043 return TMEPOJS.currency_format_decimal_sep; 24044 } 24045 return $.epoAPI.locale.getSystemDecimalSeparator(); 24046 }; 24047 24048 var getLocalThousandSeparator = function() { 24049 if ( TMEPOJS.tm_epo_global_displayed_decimal_separator === '' ) { 24050 return TMEPOJS.currency_format_thousand_sep; 24051 } 24052 return $.epoAPI.locale.getSystemDecimalSeparator(); 24053 }; 24054 24055 var getEpoDelay = function() { 24056 if ( TMEPOJS.tm_epo_start_animation_delay ) { 24057 return TMEPOJS.tm_epo_start_animation_delay; 24058 } else if ( window.tc_epo_delay ) { 24059 return window.tc_epo_delay; 24060 } 24061 return 500; 24062 }; 24063 24064 var getEpoAnimationDelay = function() { 24065 if ( TMEPOJS.tm_epo_animation_delay ) { 24066 return TMEPOJS.tm_epo_start_animation_delay; 24067 } else if ( window.tc_epo_animation_delay ) { 24068 return window.tc_epo_animation_delay; 24069 } 24070 return 500; 24071 }; 24072 24073 var originalVal = $.fn.val; 24074 24075 if ( ! TMEPOJS || ! wp ) { 24076 return; 24077 } 24078 24079 // Trigger plugin events when other plugins use val. 24080 $.fn.val = function() { 24081 var result = originalVal.apply( this, arguments ); 24082 if ( arguments.length > 0 ) { 24083 if ( $( this ).is( '.input-text.qty' ) ) { 24084 $( this ).trigger( 'change.cpf' ); 24085 } 24086 } 24087 return result; 24088 }; 24089 24090 // Set update event for Lazy Load XT 24091 if ( TMEPOJS.tm_epo_no_lazy_load === 'no' && $.lazyLoadXT ) { 24092 $.extend( $.lazyLoadXT, { 24093 autoInit: false, 24094 updateEvent: $.lazyLoadXT.updateEvent + ' tmlazy' 24095 } ); 24096 } 24097 24098 tcAPI.localInputDecimalSeparator = getLocalInputDecimalSeparator(); 24099 tcAPI.localDecimalSeparator = getLocalDecimalSeparator(); 24100 tcAPI.localThousandSeparator = getLocalThousandSeparator(); 24101 tcAPI.epoDelay = getEpoDelay(); 24102 tcAPI.epoAnimationDelay = getEpoAnimationDelay(); 24103 tcAPI.getElementFromFieldCache = []; 24104 tcAPI.epoSelector = '.tc-extra-product-options'; 24105 tcAPI.associatedEpoSelector = '.tc-extra-product-options-inline'; 24106 tcAPI.associatedEpoCart = '.tc-epo-element-product-container-cart'; 24107 tcAPI.addToCartSelector = "input[name='add-to-cart']"; 24108 tcAPI.tcAddToCartSelector = 'input.tc-add-to-cart'; 24109 tcAPI.qtySelector = "input.qty,input[name='quantity'],select.qty,.drop-down-button #qty,.plus-minus-button #qty,.slider-input #amount"; 24110 tcAPI.associateQtySelector = 'input.tm-qty-alt'; 24111 tcAPI.addToCartButtonSelector = '.add_to_cart_button, .single_add_to_cart_button'; 24112 tcAPI.compositeSelector = '.bto_item,.component'; 24113 tcAPI.nativeProductPriceSelector = TMEPOJS.tm_epo_global_product_price_selector || '.woocommerce .product p.price, .wc-block-components-product-price'; 24114 tcAPI.associatedNativeProductPriceSelector = '.product-price .associated-price'; 24115 tcAPI.templateEngine = $.epoAPI.applyFilter( 'tc_adjust_templateEngine', { 24116 plain_price: wp.template( 'tc-plain-price' ), 24117 suffix: wp.template( 'tc-suffix' ), 24118 main_suffix: wp.template( 'tc-main-suffix' ), 24119 price: wp.template( 'tc-price' ), 24120 price_m: wp.template( 'tc-price-m' ), 24121 sale_price: wp.template( 'tc-sale-price' ), 24122 sale_price_m10: wp.template( 'tc-sale-price-m10' ), 24123 sale_price_m01: wp.template( 'tc-sale-price-m01' ), 24124 sale_price_m11: wp.template( 'tc-sale-price-m11' ), 24125 tc_chars_remanining: wp.template( 'tc-chars-remanining' ), 24126 tc_final_totals: wp.template( 'tc-final-totals' ), 24127 tc_floating_box: wp.template( 'tc-floating-box' ), 24128 tc_floating_box_nks: wp.template( 'tc-floating-box-nks' ), 24129 tc_formatted_price: wp.template( 'tc-formatted-price' ), 24130 tc_formatted_sale_price: wp.template( 'tc-formatted-sale-price' ), 24131 tc_lightbox: wp.template( 'tc-lightbox' ), 24132 tc_lightbox_zoom: wp.template( 'tc-lightbox-zoom' ), 24133 tc_section_pop_link: wp.template( 'tc-section-pop-link' ), 24134 tc_upload_messages: wp.template( 'tc-upload-messages' ) 24135 } ); 24136 24137 // make API available to 3rd party plugins 24138 $.tcAPI = function() { 24139 return tcAPI; 24140 }; 24141 // method for accessing internal api variables 24142 $.tcAPIGet = function( name ) { 24143 return tcAPI[ name ]; 24144 }; 24145 24146 // method for setting internal api variables 24147 $.tcAPISet = function( name, value ) { 24148 tcAPI[ name ] = value; 24149 }; 24150 24151 if ( $.tc_validator ) { 24152 $.extend( $.tc_validator.messages, { 24153 required: TMEPOJS.tm_epo_global_validator_messages.required, 24154 email: TMEPOJS.tm_epo_global_validator_messages.email, 24155 url: TMEPOJS.tm_epo_global_validator_messages.url, 24156 number: TMEPOJS.tm_epo_global_validator_messages.number, 24157 digits: TMEPOJS.tm_epo_global_validator_messages.digits, 24158 maxlengthsingle: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.maxlengthsingle ), 24159 maxlength: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.maxlength ), 24160 minlengthsingle: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.minlengthsingle ), 24161 minlength: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.minlength ), 24162 max: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.max ), 24163 min: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.min ), 24164 step: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.step ), 24165 lettersonly: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.lettersonly ), 24166 lettersspaceonly: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.lettersspaceonly ), 24167 alphanumeric: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.alphanumeric ), 24168 alphanumericunicode: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.alphanumericunicode ), 24169 alphanumericunicodespace: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.alphanumericunicodespace ), 24170 repeaterminrows: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.repeaterminrows ), 24171 repeatermaxrows: $.tc_validator.format( TMEPOJS.tm_epo_global_validator_messages.repeatermaxrows ) 24172 } ); 24173 24174 /* 24175 ASCII Digits 24176 \u0030-\u0039 24177 24178 Latin Alphabet 24179 \u0041-\u005A\u0061-\u007A 24180 24181 Latin-1 Supplement 24182 \u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF 24183 24184 Latin Extended-A 24185 \u0100-\u0148\u014A-\u017F 24186 24187 Latin Extended-B 24188 \u0180-\u01BF\u01C4-\u024F 24189 24190 Latin Extended Additional 24191 \u1E02-\u1EF3 24192 24193 Greek and Coptic 24194 \u0370-\u03FF 24195 24196 Cyrillic 24197 \u0400-\u04FF\u0500-\u052F 24198 24199 Japanese Hiragana 24200 \u3040-\u309f 24201 Japanese Katakana 24202 \u30a0-\u30ff 24203 Japanese Kanji (common & uncommon) 24204 \u4e00-\u9faf 24205 Japanese Kanji (rare) 24206 \u3400-\u4dbf 24207 24208 Arabic 24209 \u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF\u10E60-\u10E7F\u1EC70-\u1ECBF\u1ED00-\u1ED4F\u1EE00-\u1EEFF 24210 24211 \u0600-\u06ff 24212 \u0600-\u06FF 24213 24214 Armenian 24215 \u0530-\u1058F 24216 24217 \u0030-\u0039\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u0148\u014A-\u017F\u0180-\u01BF\u01C4-\u024F\u1E02-\u1EF3\u0370-\u03FF\u0400-\u04FF\u0500-\u052F\u3040-\u309f\u30a0-\u30ff\u4e00-\u9faf\u3400-\u4dbf\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF\u10E60-\u10E7F\u1EC70-\u1ECBF\u1ED00-\u1ED4F\u1EE00-\u1EEFF\u0530-\u1058F 24218 24219 */ 24220 24221 $.tc_validator.addMethod( 24222 'alphanumeric', 24223 function( value, element ) { 24224 return this.optional( element ) || /^[a-zA-Z0-9.-]+$/i.test( value ); 24225 }, 24226 $.tc_validator.messages.alphanumeric 24227 ); 24228 24229 $.tc_validator.addMethod( 24230 'lettersonly', 24231 function( value, element ) { 24232 return this.optional( element ) || /^[a-z]+$/i.test( value ); 24233 }, 24234 $.tc_validator.messages.lettersonly 24235 ); 24236 24237 $.tc_validator.addMethod( 24238 'lettersspaceonly', 24239 function( value, element ) { 24240 return this.optional( element ) || /^[a-z,\u0020]+$/i.test( value ); 24241 }, 24242 $.tc_validator.messages.lettersspaceonly 24243 ); 24244 24245 $.tc_validator.addMethod( 24246 'alphanumericunicode', 24247 function( value, element ) { 24248 return ( 24249 this.optional( element ) || 24250 /^[\u0030-\u0039\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u0148\u014A-\u017F\u0180-\u01BF\u01C4-\u024F\u1E02-\u1EF3\u0370-\u03FF\u0400-\u04FF\u0500-\u052F\u3040-\u309f\u30a0-\u30ff\u4e00-\u9faf\u3400-\u4dbf\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF\u10E60-\u10E7F\u1EC70-\u1ECBF\u1ED00-\u1ED4F\u1EE00-\u1EEFF\u0530-\u1058F]+$/i.test( 24251 value 24252 ) 24253 ); 24254 }, 24255 $.tc_validator.messages.alphanumericunicode 24256 ); 24257 24258 $.tc_validator.addMethod( 24259 'alphanumericunicodespace', 24260 function( value, element ) { 24261 return ( 24262 this.optional( element ) || 24263 /^[\u0030-\u0039\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u0148\u014A-\u017F\u0180-\u01BF\u01C4-\u024F\u1E02-\u1EF3\u0370-\u03FF\u0400-\u04FF\u0500-\u052F\u3040-\u309f\u30a0-\u30ff\u4e00-\u9faf\u3400-\u4dbf\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF\u10E60-\u10E7F\u1EC70-\u1ECBF\u1ED00-\u1ED4F\u1EE00-\u1EEFF\u0530-\u1058F,\u0020]+$/i.test( 24264 value 24265 ) 24266 ); 24267 }, 24268 $.tc_validator.messages.alphanumericunicodespace 24269 ); 24270 $.tc_validator.addMethod( 24271 'repeaterminrows', 24272 function( value, element, param ) { 24273 return $.epoAPI.math.toInt( $( element ).closest( '.tc-element-inner-wrap' ).find( '.tc-repeater-element' ).length ) >= $.epoAPI.math.toInt( param ); 24274 }, 24275 $.tc_validator.messages.repeaterminrows 24276 ); 24277 $.tc_validator.addMethod( 24278 'repeatermaxrows', 24279 function( value, element, param ) { 24280 return $.epoAPI.math.toInt( $( element ).closest( '.tc-element-inner-wrap' ).find( '.tc-repeater-element' ).length ) <= $.epoAPI.math.toInt( param ); 24281 }, 24282 $.tc_validator.messages.repeatermaxrows 24283 ); 24284 $.tc_validator.addMethod( 24285 'product_element_radio_qty', 24286 function( value, element ) { 24287 var qty = $( element ).closest( '.tm-element-ul-product' ).find( 'input.tc-epo-field-product.tm
24287cp-radio:checked' ).closest( '.tc-epo-element-product-holder' ).find( '.tm-qty' ).first().val(); 24288 return qty > 0; 24289 }, 24290 $.tc_validator.messages.required 24291 ); 24292 $.tc_validator.addMethod( 24293 'product_element_select_qty', 24294 function( value, element ) { 24295 var qty = $( element ).closest( '.tm-element-ul-product' ).find( 'select.tc-epo-field-product.tmcp-select' ).closest( '.tc-epo-element-product-holder' ).find( '.tm-qty' ).first().val(); 24296 return qty > 0; 24297 }, 24298 $.tc_validator.messages.required 24299 ); 24300 } 24301 24302 $.epoAPI.util.unformat = function( o ) { 24303 var a = $.epoAPI.math.unformat( o, tcAPI.localInputDecimalSeparator ); 24304 var n = parseFloat( a ); 24305 24306 if ( ! Number.isFinite( n ) ) { 24307 return a; 24308 } 24309 return n; 24310 }; 24311 24312 if ( ! $.tmType ) { 24313 $.tmType = function( obj ) { 24314 return Object.prototype.toString 24315 .call( obj ) 24316 .match( /\s([a-zA-Z]+)/ )[ 1 ] 24317 .toLowerCase(); 24318 }; 24319 } 24320 24321 if ( ! $.is_on_screen ) { 24322 $.fn.is_on_screen = function() { 24323 // we don't use jWindow because we want the current window object 24324 var win = $( window ); 24325 var scroll = $.epoAPI.dom.scroll(); 24326 var bounds = this.offset(); 24327 var viewport = { 24328 top: scroll.top, 24329 left: scroll.left 24330 }; 24331 24332 viewport.right = viewport.left + win.width(); 24333 viewport.bottom = viewport.top + win.height(); 24334 bounds.right = bounds.left + this.outerWidth(); 24335 bounds.bottom = bounds.top + this.outerHeight(); 24336 24337 return ! ( viewport.right < bounds.left || viewport.left > bounds.right || viewport.bottom < bounds.top || viewport.top > bounds.bottom ); 24338 }; 24339 } 24340 24341 if ( ! $().tmtoggle ) { 24342 $.fn.tmtoggle = function() { 24343 var elements = this; 24344 var is_one_open_for_accordion = false; 24345 var init_done = 0; 24346 24347 if ( elements.length === 0 ) { 24348 return; 24349 } 24350 24351 if ( window.tc_accordion_offset === undefined ) { 24352 window.tc_accordion_offset = -100; 24353 } 24354 24355 elements.toArray().forEach( function( t ) { 24356 var headers; 24357 var wrap; 24358 var wraps; 24359 24360 t = $( t ); 24361 24362 if ( ! t.data( 'tm-toggle-init' ) ) { 24363 t.data( 'tm-toggle-init', 1 ); 24364 headers = t.find( '.tm-toggle' ); 24365 wrap = t.find( '.tm-collapse-wrap' ); 24366 wraps = $( '.tm-collapse.tmaccordion' ); 24367 if ( wraps.closest( '.tc-epo-element-product-holder' ).length > 0 ) { 24368 wraps = wraps.closest( '.tc-epo-element-product-holder' ).find( '.tm-collapse.tmaccordion' ).find( '.tm-toggle' ); 24369 } else { 24370 wraps = $( '.tm-collapse.tmaccordion' ).not( '.tc-epo-element-product-holder .tm-collapse.tmaccordion' ).find( '.tm-toggle' ); 24371 } 24372 if ( headers.length === 0 || wrap.length === 0 ) { 24373 return; 24374 } 24375 24376 if ( wrap.is( '.closed' ) ) { 24377 $( wrap ).removeClass( 'closed open' ).addClass( 'closed' ).hide(); 24378 $( headers ).find( '.tm-arrow' ).removeClass( 'tcfa-angle-down tcfa-angle-up' ).addClass( 'tcfa-angle-down' ); 24379 $( headers ).removeClass( 'toggle-header-open toggle-header-closed' ).addClass( 'toggle-header-closed' ); 24380 $( headers ).attr( 'aria-expanded', false ); 24381 } else { 24382 $( wrap ).removeClass( 'closed open' ).addClass( 'open' ).show(); 24383 $( headers ).find( '.tm-arrow' ).removeClass( 'tcfa-angle-down tcfa-angle-up' ).addClass( 'tcfa-angle-up' ); 24384 $( headers ).removeClass( 'toggle-header-open toggle-header-closed' ).addClass( 'toggle-header-open' ); 24385 $( headers ).attr( 'aria-expanded', true ); 24386 is_one_open_for_accordion = true; 24387 } 24388 24389 headers.toArray().forEach( function( header ) { 24390 header = $( header ); 24391 header.on( 'closewrap.tmtoggle', function() { 24392 if ( t.is( '.tmaccordion' ) && $( wrap ).is( '.closed' ) ) { 24393 return; 24394 } 24395 $( wrap ).removeClass( 'closed open' ).addClass( 'closed' ); 24396 $( this ).find( '.tm-arrow' ).removeClass( 'tcfa-angle-down tcfa-angle-up' ).addClass( 'tcfa-angle-down' ); 24397 $( this ).removeClass( 'toggle-header-open toggle-header-closed' ).addClass( 'toggle-header-closed' ); 24398 $( this ).attr( 'aria-expanded', false ); 24399 $( wrap ).removeClass( 'tm-animated fadein' ); 24400 if ( t.is( '.tmaccordion' ) ) { 24401 $( wrap ).animate( { height: 'toggle' }, 100, function() { 24402 $( wrap ).hide(); 24403 } ); 24404 } else { 24405 $( wrap ).animate( { height: 'toggle' }, 100, function() { 24406 $( wrap ).hide(); 24407 } ); 24408 } 24409 jWindow.trigger( 'tmlazy' ); 24410 } ); 24411 24412 header.on( 'openwrap.tmtoggle', function( e, data ) { 24413 if ( t.is( '.tmaccordion' ) ) { 24414 $( wraps ).not( $( this ) ).trigger( 'closewrap.tmtoggle' ); 24415 } 24416 $( wrap ).removeClass( 'closed open' ).addClass( 'open' ); 24417 $( this ).find( '.tm-arrow' ).removeClass( 'tcfa-angle-down tcfa-angle-up' ).addClass( 'tcfa-angle-up' ); 24418 $( this ).removeClass( 'toggle-header-open toggle-header-closed' ).addClass( 'toggle-header-open' ); 24419 $( this ).attr( 'aria-expanded', true ); 24420 $( wrap ).show().removeClass( 'tm-animated fadein' ).addClass( 'tm-animated fadein' ); 24421 setTimeout( function() { 24422 jWindow.trigger( 'tmlazy' ); 24423 }, 200 ); 24424 setTimeout( function() { 24425 if ( data === undefined && init_done && t.is( '.tmaccordion' ) && ! t.is_on_screen() ) { 24426 jWindow.tcScrollTo( header, 10, window.tc_accordion_offset ); 24427 } 24428 }, 110 ); 24429 } ); 24430 24431 header.on( 'click.tmtoggle keydown.tmtoggle', function( e ) { 24432 // If it's a keydown event, only trigger if the Enter key was pressed 24433 if ( e.type === 'keydown' && e.key !== 'Enter' ) { 24434 return; // Ignore all other keypresses 24435 } 24436 e.preventDefault(); 24437 if ( $( wrap ).is( '.closed' ) ) { 24438 $( this ).trigger( 'openwrap.tmtoggle' ); 24439 } else { 24440 $( this ).trigger( 'closewrap.tmtoggle' ); 24441 } 24442 } ); 24443 24444 header 24445 .find( '.tm-qty' ) 24446 .closest( '.cpf-element' ) 24447 .find( '.tm-epo-field' ) 24448 .on( 'change.cpf', function() { 24449 header.trigger( 'openwrap.tmtoggle' ); 24450 } ); 24451 } ); 24452 } 24453 } ); 24454 if ( undefined === window.tc_accordion_closed_on_page_load && ! is_one_open_for_accordion && elements.filter( '.tmaccordion' ).length > 0 ) { 24455 elements.filter( '.tmaccordion' ).first().find( '.tm-toggle' ).trigger( 'openwrap.tmtoggle', { nomove: 1 } ); 24456 } 24457 init_done = 1; 24458 return elements; 24459 }; 24460 } 24461 24462 if ( ! $().tmpoplink ) { 24463 $.fn.tmpoplink = function( options ) { 24464 var elements = this; 24465 var floatbox_template; 24466 var settings = { 24467 classname: 'flasho tc-wrapper cart-popup' 24468 }; 24469 24470 if ( elements.length === 0 ) { 24471 return; 24472 } 24473 if ( options ) { 24474 settings = $.extend( {}, settings, options ); 24475 } 24476 24477 floatbox_template = function( data ) { 24478 return $.epoAPI.template.html( wp.template( 'tc-cart-options-popup' ), { 24479 title: data.title, 24480 id: data.id, 24481 html: data.html, 24482 close: TMEPOJS.i18n_close 24483 } ); 24484 }; 24485
24486 return elements.toArray().forEach( function( t ) { 24487 var id; 24488 var title; 24489 var html; 24490 var $_html; 24491 24492 t = $( t ); 24493 if ( t.is( '.tc-poplink' ) ) { 24494 return; 24495 } 24496 t.addClass( 'tc-poplink' ); 24497 id = t.attr( 'href' ); 24498 title = t.attr( 'data-title' ); 24499 html = $( id ).html(); 24500 if ( ! title ) { 24501 title = TMEPOJS.i18n_addition_options; 24502 } 24503 $_html = floatbox_template( { 24504 id: 'tc-floatbox-content', 24505 html: html, 24506 title: title 24507 } ); 24508 24509 t.on( 'click.tmpoplink', function( e ) { 24510 $.tcFloatBox( { 24511 fps: 1, 24512 ismodal: false, 24513 width: '80%', 24514 height: '80%', 24515 classname: settings.classname, 24516 data: $_html 24517 } ); 24518 24519 e.preventDefault(); 24520 } ); 24521 } ); 24522 }; 24523 } 24524 24525 function readableFileSize( a, b, c, d, e ) { 24526 b = Math; 24527 c = b.log; 24528 d = 1024; 24529 e = c( a ) / c( d ) | 0; //eslint-disable-line no-bitwise 24530 24531 return ( ( a / b.pow( d, e ) ).toFixed( e ? 2 : 0 ) ) + ' ' + ( e ? 'KMGTPEZY'[ --e ] + 'B' : 'bytes' ); 24532 } 24533 24534 function toggleState( thisProductContainerWrap, disabled ) { 24535 thisProductContainerWrap.toArray().forEach( function( setter ) { 24536 setter = $( setter ); 24537 setter.find( ':input' ).prop( 'disabled', function( i, v ) { 24538 var state = $( this ).data( 'tc-state' ); 24539 if ( state === undefined ) { 24540 $( this ).data( 'tc-state', v ); 24541 return disabled; 24542 } 24543 if ( state === false ) { 24544 return disabled; 24545 } 24546 return state; 24547 } ); 24548 } ); 24549 } 24550 // Function to calculate tax amount 24551 function calculateTaxAmount( priceWithTax, _cart ) { 24552 var taxable; 24553 var tax_rate; 24554 var pricesIncludeTax; 24555 var tax_display_mode; 24556 var current_variation; 24557 var priceWithoutTax; 24558 var taxAmount = 0; 24559 24560 if ( _cart ) { 24561 taxable = _cart.attr( 'data-taxable' ); 24562 tax_rate = _cart.attr( 'data-tax-rate' ); 24563 pricesIncludeTax = _cart.attr( 'data-prices-include-tax' ) || TMEPOJS.prices_include_tax; 24564 tax_display_mode = _cart.attr( 'data-tax-display-mode' ); 24565 if ( _cart.data( 'current_variation' ) !== undefined ) { 24566 current_variation = _cart.data( 'current_variation' ); 24567 } 24568 24569 if ( current_variation !== undefined ) { 24570 current_variation = _cart.data( 'current_variation' ); 24571 taxable = current_variation.tc_is_taxable; 24572 tax_rate = current_variation.tc_tax_rate; 24573 } 24574 } 24575 24576 if ( taxable ) { 24577 tax_rate = parseFloat( tax_rate / 100 ); 24578 24579 if ( pricesIncludeTax === '1' ) { 24580 if ( tax_display_mode === 'incl' ) { 24581 priceWithTax = parseFloat( priceWithTax ); 24582 24583 // Calculate price without tax 24584 priceWithoutTax = priceWithTax / ( 1 + tax_rate ); 24585 24586 // Calculate tax amount 24587 taxAmount = priceWithTax - priceWithoutTax; 24588 } else { 24589 // Calculate price without tax 24590 priceWithoutTax = priceWithTax; 24591 24592 // Calculate tax amount 24593 taxAmount = priceWithTax * tax_rate; 24594 } 24595 } else if ( tax_display_mode === 'incl' ) { 24596 // Calculate price without tax 24597 priceWithoutTax = priceWithTax / ( 1 + tax_rate ); 24598 24599 // Calculate tax amount 24600 taxAmount = priceWithTax - priceWithoutTax; 24601 } 24602 24603 taxAmount = $.epoAPI.math.toFloat( taxAmount ); 24604 } 24605 24606 return taxAmount; 24607 } 24608 // Taxes setup 24609 function get_price_including_tax( price, _cart, element, force, variation, pricetype, doubleforce ) { 24610 var taxable; 24611 var tax_rate; 24612 var prices_include_tax; 24613 var is_vat_exempt; 24614 var non_base_location_prices; 24615 var taxes_of_one; 24616 var base_taxes_of_one; 24617 var modded_taxes_of_one; 24618 var current_variation; 24619 24620 if ( ! Number.isFinite( parseFloat( price ) ) ) { 24621 price = 0; 24622 } 24623 price = price * 10000; 24624 if ( _cart ) { 24625 taxable = _cart.attr( 'data-taxable' ); 24626 tax_rate = _cart.attr( 'data-tax-rate' ); 24627 prices_include_tax = _cart.attr( 'data-prices-include-tax' ) || TMEPOJS.prices_include_tax; 24628 is_vat_exempt = _cart.attr( 'data-is-vat-exempt' ); 24629 non_base_location_prices = _cart.attr( 'data-non-base-location-prices' ); 24630 taxes_of_one = _cart.attr( 'data-taxes-of-one' ); 24631 base_taxes_of_one = _cart.attr( 'data-base-taxes-of-one' ); 24632 modded_taxes_of_one = _cart.attr( 'data-modded-taxes-of-one' ); 24633 24634 if ( _cart.data( 'current_variation' ) !== undefined ) { 24635 current_variation = _cart.data( 'current_variation' ); 24636 } else if ( variation !== undefined ) { 24637 current_variation = variation; 24638 } 24639 24640 if ( current_variation !== undefined ) { 24641 current_variation = _cart.data( 'current_variation' ); 24642 taxable = current_variation.tc_is_taxable; 24643 tax_rate = current_variation.tc_tax_rate; 24644 non_base_location_prices = current_variation.tc_non_base_location_prices; 24645 taxes_of_one = current_variation.tc_taxes_of_one; 24646 base_taxes_of_one = current_variation.tc_base_taxes_of_one; 24647 modded_taxes_of_one = current_variation.tc_modded_taxes_of_one; 24648 } 24649 24650 if ( element ) { 24651 if ( element.data( 'tax-obj' ) ) { 24652 tax_rate = element.data( 'tax-obj' ); 24653 if ( tax_rate.has_fee === 'no' ) { 24654 taxable = false;
24655 } else if ( tax_rate.has_fee === 'yes' ) { 24656 taxable = true; 24657 } 24658 if ( base_taxes_of_one === '' || base_taxes_of_one === undefined ) { 24659 base_taxes_of_one = tax_rate / 100; 24660 } 24661 if ( tax_rate.base_taxes_of_one !== undefined ) { 24662 base_taxes_of_one = tax_rate.base_taxes_of_one; 24663 } 24664 tax_rate = tax_rate.tax_rate; 24665 taxes_of_one = tax_rate / 100; 24666 } 24667 } 24668 if ( taxable ) { 24669 if ( prices_include_tax === '1' && ! force ) { 24670 if ( is_vat_exempt === '1' ) { 24671 if ( non_base_location_prices === '1' ) { 24672 price = parseFloat( price ) - ( taxes_of_one * price ); 24673 } else { 24674 price = parseFloat( price ) - ( base_taxes_of_one * price ); 24675 } 24676 } else if ( non_base_location_prices === '1' ) { 24677 price = parseFloat( price ) - ( base_taxes_of_one * price ) + ( modded_taxes_of_one * price ); 24678 } 24679 } else if ( element || current_variation === undefined || doubleforce ) { 24680 price = parseFloat( price ) + ( parseFloat( price ) * taxes_of_one ); 24681 } 24682 } 24683 } 24684 price = price / 10000; 24685 24686 return price; 24687 } 24688 24689 function get_price_excluding_tax( price, _cart, element, force, variation, pricetype, doubleforce ) { 24690 var taxable; 24691 var tax_rate; 24692 var taxes_of_one; 24693 var base_taxes_of_one; 24694 var prices_include_tax; 24695 var current_variation; 24696 var tax_display_mode; 24697 24698 if ( ! Number.isFinite( parseFloat( price ) ) ) { 24699 price = 0; 24700 } 24701 price = price * 10000; 24702 24703 if ( _cart ) { 24704 tax_display_mode = _cart.attr( 'data-tax-display-mode' ); 24705 24706 taxable = _cart.attr( 'data-taxable' ); 24707 tax_rate = _cart.attr( 'data-tax-rate' ); 24708 taxes_of_one = _cart.attr( 'data-taxes-of-one' ); 24709 base_taxes_of_one = _cart.attr( 'data-base-taxes-of-one' ); 24710 prices_include_tax = _cart.attr( 'data-prices-include-tax' ); 24711 24712 if ( _cart.data( 'current_variation' ) !== undefined ) { 24713 current_variation = _cart.data( 'current_variation' ); 24714 } else if ( variation !== undefined ) { 24715 current_variation = variation; 24716 } 24717 if ( current_variation !== undefined ) { 24718 taxable = current_variation.tc_is_taxable; 24719 tax_rate = current_variation.tc_tax_rate; 24720 taxes_of_one = current_variation.tc_taxes_of_one; 24721 base_taxes_of_one = current_variation.tc_base_taxes_of_one; 24722 } 24723 24724 if ( element ) { 24725 if ( element.data( 'tax-obj' ) ) { 24726 tax_rate = element.data( 'tax-obj' ); 24727 if ( tax_rate.has_fee === 'no' ) { 24728 taxable = false; 24729 } else if ( tax_rate.has_fee === 'yes' ) { 24730 taxable = true; 24731 } 24732 if ( base_taxes_of_one === '' || base_taxes_of_one === undefined ) { 24733 base_taxes_of_one = tax_rate / 100; 24734 } 24735 if ( tax_rate.base_taxes_of_one !== undefined ) { 24736 base_taxes_of_one = tax_rate.base_taxes_of_one; 24737 } 24738 tax_rate = tax_rate.tax_rate; 24739 } 24740 } 24741 24742 if ( taxable ) { 24743 if ( prices_include_tax === '1' || force ) { 24744 if ( tax_display_mode === 'incl' ) { 24745 // This should never run on this function 24746 } else if ( element || current_variation === undefined || force || doubleforce ) { 24747 if ( base_taxes_of_one === taxes_of_one ) { 24748 price = parseFloat( price ) - parseFloat( taxes_of_one * price ); 24749 } else { 24750 price = price * ( 1 - parseFloat( base_taxes_of_one ) ); 24751 } 24752 } 24753 } 24754 } 24755 } 24756 price = price / 10000; 24757 24758 return price; 24759 } 24760 24761 function tm_set_tax_price( value, _cart, element, pricetype, force, variation, doubleforce ) { 24762 var tax_display_mode; 24763 24764 if ( ! Number.isFinite( parseFloat( value ) ) ) { 24765 value = 0; 24766 } 24767 if ( _cart ) { 24768 tax_display_mode = _cart.attr( 'data-tax-display-mode' ) || TMEPOJS.tax_display_mode; 24769 if ( tax_display_mode === 'incl' ) { 24770 value = get_price_including_tax( value, _cart, element, force, variation, pricetype, doubleforce ); 24771 } else { 24772 value = get_price_excluding_tax( value, _cart, element, force, variation, pricetype, doubleforce ); 24773 } 24774 } 24775 return value; 24776 } 24777 24778 // Return a formatted currency value 24779 function formatPrice( value, args ) { 24780 var data; 24781 if ( ! args ) { 24782 args = {}; 24783 } 24784 data = $.extend( { 24785 symbol: '', 24786 format: '', 24787 decimal: tcAPI.localDecimalSeparator, 24788 thousand: tcAPI.localThousandSeparator, 24789 precision: TMEPOJS.currency_format_num_decimals 24790 }, args ); 24791 24792 if ( TMEPOJS.tm_epo_trim_zeros === 'yes' ) { 24793 if ( ( ( value % 1 ).toString() !== '0' ) === false ) { 24794 data.precision = 0; 24795 } 24796 } 24797 24798 return $.epoAPI.applyFilter( 'tc_formatPrice', $.epoAPI.math.format( value, data ), data, value ); 24799 } 24800 24801 // Return a formatted currency value 24802 function tm_set_price_( value, sign ) { 24803 return ( 24804 sign + 24805 formatPrice( value, { symbol: TMEPOJS.currency_format_symbol, format: TMEPOJS.currency_format } ) 24806 ); 24807 } 24808 24809 // Return a formatted currency value 24810 function tm_set_price( value, _cart, notax, element, pricetype ) { 24811 var val; 24812 var sign = TMEPOJS.option_plus_sign + ' '; 24813 24814 if ( ! notax ) { 24815 value = tm_set_tax_price( value, _cart, element, pricetype ); 24816 } 24817 24818 val = Math.abs( value ); 24819 24820 if ( TMEPOJS.tm_epo_global_options_price_sign === 'minus' ) { 24821 sign = ''; 24822 } 24823 if ( value < 0 ) { 24824 sign = TMEPOJS.option_minus_sign + ' '; 24825 } 24826 24827 return tm_set_price_( val, sign ); 24828 } 24829 24830 // Return a price currency value without any formatting 24831 function tm_get_price( value, _cart, notax, element, pricetype, force ) { 24832 if ( ! notax ) { 24833 value = tm_set_tax_price( value, _cart, element, pricetype, force ); 24834 } 24835 24836 return value; 24837 } 24838 24839 // FloatingTotalsBox plugin 24840 FloatingTotalsBox = function( this_epo_totals_container, is_quickview, main_cart ) { 24841 this.this_epo_totals_container = this_epo_totals_container; 24842 this.is_quickview = is_quickview; 24843 this.main_cart = main_cart; 24844 24845 if ( ! is_quickview && TMEPOJS.floating_totals_box && TMEPOJS.floating_totals_box !== 'disable' && main_cart && this_epo_totals_container.length ) { 24846 this.init(); 24847 return this; 24848 } 24849 24850 return false;
24851 }; 24852 24853 FloatingTotalsBox.prototype = { 24854 constructor: FloatingTotalsBox, 24855 24856 onUpdate: function() { 24857 var tm_epo_totals_html = this.this_epo_totals_container.data( 'tm-html' ); 24858 var tm_floating_box_data = this.this_epo_totals_container.data( 'tm-floating-box-data' ); 24859 var values_obj = []; 24860 var floatingBoxHtml; 24861 var floatingBoxaddToCartButton; 24862 var len; 24863 var i; 24864 var row; 24865 var tempDiv; 24866 var j; 24867 var spans; 24868 var container; 24869 24870 if ( tm_floating_box_data && tm_floating_box_data.length ) { 24871 len = tm_floating_box_data.length; 24872 for ( i = 0; i < len; i++ ) { 24873 row = tm_floating_box_data[ i ]; 24874 // Ensure title and value are properly set 24875 row.title = row.title ? String( row.title ) : ' '; 24876 row.value = row.value ? String( row.value ) : ' '; 24877 24878 // Sanitize title by removing spans 24879 if ( row.title !== ' ' ) { 24880 tempDiv = document.createElement( 'div' ); 24881 tempDiv.innerHTML = row.title; 24882 spans = tempDiv.querySelectorAll( 'span' ); 24883 for ( j = 0; j < spans.length; j++ ) { 24884 spans[ j ].remove(); 24885 } 24886 row.title = tempDiv.innerHTML; 24887 } 24888 24889 // Handle "is_nks" logic 24890 if ( this.is_nks ) { 24891 if ( row.label_show !== '' ) { 24892 row.title = ''; 24893 } 24894 if ( row.value_show !== '' ) { 24895 row.value = ''; 24896 } 24897 } 24898 24899 // Auto-hide price if zero 24900 if ( TMEPOJS.tm_epo_auto_hide_price_if_zero === 'yes' && $.epoAPI.util.isEmpty( row.price ) === true ) { 24901 row.price = ''; 24902 } else { 24903 row.price = tm_set_price( row.price, this.this_epo_totals_container, true ); 24904 } 24905 24906 // Push processed data into values_obj 24907 values_obj.push( { 24908 label_show: row.label_show, 24909 value_show: row.value_show, 24910 title: row.title, 24911 value: row.value, 24912 quantity: row.quantity, 24913 price: row.price 24914 } ); 24915 } 24916 } 24917 24918 if ( ( ( tm_epo_totals_html && tm_epo_totals_html === '' ) && ( ! tm_floating_box_data || ! tm_floating_box_data.length ) ) || ! ( ( tm_epo_totals_html && tm_epo_totals_html !== '' ) || this.is_nks ) ) { 24919 tm_epo_totals_html = ''; 24920 this.floatingBox.hide(); 24921 } 24922 24923 floatingBoxHtml = $.epoAPI.template.html( this.engineTemplate, { 24924 html_before: TMEPOJS.floating_totals_box_html_before, 24925 html_after: TMEPOJS.floating_totals_box_html_after, 24926 option_label: TMEPOJS.i18n_option_label, 24927 option_value: TMEPOJS.i18n_option_value, 24928 option_qty: TMEPOJS.i18n_option_qty, 24929 option_price: TMEPOJS.i18n_option_price, 24930 values: values_obj, 24931 totals: tm_epo_totals_html 24932 } ); 24933 24934 this.floatingBox.html( floatingBoxHtml ); 24935 this.onUpdateScroll(); 24936 24937 if ( TMEPOJS.tm_epo_no_lazy_load !== 'yes' ) { 24938 this.floatingBox.addClass( 'lazyxt' ); 24939 container = this.floatingBox.find( 'img.tmlazy' ); 24940 container.lazyLoadXT(); 24941 container.on( 'lazyshow', function() { 24942 jWindow.trigger( 'lazyLoadXToncomplete' ); 24943 } ); 24944 } 24945 24946 if ( TMEPOJS.floating_totals_box_add_button === 'yes' ) { 24947 floatingBoxaddToCartButton = this.main_cart.find( tcAPI.addToCartButtonSelector ).first(); 24948 floatingBoxaddToCartButton 24949 .tcClone() 24950 .addClass( 'tc-add-to-cart-button' ) 24951 .on( 'click', function() { 24952 floatingBoxaddToCartButton.trigger( 'click' ); 24953 } ) 24954 .appendTo( this.floatingBox ); 24955 } 24956 }, 24957 24958 onUpdateScroll: function() { 24959 if ( TMEPOJS.floating_totals_box_visibility === 'always' ) { 24960 if ( this.floatingBox.is( ':empty' ) && ! this.is_nks_alt ) { 24961 this.floatingBox.hide(); 24962 } else { 24963 this.floatingBox.show(); 24964 } 24965 return; 24966 } 24967 if ( TMEPOJS.floating_totals_box_visibility === 'hideafterscroll' ) { 24968 if ( jWindow.scrollTop() > $.epoAPI.math.toFloat( TMEPOJS.floating_totals_box_pixels ) && ! this.is_nks_alt ) { 24969 if ( ! this.floatingBox.is( ':hidden' ) ) { 24970 if ( this.is_nks === false ) { 24971 this.floatingBox.fadeOut(); 24972 } else { 24973 this.floatingBox.hide(); 24974 } 24975 } 24976 } else if ( this.floatingBox.is( ':hidden' ) || this.is_nks_alt ) { 24977 if ( ! this.floatingBox.is( ':empty' ) || this.is_nks_alt ) { 24978 if ( this.is_nks === false ) { 24979 this.floatingBox.fadeIn(); 24980 } else { 24981 this.floatingBox.show(); 24982 } 24983 } 24984 } 24985 } 24986 24987 if ( TMEPOJS.floating_totals_box_visibility === 'afterscroll' ) { 24988 if ( jWindow.scrollTop() >
24988 $.epoAPI.math.toFloat( TMEPOJS.floating_totals_box_pixels ) || this.is_nks_alt ) { 24989 if ( ( this.floatingBox.is( ':hidden' ) && ! this.floatingBox.is( ':empty' ) ) || this.is_nks_alt ) { 24990 if ( this.is_nks === false ) { 24991 this.floatingBox.fadeIn(); 24992 } else { 24993 this.floatingBox.show(); 24994 } 24995 } else if ( ! this.floatingBox.is( ':hidden' ) && this.floatingBox.is( ':empty' ) ) { 24996 if ( this.is_nks === false ) { 24997 this.floatingBox.fadeOut(); 24998 } else { 24999 this.floatingBox.hide(); 25000 } 25001 } 25002 } else if ( ! this.floatingBox.is( ':hidden' ) ) { 25003 if ( this.is_nks === false ) { 25004 this.floatingBox.fadeOut(); 25005 } else { 25006 this.floatingBox.hide(); 25007 } 25008 } 25009 } 25010 }, 25011 25012 addEvents: function() { 25013 this.onUpdate(); 25014 25015 this.main_cart.on( 'tm-epo-after-update', this.onUpdate.bind( this ) ); 25016 this.main_cart.on( 'tm-epo-short-update', this.onUpdate.bind( this ) ); 25017 25018 if ( this.is_nks === false ) { 25019 jWindow.on( 'scroll', this.onUpdateScroll.bind( this ) ); 25020 } 25021 }, 25022 25023 init: function() { 25024 this.floatingBox = $( '<div class="tm-floating-box ' + TMEPOJS.floating_totals_box + '"></div>' ); 25025 this.nks_selector = $( '.tm-floating-box-nks' ).first(); 25026 this.alt_selector = $( '.tm-floating-box-alt' ).first(); 25027 this.engineTemplate = tcAPI.templateEngine.tc_floating_box; 25028 this.is_nks = false; 25029 this.is_nks_alt = false; 25030 25031 if ( this.nks_selector.length > 0 ) { 25032 this.is_nks = true; 25033 this.floatingBox.removeClass( 'top left right bottom' ).appendTo( this.nks_selector ).show(); 25034 } else if ( this.alt_selector.length > 0 ) { 25035 this.floatingBox.removeClass( 'top left right bottom' ).appendTo( this.alt_selector ).hide(); 25036 } else { 25037 this.floatingBox.appendTo( 'body' ).hide(); 25038 } 25039 25040 if ( this.nks_selector.length > 0 || this.alt_selector.length > 0 ) { 25041 this.is_nks_alt = true; 25042 this.engineTemplate = tcAPI.templateEngine.tc_floating_box_nks; 25043 } 25044 25045 this.addEvents(); 25046 } 25047 }; 25048 25049 $.tcFloatingTotalsBox = function( this_epo_totals_container, is_quickview, main_cart ) { 25050 var data = false; 25051 25052 if ( this_epo_totals_container && this_epo_totals_container.length && this_epo_totals_container.data( 'tcfloatingtotalsbox' ) === undefined ) { 25053 data = new FloatingTotalsBox( this_epo_totals_container, is_quickview, main_cart ); 25054 this_epo_totals_container.data( 'tcfloatingtotalsbox', data ); 25055 } 25056 25057 return data; 25058 }; 25059 25060 $.tc_product_image = {}; 25061 $.tc_product_image_store = {}; 25062 25063 // replace obj1 values with obj2 values 25064 $.tc_replace_object_values = function( obj1, obj2 ) { 25065 Object.keys( obj1 ).forEach( function( x ) { 25066 Object.keys( obj1[ x ] ).forEach( function( attr ) { 25067 if ( undefined !== obj2[ x ] && undefined !== obj2[ x ][ attr ] && Object.prototype.hasOwnProperty.call( obj2[ x ], attr ) ) { 25068 obj1[ x ][ attr ] = obj2[ x ][ attr ]; 25069 } 25070 } ); 25071 } ); 25072 return obj1; 25073 }; 25074 // copy obj2 values to obj1 25075 $.tc_maybe_copy_object_values = function( obj1, obj2 ) { 25076 Object.keys( obj2 ).forEach( function( x ) { 25077 Object.keys( obj2[ x ] ).forEach( function( attr ) { 25078 if ( undefined !== obj2[ x ] && Object.prototype.hasOwnProperty.call( obj2[ x ], attr ) && undefined !== obj2[ x ][ attr ] && ( undefined === obj1[ x ] || undefined === obj1[ x ][ attr ] ) ) { 25079 if ( undefined === obj1[ x ] ) { 25080 obj1[ x ] = {}; 25081 } 25082 obj1[ x ][ attr ] = obj2[ x ][ attr ]; 25083 } 25084 } ); 25085 } ); 25086 return obj1; 25087 }; 25088 25089 $.tc_pre_populate_store = function() { 25090 var obj = {}; 25091 25092 obj[ 0 ] = {}; 25093 obj[ 1 ] = {}; 25094 obj[ 2 ] = {}; 25095 obj[ 3 ] = {}; 25096 25097 obj[ 0 ].src = ''; 25098 obj[ 0 ].srcset = ''; 25099 obj[ 0 ].sizes = ''; 25100 obj[ 0 ].title = ''; 25101 obj[ 0 ].alt = ''; 25102 obj[ 0 ][ 'data-src' ] = ''; 25103 obj[ 0 ][ 'data-large_image' ] = ''; 25104 obj[ 0 ][ 'data-large_image_width' ] = ''; 25105 obj[ 0 ][ 'data-large_image_height' ] = ''; 25106 obj[ 1 ][ 'data-thumb' ] = ''; 25107 obj[ 2 ].src = ''; 25108 obj[ 3 ].href = ''; 25109 obj[ 3 ].title = ''; 25110 25111 return obj; 25112 }; 25113 25114 $.tc_populate_store = function( img, product_element ) { 25115 var $gallery_img = product_element.find( '.flex-control-nav li:eq(0) img' ); 25116 var $gallery_wrapper = product_element.find( '.woocommerce-product-gallery__wrapper ' ); 25117 var $product_img_wrap = $gallery_wrapper.find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ).eq( 0 ); 25118 var $product_img = img; 25119 var $product_link = img.closest( 'a' ); 25120 var obj = {}; 25121 25122 obj[ 0 ] = {}; 25123 obj[ 1 ] = {}; 25124 obj[ 2 ] = {}; 25125 obj[ 3 ] = {}; 25126 25127 obj[ 0 ].src = $product_img.attr( 'src' ); 25128 obj[ 0 ].srcset = $product_img.attr( 'srcset' ); 25129 obj[ 0 ].sizes = $product_img.attr( 'sizes' ); 25130 obj[ 0 ].title = $product_img.attr( 'title' ); 25131 obj[ 0 ].alt = $product_img.attr( 'alt' ); 25132 obj[ 0 ][ 'data-src' ] = $product_img.attr( 'data-src' ); 25133 obj[ 0 ][ 'data-large_image' ] = $product_img.attr( 'data-large_image' ); 25134 obj[ 0 ][ 'data-large_image_width' ] = $product_img.attr( 'data-large_image_width' ); 25135 obj[ 0 ][ 'data-large_image_height' ] = $product_img.attr( 'data-large_image_height' ); 25136 obj[ 1 ][ 'data-thumb' ] = $product_img_wrap.attr( 'data-thumb' ); 25137 obj[ 2 ].src = $gallery_img.attr( 'src' ); 25138 obj[ 3 ].href = $product_link.attr( 'href' ); 25139 obj[ 3 ].title = $product_link.attr( 'title' ); 25140 25141 return obj; 25142 }; 25143 25144 $.tc_maybe_copy_object_values_from_img = function( obj1, img, product_element ) { 25145 var $gallery_img = product_element.find( '.flex-control-nav li:eq(0) img' ); 25146 var $gallery_wrapper = product_element.find( '.woocommerce-product-gallery__wrapper' ); 25147 var $product_img_wrap = $gallery_wrapper.find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ).eq( 0 ); 25148 var $product_img = img; 25149 var $product_link = img.closest( 'a' ); 25150 25151 var all = [ $product_img, $product_img_wrap, $gallery_img, $product_link ]; 25152 var attrs_all = [ 25153 [ 'src', 'srcset', 'sizes', 'title', 'alt', 'data-src', 'data-large_image', 'data-large_image_width', 'data-large_image_height', 'large-image' ], 25154 [ 'data-thumb' ], 25155 [ 'src' ], 25156 [ 'href', 'title' ] 25157 ]; 25158 var i; 25159 var item; 25160 var attrs; 25161 var attr; 25162 var j; 25163 25164 for ( i = 0; i < all.length; i++ ) { 25165 item = all[ i ]; 25166 25167 if ( item && item[ 0 ] ) { 25168 attrs = item[ 0 ].attributes; 25169 25170 for ( j = 0; j < attrs.length; j++ ) { 25171 attr = attrs[ j ]; 25172 25173 if ( attr.specified && attrs_all[ i ].indexOf( attr.name ) !== -1 ) { 25174 if ( obj1[ i ] === undefined || ( obj1[ i ] !== undefined && obj1[ i ][ attr.name ] === undefined ) ) { 25175 if ( undefined === obj1[ i ] ) { 25176 obj1[ i ] = {}; 25177 } 25178 obj1[ i ][ attr.name ] = attr.value; 25179 } 25180 } 25181 } 25182 } 25183 } 25184 25185 return obj1; 25186 }; 25187 25188 // Stores a default attribute for an element so it can be reset later 25189 $.fn.tc_set_attr = function( attr, value, id ) { 25190 if ( undefined === id ) { 25191 id = 0; 25192 } 25193 if ( undefined === $.tc_product_image[ id ] || ( undefined !== $.tc_product_image[ id ] && undefined === $.tc_product_image[ id ][ attr ] ) ) { 25194 if ( undefined === $.tc_product_image[ id ] ) { 25195 $.tc_product_image[ id ] = {}; 25196 } 25197 $.tc_product_image[ id ][ attr ] = ''; 25198 if ( this.attr( attr ) ) { 25199 $.tc_product_image[ id ][ attr ] = this.attr( attr ); 25200 } 25201 } 25202 if ( false === value ) { 25203 this.removeAttr( attr ); 25204 } else { 25205 this.attr( attr, value ); 25206 } 25207 }; 25208 25209 // Reset a default attribute for an element so it can be reset later 25210 $.fn.tc_reset_attr = function( attr, id ) { 25211 if ( undefined === id ) { 25212 id = 0; 25213 } 25214 if ( undefined === $.tc_product_image[ id ] ) { 25215 return; 25216 } 25217 if ( undefined !== $.tc_product_image[ id ][ attr ] ) { 25218 this.attr( attr, $.tc_product_image[ id ][ attr ] ); 25219 } 25220 delete $.tc_product_image[ id ][ attr ]; 25221 }; 25222 25223 $.fn.tc_update_attr = function( attr, id ) { 25224 if ( undefined === id ) { 25225 id = 0; 25226 } 25227 if ( undefined !== $.tc_product_image[ id ] ) { 25228 $.tc_product_image[ id ][ attr ] = this.attr( attr ); 25229 } 25230 }; 25231 25232 $.fn.tc_image_update = function( dom, image ) { 25233 var element = $( dom ); 25234 var $form = this; 25235 var $image = $( image ); 25236 var epo_object = $form.data( 'epo_object' ); 25237 var image_info; 25238 var $product_img; 25239 var product_element = epo_object.main_product.closest( '#product-' + epo_object.product_id ); 25240 var $product_element = product_element; 25241 var $product_img_thumb; 25242 var $product_link; 25243 var use_image_info; 25244 25245 if ( product_element.length <= 0 ) { 25246 $product_element = epo_object.main_product.closest( '.post-' + epo_object.product_id ); 25247 } 25248 25249 $product_img_thumb = $product_element.find( '.flex-control-nav li:eq(0) img' ); 25250 25251 if ( element.is( 'select' ) ) { 25252 element = element.children( 'option:selected' ); 25253 } 25254 image_info = element.data( 'image-variations' ); 25255 25256 if ( TMEPOJS.tm_epo_global_product_image_selector !== '' ) { 25257 $product_img = $( TMEPOJS.tm_epo_global_product_image_selector ); 25258 } else { 25259 $product_img = $product_element.find( 'a.woocommerce-main-image img, img.woocommerce-main-image,a img' ).not( '.thumbnails img,.product_list_widget img,img.emoji,a.woocommerce-product-gallery__trigger img' ).first(); 25260 } 25261 $product_link = $product_img.closest( 'a' ); 25262 25263 if ( $product_img.length > 1 ) { 25264 $product_img = $product_img.first(); 25265 } 25266 25267 if ( element && image_info && $image.length > 0 ) { 25268 $image.removeAttr( 'data-o_src' ).removeAttr( 'data-o_title' ).removeAttr( 'data-o_alt' ).removeAttr( 'data-o_srcset' ).removeAttr( 'data-o_sizes' ).removeAttr( 'srcset' ).removeAttr( 'sizes' ); 25269 25270 use_image_info = image_info.imagep; 25271 if ( ! image_info.imagep.image_link ) { 25272 use_image_info = image_info.image; 25273 } 25274 25275 $image.attr( 'title', use_image_info.image_title ); 25276 $image.attr( 'alt', use_image_info.image_alt ); 25277 if ( use_image_info.image_srcset ) { 25278 $image.attr( 'srcset', use_image_info.image_srcset ); 25279 } 25280 if ( use_image_info.image_sizes ) { 25281 $image.attr( 'sizes', use_image_info.image_sizes ); 25282 } 25283 25284 $product_img.tc_set_attr( 'title', use_image_info.image_title ); 25285 $product_img.tc_set_attr( 'alt', use_image_info.image_alt ); 25286 25287 $product_img.tc_set_attr( 'data-large-image', use_image_info.image_link ); 25288 if ( $product_img.data.wc27_zoom_target ) { 25289 $product_img.data.wc27_zoom_target.tc_set_attr( 'data-thumb', use_image_info.image_link ); 25290 $product_img_thumb.tc_set_attr( 'src', use_image_info.image_link ); 25291 if ( use_image_info.image_srcset ) { 25292 $product_img_thumb.tc_set_attr( 'srcset', use_image_info.image_srcset ); 25293 } 25294 if ( use_image_info.image_sizes ) { 25295 $product_img_thumb.tc_set_attr( 'sizes', use_image_info.image_sizes ); 25296 } 25297 } 25298 25299 $product_link.tc_set_attr( 'href', use_image_info.image_link ); 25300 $product_link.tc_set_attr( 'title', use_image_info.image_caption ); 25301 } else { 25302 $product_img.tc_reset_attr( 'title' ); 25303 $product_img.tc_reset_attr( 'alt' ); 25304 25305 $product_img.tc_reset_attr( 'data-large-image' ); 25306 if ( $product_img.data.wc27_zoom_target ) { 25307 $product_img.data.wc27_zoom_target.tc_reset_attr( 'data-thumb' ); 25308 $product_img_thumb.tc_reset_attr( 'src' ); 25309 $product_img_thumb.tc_reset_attr( 'srcset' ); 25310 $product_img_thumb.tc_reset_attr( 'sizes' ); 25311 } 25312 25313 $product_link.tc_reset_attr( 'href' ); 25314 $product_link.tc_reset_attr( 'title' ); 25315 } 25316 }; 25317 25318 // variations checker 25319 $.fn.tm_find_matching_variations = function( product_variations, settings ) { 25320 var matching = []; 25321 var i; 25322 var variation; 25323 25324 if ( product_variations ) { 25325 for ( i = 0; i < product_variations.length; i += 1 ) { 25326 variation = product_variations[ i ]; 25327 25328 if ( $.fn.tm_variations_match( variation.attributes, settings ) ) { 25329 matching.push( variation ); 25330 } 25331 } 25332 } 25333 25334 return matching; 25335 }; 25336 25337 $.fn.tm_variations_match = function( attrs1, attrs2 ) { 25338 var match = true; 25339 var val1; 25340 var val2; 25341 25342 Object.keys( attrs1 ).forEach( function( x ) { 25343 if ( Object.prototype.hasOwnProperty.call( attrs1, x ) ) { 25344 val1 = attrs1[ x ]; 25345 val2 = attrs2[ x ]; 25346 25347 if ( val1 !== undefined && val2 !== undefined && val1.length !== 0 && val2.length !== 0 && val1 !== val2 ) { 25348 match = false;
25349 } 25350 } 25351 } ); 25352 25353 return match; 25354 }; 25355 25356 function get_element_from_field( element, ckey ) { 25357 var $element = $( element ); 25358 var data_uniqid; 25359 var the_epo_id; 25360 var _class; 25361 var epoContainer; 25362 25363 if ( $element.length === 0 ) { 25364 return; 25365 } 25366 25367 if ( $element.is( '.cpf-section' ) ) { 25368 return element.find( '.tm-epo-field' ); 25369 } 25370 data_uniqid = $element.attr( 'data-uniqid' ); 25371 epoContainer = $element.closest( tcAPI.epoSelector ); 25372 the_epo_id = epoContainer.attr( 'data-epo-id' ); 25373 25374 if ( ! epoContainer.is( '.reactivate' ) && tcAPI.getElementFromFieldCache && tcAPI.getElementFromFieldCache[ the_epo_id ] && tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ] && tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] ) { 25375 return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ]; 25376 } 25377 _class = $element 25378 .attr( 'class' ) 25379 .split( ' ' ) 25380 .map( function( cls ) { 25381 if ( cls.indexOf( 'cpf-type-', 0 ) !== -1 ) { 25382 return cls; 25383 } 25384 return null; 25385 } ) 25386 .filter( function( v ) { 25387 if ( v !== null && v !== undefined ) { 25388 return v; 25389 } 25390 return null; 25391 } ); 25392 25393 if ( _class.length > 0 ) { 25394 _class = _class[ 0 ]; 25395 if ( _class === 'cpf-type-product' ) { 25396 if ( $element.is( '.cpf-type-product-mode-product' ) || $element.is( '.cpf-type-product-checkbox' ) || $element.is( '.cpf-type-product-thumbnailmultiple' ) || $element.is( '.cpf-type-product-custombundle' ) ) { 25397 _class = 'cpf-type-checkbox'; 25398 } else if ( $element.is( '.cpf-type-product-dropdown' ) ) { 25399 _class = 'cpf-type-select'; 25400 } else { 25401 _class = 'cpf-type-radio'; 25402 } 25403 } 25404 if ( tcAPI.getElementFromFieldCache[ the_epo_id ] === undefined ) { 25405 tcAPI.getElementFromFieldCache[ the_epo_id ] = []; 25406 } 25407 if ( tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ] === undefined ) { 25408 tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ] = []; 25409 } 25410 switch ( _class ) { 25411 case 'cpf-type-radio': 25412 tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tmcp-radio' ); 25413 return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ]; 25414 25415 case 'cpf-type-checkbox': 25416 tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tmcp-checkbox' ); 25417 return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ]; 25418 25419 case 'cpf-type-select': 25420 tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tmcp-select' ); 25421 return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ]; 25422 25423 case 'cpf-type-selectmultiple': 25424 tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tmcp-selectmultiple' ); 25425 return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ]; 25426 25427 case 'cpf-type-textarea': 25428 tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tmcp-textarea' ); 25429 return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ]; 25430 25431 case 'cpf-type-textfield': 25432 tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tmcp-textfield' ); 25433 return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ]; 25434 25435 case 'cpf-type-color': 25436 tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tm-color-picker' ); 25437 return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ]; 25438 25439 case 'cpf-type-range': 25440 tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tmcp-range' ); 25441 return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ]; 25442 25443 case 'cpf-type-date': 25444 tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tmcp-date' ); 25445 return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ]; 25446 25447 case 'cpf-type-time': 25448 tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.find( '.tm-epo-field.tmcp-time' ); 25449 return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ]; 25450
25451 case 'cpf-type-variations': 25452 tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ] = $element.closest( '.cpf-section' ).find( '.tm-epo-field.tm-epo-variation-element' ); 25453 return tcAPI.getElementFromFieldCache[ the_epo_id ][ data_uniqid ][ ckey ]; 25454 } 25455 } 25456 } 25457 25458 // tc-lightbox 25459 if ( ! $().tclightbox ) { 25460 $.fn.tclightbox = function() { 25461 var elements = this; 25462 25463 if ( elements.length === 0 ) { 25464 return; 25465 } 25466 25467 return elements.toArray().forEach( function( lb ) { 25468 var $this = $( lb ); 25469 var _imgsrc; 25470 var _label; 25471 var _input; 25472 var tclightboxwrap; 25473 var _img_button; 25474 var preload_img; 25475 var addButtonEvent; 25476 25477 if ( $this.is( '.tcinit' ) ) { 25478 return; 25479 } 25480 _imgsrc = $this.attr( 'src' ) || $this.attr( 'data-original' ); 25481 _label = $this.closest( 'label' ); 25482 _input = _label.closest( '.tmcp-field-wrap' ).find( ".tm-epo-field[id='" + _label.attr( 'for' ) + "']" ); 25483 _imgsrc = $this.attr( 'data-large_image' ) || _input.attr( 'data-imagel' ) || _input.attr( 'data-imagep' ) || _input.attr( 'data-image' ) || _imgsrc; 25484 25485 if ( ! _imgsrc ) { 25486 return; 25487 } 25488 25489 $this.addClass( 'tcinit' ).before( $.epoAPI.template.html( tcAPI.templateEngine.tc_lightbox, {} ) ); 25490 tclightboxwrap = $this.prev(); 25491 25492 $this.wrap( "<div class='tc-lightbox-image-wrap'/>" ); 25493 $this.after( tclightboxwrap ); 25494 25495 _img_button = tclightboxwrap.find( '.tc-lightbox-button' ); 25496 25497 addButtonEvent = function() { 25498 _img_button.addClass( 'tcinit' ).on( 'click.tclightbox', function( buttonevent ) { 25499 var size; 25500 var _img; 25501 25502 if ( $( '.tc-closing.tc-lightbox' ).length > 0 ) { 25503 return; 25504 } 25505 25506 size = $.epoAPI.dom.size(); 25507 _img = $( '<img>' ) 25508 .addClass( 'tc-lightbox-img' ) 25509 .attr( 'src', _imgsrc ) 25510 .css( 'maxHeight', size.visibleHeight + 'px' ) 25511 .css( 'maxWidth', size.visibleWidth + 'px' ); 25512 25513 $.tcFloatBox( { 25514 fps: 1, 25515 ismodal: false, 25516 width: 'auto', 25517 height: 'auto', 25518 classname: 'flasho tc-lightbox', 25519 animateIn: 'tc-lightbox-zoomin', 25520 animateOut: 'tc-lightbox-zoomout', 25521 data: $.epoAPI.template.html( tcAPI.templateEngine.tc_lightbox_zoom, { img: _img[ 0 ].outerHTML } ), 25522 zIndex: 102001, 25523 cancelClass: '.tc-lightbox-img, .tc-lightbox-button-close', 25524 unique: true 25525 } ); 25526 25527 buttonevent.preventDefault(); 25528 } ); 25529 }; 25530 if ( TMEPOJS.tm_epo_preload_lightbox_image === 'yes' ) { 25531 preload_img = new Image(); 25532 preload_img.src = _imgsrc; 25533 preload_img.onload = function() { 25534 addButtonEvent(); 25535 }; 25536 } else { 25537 addButtonEvent(); 25538 } 25539 } ); 25540 }; 25541 } 25542 25543 // Start Section popup 25544 if ( ! $().tmsectionpoplink ) { 25545 $.fn.tmsectionpoplink = function() { 25546 var elements = this; 25547 25548 if ( elements.length === 0 ) { 25549 return; 25550 } 25551 25552 return elements.toArray().forEach( function( pl ) { 25553 var $this = $( pl ); 25554 var id; 25555 var title; 25556 var section; 25557 var clicked; 25558 var cancelfunc; 25559 var cancelpop; 25560 25561 if ( $this.data( 'tmsectionpoplink' ) ) { 25562 return; 25563 } 25564 25565 $this.data( 'tmsectionpoplink', true ); 25566 id = $this.attr( 'data-sectionid' ); 25567 title = TMEPOJS.i18n_addition_options; 25568 section = $this.closest( ".cpf-section[data-uniqid='" + id + "']" ); 25569 clicked = false; 25570 cancelfunc = function() { 25571 var pop = $( '#tm-section-pop-up' ); 25572 pop.parents().removeClass( 'noanimated' ); 25573 25574 pop.after( section ); 25575 pop.remove(); 25576 25577 section.find( '.tm-section-link' ).show(); 25578 section.find( '.tm-section-pop' ).hide(); 25579 }; 25580 cancelpop = function( e ) { 25581 if ( e.target === $( '.flasho' )[ 0 ] || $( e.target ).closest( '.flasho' ).length ) { 25582 return; 25583 } 25584 25585 cancelfunc(); 25586 }; 25587 25588 if ( $this.attr( 'data-title' ) ) { 25589 title = $this.attr( 'data-title' ); 25590 } 25591 25592 $this.on( 'click.tmsectionpoplink', function( e ) { 25593 var pop; 25594 25595 e.preventDefault(); 25596 clicked = false; 25597 25598 section.before( 25599 $.epoAPI.template.html( tcAPI.templateEngine.tc_section_pop_link, { 25600 title: title, 25601 close: TMEPOJS.i18n_close 25602 } ) 25603 ); 25604 25605 pop = $( '#tm-section-pop-up' ); 25606 25607 pop.on( 'click', cancelpop ); 25608 25609 pop.find( '.float-editbox' ).prepend( section ); 25610 25611 section.find( '.tm-section-link' ).hide(); 25612 section.find( '.tm-section-pop' ).show(); 25613 25614 pop.parents().addClass( 'noanimated' ); 25615 25616 pop.find( '.floatbox-cancel' ).on( 'click', function() { 25617 if ( clicked ) { 25618 return; 25619 } 25620 clicked = true; 25621 cancelfunc(); 25622 } ); 25623 jWindow.trigger( 'tmlazy' ); 25624 jWindow.trigger( 'tmsectionpoplink' ); 25625 } ); 25626 } ); 25627 }; 25628 } // End Section popup 25629 25630 function getVariationIdSelector( currentCart ) { 25631 var variationIdSelector = "input[name^='variation_id']"; 25632
25633 if ( currentCart.find( 'input.variation_id' ).length > 0 ) { 25634 variationIdSelector = 'input.variation_id'; 25635 } else { 25636 variationIdSelector = 'input.product-variation-id'; 25637 } 25638 25639 return variationIdSelector; 25640 } 25641 25642 function getVariationIdElement( currentCart, not ) { 25643 var variationIdSelector = getVariationIdSelector( currentCart ); 25644 var variationIdElement = currentCart.find( variationIdSelector ); 25645 25646 if ( currentCart.is( '.tc-epo-element-product-container-cart' ) ) { 25647 variationIdElement = currentCart.closest( '.tc-epo-element-product-li-container' ).find( variationIdSelector ); 25648 } else { 25649 variationIdElement = currentCart.find( variationIdSelector ).not( '.tc-epo-element-product-container-variation-id ' + variationIdSelector ); 25650 } 25651 if ( not ) { 25652 variationIdElement = variationIdElement.not( not ); 25653 } 25654 25655 return variationIdElement; 25656 } 25657 25658 function getCurrentVariation( currentCart ) { 25659 var field_div; 25660 var newCart; 25661 25662 if ( currentCart.is( '.tc-epo-element-product-container-cart' ) ) { 25663 field_div = currentCart.closest( '.cpf-element' ); 25664 if ( field_div.is( '.cpf-type-product-thumbnailmultiple' ) || field_div.is( '.cpf-type-product-checkbox' ) || field_div.is( '.cpf-type-product-custombundle' ) ) { 25665 newCart = currentCart.closest( '.tc-epo-element-product-holder' ).find( '.tc-epo-element-product-container-variation-id' ); 25666 } else if ( field_div.is( '.cpf-type-product-thumbnail' ) || field_div.is( '.cpf-type-product-radio' ) || field_div.is( '.cpf-type-product-dropdown' ) || field_div.is( '.cpf-type-product-single' ) ) { 25667 newCart = field_div.find( '.tc-epo-element-product-container-variation-id' ); 25668 } 25669 if ( newCart && newCart.length ) { 25670 currentCart = newCart; 25671 } 25672 } 25673 return currentCart.find( getVariationIdSelector( currentCart ) ).val() || 0; 25674 } 25675 25676 function getQtyElement( currentCart ) { 25677 var qty = currentCart.find( tcAPI.qtySelector ).last(); 25678 if ( qty.length === 0 ) { 25679 qty = currentCart.find( tcAPI.associateQtySelector ).last(); 25680 } 25681 qty = $.epoAPI.applyFilter( 'tc_getQtyElement', qty, currentCart ); 25682 return qty; 25683 } 25684 25685 function getCurrentQty( currentCart ) { 25686 return $.epoAPI.applyFilter( 'tc_getCurrentQty', $.epoAPI.math.toFloat( getQtyElement( currentCart ).val() ), currentCart ); 25687 } 25688 25689 function add_variation_event( name, selector, func ) { 25690 lateVariationEvent[ lateVariationEvent.length ] = { 25691 name: name, 25692 selector: selector, 25693 func: func 25694 }; 25695 } 25696 25697 function field_is_active( field, nochecks, single, simpleCheck ) { 25698 var ret = true; 25699 var insideProductCheck = false; 25700 var productElement; 25701 field = $( field ); 25702 productElement = field.filter( '.tc-epo-field-product' ); 25703 if ( productElement.length && productElement.data( 'islogicinit' ) === undefined ) { 25704 insideProductCheck = true; 25705 } 25706 field.toArray().forEach( function( element ) { 25707 if ( ! ret && field.has( '.tc-epo-field-product' ).length ) { 25708 if ( insideProductCheck || productElement.is( '.tcdisabled' ) ) { 25709 if ( simpleCheck ) { 25710 field_check_active_simple( element ); 25711 } else { 25712 field_check_active( element, nochecks, single, simpleCheck ); 25713 } 25714 } 25715 } else if ( simpleCheck ) { 25716 ret = field_check_active_simple( element ); 25717 } else { 25718 ret = field_check_active( element, nochecks, single, simpleCheck ) && ret; 25719 } 25720 } ); 25721 25722 return ret; 25723 } 25724 25725 function field_check_active_simple( field ) { 25726 var hideElement; 25727 var isInsideProductElement; 25728 var productElementActive; 25729 var productElementSectionActive; 25730 var section; 25731 25732 field = $( field ); 25733 if ( field.is( '.cpf-element' ) ) { 25734 hideElement = field; 25735 field = field.find( '.tmcp-field, .tmcp-fee-field' ); 25736 } else { 25737 hideElement = field.closest( '.cpf-element' ); 25738 } 25739 25740 section = hideElement.closest( '.cpf-section' ); 25741 25742 isInsideProductElement = ! field.is( '.tc-epo-field-product' ) && hideElement.closest( '.cpf-type-product' ); 25743 25744 if ( isInsideProductElement.length ) { 25745 productElementActive = isInsideProductElement.data( 'isactive' ); 25746 isInsideProductElement = isInsideProductElement.closest( '.cpf-section' ); 25747 productElementSectionActive = isInsideProductElement.data( 'isactive' ); 25748 } 25749 if ( productElementActive !== false && productElementSectionActive !== false && hideElement.data( 'isactive' ) !== false && section.data( 'isactive' ) !== false ) { 25750 return true; 25751 } 25752 25753 return false;
25754 } 25755 25756 function field_check_active( field, nochecks, single ) { 25757 var hideElement; 25758 var singleField; 25759 var ul; 25760 var isInsideProductElement; 25761 var productElementActive; 25762 var productElementSectionActive; 25763 var productElementQty; 25764 var section; 25765 var disableElements; 25766 var sectionLi; 25767 var allSectionsDisabled; 25768 var tabSlide; 25769 var epoFields; 25770 25771 field = $( field ); 25772 if ( field.is( '.cpf-element' ) ) { 25773 hideElement = field; 25774 field = field.find( '.tmcp-field, .tmcp-fee-field' ); 25775 } else { 25776 hideElement = field.closest( '.cpf-element' ); 25777 } 25778 25779 section = hideElement.closest( '.cpf-section' ); 25780 sectionLi = section.closest( '.tm-extra-product-options-field' ); 25781 25782 if ( single ) { 25783 ul = field.closest( '.tmcp-ul-wrap' ); 25784 } else { 25785 ul = hideElement; 25786 } 25787 25788 if ( field.is( '.tc-epo-field-product' ) && field.data( 'islogicinit' ) === undefined ) { 25789 field.data( 'islogicinit', 1 ); 25790 } 25791 25792 if ( ! field.is( '.tc-force-disabled' ) ) { 25793 isInsideProductElement = ! field.is( '.tc-epo-field-product' ) && hideElement.closest( '.cpf-type-product' ); 25794 25795 if ( isInsideProductElement.length ) { 25796 productElementQty = isInsideProductElement.find( tcAPI.associateQtySelector ); 25797 if ( productElementQty.length ) { 25798 if ( $.epoAPI.math.toFloat( productElementQty.val() ) > 0 ) { 25799 field.removeClass( 'ignore' ); 25800 productElementQty.removeClass( 'ignore' ); 25801 } else { 25802 field.addClass( 'ignore' ); 25803 productElementQty.addClass( 'ignore' ); 25804 } 25805 } 25806 productElementActive = isInsideProductElement.data( 'isactive' ); 25807 isInsideProductElement = isInsideProductElement.closest( '.cpf-section' ); 25808 productElementSectionActive = isInsideProductElement.data( 'isactive' ); 25809 } 25810 if ( productElementActive !== false && productElementSectionActive !== false && hideElement.data( 'isactive' ) !== false && section.data( 'isactive' ) !== false ) { 25811 singleField = field.first(); 25812 field.prop( 'disabled', false ); 25813 if ( field.data( 'tc-state' ) !== undefined ) { 25814 field.data( 'tc-state', false ); 25815 } 25816 25817 if ( TMEPOJS.tm_epo_show_only_active_quantities !== 'yes' ) { 25818 if ( singleField.is( ':radio, .cpf-type-radio' ) || singleField.is( ':checkbox, .cpf-type-checkbox' ) ) { 25819 field.filter( ':checked' ).closest( '.tmcp-field-wrap' ).find( '.tm-qty, .tc-qty-button' ).prop( 'disabled', false ); 25820 field.not( ':checked' ).closest( '.tmcp-field-wrap' ).find( '.tm-qty, .tc-qty-button' ).prop( 'disabled', true ); 25821 } else if ( singleField.is( 'select, .cpf-type-select, .cpf-type-selectmultiple' ) ) { 25822 if ( singleField.val() ) { 25823 ul.find( '.tm-qty, .tc-qty-button' ).prop( 'disabled', false ); 25824 } else { 25825 ul.find( '.tm-qty, .tc-qty-button' ).prop( 'disabled', true ); 25826 } 25827 } else if ( singleField.val() ) { 25828 ul.find( '.tm-qty, .tc-qty-button' ).prop( 'disabled', false ); 25829 } else { 25830 ul.find( '.tm-qty, .tc-qty-button' ).prop( 'disabled', true ); 25831 } 25832 } else if ( ! nochecks ) { 25833 hideElement.find( '.tm-quantity' ).trigger( 'showhide.cpfcustom' ); 25834 } 25835 25836 if ( ! singleField.is( '.cpf-element' ) ) { 25837 field.removeClass( 'tcdisabled' ).addClass( 'tcenabled' ); 25838 25839 if ( field.is( '.tmcp-upload' ) ) { 25840 if ( field.next( '.tmcp-upload-hidden' ).length ) { 25841 field.next( '.tmcp-upload-hidden' ).removeClass( 'tcdisabled' ).addClass( 'tcenabled' ).prop( 'disabled', false ); 25842 } 25843 } 25844 } 25845 25846 hideElement.removeClass( 'tc-container-disabled' ).addClass( 'tc-container-enabled' ); 25847 hideElement.find( '.product-variation-id, .tc-epo-field-product-counter' ).prop( 'disabled', false ); 25848 25849 field.trigger( { 25850 type: 'tm-field-is-active', 25851 field: field, 25852 value: true 25853 } ); 25854 section.removeClass( 'section-disabled' ); 25855 sectionLi.removeClass( 'tc-hidden' ); 25856 25857 hideElement.closest( '.owl-item' ).removeClass( 'tc-hidden-visibility' ); 25858 25859 return true; 25860 } 25861 } 25862 25863 if ( ! field.is( '.cpf-element' ) ) { 25864 field.prop( 'disabled', true ).removeClass( 'tcenabled' ).addClass( 'tcdisabled' ); 25865 if ( field.data( 'tc-state' ) !== undefined ) { 25866 field.data( 'tc-state', true ); 25867 } 25868 hideElement.find( '.tm-qty, .tc-qty-button' ).prop( 'disabled', true ); 25869 if ( field.is( '.tmcp-upload' ) ) { 25870 if ( field.next( '.tmcp-upload-hidden' ).length ) { 25871 field.next( '.tmcp-upload-hidden' ).removeClass( 'tcenabled' ).addClass( 'tcdisabled' ).prop( 'disabled', true ); 25872 } 25873 } 25874 } 25875 25876 if ( field.is( '.tc-force-disabled' ) ) { 25877 epoFields = hideElement.find( '.tmcp-field, .tmcp-fee-field' ); 25878 if ( epoFields.length !== epoFields.filter( '.tc-force-disabled' ).length ) { 25879 return false;
25880 } 25881 } 25882 25883 hideElement.removeClass( 'tc-container-enabled' ).addClass( 'tc-container-disabled' ); 25884 hideElement.find( '.product-variation-id, .tc-epo-field-product-counter' ).prop( 'disabled', true ); 25885 25886 field.trigger( { 25887 type: 'tm-field-is-active', 25888 field: field, 25889 value: false 25890 } ); 25891 25892 disableElements = section.find( '.cpf-element.tc-container-enabled' ).length === 0; 25893 if ( disableElements ) { 25894 section.addClass( 'section-disabled' ); 25895 allSectionsDisabled = sectionLi.children( '.cpf-section' ).filter( function() { 25896 return ! $( this ).hasClass( 'section-disabled' ); 25897 } ).length === 0; 25898 if ( allSectionsDisabled ) { 25899 sectionLi.addClass( 'tc-hidden' ); 25900 } 25901 } 25902 25903 tabSlide = hideElement.closest( '.tc-tab-slide' ).find( '.cpf-element.tc-container-enabled' ).length === 0; 25904 if ( tabSlide ) { 25905 hideElement.closest( '.owl-item' ).addClass( 'tc-hidden-visibility' ); 25906 } 25907 25908 return false; 25909 } 25910 25911 function tm_variation_check_match( element, val2, operator ) { 25912 var $element = $( element ); 25913 var epoId = $element.attr( 'data-epo_id' ) || $element.attr( 'data-epo-id' ); 25914 var productId = $element.attr( 'data-product_id' ) || $element.attr( 'data-product-id' ); 25915 25916 var variationsForm = $( '.variations_form[data-epo_id="' + epoId + '"][data-product_id="' + productId + '"]' ); 25917 var val1; 25918 var variationIdSelector = 'input[name^="variation_id"]'; 25919 var $variationId; 25920 25921 variationsForm = $.epoAPI.applyFilter( 'tm_variation_check_match_variationsForm', variationsForm, epoId, productId, $element ); 25922 if ( $element.attr( 'data-product_type' ) === 'variation' ) { 25923 variationsForm = $element; 25924 $variationId = productId; 25925 } 25926 if ( variationsForm.length === 0 && $element.is( '.cpf-type-variations' ) && ! epoId && ! productId ) { 25927 variationsForm = $element.closest( '.tc-epo-element-product-container' ); 25928 if ( variationsForm.length ) { 25929 productId = variationsForm.attr( 'data-product_id' ); 25930 $variationId = productId; 25931 } 25932 } 25933 25934 if ( variationsForm.length === 0 ) { 25935 return false; 25936 } 25937 25938 if ( ! $variationId ) { 25939 $variationId = variationsForm.find( variationIdSelector ); 25940 25941 if ( $variationId.length === 0 ) { 25942 variationIdSelector = 'input.variation_id'; 25943 25944 $variationId = variationsForm.find( variationIdSelector ); 25945 25946 if ( $variationId.length === 0 ) { 25947 $variationId = variationsForm.closest( '.tc-epo-element-product-li-container' ).find( '.product-variation-id' ); 25948 } 25949 } 25950 if ( $variationId.length ) { 25951 $variationId = $variationId.val(); 25952 } else { 25953 $variationId = 0; 25954 } 25955 } 25956 25957 if ( element !== null && val2 !== null && element !== undefined && val2 !== undefined && element !== false && val2 !== false ) { 25958 if ( val2 ) { 25959 val2 = parseInt( val2, 10 ); 25960 } else { 25961 val2 = -1; 25962 } 25963 } 25964 25965 val1 = parseInt( $variationId, 10 ); 25966 25967 if ( ! Number.isFinite( val1 ) ) { 25968 val1 = 0; 25969 } 25970 if ( ! Number.isFinite( val2 ) ) { 25971 val2 = 0; 25972 } 25973 25974 switch ( operator ) { 25975 case 'is': 25976 return val1 !== '' && val1 === val2; 25977 25978 case 'isnot': 25979 return val1 !== '' && val1 !== val2; 25980 25981 case 'isempty': 25982 return val1 === '' || val1 === 0; 25983 25984 case 'isnotempty': 25985 return val1 !== '' && val1 !== 0; 25986 25987 case 'startswith': 25988 return val1.toString().startsWith( val2 ); 25989 25990 case 'endswith': 25991 return val1.toString().endsWith( val2 ); 25992 25993 case 'greaterthan': 25994 return parseFloat( val1 ) > parseFloat( val2 ); 25995 25996 case 'lessthan': 25997 return parseFloat( val1 ) < parseFloat( val2 ); 25998 25999 case 'greaterthanequal': 26000 return parseFloat( val1 ) >= parseFloat( val2 ); 26001 26002 case 'lessthanequal': 26003 return parseFloat( val1 ) <= parseFloat( val2 ); 26004 } 26005 return false; 26006 } 26007 26008 function tm_variationattributes_check_match( element, rule ) { 26009 var $element = $( element ); 26010 var val2 = rule.value; 26011 var operator = rule.operator; 26012 var epoId = $element.attr( 'data-epo_id' ) || $element.attr( 'data-epo-id' ); 26013 var productId = $element.attr( 'data-product_id' ) || $element.attr( 'data-product-id' ); 26014 26015 var variationsForm = $( '.variations_form[data-epo_id="' + epoId + '"][data-product_id="' + productId + '"]' ); 26016 var val1; 26017 var $att; 26018 26019 variationsForm = $.epoAPI.applyFilter( 'tm_variation_check_match_variationsForm', variationsForm, epoId, productId, $element );
26020 if ( $element.attr( 'data-product_type' ) === 'variation' ) { 26021 variationsForm = $element; 26022 } 26023 if ( variationsForm.length === 0 && $element.is( '.cpf-type-variations' ) && ! epoId && ! productId ) { 26024 variationsForm = $element.closest( '.tc-epo-element-product-container' ); 26025 if ( variationsForm.length ) { 26026 productId = variationsForm.attr( 'data-product_id' ); 26027 } 26028 } 26029 26030 if ( variationsForm.length === 0 ) { 26031 return false; 26032 } 26033 26034 $att = variationsForm.find( '[name="attribute_' + rule.taxonomy + '"]' ); 26035 26036 if ( ! $att.length ) { 26037 return false; 26038 } 26039 26040 val1 = $att.find( 'option:selected' ).attr( 'value' ); 26041 26042 switch ( operator ) { 26043 case 'is': 26044 return val1 !== '' && val1 === val2; 26045 26046 case 'isnot': 26047 return val1 !== '' && val1 !== val2; 26048 26049 case 'isempty': 26050 return val1 === '' || val1 === 0; 26051 26052 case 'isnotempty': 26053 return val1 !== '' && val1 !== 0; 26054 26055 case 'startswith': 26056 return val1.toString().startsWith( val2 ); 26057 26058 case 'endswith': 26059 return val1.toString().endsWith( val2 ); 26060 } 26061 return false; 26062 } 26063 26064 function tm_check_match( val1, val2, operator ) { 26065 if ( val1 !== null && val2 !== null ) { 26066 val1 = encodeURIComponent( val1 ); 26067 if ( $.qtranxj_split ) { 26068 //backwards compatible 26069 val2 = encodeURIComponent( $.qtranxj_split( decodeURIComponent( val2 ) )[ TMEPOQTRANSLATEXJS.language ] ); 26070 } else { 26071 //backwards compatible 26072 val2 = encodeURIComponent( decodeURIComponent( val2 ) ); 26073 } 26074 26075 if ( val1 ) { 26076 val1 = val1.toLowerCase(); 26077 } else { 26078 val1 = ''; 26079 } 26080 if ( val2 ) { 26081 val2 = val2.toLowerCase(); 26082 } else { 26083 val2 = ''; 26084 } 26085 } else { 26086 return false; 26087 } 26088 26089 val1 = val1.toString(); 26090 val2 = val2.toString(); 26091 26092 switch ( operator ) { 26093 case 'is': 26094 return val1 !== null && val1 === val2; 26095 26096 case 'isnot': 26097 return val1 !== null && val1 !== val2; 26098 26099 case 'isempty': 26100 return ! ( val1 !== 'undefined' && val1 !== undefined && val1 !== '' ); 26101 26102 case 'isnotempty': 26103 return val1 !== 'undefined' && val1 !== undefined && val1 !== ''; 26104 26105 case 'startswith': 26106 return val1.startsWith( val2 ); 26107 26108 case 'endswith': 26109 return val1.endsWith( val2 ); 26110 26111 case 'greaterthan': 26112 return parseFloat( val1 ) > parseFloat( val2 ); 26113 26114 case 'lessthan': 26115 return parseFloat( val1 ) < parseFloat( val2 ); 26116 26117 case 'greaterthanequal': 26118 return parseFloat( val1 ) >= parseFloat( val2 ); 26119 26120 case 'lessthanequal': 26121 return parseFloat( val1 ) <= parseFloat( val2 ); 26122 } 26123 26124 return false; 26125 } 26126 26127 function tm_check_section_match( elements, operator ) { 26128 var any_checked; 26129 var val; 26130 var all_elements = elements.find( '.cpf-element' ); 26131 var radio_checked; 26132 var checkbox_checked; 26133 var noSplit = false; 26134 26135 if ( elements.is( '.tc-hidden' ) ) { 26136 if ( operator === 'isnotempty' ) { 26137 return false; 26138 } else if ( operator === 'isempty' ) { 26139 return true; 26140 } 26141 } 26142 26143 if ( operator === 'isnotempty' ) { 26144 any_checked = false; 26145 } else if ( operator === 'isempty' ) { 26146 any_checked = true; 26147 } 26148 26149 $( all_elements ).toArray().forEach( function( element ) { 26150 var _class; 26151 var elementToCheck = ''; 26152 26153 element = $( element ); 26154 if ( element.is( '.cpf-type-product' ) ) { 26155 elementToCheck = ':not(' + tcAPI.associatedEpoSelector + ' .tm-epo-field)'; 26156 } 26157 if ( field_is_active( element, undefined, undefined, true ) ) { 26158 _class = element 26159 .attr( 'class' ) 26160 .split( ' ' ) 26161 .map( function( cls ) { 26162 if ( cls.indexOf( 'cpf-type-', 0 ) !== -1 ) { 26163 return cls; 26164 } 26165 return null; 26166 } ) 26167 .filter( function( v ) { 26168 if ( v !== null && v !== undefined ) { 26169 return v; 26170 } 26171 return null; 26172 } ); 26173 26174 if ( _class.length > 0 ) { 26175 _class = _class[ 0 ]; 26176 if ( _class === 'cpf-type-product' ) { 26177 noSplit = true; 26178 if ( element.is( '.cpf-type-product-mode-product' ) || element.is( '.cpf-type-product-checkbox' ) || element.is( '.cpf-type-product-thumbnailmultiple' ) || element.is( '.cpf-type-product-custombundle' ) ) { 26179 _class = 'cpf-type-checkbox'; 26180 } else if ( element.is( '.cpf-type-product-dropdown' ) ) { 26181 _class = 'cpf-type-select'; 26182 } else { 26183 _class = 'cpf-type-radio'; 26184 } 26185 } 26186 switch ( _class ) { 26187 case 'cpf-type-radio':
26188 radio_checked = element.find( 'input.tm-epo-field.tmcp-radio:checked' + elementToCheck ); 26189 if ( operator === 'isnotempty' ) { 26190 any_checked = any_checked || radio_checked.length > 0; 26191 if ( radio_checked.length > 0 ) { 26192 val = radio_checked.length; 26193 } 26194 } else if ( operator === 'isempty' ) { 26195 any_checked = any_checked && radio_checked.length === 0; 26196 } 26197 break; 26198 26199 case 'cpf-type-checkbox': 26200 checkbox_checked = element.find( 'input.tm-epo-field.tmcp-checkbox:checked' + elementToCheck ); 26201 if ( operator === 'isnotempty' ) { 26202 any_checked = any_checked || checkbox_checked.length > 0; 26203 if ( checkbox_checked.length > 0 ) { 26204 val = checkbox_checked.length; 26205 } 26206 } else if ( operator === 'isempty' ) { 26207 any_checked = any_checked && checkbox_checked.length === 0; 26208 } 26209 break; 26210 26211 case 'cpf-type-select': 26212 val = element.find( 'select.tm-epo-field.tmcp-select' + elementToCheck ).val(); 26213 if ( val && ! noSplit ) { 26214 val = val.slice( 0, val.lastIndexOf( '_' ) ); 26215 } 26216 break; 26217 26218 case 'cpf-type-selectmultiple': 26219 val = element.find( 'select.tm-epo-field.tmcp-selectmultiple' + elementToCheck ).val(); 26220 if ( val && ! noSplit ) { 26221 val.forEach( function( option, i ) { 26222 val[ i ] = option.slice( 0, option.lastIndexOf( '_' ) ); 26223 } ); 26224 } 26225 break; 26226 26227 default: 26228 val = element.find( '.tm-epo-field' + elementToCheck ).val(); 26229 break; 26230 } 26231 if ( Array.isArray( val ) ) { 26232 if ( operator === 'isnotempty' ) { 26233 any_checked = any_checked || val.some( function( item ) { 26234 return tm_check_match( item, '', operator ); 26235 } ); 26236 } else if ( operator === 'isempty' ) { 26237 any_checked = any_checked && val.every( function( item ) { 26238 return tm_check_match( item, '', operator ); 26239 } ); 26240 } 26241 } else if ( operator === 'isnotempty' ) { 26242 any_checked = any_checked || tm_check_match( val, '', operator ); 26243 } else if ( operator === 'isempty' ) { 26244 any_checked = any_checked && tm_check_match( val, '', operator ); 26245 } 26246 } else { 26247 any_checked = false; 26248 } 26249 } 26250 } ); 26251 26252 return any_checked; 26253 } 26254 26255 function tm_check_field_match( f ) { 26256 var element = f.element; 26257 var operator = f.rule.operator; 26258 var value = f.rule.value; 26259 var type = f.type; 26260 var val; 26261 var radio_checked; 26262 var checkbox_checked; 26263 var ret; 26264 var _class; 26265 var noSplit = false; 26266 var elementToCheck = ''; 26267 26268 if ( type === 'quantity' ) { 26269 return tm_check_match( element.val(), value, operator ); 26270 } 26271 if ( type === 'productid' ) { 26272 return tm_check_match( element, value, operator ); 26273 } 26274 if ( type === 'variation' ) { 26275 return tm_variation_check_match( element, value, operator ); 26276 } 26277 if ( type === 'variationattributes' ) { 26278 return tm_variationattributes_check_match( element, f.rule ); 26279 } 26280 element = $( f.element ); 26281 26282 if ( ! element.length ) { 26283 return false; 26284 } 26285 if ( element.is( '.cpf-section' ) ) { 26286 return tm_check_section_match( element, operator ); 26287 } 26288 if ( element.is( '.cpf-type-product' ) ) { 26289 elementToCheck = ':not(' + tcAPI.associatedEpoSelector + ' .tm-epo-field)'; 26290 } 26291 _class = element 26292 .attr( 'class' ) 26293 .split( ' ' ) 26294 .map( function( cls ) { 26295 if ( cls.indexOf( 'cpf-type-', 0 ) !== -1 ) { 26296 return cls; 26297 } 26298 return null; 26299 } ) 26300 .filter( function( v ) { 26301 if ( v !== null && v !== undefined ) { 26302 return v; 26303 } 26304 return null; 26305 } ); 26306 26307 if ( _class.length > 0 ) { 26308 _class = _class[ 0 ]; 26309 if ( _class === 'cpf-type-product' ) { 26310 noSplit = true; 26311 if ( element.is( '.cpf-type-product-mode-product' ) || element.is( '.cpf-type-product-checkbox' ) || element.is( '.cpf-type-product-thumbnailmultiple' ) || element.is( '.cpf-type-product-custombundle' ) ) { 26312 _class = 'cpf-type-checkbox'; 26313 } else if ( element.is( '.cpf-type-product-dropdown' ) ) { 26314 _class = 'cpf-type-select'; 26315 } else { 26316 _class = 'cpf-type-radio'; 26317 } 26318 } 26319 switch ( _class ) { 26320 case 'cpf-type-radio':
26321 radio_checked = element.find( 'input.tm-epo-field.tmcp-radio:checked' + elementToCheck ); 26322 26323 if ( operator === 'is' || operator === 'isnot' ) { 26324 if ( radio_checked.length === 0 && operator === 'is' ) { 26325 return false; 26326 } 26327 if ( radio_checked.length === 0 && operator === 'isnot' ) { 26328 return true; 26329 } 26330 } 26331 if ( operator === 'isnotempty' ) { 26332 return radio_checked.length > 0; 26333 } 26334 if ( operator === 'isempty' ) { 26335 return radio_checked.length === 0; 26336 } 26337 val = element.find( 'input.tm-epo-field.tmcp-radio:checked' + elementToCheck ).val(); 26338 if ( val && ! noSplit ) { 26339 val = val.slice( 0, val.lastIndexOf( '_' ) ); 26340 } 26341 break; 26342 case 'cpf-type-checkbox': 26343 checkbox_checked = element.find( 'input.tm-epo-field.tmcp-checkbox:checked' + elementToCheck ); 26344 26345 if ( operator === 'is' || operator === 'isnot' ) { 26346 if ( checkbox_checked.length === 0 && operator === 'is' ) { 26347 return false; 26348 } 26349 if ( checkbox_checked.length === 0 && operator === 'isnot' ) { 26350 return true; 26351 } 26352 ret = false;
26353 checkbox_checked.toArray().forEach( function( el ) { 26354 val = $( el ).val(); 26355 if ( val && ! noSplit ) { 26356 val = val.slice( 0, val.lastIndexOf( '_' ) ); 26357 } 26358 if ( tm_check_match( val, value, operator ) ) { 26359 ret = true; 26360 } else if ( operator === 'isnot' ) { 26361 ret = false; 26362 return false; 26363 } 26364 } ); 26365 return ret; 26366 } 26367 if ( operator === 'isnotempty' ) { 26368 return checkbox_checked.length > 0; 26369 } 26370 if ( operator === 'isempty' ) { 26371 return checkbox_checked.length === 0; 26372 } 26373 break; 26374 case 'cpf-type-select': 26375 val = element.find( 'select.tm-epo-field.tmcp-select' + elementToCheck ).val(); 26376 if ( val && ! noSplit ) { 26377 val = val.slice( 0, val.lastIndexOf( '_' ) ); 26378 } 26379 break; 26380 case 'cpf-type-selectmultiple': 26381 val = element.find( 'select.tm-epo-field.tmcp-selectmultiple' + elementToCheck ).val(); 26382 if ( val && ! noSplit ) { 26383 val.forEach( function( option, i ) { 26384 val[ i ] = option.slice( 0, option.lastIndexOf( '_' ) ); 26385 } ); 26386 } 26387 break; 26388 case 'cpf-type-variations': 26389 return tm_variation_check_match( element, value, operator ); 26390 26391 default: 26392 val = element.find( '.tm-epo-field' + elementToCheck ).val(); 26393 break; 26394 } 26395 if ( Array.isArray( val ) ) { 26396 return val.some( function( item ) { 26397 return tm_check_match( item, value, operator ); 26398 } ); 26399 } 26400 return tm_check_match( val, value, operator ); 26401 } 26402 return false; 26403 } 26404 26405 function tm_check_rules( o, theevent ) { 26406 o.toArray().forEach( function( oel ) { 26407 var $this = $( oel ); 26408 var matches = $this.data( 'matches' ); 26409 var toggle = $this.data( 'toggle' ); 26410 var fields = $this.data( 'fields' ); 26411 var checked = []; 26412 var show = toggle !== 'show'; 26413 var ifield; 26414 var i; 26415 var field; 26416 var ii; 26417 var im; 26418 var sectionFields; 26419 var isInSectionRepeater; 26420 26421 if ( ! fields ) { 26422 return; 26423 } 26424 26425 sectionFields = $this.closest( '.tc-section-fields' ); 26426 isInSectionRepeater = sectionFields.is( '.tc-repeater-section' ); 26427 26428 for ( i = 0; i < fields.length; i++ ) { 26429 ifield = fields[ i ]; 26430 if ( Array.isArray( ifield ) ) { 26431 checked[ i ] = 0; 26432 for ( ii = 0; ii < ifield.length; ii++ ) { 26433 field = ifield[ ii ]; 26434 if ( isInSectionRepeater ) { 26435 field.element = sectionFields.find( '[data-uniqid="' + field.element.attr( 'data-uniqid' ) + '"' ); 26436 } 26437 if ( theevent !== 'cpflogic' || field_is_active( $( field.element ), undefined, undefined, true ) ) { 26438 if ( tm_check_field_match( field ) ) { 26439 checked[ i ] = ( checked[ i ] || 0 ) + 1; 26440 } 26441 } 26442 } 26443 } 26444 } 26445 26446 for ( im = 0; im < matches.length; im++ ) { 26447 if ( parseInt( checked[ im ], 10 ) === parseInt( matches[ im ], 10 ) ) { 26448 show = ! show; 26449 break; 26450 } 26451 } 26452 26453 if ( show ) { 26454 if ( theevent === 'cpflogic' && ! $this.data( 'did_initial_activation' ) ) { 26455 latecpflogicactions.push( function() { 26456 var enabledEpos = $this.find( '.tm-epo-field.tcenabled' ); 26457 enabledEpos.toArray().forEach( function( el ) { 26458 el = $( el ); 26459 if ( ! el.data( 'initial_activation' ) && ! $this.closest( '.cpf-section' ).is( '.tc-hidden' ) && field_is_active( el ) ) { 26460 el.trigger( 'tc_element_epo_rules' ); 26461 el.data( 'initial_activation', 1 ); 26462 } 26463 } ); 26464 if ( ( $this.is( '.cpf-element' ) && enabledEpos.length ) || $this.is( '.cpf-section' ) ) { 26465 $this.data( 'did_initial_activation', 1 ); 26466 } 26467 } ); 26468 } 26469 $this.removeClass( 'tc-hidden' ); 26470 } else { 26471 $this.addClass( 'tc-hidden' ); 26472 } 26473 26474 $this.data( 'isactive', show ).trigger( 'tc-logic' ); 26475 } ); 26476 } 26477 26478 function run_cpfdependson( obj ) { 26479 var iscpfdependson; 26480 var last_activate_field = []; 26481 var epo_object; 26482 26483 if ( ! $( obj ).length ) { 26484 obj = 'body'; 26485 } 26486 obj = $( obj ); 26487 iscpfdependson = obj.find( '.iscpfdependson' ); 26488 iscpfdependson.toArray().forEach( function( elements ) { 26489 $( elements ).toArray().forEach( function( el ) { 26490 tm_check_rules( $( el ) ); 26491 } ); 26492 } );
26493 iscpfdependson.toArray().forEach( function( elements ) { 26494 $( elements ).toArray().forEach( function( el ) { 26495 tm_check_rules( $( el ), 'cpflogic' ); 26496 } ); 26497 } ); 26498 iscpfdependson.toArray().forEach( function( elements ) { 26499 $( elements ).toArray().forEach( function( o ) { 26500 o = $( o ); 26501 if ( o.is( '.cpf-section' ) ) { 26502 o = o.find( '.cpf-element' ); 26503 } 26504 o.toArray().forEach( function( theelement ) { 26505 var $theelement = $( theelement ); 26506 var $theelementepos = $theelement.find( '.tm-epo-field' ); 26507 var len = $theelementepos.length; 26508 if ( len > 0 ) { 26509 field_is_active( $theelementepos ); 26510 } else { 26511 field_is_active( $theelement ); 26512 } 26513 } ); 26514 } ); 26515 } ); 26516 latecpflogicactions.forEach( function( func ) { 26517 func(); 26518 } ); 26519 latecpflogicactions = []; 26520 if ( $().selectric ) { 26521 $( '.tm-extra-product-options select' ).selectric( 'refresh' ); 26522 } 26523 setTimeout( function() { 26524 $( '.tm-owl-slider' ).toArray().forEach( function( slider ) { 26525 $( slider ).trigger( 'refresh.owl.carousel' ); 26526 } ); 26527 }, 200 ); 26528 26529 obj.find( '.tm-product-image:checked,select.tm-product-image' ).toArray().forEach( function( t ) { 26530 t = $( t ); 26531 if ( field_is_active( t ) && t.val() !== '' ) { 26532 last_activate_field.push( t ); 26533 } 26534 } ); 26535 if ( last_activate_field.length ) { 26536 last_activate_field[ last_activate_field.length - 1 ].trigger( 'tm_trigger_product_image' ); 26537 } else { 26538 epo_object = obj.data( 'epo_object' ); 26539 if ( epo_object ) { 26540 epo_object.main_product.trigger( 'tm_restore_product_image' ); 26541 } 26542 } 26543 26544 jWindow.trigger( 'cpflogicrun' ); 26545 jWindow.trigger( 'tmlazy' ); 26546 jWindow.trigger( 'cpflogicdone' ); 26547 } 26548 26549 // Start Conditional logic 26550 if ( ! $().cpfdependson ) { 26551 $.fn.cpfdependson = function( fields, toggle, refresh, epoObject ) { 26552 var elements = this; 26553 var matches = []; 26554 var $this_epo_container = null; 26555 var get_element; 26556 var $element; 26557 var $pid1; 26558 var $epo_id1; 26559 var _events; 26560 var $container; 26561 var i; 26562 var ii; 26563 var iii; 26564 var e; 26565 var ifield; 26566 var field; 26567 var $this; 26568 var show; 26569 var sectionFields; 26570 var isInSectionRepeater; 26571 26572 if ( ! elements.length || typeof fields !== 'object' ) { 26573 return; 26574 } 26575 26576 if ( ! toggle ) { 26577 toggle = 'show'; 26578 } 26579 26580 sectionFields = elements.first().closest( '.tc-section-fields' ); 26581 isInSectionRepeater = sectionFields.is( '.tc-repeater-section' ); 26582 26583 // Initialize the matches array 26584 for ( i = 0; i < fields.length; i++ ) { 26585 matches[ i ] = 0; 26586 ifield = fields[ i ]; 26587 26588 if ( Array.isArray( ifield ) ) { 26589 for ( ii = 0; ii < ifield.length; ii++ ) { 26590 field = ifield[ ii ]; 26591 if ( typeof field !== 'object' ) { 26592 continue; 26593 } 26594 if ( isInSectionRepeater ) { 26595 field.element = sectionFields.find( '[data-uniqid="' + field.element.attr( 'data-uniqid' ) + '"' ); 26596 } 26597 26598 if ( field.type === 'quantity' ) { 26599 if ( ! field.element.data( 'didcpflogic' ) ) { 26600 _events = 'change.cpflogic input.cpflogic'; 26601 field.element.off( _events ).on( _events, function() { 26602 run_cpfdependson( epoObject.this_epo_container ); 26603 } ).data( 'didcpflogic', 1 ); 26604 } 26605 } else if ( field.type === 'variation' || field.type === 'variationattributes' ) { 26606 add_variation_event( 'found_variation.tmlogic', false, function() { 26607 run_cpfdependson( field.element ); 26608 jWindow.trigger( 'tm-do-epo-update' ); 26609 } ); 26610 26611 add_variation_event( 'hide_variation.tmlogic', false, function() { 26612 run_cpfdependson( field.element ); 26613 jWindow.trigger( 'tm-do-epo-update' ); 26614 } ); 26615 } else { 26616 get_element = get_element_from_field( field.element, isInSectionRepeater ? sectionFields.index() : 0 ); 26617 if ( get_element && get_element.length > 0 ) { 26618 for ( iii = 0; iii < get_element.length; iii++ ) { 26619 if ( ! get_element[ iii ] ) { 26620 continue; 26621 } 26622 $element = $( get_element[ iii ] ); 26623 26624 if ( $element.length === 0 ) { 26625 continue; 26626 } 26627 26628 _events = 'change.cpflogic'; 26629
26630 // this essentially only works for the plugin so we use 26631 // cache and not recalcualte each time 26632 if ( ! $this_epo_container || $this_epo_container.closest( tcAPI.associatedEpoSelector ).length ) { 26633 $container = $element.closest( tcAPI.epoSelector ); 26634 $pid1 = '.tm-product-id-' + $container.attr( 'data-product-id' ); 26635 $epo_id1 = "[data-epo-id='" + $container.attr( 'data-epo-id' ) + "']"; 26636 $this_epo_container = $( tcAPI.epoSelector + $pid1 + $epo_id1 ); 26637 } 26638 26639 if ( ! $element.data( 'tmhaslogicevents' ) || refresh ) { 26640 /* For variation elements we must only add the event once, 26641 * otherwise if the variable product is on a product element 26642 * it will generate multiple events and slow down the site 26643 */ 26644 if ( ! $element.data( 'tmhaslogicevents' ) && $element.is( '.tm-epo-variation-element' ) ) { 26645 // associated product event prefixes are added later 26646 add_variation_event( 'found_variation.tmlogic', false, function() { 26647 run_cpfdependson( $this_epo_container ); 26648 jWindow.trigger( 'tm-do-epo-update' ); 26649 } ); 26650 26651 add_variation_event( 'hide_variation.tmlogic', false, function() { 26652 run_cpfdependson( $this_epo_container ); 26653 jWindow.trigger( 'tm-do-epo-update' ); 26654 } ); 26655 } else { 26656 if ( $element.is( ':text, textarea' ) ) { 26657 _events = 'change.cpflogic input.cpflogic'; 26658 } 26659 if ( $element.is( ':input[type="number"]' ) ) { 26660 _events = 'change.cpflogic input.cpflogic keypress.cpflogic'; 26661 } 26662 26663 $element.off( _events ).on( _events, function() { 26664 run_cpfdependson( $this_epo_container ); 26665 } ); 26666 } 26667 26668 $element.data( 'tmhaslogicevents', 1 ); 26669 } 26670 } 26671 } 26672 } 26673 26674 matches[ i ]++; 26675 } 26676 } 26677 } 26678 26679 // Loop through all elements and apply visibility toggling 26680 for ( e = 0; e < elements.length; e++ ) { 26681 $this = $( elements[ e ] ); 26682 show = toggle === 'hide'; 26683 26684 $this.data( { 26685 matches: matches, 26686 toggle: toggle, 26687 fields: fields, 26688 isactive: show 26689 } ); 26690 26691 if ( show ) { 26692 $this.removeClass( 'tc-hidden' ); 26693 } else { 26694 $this.addClass( 'tc-hidden' ); 26695 } 26696 } 26697 26698 elements.addClass( 'iscpfdependson is-epo-depend' ).data( 'iscpfdependson', 1 ); 26699 return elements; 26700 }; 26701 26702 $.fn.run_cpfdependson = function() { 26703 run_cpfdependson(); 26704 }; 26705 } 26706 26707 $.tcepo = { 26708 formSubmitEvents: {}, 26709 26710 oneOptionIsSelected: {}, 26711 26712 initialActivation: {}, 26713 26714 // Holds the active precentage of total current price type fields 26715 lateFieldsPrices: {}, 26716 26717 errorObject: {}, 26718 26719 showHideTotal: {} 26720 }; 26721 26722 function validate_logic( l ) { 26723 return typeof l === 'object' && 'toggle' in l && 'rules' in l && l.rules.length > 0; 26724 } 26725 26726 function convert_rules( rules ) { 26727 if ( rules.what ) { 26728 if ( rules.what === 'all' ) { 26729 rules.rules = [ rules.rules ]; 26730 } else if ( rules.what === 'any' ) { 26731 rules.rules = rules.rules.reduce( function( accumulator, elrule ) { 26732 accumulator.push( [ elrule ] ); 26733 return accumulator; 26734 }, [] ); 26735 } 26736 delete rules.what; 26737 } 26738 return rules; 26739 } 26740 26741 function getLogicType( section, element ) { 26742 var type = 'element'; 26743 if ( section === 'product-properties' ) { 26744 switch ( String( element ) ) { 26745 case '0': 26746 type = 'quantity'; 26747 break; 26748 case '1': 26749 type = 'productid'; 26750 break; 26751 case '2': 26752 type = 'variation'; 26753 break; 26754 case '3': 26755 type = 'variationattributes'; 26756 break; 26757 } 26758 } 26759 26760 return type; 26761 } 26762 26763 // The following loops are required for the logic to work on composite products that have custom variations 26764 function cpf_section_logic( epoObject ) { 26765 var obj = epoObject.this_epo_container; 26766 var root_element = $( obj ); 26767 var all_sections = root_element.find( '.cpf-section' ).not( '.cpf-type-product .cpf-section' ); 26768 var search_obj; 26769 var cpf_section; 26770 var sect; 26771 var logic; 26772 var haslogic; 26773 var fields; 26774 var section; 26775 var element; 26776 var type; 26777 var obj_section; 26778 var obj_element; 26779 var closestProductElement; 26780 var selector = '[data-haslogic="1"]'; 26781 26782 if ( root_element.is( '.cpf-section' ) ) { 26783 search_obj = false;
26784 } else { 26785 search_obj = all_sections; 26786 } 26787 26788 if ( ! epoObject.is_associated ) { 26789 selector = '[data-haslogic="1"]:not(".cpf-type-product .cpf-section")'; 26790 } 26791 26792 root_element.toArray().forEach( function( obj_el ) { 26793 if ( $( obj_el ).is( '.cpf-section' ) ) { 26794 cpf_section = $( obj_el ); 26795 } else { 26796 cpf_section = $( obj_el ).find( '.cpf-section' ); 26797 } 26798 26799 cpf_section.filter( selector ).toArray().forEach( function( el ) { 26800 var irule; 26801 var rule; 26802 var i; 26803 var ii; 26804 sect = $( el ); 26805 logic = sect.data( 'logic' ); 26806 // backwards compatibility conversion. 26807 logic = convert_rules( logic ); 26808 haslogic = parseInt( sect.data( 'haslogic' ), 10 ); 26809 fields = []; 26810 closestProductElement = sect.parent().closest( '.cpf-type-product' ); 26811 26812 if ( haslogic === 1 && validate_logic( logic ) ) { 26813 for ( i = 0; i < logic.rules.length; i++ ) { 26814 irule = logic.rules[ i ]; 26815 if ( ! irule || ! Array.isArray( irule ) ) { 26816 continue; 26817 } 26818 fields[ i ] = []; 26819 for ( ii = 0; ii < irule.length; ii++ ) { 26820 rule = irule[ ii ]; 26821 section = rule.section; 26822 element = rule.element; 26823 type = getLogicType( section, element ); 26824 26825 if ( type === 'quantity' ) { 26826 if ( closestProductElement.length ) { 26827 obj_element = epoObject.main_cart.find( tcAPI.associateQtySelector ); 26828 } else { 26829 obj_element = epoObject.main_cart.find( epoObject.qtySelector ); 26830 } 26831 } else if ( type === 'productid' ) { 26832 obj_element = epoObject.product_id; 26833 } else if ( type === 'variation' || type === 'variationattributes' ) { 26834 if ( closestProductElement.length ) { 26835 obj_element = closestProductElement.find( '.tc-epo-element-product-container' ); 26836 if ( ! obj_element.length ) { 26837 obj_element = closestProductElement.closest( '.tc-epo-element-product-container' ); 26838 } 26839 } else { 26840 obj_element = root_element; 26841 } 26842 } else if ( search_obj ) { 26843 if ( closestProductElement.length ) { 26844 obj_section = root_element.find( '.cpf-section' ).filter( "[data-uniqid='" + section + "']" ); 26845 if ( element !== section ) { 26846 obj_element = obj_section.find( '.cpf-element' ).eq( element ); 26847 } else { 26848 obj_element = obj_section; 26849 } 26850 } else { 26851 obj_section = search_obj.filter( "[data-uniqid='" + section + "']" ); 26852 if ( element !== section ) { 26853 obj_element = obj_section.find( '.cpf-element:not(.cpf-element .cpf-element)' ).eq( element ); 26854 } else { 26855 obj_element = obj_section; 26856 } 26857 } 26858 } else if ( element !== section ) { 26859 obj_element = root_element.find( '.cpf-element' ).eq( element ); 26860 } else { 26861 obj_section = root_element.find( '.cpf-section' ).filter( "[data-uniqid='" + section + "']" ); 26862 obj_element = obj_section; 26863 } 26864 26865 fields[ i ].push( { 26866 element: obj_element, 26867 rule: rule, 26868 type: type 26869 } ); 26870 } 26871 } 26872 if ( ! sect.data( 'iscpfdependson' ) ) { 26873 sect.data( 'cpfdependson-fields', fields ); 26874 sect.cpfdependson( fields, logic.toggle, false, epoObject ); 26875 } else { 26876 sect.cpfdependson( sect.data( 'cpfdependson-fields' ), logic.toggle, true, epoObject ); 26877 } 26878 } 26879 } ); 26880 } ); 26881 } 26882 26883 function cpf_element_logic( epoObject ) { 26884 var obj = epoObject.this_epo_container; 26885 var root_element = $( obj ); 26886 var all_sections = root_element.find( '.cpf-section' ).not( '.cpf-type-product .cpf-section' ); 26887 var search_obj; 26888 var current_element; 26889 var logic; 26890 var haslogic; 26891 var section; 26892 var element; 26893 var type; 26894 var obj_section; 26895 var obj_element; 26896 var closestProductElement; 26897 var isInProductElement = false; 26898 var selector = '.cpf-element[data-haslogic="1"]'; 26899 26900 if ( root_element.parent().is( tcAPI.associatedEpoSelector ) ) { 26901 all_sections = root_element.find( '.cpf-section' ); 26902 isInProductElement = true; 26903 } 26904 if ( root_element.is( '.cpf-section' ) ) { 26905 search_obj = false; 26906 } else { 26907 search_obj = all_sections; 26908 } 26909 26910 if ( ! epoObject.is_associated ) { 26911 selector = '.cpf-element[data-haslogic="1"]:not(".cpf-type-product .cpf-element")'; 26912 } 26913
26914 root_element.find( selector ).toArray().forEach( function( el ) { 26915 var fields = []; 26916 var irule; 26917 var rule; 26918 var i; 26919 var ii; 26920 26921 current_element = $( el ); 26922 logic = current_element.data( 'logic' ); 26923 // backwards compatibility conversion. 26924 logic = convert_rules( logic ); 26925 26926 haslogic = parseInt( current_element.data( 'haslogic' ), 10 ); 26927 26928 if ( isInProductElement ) { 26929 closestProductElement = root_element; 26930 } else { 26931 closestProductElement = current_element.parent().closest( '.cpf-type-product' ); 26932 } 26933 26934 if ( haslogic === 1 && validate_logic( logic ) ) { 26935 for ( i = 0; i < logic.rules.length; i++ ) { 26936 irule = logic.rules[ i ]; 26937 if ( ! irule || ! Array.isArray( irule ) ) { 26938 continue; 26939 } 26940 fields[ i ] = []; 26941 for ( ii = 0; ii < irule.length; ii++ ) { 26942 rule = irule[ ii ]; 26943 section = rule.section; 26944 element = rule.element; 26945 type = getLogicType( section, element ); 26946 26947 if ( type === 'quantity' ) { 26948 if ( closestProductElement.length ) { 26949 obj_element = epoObject.main_cart.find( tcAPI.associateQtySelector ); 26950 } else { 26951 obj_element = epoObject.main_cart.find( epoObject.qtySelector ); 26952 } 26953 } else if ( type === 'productid' ) { 26954 obj_element = epoObject.product_id; 26955 } else if ( type === 'variation' || type === 'variationattributes' ) { 26956 if ( closestProductElement.length ) { 26957 obj_element = closestProductElement.find( '.tc-epo-element-product-container' ); 26958 if ( ! obj_element.length ) { 26959 obj_element = closestProductElement.closest( '.tc-epo-element-product-container' ); 26960 } 26961 } else { 26962 obj_element = root_element; 26963 } 26964 } else if ( search_obj ) { 26965 if ( closestProductElement.length ) { 26966 obj_section = root_element.find( '.cpf-section' ).filter( "[data-uniqid='" + section + "']" ); 26967 if ( element !== section ) { 26968 obj_element = obj_section.find( '.cpf-element' ).eq( element ); 26969 } else { 26970 obj_element = obj_section; 26971 } 26972 } else { 26973 obj_section = search_obj.filter( "[data-uniqid='" + section + "']" ); 26974 if ( element !== section ) { 26975 obj_element = obj_section.find( '.cpf-element:not(.cpf-element .cpf-element)' ).eq( element ); 26976 } else { 26977 obj_element = obj_section; 26978 } 26979 } 26980 } else if ( element !== section ) { 26981 obj_element = root_element.find( '.cpf-element' ).eq( element ); 26982 } else { 26983 obj_section = root_element.find( '.cpf-section' ).filter( "[data-uniqid='" + section + "']" ); 26984 obj_element = obj_section; 26985 } 26986 26987 fields[ i ].push( { 26988 element: obj_element, 26989 rule: rule, 26990 type: type 26991 } ); 26992 } 26993 } 26994 26995 if ( ! current_element.data( 'iscpfdependson' ) ) { 26996 current_element.data( 'cpfdependson-fields', fields ); 26997 current_element.cpfdependson( fields, logic.toggle, false, epoObject ); 26998 } else { 26999 current_element.cpfdependson( current_element.data( 'cpfdependson-fields' ), logic.toggle, true, epoObject ); 27000 } 27001 } 27002 } ); 27003 } // End Conditional logic 27004 27005 // Return price value without tax 27006 function tm_set_price_without_tax( value, _cart, force ) { 27007 var taxable; 27008 var tax_rate; 27009 var tax_display_mode; 27010 var prices_include_tax; 27011 27012 if ( _cart ) { 27013 taxable = _cart.attr( 'data-taxable' ); 27014 tax_rate = _cart.attr( 'data-tax-rate' ); 27015 tax_display_mode = _cart.attr( 'data-tax-display-mode' ); 27016 prices_include_tax = _cart.attr( 'data-prices-include-tax' ); 27017 27018 if ( force || ( taxable && tax_display_mode === 'incl' && prices_include_tax !== '1' ) ) { 27019 value = parseFloat( value ) / ( 1 + ( tax_rate / 100 ) ); 27020 } 27021 } 27022 27023 return value; 27024 } 27025 27026 // Return price with tax 27027 function tm_set_price_with_tax( value, _cart, force ) { 27028 var taxable; 27029 var tax_rate; 27030 var tax_display_mode; 27031 var prices_include_tax; 27032 27033 if ( _cart ) { 27034 taxable = _cart.attr( 'data-taxable' ); 27035 tax_rate = _cart.attr( 'data-tax-rate' ); 27036 tax_display_mode = _cart.attr( 'data-tax-display-mode' ); 27037 prices_include_tax = _cart.attr( 'data-prices-include-tax' );
27038 if ( force || ( taxable && tax_display_mode !== 'incl' && prices_include_tax === '1' ) ) { 27039 value = parseFloat( value ) * ( 1 + ( tax_rate / 100 ) ); 27040 } 27041 } 27042 27043 return value; 27044 } 27045 27046 // Return price 27047 function tm_set_backend_price( value, _cart, variation ) { 27048 var taxable; 27049 var tax_display_mode; 27050 var prices_include_tax; 27051 27052 if ( _cart ) { 27053 taxable = _cart.attr( 'data-taxable' ); 27054 tax_display_mode = _cart.attr( 'data-tax-display-mode' ); 27055 prices_include_tax = _cart.attr( 'data-prices-include-tax' ); 27056 if ( taxable ) { 27057 if ( variation && variation.tc_tax_rate && String( variation.tc_tax_rate ) === '0' ) { 27058 return value; 27059 } 27060 if ( prices_include_tax === '1' ) { 27061 if ( tax_display_mode === 'incl' ) { 27062 // if we are not in the base tax 27063 if ( variation.tc_base_taxes_of_one !== variation.tc_modded_taxes_of_one ) { 27064 value = parseFloat( ( ( 1 - variation.tc_taxes_of_one ) * value ) * ( 1 / ( 1 - variation.tc_base_taxes_of_one ) ) ); 27065 } 27066 } else { 27067 value = tm_set_price_with_tax( value, _cart ); 27068 } 27069 } else if ( prices_include_tax !== '1' && tax_display_mode === 'incl' ) { 27070 value = tm_set_price_without_tax( value, _cart ); 27071 } 27072 } 27073 } 27074 27075 return value; 27076 } 27077 27078 // Return a formatted currency value 27079 function tm_set_price_totals( value, _cart, notax, element ) { 27080 var sign = ''; 27081 var val; 27082 27083 if ( ! notax ) { 27084 value = tm_set_tax_price( value, _cart, element, undefined, true ); 27085 } 27086 val = Math.abs( value ); 27087 27088 if ( value < 0 ) { 27089 sign = TMEPOJS.minus_sign + ' '; 27090 } 27091 27092 return tm_set_price_( val, sign ); 27093 } 27094 27095 function replace_suffixes( value, rawValue, tc_totals_ob, totalsHolder ) { 27096 if ( totalsHolder.attr( 'data-tax-display-mode' ) === 'excl' ) { 27097 tc_totals_ob[ value ] = tc_totals_ob[ value ].replaceAll( '{price_excluding_tax}', tm_set_price_totals( tc_totals_ob[ rawValue ], totalsHolder, true ) ); 27098 tc_totals_ob[ value ] = tc_totals_ob[ value ].replaceAll( '{price_including_tax}', tm_set_price_totals( tm_set_price_with_tax( tc_totals_ob[ rawValue ], totalsHolder, true ), totalsHolder, true ) ); 27099 } else { 27100 tc_totals_ob[ value ] = tc_totals_ob[ value ].replaceAll( '{price_including_tax}', tm_set_price_totals( tc_totals_ob[ rawValue ], totalsHolder, true ) ); 27101 tc_totals_ob[ value ] = tc_totals_ob[ value ].replaceAll( '{price_excluding_tax}', tm_set_price_totals( tm_set_price_without_tax( tc_totals_ob[ rawValue ], totalsHolder, true ), totalsHolder, true ) ); 27102 } 27103 return tc_totals_ob; 27104 } 27105 27106 function replace_suffixes_in_html( html, price, totalsHolder ) { 27107 if ( totalsHolder.attr( 'data-tax-display-mode' ) === 'excl' ) { 27108 html = html.replaceAll( '{price_excluding_tax}', tm_set_price_totals( price, totalsHolder, true ) ); 27109 html = html.replaceAll( '{price_including_tax}', tm_set_price_totals( tm_set_price_with_tax( price, totalsHolder, true ), totalsHolder, true ) ); 27110 } else { 27111 html = html.replaceAll( '{price_including_tax}', tm_set_price_totals( price, totalsHolder, true ) ); 27112 html = html.replaceAll( '{price_excluding_tax}', tm_set_price_totals( tm_set_price_without_tax( price, totalsHolder, true ), totalsHolder, true ) ); 27113 } 27114 return html; 27115 } 27116 27117 function tm_force_update_price( epoObject, obj, price, formatted_price, original_price, useFormattedPrice ) { 27118 tm_update_price( { 27119 epoObject: epoObject, 27120 obj: obj, 27121 price: price, 27122 formatted_price: formatted_price, 27123 original_price: original_price, 27124 force: true, 27125 useFormattedPrice: useFormattedPrice 27126 } ); 27127 } 27128 27129 function tm_update_price( priceobj ) { 27130 var $obj; 27131 var w; 27132 var $ba_amount; 27133 var f; 27134 var pw; 27135 var price; 27136 var formatted_price; 27137 var original_price; 27138 var force; 27139 var useFormattedPrice; 27140 var template; 27141 var templatePrice; 27142 var html; 27143 var totalsHolder; 27144 var sign; 27145 27146 $obj = $( priceobj.obj ); 27147 27148 if ( $obj.length === 0 ) { 27149 return; 27150 } 27151 27152 w = $obj.closest( '.tmcp-field-wrap' ); 27153 pw = $obj.closest( '.tc-price-wrap' ); 27154 f = w.find( '.tm-epo-field' ); 27155 27156 price = priceobj.price || 0; 27157 formatted_price = priceobj.formatted_price || ''; 27158 original_price = priceobj.original_price || ''; 27159 force = priceobj.force || false; 27160 useFormattedPrice = priceobj.useFormattedPrice || false; 27161 totalsHolder = priceobj.epoObject.this_epo_totals_container; 27162 27163 if ( ! force && f.attr( 'data-no-price-change' ) === '1' && f.data( 'price-changed' ) ) { 27164 return; 27165 } 27166 27167 price = $.epoAPI.applyFilter( 'tc_adjust_update_price_price', price ); //number 27168 formatted_price = $.epoAPI.applyFilter( 'tc_adjust_update_price_formatted_price', formatted_price, price ); //formatted 27169 original_price = $.epoAPI.applyFilter( 'tc_adjust_update_price_original_price', original_price ); //number 27170 27171 if ( ! Number.isFinite( parseFloat( original_price ) ) ) { 27172 original_price = 0; 27173 } 27174 if ( ! Number.isFinite( parseFloat( price ) ) ) { 27175 price = 0; 27176 } 27177 27178 $ba_amount = w.find( '.before-amount,.after-amount' ); 27179 27180 if ( ( TMEPOJS.tm_epo_auto_hide_price_if_zero === 'yes' && ( $.epoAPI.util.isEmpty( price ) === false || ( TMEPOJS.tm_epo_no_hide_price_if_original_not_zero === 'yes' && $.epoAPI.util.isEmpty( price ) === true && $.epoAPI.util.isEmpty( original_price ) === false ) ) ) || TMEPOJS.tm_epo_auto_hide_price_if_zero !== 'yes' ) { 27181 if ( ( $.epoAPI.util.isEmpty( price ) === true && f.attr( 'data-no-price' ) === '1' ) || ( ! force && f.length > 0 && ( f.attr( 'data-no-price' ) === '1' || ( f.attr( 'data-type' ) === 'variable' && ! f.data( 'price' ) ) ) ) ) { 27182 pw.addClass( 'tm-hidden' ); 27183 $obj.addClass( 'tm-hidden' ); 27184 $obj.empty(); 27185 $ba_amount.addClass( 'tm-hidden' ); 27186 } else { 27187 if ( original_price && original_price !== undefined && parseFloat( original_price ) !== parseFloat( price ) ) { 27188 if ( useFormattedPrice ) { 27189 template = tcAPI.templateEngine.plain_price; 27190 templatePrice = { price: formatted_price }; 27191 } else { 27192 if ( price < 0 && ! original_price < 0 ) { 27193 template = tcAPI.templateEngine.sale_price_m10; 27194 price = Math.abs( price ); 27195 } else if ( ! price < 0 && original_price < 0 ) { 27196 template = tcAPI.templateEngine.sale_price_m01; 27197 original_price = Math.abs( original_price ); 27198 } else if ( price < 0 && original_price < 0 ) { 27199 template = tcAPI.templateEngine.sale_price_m11; 27200 price = Math.abs( price ); 27201 original_price = Math.abs( original_price ); 27202 } else { 27203 template = tcAPI.templateEngine.sale_price; 27204 } 27205 templatePrice = { price: formatPrice( original_price ), sale_price: formatPrice( price ) }; 27206 } 27207 } else if ( useFormattedPrice ) { 27208 template = tcAPI.templateEngine.plain_price; 27209 templatePrice = { price: formatted_price }; 27210 } else { 27211 template = tcAPI.templateEngine.price; 27212 if ( price < 0 ) { 27213 template = tcAPI.templateEngine.price_m; 27214 price = Math.abs( price ); 27215 } 27216 templatePrice = { price: formatPrice( price ) }; 27217 } 27218 html = $.epoAPI.util.decodeHTML( $.epoAPI.template.html( template, templatePrice ) ); 27219 html = replace_suffixes_in_html( html, price, totalsHolder ); 27220 html = $.epoAPI.applyFilter( 'tc_adjust_update_price_formatted_price_html', html ); 27221 sign = ''; 27222 if ( ! useFormattedPrice && price > 0 && TMEPOJS.tm_epo_global_options_price_sign !== 'minus' ) { 27223 sign = TMEPOJS.option_plus_sign + ' '; 27224 } 27225 $obj.html( sign + html ); 27226 pw.removeClass( 'tm-hidden' ); 27227 $obj.removeClass( 'tm-hidden' ); 27228 $ba_amount.removeClass( 'tm-hidden' ); 27229 } 27230 } else { 27231 pw.addClass( 'tm-hidden' ); 27232 $obj.addClass( 'tm-hidden' ); 27233 $obj.empty(); 27234 $ba_amount.addClass( 'tm-hidden' ); 27235 } 27236 } 27237 27238 function get_variation_current_settings( form, epoObject ) { 27239 var current_settings = {}; 27240 27241 if ( epoObject.thisForm ) { 27242 form = epoObject.thisForm; 27243 } 27244 27245 form.find( '.variations select, .tc-epo-variable-product-selector' ).toArray().forEac
27245h( function( el ) { 27246 var attribute_name; 27247 var value; 27248 el = $( el ); 27249 27250 // Get attribute name from data-attribute_name, or from input name 27251 // if it doesn't exist 27252 if ( typeof el.data( 'attribute_name' ) !== 'undefined' ) { 27253 attribute_name = el.data( 'attribute_name' ); 27254 } else { 27255 attribute_name = el.attr( 'name' ); 27256 } 27257 27258 // Encode entities 27259 value = el.val(); 27260 27261 // Add to settings array 27262 current_settings[ attribute_name ] = value; 27263 } ); 27264 27265 return current_settings; 27266 } 27267 27268 function do_tm_custom_variations_update( form, all_variations, epoObject ) { 27269 var check_if_all_are_not_set = []; 27270 var formSettings = get_variation_current_settings( form, epoObject ); 27271 var redo_check = true; 27272 var variationId = form.find( getVariationIdSelector( form ) ).val(); 27273 var ii; 27274 27275 variationId = ( variationId !== '0' && variationId !== '' ) || form.find( '.cpf-type-variations' ).find( '.tm-epo-variation-element:checked' ).length > 0 || form.find( '.cpf-type-variations' ).find( '.tm-epo-variation-element option[value!=""]:selected' ); 27276 27277 if ( ! variationId ) { 27278 return; 27279 } 27280 form.find( '.cpf-type-variations' ).toArray().forEach( function( el, i ) { 27281 var t = $( el ).find( '.tm-epo-variation-element' ); 27282 var id; 27283 var v; 27284 var exists = false; 27285 27286 check_if_all_are_not_set[ i ] = true; 27287 27288 if ( t.is( 'select' ) ) { 27289 id = $.epoAPI.dom.id( t.attr( 'data-tm-for-variation' ) ); 27290 v = t.val(); 27291 if ( v ) { 27292 check_if_all_are_not_set[ i ] = false; 27293 } 27294 t.children( 'option' ).toArray().forEach( function( o ) { 27295 exists = false; 27296 form.find( "[data-attribute_name='attribute_" + id + "']" ) 27297 .children( 'option' ) 27298 .toArray().forEach( function( att ) { 27299 if ( $( att ).attr( 'value' ) === $( o ).attr( 'value' ) ) { 27300 exists = true; 27301 return false; 27302 } 27303 } ); 27304 if ( ! exists ) { 27305 $( o ).prop( 'disabled', true ).hide(); 27306 } else { 27307 $( o ).prop( 'disabled', false ).show(); 27308 } 27309 } ); 27310 } else { 27311 t.toArray().forEach( function( oe ) { 27312 var o = $( oe ); 27313 var li = o.closest( 'li' ); 27314 var input = li.find( '.tm-epo-variation-element' ); 27315 var this_settings = $.extend( true, {}, formSettings ); 27316 var matching_variations; 27317 var variation; 27318 var is_in_stock; 27319 27320 id = o.attr( 'data-tm-for-variation' ); 27321 v = o.val(); 27322 if ( o.is( ':checked' ) ) { 27323 check_if_all_are_not_set[ i ] = false; 27324 } 27325 27326 this_settings[ 'attribute_' + id ] = v; 27327 27328 matching_variations = $.fn.tm_find_matching_variations( all_variations, this_settings ); 27329 variation = matching_variations.shift(); 27330 27331 is_in_stock = variation && 'is_in_stock' in variation && variation.is_in_stock; 27332 27333 if ( ! is_in_stock ) { 27334 if ( ! input.is( ':checked' ) && ! is_in_stock ) { 27335 li.addClass( 'pointereventsoff' ); 27336 } else { 27337 li.removeClass( 'pointereventsoff' ); 27338 } 27339 27340 o.attr( 'disabled', 'disabled' ).addClass( 'tm-disabled' ); 27341 27342 input.attr( 'disabled', 'disabled' ); 27343 input.attr( 'data-tm-disabled', 'disabled' ); 27344 27345 li.addClass( 'tm-attribute-disabled' ).fadeTo( 'fast', 0.5 ); 27346 } else { 27347 o.prop( 'disabled', false ).removeClass( 'tm-disabled' ); 27348 li.removeClass( 'pointereventsoff tm-attribute-disabled' ).fadeTo( 'fast', 1, function() { 27349 $( this ).css( 'opacity', '' ); 27350 } ); 27351 input.prop( 'disabled', false ); 27352 input.removeAttr( 'data-tm-disabled' ); 27353 } 27354 } ); 27355 } 27356 } ); 27357 27358 if ( check_if_all_are_not_set ) { 27359 check_if_all_are_not_set.shift(); 27360 27361 for ( ii = 0; ii < check_if_all_are_not_set.length; ii++ ) { 27362 if ( check_if_all_are_not_set[ ii ] === false ) { 27363 redo_check = false; 27364 break; 27365 } 27366 } 27367 27368 if ( redo_check ) { 27369 form.find( '.cpf-type-variations' ) 27370 .first() 27371 .toArray().forEach( function( el ) { 27372 var t; 27373 var li; 27374 var input; 27375 27376 t = $( el ).find( '.tm-epo-variation-element' ); 27377 27378 if ( ! t.is( 'select' ) ) { 27379 t.toArray().forEach( function( o ) { 27380 o = $( o ); 27381 li = o.closest( 'li' ); 27382 input = li.find( '.tm-epo-variation-element' ); 27383 o.prop( 'disabled', false ).removeClass( 'tm-disabled' ); 27384 li.removeClass( 'tm-attribute-disabled' ).stop().css( 'opacity', '' ); 27385 input.prop( 'disabled', false ); 27386 input.removeAttr( 'data-tm-disabled' ); 27387 } ); 27388 } 27389 } ); 27390 } 27391 } 27392 } 27393 27394 function tm_custom_variations_update( form, epoObject ) { 27395 var data; 27396 var all_variations = form.data( 'product_variations' ); 27397 var product_id = parseInt( form.data( 'product_id' ), 10 ); 27398 var globalVariationObject = form.data( 'globalVariationObject' ) || false; 27399 27400 if ( TMEPOJS.skipCustomVariationsUpdate ) { 27401 return; 27402 } 27403 27404 if ( ! product_id ) { 27405 product_id = form.data( 'tc_product_id' ); 27406 } 27407 27408 if ( ! product_id && form.is( tcAPI.compositeSelector ) ) { 27409 data = form.find( '.component_options' ).data( 'options_data' ); 27410 product_id = data[ 0 ].option_id; 27411 if ( ! all_variations ) { 27412 all_variations = form.find( '.details.component_data' ).data( 'product_variations' ); 27413 } 27414 } 27415 27416 if ( ! epoObject.is_associated ) { 27417 // Fallback to window property if not set - backwards compat 27418 if ( ! all_variations && window.product_variations && window.product_variations.product_id ) { 27419 all_variations = window.product_variations.product_id; 27420 } 27421 if ( ! all_variations && window.product_variations ) { 27422 all_variations = window.product_variations; 27423 } 27424 if ( ! all_variations && window[ 'product_variations_' + product_id ] ) { 27425 all_variations = window[ 'product_variations_' + product_id ]; 27426 } 27427 } 27428 27429 if ( ! all_variations ) { 27430 if ( ! globalVariationObject ) { 27431 data = { 27432 action: 'woocommerce_tm_get_variations_array', 27433 post_id: product_id 27434 }; 27435 $.post( 27436 TMEPOJS.ajax_url, 27437 data, 27438 function( response ) { 27439 globalVariationObject = response; 27440 form.data( 'globalVariationObject', response ); 27441 do_tm_custom_variations_update( form, globalVariationObject.variations, epoObject ); 27442 }, 27443 'json' 27444 ); 27445 } else { 27446 do_tm_custom_variations_update( form, globalVariationObject.variations, epoObject ); 27447 } 27448 27449 return; 27450 } 27451 // may need 2.4 check for woocommerce_ajax_variation_threshold 27452 do_tm_custom_variations_update( form, all_variations, epoObject ); 27453 } 27454 27455 function tm_fix_stock( cart, html ) { 27456 var custom_variations; 27457 var section; 27458 27459 if ( html === undefined ) { 27460 return false;
27461 } 27462 cart = $( cart ); 27463 custom_variations = cart.find( '.tm-epo-variation-element' ).first(); 27464 section = custom_variations.closest( '.tm-epo-variation-section' ); 27465 27466 if ( custom_variations.length ) { 27467 section.find( '.tm-stock' ).remove(); 27468 section.append( '<div class="tm-stock">' + html + '</div>' ); 27469 return true; 27470 } 27471 cart.find( '.tm-stock' ).remove(); 27472 cart.find( '.variations' ).after( '<div class="tm-stock">' + html + '</div>' ); 27473 return true; 27474 } 27475 27476 function fix_stock( $this, form ) { 27477 var stock; 27478 27479 if ( TMEPOJS.tm_epo_global_move_out_of_stock === 'no' ) { 27480 return; 27481 } 27482 stock = $this.find( '.woocommerce-variation-availability' ).last(); 27483 if ( ! stock.length ) { 27484 stock = $this.find( '.stock' ).last(); 27485 } 27486 27487 if ( stock.length ) { 27488 form.find( '.tm-stock' ).remove(); 27489 if ( tm_fix_stock( form, stock.prop( 'outerHTML' ) ) ) { 27490 stock.remove(); 27491 } 27492 } else { 27493 form.find( '.tm-stock' ).remove(); 27494 } 27495 } 27496 27497 function get_main_input_id( main_product, product, id ) { 27498 var selector = ''; 27499 var inputid; 27500 27501 if ( id ) { 27502 selector = selector + "[value='" + id + "']"; 27503 } 27504 if ( ! product ) { 27505 product = main_product; 27506 } 27507 inputid = product.find( tcAPI.addToCartSelector + selector ); 27508 if ( inputid.length === 0 ) { 27509 inputid = product.find( tcAPI.tcAddToCartSelector + selector ); 27510 } 27511 return inputid.last(); 27512 } 27513 27514 function get_main_form( main_product, product, selector, id ) { 27515 if ( ! selector ) { 27516 selector = 'form'; 27517 } 27518 return get_main_input_id( main_product, product, id ).closest( selector ); 27519 } 27520 27521 function get_main_cart( main_product, product, selector, id ) { 27522 return get_main_form( main_product, product, selector, id ); 27523 } 27524 27525 function tm_get_native_prices_block( obj ) { 27526 var selector = $.epoAPI.applyFilter( 'tcGetNativePricesBlockSelector', '.single_variation .price', obj ); 27527 27528 return $( obj ).find( selector ).not( '.tc-price' ); 27529 } 27530 27531 // URL replacement setup 27532 function tm_set_url_fields() { 27533 jDocument.on( 'click.cpfurl change.cpfurl tmredirect', '.tc-url-container .tmcp-radio, .tc-url-container .tmcp-radio+label', function( e ) { 27534 var data_url = $( this ).attr( 'data-url' ); 27535 if ( data_url ) { 27536 if ( window.location !== data_url ) { 27537 e.preventDefault(); 27538 window.location = data_url; 27539 } 27540 } 27541 } ); 27542 jDocument.on( 'change.cpfurl tmredirect', '.tc-url-container .tmcp-select', function( e ) { 27543 var data_url = $( this ).children( 'option:selected' ).attr( 'data-url' ); 27544 if ( data_url ) { 27545 if ( window.location !== data_url ) { 27546 e.preventDefault(); 27547 window.location = data_url; 27548 } 27549 } 27550 } ); 27551 } 27552 27553 function tm_floating_totals( this_epo_totals_container, is_quickview, main_cart ) { 27554 $.tcFloatingTotalsBox( this_epo_totals_container, is_quickview, main_cart ); 27555 } 27556 27557 function tm_show_hide_add_to_cart_button( main_product, currentEpoObject ) { 27558 var button; 27559 var qty; 27560 var showHideCart = currentEpoObject.showHideCart; 27561 27562 if ( ! currentEpoObject.is_associated && showHideCart !== undefined ) { 27563 if ( TMEPOJS.tm_epo_hide_add_cart_button === 'yes' || TMEPOJS.tm_epo_hide_all_add_cart_button === 'yes' || TMEPOJS.tm_epo_hide_required_add_cart_button === 'yes' ) { 27564 button = main_product.find( tcAPI.addToCartButtonSelector ).first(); 27565 qty = main_product.find( tcAPI.qtySelector ).first(); 27566 27567 if ( showHideCart ) { 27568 button.removeClass( 'tc-hide-add-to-cart-button' ); 27569 qty.removeClass( 'tc-hide-add-to-cart-button' ); 27570 } else { 27571 button.addClass( 'tc-hide-add-to-cart-button' ); 27572 qty.addClass( 'tc-hide-add-to-cart-button' ); 27573 } 27574 27575 jWindow.trigger( 'epoShowHideCart', { 27576 main_product: main_product, 27577 currentEpoObject: currentEpoObject, 27578 showHideCart: showHideCart, 27579 button: button, 27580 qty: qty 27581 } ); 27582 } 27583 } 27584 } 27585 27586 function addShowHidetoEpoObject( currentEpoObject, epoEventId, epoObject ) { 27587 var has_epo; 27588 var this_epo_container; 27589 var epos; 27590 var allElementsAreSelected; 27591 var showHideCart = true; 27592 var showHideTotal = true; 27593 var one_option_is_selected = $.tcepo.oneOptionIsSelected[ epoEventId ]; 27594 27595 if ( currentEpoObject.is_associated ) { 27596 currentEpoObject = $.epoAPI.applyFilter( 'tc_currentEpoObject_associated', currentEpoObject, epoEventId, epoObject ); 27597 return currentEpoObject; 27598 } 27599 27600 if ( typeof epoObject === 'object' ) { 27601 has_epo = epoObject.has_epo; 27602 this_epo_container = epoObject.this_epo_container; 27603 has_epo = has_epo && ( this_epo_container.find( '.tmcp-fee-field' ).length || this_epo_container.find( '.tmcp-field' ).not( '.cpf-type-variations .tmcp-field' ).length ); 27604 } else { 27605 has_epo = epoObject; 27606 } 27607 27608 currentEpoObject.showHideCart = undefined; 27609 currentEpoObject.showHideTotal = undefined; 27610 27611 if ( has_epo && ( TMEPOJS.tm_epo_hide_add_cart_button === 'yes' || TMEPOJS.tm_epo_hide_all_add_cart_button === 'yes' || TMEPOJS.tm_epo_hide_required_add_cart_button === 'yes' || TMEPOJS.tm_epo_hide_totals_until_any === 'yes' || TMEPOJS.tm_epo_hide_totals_until_all_required === 'yes' || TMEPOJS.tm_epo_hide_totals_until_all === 'yes' ) ) { 27612 // Hide cart button until an element is chosen 27613 if ( TMEPOJS.tm_epo_hide_add_cart_button === 'yes' ) { 27614 showHideCart = one_option_is_selected; 27615 } 27616 27617 // Hide Final total box until an element is chosen 27618 if ( TMEPOJS.tm_epo_hide_totals_until_any === 'yes' ) { 27619 showHideTotal = one_option_is_selected; 27620 } 27621 27622 // Hide until all required elements are chosen 27623 if ( TMEPOJS.tm_epo_hide_required_add_cart_button === 'yes' || TMEPOJS.tm_epo_hide_totals_until_all_required === 'yes' ) { 27624 epos = currentEpoObject.this_epo_container.find( '.cpf-element' ).not( '.cpf-type-variations' ).filter( '.tc-container-enabled.tc-is-required' ); 27625 allElementsAreSelected = checkFullSelection( epos ); 27626 if ( TMEPOJS.tm_epo_hide_required_add_cart_button === 'yes' ) { 27627 showHideCart = allElementsAreSelected; 27628 } 27629 if ( TMEPOJS.tm_epo_hide_totals_until_all_required === 'yes' ) { 27630 showHideTotal = allElementsAreSelected; 27631 } 27632 } 27633 27634 // Hide until all elements are chosen 27635 if ( TMEPOJS.tm_epo_hide_all_add_cart_button === 'yes' || TMEPOJS.tm_epo_hide_totals_until_all === 'yes' ) { 27636 epos = currentEpoObject.this_epo_container.find( '.cpf-element' ).not( '.cpf-type-variations' ).filter( '.tc-container-enabled' ); 27637 allElementsAreSelected = checkFullSelection( epos ); 27638 if ( TMEPOJS.tm_epo_hide_all_add_cart_button === 'yes' ) { 27639 showHideCart = allElementsAreSelected; 27640 } 27641 if ( TMEPOJS.tm_epo_hide_totals_until_all === 'yes' ) { 27642 showHideTotal = allElementsAreSelected; 27643 } 27644 } 27645 27646 currentEpoObject.showHideCart = showHideCart; 27647 currentEpoObject.showHideTotal = showHideTotal; 27648 $.tcepo.showHideTotal[ epoEventId ] = showHideTotal; 27649 } 27650 27651 currentEpoObject = $.epoAPI.applyFilter( 'tc_currentEpoObject', currentEpoObject, epoEventId, epoObject ); 27652 27653 return currentEpoObject; 27654 } 27655 27656 function checkFullSelection( epos, mode ) { 27657 var funcCallback = function( element ) { 27658 var elementToCheck = ''; 27659 var _class; 27660 var noSplit = false;
27661 var radio_checked; 27662 var checkbox_checked; 27663 var val; 27664 27665 element = $( element ); 27666 if ( element.is( '.cpf-type-product' ) ) { 27667 elementToCheck = ':not(' + tcAPI.associatedEpoSelector + ' .tm-epo-field)'; 27668 } 27669 _class = element 27670 .attr( 'class' ) 27671 .split( ' ' ) 27672 .map( function( cls ) { 27673 if ( cls.indexOf( 'cpf-type-', 0 ) !== -1 ) { 27674 return cls; 27675 } 27676 return null; 27677 } ) 27678 .filter( function( v ) { 27679 if ( v !== null && v !== undefined ) { 27680 return v; 27681 } 27682 return null; 27683 } ); 27684 27685 if ( _class.length > 0 ) { 27686 _class = _class[ 0 ]; 27687 if ( _class === 'cpf-type-product' ) { 27688 noSplit = true; 27689 if ( element.is( '.cpf-type-product-mode-product' ) || element.is( '.cpf-type-product-checkbox' ) || element.is( '.cpf-type-product-thumbnailmultiple' ) || element.is( '.cpf-type-product-custombundle' ) ) { 27690 _class = 'cpf-type-checkbox'; 27691 } else if ( element.is( '.cpf-type-product-dropdown' ) ) { 27692 _class = 'cpf-type-select'; 27693 } else { 27694 _class = 'cpf-type-radio'; 27695 } 27696 } 27697 switch ( _class ) { 27698 case 'cpf-type-radio': 27699 radio_checked = element.find( 'input.tm-epo-field.tmcp-radio:checked' + elementToCheck ); 27700 return radio_checked.length > 0; 27701 27702 case 'cpf-type-checkbox': 27703 checkbox_checked = element.find( 'input.tm-epo-field.tmcp-checkbox:checked' + elementToCheck ); 27704 return checkbox_checked.length > 0; 27705 27706 case 'cpf-type-select': 27707 val = element.find( 'select.tm-epo-field.tmcp-select' + elementToCheck ).val(); 27708 if ( val && ! noSplit ) { 27709 val = val.slice( 0, val.lastIndexOf( '_' ) ); 27710 } 27711 break; 27712 27713 case 'cpf-type-selectmultiple': 27714 val = element.find( 'select.tm-epo-field.tmcp-selectmultiple' + elementToCheck ).val(); 27715 if ( val && ! noSplit ) { 27716 val.forEach( function( option, i ) { 27717 val[ i ] = option.slice( 0, option.lastIndexOf( '_' ) ); 27718 } ); 27719 } 27720 break; 27721 27722 default: 27723 val = element.find( '.tm-epo-field' + elementToCheck ).val(); 27724 break; 27725 } 27726 if ( Array.isArray( val ) ) { 27727 return val.some( function( item ) { 27728 return item !== ''; 27729 } ); 27730 } 27731 return val !== ''; 27732 } 27733 return false; 27734 }; 27735 if ( mode === 'some' ) { 27736 return epos.toArray().some( funcCallback ); 27737 } 27738 return epos.toArray().every( funcCallback ); 27739 } 27740 27741 function goto_error_item( item, epoEventId ) { 27742 var el = $.tcepo.errorObject[ epoEventId ] || item; 27743 var elsection; 27744 var elsectionlink; 27745 var cpfElement; 27746 var productSection; 27747 var pos; 27748 27749 if ( el ) { 27750 if ( TMEPOJS.tm_epo_disable_error_scroll !== 'yes' ) { 27751 elsection = el.closest( '.cpf-section' ); 27752 elsectionlink = elsection.find( '.tm-section-link' ); 27753 cpfElement = el.closest( '.cpf-element' ); 27754 productSection = el.closest( '.cpf-type-product' ).closest( '.cpf-section' ); 27755 27756 if ( productSection.length && productSection.find( '.tm-toggle' ).length ) { 27757 productSection.find( '.tm-toggle' ).trigger( 'openwrap.tmtoggle' ); 27758 } 27759 27760 if ( elsection.find( '.tm-toggle' ).length ) { 27761 elsection.find( '.tm-toggle' ).trigger( 'openwrap.tmtoggle' ); 27762 } 27763 if ( window.tc_validation_offset === undefined ) { 27764 window.tc_validation_offset = -100; 27765 } 27766 if ( elsection.is( '.section_popup' ) ) { 27767 errorContainer.tcScrollTo( elsectionlink, 300, window.tc_validation_offset ); 27768 elsectionlink.trigger( 'click.tmsectionpoplink' ); 27769 } else if ( elsection.is( '.tm-owl-slider-section' ) ) { 27770 pos = el.closest( '.owl-item' ).index(); 27771 elsection.find( '.tcowl-carousel' ).trigger( 'to.owl.carousel', [ pos, 100 ] ); 27772 setTimeout( function() { 27773 elsection.find( '.tcowl-carousel' ).trigger( 'refresh.owl.carousel' ); 27774 27775 if ( cpfElement.length > 0 ) { 27776 errorContainer.tcScrollTo( cpfElement, 300, window.tc_validation_offset ); 27777 } 27778 }, 200 ); 27779 } else if ( elsection.is( '.tc-tabs-section' ) ) { 27780 pos = el.closest( '.tc-tab-slide' ).index(); 27781 el.closest( '.tc-tabs' ).find( '.tc-tab-headers .tc-tab-header .tab-header[data-id="tc-tab-slide' + pos + '"]' ).trigger( 'click.tmtabs' ); 27782 setTimeout( function() { 27783 if ( cpfElement.length > 0 ) { 27784 errorContainer.tcScrollTo( cpfElement, 300, window.tc_validation_offset ); 27785 } 27786 }, 200 ); 27787 } else if ( cpfElement.length > 0 ) { 27788 errorContainer.tcScrollTo( cpfElement, 300, window.tc_validation_offset ); 27789 } 27790 } 27791 27792 if ( ! item ) { 27793 $.tcepo.errorObject[ epoEventId ] = false;
27794 } 27795 } 27796 } 27797 27798 function tm_limit_c_selection( field, prevent ) { 27799 var allowed = parseInt( field.attr( 'data-limit' ), 10 ); 27800 var checked = false; 27801 var val; 27802 var q; 27803 27804 if ( allowed > 0 ) { 27805 checked = 0; 27806 field 27807 .closest( '.tm-extra-product-options-checkbox' ) 27808 .find( "input.tm-epo-field[type='checkbox']:checked" ) 27809 .toArray().forEach( function( cb ) { 27810 cb = $( cb ); 27811 q = cb.closest( 'li.tmcp-field-wrap' ).find( 'input.tm-qty' ); 27812 if ( q.length > 0 ) { 27813 val = parseInt( q.val(), 10 ); 27814 if ( val <= 0 ) { 27815 val = 1; 27816 } 27817 checked = parseInt( checked, 10 ) + val; 27818 } else { 27819 checked = parseInt( checked, 10 ) + 1; 27820 } 27821 } ); 27822 if ( checked > allowed ) { 27823 if ( prevent ) { 27824 field.prop( 'checked', '' ).trigger( 'change' ); 27825 } 27826 return false; 27827 } 27828 } 27829 return true; 27830 } 27831 27832 function tm_exact_c_selection( field, prevent ) { 27833 var allowed = parseInt( field.attr( 'data-exactlimit' ), 10 ); 27834 var checked = false; 27835 var val; 27836 var q; 27837 27838 if ( allowed > 0 ) { 27839 checked = 0; 27840 field 27841 .closest( '.tm-extra-product-options-checkbox' ) 27842 .find( "input.tm-epo-field[type='checkbox']:checked" ) 27843 .toArray().forEach( function( cb ) { 27844 cb = $( cb ); 27845 q = cb.closest( 'li.tmcp-field-wrap' ).find( 'input.tm-qty' ); 27846 if ( q.length > 0 ) { 27847 val = parseInt( q.val(), 10 ); 27848 if ( val <= 0 ) { 27849 val = 1; 27850 } 27851 checked = parseInt( checked, 10 ) + val; 27852 } else { 27853 checked = parseInt( checked, 10 ) + 1; 27854 } 27855 } ); 27856 if ( checked > allowed ) { 27857 if ( prevent ) { 27858 field.prop( 'checked', '' ).trigger( 'change' ); 27859 } 27860 return false; 27861 } 27862 } 27863 return true; 27864 } 27865 27866 function tm_limit_cont( fields, main_product, epoEventId ) { 27867 var checkall = true; 27868 var first_error_obj = false; 27869 var limit; 27870 var eln; 27871 var checked; 27872 var val; 27873 var q; 27874 var ew; 27875 var em; 27876 var message; 27877 27878 fields.toArray().forEach( function( field ) { 27879 field = $( field ); 27880 limit = field.find( "[type='checkbox'][data-limit]" ); 27881 if ( limit.length && field_is_active( limit ) ) { 27882 eln = parseInt( limit.attr( 'data-limit' ), 10 ); 27883 checked = 0; 27884 field.find( "input.tm-epo-field[type='checkbox']:checked" ).toArray().forEach( function( cb ) { 27885 cb = $( cb ); 27886 q = cb.closest( 'li.tmcp-field-wrap' ).find( 'input.tm-qty' ); 27887 if ( q.length > 0 ) { 27888 val = parseInt( q.val(), 10 ); 27889 if ( val <= 0 ) { 27890 val = 1; 27891 } 27892 checked = parseInt( checked, 10 ) + val; 27893 } else { 27894 checked = parseInt( checked, 10 ) + 1; 27895 } 27896 } ); 27897 ew = field.closest( '.cpf-element' ); 27898 em = ew.find( 'div.tm-error-min' ); 27899 27900 if ( eln < checked ) { 27901 checkall = false; 27902 first_error_obj = field; 27903 if ( eln === 1 ) { 27904 message = TMEPOJS.tm_epo_global_validator_messages.epolimitsingle.replaceAll( '{0}', eln ); 27905 } else { 27906 message = TMEPOJS.tm_epo_global_validator_messages.epolimit.replaceAll( '{0}', eln ); 27907 } 27908 if ( em.length ) { 27909 em.remove(); 27910 } 27911 if ( TMEPOJS.tm_epo_global_error_label_placement === 'before' ) { 27912 field.closest( '.tc-element-container' ).before( '<div class="tm-error-min tm-error tc-cell tcwidth tcwidth-100">' + message + '</div>' ); 27913 } else { 27914 field.closest( '.tc-element-container' ).after( '<div class="tm-error-min tm-error tc-cell tcwidth tcwidth-100">' + message + '</div>' ); 27915 } 27916 main_product.find( tcAPI.addToCartButtonSelector ).first().removeClass( 'disabled loading fpd-disabled' ).prop( 'disabled', false ); 27917 } else { 27918 em.remove(); 27919 } 27920 } 27921 } ); 27922 if ( first_error_obj ) { 27923 $.tcepo.errorObject[ epoEventId ] = first_error_obj; 27924 } 27925 return checkall; 27926 } 27927 27928 function tm_check_limit_cont( limit_cont, main_product, epoEventId ) { 27929 $.tcepo.formSubmitEvents[ epoEventId ][ $.tcepo.formSubmitEvents[ epoEventId ].length ] = { 27930 trigger: function() { 27931 return tm_limit_cont( limit_cont, main_product, epoEventId ); 27932 }, 27933 on_true: function() { 27934 return true; 27935 }, 27936 on_false: function() { 27937 goto_error_item( $( limit_cont ).find( '.tm-epo-field' ).first(), epoEventId ); 27938 return true; 27939 } 27940 }; 27941 } 27942 27943 function tm_exactlimit_cont( fields, main_product, epoEventId ) { 27944 var checkall = true; 27945 var first_error_obj = false;
27946 var exactlimit; 27947 var eln; 27948 var checked; 27949 var val; 27950 var q; 27951 var ew; 27952 var em; 27953 var message; 27954 27955 fields.toArray().forEach( function( field ) { 27956 field = $( field ); 27957 exactlimit = field.find( "[type='checkbox'][data-exactlimit]" ); 27958 if ( exactlimit.length && field_is_active( exactlimit ) ) { 27959 eln = parseInt( exactlimit.attr( 'data-exactlimit' ), 10 ); 27960 checked = 0; 27961 field.find( "input.tm-epo-field[type='checkbox']:checked" ).toArray().forEach( function( cb ) { 27962 cb = $( cb ); 27963 q = cb.closest( 'li.tmcp-field-wrap' ).find( 'input.tm-qty' ); 27964 if ( q.length > 0 ) { 27965 val = parseInt( q.val(), 10 ); 27966 if ( val <= 0 ) { 27967 val = 1; 27968 } 27969 checked = parseInt( checked, 10 ) + val; 27970 } else { 27971 checked = parseInt( checked, 10 ) + 1; 27972 } 27973 } ); 27974 ew = field.closest( '.cpf-element' ); 27975 em = ew.find( 'div.tm-error-min' ); 27976 27977 if ( eln !== checked ) { 27978 checkall = false; 27979 first_error_obj = field; 27980 if ( eln === 1 ) { 27981 message = TMEPOJS.tm_epo_global_validator_messages.epoexactsingle.replaceAll( '{0}', eln ); 27982 } else { 27983 message = TMEPOJS.tm_epo_global_validator_messages.epoexact.replaceAll( '{0}', eln ); 27984 } 27985 if ( em.length ) { 27986 em.remove(); 27987 } 27988 if ( TMEPOJS.tm_epo_global_error_label_placement === 'before' ) { 27989 field.closest( '.tc-element-container' ).before( '<div class="tm-error-min tm-error tc-cell tcwidth tcwidth-100">' + message + '</div>' ); 27990 } else { 27991 field.closest( '.tc-element-container' ).after( '<div class="tm-error-min tm-error tc-cell tcwidth tcwidth-100">' + message + '</div>' ); 27992 } 27993 main_product.find( tcAPI.addToCartButtonSelector ).first().removeClass( 'disabled loading fpd-disabled' ).prop( 'disabled', false ); 27994 } else { 27995 em.remove(); 27996 } 27997 } 27998 } ); 27999 if ( first_error_obj ) { 28000 $.tcepo.errorObject[ epoEventId ] = first_error_obj; 28001 } 28002 return checkall; 28003 } 28004 28005 function tm_check_exactlimit_cont( exactlimit_cont, main_product, epoEventId ) { 28006 $.tcepo.formSubmitEvents[ epoEventId ][ $.tcepo.formSubmitEvents[ epoEventId ].length ] = { 28007 trigger: function() { 28008 return tm_exactlimit_cont( exactlimit_cont, main_product, epoEventId ); 28009 }, 28010 on_true: function() { 28011 return true; 28012 }, 28013 on_false: function() { 28014 goto_error_item( $( exactlimit_cont ).find( '.tm-epo-field' ).first(), epoEventId ); 28015 return true; 28016 } 28017 }; 28018 } 28019 28020 function tm_minimumlimit_cont( fields, epoEventId ) { 28021 var checkall = true; 28022 var first_error_obj = false; 28023 var eln; 28024 var checked; 28025 var val; 28026 var q; 28027 var ew; 28028 var em; 28029 var message; 28030 28031 fields.toArray().forEach( function( field ) { 28032 var minimumlimit; 28033 28034 field = $( field ); 28035 minimumlimit = field.find( "[type='checkbox'][data-minimumlimit]" ); 28036 28037 if ( minimumlimit.length && field_is_active( minimumlimit ) ) { 28038 eln = parseInt( minimumlimit.attr( 'data-minimumlimit' ), 10 ); 28039 checked = 0; 28040 field.find( "input.tm-epo-field[type='checkbox']:checked" ).toArray().forEach( function( cb ) { 28041 cb = $( cb ); 28042 q = cb.closest( 'li.tmcp-field-wrap' ).find( 'input.tm-qty' ); 28043 if ( q.length > 0 ) { 28044 val = parseInt( q.val(), 10 ); 28045 if ( val <= 0 ) { 28046 val = 1; 28047 } 28048 checked = parseInt( checked, 10 ) + val; 28049 } else { 28050 checked = parseInt( checked, 10 ) + 1; 28051 } 28052 } ); 28053 ew = field.closest( '.cpf-element' ); 28054 em = ew.find( 'div.tm-error-min' ); 28055 if ( eln > checked ) { 28056 checkall = false; 28057 first_error_obj = field; 28058 if ( eln === 1 ) { 28059 message = TMEPOJS.tm_epo_global_validator_messages.epominsingle.replaceAll( '{0}', eln ); 28060 } else { 28061 message = TMEPOJS.tm_epo_global_validator_messages.epomin.replaceAll( '{0}', eln ); 28062 } 28063 if ( em.length ) { 28064 em.remove(); 28065 } 28066 if ( TMEPOJS.tm_epo_global_error_label_placement === 'before' ) { 28067 field.closest( '.tc-element-container' ).before( '<div class="tm-error-min tm-error tc-cell tcwidth tcwidth-100">' + message + '</div>' ); 28068 } else { 28069 field.closest( '.tc-element-container' ).after( '<div class="tm-error-min tm-error tc-cell tcwidth tcwidth-100">' + message + '</div>' ); 28070 } 28071 } else { 28072 em.remove(); 28073 } 28074 } 28075 } ); 28076 28077 if ( first_error_obj ) { 28078 $.tcepo.errorObject[ epoEventId ] = first_error_obj; 28079 } 28080 28081 return checkall; 28082 } 28083 28084 function tm_check_minimumlimit_cont( minimumlimit_cont, epoEventId ) { 28085 $.tcepo.formSubmitEvents[ epoEventId ][ $.tcepo.formSubmitEvents[ epoEventId ].length ] = { 28086 trigger: function() { 28087 return tm_minimumlimit_cont( minimumlimit_cont, epoEventId ); 28088 }, 28089 on_true: function() { 28090 return true; 28091 }, 28092 on_false: function() { 28093 goto_error_item( false, epoEventId ); 28094 return true; 28095 } 28096 }; 28097 } 28098 28099 function cleanPrice( price ) { 28100 if ( price === null ) { 28101 return 0; 28102 } 28103 28104 if ( typeof price === 'object' ) { 28105 price = price[ 0 ]; 28106 } 28107 28108 if ( ! Number.isFinite( parseFloat( price ) ) ) { 28109 price = 0; 28110 } 28111 28112 return price; 28113 } 28114 28115 function tm_apply_dpd( price, totals, apply, force ) { 28116 price = cleanPrice( price ); 28117 28118 if ( apply ) { 28119 price = $.epoAPI.applyFilter( 'tc_apply_dpd', price, totals, apply, force ); 28120 } 28121 28122 return price; 28123 } 28124 28125 function tm_calculate_product_regular_price( totals, allowfalse ) { 28126 var price = 0; 28127 28128 if ( totals.length > 0 ) { 28129 price = totals.data( 'regular-price' ); 28130 } 28131 28132 price = $.epoAPI.applyFilter( 'tc_calculate_product_regular_price', price, totals ); 28133 28134 if ( allowfalse && price === false ) { 28135 return false;
28136 } 28137 price = parseFloat( price ); 28138 28139 if ( ! Number.isFinite( price ) ) { 28140 price = 0; 28141 } 28142 28143 return price; 28144 } 28145 28146 function tm_calculate_product_price( totals, allowfalse ) { 28147 var price = 0; 28148 28149 if ( totals.length > 0 ) { 28150 price = totals.data( 'price' ); 28151 } 28152 28153 price = $.epoAPI.applyFilter( 'tc_calculate_product_price', price, totals ); 28154 28155 if ( allowfalse && price === false ) { 28156 return false; 28157 } 28158 price = parseFloat( price ); 28159 28160 if ( ! Number.isFinite( price ) ) { 28161 price = 0; 28162 } 28163 28164 return price; 28165 } 28166 28167 function calculateMathPrice( price, thisElement, epoObject, noevents, useOriginalPrice, funcTotal, cumulativeTotal, mathskip ) { 28168 var formula = price.toString(); 28169 var val = 0; 28170 var matches; 28171 var match; 28172 var elementWrap; 28173 var allElements; 28174 var element; 28175 var reg; 28176 var elementPrice = 0; 28177 var pos; 28178 var type; 28179 var id; 28180 var thisVal; 28181 var thisValForced; 28182 var thisElementId = thisElement.closest( '.cpf-element' ).attr( 'data-uniqid' ); 28183 var thisElementWrap = thisElement.closest( '.tmcp-ul-wrap' ); 28184 var totalsHolder_tc_totals_ob = epoObject.this_epo_totals_container.data( 'totalsHolder_tc_totals_ob' ); 28185 var thisElementIndex = thisElementWrap.find( '.tmcp-field, .tmcp-fee-field, .tmcp-sub-fee-field' ).filter( ':checked' ).index( thisElement ); 28186 var thisElementIndexForced = thisElementWrap.find( '.tmcp-field, .tmcp-fee-field, .tmcp-sub-fee-field' ).index( thisElement ); 28187 var this_epo_container = epoObject.is_associated ? epoObject.this_epo_container : epoObject.this_epo_container.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector ); 28188 var constants = $.epoAPI.util.parseJSON( TMEPOJS.tm_epo_math ) || {}; 28189 var productPrice; 28190 var dynamicProductPrice; 28191 var __price; 28192 var __price_type; 28193 28194 if ( thisElementIndex === -1 && ! thisElement.is( '.tmcp-checkbox, .tmcp-radio' ) ) { 28195 thisElementIndex = 0; 28196 } 28197 if ( thisElementIndexForced === -1 && ! thisElement.is( '.tmcp-checkbox, .tmcp-radio' ) ) { 28198 thisElementIndexForced = 0; 28199 } 28200 28201 if ( ! thisElement.is( '.tcdisabled' ) && ! noevents && ! thisElement.data( 'addedtcEpoBeforeOptionPriceCalculation' ) ) { 28202 jWindow.on( 'tcEpoBeforeOptionPriceCalculation.math' + thisElementId, function() { 28203 tm_element_epo_rules( epoObject, thisElement, undefined, undefined, undefined, true ); 28204 } ); 28205 jWindow.on( 'tcEpoAfterNormalOptionPriceCalculation.math' + thisElementId, function() { 28206 thisElement.data( 'fetchOptionPrices', false ); 28207 thisElement.data( 'fetchOptionPrices-forced', false ); 28208 thisElement.data( 'fetchOptionPrices-fee', false ); 28209 thisElement.data( 'fetchOptionPrices-fee-forced', false ); 28210 thisElement.data( 'fetchOptionPrices-sub-fee', false ); 28211 thisElement.data( 'fetchOptionPrices-sub-fee-forced', false ); 28212 } ); 28213 thisElement.data( 'addedtcEpoBeforeOptionPriceCalculation', 1 ); 28214 } 28215 28216 if ( thisElement.is( '.tmcp-field' ) ) { 28217 if ( thisElement.data( 'fetchOptionPrices' ) ) { 28218 thisVal = thisElement.data( 'fetchOptionPrices' ); 28219 thisValForced = thisElement.data( 'fetchOptionPrices-forced' ); 28220 } else { 28221 thisVal = fetchOptionPrices( epoObject, thisElementWrap, '.tmcp-field', 0, 0, [], true, undefined, undefined, undefined, undefined, undefined, true ); 28222 thisValForced = fetchOptionPrices( epoObject, thisElementWrap, '.tmcp-field', 0, 0, [], true, true, undefined, undefined, undefined, undefined, true ); 28223 thisElement.data( 'fetchOptionPrices', thisVal ); 28224 thisElement.data( 'fetchOptionPrices-forced', thisValForced ); 28225 } 28226 } else if ( thisElement.is( '.tmcp-fee-field' ) ) { 28227 if ( thisElement.data( 'fetchOptionPrices-fee' ) ) { 28228 thisVal = thisElement.data( 'fetchOptionPrices-fee' ); 28229 thisValForced = thisElement.data( 'fetchOptionPrices-fee-forced' ); 28230 } else { 28231 thisVal = fetchOptionPrices( epoObject, thisElementWrap, '.tmcp-fee-field', 0, 0, [], true, undefined, undefined, undefined, undefined, undefined, true ); 28232 thisValForced = fetchOptionPrices( epoObject, thisElementWrap, '.tmcp-fee-field', 0, 0, [], true, true, undefined, undefined, undefined, undefined, true ); 28233 thisElement.data( 'fetchOptionPrices-fee', thisVal ); 28234 thisElement.data( 'fetchOptionPrices-fee-forced', thisValForced ); 28235 } 28236 } else if ( thisElement.is( '.tmcp-sub-fee-field' ) ) { 28237 if ( thisElement.data( 'fetchOptionPrices-sub-fee' ) ) { 28238 thisVal = thisElement.data( 'fetchOptionPrices-sub-fee' ); 28239 thisValForced = thisElement.data( 'fetchOptionPrices-sub-fee-forced' ); 28240 } else { 28241 thisVal = fetchOptionPrices( epoObject, thisElementWrap, '.tmcp-sub-fee-field', 0, 0, [], true, undefined, undefined, undefined, undefined, undefined, true ); 28242 thisValForced = fetchOptionPrices( epoObject, thisElementWrap, '.tmcp-sub-fee-field', 0, 0, [], true, true, undefined, undefined, undefined, undefined, true ); 28243 thisElement.data( 'fetchOptionPrices-sub-fee', thisVal ); 28244 thisElement.data( 'fetchOptionPrices-sub-fee-forced', thisValForced ); 28245 } 28246 } 28247 28248 Object.keys( constants ).forEach( function( key ) { 28249 var name; 28250 var value; 28251 28252 if ( constants[ key ].name !== '' && constants[ key ].value !== '' ) { 28253 name = constants[ key ].name; 28254 value = constants[ key ].value;
28255 if ( name.startsWith( '{' ) ) { 28256 formula = formula.replaceAll( name, value ); 28257 } else if ( constants[ key ].name.isNumeric() ) { 28258 formula = formula.replaceAll( '{' + name + '}', value ); 28259 } else { 28260 name = '{' + name + '}'; 28261 if ( value.startsWith( '{' ) ) { 28262 formula = formula.replaceAll( name, value ); 28263 } else { 28264 formula = formula.replaceAll( name, $.epoAPI.math.unformat( value.replace( ',', '.' ) ) ); 28265 } 28266 } 28267 } 28268 } ); 28269 28270 if ( totalsHolder_tc_totals_ob !== undefined ) { 28271 // product quantity 28272 formula = formula.replaceAll( '{quantity}', $.epoAPI.math.unformat( totalsHolder_tc_totals_ob.qty ) ); 28273 // original product price 28274 if ( useOriginalPrice && totalsHolder_tc_totals_ob.original_product_price !== undefined ) { 28275 productPrice = $.epoAPI.math.unformat( totalsHolder_tc_totals_ob.original_product_price ); 28276 } else { 28277 productPrice = $.epoAPI.math.unformat( totalsHolder_tc_totals_ob.product_price ); 28278 } 28279 if ( totalsHolder_tc_totals_ob.dynamic_product_price !== undefined ) { 28280 dynamicProductPrice = $.epoAPI.math.unformat( totalsHolder_tc_totals_ob.dynamic_product_price ); 28281 } else { 28282 dynamicProductPrice = 0; 28283 } 28284 } else { 28285 // product quantity 28286 formula = formula.replaceAll( '{quantity}', 0 ); 28287 // original product price 28288 productPrice = 0; 28289 dynamicProductPrice = 0; 28290 } 28291 28292 productPrice = $.epoAPI.math.toFloat( productPrice ); 28293 28294 formula = formula.replaceAll( '{product_price}', productPrice ); 28295 formula = formula.replaceAll( '{dynamic_product_price}', dynamicProductPrice ); 28296 28297 if ( ! funcTotal ) { 28298 funcTotal = 0; 28299 } 28300 funcTotal = $.epoAPI.math.toFloat( funcTotal ); 28301 28302 if ( ! cumulativeTotal ) { 28303 cumulativeTotal = 0; 28304 } 28305 cumulativeTotal = $.epoAPI.math.toFloat( cumulativeTotal ); 28306 28307 formula = formula.replaceAll( '{options_total}', funcTotal ); 28308 formula = formula.replaceAll( '{product_price_plus_options_total}', productPrice + funcTotal ); 28309 formula = formula.replaceAll( '{cumulative_total}', cumulativeTotal ); 28310 formula = formula.replaceAll( '{product_price_plus_cumulative_total}', productPrice + cumulativeTotal ); 28311 28312 if ( thisValForced.floatingBoxData !== undefined && thisValForced.floatingBoxData[ thisElementIndexForced ] !== undefined ) { 28313 // the option/element value to float 28314 if ( thisValForced.floatingBoxData[ thisElementIndexForced ].input_type === 'number' || thisValForced.floatingBoxData[ thisElementIndexForced ].input_type === 'hidden' ) { 28315 formula = formula 28316 .replaceAll( '{this.value}', $.epoAPI.math.toFloat( $.epoAPI.math.unformat( thisValForced.floatingBoxData[ thisElementIndexForced ].valueText ) ) ); 28317 } else { 28318 formula = formula 28319 .replaceAll( '{this.value}', $.epoAPI.math.toFloat( $.epoAPI.math.unformat( thisValForced.floatingBoxData[ thisElementIndexForced ].valueText, tcAPI.localDecimalSeparator ) ) ); 28320 } 28321 // the option/element raw value 28322 formula = formula.replaceAll( '{this.rawvalue}', thisValForced.floatingBoxData[ thisElementIndexForced ].valueText ); 28323 // the option/element raw value 28324 formula = formula.replaceAll( '{this.text}', thisValForced.floatingBoxData[ thisElementIndexForced ].valueText ); 28325 // the option/element value length 28326 formula = formula 28327 .replaceAll( '{this.value.length}', thisValForced.floatingBoxData[ thisElementIndexForced ].valueText.length ); 28328 } else { 28329 formula = formula 28330 // the option/element value to float 28331 .replaceAll( '{this.value}', 0 ) 28332 // the option/element raw value 28333 .replaceAll( '{this.rawvalue}', '' ) 28334 // the option/element raw value 28335 .replaceAll( '{this.text}', '' ) 28336 // the option/element value length 28337 .replaceAll( '{this.value.length}', 0 ); 28338 } 28339 28340 formula = formula 28341 // the number of options the user has selected 28342 .replaceAll( '{this.count}', thisVal.floatingBoxData.length ) 28343 // the total option quantity of this element 28344 .replaceAll( 28345 '{this.count.quantity}', 28346 thisVal.floatingBoxData 28347 .map( function( x ) { 28348 return x.quantity; 28349 } ) 28350 .reduce( function( acc, thisval ) { 28351 return $.epoAPI.math.toFloat( acc ) + $.epoAPI.math.toFloat
28351( thisval ); 28352 }, 0 ) 28353 ) 28354 // the option quantity of this element 28355 .replaceAll( '{this.quantity}', thisElement.data( 'tm-quantity' ) ); 28356 28357 if ( formula.match( /\{(\s)*?field\.([^}]*)}/ ) ) { 28358 matches = formula.match( /\{(\s)*?field\.([^}]*)}/g ); 28359 matches.forEach( function( field ) { 28360 match = field.match( /\{(\s)*?field\.([^}]*)}/ ); 28361 if ( undefined !== match[ 2 ] && 'string' === typeof match[ 2 ] ) { 28362 pos = match[ 2 ].lastIndexOf( '.' ); 28363 if ( pos !== -1 ) { 28364 id = match[ 2 ].substring( 0, pos ); 28365 type = match[ 2 ].substring( pos + 1 ); 28366 28367 if ( $.inArray( type, [ 'price', 'value', 'value.length', 'rawvalue', 'text', 'text.length', 'quantity', 'count', 'count.quantity' ] ) !== -1 ) { 28368 elementWrap = this_epo_container.find( "[data-uniqid='" + $.epoAPI.util.escapeSelector( id ) + "']" ); 28369 if ( elementWrap.length ) { 28370 allElements = elementWrap.find( '.tmcp-field, .tmcp-fee-field, .tmcp-sub-fee-field' ); 28371 element = allElements.first(); 28372 28373 if ( ! thisElement.is( '.tcdisabled' ) && ! noevents && ! thisElement.data( 'addedfieldtcEpoBeforeOptionPriceCalculation' ) ) { 28374 jWindow.on( 'tcEpoBeforeOptionPriceCalculation.math' + thisElementId, function() { 28375 tm_element_epo_rules( epoObject, thisElement, undefined, undefined, undefined, true ); 28376 thisElement.trigger( 'tm-math-select-change-html-all' ); 28377 } ); 28378 thisElement.data( 'addedfieldtcEpoBeforeOptionPriceCalculation', 1 ); 28379 } 28380 val = 0; 28381 switch ( type ) { 28382 case 'text': 28383 case 'rawvalue': 28384 val = ''; 28385 break; 28386 } 28387 28388 if ( elementWrap.is( '.tc-container-enabled' ) ) { 28389 if ( ! mathskip ) { 28390 allElements.toArray().forEach( function( singleElement ) { 28391 singleElement = $( singleElement ); 28392 // For now we only recalculate dynamic elements 28393 if ( thisElement.attr( 'id' ) !== singleElement.attr( 'id' ) && ( thisElement.is( '.tmcp-dynamic' ) || singleElement.is( '.tmcp-dynamic' ) ) ) { 28394 tm_element_epo_rules( epoObject, singleElement, undefined, undefined, undefined, true, undefined, undefined, true ); 28395 } 28396 if ( ! noevents && ! singleElement.data( 'addedmathevent' ) ) { 28397 singleElement.on( 'input.mathevent', function() { 28398 if ( ! thisElement.is( '.tcdisabled' ) ) { 28399 thisElement.trigger( 'change.cpf', { calculateMathPrice: 1 } ); 28400 } 28401 } ); 28402 singleElement.data( 'addedmathevent', 1 ); 28403 } 28404 } ); 28405 } 28406 if ( element.is( '.tmcp-field' ) ) { 28407 val = fetchOptionPrices( epoObject, elementWrap, '.tmcp-field', 0, 0, [], true, undefined, undefined, true, undefined, undefined, true ); 28408 } else if ( element.is( '.tmcp-fee-field' ) ) { 28409 val = fetchOptionPrices( epoObject, elementWrap, '.tmcp-fee-field', 0, 0, [], true, undefined, undefined, true, undefined, undefined, true ); 28410 } else if ( element.is( '.tmcp-sub-fee-field' ) ) { 28411 val = fetchOptionPrices( epoObject, elementWrap, '.tmcp-sub-fee-field', 0, 0, [], true, undefined, undefined, true, undefined, undefined, true ); 28412 } 28413 28414 switch ( type ) { 28415 // element price 28416 case 'price': 28417 val = val.total; 28418 if ( thisElement.is( '.tmcp-dynamic' ) ) { 28419 __price = get_type( epoObject, element, 'price' ); 28420 __price_type = get_type( epoObject, element, 'price_type' ); 28421 if ( 'math' === __price_type && __price.includes( '{dynamic_product_price}' ) ) { 28422 val = 0; 28423 } 28424 } 28425 break; 28426 28427 // element value 28428 case 'value': 28429 case 'text': 28430 case 'rawvalue': 28431 if ( val.floatingBoxData ) { 28432 val = val.floatingBoxData 28433 .map( function( x ) { 28434 if ( x.input_type === 'number' || x.input_type === 'hidden' ) { 28435 if ( type === 'text' || type === 'rawvalue' ) { 28436 return x.valueText; 28437 } 28438 return $.epoAPI.math.unformat( x.valueText ); 28439 } 28440 if ( type === 'text' || type === 'rawvalue' ) { 28441 return x.valueText; 28442 } 28443 return $.epoAPI.math.unformat( x.valueText, tcAPI.localIn
28443putDecimalSeparator ); 28444 } ) 28445 .reduce( function( acc, thisval ) { 28446 if ( type === 'text' || type === 'rawvalue' ) { 28447 return acc + thisval; 28448 } 28449 return $.epoAPI.math.toFloat( acc ) + $.epoAPI.math.toFloat( thisval ); 28450 }, ( type === 'text' || type === 'rawvalue' ) ? '' : 0 ); 28451 28452 if ( type === 'text' || type === 'rawvalue' ) { 28453 if ( val === '' ) { 28454 val = "''"; 28455 } else if ( ! val.toString().isNumeric() ) { 28456 val = "'" + val.replaceAll( "'", "\\'" ) + "'"; 28457 } 28458 } 28459 } 28460 break; 28461 28462 // element value length 28463 case 'value.length': 28464 case 'text.length': 28465 if ( val.floatingBoxData ) { 28466 val = val.floatingBoxData 28467 .map( function( x ) { 28468 return x.valueText; 28469 } ) 28470 .reduce( function( acc, thisval ) { 28471 return $.epoAPI.math.toFloat( acc ) + thisval.length; 28472 }, 0 ); 28473 } 28474 break; 28475 28476 // element quantity 28477 // the total option quantity of this element 28478 case 'quantity': 28479 case 'count.quantity': 28480 if ( val.floatingBoxData ) { 28481 val = val.floatingBoxData 28482 .map( function( x ) { 28483 return x.quantity; 28484 } ) 28485 .reduce( function( acc, thisval ) { 28486 return $.epoAPI.math.toFloat( acc ) + $.epoAPI.math.toFloat( thisval ); 28487 }, 0 ); 28488 } 28489 break; 28490 28491 // number of element options the user has selected 28492 case 'count': 28493 if ( val.floatingBoxData ) { 28494 val = val.floatingBoxData.length; 28495 } 28496 break; 28497 } 28498 if ( type !== 'text' && type !== 'rawvalue' ) { 28499 val = $.epoAPI.math.toFloat( val ); 28500 if ( ! Number.isFinite( val ) ) { 28501 val = 0; 28502 } 28503 } 28504 } 28505 } else { 28506 val = 0; 28507 switch ( type ) { 28508 case 'text': 28509 case 'rawvalue': 28510 val = ''; 28511 break; 28512 } 28513 } 28514 reg = new RegExp( match[ 0 ] ); 28515 if ( type === 'text' || type === 'rawvalue' ) { 28516 formula = val === '' ? formula.replace( reg, "''" ) : formula.replace( reg, val ); 28517 } else { 28518 formula = ! Number.isFinite( val ) ? formula.replace( reg, "'" + val.replace( "'", "\\'" ) + "'" ) : formula.replace( reg, val ); 28519 } 28520 } 28521 } 28522 } 28523 } ); 28524 } 28525 28526 try { 28527 elementPrice = tcmexp.evaluate( formula ); 28528 } catch ( e ) { 28529 elementPrice = 0; 28530 } 28531 28532 return elementPrice; 28533 } 28534 28535 function get_type( epoObject, obj, type ) { 28536 var element = $( obj ); 28537 var setter = element; 28538 var cart; 28539 var current_variation; 28540 var rules; 28541 var rulestype; 28542 var _rulestype; 28543 var pricetype; 28544 var variation_id_selector; 28545 var _tmcpulwrap; 28546 var price; 28547 var _rules; 28548 28549 cart = epoObject.main_cart; 28550 variation_id_selector = "input[name^='variation_id']"; 28551 if ( cart.find( 'input.variation_id' ).length > 0 ) { 28552 variation_id_selector = 'input.variation_id'; 28553 } 28554 current_variation = cart.find( variation_id_selector ).val(); 28555 // Get current woocommerce variation 28556 if ( ! current_variation ) { 28557 current_variation = 0; 28558 } 28559 28560 if ( element.is( 'select' ) ) { 28561 setter = element.find( 'option:selected' ); 28562 } 28563 28564 rules = $.epoAPI.util.parseJSON( setter.attr( 'data-rules' ) ); 28565 rulestype = $.epoAPI.util.parseJSON( setter.attr( 'data-rulestype' ) ); 28566 28567 pricetype = ''; 28568 if ( typeof rules === 'object' ) { 28569 if ( current_variation in rules ) { 28570 price = rules[ current_variation ]; 28571 } else { 28572 _rules = $.epoAPI.util.parseJSON( element.closest( '.tmcp-ul-wrap' ).attr( 'data-rules' ) ); 28573 28574 if ( typeof _rules === 'object' ) { 28575 if ( current_variation in _rules ) { 28576 price = _rules[ current_variation ]; 28577 } else { 28578 price = rules[ 0 ]; 28579 } 28580 } else { 28581 price = rules[ 0 ]; 28582 } 28583 } 28584 if ( typeof rulestype === 'object' ) { 28585 if ( current_variation in rulestype ) { 28586 pricetype = rulestype[ current_variation ]; 28587 } else { 28588 _rulestype = $.epoAPI.util.parseJSON( element.closest( '.tmcp-ul-wrap' ).attr( 'data-rulestype' ) ); 28589 if ( typeof _rulestype === 'object' ) { 28590 if ( current_variation in _rulestype ) { 28591 pricetype = _rulestype[ current_variation ]; 28592 } else { 28593 pricetype = rulestype[ 0 ]; 28594 } 28595 } else { 28596 pricetype = rulestype[ 0 ]; 28597 } 28598 } 28599 } else { 28600 rulestype = $.epoAPI.util.parseJSON( element.closest( '.tmcp-ul-wrap' ).attr( 'data-ulestype' ) ); 28601 if ( typeof rulestype === 'object' ) { 28602 if ( current_variation in rulestype ) { 28603 pricetype = rulestype[ current_variation ]; 28604 } else { 28605 pricetype = rulestype[ 0 ]; 28606 } 28607 } 28608 } 28609 } else { 28610 _tmcpulwrap = element.closest( '.tmcp-ul-wrap' ); 28611 rules = $.epoAPI.util.parseJSON( _tmcpulwrap.attr( 'data-rules' ) ); 28612 28613 if ( typeof rules === 'object' ) { 28614 if ( current_variation in rules ) { 28615 price = rules[ current_variation ]; 28616 } else { 28617 price = rules[ 0 ]; 28618 } 28619 if ( typeof rulestype === 'object' ) { 28620 if ( current_variation in rulestype ) { 28621 pricetype = rulestype[ current_variation ]; 28622 } else { 28623 _rulestype = $.epoAPI.util.parseJSON( _tmcpulwrap.attr( 'data-rulestype' ) ); 28624 if ( typeof _rulestype === 'object' ) { 28625 if ( current_variation in _rulestype ) { 28626 pricetype = _rulestype[ current_variation ]; 28627 } else { 28628 pricetype = rulestype[ 0 ]; 28629 } 28630 } else { 28631 pricetype = rulestype[ 0 ]; 28632 } 28633 } 28634 } else { 28635 rulestype = $.epoAPI.util.parseJSON( _tmcpulwrap.attr( 'data-rulestype' ) ); 28636 if ( typeof rulestype === 'object' ) { 28637 if ( current_variation in rulestype ) { 28638 pricetype = rulestype[ current_variation ]; 28639 } else { 28640 pricetype = rulestype[ 0 ]; 28641 } 28642 } 28643 } 28644 } 28645 } 28646 28647 if ( typeof price === 'object' ) { 28648 price = price[ 0 ]; 28649 } 28650 28651 if ( typeof pricetype === 'object' ) { 28652 pricetype = pricetype[ 0 ]; 28653 } 28654 if ( element.is( '.tmcp-fee-field' ) ) { 28655 if ( $.inArray( pricetype, [ 'fee', 'stepfee', 'currentstepfee' ] ) !== -1 ) { 28656 pricetype = ''; 28657 } 28658 } 28659 28660 if ( type === 'price' ) { 28661 return price; 28662 } 28663 28664 return pricetype; 28665 } 28666 28667 function wordLength( str ) { 28668 var regex = new RegExp( /[\p{L}\d!@#$%^&*()_+=\{[\}\]|\\"':;?/>.<,-]+/, 'gu' ); 28669 var m; 28670 var len = 0; 28671 28672 while ( ( m = regex.exec( str ) ) !== null ) { 28673 // This is necessary to avoid infinite loops with zero-width matches 28674 if ( m.index === regex.lastIndex ) { 28675 regex.lastIndex++; 28676 } 28677 len = len + m.length; 28678 } 28679 return len; 28680 } 28681 28682 // Set field price rules 28683 function tm_element_epo_rules( epoObject, obj, args, setter_override, noremove, manthnoevent, funcTotal, cumulativeTotal, mathskip ) { 28684 var element = obj instanceof $ ? obj : $( obj ); 28685 var setterall = element; 28686 var cart; 28687 var current_variation; 28688 var bundleid; 28689 var epoTotalsContainer; 28690 var apply_dpd; 28691 var product_price; 28692 var product_original_price; 28693 var is_range_field = element.is( '.tmcp-range' ); 28694 var rules; 28695 var rulestype; 28696 var original_rules; 28697 var _rules; 28698 var _rulestype; 28699 var _original_rules; 28700 var pricetype; 28701 var price; 28702 var original_price; 28703 var raw_price; 28704 var raw_original_price; 28705 var formatted_price = ''; 28706 var textlength; 28707 var freechars; 28708 var min_value; 28709 var main_product = epoObject.main_product; 28710 var epoEventId = epoObject.epoEventId; 28711 var variation_id_selector; 28712 var _tmcpulwrap; 28713 var cart_total; 28714 var per_product_pricing = true; 28715 var addedPrice = 0; 28716 var originalAddedPrice = 0; 28717 var undiscounted_raw_price; 28718 var undiscounted_raw_original_price; 28719 var undiscounted_price; 28720 var undiscounted_original_price; 28721 var isFilled; 28722 var useFormattedPrice = false;
28723 28724 if ( element.data( 'associated_price_set' ) ) { 28725 return; 28726 } 28727 28728 if ( ! args ) { 28729 cart = epoObject.main_cart; 28730 if ( cart.data( 'per_product_pricing' ) !== undefined ) { 28731 per_product_pricing = cart.data( 'per_product_pricing' ); 28732 } 28733 variation_id_selector = "input[name^='variation_id']"; 28734 if ( cart.find( 'input.variation_id' ).length > 0 ) { 28735 variation_id_selector = 'input.variation_id'; 28736 } 28737 current_variation = cart.find( variation_id_selector ).val(); 28738 28739 bundleid = $.epoAPI.applyFilter( 'tc_get_bundleid', cart.attr( 'data-product_id' ), cart, epoObject ); 28740 28741 // Get current woocommerce variation 28742 if ( ! current_variation ) { 28743 current_variation = 0; 28744 } 28745 28746 epoTotalsContainer = $.epoAPI.applyFilter( 'tc_get_totals_container', epoObject.this_epo_totals_container, element, main_product, bundleid ); 28747 product_price = tm_calculate_product_price( epoTotalsContainer ); 28748 product_original_price = tm_calculate_product_regular_price( epoTotalsContainer ); 28749 apply_dpd = epoTotalsContainer.data( 'fields-price-rules' ); 28750 } else { 28751 cart = args.cart; 28752 current_variation = args.current_variation; 28753 28754 bundleid = args.bundleid; 28755 epoTotalsContainer = args.epoTotalsContainer; 28756 product_price = args.product_price; 28757 product_original_price = args.product_original_price; 28758 apply_dpd = args.apply_dpd; 28759 per_product_pricing = args.per_product_pricing; 28760 } 28761 product_price = $.epoAPI.applyFilter( 'tc_alter_product_price', product_price, element, cart, epoTotalsContainer, bundleid ); 28762 product_original_price = $.epoAPI.applyFilter( 'tc_alter_product_original_price', product_original_price, element, cart, epoTotalsContainer ); 28763 28764 if ( product_price === false || ! per_product_pricing ) { 28765 return; 28766 } 28767 28768 if ( element.is( 'select' ) ) { 28769 setterall = element.find( 'option:selected' ); 28770 } 28771 if ( setter_override ) { 28772 setterall = setter_override; 28773 } 28774 28775 setterall.toArray().forEach( function( setter ) { 28776 var mathopc = false; 28777 setter = $( setter ); 28778 28779 rules = $.epoAPI.util.parseJSON( setter.attr( 'data-rules' ) ); 28780 rulestype = $.epoAPI.util.parseJSON( setter.attr( 'data-rulestype' ) ); 28781 original_rules = $.epoAPI.util.parseJSON( setter.attr( 'data-original-rules' ) ); 28782 if ( element.is( '.tmcp-dynamic' ) ) { 28783 rules = $.epoAPI.util.parseJSON( setter.attr( 'data-formula' ) ); 28784 original_rules = $.epoAPI.util.parseJSON( setter.attr( 'data-formula' ) ); 28785 rulestype = $.epoAPI.util.parseJSON( setter.attr( 'data-calculation-type' ) ); 28786 } 28787 if ( original_rules === undefined ) { 28788 original_rules = rules; 28789 } 28790 28791 pricetype = ''; 28792 if ( typeof rules === 'object' ) { 28793 if ( current_variation in rules ) { 28794 price = rules[ current_variation ]; 28795 original_price = original_rules[ current_variation ]; 28796 } else { 28797 _rules = $.epoAPI.util.parseJSON( element.closest( '.tmcp-ul-wrap' ).attr( 'data-rules' ) ); 28798 _original_rules = element.closest( '.tmcp-ul-wrap' ).data( 'original-rules' ); 28799 28800 if ( typeof _rules === 'object' ) { 28801 if ( current_variation in _rules ) { 28802 price = _rules[ current_variation ]; 28803 } else { 28804 price = rules[ 0 ]; 28805 } 28806 } else { 28807 price = rules[ 0 ]; 28808 } 28809 28810 if ( typeof _original_rules === 'object' ) { 28811 if ( current_variation in _original_rules ) { 28812 original_price = _original_rules[ current_variation ]; 28813 } else { 28814 original_price = original_rules[ 0 ]; 28815 } 28816 } else { 28817 original_price = original_rules[ 0 ]; 28818 } 28819 } 28820 28821 if ( typeof rulestype === 'object' ) { 28822 if ( current_variation in rulestype ) { 28823 pricetype = rulestype[ current_variation ]; 28824 } else { 28825 _rulestype = $.epoAPI.util.parseJSON( element.closest( '.tmcp-ul-wrap' ).attr( 'data-rulestype' ) ); 28826 if ( typeof _rulestype === 'object' ) { 28827 if ( current_variation in _rulestype ) { 28828 pricetype = _rulestype[ current_variation ]; 28829 } else { 28830 pricetype = rulestype[ 0 ]; 28831 } 28832 } else { 28833 pricetype = rulestype[ 0 ]; 28834 } 28835 } 28836 } else { 28837 rulestype = $.epoAPI.util.parseJSON( element.closest( '.tmcp-ul-wrap' ).attr( 'data-ulestype' ) ); 28838 if ( typeof rulestype === 'object' ) { 28839 if ( current_variation in rulestype ) { 28840 pricetype = rulestype[ current_variation ]; 28841 } else { 28842 pricetype = rulestype[ 0 ]; 28843 } 28844 } 28845 } 28846 } else { 28847 _tmcpulwrap = element.closest( '.tmcp-ul-wrap' ); 28848 rules = $.epoAPI.util.parseJSON( _tmcpulwrap.attr( 'data-rules' ) ); 28849 original_rules = $.epoAPI.util.parseJSON( _tmcpulwrap.attr( 'data-original-rules' ) ); 28850 28851 if ( typeof rules === 'object' ) { 28852 if ( current_variation in rules ) { 28853 price = rules[ current_variation ]; 28854 } else { 28855 price = rules[ 0 ]; 28856 } 28857 if ( typeof original_rules === 'object' ) { 28858 if ( current_variation in original_rules ) { 28859 original_price = original_rules[ current_variation ]; 28860 } else { 28861 original_price = original_rules[ 0 ]; 28862 } 28863 } else { 28864 original_price = price; 28865 } 28866 28867 if ( typeof rulestype === 'object' ) { 28868 if ( current_variation in rulestype ) { 28869 pricetype = rulestype[ current_variation ]; 28870 } else { 28871 _rulestype = $.epoAPI.util.parseJSON( _tmcpulwrap.attr( 'data-rulestype' ) ); 28872 if ( typeof _rulestype === 'object' ) { 28873 if ( current_variation in _rulestype ) { 28874 pricetype = _rulestype[ current_variation ]; 28875 } else { 28876 pricetype = rulestype[ 0 ]; 28877 } 28878 } else { 28879 pricetype = rulestype[ 0 ]; 28880 } 28881 } 28882 } else { 28883 rulestype = $.epoAPI.util.parseJSON( _tmcpulwrap.attr( 'data-rulestype' ) ); 28884 if ( typeof rulestype === 'object' ) { 28885 if ( current_variation in rulestype ) { 28886 pricetype = rulestype[ current_variation ]; 28887 } else { 28888 pricetype = rulestype[ 0 ]; 28889 } 28890 } 28891 } 28892 } 28893 } 28894 28895 if ( typeof pricetype === 'object' ) { 28896 pricetype = pricetype[ 0 ]; 28897 } 28898 if ( element.is( '.tmcp-fee-field' ) ) { 28899 if ( $.inArray( pricetype, [ 'fee', 'stepfee', 'currentstepfee' ] ) !== -1 ) { 28900 pricetype = ''; 28901 } 28902 apply_dpd = 0; 28903 } 28904 28905 if ( noremove === undefined ) { 28906 if ( element.is( 'select' ) ) { 28907 element.find( 'option' ).removeClass( 'tm-epo-late-field' ).removeData( 'tm-price-for-late islate' ); 28908 } else { 28909 setter.removeClass( 'tm-epo-late-field' ).removeData( 'tm-price-for-late islate' ); 28910 } 28911 } 28912 if ( pricetype !== 'math' ) { 28913 price = cleanPrice( price ); 28914 original_price = cleanPrice( original_price ); 28915 } else if ( typeof price === 'object' ) { 28916 price = price[ 0 ]; 28917 } 28918 28919 undiscounted_raw_price = price; 28920 undiscounted_raw_original_price = original_price; 28921 28922 switch ( pricetype ) { 28923 case '': 28924 undiscounted_price = price; 28925 price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ); 28926 // original_price No change 28927 break; 28928 case 'fixednon': 28929 freechars = parseInt( setter.attr( 'data-freechars' ), 10 ); 28930 if ( ! Number.isFinite( freechars ) ) { 28931 freechars = 0; 28932 } 28933 textlength = setter.val().length - freechars; 28934 if ( textlength <= 0 ) { 28935 price = 0; 28936 } 28937 undiscounted_price = price; 28938 price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ); 28939 break; 28940 case 'math': 28941 if ( price !== original_price ) { 28942 mathopc = true; 28943 } else { 28944 mathopc = false;
28945 } 28946 if ( mathopc ) { 28947 original_price = calculateMathPrice( original_price, element, epoObject, true, true, funcTotal, cumulativeTotal, mathskip ); 28948 } 28949 price = calculateMathPrice( price, element, epoObject, manthnoevent, $.epoAPI.applyFilter( 'tc_use_undiscounted_price', undefined, element, cart, epoTotalsContainer ), funcTotal, cumulativeTotal, mathskip ); 28950 if ( ! mathopc ) { 28951 original_price = price; 28952 } 28953 undiscounted_price = price; 28954 price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ); 28955 // original_price No other change 28956 break; 28957 case 'percent_cart_total': 28958 cart_total = parseFloat( TMEPOJS.cart_total ); 28959 28960 if ( ! Number.isFinite( cart_total ) ) { 28961 cart_total = 0; 28962 } 28963 undiscounted_price = ( price / 100 ) * cart_total; 28964 price = ( tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) / 100 ) * cart_total; 28965 original_price = ( tm_apply_dpd( original_price, epoTotalsContainer, apply_dpd ) / 100 ) * cart_total; 28966 break; 28967 28968 case 'percent': 28969 undiscounted_price = ( price / 100 ) * product_price; 28970 price = ( tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) / 100 ) * product_price; 28971 original_price = ( original_price / 100 ) * product_original_price; 28972 break; 28973 case 'percentcurrenttotal': 28974 $.tcepo.lateFieldsPrices[ epoEventId ].push( { 28975 setter: setter, 28976 price: price, 28977 original_price: original_price, 28978 bundleid: bundleid, 28979 pricetype: pricetype 28980 } ); 28981 setter.data( 'tm-price-for-late', price ).data( 'tm-original-price-for-late', original_price ).data( 'islate', 1 ).addClass( 'tm-epo-late-field' ); 28982 undiscounted_price = 0; 28983 price = 0; 28984 original_price = 0; 28985 break; 28986 case 'fixedcurrenttotal': 28987 price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ); 28988 $.tcepo.lateFieldsPrices[ epoEventId ].push( { 28989 setter: setter, 28990 price: price, 28991 original_price: original_price, 28992 bundleid: bundleid, 28993 pricetype: pricetype 28994 } ); 28995 setter.data( 'tm-price-for-late', price ).data( 'tm-original-price-for-late', original_price ).data( 'islate', 1 ).addClass( 'tm-epo-late-field' ); 28996 undiscounted_price = 0; 28997 price = 0; 28998 original_price = 0; 28999 break; 29000 case 'word': 29001 undiscounted_price = price * wordLength( setter.val() ); 29002 price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * wordLength( setter.val() ); 29003 original_price = original_price * wordLength( setter.val() ); 29004 break; 29005 case 'wordpercent': 29006 undiscounted_price = ( price / 100 ) * product_price * wordLength( setter.val() ); 29007 price = ( tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) / 100 ) * product_price * wordLength( setter.val() ); 29008 original_price = ( original_price / 100 ) * product_original_price * wordLength( setter.val() ); 29009 break; 29010 case 'wordnon': 29011 freechars = parseInt( setter.attr( 'data-freechars' ), 10 ); 29012 if ( ! Number.isFinite( freechars ) ) { 29013 freechars = 0; 29014 } 29015 textlength = wordLength( setter.val() ) - freechars; 29016 if ( textlength < 0 ) { 29017 textlength = 0; 29018 } 29019 undiscounted_price = price * textlength; 29020 price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * textlength; 29021 original_price = original_price * textlength; 29022 break; 29023 case 'wordpercentnon': 29024 freechars = parseInt( setter.attr( 'data-freechars' ), 10 ); 29025 if ( ! Number.isFinite( freechars ) ) { 29026 freechars = 0; 29027 } 29028 textlength = wordLength( setter.val() ) - freechars; 29029 if ( textlength < 0 ) { 29030 textlength = 0; 29031 } 29032 undiscounted_price = ( price / 100 ) * product_price * textlength; 29033 price = ( tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) / 100 ) * product_price * textlength; 29034 original_price = ( original_price / 100 ) * product_original_price * textlength; 29035 break; 29036 29037 case 'char': 29038 undiscounted_price = price * setter.val().length; 29039 price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * setter.val().length; 29040 original_price = original_price * setter.val().length; 29041 break; 29042 case 'charpercent': 29043 undiscounted_price = ( price / 100 ) * product_price * setter.val().length; 29044 price = ( tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) / 100 ) * product_price * setter.val().length; 29045 original_price = ( original_price / 100 ) * product_original_price * setter.val().length; 29046 break; 29047 case 'charnospaces': 29048 undiscounted_price = price * setter.val().replace( /\s/g, '' ).length; 29049 price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * setter.val().replace( /\s/g, '' ).length; 29050 original_price = original_price * setter.val().replace( /\s/g, '' ).length; 29051 break; 29052 case 'charnofirst': 29053 textlength = setter.val().length - 1; 29054 if ( textlength < 0 ) { 29055 textlength = 0; 29056 } 29057 undiscounted_price = price * textlength; 29058 price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * textlength; 29059 original_price = original_price * textlength; 29060 break; 29061
29062 case 'charnon': 29063 freechars = parseInt( setter.attr( 'data-freechars' ), 10 ); 29064 if ( ! Number.isFinite( freechars ) ) { 29065 freechars = 0; 29066 } 29067 textlength = setter.val().length - freechars; 29068 if ( textlength < 0 ) { 29069 textlength = 0; 29070 } 29071 undiscounted_price = price * textlength; 29072 price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * textlength; 29073 original_price = original_price * textlength; 29074 break; 29075 case 'charpercentnon': 29076 freechars = parseInt( setter.attr( 'data-freechars' ), 10 ); 29077 if ( ! Number.isFinite( freechars ) ) { 29078 freechars = 0; 29079 } 29080 textlength = setter.val().length - freechars; 29081 if ( textlength < 0 ) { 29082 textlength = 0; 29083 } 29084 undiscounted_price = ( price / 100 ) * product_price * textlength; 29085 price = ( tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) / 100 ) * product_price * textlength; 29086 original_price = ( original_price / 100 ) * product_original_price * textlength; 29087 break; 29088 case 'charnonnospaces': 29089 freechars = parseInt( setter.attr( 'data-freechars' ), 10 ); 29090 if ( ! Number.isFinite( freechars ) ) { 29091 freechars = 0; 29092 } 29093 textlength = setter.val().replace( /\s/g, '' ).length - freechars; 29094 if ( textlength < 0 ) { 29095 textlength = 0; 29096 } 29097 undiscounted_price = price * textlength; 29098 price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * textlength; 29099 original_price = original_price * textlength; 29100 break; 29101 case 'charpercentnonnospaces': 29102 freechars = parseInt( setter.attr( 'data-freechars' ), 10 ); 29103 if ( ! Number.isFinite( freechars ) ) { 29104 freechars = 0; 29105 } 29106 textlength = setter.val().replace( /\s/g, '' ).length - freechars; 29107 if ( textlength < 0 ) { 29108 textlength = 0; 29109 } 29110 undiscounted_price = ( price / 100 ) * product_price * textlength; 29111 price = ( tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) / 100 ) * product_price * textlength; 29112 original_price = ( original_price / 100 ) * product_original_price * textlength; 29113 break; 29114 29115 case 'charpercentnofirst': 29116 textlength = setter.val().length - 1; 29117 if ( textlength < 0 ) { 29118 textlength = 0; 29119 } 29120 undiscounted_price = ( price / 100 ) * product_price * textlength; 29121 price = ( tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) / 100 ) * product_price * textlength; 29122 original_price = ( original_price / 100 ) * product_original_price * textlength; 29123 break; 29124 case 'step': 29125 if ( is_range_field ) { 29126 undiscounted_price = price * setter.val(); 29127 price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * setter.val(); 29128 original_price = original_price * $.epoAPI.math.toFloat( setter.val() ); 29129 } else { 29130 undiscounted_price = price * $.epoAPI.math.toFloat( setter.val() ); 29131 price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * $.epoAPI.math.toFloat( setter.val() ); 29132 original_price = original_price * $.epoAPI.math.toFloat( setter.val() ); 29133 } 29134 break; 29135 case 'currentstep': 29136 if ( is_range_field ) { 29137 undiscounted_price = setter.val(); 29138 price = tm_apply_dpd( setter.val(), epoTotalsContainer, apply_dpd ); 29139 original_price = tm_apply_dpd( setter.val(), epoTotalsContainer, apply_dpd ); 29140 } else { 29141 undiscounted_price = $.epoAPI.math.toFloat( setter.val() ); 29142 price = tm_apply_dpd( $.epoAPI.math.toFloat( setter.val() ), epoTotalsContainer, apply_dpd ); 29143 original_price = tm_apply_dpd( $.epoAPI.math.toFloat( setter.val() ), epoTotalsContainer, apply_dpd ); 29144 } 29145 break; 29146 case 'intervalstep': 29147 if ( is_range_field ) { 29148 min_value = parseFloat( $( '.tm-range-picker[data-field-id="' + setter.attr( 'id' ) + '"]' ).attr( 'data-min' ) ); 29149 undiscounted_price = price * ( setter.val() - min_value ); 29150 price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * ( setter.val() - min_value ); 29151 original_price = original_price * ( setter.val() - min_value ); 29152 } 29153 break; 29154 case 'row': 29155 undiscounted_price = price * ( ( setter.val().match( /(\r\n|\n|\r)/gm ) || [] ).length + 1 ); 29156 price = tm_apply_dpd( price, epoTotalsContainer, apply_dpd ) * ( ( setter.val().match( /(\r\n|\n|\r)/gm ) || [] ).length + 1 ); 29157 original_price = original_price * ( ( setter.val().match( /(\r\n|\n|\r)/gm ) || [] ).length + 1 ); 29158 break; 29159 } 29160 29161 raw_price = price; 29162 raw_original_price = original_price; 29163 29164 undiscounted_original_price = original_price; 29165 undiscounted_raw_price = undiscounted_price; 29166 undiscounted_raw_original_price = undiscounted_original_price; 29167 29168 if ( element.data( 'tm-quantity' ) ) { 29169 undiscounted_price = undiscounted_price * parseFloat( element.data( 'tm-quantity' ) ); 29170 undiscounted_original_price = undiscounted_original_price * parseFloat( element.data( 'tm-quantity' ) ); 29171 undiscounted_raw_price = undiscounted_raw_price * parseFloat( element.data( 'tm-quantity' ) ); 29172 undiscounted_raw_original_price = undiscounted_raw_original_price * parseFloat( element.data( 'tm-quantity' ) ); 29173 29174 price = price * parseFloat( element.data( 'tm-quantity' ) ); 29175 original_price = original_price * parseFloat( element.data( 'tm-quantity' ) ); 29176 raw_price = raw_price * parseFloat( element.data( 'tm-quantity' ) ); 29177 raw_original_price = raw_original_price * parseFloat( element.data( 'tm-quantity' ) ); 29178 } 29179 29180 addedPrice = addedPrice + parseFloat( price ); 29181 originalAddedPrice = originalAddedPrice + parseFloat( original_price ); 29182 29183 element.data( 'price_set', 1 ); 29184 setter.data( 'price_set', 1 ); 29185 29186 setter.data( 'undiscounted_raw_price', undiscounted_raw_price ); 29187 setter.data( 'undiscounted_raw_original_price', undiscounted_raw_original_price ); 29188 setter.data( 'undiscounted_price', tm_set_tax_price( undiscounted_price, epoTotalsContainer, setter, pricetype ) ); 29189 setter.data( 'undiscounted_original_price', tm_set_tax_price( undiscounted_original_price, epoTotalsContainer, setter, pricetype ) ); 29190 29191 setter.data( 'raw_price', raw_price ); 29192 setter.data( 'raw_original_price', raw_original_price ); 29193 setter.data( 'price', tm_set_tax_price( price, epoTotalsContainer, setter, pricetype ) ); 29194 setter.data( 'original_price', tm_set_tax_price( original_price, epoTotalsContainer, setter, pricetype ) ); 29195 29196 if ( ! setter_override ) { 29197 if ( element.is( '.tc-epo-field-product' ) ) { 29198 isFilled = false;
29199 if ( element.is( 'select' ) ) { 29200 if ( element.val() !== '' ) { 29201 isFilled = true; 29202 } 29203 } else if ( ( element.is( ':checkbox' ) || element.is( ':radio' ) ) ) { 29204 if ( element.is( ':checked' ) ) { 29205 isFilled = true; 29206 } 29207 } else if ( element.val() !== '' ) { 29208 isFilled = true; 29209 } 29210 29211 if ( ! isFilled ) { 29212 formatted_price = setter.data( 'price-html' ); 29213 useFormattedPrice = true; 29214 } 29215 } 29216 tm_update_price( { 29217 epoObject: epoObject, 29218 obj: setter.closest( '.tmcp-field-wrap' ).find( '.tc-price' ), 29219 price: tm_get_price( addedPrice, epoTotalsContainer, false, setter, pricetype ), 29220 formatted_price: formatted_price, 29221 original_price: tm_get_price( originalAddedPrice, epoTotalsContainer, false, setter, pricetype ), 29222 force: false, 29223 useFormattedPrice: useFormattedPrice 29224 } ); 29225 element.data( 'price-changed', 1 ); 29226 } 29227 } ); 29228 } 29229 29230 function tm_epo_rules( epoObject, theCart ) { 29231 var all_carts; 29232 var variation_id_selector; 29233 var per_product_pricing = true; 29234 var current_variation; 29235 var bundleid; 29236 var epoContainer; 29237 var epoTotalsContainer; 29238 var apply_dpd; 29239 var rules; 29240 var original_rules; 29241 var price; 29242 var original_price; 29243 var product_price; 29244 var product_original_price; 29245 var all_fields; 29246 var active_fields; 29247 var args; 29248 var main_product = epoObject.main_product; 29249 var epoEventId = epoObject.epoEventId; 29250 var this_epo_container = epoObject.this_epo_container; 29251 var this_epo_totals_container = epoObject.this_epo_totals_container; 29252 29253 if ( ! theCart ) { 29254 all_carts = main_product.find( '.cart' ); 29255 } else { 29256 all_carts = theCart; 29257 } 29258 if ( all_carts.length <= 0 ) { 29259 return; 29260 } 29261 29262 $.tcepo.lateFieldsPrices[ epoEventId ] = []; 29263 29264 all_carts.toArray().forEach( function( cart ) { 29265 cart = $( cart ); 29266 variation_id_selector = "input[name^='variation_id']"; 29267 if ( cart.find( 'input.variation_id' ).length > 0 ) { 29268 variation_id_selector = 'input.variation_id'; 29269 } 29270 29271 if ( cart.data( 'per_product_pricing' ) !== undefined ) { 29272 per_product_pricing = cart.data( 'per_product_pricing' ); 29273 } 29274 29275 current_variation = cart.find( variation_id_selector ).val(); 29276 bundleid = $.epoAPI.applyFilter( 'tc_get_bundleid', cart.attr( 'data-product_id' ), cart, epoObject ); 29277 29278 // get current woocommerce variation 29279 if ( ! current_variation ) { 29280 current_variation = 0; 29281 } 29282 29283 epoContainer = $.epoAPI.applyFilter( 'tc_get_epo_container', this_epo_container, cart, main_product, bundleid ); 29284 epoTotalsContainer = $.epoAPI.applyFilter( 'tc_get_totals_container', this_epo_totals_container, cart, main_product, bundleid ); 29285 29286 // WooCommerce Dynamic Pricing & Discounts 29287 apply_dpd = epoTotalsContainer.data( 'fields-price-rules' ); 29288 29289 // set initial prices for all fields 29290 if ( ! epoContainer.data( 'tm_rules_init_done' ) ) { 29291 if ( epoTotalsContainer.data( 'force-quantity' ) ) { 29292 cart.find( tcAPI.qtySelector ).val( epoTotalsContainer.data( 'force-quantity' ) ); 29293 } 29294 epoContainer.toArray().forEach( function( el ) { 29295 $( el ).closest( '.tmcp-field-wrap' ).find( '.tm-epo-field' ).data( 'tm-quantity', $( el ).val() ); 29296 } ); 29297 29298 epoContainer 29299 .find( '.tmcp-attributes, .tmcp-elements' ) 29300 .toArray() 29301 .forEach( function( element ) { 29302 element = $( element ); 29303 rules = $.epoAPI.util.parseJSON( element.attr( 'data-rules' ) ); 29304 original_rules = $.epoAPI.util.parseJSON( element.attr( 'data-original-rules' ) ); 29305 29306 // if rule doesn't exit then init an empty rule 29307 if ( typeof rules !== 'object' ) { 29308 rules = { 29309 0: '0' 29310 }; 29311 } 29312 if ( typeof original_rules !== 'object' ) { 29313 original_rules = { 29314 0: '0' 29315 }; 29316 } 29317 if ( typeof rules === 'object' ) { 29318 // we skip price validation test so that every field has at least a price of 0 29319 price = tm_apply_dpd( rules[ $.epoAPI.math.toFloat( current_variation ) ], epoTotalsContainer, apply_dpd ); 29320 original_price = tm_apply_dpd( original_rules[ $.epoAPI.math.toFloat( current_variation ) ], epoTotalsContainer, apply_dpd ); 29321 29322 element 29323 .find( '.tmcp-field, .tmcp-fee-field ' ) 29324 .toArray() 29325 .forEach( function( el ) { 29326 el = $( el ); 29327 if ( per_product_pricing ) { 29328 if ( el.attr( 'data-no-price' ) === '1' ) { 29329 price = 0; 29330 original_price = 0; 29331 } 29332 el.data( 'raw_price', price ); 29333 el.data( 'raw_original_price', original_price ); 29334 29335 el.data( 'price', tm_set_tax_price( price, epoTotalsContainer, el ) ); 29336 el.data( 'original_price', tm_set_tax_price( original_price, epoTotalsContainer, el ) ); 29337 29338 tm_update_price( { 29339 epoObject: epoObject, 29340 obj: el.closest( '.tmcp-field-wrap' ).find( '.tc-price' ), 29341 price: tm_get_price( price, epoTotalsContainer ), 29342 original_price: tm_get_price( original_price, epoTotalsContainer ), 29343 force: false, 29344 useFormattedPrice: false 29345 } ); 29346 } else { 29347 el.data( 'price', 0 ); 29348 el.data( 'original_price', 0 ); 29349 el.closest( '.tmcp-field-wrap' ).find( '.amount' ).empty(); 29350 } 29351 } ); 29352 } 29353 } ); 29354 epoContainer.data( 'tm_rules_init_done', 1 ); 29355 } 29356 29357 // skip specific field rules if per_product_pricing is false 29358 if ( ! per_product_pricing ) { 29359 return true; 29360 } 29361 29362 product_price = tm_calculate_product_price( epoTotalsContainer ); 29363 product_original_price = tm_calculate_product_regular_price( epoTotalsContainer ); 29364 29365 args = { 29366 cart: cart, 29367 current_variation: current_variation, 29368 bundleid: bundleid, 29369 epoTotalsContainer: epoTotalsContainer, 29370 product_price: product_price, 29371 product_original_price: product_original_price, 29372 apply_dpd: apply_dpd, 29373 per_product_pricing: per_product_pricing 29374 }; 29375 29376 all_fields = epoContainer.find( '.tmcp-field,.tmcp-sub-fee-field,.tmcp-fee-field' ); 29377 if ( ! epoObject.is_associated ) { 29378 all_fields = all_fields.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-field,' + tcAPI.associatedEpoSelector + ' ' + '.tmcp-sub-fee-field,' + tcAPI.associatedEpoSelector + ' ' + '.tmcp-fee-field' ); 29379 } 29380 active_fields = all_fields.filter( '.tcenabled' ); 29381 29382 // note: find a better way if any 29383 if ( ! $.tcepo.initialActivation[ epoEventId ] || ( active_fields.length === 0 && all_fields.length > 0 ) ) {
29384 all_fields.toArray().forEach( function( el ) { 29385 field_is_active( $( el ) ); 29386 } ); 29387 epoContainer.find( '.cpf-type-divider,.cpf-type-header' ).toArray().forEach( function( el ) { 29388 field_is_active( $( el ) ); 29389 } ); 29390 29391 $.tcepo.initialActivation[ epoEventId ] = true; 29392 } 29393 29394 // apply specific field rules 29395 all_fields.filter( '.tcenabled' ).toArray().forEach( function( element ) { 29396 tm_element_epo_rules( epoObject, element, args ); 29397 } ); 29398 29399 all_fields.toArray().forEach( function( element ) { 29400 $( element ).on( 'tc_element_epo_rules', function() { 29401 tm_element_epo_rules( epoObject, element, args ); 29402 } ); 29403 } ); 29404 } ); 29405 } 29406 29407 function add_late_fields_prices( epoObject, currentProductPrice, originalProductPrice, options_total, original_options_total, bid, _cart, applydpd ) { 29408 var total = 0; 29409 var originalTotal = 0; 29410 var totalFees = 0; 29411 var originalTotalFees = 0; 29412 var price; 29413 var originalPrice; 29414 var priceType; 29415 var setter; 29416 var id; 29417 var hidden; 29418 var bundleid; 29419 var realSetter; 29420 var productId; 29421 var epoId; 29422 var epoEventId = epoObject.epoEventId; 29423 var taxPrice; 29424 var taxOriginalPrice; 29425 var hiddenName; 29426 var productPrice; 29427 var oProductPrice; 29428 var apply_dpd; 29429 29430 if ( applydpd !== undefined ) { 29431 apply_dpd = applydpd; 29432 } else { 29433 apply_dpd = epoObject.this_epo_totals_container.data( 'fields-price-rules' ); 29434 } 29435 productPrice = currentProductPrice; 29436 oProductPrice = originalProductPrice; 29437 29438 $.tcepo.lateFieldsPrices[ epoEventId ].forEach( function( field ) { 29439 price = field.price; 29440 originalPrice = field.original_price; 29441 priceType = field.pricetype; 29442 setter = field.setter; 29443 bundleid = field.bundleid; 29444 realSetter = setter; 29445 29446 if ( priceType === 'percentcurrenttotal' ) { 29447 hiddenName = '_hidden'; 29448 } else { 29449 hiddenName = '_hiddenfixed'; 29450 } 29451 29452 if ( setter.is( 'option' ) ) { 29453 realSetter = setter.closest( 'select' ); 29454 } 29455 29456 productPrice = parseFloat( $.epoAPI.applyFilter( 'tc_alter_product_price', productPrice, realSetter, _cart, epoObject.this_epo_totals_container, bid ) ); 29457 oProductPrice = parseFloat( $.epoAPI.applyFilter( 'tc_alter_original_product_price', oProductPrice, realSetter, _cart, epoObject.this_epo_totals_container, bid ) ); 29458 29459 id = $.epoAPI.dom.id( realSetter.attr( 'name' ) ); 29460 productId = $( '.tc-totals-form.tm-totals-form-' + _cart.attr( 'data-cart-id' ) ).attr( 'data-product-id' ); 29461 epoId = $( '.tc-totals-form.tm-totals-form-' + _cart.attr( 'data-cart-id' ) ).attr( 'data-epo-id' ); 29462 //workaround to support composite products 29463 hidden = $( tcAPI.epoSelector + '.tm-product-id-' + productId + "[data-epo-id='" + epoId + "']" ).find( '#' + id + hiddenName ); 29464 29465 if ( bundleid === bid ) { 29466 if ( priceType === 'percentcurrenttotal' ) { 29467 price = ( parseFloat( price ) / 100 ) * ( tm_apply_dpd( parseFloat( productPrice ), epoObject.this_epo_totals_container, apply_dpd ) + parseFloat( options_total ) ); 29468 originalPrice = ( parseFloat( originalPrice ) / 100 ) * ( parseFloat( oProductPrice ) + parseFloat( original_options_total ) ); 29469 } else if ( priceType === 'fixedcurrenttotal' ) { 29470 price = parseFloat( price ) + parseFloat( options_total ); 29471 originalPrice = parseFloat( originalPrice ) + parseFloat( original_options_total ); 29472 } 29473 if ( realSetter.data( 'tm-quantity' ) ) { 29474 price = price * parseFloat( realSetter.data( 'tm-quantity' ) ); 29475 originalPrice = originalPrice * parseFloat( realSetter.data( 'tm-quantity' ) ); 29476 } 29477 29478 if ( setter.data( 'isset' ) === 1 && field_is_active( setter ) ) { 29479 if ( realSetter.is( '.tmcp-field' ) ) { 29480 total = total + price; 29481 originalTotal = originalTotal + originalPrice; 29482 } else if ( realSetter.is( '.tmcp-fee-field' ) ) { 29483 totalFees = totalFees + price; 29484 originalTotalFees = originalTotalFees + originalPrice; 29485 } 29486 } 29487 29488 taxPrice = tm_set_tax_price( price, _cart, setter ); 29489 taxOriginalPrice = tm_set_tax_price( originalPrice, _cart, setter ); 29490 29491 setter.data( 'price', taxPrice ); 29492 setter.data( 'pricew', taxPrice ); 29493 setter.data( 'original_price', taxOriginalPrice ); 29494 setter.data( 'original_pricew', taxOriginalPrice ); 29495 29496 tm_update_price( { 29497 epoObject: epoObject, 29498 obj: setter.closest( '.tmcp-field-wrap' ).find( '.tc-price' ), 29499 price: tm_get_price( taxPrice, _cart, false, setter ), 29500 original_price: tm_get_price( taxOriginalPrice, _cart, false, setter ), 29501 force: false, 29502 useFormattedPrice: false 29503 } ); 29504 29505 if ( hidden.length === 0 ) { 29506 realSetter.before( '<input type="hidden" id="' + id + hiddenName + '" name="' + id + hiddenName + '" value="' + tm_set_price_without_tax( price, _cart ) + '">' ); 29507 } 29508 if ( setter.is( '.tm-epo-field.tmcp-radio' ) || setter.is( '.tm-epo-field.tmcp-checkbox' ) ) { 29509 if ( setter.is( ':checked' ) ) { 29510 hidden.val( tm_set_price_without_tax( price, _cart ) ); 29511 } 29512 } else { 29513 hidden.val( tm_set_price_without_tax( price, _cart ) ); 29514 } 29515 } else if ( setter.data( 'pricew' ) !== undefined ) { 29516 // Prices are already taxed 29517 tm_update_price( { 29518 epoObject: epoObject, 29519 obj: setter.closest( '.tmcp-field-wrap' ).find( '.tc-price' ), 29520 price: setter.data( 'pricew' ), 29521 original_price: ( setter.data( 'original_pricew' ) !== undefined ? setter.data( 'original_pricew' ) : setter.data( 'pricew' ) ), 29522 force: false, 29523 useFormattedPrice: false 29524 } ); 29525 } 29526 } ); 29527 29528 return { 29529 normal: [ total, originalTotal ], 29530 fees: [ totalFees, originalTotalFees ] 29531 }; 29532 } 29533 29534 function tm_lazyload() { 29535 var container; 29536 29537 if ( TMEPOJS.tm_epo_no_lazy_load === 'yes' ) { 29538 return; 29539 } 29540 29541 if ( tmLazyloadContainer ) { 29542 container = $( tmLazyloadContainer ).find( 'img.tmlazy' ); 29543 } else {
29544 container = $( tcAPI.epoSelector + ' img.tmlazy, .tc-styled-variations img.tmlazy' ); 29545 } 29546 29547 container.lazyLoadXT(); 29548 container.on( 'lazyshow', function() { 29549 jWindow.trigger( 'lazyLoadXToncomplete' ); 29550 } ); 29551 } 29552 29553 function tm_css_styles( obj ) { 29554 var $cart; 29555 var sliderSection; 29556 29557 if ( ! obj ) { 29558 return; 29559 } 29560 29561 $cart = $( '.cart' ); 29562 29563 sliderSection = obj.find( '.tm-owl-slider-section' ); 29564 if ( ! sliderSection.length ) { 29565 sliderSection = obj; 29566 if ( ! sliderSection.is( '.tc-repeater-section' ) ) { 29567 sliderSection = false; 29568 } 29569 } 29570 29571 if ( sliderSection ) { 29572 sliderSection.toArray().forEach( function( slider ) { 29573 slider = $( slider ); 29574 29575 slider.find( '.tc-slider-content' ).addClass( 'tm-owl-slider' ); 29576 29577 slider = slider.find( '.tm-owl-slider' ); 29578 if ( slider.length ) { 29579 slider 29580 .addClass( 'tcowl-carousel-show' ) 29581 .addClass( 'tcowl-carousel' ) 29582 .on( 'changed.owl.carousel', function() { 29583 $cart.css( 'display', 'block' ).addClass( 'slider-setup' ); 29584 } ) 29585 .tmowlCarousel( Object.assign( { 29586 rtl: TMEPOJS.isRTL === '1', 29587 dots: false, 29588 nav: true, 29589 items: 1, 29590 autoHeight: true, 29591 mouseDrag: false, 29592 touchDrag: true, 29593 navText: [ TMEPOJS.i18n_prev_text, TMEPOJS.i18n_next_text ], 29594 navClass: [ 'owl-prev button', 'owl-next button' ], 29595 navElement: 'a', 29596 loop: false, 29597 navRewind: false 29598 }, window.tmowlCarouselSettings || {} ) ); 29599 29600 slider.removeClass( 'tcowl-carousel-show' ); 29601 } 29602 } ); 29603 } 29604 29605 if ( $.fn.tcTabs ) { 29606 obj.find( '.tc-tabs' ).tcTabs( { 29607 headers: 'tc-tab-headers', 29608 header: 'tab-header', 29609 dataopenattribute: 'data-tab', 29610 sortabletabs: false 29611 } ); 29612 } 29613 } 29614 29615 function repeaterAdd( el, elementInnerWrap ) { 29616 var cpf = elementInnerWrap.closest( '.cpf-element' ); 29617 var maxRows = cpf.data( 'repeater-max-rows' ); 29618 var minRows = cpf.data( 'repeater-min-rows' ) || 1; 29619 var repeater = elementInnerWrap.find( '.tc-repeater-element' ); 29620 var rows = repeater.length; 29621 var repeaterLast = repeater.last(); 29622 var repeaterLastUL = repeaterLast.find( '.tmcp-ul-wrap' ); 29623 var clone; 29624 var cloneUl; 29625 var index = el.data( 'tc-repeater-init' ); 29626 29627 if ( maxRows ) { 29628 if ( rows >= maxRows ) { 29629 return false; 29630 } 29631 } 29632 29633 if ( rows + 1 >= maxRows && el.is( '.tc-repeater-add' ) ) { 29634 el.closest( '.tc-repeater-wrap' ).addClass( 'tc-hidden' ); 29635 } 29636 29637 if ( repeaterLastUL.is( '.tm-element-ul-date, .tm-element-ul-time' ) ) { 29638 repeaterLastUL.find( '.tm-epo-field' ).tm_datepicker( 'destroy' ); 29639 repeaterLastUL.find( '.tmcp-date-select' ).off(); 29640 } 29641 if ( repeaterLastUL.is( '.tm-element-ul-color' ) ) { 29642 repeaterLastUL.find( '.tm-epo-field' ).spectrum( 'destroy' ); 29643 } 29644 29645 clone = repeaterLast.tcClone( true ); 29646 29647 clone.find( '.tm-epo-field' ).attr( 'id', function( i, value ) { 29648 return value.replace( /\_\d+$/g, '' ) + '_' + index; 29649 } ); 29650 clone.find( '[data-for]' ).attr( 'data-for', function( i, value ) { 29651 return value.replace( /\_\d+$/g, '' ) + '_' + index; 29652 } ); 29653 clone.find( '[for]:not(:has(.tmcp-date-select))' ).attr( 'for', function( i, value ) { 29654 return value.replace( /\_\d+$/g, '' ) + '_' + index; 29655 } ); 29656 clone.find( '[data-field-id]' ).attr( 'data-field-id', function( i, value ) { 29657 return value.replace( /\_\d+$/g, '' ) + '_' + index; 29658 } ); 29659 clone.find( '[data-tm-date]' ).attr( 'data-tm-date', function( i, value ) { 29660 return value.replace( /\_\d+$/g, '' ) + '_' + index; 29661 } ); 29662 clone.find( '.tmcp-date-select' ).attr( 'id', function( i, value ) { 29663 return $( this ).attr( 'data-tm-date' ) + '_' + value.substring( value.lastIndexOf( '_' ) + 1 ); 29664 } ); 29665 clone.find( '[for]:has(.tmcp-date-select)' ).attr( 'for', function( i, value ) { 29666 return $( this ).find( '.tmcp-date-select' ).attr( 'data-tm-date' ) + '_' + value.substring( value.lastIndexOf( '_' ) + 1 ); 29667 } ); 29668 clone.find( '.tm-epo-field' ).attr( 'name', function( i, value ) { 29669 return value.replace( /\[\d+\]/g, '[' + index + ']' ); 29670 } ); 29671 clone.find( '.tm-qty' ).attr( 'name', function( i, value ) { 29672 return value.replace( /\[\d+\]/g, '[' + index + ']' ); 29673 } ); 29674 clone.find( '.tmcp-date-select' ).attr( 'name', function( i, value ) { 29675 return value.replace( /\[\d+\]/g, '[' + index + ']' ); 29676 } ); 29677 29678 cloneUl = clone.find( '.tmcp-ul-wrap' ); 29679 29680 if ( rows >= minRows && elementInnerWrap.find( '.tc-repeater-element' ).length >= 1 ) { 29681 elementInnerWrap.find( '.tc-repeater-delete' ).removeClass( 'tc-hidden' ); 29682 clone.find( '.tc-repeater-delete' ).removeClass( 'tc-hidden' ); 29683 } 29684 29685 if ( cloneUl.is( '.tm-element-ul-checkbox' ) ) { 29686 clone.find( 'li.tmcp-field-wrap' ).removeClass( 'tc-active' ); 29687 clone 29688 .find( '.tm-epo-field.tmcp-checkbox' ) 29689 .prop( 'checked', false ); 29690 clone 29691 .find( '.tm-epo-field.tmcp-checkbox' ) 29692 .filter( function( i, x ) { 29693 return $.inArray( $( x ).val(), el.data( 'repeater-init-value' ) ) !== -1; 29694 } ) 29695 .prop( 'checked', true ) 29696 .closest( 'li.tmcp-field-wrap' ).addClass( 'tc-active' ); 29697 } else if ( cloneUl.is( '.tm-element-ul-radio' ) ) { 29698 clone.find( 'li.tmcp-field-wrap' ).removeClass( 'tc-active' ); 29699 clone 29700 .find( '.tm-epo-field.tmcp-radio' ) 29701 .filter( function( i, x ) { 29702 return $( x ).val() === el.data( 'repeater-init-value' ); 29703 } ) 29704 .prop( 'checked', true ) 29705 .closest( 'li.tmcp-field-wrap' ).addClass( 'tc-active' ); 29706 } else { 29707 clone.find( '.tm-epo-field' ).val( el.data( 'repeater-init-value' ) ); 29708 } 29709 29710 if ( ! cloneUl.is( '.tm-element-ul-checkbox' ) && ! cloneUl.is( '.tm-element-ul-radio' ) ) { 29711 clone.find( '.tm-epo-field' ).val( el.data( 'repeater-init-value' ) ); 29712 } 29713 29714 if ( cloneUl.is( '.tm-element-ul-upload' ) ) { 29715 clone.find( '.tc-upload-preview' ).remove(); 29716 clone.find( '.tm-filename' ).remove(); 29717 } 29718
29719 clone.find( '.tc-element-qty' ).toArray().forEach( function( elc ) { 29720 var qelc = $( elc ); 29721 var defaultValue = qelc.attr( 'data-default-value' ); 29722 qelc.val( defaultValue ).trigger( 'change' ); 29723 } ); 29724 29725 el.data( 'tc-repeater-init', el.data( 'tc-repeater-init' ) + 1 ); 29726 29727 return [ clone, repeaterLast, repeaterLastUL ]; 29728 } 29729 29730 function repeaterAddAfter( epoObject, clone, repeaterLastUL, doevents ) { 29731 var cloneUl = clone.find( '.tmcp-ul-wrap' ); 29732 29733 if ( cloneUl.is( '.tm-element-ul-range' ) ) { 29734 clone.find( '.tm-range-picker' ).removeData( 'tc-picker-init' ).attr( 'class', 'tm-range-picker' ).html( '' ); 29735 setRangePickers( clone ); 29736 } 29737 if ( cloneUl.is( '.tm-element-ul-date, .tm-element-ul-time' ) ) { 29738 tm_set_datepicker( repeaterLastUL ); 29739 tm_set_datepicker( cloneUl ); 29740 } 29741 if ( cloneUl.is( '.tm-element-ul-color' ) ) { 29742 tm_set_color_pickers( repeaterLastUL ); 29743 tm_set_color_pickers( cloneUl ); 29744 } 29745 clone.find( '.tm-tooltip' ).removeData( 'tctooltip' ).removeData( 'tm-has-tm-tip' ); 29746 $.tcToolTip( clone.find( '.tm-tooltip' ) ); 29747 29748 // apply specific field rules 29749 clone.find( '.tm-epo-field' ) 29750 .removeData( 'addedtcEpoBeforeOptionPriceCalculation' ) 29751 .toArray().forEach( function( elc ) { 29752 elc = $( elc ); 29753 field_is_active( elc, false, true ); 29754 if ( elc.is( '.tcenabled' ) ) { 29755 tm_element_epo_rules( epoObject, elc ); 29756 } 29757 elc.on( 'tc_element_epo_rules', function() { 29758 tm_element_epo_rules( epoObject, elc ); 29759 } ); 29760 } ); 29761 if ( ! doevents ) { 29762 return; 29763 } 29764 if ( cloneUl.is( '.tm-element-ul-checkbox' ) ) { 29765 clone 29766 .find( '.tm-epo-field.tmcp-checkbox' ) 29767 .filter( ':checked' ) 29768 .trigger( 'change.cpf' ); 29769 } else if ( cloneUl.is( '.tm-element-ul-radio' ) ) { 29770 clone 29771 .find( '.tm-epo-field.tmcp-radio' ) 29772 .filter( ':checked' ) 29773 .trigger( 'change.cpf' ); 29774 } else { 29775 clone.find( '.tm-epo-field' ).trigger( 'change.cpf' ); 29776 } 29777 } 29778 29779 function repeaterDelete( elementInnerWrap, repeaterElement, repeaterObj, $this ) { 29780 var cpf = elementInnerWrap.closest( '.cpf-element' ); 29781 var minRows = cpf.data( 'repeater-min-rows' ); 29782 var rows = elementInnerWrap.find( '.tc-repeater-element' ).length; 29783 var repeaterElementIndex = repeaterElement.index(); 29784 var message; 29785 29786 if ( minRows ) { 29787 if ( rows <= minRows ) { 29788 if ( $.tc_validator && $this ) { 29789 message = '<div class="tm-error-repeater tm-error tc-cell tcwidth tcwidth-100">' + $.tc_validator.messages.repeaterminrows( minRows ) + '</div>'; 29790 $this.tcToolTip( { tip: message, onetime: true, trigger: true, tipclass: 'tc-error' } ); 29791 } 29792 return false; 29793 } 29794 } 29795 if ( rows === 1 ) { 29796 return; 29797 } 29798 if ( rows === 2 || ( rows - 1 ) <= minRows ) { 29799 elementInnerWrap.find( '.tc-repeater-delete' ).addClass( 'tc-hidden' ); 29800 } 29801 if ( repeaterObj.is( '.tc-repeater-add' ) ) { 29802 repeaterObj.closest( '.tc-repeater-wrap' ).removeClass( 'tc-hidden' ); 29803 } 29804 repeaterElement.remove(); 29805 repeaterObj.data( 'tc-repeater-init', repeaterObj.data( 'tc-repeater-init' ) - 1 ); 29806 if ( repeaterElementIndex + 1 === rows ) { 29807 return; 29808 } 29809 elementInnerWrap.find( '.tc-repeater-element' ) 29810 .toArray() 29811 .forEach( function( clone, index ) { 29812 clone = $( clone ); 29813 clone.find( '.tm-epo-field' ).attr( 'id', function( i, value ) { 29814 return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' ); 29815 } ); 29816 clone.find( '[data-for]' ).attr( 'data-for', function( i, value ) { 29817 return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' ); 29818 } ); 29819 clone.find( '[for]:not(:has(.tmcp-date-select))' ).attr( 'for', function( i, value ) { 29820 return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' ); 29821 } ); 29822 clone.find( '[data-field-id]' ).attr( 'data-field-id', function( i, value ) { 29823 return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' ); 29824 } ); 29825 clone.find( '[data-tm-date]' ).attr( 'data-tm-date', function( i, value ) { 29826 return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' ); 29827 } ); 29828 clone.find( '.tmcp-date-select' ).attr( 'id', function( i, value ) { 29829 return $( this ).attr( 'data-tm-date' ) + '_' + value.substring( value.lastIndexOf( '_' ) + 1 ); 29830 } ); 29831 clone.find( '[for]:has(.tmcp-date-select)' ).attr( 'for', function( i, value ) { 29832 return $( this ).find( '.tmcp-date-select' ).attr( 'data-tm-date' ) + '_' + value.substring( value.lastIndexOf( '_' ) + 1 ); 29833 } ); 29834 clone.find( '.tm-epo-field' ).attr( 'name', function( i, value ) { 29835 return value.replace( /\[\d+\]/g, '[' + index + ']' ); 29836 } ); 29837 clone.find( '.tm-qty' ).attr( 'name', function( i, value ) { 29838 return value.replace( /\[\d+\]/g, '[' + index + ']' ); 29839 } ); 29840 clone.find( '.tmcp-date-select' ).attr( 'name', function( i, value ) { 29841 return value.replace( /\[\d+\]/g, '[' + index + ']' ); 29842 } ); 29843 } ); 29844 } 29845 29846 function repeaterDeleteSection( elementInnerWrap, repeaterElement, repeaterObj, $this ) { 29847 var cpf = elementInnerWrap.closest( '.cpf-section' ); 29848 var minRows = cpf.data( 'repeater-min-rows' ); 29849 var rows = elementInnerWrap.find( '.tc-repeater-section' ).length; 29850 var repeaterElementIndex = repeaterElement.index(); 29851 var message; 29852 29853 if ( minRows ) { 29854 if ( rows <= minRows ) { 29855 if ( $.tc_validator && $this ) { 29856 message = '<div class="tm-error-repeater tm-error tc-cell tcwidth tcwidth-100">' + $.tc_validator.messages.repeaterminrows( minRows ) + '</div>'; 29857 $this.tcToolTip( { tip: message, onetime: true, trigger: true, tipclass: 'tc-error' } ); 29858 } 29859 return false;
29860 } 29861 } 29862 if ( rows === 1 ) { 29863 return; 29864 } 29865 if ( rows === 2 || ( rows - 1 ) <= minRows ) { 29866 elementInnerWrap.find( '.tc-repeater-section-delete' ).addClass( 'tc-hidden' ); 29867 elementInnerWrap.find( '.tc-repeater-section' ).removeClass( 'has-delete' ); 29868 cpf.find( '.tcowl-carousel' ).trigger( 'refresh.owl.carousel' ); 29869 } 29870 if ( repeaterObj.is( '.tc-section-repeater-add' ) ) { 29871 repeaterObj.closest( '.tc-repeater-wrap' ).removeClass( 'tc-hidden' ); 29872 } 29873 repeaterElement.remove(); 29874 repeaterObj.data( 'tc-repeater-init', repeaterObj.data( 'tc-repeater-init' ) - 1 ); 29875 if ( repeaterElementIndex + 1 === rows ) { 29876 return; 29877 } 29878 elementInnerWrap.find( '.tc-repeater-section' ) 29879 .toArray() 29880 .forEach( function( clone, index ) { 29881 clone = $( clone ); 29882 29883 clone.find( '.tm-epo-field' ).attr( 'id', function( i, value ) { 29884 return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' ); 29885 } ); 29886 clone.find( '[data-for]' ).attr( 'data-for', function( i, value ) { 29887 return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' ); 29888 } ); 29889 clone.find( '[for]:not(:has(.tmcp-date-select))' ).attr( 'for', function( i, value ) { 29890 return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' ); 29891 } ); 29892 clone.find( '[data-field-id]' ).attr( 'data-field-id', function( i, value ) { 29893 return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' ); 29894 } ); 29895 clone.find( '[data-tm-date]' ).attr( 'data-tm-date', function( i, value ) { 29896 return value.replace( /\_\d+$/g, '' ) + ( ( index !== 0 ) ? '_' + index : '' ); 29897 } ); 29898 clone.find( '.tmcp-date-select' ).attr( 'id', function( i, value ) { 29899 return $( this ).attr( 'data-tm-date' ) + '_' + value.substring( value.lastIndexOf( '_' ) + 1 ); 29900 } ); 29901 clone.find( '[for]:has(.tmcp-date-select)' ).attr( 'for', function( i, value ) { 29902 return $( this ).find( '.tmcp-date-select' ).attr( 'data-tm-date' ) + '_' + value.substring( value.lastIndexOf( '_' ) + 1 ); 29903 } ); 29904 clone.find( '.tm-epo-field' ).attr( 'name', function( i, value ) { 29905 return value.replace( /\[\d+\]/g, '[' + index + ']' ); 29906 } ); 29907 clone.find( '.tm-qty' ).attr( 'name', function( i, value ) { 29908 return value.replace( /\[\d+\]/g, '[' + index + ']' ); 29909 } ); 29910 clone.find( '.tmcp-date-select' ).attr( 'name', function( i, value ) { 29911 return value.replace( /\[\d+\]/g, '[' + index + ']' ); 29912 } ); 29913 } ); 29914 } 29915 29916 function repeaterAddSection( el, elementInnerWrap ) { 29917 var cpf = elementInnerWrap.closest( '.cpf-section' ); 29918 var maxRows = cpf.data( 'repeater-max-rows' ); 29919 var minRows = cpf.data( 'repeater-min-rows' ) || 1; 29920 var repeater = elementInnerWrap.find( '.tc-repeater-section' ); 29921 var rows = repeater.length; 29922 var repeaterLast = repeater.last(); 29923 var repeaterLastUL = repeaterLast.find( '.tmcp-ul-wrap' ); 29924 var clone; 29925 var cloneUl; 29926 var index = el.data( 'tc-repeater-init' ); 29927 var repeaterInitValue = el.data( 'repeater-init-value' ); 29928 29929 if ( maxRows ) { 29930 if ( rows >= maxRows ) { 29931 return false; 29932 } 29933 } 29934 29935 if ( rows + 1 >= maxRows && el.is( '.tc-repeater-add' ) ) { 29936 el.closest( '.tc-repeater-wrap' ).addClass( 'tc-hidden' ); 29937 } 29938 29939 repeaterLastUL.toArray().forEach( function( field ) { 29940 var rlul = $( field ); 29941 if ( rlul.is( '.tm-element-ul-date, .tm-element-ul-time' ) ) { 29942 rlul.find( '.tm-epo-field' ).tm_datepicker( 'destroy' ); 29943 rlul.find( '.tmcp-date-select' ).off(); 29944 } 29945 if ( rlul.is( '.tm-element-ul-color' ) ) { 29946 rlul.find( '.tm-epo-field' ).spectrum( 'destroy' ); 29947 } 29948 } ); 29949 29950 clone = repeaterLast.tcClone( true ); 29951 29952 clone.find( '.tm-epo-field' ).attr( 'id', function( i, value ) { 29953 return value.replace( /\_\d+$/g, '' ) + '_' + index; 29954 } ); 29955 clone.find( '[data-for]' ).attr( 'data-for', function( i, value ) { 29956 return value.replace( /\_\d+$/g, '' ) + '_' + index; 29957 } ); 29958 clone.find( '[for]:not(:has(.tmcp-date-select))' ).attr( 'for', function( i, value ) { 29959 return value.replace( /\_\d+$/g, '' ) + '_' + index; 29960 } ); 29961 clone.find( '[data-field-id]' ).attr( 'data-field-id', function( i, value ) { 29962 return value.replace( /\_\d+$/g, '' ) + '_' + index; 29963 } ); 29964 clone.find( '[data-tm-date]' ).attr( 'data-tm-date', function( i, value ) { 29965 return value.replace( /\_\d+$/g, '' ) + '_' + index; 29966 } ); 29967 clone.find( '.tmcp-date-select' ).attr( 'id', function( i, value ) { 29968 return $( this ).attr( 'data-tm-date' ) + '_' + value.substring( value.lastIndexOf( '_' ) + 1 ); 29969 } ); 29970 clone.find( '[for]:has(.tmcp-date-select)' ).attr( 'for', function( i, value ) { 29971 return $( this ).find( '.tmcp-date-select' ).attr( 'data-tm-date' ) + '_' + value.substring( value.lastIndexOf( '_' ) + 1 ); 29972 } ); 29973 clone.find( '.tm-epo-field' ).attr( 'name', function( i, value ) { 29974 return value.replace( /\[\d+\]/g, '[' + index + ']' ); 29975 } ); 29976 clone.find( '.tm-qty' ).attr( 'name', function( i, value ) { 29977 return value.replace( /\[\d+\]/g, '[' + index + ']' ); 29978 } ); 29979 clone.find( '.tmcp-date-select' ).attr( 'name', function( i, value ) { 29980 return value.replace( /\[\d+\]/g, '[' + index + ']' ); 29981 } ); 29982 29983 cloneUl = clone.find( '.tmcp-ul-wrap' ); 29984 29985 if ( rows >= minRows && elementInnerWrap.find( '.tc-repeater-section' ).length >= 1 ) { 29986 elementInnerWrap.find( '.tc-repeater-section-delete' ).removeClass( 'tc-hidden' ); 29987 clone.find( '.tc-repeater-section-delete' ).removeClass( 'tc-hidden' ); 29988 repeater.addClass( 'has-delete' ); 29989 clone.addClass( 'has-delete' ); 29990 cpf.find( '.tcowl-carousel' ).trigger( 'refresh.owl.carousel' ); 29991 } 29992
29993 cloneUl.toArray().forEach( function( field ) { 29994 var cUl = $( field ); 29995 if ( cUl.is( '.tm-element-ul-checkbox' ) ) { 29996 cUl.find( 'li.tmcp-field-wrap' ).removeClass( 'tc-active' ); 29997 cUl 29998 .find( '.tm-epo-field.tmcp-checkbox' ) 29999 .prop( 'checked', false ); 30000 cUl 30001 .find( '.tm-epo-field.tmcp-checkbox' ) 30002 .filter( function( i, x ) { 30003 var $field = $( x ); 30004 var fieldId = $field.attr( 'id' ).replace( /_(\d+)$/, '' ); 30005 return $.inArray( $field.val(), repeaterInitValue[ fieldId ] ) !== -1; 30006 } ) 30007 .prop( 'checked', true ) 30008 .closest( 'li.tmcp-field-wrap' ).addClass( 'tc-active' ); 30009 } else if ( cUl.is( '.tm-element-ul-radio' ) ) { 30010 cUl.find( 'li.tmcp-field-wrap' ).removeClass( 'tc-active' ); 30011 cUl 30012 .find( '.tm-epo-field.tmcp-radio' ) 30013 .filter( function( i, x ) { 30014 var $field = $( x ); 30015 var fieldId = $field.attr( 'id' ).replace( /_(\d+)$/, '' ); 30016 return $field.val() === repeaterInitValue[ fieldId ]; 30017 } ) 30018 .prop( 'checked', true ) 30019 .closest( 'li.tmcp-field-wrap' ).addClass( 'tc-active' ); 30020 } else { 30021 cUl.find( '.tm-epo-field' ).each( function() { 30022 var $field = $( this ); 30023 var fieldId = $field.attr( 'id' ).replace( /_(\d+)$/, '' ); 30024 if ( repeaterInitValue.hasOwnProperty( fieldId ) ) { 30025 $field.val( repeaterInitValue[ fieldId ] ); 30026 } 30027 } ); 30028 } 30029 30030 if ( ! cUl.is( '.tm-element-ul-checkbox' ) && ! cUl.is( '.tm-element-ul-radio' ) ) { 30031 cUl.find( '.tm-epo-field' ).each( function() { 30032 var $field = $( this ); 30033 var fieldId = $field.attr( 'id' ).replace( /_(\d+)$/, '' ); 30034 if ( repeaterInitValue.hasOwnProperty( fieldId ) ) { 30035 $field.val( repeaterInitValue[ fieldId ] ); 30036 } 30037 } ); 30038 } 30039 30040 if ( cUl.is( '.tm-element-ul-upload' ) ) { 30041 cUl.find( '.tc-upload-preview' ).remove(); 30042 cUl.find( '.tm-filename' ).remove(); 30043 } 30044 } ); 30045 30046 clone.find( '.tc-element-qty' ).toArray().forEach( function( elc ) { 30047 var qelc = $( elc ); 30048 var defaultValue = qelc.attr( 'data-default-value' ); 30049 qelc.val( defaultValue ).trigger( 'change' ); 30050 } ); 30051 30052 el.data( 'tc-repeater-init', el.data( 'tc-repeater-init' ) + 1 ); 30053 30054 return [ clone, repeaterLast, repeaterLastUL ]; 30055 } 30056 30057 function repeaterAddSectionAfter( epoObject, clone, repeaterLastUL, doevents ) { 30058 var cloneUl = clone.find( '.tmcp-ul-wrap' ); 30059 var doDate; 30060 var doColor; 30061 cloneUl.toArray().forEach( function( field ) { 30062 var cUL = $( field ); 30063 if ( cUL.is( '.tm-element-ul-range' ) ) { 30064 cUL.find( '.tm-range-picker' ).removeData( 'tc-picker-init' ).attr( 'class', 'tm-range-picker' ).html( '' ); 30065 setRangePickers( cUL ); 30066 } 30067 if ( cUL.is( '.tm-element-ul-date, .tm-element-ul-time' ) ) { 30068 doDate = true; 30069 tm_set_datepicker( cUL ); 30070 } 30071 if ( cUL.is( '.tm-element-ul-color' ) ) { 30072 doColor = true; 30073 tm_set_color_pickers( cUL ); 30074 } 30075 if ( doevents ) { 30076 if ( cUL.is( '.tm-element-ul-checkbox' ) ) { 30077 cUL 30078 .find( '.tm-epo-field.tmcp-checkbox' ) 30079 .filter( ':checked' ) 30080 .trigger( 'change.cpf' ); 30081 } else if ( cUL.is( '.tm-element-ul-radio' ) ) { 30082 cUL 30083 .find( '.tm-epo-field.tmcp-radio' ) 30084 .filter( ':checked' ) 30085 .trigger( 'change.cpf' ); 30086 } else { 30087 cUL.find( '.tm-epo-field' ).trigger( 'change.cpf' ); 30088 } 30089 } 30090 } ); 30091 if ( doDate ) { 30092 tm_set_datepicker( repeaterLastUL ); 30093 } 30094 if ( doColor ) { 30095 tm_set_color_pickers( repeaterLastUL ); 30096 } 30097 30098 clone.find( '.tm-tooltip' ).removeData( 'tctooltip' ).removeData( 'tm-has-tm-tip' ); 30099 $.tcToolTip( clone.find( '.tm-tooltip' ) ); 30100 30101 // apply specific field rules 30102 clone.find( '.tm-epo-field' ) 30103 .removeData( 'addedtcEpoBeforeOptionPriceCalculation' ) 30104 .toArray().forEach( function( elc ) { 30105 elc = $( elc ); 30106 field_is_active( elc, false, true ); 30107 if ( elc.is( '.tcenabled' ) ) { 30108 tm_element_epo_rules( epoObject, elc ); 30109 } 30110 elc.on( 'tc_element_epo_rules', function() { 30111 tm_element_epo_rules( epoObject, elc ); 30112 } ); 30113 } ); 30114 clone.find( '.tc-tabs' ).removeData( 'tctabs' ); 30115 clone.find( '.tcowl-carousel' ).removeData( 'owl.carousel' ); 30116 clone.find( '.owl-nav, .owl-dots' ).remove(); 30117 tm_css_styles( clone ); 30118 } 30119 30120 function tm_set_repeaters( obj, epoObject ) { 30121 var currentCart; 30122 var qtyElement; 30123 var quantityRepeaters; 30124 var sectionQuantityRepeaters; 30125 if ( ! obj ) { 30126 return; 30127 } 30128 obj = $( obj ); 30129 30130 if ( obj.length ) { 30131 currentCart = epoObject.main_cart; 30132 qtyElement = getQtyElement( currentCart ); 30133 qtyElement = $.epoAPI.applyFilter( 'qtyElementForRepeaterQuantity', qtyElement, { 30134 epo: epoObject, 30135 currentCart: currentCart, 30136 obj: obj, 30137 qtyElement: qtyElement 30138 } ); 30139 quantityRepeaters = obj.find( '.tc-repeater-quantity' ); 30140 quantityRepeaters 30141 .toArray() 30142 .forEach( function( repeater, qx ) { 30143 var el = $( repeater ); 30144 var tmEpoField; 30145 var repeaterElement; 30146 var length; 30147 var elementInnerWrap; 30148 var maxRows = el.data( 'repeater-max-rows' ); 30149 30150 if ( el.data( 'tc-repeater-init' ) ) { 30151 return; 30152 } 30153 repeaterElement = el.find( '.tc-repeater-element' ); 30154 length = repeaterElement.length; 30155 tmEpoField = repeaterElement.first().find( '.tm-epo-field' ); 30156 if ( tmEpoField.is( ':checkbox' ) ) { 30157 el.data( 'repeater-init-value', 30158 tmEpoField.filter( ':checked' ).toArray().map( function( x ) { 30159 return $( x ).val(); 30160 } ) ); 30161 } else if ( tmEpoField.is( ':radio' ) ) { 30162 el.data( 'repeater-init-value', tmEpoField.filter( ':checked' ).val() ); 30163 } else { 30164 el.data( 'repeater-init-value', tmEpoField.val() ); 30165 } 30166 el.data( 'tc-repeater-init', length ); 30167 el.data( 'tc-repeater-name', tmEpoField.attr( 'name' ) ); 30168 30169 if ( qtyElement.length ) { 30170 elementInnerWrap = el.find( '.tc-element-inner-wrap' ); 30171 qtyElement 30172 .off( 'change.r' + qx + 'cpf input.r' + qx + 'cpf' ) 30173 .on( 'change.r' + qx + 'cpf input.r' + qx + 'cpf', function( event ) { 30174 var field = $( this ); 30175 var prevValue = field.data( 'epopreviousvalue' ); 30176 var value = $.epoAPI.applyFilter( 'qtyElementForRepeaterQuantityValue', field.val(), { 30177 epo: epoObject, 30178 currentCart: currentCart, 30179 obj: obj, 30180 qtyElement: qtyElement, 30181 field: field 30182 } ); 30183 var difference = value - prevValue; 30184 var thisRepeaterElement; 30185 var i; 30186 var ele; 30187 var cloned; 30188 var repeaterLastUL; 30189 var fieldprevval; 30190 if ( prevValue === undefined ) { 30191 prevValue = value - 1; 30192 difference = value - prevValue; 30193 } 30194 if ( event.isTrigger !== undefined ) { 30195 prevValue = el.find( '.tc-element-inner-wrap' ).find( '.tc-repeater-element' ).length; 30196 difference = value - prevValue; 30197 } 30198 if ( maxRows && difference > maxRows ) { 30199 difference = maxRows - 1; 30200 } 30201 if ( difference === 0 ) { 30202 return; 30203 } 30204 fieldprevval = $.epoAPI.applyFilter( 'qtyElementForRepeaterQuantity_epopreviousvalue', field.val(), { 30205 epo: epoObject, 30206 currentCart: currentCart, 30207 obj: obj, 30208 qtyElement: qtyElement, 30209 field: field 30210 } ); 30211 if ( fieldprevval <= 0 ) { 30212 fieldprevval = 1; 30213 } 30214 if ( qx === quantityRepeaters.length ) { 30215 field.data( 'epopreviousvalue', fieldprevval ); 30216 } 30217 if ( difference > 0 ) { 30218 thisRepeaterElement = elementInnerWrap.find( '.tc-repeater-element' ).eq( value - 1 ); 30219 if ( thisRepeaterElement.length ) { 30220 return; 30221 } 30222 for ( i = 0; i < difference; i++ ) { 30223 cloned = repeaterAdd( el, elementInnerWrap ); 30224 if ( cloned ) { 30225 if ( ele ) { 30226 ele = ele.add( cloned[ 0 ] ); 30227 } else { 30228 ele = cloned[ 0 ]; 30229 } 30230 if ( i === 0 ) { 30231 repeaterLastUL = cloned[ 2 ]; 30232 } 30233 } 30234 } 30235 if ( ele ) { 30236 ele.appendTo( elementInnerWrap.find( '.tc-element-container' ) ); 30237 repeaterAddAfter( epoObject, ele, repeaterLastUL ); 30238 } 30239 } else { 30240 for ( i = value - difference; i > value; i -= 1 ) { 30241 thisRepeaterElement = elementInnerWrap.find( '.tc-repeater-element' ).eq( i - 1 ); 30242 repeaterDelete( elementInnerWrap, thisRepeaterElement, el ); 30243 } 30244 } 30245 currentCart.trigger( { 30246 type: 'tm-epo-update', 30247 norules: 2 30248 } ); 30249 } ); 30250 qtyElement.data( 'epopreviousvalue', $.epoAPI.applyFilter( 'qtyElementForRepeaterQuantityValue', qtyElement.val(), { 30251 epo: epoObject, 30252 currentCart: currentCart, 30253 obj: obj, 30254 qtyElement: qtyElement, 30255 field: qtyElement 30256 } ) ).trigger( 'change' ); 30257 } 30258 } ); 30259 30260 obj.find( '.tc-repeater-add' ) 30261 .toArray() 30262 .forEach( function( repeater ) { 30263 var el = $( repeater ); 30264 var tmEpoField; 30265 var elementInnerWrap; 30266 var repeaterElement; 30267 var length; 30268 if ( el.data( 'tc-repeater-init' ) ) { 30269 return; 30270 } 30271 elementInnerWrap = el.closest( '.tc-element-inner-wrap' ); 30272 repeaterElement = elementInnerWrap.find( '.tc-repeater-element' ); 30273 length = repeaterElement.length; 30274 tmEpoField = repeaterElement.first().find( '.tm-epo-field' ); 30275 if ( elementInnerWrap.find( '.tc-repeater-element' ).length > 1 ) { 30276 elementInnerWrap.find( '.tc-repeater-delete' ).removeClass( 'tc-hidden' ); 30277 } 30278 if ( tmEpoField.is( ':checkbox' ) ) { 30279 el.data( 'repeater-init-value', 30280 tmEpoField.filter( ':checked' ).toArray().map( function( x ) { 30281 return $( x ).val(); 30282 } ) ); 30283 } else if ( tmEpoField.is( ':radio' ) ) { 30284 el.data( 'repeater-init-value', tmEpoField.filter( ':checked' ).val() ); 30285 } else { 30286 el.data( 'repeater-init-value', tmEpoField.val() ); 30287 } 30288 el.data( 'tc-repeater-init', length ); 30289 el.data( 'tc-repeater-name', tmEpoField.attr( 'name' ) ); 30290 30291 el.on( 'click.repeater', function() { 30292 var ele = repeaterAdd( el, elementInnerWrap ); 30293 if ( ele ) { 30294 ele[ 0 ].appendTo( elementInnerWrap.find( '.tc-element-container' ) ); 30295 repeaterAddAfter( epoObject, ele[ 0 ], ele[ 2 ], true ); 30296 } 30297 } ); 30298 } ); 30299 30300 obj.find( '.tc-repeater-delete .delete' ).on( 'click', function() { 30301 var $this = $( this ); 30302 var elementInnerWrap = $this.closest( '.tc-element-inner-wrap' ); 30303 var repeaterElement = $this.closest( '.tc-repeater-element' ); 30304 repeaterDelete( elementInnerWrap, repeaterElement, elementInnerWrap.find( '.tc-repeater-add' ), $this ); 30305 } ); 30306 30307 obj.find( '.tc-section-repeater-add' ) 30308 .toArray() 30309 .forEach( function( repeater ) { 30310 var el = $( repeater ); 30311 var tmEpoField; 30312 var elementInnerWrap; 30313 var repeaterElement; 30314 var length; 30315 var fieldData = []; 30316 if ( el.data( 'tc-repeater-init' ) ) { 30317 return; 30318 } 30319 elementInnerWrap = el.closest( '.tc-section-inner-wrap' ); 30320 repeaterElement = elementInnerWrap.find( '.tc-repeater-section' ); 30321 length = repeaterElement.length; 30322 tmEpoField = elementInnerWrap.find( '.sections_repeater' ); 30323 if ( elementInnerWrap.find( '.tc-repeater-section' ).length > 1 ) { 30324 elementInnerWrap.find( '.tc-section-repeater-delete' ).removeClass( 'tc-hidden' ); 30325 } 30326 repeaterElement.first().find( '.tm-epo-field' ) 30327 .toArray() 30328 .forEach( function( field ) { 30329 var epofield = $( field ); 30330 var id = epofield.attr( 'id' ); 30331 if ( epofield.is( ':checkbox' ) ) { 30332 fieldData[ id ] = epofield.filter( ':checked' ).toArray().map( function( x ) { 30333 return $( x ).val(); 30334 } ); 30335 } else if ( epofield.is( ':radio' ) ) { 30336 fieldData[ id ] = epofield.filter( ':checked' ).val(); 30337 } else { 30338 fieldData[ id ] = epofield.val(); 30339 } 30340 } ); 30341 el.data( 'repeater-init-value', fieldData ); 30342 30343 el.data( 'tc-repeater-init', length ); 30344 el.data( 'tc-repeater-name', tmEpoField.attr( 'name' ) ); 30345 30346 el.on( 'click.repeater', function() { 30347 var ele = repeaterAddSection( el, elementInnerWrap ); 30348 if ( ele ) { 30349 ele[ 1 ].after( ele[ 0 ] ); 30350 repeaterAddSectionAfter( epoObject, ele[ 0 ], ele[ 2 ], true ); 30351 tmEpoField.val( function( i, currentValue ) { 30352 return currentValue ? parseInt( currentValue, 10 ) + 1 : 2; 30353 } ); 30354 } 30355 } ); 30356 } ); 30357 30358 sectionQuantityRepeaters = obj.find( '.tc-section-repeater-quantity' ); 30359 sectionQuantityRepeaters 30360 .toArray() 30361 .forEach( function( repeater, qx ) { 30362 var el = $( repeater ); 30363 var tmEpoField; 30364 var elementInnerWrap; 30365 var repeaterElement; 30366 var length; 30367 var fieldData = []; 30368 var maxRows = el.closest( '.cpf-section' ).data( 'repeater-max-rows' ); 30369 if ( el.data( 'tc-repeater-init' ) ) { 30370 return; 30371 } 30372 elementInnerWrap = el.find( '.tc-section-inner-wrap' ); 30373 repeaterElement = elementInnerWrap.find( '.tc-repeater-section' ); 30374 length = repeaterElement.length; 30375 tmEpoField = elementInnerWrap.find( '.sections_repeater' ); 30376 repeaterElement.first().find( '.tm-epo-field' ) 30377 .toArray() 30378 .forEach( function( field ) { 30379 var epofield = $( field ); 30380 var id = epofield.attr( 'id' ); 30381 if ( epofield.is( ':checkbox' ) ) { 30382 fieldData[ id ] = epofield.filter( ':checked' ).toArray().map( function( x ) { 30383 return $( x ).val(); 30384 } ); 30385 } else if ( epofield.is( ':radio' ) ) { 30386 fieldData[ id ] = epofield.filter( ':checked' ).val(); 30387 } else { 30388 fieldData[ id ] = epofield.val(); 30389 } 30390 } ); 30391 el.data( 'repeater-init-value', fieldData ); 30392 30393 el.data( 'tc-repeater-init', length ); 30394 el.data( 'tc-repeater-name', tmEpoField.attr( 'name' ) ); 30395 30396 if ( qtyElement.length ) { 30397 qtyElement 30398 .off( 'change.rs' + qx + 'cpf input.rs' + qx + 'cpf' ) 30399 .on( 'change.rs' + qx + 'cpf input.rs' + qx + 'cpf', function( event ) { 30400 var field = $( this ); 30401 var prevValue = field.data( 'epopreviousvalue' + qx ); 30402 var value = $.epoAPI.applyFilter( 'qtyElementForRepeaterQuantityValue', field.val(), { 30403 epo: epoObject, 30404 currentCart: currentCart, 30405 obj: obj, 30406 qtyElement: qtyElement, 30407 field: field 30408 } ); 30409 var difference = value - prevValue; 30410 var thisRepeaterElement; 30411 var i; 30412 var ele; 30413 var cloned; 30414 var repeaterLastUL; 30415 var fieldprevval; 30416 var firstcloned; 30417 if ( prevValue === undefined ) { 30418 prevValue = value - 1; 30419 difference = value - prevValue; 30420 } 30421 if ( event.isTrigger !== undefined ) { 30422 prevValue = el.find( '.tc-section-inner-wrap' ).find( '.tc-repeater-section' ).length; 30423 difference = value - prevValue; 30424 } 30425 if ( maxRows && difference > maxRows ) { 30426 difference = maxRows - 1; 30427 } 30428 if ( difference === 0 ) { 30429 return; 30430 } 30431 fieldprevval = $.epoAPI.applyFilter( 'qtyElementForRepeaterQuantity_epopreviousvalue', field.val(), { 30432 epo: epoObject, 30433 currentCart: currentCart, 30434 obj: obj, 30435 qtyElement: qtyElement, 30436 field: field 30437 } ); 30438 if ( fieldprevval <= 0 ) { 30439 fieldprevval = 1; 30440 } 30441 if ( qx === quantityRepeaters.length ) { 30442 field.data( 'epopreviousvalue' + qx, fieldprevval ); 30443 } 30444 if ( difference > 0 ) { 30445 thisRepeaterElement = elementInnerWrap.find( '.tc-repeater-section' ).eq( value - 1 ); 30446 if ( thisRepeaterElement.length ) { 30447 return; 30448 } 30449 for ( i = 0; i < difference; i++ ) { 30450 cloned = repeaterAddSection( el, elementInnerWrap ); 30451 if ( cloned ) { 30452 if ( ! firstcloned ) { 30453 firstcloned = cloned; 30454 } 30455 if ( ele ) { 30456 ele = ele.add( cloned[ 0 ] ); 30457 } else { 30458 ele = cloned[ 0 ]; 30459 } 30460 if ( i === 0 ) { 30461 repeaterLastUL = cloned[ 2 ]; 30462 } 30463 } 30464 } 30465 if ( ele ) { 30466 tmEpoField.val( function( ii, currentValue ) { 30467 return currentValue ? parseInt( currentValue, 10 ) + parseInt( difference, 10 ) : 2; 30468 } ); 30469 firstcloned[ 1 ].after( ele ); 30470 repeaterAddSectionAfter( epoObject, ele, r
30470epeaterLastUL ); 30471 } 30472 } else { 30473 for ( i = value - difference; i > value; i -= 1 ) { 30474 thisRepeaterElement = elementInnerWrap.find( '.tc-repeater-section' ).eq( i - 1 ); 30475 repeaterDeleteSection( elementInnerWrap, thisRepeaterElement, el ); 30476 } 30477 tmEpoField.val( elementInnerWrap.find( '.tc-repeater-section' ).length ); 30478 } 30479 currentCart.trigger( { 30480 type: 'tm-epo-update', 30481 norules: 2 30482 } ); 30483 } ); 30484 qtyElement.data( 'epopreviousvalue' + qx, $.epoAPI.applyFilter( 'qtyElementForRepeaterQuantityValue', qtyElement.val(), { 30485 epo: epoObject, 30486 currentCart: currentCart, 30487 obj: obj, 30488 qtyElement: qtyElement, 30489 field: qtyElement 30490 } ) ).trigger( 'change' ); 30491 } 30492 } ); 30493 30494 obj.find( '.tc-repeater-section-delete .delete' ).on( 'click', function() { 30495 var $this = $( this ); 30496 var elementInnerWrap = $this.closest( '.tc-section-inner-wrap' ); 30497 var repeaterElement = $this.closest( '.tc-repeater-section' ); 30498 var tmEpoField; 30499 tmEpoField = elementInnerWrap.find( '.sections_repeater' ); 30500 repeaterDeleteSection( elementInnerWrap, repeaterElement, elementInnerWrap.find( '.tc-section-repeater-add' ), $this ); 30501 tmEpoField.val( function( ii, currentValue ) { 30502 return currentValue ? parseInt( currentValue, 10 ) - 1 : 2; 30503 } ); 30504 } ); 30505 } 30506 } 30507 30508 function tm_set_color_pickers( obj ) { 30509 if ( ! obj ) { 30510 return; 30511 } 30512 obj = $( obj ).find( '.tm-color-picker' ); 30513 if ( obj.length ) { 30514 obj.spectrum( { 30515 type: 'color', 30516 theme: 'epo', 30517 showButtons: true, 30518 allowEmpty: true, 30519 showInitial: true, 30520 showInput: true, 30521 clickoutFiresChange: false, 30522 chooseText: TMEPOJS.closeText, 30523 cancelText: TMEPOJS.i18n_cancel, 30524 clearText: '' 30525 } ); 30526 obj.spectrum( 'enable' ); 30527 } 30528 } 30529 30530 function tm_set_lightbox( obj ) { 30531 if ( ! obj ) { 30532 return; 30533 } 30534 if ( $( obj ).length ) { 30535 // document ready 30536 $( function() { 30537 $( obj ).tclightbox(); 30538 } ); 30539 } 30540 } 30541 30542 function has_active_changes_product_image( field ) { 30543 var uic = field.closest( '.tmcp-field-wrap' ).find( 'label img' ); 30544 var src = $( uic ).first().attr( 'data-original' ); 30545 30546 if ( field.is( 'select.tm-product-image' ) ) { 30547 field = field.children( 'option:selected' ); 30548 } 30549 30550 if ( ! src ) { 30551 src = $( uic ).first().attr( 'src' ); 30552 } 30553 if ( ! src ) { 30554 src = field.attr( 'data-image' ); 30555 } 30556 if ( field.attr( 'data-imagep' ) ) { 30557 src = field.attr( 'data-imagep' ); 30558 } 30559 if ( src ) { 30560 return true; 30561 } 30562 30563 return false; 30564 } 30565 30566 function tm_set_upload_fields( epoObject ) { 30567 var field; 30568 var dT; 30569 var name; 30570 var file; 30571 var selector = epoObject.is_associated 30572 ? epoObject.this_epo_container.find( '.tm-epo-field.tmcp-upload' ) 30573 : epoObject.this_epo_container.find( '.tm-epo-field.tmcp-upload' ).not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-epo-field.tmcp-upload' ); 30574 30575 try { 30576 selector 30577 .not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-epo-field.tmcp-upload' ) 30578 .toArray() 30579 .forEach( function( el ) { 30580 var dataFiles; 30581 var dataFilename; 30582 file = []; 30583 field = $( el ); 30584 if ( field.attr( 'data-file' ) === '' ) { 30585 return false; 30586 } 30587 dataFiles = field.attr( 'data-file' ).split( '|' ); 30588 if ( dataFiles.length === 0 ) { 30589 return false; 30590 } 30591 if ( ClipboardEvent || DataTransfer ) { 30592 dT = new ClipboardEvent( '' ).clipboardData || new DataTransfer(); 30593 } 30594 dataFiles.forEach( function( dataFile ) { 30595 dataFilename = $.epoAPI.util.basename( dataFile ); 30596 if ( ClipboardEvent || DataTransfer ) { 30597 dT.items.add( new File( [ dataFile ], dataFilename ) ); 30598 } 30599 file.push( dataFile ); 30600 } ); 30601 if ( dT ) { 30602 el.files = dT.files; 30603 } 30604 file = file.join( '|' ); 30605 name = field.attr( 'name' ); 30606 field.trigger( 'tcupload' ); 30607 field.after( '<input type="hidden" class="tmcp-upload-hidden" name="' + name + '" value="' + file + '">' ); 30608 field.removeAttr( 'data-file' ); 30609 } ); 30610 } catch ( err ) { 30611 window.console.log( err ); 30612 $( '.tm-epo-field.tmcp-upload' ).not( '.tm-multiple-file-upload' ).addClass( 'tc-nodt' ); 30613 errorObject = err; 30614 } 30615 } 30616 30617 function tm_set_upload_rules( epoObject ) { 30618 var epoEventId = epoObject.epoEventId; 30619 var this_epo_container = epoObject.this_epo_container; 30620 30621 if ( TMEPOJS.tm_epo_upload_popup === 'yes' ) { 30622 $.tcepo.formSubmitEvents[ epoEventId ][ $.tcepo.formSubmitEvents[ epoEventId ].length ] = { 30623 trigger: function() { 30624 return true; 30625 }, 30626 on_true: function() { 30627 var upload_fields = this_epo_container.data( 'num_uploads' ); 30628 var thisPopup; 30629 var ajaxSuccessFunc; 30630 if ( upload_fields && Object.keys( upload_fields ).length ) { 30631 thisPopup = $.tcFloatBox( { 30632 fps: 1, 30633 ismodal: true, 30634 width: '50%', 30635 height: '300px', 30636 classname: 'flasho tc-wrapper', 30637 data: $.epoAPI.template.html( tcAPI.templateEngine.tc_upload_messages, { 30638 files: upload_fields, 30639 title: TMEPOJS.i18n_uploading_files, 30640 message: TMEPOJS.i18n_uploading_message 30641 } ) 30642 } ); 30643 ajaxSuccessFunc = function() { 30644 thisPopup.destroy(); 30645 jDocument.off( 'ajaxSuccess', ajaxSuccessFunc ); 30646 }; 30647 jDocument.on( 'ajaxSuccess', ajaxSuccessFunc ); 30648 } 30649 30650 return true; 30651 }, 30652 on_false: function() { 30653 return true; 30654 } 30655 }; 30656 } 30657 } 30658 30659 function tm_set_expanables() { 30660 var obj = $( '.tc-expand' );
30661 obj.toArray().forEach( function( o ) { 30662 var el = $( o ); 30663 var max = parseInt( el.attr( 'data-max-items' ), 10 ); 30664 var ul = el.find( '.tmcp-ul-wrap' ); 30665 var gap = ul.css( 'gap' ) || ul.css( 'row-gap' ); 30666 var lis = ul.find( '> li' ); 30667 var lisMax = lis.slice( 0, max ); 30668 var height; 30669 var totalHeight; 30670 if ( lisMax.length ) { 30671 totalHeight = lis.toArray() 30672 .reduce( function( sum, element ) { 30673 return sum + $( element ).outerHeight( true ); 30674 }, 0 ); 30675 totalHeight = 'calc(100px + ' + totalHeight + 'px + (' + gap + ' * (' + max + ' - 1) ) )'; 30676 height = lisMax.toArray() 30677 .reduce( function( sum, element ) { 30678 return sum + $( element ).outerHeight( true ); 30679 }, 0 ); 30680 height = 'calc(' + height + 'px + (' + gap + ' * (' + max + ' - 1) ) )'; 30681 ul.css( 'max-height', height ); 30682 ul.after( $( '<button type="button" data-height="' + height + '" data-total-height="' + totalHeight + '" class="button load-more-button">Load more</button>' ) ); 30683 } 30684 } ); 30685 jDocument.on( 'click.txexpand', '.load-more-button', function() { 30686 var b = $( this ); 30687 var h; 30688 if ( b.is( '.expanded' ) ) { 30689 b.removeClass( 'expanded' ); 30690 } else { 30691 b.addClass( 'expanded' ); 30692 } 30693 h = b.is( '.expanded' ) ? $( this ).attr( 'data-total-height' ) : $( this ).attr( 'data-height' ); 30694 b.prev().css( 'max-height', h ); 30695 } ); 30696 } 30697 30698 function tm_set_checkboxes_rules( epoObject ) { 30699 var this_epo_container = epoObject.this_epo_container; 30700 var main_product = epoObject.main_product; 30701 var epoEventId = epoObject.epoEventId; 30702 var limit_cont = this_epo_container.find( '.tm-limit' ); 30703 var exactlimit_cont = this_epo_container.find( '.tm-exactlimit' ); 30704 var minimumlimit_cont = this_epo_container.find( '.tm-minimumlimit' ); 30705 30706 // Limit checkbox selection 30707 this_epo_container.on( 'change.cpflimit', 'input.tm-epo-field.tmcp-checkbox', function() { 30708 var $this = $( this ); 30709 tm_limit_c_selection( $this, true ); 30710 tm_exact_c_selection( $this, true ); 30711 } ); 30712 if ( limit_cont.length ) { 30713 tm_check_limit_cont( limit_cont, main_product, epoEventId ); 30714 } 30715 30716 // Exact value checkbox check (Todo:check for isvisible) 30717 if ( exactlimit_cont.length ) { 30718 tm_check_exactlimit_cont( exactlimit_cont, main_product, epoEventId ); 30719 } 30720 30721 // Minimum number checkbox check (Todo:check for isvisible) 30722 if ( minimumlimit_cont.length ) { 30723 tm_check_minimumlimit_cont( minimumlimit_cont, epoEventId ); 30724 } 30725 } 30726 30727 function tm_theme_specific_actions( epoObject ) { 30728 var this_epo_container = epoObject.this_epo_container; 30729 var theme_name = TMEPOJS.theme_name; 30730 var all_epo_selects; 30731 var blaszok_selects; 30732 30733 if ( theme_name ) { 30734 theme_name = theme_name.toLowerCase(); 30735 all_epo_selects = this_epo_container.find( 'select' ); 30736 30737 switch ( theme_name ) { 30738 case 'flatsome': 30739 case 'flatsome-child': 30740 case 'flatsome child': 30741 all_epo_selects.wrap( '<div class="custom select-wrapper"/>' ); 30742 break; 30743 30744 case 'avada': 30745 case 'avada-child': 30746 case 'avada child': 30747 all_epo_selects.wrap( '<div class="avada-select-parent tm-select-parent"></div>' ); 30748 $( '<div class="select-arrow"></div>' ).appendTo( this_epo_container.find( '.tm-select-parent' ) ); 30749 if ( window.calc_select_arrow_dimensions ) { 30750 window.calc_select_arrow_dimensions(); 30751 jWindow.on( 'tmsectionpoplink cpflogicdone', function() { 30752 window.calc_select_arrow_dimensions(); 30753 } ); 30754 } else if ( window.calcSelectArrowDimensions ) { 30755 window.calcSelectArrowDimensions(); 30756 jWindow.on( 'tmsectionpoplink cpflogicdone', function() { 30757 window.calcSelectArrowDimensions(); 30758 } ); 30759 } 30760 break; 30761 30762 case 'bazar': 30763 case 'bazar-child': 30764 case 'bazar child': 30765 all_epo_selects.wrap( '<div class="tm-select-wrapper select-wrapper"/>' ); 30766 break; 30767 30768 case 'blaszok': 30769 case 'blaszok-child': 30770 case 'blaszok child': 30771 blaszok_selects = function() { 30772 setTimeout( function() { 30773 $( '.tm-extra-product-options select' ) 30774 .not( '.hasCustomSelect' ) 30775 .filter( ':visible' ) 30776 .toArray().forEach( function( el ) { 30777 el = $( el ); 30778 if ( ! el.is( '.mpcthSelect' ) ) { 30779 el.width( el.outerWidth() ); 30780 el.customSelect( { customClass: 'mpcthSelect' } ); 30781 } 30782 } ); 30783 }, 100 ); 30784 }; 30785 jWindow.on( 'cpflogicrun', function() { 30786 blaszok_selects(); 30787 } ); 30788 jWindow.on( 'epo_options_visible', function() { 30789 blaszok_selects(); 30790 } ); 30791 30792 break; 30793
30794 case 'handmade': 30795 case 'handmade child theme': 30796 $( '.tm-owl-slider.tcowl-carousel' ).addClass( 'manual' ); 30797 break; 30798 } 30799 30800 jWindow.trigger( 'tm-theme-specific-actions', { 30801 epo: { 30802 theme_name: theme_name, 30803 all_epo_selects: all_epo_selects 30804 } 30805 } ); 30806 } 30807 30808 // Fix added +/- quantity button on most themes. 30809 jDocument.off( 'click.cpf', '.quantity:not(.buttons_added) .minus, .quantity:not(.buttons_added) .plus' ).on( 'click.cpf', '.quantity:not(.buttons_added) .minus, .quantity:not(.buttons_added) .plus', function() { 30810 $( this ).closest( '.quantity' ).find( tcAPI.qtySelector ).trigger( 'change.cpf' ); 30811 } ); 30812 } 30813 30814 function tm_custom_variations( epoObject, form, item_id, $main_product, $epo_holder ) { 30815 var epoEventId = epoObject.epoEventId; 30816 var variation_id_selector = "input[name^='variation_id']"; 30817 var tm_epo_variation_section; 30818 var li_variations; 30819 var composite_load_test; 30820 var form_event; 30821 var type; 30822 var name; 30823 var selector; 30824 var func; 30825 var i; 30826 var eventName = epoObject.is_associated ? 'tc_variation_form.tmlogic' : 'wc_variation_form.tmlogic'; 30827 var eventNamePrefix = epoObject.is_associated ? 'tc_' : ''; 30828 var variationsForm = epoObject.variations_form; 30829 var variationsTable = epoObject.is_associated ? variationsForm.find( '.tc-epo-element-variations' ) : variationsForm.find( '.variations' ); 30830 var resetSelector = epoObject.is_associated ? '.tc-epo-element-variable-reset-variations' : '.reset_variations'; 30831 30832 variationsForm.attr( 'data-epo_id', epoObject.epo_id ); 30833
30834 if ( form.find( 'input.variation_id' ).length > 0 ) { 30835 variation_id_selector = 'input.variation_id'; 30836 } 30837 if ( $epo_holder.find( '.tm-epo-variation-element' ).length || $epo_holder.data( 'tm-epo-variation-element' ) ) { 30838 tm_epo_variation_section = $epo_holder.find( '.tm-epo-variation-section' ).first(); 30839 tm_epo_variation_section.find( '.cpf-type-variations' ).attr( 'data-epo_id', epoObject.epo_id ).attr( 'data-product_id', variationsForm.attr( 'data-product_id' ) ); 30840 30841 $epo_holder.data( 'tm-epo-variation-element', tm_epo_variation_section.find( '.tm-epo-variation-element' ) ); 30842 30843 if ( item_id && item_id !== 'main' && ! epoObject.is_associated ) { 30844 // on composite 30845 30846 variationsForm = epoObject.form; 30847 variationsTable = variationsForm.find( '.composite_component[data-item_id="' + item_id + '"]' ).find( '.variations' ); 30848 variationsForm.attr( 'data-epo_id', epoObject.epo_id ); 30849 30850 if ( variationsTable.length === 0 ) { 30851 return; 30852 } 30853 30854 li_variations = tm_epo_variation_section.closest( 'li.tm-extra-product-options-field' ); 30855 if ( ! tm_epo_variation_section.is( '.tm-hidden' ) ) { 30856 variationsTable.hide(); 30857 } 30858 30859 variationsTable.after( tm_epo_variation_section.addClass( 'tm-extra-product-options nopadding' ) ); 30860 if ( li_variations.is( ':empty' ) ) { 30861 li_variations.hide(); 30862 } 30863 30864 if ( ! tm_epo_variation_section.is( '.section_popup' ) ) { 30865 tm_epo_variation_section.removeClass( 'tc-cell' ); 30866 tm_epo_variation_section.wrap( "<div class='tc-styled-variations'></div>" ); 30867 } else { 30868 tm_epo_variation_section.wrap( "<div class='tc-styled-variations tc-row'></div>" ); 30869 } 30870 30871 composite_load_test = false; 30872 form.off( eventName ).on( eventName, function() { 30873 composite_load_test = true; 30874 variationsForm.on( 'click.tmlogic', '.reset_variations', function() { 30875 tm_epo_variation_section.find( 'select.tm-epo-variation-element' ).val( '' ).children( 'option' ).prop( 'disabled', false ).show(); 30876 tm_epo_variation_section.find( '.tm-epo-variation-element' ).prop( 'disabled', false ).removeClass( 'tm-disabled' ).prop( 'checked', false ).closest( 'li' ).show(); 30877 jWindow.trigger( 'tmlazy' ); 30878 tm_epo_variation_section.find( '.tm-epo-variation-element' ).trigger( 'tm_trigger_product_image' ); 30879 tm_epo_variation_section.find( 'li' ).removeClass( 'tc-active tm-attribute-disabled' ).css( 'opacity', '' ); 30880 } ); 30881 30882 // Disable option fields that are unavaiable for current set of attributes 30883 form.off( 'woocommerce_update_variation_values_tmlogic' ).on( 'woocommerce_update_variation_values_tmlogic', function() { 30884 tm_custom_variations_update( form, epoObject ); 30885 } ); 30886 for ( i = 0; i < lateVariationEvent.length; i += 1 ) { 30887 form_event = lateVariationEvent[ i ]; 30888 type = typeof form_event; 30889 if ( type === 'object' ) { 30890 name = typeof form_event.name === 'string' || false; 30891 selector = typeof form_event.selector === 'string' || false; 30892 func = typeof form_event.func === 'function' || false; 30893 if ( name && func ) { 30894 if ( selector === "input[name='variation_id']" ) { 30895 selector = variation_id_selector; 30896 } 30897 if ( form_event.selector ) { 30898 form.data( 'tm-styled-variations', 1 ) 30899 .off( eventNamePrefix + form_event.name + i, selector ) 30900 .on( eventNamePrefix + form_event.name + i, selector, form_event.func ); 30901 } else { 30902 form.data( 'tm-styled-variations', 1 ) 30903 .off( eventNamePrefix + form_event.name + i ) 30904 .on( eventNamePrefix + form_event.name + i, form_event.func ); 30905 } 30906 } 30907 } 30908 } 30909 lateVariationEvent = []; 30910 tm_epo_variation_section.find( '.tm-epo-variation-element:not(.tm-hidden .tm-epo-variation-element)' ).last().trigger( 'tm_epo_variation_element_change' ); 30911 } ); 30912 // document ready 30913 $( function() { 30914 if ( composite_load_test === false ) { 30915 form.trigger( eventName ); 30916 } 30917 } ); 30918 } else { 30919 if ( tm_epo_variation_section.length ) { 30920 if ( ! tm_epo_variation_section.is( '.tm-hidden' ) ) { 30921 variationsTable.hide(); 30922 } 30923 30924 li_variations = tm_epo_variation_section.closest( 'li.tm-extra-product-options-field' ); 30925 30926 variationsTable.after( tm_epo_variation_section.addClass( 'tm-extra-product-options nopadding' ) ); 30927 if ( li_variations.is( ':empty' ) ) { 30928 li_variations.hide(); 30929 } 30930 30931 if ( ! tm_epo_variation_section.is( '.section_popup' ) ) { 30932 tm_epo_variation_section.removeClass( 'tc-cell' ); 30933 tm_epo_variation_section.wrap( "<div class='tc-styled-variations'></div>" ); 30934 } else { 30935 tm_epo_variation_section.wrap( "<div class='tc-styled-variations tc-row'></div>" ); 30936 } 30937 30938 variationsForm.off( 'click.tmlogic', resetSelector ).on( 'click.tmlogic', resetSelector, function() { 30939 tm_epo_variation_section.find( 'select.tm-epo-variation-element' ).val( '' ).children( 'option' ).prop( 'disabled', false ).show(); 30940 tm_epo_variation_section.find( '.tm-epo-variation-element' ).prop( 'disabled', false ).removeClass( 'tm-disabled' ).prop( 'checked', false ).closest( 'li' ).show(); 30941 jWindow.trigger( 'tmlazy' ); 30942 tm_epo_variation_section.find( '.tm-epo-variation-element' ).trigger( 'tm_trigger_product_image' ); 30943 tm_epo_variation_section.find( 'li' ).removeClass( 'tc-active tm-attribute-disabled' ).css( 'opacity', '' ); 30944 } ); 30945 } 30946 30947 // Disable option fields that are unavaiable for current set of attributes 30948 variationsForm.off( 'woocommerce_update_variation_values_tmlogic' ).on( 'woocommerce_update_variation_values_tmlogic', function() { 30949 tm_custom_variations_update( variationsForm, epoObject ); 30950 } ); 30951 30952 for ( i = 0; i < lateVariationEvent.length; i += 1 ) { 30953 form_event = lateVariationEvent[ i ]; 30954 type = typeof form_event; 30955 if ( type === 'object' ) { 30956 name = typeof form_event.name === 'string' || false; 30957 selector = typeof form_event.selector === 'string' || false; 30958 func = typeof form_event.func === 'function' || false;
30959 if ( name && func ) { 30960 if ( selector === "input[name='variation_id']" ) { 30961 selector = variation_id_selector; 30962 } 30963 if ( form_event.selector ) { 30964 variationsForm 30965 .data( 'tm-styled-variations', 1 ) 30966 .off( eventNamePrefix + form_event.name + i, selector ) 30967 .on( eventNamePrefix + form_event.name + i, selector, form_event.func ); 30968 } else { 30969 variationsForm 30970 .data( 'tm-styled-variations', 1 ) 30971 .off( eventNamePrefix + form_event.name + i ) 30972 .on( eventNamePrefix + form_event.name + i, form_event.func ); 30973 } 30974 } 30975 } 30976 } 30977 lateVariationEvent = []; 30978 tm_epo_variation_section.find( '.tm-epo-variation-element:not(.tm-hidden .tm-epo-variation-element)' ).last().trigger( 'tm_epo_variation_element_change' ); 30979 } 30980 30981 // global event for custom variations 30982 $.tcepo.formSubmitEvents[ epoEventId ][ $.tcepo.formSubmitEvents[ epoEventId ].length ] = { 30983 trigger: function() { 30984 return true; 30985 }, 30986 on_true: function() { 30987 tm_epo_variation_section.find( '.tm-epo-variation-element' ).attr( 'disabled', 'disabled' ); 30988 return true; 30989 }, 30990 on_false: function() { 30991 tm_epo_variation_section.find( '.tm-epo-variation-element' ).prop( 'disabled', false ); 30992 } 30993 }; 30994 30995 $( document.body ).on( 'added_to_cart', function() { 30996 tm_epo_variation_section.find( '.tm-epo-variation-element' ).prop( 'disabled', false ); 30997 } ); 30998 } 30999 } 31000 31001 function repopulate_backup_image_atts( img, product_element ) { 31002 var $gallery_img = product_element.find( '.flex-control-nav li:eq(0) img' ); 31003 var $gallery_wrapper = product_element.find( '.woocommerce-product-gallery__wrapper ' ); 31004 var $product_img_wrap = $gallery_wrapper.find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ).eq( 0 ); 31005 var $product_img = img; 31006 var $product_link = img.closest( 'a' ); 31007 31008 $product_img.attr( 'data-o_' + 'src', $.tc_product_image_store[ 0 ].src ); 31009 $product_img.attr( 'data-o_' + 'srcset', $.tc_product_image_store[ 0 ].srcset ); 31010 $product_img.attr( 'data-o_' + 'sizes', $.tc_product_image_store[ 0 ].sizes ); 31011 $product_img.attr( 'data-o_' + 'title', $.tc_product_image_store[ 0 ].title ); 31012 $product_img.attr( 'data-o_' + 'alt', $.tc_product_image_store[ 0 ].alt ); 31013 $product_img.attr( 'data-o_' + 'data-src', $.tc_product_image_store[ 0 ][ 'data-src' ] ); 31014 $product_img.attr( 'data-o_' + 'data-large_image', $.tc_product_image_store[ 0 ][ 'data-large_image' ] ); 31015 $product_img.attr( 'data-o_' + 'data-large_image_width', $.tc_product_image_store[ 0 ][ 'data-large_image_width' ] ); 31016 $product_img.attr( 'data-o_' + 'data-large_image_height', $.tc_product_image_store[ 0 ][ 'data-large_image_height' ] ); 31017 $product_img_wrap.attr( 'data-o_' + 'data-thumb', $.tc_product_image_store[ 1 ][ 'data-thumb' ] ); 31018 if ( $.tc_product_image_store[ 2 ] ) { 31019 $gallery_img.attr( 'data-o_' + 'src', $.tc_product_image_store[ 2 ].src ); 31020 } 31021 31022 $product_link.attr( 'data-o_' + 'href', $.tc_product_image_store[ 3 ].href ); 31023 $product_link.attr( 'data-o_' + 'title', $.tc_product_image_store[ 3 ].title ); 31024 } 31025 31026 function reset_saved_image( img, product_element ) { 31027 var $gallery_img = product_element.find( '.flex-control-nav li:eq(0) img' ); 31028 var $gallery_wrapper = product_element.find( '.woocommerce-product-gallery__wrapper ' ); 31029 var $product_img_wrap = $gallery_wrapper.find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ).eq( 0 ); 31030 var $product_img = img; 31031 var $product_link = img.closest( 'a' ); 31032 31033 // backup current product image attributes 31034 if ( ! $.isEmptyObject( $.tc_product_image ) ) { 31035 $.tc_product_image_store = $.tc_pre_populate_store(); 31036 $.tc_product_image_store = $.tc_maybe_copy_object_values( $.tc_product_image_store, $.tc_product_image ); 31037 } else { 31038 $.tc_product_image_store = $.tc_populate_store( img, product_element ); 31039 } 31040 31041 $product_img.tc_update_attr( 'src', 0 ); 31042 $product_img.tc_update_attr( 'srcset', 0 ); 31043 $product_img.tc_update_attr( 'sizes', 0 ); 31044 $product_img.tc_update_attr( 'title', 0 ); 31045 $product_img.tc_update_attr( 'alt', 0 ); 31046 $product_img.tc_update_attr( 'data-src', 0 ); 31047 $product_img.tc_update_attr( 'data-large_image', 0 ); 31048 $product_img.tc_update_attr( 'data-large_image_width', 0 ); 31049 $product_img.tc_update_attr( 'data-large_image_height', 0 ); 31050 $product_img_wrap.tc_update_attr( 'data-thumb', 1 ); 31051 $gallery_img.tc_update_attr( 'src', 2 ); 31052 31053 $product_link.tc_update_attr( 'href', 3 ); 31054 $product_link.tc_update_attr( 'title', 3 ); 31055 } 31056 31057 function image_update( data, img, product_element ) { 31058 var $gallery_img = product_element.find( '.flex-control-nav li:eq(0) img' ); 31059 var $gallery_wrapper = product_element.find( '.woocommerce-product-gallery__wrapper ' ); 31060 var $product_img_wrap = $gallery_wrapper.find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ).eq( 0 ); 31061 var $product_img = img; 31062 var $product_link = img.closest( 'a' ); 31063 var $img_zoom = $product_link.next( '.zoomImg' ); 31064 31065 if ( data && data.image_link && data.image_link && data.image_link.length > 1 ) { 31066 if ( data.full_src === null || data.full_src === '' ) { 31067 data.full_src = data.image_link; 31068 } 31069 if ( data.full_src_w === null || data.full_src_w === '' ) { 31070 data.full_src_w = $product_img.attr( 'data-large_image_width' ); 31071 } 31072 if ( data.full_src_h === null || data.full_src_h === '' ) { 31073 data.full_src_h = $product_img.attr( 'data-large_image_height' ); 31074 } 31075 if ( $product_img.length ) { 31076 if ( ! data.image_srcset ) { 31077 data.image_sizes = false;
31078 } 31079 if ( ! data.image_sizes ) { 31080 data.image_srcset = false; 31081 } 31082 $product_img.tc_set_attr( 'src', data.image_link, 0 ); 31083 $product_img.tc_set_attr( 'srcset', data.image_srcset, 0 ); 31084 $product_img.tc_set_attr( 'sizes', data.image_sizes, 0 ); 31085 $product_img.tc_set_attr( 'title', data.image_title, 0 ); 31086 $product_img.tc_set_attr( 'alt', data.image_alt, 0 ); 31087 $product_img.tc_set_attr( 'data-src', data.full_src, 0 ); 31088 $product_img.tc_set_attr( 'data-large_image', data.full_src, 0 ); 31089 $product_img.tc_set_attr( 'data-large_image_width', data.full_src_w, 0 ); 31090 $product_img.tc_set_attr( 'data-large_image_height', data.full_src_h, 0 ); 31091 $product_img_wrap.tc_set_attr( 'data-thumb', data.image_link, 1 ); 31092 } 31093 if ( $gallery_img.length ) { 31094 $gallery_img.tc_set_attr( 'src', data.image_link, 2 ); 31095 $gallery_img.tc_set_attr( 'srcset', data.image_srcset, 2 ); 31096 $gallery_img.tc_set_attr( 'sizes', data.image_sizes, 2 ); 31097 } 31098 if ( $product_link.length ) { 31099 $product_link.tc_set_attr( 'href', data.full_src, 3 ); 31100 $product_link.tc_set_attr( 'title', data.image_caption, 3 ); 31101 } 31102 if ( $img_zoom.length ) { 31103 $img_zoom.tc_set_attr( 'src', data.full_src, 4 ); 31104 } 31105 } else { 31106 if ( $product_img.length ) { 31107 $product_img.tc_reset_attr( 'src', 0 ); 31108 $product_img.tc_reset_attr( 'srcset', 0 ); 31109 $product_img.tc_reset_attr( 'sizes', 0 ); 31110 $product_img.tc_reset_attr( 'title', 0 ); 31111 $product_img.tc_reset_attr( 'alt', 0 ); 31112 $product_img.tc_reset_attr( 'data-src', 0 ); 31113 $product_img.tc_reset_attr( 'data-large_image', 0 ); 31114 $product_img.tc_reset_attr( 'data-large_image_width', 0 ); 31115 $product_img.tc_reset_attr( 'data-large_image_height', 0 ); 31116 $product_img_wrap.tc_reset_attr( 'data-thumb', 1 ); 31117 } 31118 if ( $gallery_img.length ) { 31119 $gallery_img.tc_reset_attr( 'src', 2 ); 31120 $gallery_img.tc_reset_attr( 'srcset', 2 ); 31121 $gallery_img.tc_reset_attr( 'sizes', 2 ); 31122 } 31123 if ( $product_link.length ) { 31124 $product_link.tc_reset_attr( 'href', 3 ); 31125 $product_link.tc_reset_attr( 'title', 3 ); 31126 } 31127 if ( $img_zoom.length ) { 31128 $img_zoom.tc_reset_attr( 'src', 4 ); 31129 } 31130 } 31131 } 31132 31133 function get_main_product_image( epoObject, product_element ) { 31134 var img; 31135 31136 if ( epoObject.is_associated ) { 31137 img = product_element.find( '.tc-product-image .wp-post-image' ).first(); 31138 } else if ( TMEPOJS.tm_epo_global_product_image_selector !== '' ) { 31139 img = $( TMEPOJS.tm_epo_global_product_image_selector ); 31140 } else { 31141 img = product_element.find( '.woocommerce-product-gallery__image:not(.clone), .woocommerce-product-gallery__image--placeholder:not(.clone)' ).eq( 0 ).find( '.wp-post-image' ).first(); 31142 if ( img.length === 0 ) { 31143 img = product_element.find( 'a.woocommerce-main-image img, img.woocommerce-main-image,a img' ).not( '.thumbnails img,.product_list_widget img' ).first(); 31144 } 31145 if ( img.length === 0 ) { 31146 img = product_element.find( 'img.wp-post-image' ).not( '.thumbnails img,.product_list_widget img' ).first(); 31147 } 31148 if ( img.length === 0 ) { 31149 img = product_element.find( '.elementor-widget-wd_single_product_gallery img.wp-post-image' ).first(); 31150 } 31151 if ( img.length === 0 ) { 31152 img = product_element.find( '.elementor-widget-ae-post-image .wp-post-image' ).first(); 31153 } 31154 if ( img.length === 0 ) { 31155 img = $( '.woocommerce div.product div.images' ).not( '.thumbnails img,.product_list_widget img' ).first(); 31156 } 31157 } 31158 31159 if ( $( img ).length > 1 ) { 31160 img = $( img ).first(); 31161 } 31162 31163 return img; 31164 } 31165 31166 function get_product_element( epoObject ) { 31167 var main_product; 31168 var product_id; 31169 var product_element; 31170 31171 if ( epoObject.is_associated ) { 31172 return epoObject.main_product.closest( '.tc-epo-element-product-container' ); 31173 } 31174 31175 main_product = epoObject.main_product; 31176 product_id = epoObject.product_id; 31177 product_element = main_product.closest( '#product-' + product_id ); 31178 31179 if ( product_element.length <= 0 ) { 31180 product_element = main_product.closest( '.post-' + product_id ); 31181 } 31182 31183 return product_element; 31184 } 31185 31186 function gallery_compatibility_actions( gallery_type, clone_image, preload_img, visible, event_data, $form, product_element ) { 31187 var gallery; 31188 var _elements; 31189 var ge; 31190 var galleryWidth; 31191 var zoomEnabled; 31192 var image; 31193 var zoom_options; 31194 31195 for ( gallery in gallery_type ) { 31196 if ( Object.prototype.hasOwnProperty.call( gallery_type, gallery ) ) { 31197 gallery = gallery_type[ gallery ]; 31198 31199 if ( gallery.enabled ) { 31200 switch ( gallery.type ) { 31201 case 'yith': 31202 if ( ! clone_image ) { 31203 if ( ! visible ) { 31204 gallery.yith_wcmg_zoom.attr( 'href', gallery._yith_wcmg_default_zoom ); 31205 } else { 31206 gallery.yith_wcmg_zoom.attr( 'href', gallery.yith_wcmg_default_zoom ); 31207 } 31208 if ( gallery.element.data( 'yith_magnifier' ) ) { 31209 gallery.element.yith_magnifier( 'destroy' ); 31210 } 31211 31212 gallery.element.yith_magnifier( window.yith_magnifier_options ); 31213 } else { 31214 clone_image.attr( 'srcset', preload_img ).attr( 'src-orig', preload_img ); 31215 31216 if ( gallery.element.data( 'yith_magnifier' ) ) { 31217 gallery.element.yith_magnifier( 'destroy' ); 31218 } 31219 _elements = { 31220 elements: { 31221 zoom: $( '.yith_magnifier_zoom' ), 31222 zoomImage: clone_image,
31223 gallery: $( '.yith_magnifier_gallery li a' ) 31224 } 31225 }; 31226 31227 gallery.element.yith_magnifier( $.extend( true, {}, window.yith_magnifier_options, _elements ) ); 31228 } 31229 break; 31230 case 'iosslider': 31231 setTimeout( 31232 function( g ) { 31233 g.element.iosSlider( 'update' ); 31234 }.bind( null, gallery ), 31235 150 31236 ); 31237 break; 31238 case 'flexslider': 31239 jWindow.trigger( 'resize' ); 31240 break; 31241 case 'elevatezoom': 31242 gallery.element.each( 31243 function( g, j ) { 31244 var elevateZoom = j( this ).data( 'elevateZoom' ); 31245 if ( typeof elevateZoom !== 'undefined' ) { 31246 elevateZoom.swaptheimage( g, g ); 31247 } 31248 }.bind( null, preload_img, $ ) 31249 ); 31250 break; 31251 case 'easyzoom': 31252 gallery.element.swap( null, preload_img ); 31253 break; 31254 case 'easyzoom-flatsome': 31255 gallery.element.swap( preload_img, preload_img ); 31256 break; 31257 case 'woocommerce': 31258 if ( clone_image ) { 31259 gallery.element.flexslider( 0 ); 31260 gallery.element.trigger( 'woocommerce_gallery_reset_slide_position' ); 31261 ge = gallery.element; 31262 window.setTimeout( 31263 function( g, w ) { 31264 g.trigger( 'woocommerce_gallery_init_zoom' ); 31265 w.trigger( 'resize' ); 31266 }.bind( null, ge, jWindow ), 31267 10 31268 ); 31269 } 31270 break; 31271 case 'zoom': 31272 if ( product_element ) { 31273 galleryWidth = product_element.find( '.woocommerce-product-gallery--with-images' ).width(); 31274 zoomEnabled = false; 31275 31276 image = gallery.element.find( 'img.wp-post-image' ); 31277 if ( image.attr( 'data-large_image_width' ) > galleryWidth ) { 31278 zoomEnabled = true; 31279 } 31280 31281 if ( zoomEnabled ) { 31282 zoom_options = { 31283 touch: false 31284 }; 31285 if ( 'ontouchstart' in window ) { 31286 zoom_options.on = 'click'; 31287 } 31288 31289 gallery.element.trigger( 'zoom.destroy' ); 31290 gallery.element.zoom( zoom_options ); 31291 } else { 31292 gallery.element.trigger( 'zoom.destroy' ); 31293 } 31294 } 31295 break; 31296 } 31297 } 31298 } 31299 } 31300 31301 jWindow.trigger( 'tm_gallery_compatibility_actions', { 31302 event_data: event_data, 31303 product_element: product_element, 31304 form: $form 31305 } ); 31306 } 31307 31308 function get_gallery_type( epoObject, img, product_element ) { 31309 // YITH WooCommerce Zoom Magnifier 31310 var is_yith_wcmg; 31311 var yith_wcmg; 31312 var yith_wcmg_zoom; 31313 var yith_wcmg_default_zoom; 31314 var _yith_wcmg_default_zoom; 31315 var yith_wcmg_default_image; 31316 31317 // iosslider - Touch Enabled, Responsive jQuery Horizontal Content 31318 // Slider/Carousel/Image Gallery Plugin 31319 var is_iosSlider; 31320 var is_iosSlider_element; 31321 31322 // ThemeFusion flexslider 31323 var is_flexslider; 31324 var is_flexslider_element; 31325 31326 // elevateZoom A Jquery Image Zoom Plugin 31327 var is_elevateZoom; 31328 var is_elevateZoom_obj; 31329 31330 // EasyZoom jQuery image zoom plugin 31331 var is_easyzoom; 31332 var is_easyzoom_element; 31333 31334 // new flatsome easyzoom 31335 var is_easyzoom_flatsome; 31336 var is_easyzoom_flatsome_element; 31337 31338 // WooCommerce 2.7x gallery 31339 var is_wc27_gallery; 31340 var is_wc27_gallery_element; 31341 var wc27_zoom_target; 31342 var wc_single_product_params; 31343 var zoom_target_temp; 31344 31345 // fn.zoom 31346 var is_zoom_enabled; 31347 var zoom_images; 31348 var gallery; 31349 31350 if ( epoObject.is_associated ) { 31351 return {}; 31352 } 31353 31354 // YITH WooCommerce Zoom Magnifier 31355 is_yith_wcmg = false; 31356 yith_wcmg = $( '.images' ); 31357 yith_wcmg_zoom = $( '.yith_magnifier_zoom' ); 31358 yith_wcmg_default_zoom = yith_wcmg.find( '.yith_magnifier_zoom' ).first().attr( 'href' ); 31359 _yith_wcmg_default_zoom = yith_wcmg_default_zoom; 31360 yith_wcmg_default_image = yith_wcmg.find( '.yith_magnifier_zoom img' ).first().attr( 'src' ); 31361 31362 // iosslider - Touch Enabled, Responsive jQuery Horizontal Content 31363 // Slider/Carousel/Image Gallery Plugin 31364 is_iosSlider = false;
31365 is_iosSlider_element = $( '.iosSlider.product-gallery-slider,.iosSlider.product-slider' ); 31366 31367 // ThemeFusion flexslider 31368 is_flexslider = false; 31369 is_flexslider_element = product_element.find( '.images .fusion-flexslider' ); 31370 31371 // elevateZoom A Jquery Image Zoom Plugin 31372 is_elevateZoom = img.data( 'elevateZoom' ) || false; 31373 is_elevateZoom_obj = product_element.find( 'div.product-images .woocommerce-main-image' ); 31374 31375 // EasyZoom jQuery image zoom plugin 31376 is_easyzoom = false; 31377 is_easyzoom_element = product_element.find( '.images .easyzoom' ); 31378 31379 // new flatsome easyzoom 31380 is_easyzoom_flatsome = false; 31381 is_easyzoom_flatsome_element = product_element.find( '.images .easyzoom' ); 31382 31383 // WooCommerce 2.7x gallery 31384 is_wc27_gallery = false; 31385 is_wc27_gallery_element = product_element.find( '.woocommerce-product-gallery' ); 31386 wc27_zoom_target = false; 31387 wc_single_product_params = window.wc_single_product_params; 31388 31389 // fn.zoom 31390 is_zoom_enabled = typeof $.fn.zoom === 'function' && wc_single_product_params && wc_single_product_params.zoom_enabled; 31391 zoom_images = false; 31392 31393 if ( window.yith_magnifier_options && yith_wcmg.data( 'yith_magnifier' ) ) { 31394 is_yith_wcmg = true; 31395 } 31396 31397 if ( is_iosSlider_element.length && is_iosSlider_element.iosSlider ) { 31398 is_iosSlider = true; 31399 } 31400 31401 if ( is_flexslider_element.length && is_flexslider_element.flexslider ) { 31402 is_flexslider = true; 31403 } 31404 31405 if ( is_easyzoom_element.length && is_easyzoom_element.filter( '.images .easyzoom.first' ).data( 'easyZoom' ) ) { 31406 is_easyzoom_element = is_easyzoom_element.filter( '.images .easyzoom.first' ).data( 'easyZoom' ); 31407 is_easyzoom = true; 31408 } 31409 31410 if ( ! is_easyzoom ) { 31411 is_easyzoom_flatsome_element = product_element.find( '.images .has-image-zoom .slide' ); 31412 if ( is_easyzoom_flatsome_element.length && is_easyzoom_flatsome_element.filter( '.images .has-image-zoom .slide.first' ).data( 'easyZoom' ) ) { 31413 is_easyzoom_flatsome_element = is_easyzoom_flatsome_element.filter( '.images .has-image-zoom .slide.first' ).data( 'easyZoom' ); 31414 is_easyzoom_flatsome = true; 31415 } 31416 } 31417 31418 if ( document.readyState === 'complete' ) { 31419 setTimeout( function() { 31420 if ( is_easyzoom_element.length && is_easyzoom_element.data( 'easyZoom' ) ) { 31421 is_easyzoom_element = is_easyzoom_element.data( 'easyZoom' ); 31422 is_easyzoom = true; 31423 } 31424 if ( is_easyzoom_flatsome_element.length && is_easyzoom_flatsome_element.data( 'easyZoom' ) ) { 31425 is_easyzoom_flatsome_element = is_easyzoom_flatsome_element.data( 'easyZoom' ); 31426 is_easyzoom_flatsome = true; 31427 } 31428 }, 150 ); 31429 } else { 31430 jWindow.on( 'load', function() { 31431 setTimeout( function() { 31432 if ( is_easyzoom_element.length && is_easyzoom_element.data( 'easyZoom' ) ) { 31433 is_easyzoom_element = is_easyzoom_element.data( 'easyZoom' ); 31434 is_easyzoom = true; 31435 } 31436 if ( is_easyzoom_flatsome_element.length && is_easyzoom_flatsome_element.data( 'easyZoom' ) ) { 31437 is_easyzoom_flatsome_element = is_easyzoom_flatsome_element.data( 'easyZoom' ); 31438 is_easyzoom_flatsome = true; 31439 } 31440 }, 150 ); 31441 } ); 31442 } 31443 31444 if ( is_wc27_gallery_element.length && is_wc27_gallery_element.data( 'flexslider' ) ) { 31445 is_wc27_gallery = true; 31446 31447 if ( typeof $.fn.zoom === 'function' && wc_single_product_params && wc_single_product_params.zoom_enabled ) { 31448 zoom_target_temp = img.closest( '.woocommerce-product-gallery__image' ); 31449 // Ommiting the following condition: 31450 // && img.width() > $( '.woocommerce-product-gallery' ).width() 31451 if ( zoom_target_temp.length > 0 ) { 31452 wc27_zoom_target = zoom_target_temp; 31453 img.data.wc27_zoom_target = wc27_zoom_target; 31454 } 31455 } 31456 } 31457 31458 if ( ! is_wc27_gallery && is_zoom_enabled ) { 31459 zoom_images = product_element.find( '.woocommerce-product-gallery .woocommerce-product-gallery__image' ); 31460 } 31461 31462 gallery = { 31463 is_yith_wcmg: { 31464 type: 'yith', 31465 enabled: is_yith_wcmg, 31466 element: yith_wcmg, 31467 yith_wcmg_zoom: yith_wcmg_zoom, 31468 _yith_wcmg_default_zoom: _yith_wcmg_default_zoom, 31469 yith_wcmg_default_image: yith_wcmg_default_image 31470 }, 31471 is_iosSlider: { 31472 type: 'iosslider', 31473 enabled: is_iosSlider, 31474 element: is_iosSlider_element 31475 }, 31476 is_flexslider: { 31477 type: 'flexslider', 31478 enabled: is_flexslider, 31479 element: is_flexslider_element 31480 }, 31481 is_elevateZoom: { 31482 type: 'elevatezoom', 31483 enabled: is_elevateZoom, 31484 element: is_elevateZoom_obj 31485 }, 31486 is_easyzoom: { 31487 type: 'easyzoom', 31488 enabled: is_easyzoom, 31489 element: is_easyzoom_element 31490 }, 31491 is_easyzoom_flatsome: { 31492 type: 'easyzoom-flatsome', 31493 enabled: is_easyzoom_flatsome, 31494 element: is_easyzoom_flatsome_element 31495 }, 31496 is_wc27_gallery: { 31497 type: 'woocommerce', 31498 enabled: is_wc27_gallery, 31499 element: is_wc27_gallery_element 31500 }, 31501 is_zoom_enabled: { 31502 type: 'zoom', 31503 enabled: ! is_wc27_gallery && is_zoom_enabled, 31504 element: zoom_images 31505 } 31506 }; 31507 31508 return gallery; 31509 } 31510 31511 function tm_product_image_self( epoObject ) { 31512 var this_epo_container = epoObject.is_associated ? epoObject.this_epo_container : epoObject.this_epo_container.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector ); 31513 var variationsForm = epoObject.variations_form; 31514 var main_product = epoObject.main_product; 31515 var $form = epoObject.form; 31516 var img; 31517 var gallery_type;
31518 var product_element = get_product_element( epoObject ); 31519 var last_active_field = []; 31520 var el; 31521 var el_current; 31522 var imp; 31523 var selector; 31524 var eventNamePrefix = epoObject.is_associated ? 'tc_' : ''; 31525 // This currently has a limitation that it doesn't work if there is variation active onload. 31526 var main_tc_product_image_store; 31527 31528 img = get_main_product_image( epoObject, product_element ); 31529 gallery_type = get_gallery_type( epoObject, img, product_element ); 31530 31531 if ( $( img ).length > 0 ) { 31532 $form.on( eventNamePrefix + 'reset_image.tcpi', function() { 31533 setTimeout( function() { 31534 if ( TMEPOJS.tm_epo_global_image_recalculate === 'yes' ) { 31535 img = get_main_product_image( epoObject, product_element ); 31536 $.tc_product_image_store = main_tc_product_image_store; 31537 } 31538 // restore product image atts from backup 31539 $.tc_product_image = $.tc_replace_object_values( $.tc_product_image, $.tc_product_image_store ); 31540 31541 last_active_field = []; 31542 31543 $( this_epo_container.find( '.tm-product-image:checked,select.tm-product-image' ) ) 31544 .add( variationsForm.find( '.tm-epo-variation-section' ).first().find( '.tm-product-image:checked,select.tm-product-image' ) ) 31545 .toArray().forEach( function( pi ) { 31546 pi = $( pi ); 31547 if ( field_is_active( pi ) && pi.val() !== '' ) { 31548 last_active_field.push( pi ); 31549 } 31550 } ); 31551 if ( last_active_field.length ) { 31552 last_active_field[ last_active_field.length - 1 ].trigger( 'tm_trigger_product_image' ); 31553 } else { 31554 $.tc_product_image_store = $.tc_populate_store( img, product_element ); 31555 } 31556 }, window.tc_epo_product_image_change_delay || 0 ); 31557 } ); 31558
31559 $form.on( eventNamePrefix + 'found_variation.tcpi', function() { 31560 setTimeout( function() { 31561 if ( TMEPOJS.tm_epo_global_image_recalculate === 'yes' ) { 31562 img = get_main_product_image( epoObject, product_element ); 31563 } 31564 reset_saved_image( img, product_element ); 31565 31566 last_active_field = []; 31567 $( this_epo_container.find( '.tm-product-image:checked,select.tm-product-image' ) ) 31568 .add( variationsForm.find( '.tm-epo-variation-section' ).first().find( '.tm-product-image:checked,select.tm-product-image' ) ) 31569 .toArray().forEach( function( pi ) { 31570 pi = $( pi ); 31571 if ( field_is_active( pi ) && pi.val() !== '' ) { 31572 last_active_field.push( pi ); 31573 } 31574 } ); 31575 if ( last_active_field.length ) { 31576 repopulate_backup_image_atts( img, product_element ); 31577 last_active_field[ last_active_field.length - 1 ].trigger( 'tm_trigger_product_image' ); 31578 } 31579 }, window.tc_epo_product_image_change_delay || 0 ); 31580 } ); 31581 31582 $.tc_product_image_store = $.tc_maybe_copy_object_values_from_img( $.tc_product_image_store, img, product_element ); 31583 main_tc_product_image_store = $.epoAPI.util.deepCopyArray( $.tc_product_image_store ); 31584 31585 main_product.off( 'tm_change_product_image' ).on( 'tm_change_product_image', function( evt, event_data ) { 31586 var data; 31587 evt.stopImmediatePropagation(); 31588 31589 el = event_data.element; 31590 el_current = event_data.element_current; 31591 if ( el && el_current ) { 31592 imp = el.data( 'imagep' ); 31593 selector = ''; 31594 if ( imp !== '' ) { 31595 selector = 'imagep'; 31596 } else if ( el.data( 'changes-product-image' ) === 'images' ) { 31597 selector = 'image'; 31598 } 31599 data = event_data.element_current.data( 'image-variations' ); 31600 31601 if ( data ) { 31602 data = data[ selector ]; 31603 } 31604 31605 if ( data === undefined ) { 31606 // Enter the following if you want to restore the original product image 31607 // main_product.trigger( 'tm_restore_product_image', event_data ); 31608 return; 31609 } 31610 31611 last_active_field = []; 31612 $( this_epo_container.find( '.tm-product-image:checked,select.tm-product-image' ) ) 31613 .add( variationsForm.find( '.tm-epo-variation-section' ).first().find( '.tm-product-image:checked,select.tm-product-image' ) ) 31614 .toArray().forEach( function( pi ) { 31615 pi = $( pi ); 31616 if ( pi.is( 'option' ) ) { 31617 pi = pi.closest( 'select' ); 31618 } 31619 if ( pi.val() !== '' && field_is_active( pi ) ) { 31620 last_active_field.push( pi ); 31621 } 31622 } ); 31623 31624 if ( last_active_field.length ) { 31625 if ( ! last_active_field[ last_active_field.length - 1 ].is( el ) ) { 31626 return; 31627 } 31628 } 31629 31630 setTimeout( function() { 31631 if ( TMEPOJS.tm_epo_global_image_recalculate === 'yes' ) { 31632 img = get_main_product_image( epoObject, product_element ); 31633 } 31634 image_update( data, img, product_element ); 31635 gallery_compatibility_actions( gallery_type, img, data.image_link, false, event_data, $form, product_element ); 31636 }, window.tc_epo_product_image_change_delay || 0 ); 31637 } 31638 } ); 31639 31640 main_product.off( 'tm_restore_product_image' ).on( 'tm_restore_product_image', function( evt, event_data ) { 31641 evt.stopImmediatePropagation(); 31642 31643 el = event_data ? event_data.element : false; 31644 last_active_field = []; 31645 31646 if ( el ) { 31647 $( this_epo_container.find( '.tm-product-image:checked,select.tm-product-image' ) ) 31648 .add( variationsForm.find( '.tm-epo-variation-section' ).first().find( '.tm-product-image:checked,select.tm-product-image' ) ) 31649 .toArray().forEach( function( pi ) { 31650 pi = $( pi ); 31651 if ( field_is_active( pi ) && pi.val() !== '' ) { 31652 last_active_field.push( pi ); 31653 } 31654 } ); 31655 if ( last_active_field.length ) { 31656 if ( ! last_active_field[ last_active_field.length - 1 ].is( el ) ) { 31657 last_active_field[ last_active_field.length - 1 ].trigger( 'tm_trigger_product_image' ); 31658 return; 31659 } 31660 } 31661 } 31662 31663 setTimeout( function() { 31664 if ( TMEPOJS.tm_epo_global_image_recalculate === 'yes' ) { 31665 img = get_main_product_image( epoObject, product_element ); 31666 } 31667 image_update( false, img, product_element ); 31668 gallery_compatibility_actions( gallery_type, false, img.attr( 'src' ), false, event_data, $form, product_element ); 31669 }, window.tc_epo_product_image_change_delay || 0 ); 31670 } ); 31671 31672 last_active_field = []; 31673 $( this_epo_container.find( '.tm-product-image:checked,select.tm-product-image' ) ) 31674 .add( variationsForm.find( '.tm-epo-variation-section' ).first().find( '.tm-product-image:checked,select.tm-product-image' ) )
31675 .toArray().forEach( function( pi ) { 31676 pi = $( pi ); 31677 if ( field_is_active( pi ) && pi.val() !== '' ) { 31678 last_active_field.push( pi ); 31679 } 31680 } ); 31681 if ( last_active_field.length ) { 31682 last_active_field[ last_active_field.length - 1 ].trigger( 'tm_trigger_product_image' ); 31683 } 31684 } 31685 31686 jWindow.trigger( 'tm_product_image_loaded' ); 31687 } 31688 31689 function tm_product_image_inline( epoObject ) { 31690 var this_epo_container = epoObject.is_associated ? epoObject.this_epo_container : epoObject.this_epo_container.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector ); 31691 var main_product = epoObject.main_product; 31692 var product_id = epoObject.product_id; 31693 var $form = epoObject.form; 31694 var img; 31695 var product_element = get_product_element( epoObject ); 31696 var gallery_type; 31697 var a; 31698 var img_src_original; 31699 var img_width; 31700 var img_height; 31701 var last_active_field = []; 31702 31703 img = get_main_product_image( epoObject, product_element ); 31704 31705 gallery_type = get_gallery_type( epoObject, img, product_element ); 31706 31707 if ( $( img ).length > 0 ) { 31708 img.data( 'tm-current-image', false ); 31709 a = img.closest( 'a' ); 31710 img_src_original = img.attr( 'src' ); 31711 img_width = img.width(); 31712 img_height = img.height(); 31713 31714 main_product.off( 'tm_change_product_image' ).on( 'tm_change_product_image', function( evt, e ) { 31715 setTimeout( function() { 31716 var variation_element_section; 31717 var is_variation_element; 31718 var $this_epo_container; 31719 var tm_last_visible_image_element; 31720 var last_activate_field = []; 31721 var tm_current_image_element_id; 31722 var can_show_image; 31723 var $main_product; 31724 var $current_product_element; 31725 var preload_width; 31726 var preload_height; 31727 var current_cloned_image; 31728 var preloader; 31729 var clone_image; 31730 var preload_img; 31731 var preload_img_onerror; 31732 31733 if ( TMEPOJS.tm_epo_global_image_recalculate === 'yes' ) { 31734 img = get_main_product_image( epoObject, product_element ); 31735 } 31736 31737 variation_element_section = e.element.closest( '.cpf-section' ); 31738 is_variation_element = variation_element_section.is( '.tm-epo-variation-section' ); 31739 $this_epo_container = e.epo_holder; 31740 if ( is_variation_element ) { 31741 $this_epo_container = variation_element_section; 31742 } 31743 tm_last_visible_image_element = $this_epo_container.find( '.tm-product-image:checked,select.tm-product-image' ); 31744 last_activate_field = []; 31745 tm_current_image_element_id = e.element.attr( 'id' ); 31746 can_show_image = true; 31747 $main_product = e.main_product; 31748 $current_product_element = $main_product.closest( '#product-' + product_id ); 31749 preload_width = img_width; 31750 preload_height = img_height; 31751 preloader = $( "<div class='blockUI blockOverlay tm-preloader-img'></div>" ); 31752 31753 if ( $current_product_element.length <= 0 ) { 31754 $current_product_element = $main_product.closest( '.post-' + product_id ); 31755 } 31756 31757 current_cloned_image = $current_product_element.find( '#' + tm_current_image_element_id + '_tmimage' ); 31758 if ( current_cloned_image.length === 0 ) { 31759 current_cloned_image = img; 31760 } 31761 31762 preload_img_onerror = function() { 31763 preloader.remove(); 31764 $form.tc_image_update( false ); 31765 img.data( 'tm-current-image', false ); 31766 $current_product_element.find( '.tm-clone-product-image' ).hide(); 31767 img.show(); 31768 }; 31769 31770 if ( e.src === current_cloned_image.attr( 'src' ) && current_cloned_image.is( ':visible' ) ) { 31771 return; 31772 } 31773 31774 if ( e.src === false ) { 31775 preload_img_onerror(); 31776 return; 31777 } 31778 31779 preloader.css( { 31780 width: preload_width, 31781 height: preload_height 31782 } ); 31783 31784 // Get last active field 31785 tm_last_visible_image_element.toArray().forEach( function( ie ) { 31786 ie = $( ie ); 31787 if ( 31788 field_is_active( ie ) && 31789 has_active_changes_product_image( ie ) && 31790 tm_check_field_match( { 31791 element: ie.closest( '.cpf-element' ), 31792 rule: { 31793 operator: 'isnotempty', 31794 value: '' 31795 }, 31796 type: 'element' 31797 } ) 31798 ) { 31799 last_activate_field.push( ie ); 31800 } 31801 } ); 31802 // Get last active image 31803 if ( last_activate_field.length ) { 31804 tm_last_visible_image_element = last_activate_field[ last_activate_field.length - 1 ]; 31805 } 31806 31807 if ( tm_last_visible_image_element.attr( 'id' ) !== e.element.attr( 'id' ) ) { 31808 can_show_image = false;
31809 } 31810 31811 clone_image = img.tcClone(); 31812 preload_img = new Image(); 31813 clone_image.removeAttr( 'data-o_src' ).removeAttr( 'data-o_title' ).removeAttr( 'data-o_alt' ).removeAttr( 'data-o_srcset' ).removeAttr( 'data-o_sizes' ).removeAttr( 'srcset' ).removeAttr( 'sizes' ); 31814 31815 if ( can_show_image ) { 31816 img.before( preloader ); 31817 } 31818 31819 gallery_type.is_yith_wcmg.yith_wcmg_default_zoom = gallery_type.is_yith_wcmg.element.find( '.yith_magnifier_zoom' ).first().attr( 'href' ); 31820 gallery_type.is_yith_wcmg.yith_wcmg_default_image = gallery_type.is_yith_wcmg.element.find( '.yith_magnifier_zoom img' ).first().attr( 'src' ); 31821 31822 preload_img.onerror = function() { 31823 preload_img_onerror(); 31824 }; 31825 31826 preload_img.onload = function() { 31827 if ( 'naturalHeight' in this ) { 31828 if ( this.naturalHeight + this.naturalWidth === 0 ) { 31829 this.onerror(); 31830 return; 31831 } 31832 } else if ( this.width + this.height === 0 ) { 31833 this.onerror(); 31834 return; 31835 } 31836 $current_product_element.find( '#' + tm_current_image_element_id + '_tmimage' ).remove(); 31837 $current_product_element.find( '.tm-clone-product-image' ).hide(); 31838 clone_image.prop( 'src', preload_img.src ).hide(); 31839 31840 img.hide().after( clone_image ); 31841 31842 clone_image.css( 'opacity', 0 ).show(); 31843 31844 gallery_compatibility_actions( gallery_type, clone_image, preload_img.src ); 31845 31846 preloader.animate( 31847 { 31848 opacity: 0 31849 }, 31850 750, 31851 'easeOutExpo', 31852 function() { 31853 preloader.remove(); 31854 } 31855 ); 31856 clone_image.animate( 31857 { 31858 opacity: 1 31859 }, 31860 window.tc_epo_image_animation_delay || 1500, 31861 'easeOutExpo', 31862 function() {} 31863 ); 31864 31865 jWindow.trigger( 'tm_change_product_image_loaded', { 31866 src: e.src, 31867 element: e.element, 31868 main_product: e.main_product, 31869 epo_holder: e.epo_holder 31870 } ); 31871 }; 31872 31873 clone_image 31874 .attr( 'id', tm_current_image_element_id + '_tmimage' ) 31875 .addClass( 'tm-clone-product-image' ) 31876 .hide(); 31877 31878 if ( clone_image.attr( 'src-orig' ) ) { 31879 clone_image.attr( 'src-orig', e.src ); 31880 } 31881 31882 if ( can_show_image ) { 31883 preload_img.src = e.src; 31884 31885 $form.tc_image_update( e.element, clone_image ); 31886 31887 img.data( 'tm-current-image', tm_current_image_element_id ); 31888 31889 jWindow.trigger( 'tm_change_product_image_show', { 31890 src: e.src, 31891 element: e.element, 31892 main_product: e.main_product, 31893 epo_holder: e.epo_holder 31894 } ); 31895 } else { 31896 clone_image.prop( 'src', e.src ).hide(); 31897 img.after( clone_image ); 31898 } 31899 31900 jWindow.trigger( 'tm_change_product_image_end', { 31901 src: e.src, 31902 element: e.element, 31903 main_product: e.main_product, 31904 epo_holder: e.epo_holder 31905 } ); 31906 }, window.tc_epo_product_image_change_delay || 0 ); 31907 } ); 31908 31909 main_product.off( 'tm_restore_product_image' ).on( 'tm_restore_product_image', function( evt, e ) { 31910 setTimeout( function() { 31911 var tm_current_image_element_id; 31912 var $main_product; 31913 var $current_product_element; 31914 var variation_element_section; 31915 var is_variation_element; 31916 var current_element; 31917 var current_image_replacement; 31918 var found; 31919 var is_it_visible; 31920 var len; 31921 var el_to_check; 31922 var imgSrc; 31923 var $this_epo_container; 31924 var i; 31925 31926 if ( ! e || ! e.element ) { 31927 return false; 31928 } 31929 if ( TMEPOJS.tm_epo_global_image_recalculate === 'yes' ) { 31930 img = get_main_product_image( epoObject, product_element ); 31931 } 31932 31933 jWindow.trigger( 'tm_restore_product_image_pre', { 31934 element: e.element, 31935 main_product: e.main_product, 31936 epo_holder: e.epo_holder 31937 } ); 31938 tm_current_image_element_id = e.element.attr( 'id' ); 31939 $main_product = e.main_product; 31940 $current_product_element = $main_product.closest( '#product-' + product_id ); 31941 variation_element_section = e.element.closest( '.cpf-section' ); 31942 is_variation_element = variation_element_section.is( '.tm-epo-variation-section' ); 31943 found = false; 31944 imgSrc = img_src_original; 31945 $this_epo_container = e.epo_holder; 31946 if ( is_variation_element ) { 31947 $this_epo_container = variation_element_section; 31948 } 31949 31950 if ( $current_product_element.length <= 0 ) { 31951 $current_product_element = $main_product.closest( '.post-' + product_id ); 31952 } 31953 31954 is_it_visible = $current_product_element.find( '#' + tm_current_image_element_id + '_tmimage' ).is( ':visible' ); 31955 31956 $current_product_element.find( '#' + tm_current_image_element_id + '_tmimage' ).remove(); 31957 31958 if ( $current_product_element.find( '.tm-clone-product-image' ).length === 0 ) { 31959 img.show(); 31960 img.data( 'tm-current-image', false ); 31961 $form.tc_image_update( false ); 31962 } else { 31963 if ( ! is_it_visible ) { 31964 jWindow.trigger( 'tm_restore_product_image_loaded_exit', { 31965 element: e.element, 31966 main_product: e.main_product, 31967 epo_holder: e.epo_holder 31968 } ); 31969 return; 31970 } 31971 31972 len = $current_product_element.find( '.tm-clone-product-image' ).length; 31973 tm_current_image_element_id = img.data( 'tm-current-image' ); 31974 31975 for ( i = len - 1; i >= 0; i -= 1 ) { 31976 current_image_replacement = $current_product_element.find( '.tm-clone-product-image' ).eq( i ); 31977 current_element = current_image_replacement.attr( 'id' ).replace( '_tmimage', '' ); 31978 el_to_check = $this_epo_container.find( "[id='" + current_element + "']" ); 31979 31980 if ( el_to_check.is( ':checked' ) && el_to_check.closest( '.cpf-element' ).is( ':visible' ) ) { 31981 $current_product_element.find( '.tm-clone-product-image' ).eq( i ).show(); 31982 a.attr( 'href', $current_product_element.find( '.tm-clone-product-image' ).eq( i ).prop( 'src' ) ); 31983 img.data( 'tm-current-image', current_element ); 31984 found = true; 31985 break; 31986 } else { 31987 $current_product_element.find( '.tm-clone-product-image' ).eq( i ).hide(); 31988 } 31989 } 31990 if ( ! found ) { 31991 img.show(); 31992 img.data( 'tm-current-image', false ); 31993 $form.tc_image_update( false ); 31994 } else { 31995 $current_product_element.find( '#' + tm_current_image_element_id + '_tmimage' ).remove(); 31996 } 31997 } 31998 31999 if ( found ) { 32000 imgSrc = current_image_replacement.attr( 'src' ); 32001 } 32002 32003 gallery_compatibility_actions( gallery_type, false, imgSrc, $current_product_element.find( '.tm-clone-product-image' ).filter( ':visible' ).length ); 32004 32005 jWindow.trigger( 'tm_restore_product_image_loaded', { 32006 element: e.element, 32007 main_product: e.main_product, 32008 epo_holder: e.epo_holder 32009 } ); 32010 }, window.tc_epo_product_image_change_delay || 0 ); 32011 } ); 32012 32013 main_product.off( 'tm_attempt_product_image' ).on( 'tm_attempt_product_image', function( evt, e ) { 32014 setTimeout( function() { 32015 var $main_product; 32016 var $current_product_element; 32017 var variation_element_section; 32018 var is_variation_element; 32019 var $this_epo_container; 32020 var tm_last_visible_image_element; 32021 var last_activate_field; 32022 var tm_last_visible_image_element_id; 32023 var current_image_replacement; 32024 var current_element; 32025 var found; 32026 var tm_current_image_element_id; 32027 var len; 32028 var imgSrc; 32029 var el_to_check; 32030 var tmcie_id; 32031 var i; 32032 32033 if ( TMEPOJS.tm_epo_global_image_recalculate === 'yes' ) { 32034 img = get_main_product_image( epoObject, product_element ); 32035 } 32036 32037 $main_product = e.main_product; 32038 $current_product_element = $main_product.closest( '#product-' + product_id ); 32039 if ( e.element ) { 32040 variation_element_section = e.element.closest( '.cpf-section' ); 32041 } else { 32042 variation_element_section = $( $main_product.find( '.tm-epo-variation-section' ).first(), e.epo_holder ); 32043 } 32044 is_variation_element = variation_element_section.is( '.tm-epo-variation-section' ); 32045 $this_epo_container = e.epo_holder; 32046 if ( is_variation_element ) { 32047 $this_epo_container = variation_element_section; 32048 } 32049 tm_last_visible_image_element = $this_epo_container.find( '.tm-product-image:checked,select.tm-product-image' ); 32050 last_activate_field = []; 32051 tm_last_visible_image_element_id = ''; 32052 found = false;
32053 tm_current_image_element_id = img.data( 'tm-current-image' ); 32054 imgSrc = img_src_original; 32055 32056 if ( $current_product_element.length <= 0 ) { 32057 $current_product_element = $main_product.closest( '.post-' + product_id ); 32058 } 32059 32060 $this_epo_container = $main_product.find( '.tm-epo-variation-section' ).first().add( e.epo_holder ); 32061 tm_last_visible_image_element = $this_epo_container.find( '.tm-product-image:checked,select.tm-product-image' ); 32062 32063 tm_last_visible_image_element.toArray().forEach( function( ie ) { 32064 ie = $( ie ); 32065 if ( 32066 field_is_active( ie ) && 32067 has_active_changes_product_image( ie ) && 32068 tm_check_field_match( { 32069 element: ie.closest( '.cpf-element' ), 32070 rule: { 32071 operator: 'isnotempty', 32072 value: '' 32073 }, 32074 type: 'element' 32075 } ) 32076 ) { 32077 last_activate_field.push( ie ); 32078 } 32079 } ); 32080 32081 if ( last_activate_field.length ) { 32082 tm_last_visible_image_element = last_activate_field[ last_activate_field.length - 1 ]; 32083 tm_last_visible_image_element_id = tm_last_visible_image_element.attr( 'id' ); 32084 } 32085 32086 if ( last_activate_field.length && tm_last_visible_image_element.length && ( ! tm_current_image_element_id || tm_last_visible_image_element_id !== tm_current_image_element_id ) ) { 32087 tm_last_visible_image_element.last().trigger( 'tm_trigger_product_image' ); 32088 return; 32089 } 32090 32091 tmcie_id = $this_epo_container.find( "[id='" + tm_current_image_element_id + "']" ).closest( '.cpf-element' ); 32092 if ( ! tm_current_image_element_id || ( tmcie_id.data( 'isactive' ) !== false && tmcie_id.closest( '.cpf-section' ).data( 'isactive' ) !== false ) ) { 32093 return; 32094 } 32095 32096 $current_product_element.find( '#' + tm_current_image_element_id + '_tmimage' ).remove(); 32097 len = $current_product_element.find( '.tm-clone-product-image' ).length; 32098 32099 if ( len === 0 ) { 32100 img.show(); 32101 img.data( 'tm-current-image', false ); 32102 $form.tc_image_update( false ); 32103 } else { 32104 for ( i = len - 1; i >= 0; i -= 1 ) { 32105 current_image_replacement = $current_product_element.find( '.tm-clone-product-image' ).eq( i ); 32106 current_element = current_image_replacement.attr( 'id' ).replace( '_tmimage', '' ); 32107 el_to_check = $this_epo_container.find( "[id='" + current_element + "']" ); 32108 32109 if ( el_to_check.is( ':checked' ) && el_to_check.closest( '.cpf-element' ).is( ':visible' ) ) { 32110 $current_product_element.find( '.tm-clone-product-image' ).eq( i ).show(); 32111 a.attr( 'href', $current_product_element.find( '.tm-clone-product-image' ).eq( i ).prop( 'src' ) ); 32112 img.data( 'tm-current-image', current_element ); 32113 found = true; 32114 break; 32115 } else { 32116 $current_product_element.find( '.tm-clone-product-image' ).eq( i ).hide(); 32117 } 32118 } 32119 32120 if ( ! found ) { 32121 img.show(); 32122 img.data( 'tm-current-image', false ); 32123 $form.tc_image_update( false ); 32124 } 32125 } 32126 32127 if ( found ) { 32128 imgSrc = current_image_replacement.attr( 'src' ); 32129 } 32130 32131 gallery_compatibility_actions( gallery_type, false, imgSrc, $current_product_element.find( '.tm-clone-product-image' ).filter( ':visible' ).length ); 32132 }, window.tc_epo_product_image_change_delay || 0 ); 32133 } ); 32134 32135 $( this_epo_container.find( '.tm-product-image:checked,select.tm-product-image' ) ) 32136 .add( main_product.find( '.tm-epo-variation-section' ).first().find( '.tm-product-image:checked,select.tm-product-image' ) ) 32137 .toArray().forEach( function( pi ) { 32138 pi = $( pi ); 32139 if ( field_is_active( pi ) && pi.val() !== '' ) { 32140 last_active_field.push( pi ); 32141 } 32142 } ); 32143 if ( last_active_field.length ) { 32144 last_active_field[ last_active_field.length - 1 ].trigger( 'tm_trigger_product_image' ); 32145 } 32146 } 32147 32148 jWindow.trigger( 'tm_product_image_loaded' ); 32149 } 32150 32151 function tm_product_image( epoObject ) { 32152 var galleryImages; 32153 setTimeout( function() { 32154 if ( TMEPOJS.tm_epo_global_product_image_mode === 'inline' ) { 32155 tm_product_image_inline( epoObject ); 32156 } else { 32157 tm_product_image_self( epoObject ); 32158 } 32159 32160 if ( $.fn.wc_product_gallery ) { 32161 galleryImages = epoObject.this_epo_container; 32162 if ( epoObject.is_associated ) { 32163 galleryImages = epoObject.main_product; 32164 } 32165 galleryImages.find( '.cpf-type-product-custombundle .tc-associated-product-image' ).tclightbox(); 32166 } 32167 }, window.tc_epo_product_image_setup_delay || 0 ); 32168 } 32169 32170 function tc_compatibility( epoObject ) { 32171 jWindow.trigger( 'tm-epo-compatibility', { 32172 epo: epoObject 32173 } ); 32174 } 32175 32176 // Range picker setup 32177 function setRangePickers( obj ) { 32178 if ( ! noUiSlider ) { 32179 return; 32180 } 32181 obj.find( '.tm-range-picker' ) 32182 .toArray() 32183 .forEach( function( picker ) { 32184 var el = $( picker ); 32185 var $decimals = el.attr( 'data-step' ).split( '.' ); 32186 var $tmfid = obj.find( '#' + $.epoAPI.dom.id( el.attr( 'data-field-id' ) ) ); 32187 var $min = parseFloat( el.attr( 'data-min' ) ); 32188 var $max = parseFloat( el.attr( 'data-max' ) ); 32189 var $start = parseFloat( el.attr( 'data-start' ) ); 32190 var $step = parseFloat( el.attr( 'data-step' ) ); 32191 var $show_picker_value = el.attr( 'data-show-picker-value' ); 32192 var $show_label = el.closest( 'li' ).find( '.tm-show-picker-value' ); 32193 var $noofpips = parseFloat( el.attr( 'data-noofpips' ) ); 32194 var $pips = null; 32195 var $tmh; 32196 32197 if ( el.data( 'tc-picker-init' ) ) { 32198 return; 32199 } 32200 el.data( 'tc-picker-init', 1 ); 32201 32202 if ( $decimals.length === 1 ) { 32203 $decimals = 0; 32204 } else { 32205 $decimals = $decimals[ 1 ].length; 32206 } 32207 if ( ! Number.isFinite( $min ) ) { 32208 $min = 0; 32209 } 32210 if ( ! Number.isFinite( $max ) ) { 32211 $max = 0; 32212 } 32213 if ( $max <= $min ) { 32214 $max = parseFloat( $max ) + 1; 32215 } 32216 $start = $.epoAPI.math.unformat( $start, tcAPI.localDecimalSeparator ); 32217 if ( ! Number.isFinite( $start ) ) { 32218 $start = 0; 32219 } 32220 $start = formatPrice( $start, { precision: $decimals } ); 32221 if ( ! Number.isFinite( $step ) ) { 32222 $step = 0; 32223 } 32224 if ( ! Number.isFinite( $noofpips ) ) { 32225 $noofpips = 10; 32226 } 32227 if ( $noofpips < 2 ) { 32228 $noofpips = 2; 32229 } 32230
32231 if ( el.attr( 'data-pips' ) === 'yes' ) { 32232 $pips = { 32233 mode: 'count', 32234 values: $noofpips, 32235 filter: function( value, type ) { 32236 value = parseFloat( $.epoAPI.math.toFixed( value, $decimals ) ); 32237 32238 if ( $step <= 0 ) { 32239 return 0; 32240 } 32241 32242 if ( type === 1 ) { 32243 if ( ! Number.isInteger( value ) ) { 32244 return 2; 32245 } 32246 } 32247 32248 return type; 32249 }, 32250 format: { 32251 from: function( value ) { 32252 return $.epoAPI.math.unformat( value, tcAPI.localInputDecimalSeparator ); 32253 }, 32254 to: function( value ) { 32255 return formatPrice( value, { precision: $decimals } ); 32256 } 32257 }, 32258 density: 2 32259 }; 32260 } 32261 32262 noUiSlider.create( el.get( 0 ), { 32263 direction: TMEPOJS.text_direction, 32264 start: $start, 32265 step: $step, 32266 connect: 'lower', 32267 // Configure tapping, or make the selected range dragable. 32268 behaviour: 'tap', 32269 // Full number format support. 32270 format: { 32271 from: function( value ) { 32272 return $.epoAPI.math.unformat( value, tcAPI.localDecimalSeparator ); 32273 }, 32274 to: function( value ) { 32275 return formatPrice( value, { precision: $decimals } ); 32276 } 32277 }, 32278 // Support for non-linear ranges by adding intervals. 32279 range: { 32280 min: [ $min ], 32281 max: [ $max ] 32282 }, 32283 pips: $pips, 32284 tooltips: { 32285 from: function( value ) { 32286 return $.epoAPI.math.unformat( value, tcAPI.localInputDecimalSeparator ); 32287 }, 32288 to: function( value ) { 32289 return formatPrice( value, { precision: $decimals } ); 32290 } 32291 } 32292 } ); 32293 32294 $tmh = el.find( '.noui-handle-lower' ); 32295 el.get( 0 ).noUiSlider.on( 'slide', function() { 32296 $tmfid.trigger( 'change.cpf' ); 32297 } ); 32298 el.get( 0 ).noUiSlider.on( 'update', function( values, handle ) { 32299 values[ handle ] = $.epoAPI.math.unformat( values[ handle ], tcAPI.localDecimalSeparator ); 32300 handle = 0; //fixes rtl issue. 32301 if ( $show_picker_value !== 'left' && $show_picker_value !== 'right' ) { 32302 $tmh.attr( 32303 'title', 32304 formatPrice( values[ handle ], { precision: $decimals } ) 32305 ); 32306 } 32307 $tmfid.val( values[ handle ] ).trigger( 'change' ); 32308 if ( $show_picker_value !== '' ) { 32309 $show_label.html( 32310 formatPrice( values[ handle ], { precision: $decimals } ) 32311 ); 32312 } 32313 } ); 32314 32315 if ( $show_picker_value !== '' ) { 32316 $show_label.html( $start ); 32317 } 32318 32319 if ( $show_picker_value !== 'left' && $show_picker_value !== 'right' ) { 32320 $tmh.attr( 'title', $start ); 32321 el.addClass( 'noui-show-tooltip' ); 32322 } 32323 } ); 32324 } 32325 32326 // Range picker event setup 32327 function setRangePickersEvents() { 32328 if ( ! noUiSlider || jDocument.data( 'setRangePickersEvents' ) ) { 32329 return; 32330 } 32331 jDocument.on( 'click', '.tm-show-picker-value', function() { 32332 var $this = $( this ); 32333 var li = $this.closest( '.tmcp-field-wrap' ); 32334 var value = li.find( '.tmcp-range' ).val(); 32335 var edit; 32336 var html5Slider = $this.closest( '.tmcp-field-wrap' ).find( '.tm-range-picker' ); 32337 32338 $this.addClass( 'tc-hidden' ).after( $( '<input type="number" class="tm-show-picker-value-edit">' ) ); 32339 edit = li.find( '.tm-show-picker-value-edit' ); 32340 edit.focus().val( value ).wrap( '<div class="tm-show-picker-value-edit-wrap"></div>' ); 32341 edit.attr( 'step', html5Slider.attr( 'data-step' ) ); 32342 edit.attr( 'min', html5Slider.attr( 'data-min' ) ); 32343 edit.attr( 'max', html5Slider.attr( 'data-max' ) ); 32344 $( '.tm-show-picker-value-edit' ).focus().on( 'focusout', function() { 32345 $this = li.find( '.tm-show-picker-value-edit' ); 32346 $this.closest( '.tmcp-field-wrap' ).find( '.tm-show-picker-value' ).removeClass( 'tc-hidden' ); 32347 $this.closest( '.tm-show-picker-value-edit-wrap' ).remove(); 32348 } ); 32349 } ); 32350 jDocument.on( 'change input', '.tm-show-picker-value-edit', function() { 32351 var $this = $( this ); 32352 var html5Slider = $this.closest( '.tmcp-field-wrap' ).find( '.tm-range-picker' ); 32353 var $decimals = html5Slider.attr( 'data-step' ).split( '.' ); 32354 var value = $this.val(); 32355 if ( $decimals.length === 1 ) { 32356 $decimals = 0; 32357 } else { 32358 $decimals = $decimals[ 1 ].length; 32359 } 32360 32361 html5Slider.get( 0 ).noUiSlider.set( [ formatPrice( value, { precision: $decimals } ), null ] ); 32362 } ); 32363 jDocument.on( 'keydown', '.tm-show-picker-value-edit', function( event ) { 32364 var key; 32365 32366 key = event.which; 32367 if ( key === 13 ) { 32368 event.preventDefault(); 32369 } 32370 } ); 32371 jDocument.data( 'setRangePickersEvents', 1 ); 32372 } 32373 32374 function validate_date_with_options( date, inputElement ) { 32375 var input = $( inputElement ); 32376 var inst = $.tm_datepicker._getInst( input[ 0 ] ); 32377 var enabled_only_dates = input.data( 'tc-enabled_only_dates' ); 32378 var disabled_weekdays = input.data( 'tc-disabled_weekdays' ); 32379 var disabled_months = input.data( 'tc-disabled_months' ); 32380 var disabled_dates = input.data( 'tc-disabled_dates' ); 32381 var format = input.data( 'tc-format' ); 32382 var day = date.getDay();
32383 var month = date.getDay() + 1; 32384 var string; 32385 32386 if ( ! $.tm_datepicker._isInRange( inst, date ) ) { 32387 return false; 32388 } 32389 if ( enabled_only_dates !== '' ) { 32390 string = $.tm_datepicker.formatDate( format, date ); 32391 return enabled_only_dates.indexOf( string ) !== -1; 32392 } 32393 if ( disabled_weekdays.indexOf( day.toString() ) !== -1 ) { 32394 return false; 32395 } 32396 if ( disabled_months.indexOf( month.toString() ) !== -1 ) { 32397 return false; 32398 } 32399 if ( disabled_dates !== '' ) { 32400 string = $.tm_datepicker.formatDate( format, date ); 32401 return disabled_dates.indexOf( string ) === -1; 32402 } 32403 return true; 32404 } 32405 32406 function correctDate( days ) { 32407 var sign, testDate, count, added, noOfDaysToAdd; 32408 if ( days.toString().isNumeric() ) { 32409 sign = days === 0 ? days : ( days > 0 ? 1 : -1 ); 32410 if ( sign !== 0 ) { 32411 testDate = new Date(); 32412 count = 1; 32413 added = false; 32414 noOfDaysToAdd = Math.abs( days ); 32415 while ( count <= noOfDaysToAdd ) { 32416 if ( added === false ) { 32417 added = 0; 32418 } 32419 testDate.setDate( testDate.getDate() + ( 1 * sign ) ); 32420 added++; 32421 if ( testDate.getDay() !== 0 && testDate.getDay() !== 6 ) { 32422 count++; 32423 } 32424 } 32425 if ( added !== false ) { 32426 days = added * sign; 32427 } 32428 } 32429 } 32430 return days; 32431 } 32432 // Date and time picker setup 32433 function tm_set_datepicker( obj ) { 32434 var inputIds; 32435 var elem; 32436 var timepickerSelector = '.tm-epo-timepicker'; 32437 32438 if ( ! $.tm_datepicker ) { 32439 return; 32440 } 32441 32442 inputIds = $( 'input' ) 32443 .map( function() { 32444 return this.id; 32445 } ) 32446 .get() 32447 .join( ' ' ); 32448 32449 elem = document.createElement( 'input' ); 32450 elem.setAttribute( 'type', 'date' ); 32451 32452 if ( elem.type === 'text' ) { 32453 timepickerSelector = '.tm-epo-system-timepicker'; 32454 } 32455 32456 obj.find( timepickerSelector ) 32457 .toArray() 32458 .forEach( function( el ) { 32459 var field = $( el ); 32460 var _mintime = null; 32461 var _maxtime = null; 32462 var format = field.attr( 'data-time-format' ).trim(); 32463 var date_theme = field.attr( 'data-time-theme' ).trim(); 32464 var date_theme_size = field.attr( 'data-time-theme-size' ).trim(); 32465 var date_theme_position = field.attr( 'data-time-theme-position' ).trim(); 32466 var data_translation_hour = field.attr( 'data-tranlation-hour' ).trim(); 32467 var data_translation_minute = field.attr( 'data-tranlation-minute' ).trim(); 32468 var data_translation_second = field.attr( 'data-tranlation-second' ).trim(); 32469 32470 field.attr( 'type', 'text' ); 32471 32472 if ( field.attr( 'data-min-time' ).trim() !== '' ) { 32473 _mintime = field.attr( 'data-min-time' ).trim(); 32474 } 32475 if ( field.attr( 'data-max-time' ).trim() !== '' ) { 32476 _maxtime = field.attr( 'data-max-time' ).trim(); 32477 } 32478 32479 if ( field.attr( 'data-custom-time-format' ).trim() !== '' ) { 32480 format = field.attr( 'data-custom-time-format' ).trim(); 32481 } 32482 if ( ! data_translation_hour ) { 32483 data_translation_hour = TMEPOJS.hourText; 32484 } 32485 if ( ! data_translation_minute ) { 32486 data_translation_minute = TMEPOJS.minuteText; 32487 } 32488 if ( ! data_translation_second ) { 32489 data_translation_second = TMEPOJS.secondText; 32490 } 32491 32492 field.tm_timepicker( Object.assign( { 32493 isRTL: TMEPOJS.isRTL, 32494 hourText: data_translation_hour, 32495 minuteText: data_translation_minute, 32496 secondText: data_translation_second, 32497 timeFormat: format, 32498 minTime: _mintime, 32499 maxTime: _maxtime, 32500 closeText: TMEPOJS.closeText, 32501 showOn: 'both', 32502 buttonText: '', 32503 32504 beforeShow: function( input, inst ) { 32505 $( inst.dpDiv ) 32506 .removeClass( inputIds ) 32507 .removeClass( 'tm-ui-skin-epo tm-ui-skin-epo-black tm-datepicker-medium tm-datepicker-small tm-datepicker-large tm-datepicker-normal tm-datepicker-top tm-datepicker-bottom' ) 32508 .addClass( this.id + ' tm-bsbb-all tm-ui-skin-' + date_theme + ' tm-timepicker tm-datepicker tm-datepicker-' + date_theme_position + ' tm-datepicker-' + date_theme_size ) 32509 .appendTo( 'body' ); 32510 32511 jDocument.off( 'click', '.tm-ui-dp-overlay' ).on( 'click', '.tm-ui-dp-overlay', function() { 32512 field.tm_timepicker( 'hide' ); 32513 } ); 32514 jBody.addClass( 'tm-static' ); 32515 field.prop( 'readonly', true ); 32516 32517 jWindow.trigger( { 32518 type: 'tm-timepicker-beforeShow', 32519 input: input, 32520 inst: inst 32521 } ); 32522 }, 32523 onClose: function() { 32524 jBody.removeClass( 'tm-static' ); 32525 field.prop( 'readonly', false ); 32526 field.trigger( 'change' ); 32527 } 32528 }, window.tmTimepickerSettings || window.timepicker_settings || {} ) ); 32529 $( '#ui-tm-datepicker-div' ).hide(); 32530 } ); 32531 32532 obj.find( '.tm-epo-datepicker' ) 32533 .toArray() 32534 .forEach( function( el ) { 32535 var field = $( el ); 32536 var startDate = parseInt( field.attr( 'data-start-year' ).trim(), 10 ); 32537 var endDate = parseInt( field.attr( 'data-end-year' ).trim(), 10 ); 32538 var minDate = field.attr( 'data-min-date' ).trim(); 32539 var maxDate = field.attr( 'data-max-date' ).trim(); 32540 var disabled_dates = field.attr( 'data-disabled-dates' ).trim(); 32541 var enabled_only_dates = field.attr( 'data-enabled-only-dates' ).trim(); 32542 var exlude_disabled = field.attr( 'data-exlude-disabled' ).trim(); 32543 var disabled_weekdays = field.attr( 'data-disabled-weekdays' ).trim().split( ',' ); 32544 var disabled_months = field.attr( 'data-disabled-months' ).trim().split( ',' ); 32545 var format = field.attr( 'data-date-format' ).trim(); 32546 var show = field.attr( 'data-date-showon' ).trim(); 32547 var default_date = field.attr( 'data-date-defaultdate' ).trim(); 32548 var date_theme = field.attr( 'data-date-theme' ).trim(); 32549 var date_theme_size = field.attr( 'data-date-theme-size' ).trim(); 32550 var date_theme_position = field.attr( 'data-date-theme-position' ).trim(); 32551 var $split; 32552 var $index; 32553 var $split2; 32554 var $index2; 32555 32556 if ( disabled_dates !== '' ) { 32557 $split = disabled_dates.split( ',' ); 32558 $index = disabled_dates.indexOf( ',' ); 32559 32560 if ( $index !== -1 && $split.length > 0 ) { 32561 disabled_dates = $split; 32562 } 32563 } 32564 if ( enabled_only_dates !== '' ) { 32565 $split2 = enabled_only_dates.split( ',' ); 32566 $index2 = enabled_only_dates.indexOf( ',' ); 32567 32568 if ( $index2 !== -1 && $split2.length > 0 ) { 32569 enabled_only_dates = $split2; 32570 } 32571 } 32572 32573 if ( minDate === '' ) { 32574 if ( startDate === '' ) { 32575 minDate = null; 32576 } else { 32577 minDate = new Date( startDate, 1 - 1, 1 ); 32578 } 32579 } else if ( exlude_disabled ) { 32580 minDate = correctDate( minDate ); 32581 } 32582 if ( maxDate === '' ) { 32583 if ( endDate === '' ) { 32584 maxDate = null; 32585 } else { 32586 maxDate = new Date( endDate, 12 - 1, 31 ); 32587 } 32588 } else if ( exlude_disabled ) { 32589 maxDate = correctDate( maxDate ); 32590 } 32591 32592 field.data( 'tc-enabled_only_dates', enabled_only_dates ); 32593 field.data( 'tc-disabled_weekdays', disabled_weekdays ); 32594 field.data( 'tc-disabled_months', disabled_months ); 32595 field.data( 'tc-disabled_dates', disabled_dates ); 32596 field.data( 'tc-format', format ); 32597 32598 field.tm_datepicker( Object.assign( { 32599 monthNames: TMEPOJS.monthNames, 32600 monthNamesShort: TMEPOJS.monthNamesShort, 32601 dayNames: TMEPOJS.dayNames, 32602 dayNamesShort: TMEPOJS.dayNamesShort, 32603 dayNamesMin: TMEPOJS.dayNamesMin, 32604 isRTL: TMEPOJS.isRTL, 32605 showOtherMonths: true, 32606 selectOtherMonths: true, 32607 showOn: show, 32608 defaultDate: default_date, 32609 buttonText: '', 32610 showButtonPanel: true, 32611 firstDay: TMEPOJS.first_day, 32612 closeText: TMEPOJS.closeText, 32613 currentText: TMEPOJS.currentText, 32614 dateFormat: format, 32615 minDate: minDate, 32616 maxDate: maxDate, 32617 onSelect: function() { 32618 var input = $( this ); 32619 var id = '#' + $.epoAPI.dom.id( input.attr( 'id' ) ); 32620 var date = input.tm_datepicker( 'getDate' ); 32621 var day = '';
32622 var month = ''; 32623 var year = ''; 32624 var day_field = obj.find( id + '_day' ); 32625 var month_field = obj.find( id + '_month' ); 32626 var year_field = obj.find( id + '_year' ); 32627 var string; 32628 var ld; 32629 32630 if ( date ) { 32631 day = date.getDate(); 32632 month = date.getMonth() + 1; 32633 year = date.getFullYear(); 32634 string = $.tm_datepicker.formatDate( format, date ); 32635 if ( 32636 disabled_months.indexOf( month.toString() ) !== -1 || 32637 disabled_weekdays.indexOf( date.getDay().toString() ) !== -1 || 32638 disabled_dates.indexOf( string ) !== -1 || 32639 ( enabled_only_dates !== '' && enabled_only_dates.indexOf( string ) === -1 ) 32640 ) { 32641 ld = input.data( 'tm-last-date' ); 32642 if ( input.data( 'tm-last-date' ) ) { 32643 ld = input.data( 'tm-last-date' ); 32644 } else { 32645 ld = ''; 32646 } 32647 input.val( ld ); 32648 input.tm_datepicker( 'setDate', ld ); 32649 if ( ld ) { 32650 date = input.tm_datepicker( 'getDate' ); 32651 day = date.getDate(); 32652 month = date.getMonth() + 1; 32653 year = date.getFullYear(); 32654 } else { 32655 day = ''; 32656 month = ''; 32657 year = ''; 32658 } 32659 } 32660 } 32661 32662 day_field.val( day ); 32663 month_field.val( month ); 32664 year_field.val( year ); 32665 32666 input.data( 'tm-last-date', input.val() ); 32667 input.tm_datepicker( 'hide' ); 32668 }, 32669 beforeShow: function( input, inst ) { 32670 $( inst.dpDiv ) 32671 .removeClass( inputIds ) 32672 .removeClass( 'tm-datepicker-normal tm-datepicker-top tm-datepicker-bottom' ) 32673 .addClass( this.id + ' tm-bsbb-all tm-ui-skin-' + date_theme + ' tm-datepicker tm-datepicker-' + date_theme_position + ' tm-datepicker-' + date_theme_size ) 32674 .appendTo( 'body' ); 32675 32676 jDocument.off( 'click', '.tm-ui-dp-overlay' ).on( 'click', '.tm-ui-dp-overlay', function() { 32677 field.tm_datepicker( 'hide' ); 32678 } ); 32679 jDocument.off( 'click', '.ui-tm-datepicker-current' ).on( 'click', '.ui-tm-datepicker-current', function() { 32680 var tempDate = new Date(), 32681 today = $.tm_datepicker._daylightSavingAdjust( new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ); 32682 var day = today.getDay(); 32683 var month = today.getMonth() + 1; 32684 var id = '#' + inst.id.replace( /\\\\/g, '\\' ); 32685 var check = false; 32686 var string; 32687 var date = field.tm_datepicker( 'getDate' ); 32688 32689 if ( enabled_only_dates !== '' ) { 32690 string = $.tm_datepicker.formatDate( format, date ); 32691 check = enabled_only_dates.indexOf( string ) !== -1; 32692 } else if ( disabled_months.indexOf( month.toString() ) !== -1 || disabled_weekdays.indexOf( day.toString() ) !== -1 ) { 32693 check = false; 32694 } else { 32695 if ( disabled_dates !== '' ) { 32696 string = $.tm_datepicker.formatDate( format, date ); 32697 return [ disabled_dates.indexOf( string ) === -1, '' ]; 32698 } 32699 check = true; 32700 } 32701 if ( check ) { 32702 $.tm_datepicker._setDate( inst, today ); 32703 $.tm_datepicker._gotoToday( id ); 32704 } 32705 } ); 32706 jBody.addClass( 'tm-static' ); 32707 32708 jWindow.trigger( { 32709 type: 'tm-datepicker-beforeShow', 32710 input: input, 32711 inst: inst 32712 } ); 32713 }, 32714 onClose: function() { 32715 jBody.removeClass( 'tm-static' ); 32716 field.trigger( 'change' ); 32717 }, 32718 beforeShowDay: function( date ) { 32719 var day = date.getDay(); 32720 var month = date.getMonth() + 1; 32721 var string; 32722 32723 if ( enabled_only_dates !== '' ) { 32724 string = $.tm_datepicker.formatDate( format, date ); 32725 return [ enabled_only_dates.indexOf( string ) !== -1, '' ]; 32726 } 32727 if ( disabled_months.indexOf( month.toString() ) !== -1 || disabled_weekdays.indexOf( day.toString() ) !== -1 ) { 32728 return [ false, '' ]; 32729 } 32730 if ( disabled_dates !== '' ) { 32731 string = $.tm_datepicker.formatDate( format, date ); 32732 return [ disabled_dates.indexOf( string ) === -1, '' ]; 32733 } 32734 return [ true, '' ]; 32735 } 32736 }, window.tmDatepickerSettings || {} ) ); 32737 32738 $( '#ui-tm-datepicker-div' ).hide(); 32739 } ); 32740 32741 obj.find( '.tmcp-date-select' ) 32742 .on( 'change.cpf', function() { 32743 var id = '#' + $.epoAPI.dom.id( $( this ).attr( 'data-tm-date' ) ); 32744 var input = obj.find( id ); 32745 var format = input.attr( 'data-date-format' ); 32746 var day = obj.find( id + '_day' ).val();
32747 var month = obj.find( id + '_month' ).val(); 32748 var year = obj.find( id + '_year' ).val(); 32749 var dateFormat = $.tm_datepicker.formatDate( format, new Date( year, parseInt( month, 10 ) - 1, day ) ); 32750 32751 if ( day > 0 && month > 0 && year > 0 ) { 32752 input.tm_datepicker( 'setDate', dateFormat ); 32753 input.trigger( 'change' ); 32754 } else { 32755 input.val( '' ); 32756 input.trigger( 'change.cpf' ); 32757 } 32758 } ) 32759 .on( 'focus.cpf', function() { 32760 var id = '#' + $.epoAPI.dom.id( $( this ).attr( 'data-tm-date' ) ); 32761 var input = obj.find( id ); 32762 var day_select = obj.find( id + '_day' ); 32763 var month_select = obj.find( id + '_month' ); 32764 var year_select = obj.find( id + '_year' ); 32765 var day = day_select.val(); 32766 var month = month_select.val(); 32767 var year = year_select.val(); 32768 var _select = $( this ); 32769 32770 if ( ( year !== '' && month !== '' && day !== '' ) || ( year !== '' && month !== '' && day === '' ) || ( day !== '' && year !== '' && month === '' ) || ( day !== '' && month !== '' && year === '' ) ) { 32771 _select 32772 .find( 'option' ) 32773 .toArray() 32774 .forEach( function( element ) { 32775 var option = $( element ); 32776 var val = option.val(); 32777 var date_string = year + '-' + month + '-' + day; 32778 var d; 32779 32780 if ( _select.is( '.tmcp-date-day' ) ) { 32781 if ( year === '' || month === '' ) { 32782 return; 32783 } 32784 date_string = year + '-' + month + '-' + val; 32785 } else if ( _select.is( '.tmcp-date-month' ) ) { 32786 if ( year === '' || day === '' ) { 32787 return; 32788 } 32789 date_string = year + '-' + val + '-' + day; 32790 } else if ( _select.is( '.tmcp-date-year' ) ) { 32791 if ( day === '' || month === '' ) { 32792 return; 32793 } 32794 date_string = val + '-' + month + '-' + day; 32795 } 32796 32797 if ( val !== '' ) { 32798 try { 32799 d = $.tm_datepicker.parseDate( 'yy-mm-dd', date_string ); 32800 if ( d ) { 32801 if ( validate_date_with_options( d, input ) ) { 32802 option.prop( 'disabled', false ); 32803 } else { 32804 option.prop( 'disabled', true ); 32805 } 32806 } 32807 } catch ( err ) { 32808 window.console.log( err ); 32809 32810 option.prop( 'disabled', true ); 32811 errorObject = err; 32812 } 32813 } 32814 } ); 32815 } else { 32816 day_select.find( 'option' ).prop( 'disabled', false ); 32817 month_select.find( 'option' ).prop( 'disabled', false ); 32818 year_select.find( 'option' ).prop( 'disabled', false ); 32819 } 32820 } ); 32821 32822 jWindow.on( 'resizestart', function() { 32823 var activeElement = $( document.activeElement ); 32824 32825 if ( activeElement.is( '.hasDatepicker' ) ) { 32826 activeElement.data( 'resizestarted', true ); 32827 32828 // we don't use jWindow here because we want the current window width 32829 if ( $( window ).width() < 768 ) { 32830 activeElement.data( 'resizewidth', true ); 32831 return; 32832 } 32833 activeElement.tm_datepicker( 'hide' ); 32834 } 32835 } ); 32836 jWindow.on( 'resizestop', function() { 32837 var activeElement = $( document.activeElement ); 32838 32839 if ( activeElement.is( '.hasDatepicker' ) && activeElement.data( 'resizestarted' ) ) { 32840 if ( activeElement.data( 'resizewidth' ) ) { 32841 activeElement.tm_datepicker( 'hide' ); 32842 } 32843 activeElement.tm_datepicker( 'show' ); 32844 } 32845 activeElement.data( 'resizestarted', false ); 32846 activeElement.data( 'resizewidth', false ); 32847 } ); 32848 } 32849 32850 function apply_submit_events( epoObject ) { 32851 var epoEventId = epoObject.epoEventId; 32852 var main_product = epoObject.main_product; 32853 var type; 32854 var form_is_submit = ! $.tcepo.formSubmitEvents[ epoEventId ].some( function( form_event ) { 32855 return typeof form_event && ( typeof form_event.trigger === 'function' || false ) && ! form_event.trigger(); 32856 } ); 32857 32858 $.tcepo.formSubmitEvents[ epoEventId ].forEach( function( form_event ) { 32859 type = typeof form_event; 32860 if ( type === 'object' ) { 32861 if ( form_is_submit ) { 32862 form_event.on_true(); 32863 } else { 32864 form_event.on_false(); 32865 } 32866 } 32867 } ); 32868 32869 if ( ! form_is_submit ) { 32870 setTimeout( function() { 32871 main_product.find( tcAPI.addToCartButtonSelector ).first().removeClass( 'disabled' ).removeClass( 'loading' ).prop( 'disabled', false ).removeClass( 'fpd-disabled' ); 32872 }, 100 ); 32873 } 32874 32875 jWindow.trigger( 'tm-apply-submit-events', { 32876 epo: { 32877 form_is_submit: form_is_submit 32878 } 32879 } ); 32880 32881 return form_is_submit; 32882 } 32883 32884 function tm_apply_validation( epoObject ) { 32885 var form = epoObject.form; 32886 var this_epo_container = epoObject.this_epo_container; 32887 var main_product = epoObject.main_product; 32888 var epoEventId = epoObject.epoEventId;
32889 var validation_rules; 32890 var has_rules; 32891 32892 if ( TMEPOJS.tm_epo_global_enable_validation === 'yes' ) { 32893 validation_rules = {}; 32894 32895 this_epo_container 32896 .find( '.tmcp-ul-wrap' ) 32897 .toArray() 32898 .forEach( function( tmcpulwrap ) { 32899 var field; 32900 var field_name; 32901 var subFieldName; 32902 var subRule; 32903 var productField; 32904 32905 tmcpulwrap = $( tmcpulwrap ); 32906 has_rules = tmcpulwrap.data( 'tm-validation' ); 32907 if ( has_rules && $.tmType( has_rules ) === 'object' ) { 32908 field = tmcpulwrap.find( '.tm-epo-field' ); 32909 field_name = field.first().attr( 'name' ); 32910 if ( tmcpulwrap.is( '.tm-extra-product-options-radio.tm-element-ul-radio' ) ) { 32911 field_name = field.last().attr( 'name' ); 32912 validation_rules[ field_name ] = has_rules; 32913 } else if ( tmcpulwrap.is( '.tm-extra-product-options-checkbox.tm-element-ul-checkbox' ) ) { 32914 field.toArray().forEach( function( fname ) { 32915 if ( 'required' in has_rules ) { 32916 has_rules.required = function( elem ) { 32917 var len = tmcpulwrap.find( 'input.tm-epo-field.tmcp-checkbox:checked' ).length; 32918 if ( len === 0 ) { 32919 if ( field.last().attr( 'name' ) === $( elem ).attr( 'name' ) ) { 32920 return true; 32921 } 32922 return false; 32923 } 32924 return len <= 0; 32925 }; 32926 } 32927 validation_rules[ $( fname ).attr( 'name' ) ] = has_rules; 32928 } ); 32929 } else if ( tmcpulwrap.is( '.tm-extra-product-options-product.tm-element-ul-product' ) ) { 32930 field = field.filter( '.tc-epo-field-product' ); 32931 if ( field.is( ':checkbox' ) ) { 32932 field.toArray().forEach( function( fname ) { 32933 if ( 'required' in has_rules ) { 32934 productField = $( fname ); 32935 if ( productField.is( ':checkbox' ) ) { 32936 has_rules.required = function( elem ) { 32937 var checkedFields = tmcpulwrap.find( 'input.tm-epo-field.tmcp-checkbox:checked' ); 32938 var len = checkedFields.length; 32939 var qtyCheck; 32940 if ( len === 0 ) { 32941 if ( field.last().attr( 'name' ) === $( elem ).attr( 'name' ) ) { 32942 return true; 32943 } 32944 return false; 32945 } 32946 qtyCheck = checkedFields.map( function() { 32947 return $( this ); 32948 } ).get().some( function( element ) { 32949 return element.closest( '.tc-epo-element-product-holder' ).find( '.tm-qty' ).first().val() <= 0; 32950 } ); 32951 if ( len > 0 ) { 32952 return qtyCheck; 32953 } 32954 return len <= 0; 32955 }; 32956 if ( productField.attr( 'data-type' ) === 'variable' ) { 32957 subFieldName = productField.closest( '.tc-epo-element-product-holder' ).find( '.product-variation-id' ).first().attr( 'name' ); 32958 subRule = { 32959 required: function( elem ) { 32960 var element = $( elem ); 32961 var holder = element.closest( '.tc-epo-element-product-holder' ); 32962 var checkbox = holder.find( '.tc-epo-field-product' ); 32963 32964 if ( field_is_active( checkbox, true ) && checkbox.is( ':checked' ) ) { 32965 return true; 32966 } 32967 return false; 32968 } 32969 }; 32970 validation_rules[ subFieldName ] = subRule; 32971 } 32972 } 32973 } 32974 validation_rules[ productField.attr( 'name' ) ] = has_rules; 32975 } ); 32976 } else if ( field.is( ':radio' ) ) { 32977 has_rules.product_element_radio_qty = true; 32978 validation_rules[ field.attr( 'name' ) ] = has_rules; 32979 subFieldName = field.closest( '.tc-element-container' ).find( '.product-variation-id' ).first().attr( 'name' ); 32980 subRule = { 32981 required: function( elem ) { 32982 var element = $( elem ); 32983 var holder = element.closest( '.tc-element-container' ); 32984 var radiobutton = holder.find( '.tc-epo-field-product:checked' ); 32985 32986 if ( radiobutton.length && radiobutton.attr( 'data-type' ) === 'variable' && field_is_active( radiobutton, true ) && radiobutton.is( ':checked' ) ) { 32987 return true; 32988 } 32989 return false;
32990 } 32991 }; 32992 validation_rules[ subFieldName ] = subRule; 32993 } else if ( field.is( 'select' ) ) { 32994 has_rules.product_element_select_qty = true; 32995 validation_rules[ field.attr( 'name' ) ] = has_rules; 32996 subFieldName = field.closest( '.tc-element-container' ).find( '.product-variation-id' ).first().attr( 'name' ); 32997 subRule = { 32998 required: function( elem ) { 32999 var element = $( elem ); 33000 var holder = element.closest( '.tc-element-container' ); 33001 var select = holder.find( '.tc-epo-field-product' ); 33002 33003 if ( select.length && select.children( ':selected' ).attr( 'data-type' ) === 'variable' && field_is_active( select, true ) ) { 33004 return true; 33005 } 33006 return false; 33007 } 33008 }; 33009 validation_rules[ subFieldName ] = subRule; 33010 } 33011 } else { 33012 validation_rules[ field_name ] = has_rules; 33013 } 33014 } 33015 } ); 33016 33017 form.removeData( 'tc_validator' ); 33018 form.tc_validate( { 33019 focusInvalid: false, 33020 ignore: 33021 tcAPI.qtySelector + 33022 ',.tcdisabled,.tmcp-upload-hidden,#wc_bookings_field_duration,input.tm-qty:hidden[type="number"],input.input-text.qty,.ignore,.variations select,.tc-epo-variable-product-selector,.tm-extra-product-options-variations input,.tm-extra-product-options-variations select,input:not(' + tcAPI.epoSelector + ' input),select:not(' + tcAPI.epoSelector + ' select)', 33023 rules: validation_rules, 33024 errorClass: 'tm-error', 33025 validClass: 'tm-valid', 33026 errorElement: 'label', 33027 errorPlacement: function( error, element ) { 33028 error.addClass( 'tc-cell tcwidth tcwidth-100' ); 33029 if ( TMEPOJS.tm_epo_global_error_label_placement === 'before' ) { 33030 element.closest( '.tc-element-container' ).before( error ); 33031 } else { 33032 element.closest( '.tc-element-container' ).after( error ); 33033 } 33034 return false; 33035 }, 33036 invalidHandler: function( event, validator ) { 33037 jWindow.trigger( 'tm-invalidHandler', { 33038 epo: { 33039 validator: validator 33040 } 33041 } ); 33042 setTimeout( function() { 33043 if ( ! main_product.find( tcAPI.addToCartButtonSelector ).first().is( '.disabled' ) ) { 33044 main_product.find( tcAPI.addToCartButtonSelector ).first().removeClass( 'loading' ).prop( 'disabled', false ).removeClass( 'fpd-disabled' ); 33045 main_product.find( tcAPI.addToCartButtonSelector ).first().removeClass( 'disabled' ).removeClass( 'loading' ).prop( 'disabled', false ).removeClass( 'fpd-disabled' ); 33046 } 33047 }, 100 ); 33048 if ( validator.errorList && validator.errorList[ 0 ] && validator.errorList[ 0 ].element ) { 33049 goto_error_item( $( validator.errorList[ 0 ].element ), epoEventId ); 33050 } 33051 }, 33052 submitHandler: function() { 33053 var ajaxSuccessFunc; 33054 if ( ! epoObject.is_quickview ) { 33055 main_product.find( tcAPI.addToCartButtonSelector ).first().addClass( 'disabled' ); 33056 ajaxSuccessFunc = function() { 33057 main_product.find( tcAPI.addToCartButtonSelector ).first().removeClass( 'disabled' ); 33058 jDocument.off( 'ajaxSuccess', ajaxSuccessFunc ); 33059 }; 33060 jDocument.on( 'ajaxSuccess', ajaxSuccessFunc ); 33061 } 33062 return apply_submit_events( epoObject ); 33063 } 33064 } ); 33065 33066 // This should handle most ajax based add to cart solutions 33067 form.find( tcAPI.addToCartButtonSelector ).on( 'click', function( e ) { 33068 if ( ! form.tc_validate().form() ) { 33069 e.preventDefault(); 33070 e.stopImmediatePropagation(); 33071 } 33072 } ); 33073 33074 return true; 33075 } 33076 return false; 33077 } 33078 33079 function tm_form_submit_event( epoObject ) { 33080 var form = epoObject.form; 33081 var epoEventId = epoObject.epoEventId; 33082 33083 jWindow.trigger( 'tm-from-submit', { 33084 epo: epoObject, 33085 functions: { 33086 tm_apply_validation: tm_apply_validation, 33087 apply_submit_events: apply_submit_events 33088 } 33089 } ); 33090 if ( ! tm_apply_validation( epoObject ) && $.tcepo.formSubmitEvents[ epoEventId ].length ) { 33091 form.on( 'submit', function() { 33092 apply_submit_events( epoObject ); 33093 } ); 33094 } 33095 33096 jWindow.on( 'tc_apply_validation', function() { 33097 return tm_apply_validation( epoObject ); 33098 } ); 33099 } 33100 33101 function found_variation_tmepo( dataObject ) { 33102 var epoHolder = dataObject.epoHolder; 33103 var totalsHolder = dataObject.totalsHolder; 33104 var totalsHolderContainer = dataObject.totalsHolderContainer; 33105 var currentCart = dataObject.currentCart; 33106 var variationForm = dataObject.variationForm; 33107 var variation = dataObject.variation; 33108 var variations = totalsHolder.data( 'variations' ); 33109 var product_price; 33110 33111 totalsHolder.data( 'current_variation', variation ); 33112 33113 /** 33114 * Currency converters that don't allow multi currency checkout will fail the following if statement 33115 * 33116 * if (variation.display_price!=undefined) { 33117 * product_price = variation.display_price; 33118 * totalsHolder.data('price', product_price); 33119 * } else ... 33120 * 33121 */ 33122 // This needs to be the first check as the next one 33123 // fails for taxed products as it displays the backend price only. 33124 if ( variation && 'display_price' in variation && ! totalsHolder.data( 'tm-epo-is-woocs' ) ) { 33125 product_price = variation.display_price; 33126 33127 totalsHolder.data( 'priceIsWithDiscount', '1' ); 33128 // Fancy product Designer 33129 totalsHolder.removeData( 'tcprice' ); 33130 } else if ( variations && variation && variation.variation_id && variations[ variation.variation_id ] !== undefined ) { 33131 product_price = variations[ variation.variation_id ]; 33132 33133 // Fancy product Designer 33134 totalsHolder.removeData( 'tcprice' ); 33135 } else if ( variation && $( variation.price_html ).find( '.amount:last' ).length ) { 33136 product_price = $( variation.price_html ).find( '.amount:last' ).text(); 33137 product_price = product_price.replace( TMEPOJS.currency_format_thousand_sep, '' ); 33138 product_price = product_price.replace( TMEPOJS.currency_format_decimal_sep, '.' ); 33139 product_price = product_price.replace( /[^0-9.]/g, '' ); 33140 product_price = parseFloat( product_price ); 33141 33142 // Fancy product Designer 33143 totalsHolder.removeData( 'tcprice' ); 33144 } 33145 33146 product_price = tm_set_backend_price( product_price, totalsHolder, variation ); 33147 totalsHolder.data( 'price', product_price ); 33148 33149 totalsHolderContainer.find( '.cpf-product-price' ).val( product_price ); 33150 33151 setTimeout( function() { 33152 epoHolder.find( 'select.tm-epo-field' ).trigger( 'tm-select-change-html-all-math' ); 33153 }, 100 ); 33154 33155 // This must be run every time to get correct results for percent price types 33156 // if set norules then discount will not auto work upon chosing a variation 33157 if ( ! variationForm.data( 'tm-styled-variations' ) ) { 33158 currentCart.trigger( { 33159 type: 'tm-epo-update' 33160 } ); 33161 } 33162 } 33163 33164 function fetchOptionPrices( epoObject, epoHolder, selector, total, original_total, floatingBoxData, showTotal, forced, setPriceTax, useUndiscountedPrice, mathTotal, cumulative, nopriceCac
33164heSelector, cartQty ) { 33165 var obj; 33166 var noDpd; 33167 var priceArray; 33168 var priceCacheSelector = 'none'; 33169 var total_taxed; 33170 var original_total_taxed; 33171 var vat_total = 0; 33172 var currentTotalsContainer; 33173 var epoinline; 33174 var funcTotal; 33175 var cumulativeTotal; 33176 33177 if ( ! nopriceCacheSelector ) { 33178 priceCacheSelector = epoHolder.attr( 'class' ) + epoHolder.attr( 'data-uniqid' ) + selector + epoObject.is_associated + setPriceTax + forced + setPriceTax + useUndiscountedPrice || 'none'; 33179 } 33180 33181 if ( priceCacheSelector !== 'none' && priceCache !== true && priceCache !== false && priceCache[ priceCacheSelector ] !== undefined ) { 33182 return priceCache[ priceCacheSelector ]; 33183 } 33184 33185 noDpd = useUndiscountedPrice ? 'undiscounted_' : ''; 33186 obj = epoHolder.find( selector ); 33187 if ( epoObject.is_associated === false ) { 33188 obj = obj.not( tcAPI.associatedEpoSelector + ' ' + selector + ',.cpf-type-variations ' + selector ); 33189 } 33190 if ( ! forced ) { 33191 obj = obj.filter( '.tcenabled' ); 33192 } 33193 33194 if ( ! total ) { 33195 total = 0; 33196 } 33197 if ( ! original_total ) { 33198 original_total = 0; 33199 } 33200 33201 funcTotal = total; 33202 cumulativeTotal = total; 33203 33204 total_taxed = total; 33205 original_total_taxed = original_total; 33206 33207 if ( ! floatingBoxData ) { 33208 floatingBoxData = []; 33209 } 33210 33211 currentTotalsContainer = epoObject.this_epo_totals_container; 33212 33213 if ( obj.length ) { 33214 obj.toArray().forEach( function( tmcpfield ) { 33215 var field = $( tmcpfield ); 33216 var _value = ''; 33217 var fieldval; 33218 var field_div = field.closest( '.cpf-element' ); 33219 var field_wrap = field.closest( '.tmcp-field-wrap' ); 33220 var field_label_show = field_div.attr( 'data-fblabelshow' ); 33221 var field_value_show = field_div.attr( 'data-fbvalueshow' ); 33222 var field_title = ''; 33223 var option_quantity = field_wrap.find( '.tm-qty' ).val(); 33224 var option_price; 33225 var option_price_taxed; 33226 var option_original_price; 33227 var option_original_price_taxed; 33228 var liw; 33229 var cri; 33230 var tl; 33231 var options; 33232 var forrangepicker; 33233 var $decimals; 33234 var _valueText = ''; 33235 var setter; 33236 var dofloatingBoxData = false; 33237 33238 if ( selector === '.tc-epo-field-product' ) { 33239 if ( field_div.is( '.cpf-type-product-thumbnailmultiple' ) || field_div.is( '.cpf-type-product-checkbox' ) || field_div.is( '.cpf-type-product-custombundle' ) ) { 33240 epoinline = field.closest( '.tc-epo-element-product-holder' ).find( tcAPI.associatedEpoSelector ); 33241 } else if ( field_div.is( '.cpf-type-product-thumbnail' ) || field_div.is( '.cpf-type-product-radio' ) || field_div.is( '.cpf-type-product-dropdown' ) ) { 33242 epoinline = field_div.find( '.tc-epo-element-product-container[data-product_id="' + field.val() + '"]' ).find( tcAPI.associatedEpoSelector ); 33243 } else if ( field_div.is( '.cpf-type-product-single' ) ) { 33244 epoinline = field_div.find( tcAPI.associatedEpoSelector ); 33245 } 33246 currentTotalsContainer = $( '.tc-epo-totals' + '.tm-product-id-' + epoinline.attr( 'data-product-id' ) + '[data-epo-id="' + epoinline.attr( 'data-epo-id' ) + '"]' ); 33247 } 33248 33249 if ( currentTotalsContainer.length ) { 33250 if ( field_label_show === '' ) { 33251 field_title = field_div.find( '.tc-epo-element-label-text' ).html(); 33252 } 33253 33254 if ( option_quantity === undefined ) { 33255 option_quantity = ''; 33256 } 33257 if ( mathTotal ) { 33258 tm_element_epo_rules( epoObject, field, undefined, undefined, undefined, undefined, funcTotal, cumulativeTotal ); 33259 } 33260 if ( field.is( ':checkbox, :radio, :input' ) ) { 33261 option_price = 0; 33262 option_price_taxed = 0; 33263 option_original_price = 0; 33264 option_original_price_taxed = 0; 33265 if ( field.is( '.tmcp-checkbox, .tmcp-radio' ) ) { 33266 if ( forced || field.is( ':checked' ) ) { 33267 option_price = field.data( noDpd + 'raw_price' ); 33268 option_price_taxed = field.data( noDpd + 'price' ); 33269 option_original_price = field.data( noDpd + 'raw_original_price' ); 33270 option_original_price_taxed = field.data( noDpd + 'original_price' ); 33271 showTotal = true; 33272 field.data( 'isset', 1 ); 33273 liw = field.closest( 'li.tmcp-field-wrap' ); 33274 cri = liw.find( '.tc-image' ); 33275 _value = ''; 33276 _valueText = ''; 33277 33278 tl = field.closest( 'li.tmcp-field-wrap' ).find( '.tc-label-text' ); 33279 if ( tl.length ) { 33280 _value = tl.html(); 33281 _valueText = _value; 33282 } 33283 33284 if ( cri.length ) { 33285 cri = cri.closest( '.tc-label-wrap' ).clone().addClass( 'tc-img-floating' ); 33286 cri.find( '.tc-label, .tc-epo-style-wrapper, .tc-input-wrap' ).remove(); 33287 _value = cri[ 0 ].outerHTML + '<span class="tc-label-text">' + _value + '</span>'; 33288 } 33289 dofloatingBoxData = true; 33290 } else { 33291 field.data( 'isset', 0 ); 33292 } 33293 } else if ( field.is( '.tmcp-select' ) ) {
33294 setter = field.find( 'option:selected' ); 33295 option_price = setter.data( noDpd + 'raw_price' ); 33296 option_price_taxed = setter.data( noDpd + 'price' ); 33297 option_original_price = setter.data( noDpd + 'raw_original_price' ); 33298 option_original_price_taxed = setter.data( noDpd + 'original_price' ); 33299 33300 options = field.children( 'option:selected' ); 33301 if ( ! ( options.val() === '' && options.attr( 'data-rulestype' ) === '' ) ) { 33302 showTotal = true; 33303 } 33304 33305 field.find( 'option' ).data( 'isset', 0 ); 33306 setter.data( 'isset', 1 ); 33307 33308 if ( ! ( setter.val() === '' && setter.attr( 'data-rulestype' ) === '' ) ) { 33309 _value = setter.attr( 'data-text' ); 33310 dofloatingBoxData = true; 33311 _valueText = _value; 33312 } 33313 } else if ( field.is( '.tmcp-selectmultiple' ) ) { 33314 setter = field.find( 'option:selected' ); 33315 setter.toArray().forEach( function( setterel ) { 33316 setterel = $( setterel ); 33317 option_price = option_price + $.epoAPI.math.toFloat( setterel.data( noDpd + 'raw_price' ) ); 33318 option_price_taxed = option_price_taxed + $.epoAPI.math.toFloat( setterel.data( noDpd + 'price' ) ); 33319 option_original_price = option_original_price + $.epoAPI.math.toFloat( setterel.data( noDpd + 'raw_original_price' ) ); 33320 option_original_price_taxed = option_original_price_taxed + $.epoAPI.math.toFloat( setterel.data( noDpd + 'original_price' ) ); 33321 33322 options = field.children( 'option:selected' ); 33323 if ( ! ( options.val() === '' && options.attr( 'data-rulestype' ) === '' ) ) { 33324 showTotal = true; 33325 } 33326 33327 field.find( 'option' ).data( 'isset', 0 ); 33328 setterel.data( 'isset', 1 ); 33329 33330 if ( ! ( setterel.val() === '' && setterel.attr( 'data-rulestype' ) === '' ) ) { 33331 _value = setterel.attr( 'data-text' ); 33332 dofloatingBoxData = true; 33333 _valueText = _value; 33334 } 33335 } ); 33336 } else { 33337 fieldval = field.val(); 33338 if ( field.is( "[type='file']" ) ) { 33339 fieldval = fieldval.replace( 'C:\\fakepath\\', '' ); 33340 } 33341 if ( fieldval ) { 33342 if ( field.is( '.tmcp-range' ) && fieldval === '0' ) { 33343 field.data( 'isset', 0 ); 33344 } else { 33345 option_price = field.data( noDpd + 'raw_price' ); 33346 option_price_taxed = field.data( noDpd + 'price' ); 33347 option_original_price = field.data( noDpd + 'raw_original_price' ); 33348 option_original_price_taxed = field.data( noDpd + 'original_price' ); 33349 showTotal = true; 33350 field.data( 'isset', 1 ); 33351 33352 _value = fieldval; 33353 if ( field.is( '.tmcp-range' ) ) { 33354 forrangepicker = field.closest( '.tmcp-field-wrap' ).find( '.tm-range-picker' ); 33355 $decimals = forrangepicker.attr( 'data-step' ).split( '.' ); 33356 if ( $decimals.length === 1 ) { 33357 $decimals = 0; 33358 } else { 33359 $decimals = $decimals[ 1 ].length; 33360 } 33361 _value = formatPrice( _value, { precision: $decimals } ); 33362 } 33363 dofloatingBoxData = true; 33364 if ( field.is( '.tmcp-dynamic' ) ) { 33365 field_label_show = 'hidden'; 33366 field_value_show = 'hidden'; 33367 } 33368 _valueText = fieldval; 33369 } 33370 } else { 33371 field.data( 'isset', 0 ); 33372 } 33373 } 33374 if ( ! option_price ) { 33375 option_price = 0; 33376 } 33377 if ( ! option_original_price ) { 33378 option_original_price = 0; 33379 } 33380 if ( ! option_price_taxed ) { 33381 option_price_taxed = 0; 33382 } 33383 if ( ! option_original_price_taxed ) { 33384 option_original_price_taxed = 0; 33385 } 33386 if ( dofloatingBoxData ) { 33387 floatingBoxData.push( { 33388 title: field_title, 33389 value: _value, 33390 valueText: _valueText, 33391 price: option_price_taxed, 33392 original_price: option_original_price_taxed, 33393 quantity: option_quantity, 33394 label_show: field_label_show, 33395 value_show: field_value_show, 33396 input_type: field.attr( 'type' ) 33397 } ); 33398 } 33399 if ( undefined !== cartQty && cartQty > 0 && field.is( '.tc-is-dnmpbq' ) ) { 33400 option_price = option_price / cartQty; 33401 } 33402 33403 option_price_taxed = tm_set_tax_price( option_price, currentTotalsContainer, field, undefined, undefined, undefined, true ); 33404 option_original_price_taxed = tm_set_tax_price( option_original_price, currentTotalsContainer, field, undefined, undefined, undefined, true ); 33405 33406 if ( setPriceTax ) { 33407 option_price = option_price_taxed; 33408 option_original_price = option_original_price_taxed; 33409 } 33410
33411 total = $.epoAPI.math.toFloat( total ) + $.epoAPI.math.toFloat( option_price ); 33412 total = $.epoAPI.math.toFloat( $.epoAPI.math.round( total, 10 ) ); 33413 original_total = $.epoAPI.math.toFloat( original_total ) + $.epoAPI.math.toFloat( option_original_price ); 33414 original_total = $.epoAPI.math.toFloat( $.epoAPI.math.round( original_total, 10 ) ); 33415 33416 total_taxed = $.epoAPI.math.toFloat( total_taxed ) + $.epoAPI.math.toFloat( option_price_taxed ); 33417 total_taxed = $.epoAPI.math.toFloat( $.epoAPI.math.round( total_taxed, 10 ) ); 33418 vat_total = vat_total + $.epoAPI.math.toFloat( calculateTaxAmount( option_price_taxed, currentTotalsContainer ) ); 33419 original_total_taxed = $.epoAPI.math.toFloat( original_total_taxed ) + $.epoAPI.math.toFloat( option_original_price_taxed ); 33420 original_total_taxed = $.epoAPI.math.toFloat( $.epoAPI.math.round( original_total_taxed, 10 ) ); 33421 33422 if ( cumulative ) { 33423 cumulativeTotal = total; 33424 } 33425 } 33426 } 33427 } ); 33428 } 33429 priceArray = { 33430 total: total, 33431 original_total: original_total, 33432 total_taxed: total_taxed, 33433 original_total_taxed: original_total_taxed, 33434 vat_total: vat_total, 33435 floatingBoxData: floatingBoxData, 33436 showTotal: showTotal, 33437 elementsLength: obj.length 33438 }; 33439 33440 if ( priceCache === true ) { 33441 priceCache = {}; 33442 priceCache[ priceCacheSelector ] = priceArray; 33443 } else if ( priceCache !== true && priceCache !== false ) { 33444 priceCache[ priceCacheSelector ] = priceArray; 33445 } 33446 33447 return priceArray; 33448 } 33449 33450 function show_product_html( thisEpoObject, thisMainProduct, thisVariableProductContainer, type, $this, currentCart, variableProductContainers, isTrigger, qtyalt ) { 33451 var epoObjectCopy = $.extend( true, {}, thisEpoObject ); 33452 var item_tm_extra_product_options = thisVariableProductContainer.find( tcAPI.associatedEpoSelector ); 33453 var item = thisVariableProductContainer; 33454 var newEpoObject; 33455 var showOnly = true; 33456 33457 $this.removeData( 'triggeredforced' ); 33458 33459 if ( item.closest( '.cpf-element' ).is( '.tc-hidden' ) ) { 33460 return; 33461 } 33462 33463 variableProductContainers.addClass( 'tm-hidden' ); 33464 if ( variableProductContainers.length ) { 33465 toggleState( variableProductContainers, true ); 33466 } 33467 33468 if ( type === 'variable' ) { 33469 if ( ! thisVariableProductContainer.is( '.tc-init-variations' ) ) { 33470 thisVariableProductContainer.addClass( 'variations_form' ); 33471 setTimeout( function() { 33472 newEpoObject = tm_init_epo( item, false, item_tm_extra_product_options.attr( 'data-product-id' ), item_tm_extra_product_options.attr( 'data-epo-id' ), $this, epoObjectCopy ); 33473 thisVariableProductContainer.addClass( 'tc-init-variations' ); 33474 thisVariableProductContainer.tc_product_variation_form( $this, currentCart, variableProductContainers, newEpoObject ); 33475 }, 40 ); 33476 showOnly = false; 33477 } else { 33478 thisVariableProductContainer.trigger( 'refresh.tc-variation-form' ); 33479 } 33480 } else if ( ! thisVariableProductContainer.is( '.tc-init-product' ) ) { 33481 thisVariableProductContainer.addClass( 'tc-init-product' ); 33482 variableProductContainers.find( '.tc-epo-element-variable-product' ).removeClass( 'variations_form' ); 33483 variableProductContainers.find( '.tc-epo-element-variations' ).removeClass( 'variations' ); 33484 33485 setTimeout( function() { 33486 tm_init_epo( item, false, item_tm_extra_product_options.attr( 'data-product-id' ), item_tm_extra_product_options.attr( 'data-epo-id' ), $this, epoObjectCopy ); 33487 }, 20 ); 33488 showOnly = false; 33489 } 33490 33491 setTimeout( function() { 33492 if ( variableProductContainers.length ) { 33493 toggleState( thisVariableProductContainer, false ); 33494 } 33495 thisVariableProductContainer 33496 .find( ':checkbox:checked, :radio:checked' ) 33497 .toArray().forEach( function( vpc ) { 33498 $( vpc ).closest( '.tmcp-field-wrap' ).addClass( 'tc-active' ); 33499 } ); 33500 }, 10 ); 33501 setTimeout( function() { 33502 if ( qtyalt.length ) { 33503 qtyalt.trigger( 'change' ); 33504 } 33505 if ( thisVariableProductContainer.find( tcAPI.epoSelector ).length === 0 ) { 33506 thisVariableProductContainer.addClass( 'no-epo' ); 33507 } 33508 thisVariableProductContainer.removeClass( 'tm-hidden' ); 33509 if ( showOnly ) { 33510 jWindow.trigger( 'cpflogicdone' ); 33511 thisVariableProductContainer.find( '.tm-quantity' ).trigger( 'showhide.cpfcustom' ); 33512 } 33513 if ( isTrigger === undefined && TMEPOJS.tm_epo_global_product_element_scroll === 'yes' ) { 33514 jWindow.tcScrollTo( thisVariableProductContainer, 200, $.epoAPI.math.toFloat
33514( TMEPOJS.tm_epo_global_product_element_scroll_offset ) ); 33515 } 33516 }, 210 ); 33517 } 33518 33519 function setQtyData( qtyElement, value ) { 33520 var data = qtyElement.data(); 33521 if ( value === undefined ) { 33522 value = qtyElement.val(); 33523 } 33524 if ( data ) { 33525 Object.keys( data ).filter( function( key ) { 33526 return key.indexOf( 'epopreviousvalue' ) === 0; 33527 } ).forEach( function( key ) { 33528 qtyElement.data( key, value ); 33529 } ); 33530 } 33531 } 33532 33533 function epoEventHandlers( epoObject, cartContainer, alternativeCart ) { 33534 // if cartContainer & alternativeCart is defined we are on a non default product (eg. composite product) 33535 var product_id = epoObject.product_id; 33536 var main_product = epoObject.main_product; 33537 var main_cart = epoObject.main_cart; 33538 var this_epo_container = epoObject.this_epo_container; 33539 var this_totals_container = epoObject.this_totals_container; 33540 var this_epo_totals_container = epoObject.this_epo_totals_container; 33541 var epoEventId = epoObject.epoEventId; 33542 var main_epo_inside_form = epoObject.main_epo_inside_form; 33543 var epo_id_selector = epoObject.epo_id_selector; 33544 var epo_id = epoObject.epo_id; 33545 var product_id_selector = epoObject.product_id_selector; 33546 var itemId = 'main'; 33547 var epoHolder; 33548 var totalsHolderContainer; 33549 var totalsHolder; 33550 var currentCart; 33551 var variation_id_selector; 33552 var this_product_type; 33553 var variationForm; 33554 var qtyElement; 33555 var finalTotalBoxMode; 33556 var finalTotalBoxShowFinal; 33557 var finalTotalBoxShowOptions; 33558 var eventName = epoObject.is_associated ? 'tc-variation-form' : 'wc-variation-form'; 33559 var eventNamePrefix = epoObject.is_associated ? 'tc_' : ''; 33560 var epoVariationSection; 33561 var thismaxlength; 33562 var epoFieldAll; 33563 var selectSelector; 33564 var epoFieldText; 33565 var epoResetRadio; 33566 var epoFieldUpload; 33567 var epoFieldHasClearButton; 33568 var tmQty; 33569 var tmQuantity; 33570 33571 // Non default product (eg. composite product) 33572 if ( alternativeCart && cartContainer ) { 33573 itemId = $.epoAPI.applyFilter( 'tc_get_item_id', cartContainer.attr( 'data-item_id' ), cartContainer ); 33574 epoHolder = main_product.find( '.tm-extra-product-options.tm-cart-' + itemId ); 33575 totalsHolderContainer = main_product.find( '.tm-totals-form-' + itemId ); 33576 totalsHolder = main_product.find( '.tm-epo-totals.tm-cart-' + itemId ); 33577 variationForm = cartContainer.find( '.variations_form' ).first(); 33578 // Default product 33579 } else { 33580 if ( ! main_cart || main_cart.length === 0 ) { 33581 if ( this_epo_container.is( '.tc-shortcode' ) ) { 33582 main_cart = main_product; 33583 } else { 33584 main_cart = get_main_cart( main_product, main_product, 'form', product_id ); 33585 } 33586 } 33587 cartContainer = main_cart.parent(); 33588 epoHolder = this_epo_container; 33589 totalsHolderContainer = this_totals_container; 33590 totalsHolder = this_epo_totals_container; 33591 variationForm = epoObject.variations_form; 33592 } 33593 33594 if ( epoObject.is_associated ) { 33595 itemId = epoHolder.attr( 'data-cart-id' ); 33596 } 33597 33598 currentCart = alternativeCart || main_cart; 33599 totalsHolder.data( 'tm_for_cart', currentCart ); 33600 33601 variation_id_selector = getVariationIdSelector( currentCart ); 33602 qtyElement = getQtyElement( currentCart ); 33603 33604 totalsHolder.data( 'variationIdElement', getVariationIdElement( currentCart, '.wceb_picker_wrap ' + variation_id_selector ) ); 33605 totalsHolder.data( 'qty_element', qtyElement ); 33606 33607 this_product_type = totalsHolder.data( 'type' ); 33608 33609 variationForm.data( 'tc_product_id', product_id ); 33610 33611 finalTotalBoxMode = totalsHolder.attr( 'data-tm-epo-final-total-box' ); 33612 finalTotalBoxShowFinal = totalsHolder.attr( 'data-tm-epo-show-final-total' ); 33613 finalTotalBoxShowOptions = totalsHolder.attr( 'data-tm-epo-show-options-total' ); 33614 33615 jWindow.trigger( 'epoEventHandlersStart', { 33616 epo: epoObject, 33617 cart: currentCart, 33618 alternativeCart: alternativeCart, 33619 cartContainer: cartContainer, 33620 totalsHolderContainer: totalsHolderContainer, 33621 totalsHolder: totalsHolder, 33622 epoHolder: epoHolder 33623 } ); 33624 33625 jWindow.on( 'epoCalculateRules', function( event, dataObject ) { 33626 if ( event && dataObject && dataObject.currentCart ) { 33627 tm_epo_rules( epoObject, dataObject.currentCart ); 33628 } 33629 } ); 33630 33631 if ( currentCart.is( 'form' ) ) { 33632 currentCart.on( 'reset', function() { 33633 var form = $( this ); 33634 setTimeout( function() { 33635 $( form.data( 'epo_id_selector' ) ).find( '.tm-epo-field' ).trigger( 'change' ); 33636 }, 1 ); 33637 } ); 33638 } 33639 33640 tm_epo_rules( epoObject, currentCart ); 33641 33642 epoFieldAll = epoHolder.find( '.tm-epo-field' ); 33643 if ( ! epoObject.is_associated ) { 33644 epoFieldAll = epoFieldAll.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-epo-field' ); 33645 } 33646 33647 epoFieldText = epoHolder.find( '.tm-epo-field.tmcp-textarea,.tm-epo-field.tmcp-textfield' ); 33648 if ( ! epoObject.is_associated ) { 33649 epoFieldText = epoFieldText.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-epo-field' ); 33650 } 33651 33652 epoResetRadio = epoHolder.find( '.tm-epo-reset-radio' ); 33653 if ( ! epoObject.is_associated ) { 33654 epoResetRadio = epoResetRadio.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-epo-reset-radio' ); 33655 } 33656 33657 epoFieldUpload = epoHolder.find( '.tm-epo-field.tmcp-upload' ); 33658 if ( ! epoObject.is_associated ) { 33659 epoFieldUpload = epoFieldUpload.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-epo-field.tmcp-upload' ); 33660 } 33661 33662 epoFieldHasClearButton = epoHolder.find( '.tm-has-clearbutton .tm-epo-field' ); 33663 if ( ! epoObject.is_associated ) { 33664 epoFieldHasClearButton = epoFieldHasClearButton.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-has-clearbutton .tm-epo-field' ); 33665 } 33666 33667 tmQty = epoHolder.find( '.tm-quantity .tm-qty' ); 33668 if ( ! epoObject.is_associated ) { 33669 tmQty = tmQty.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-quantity .tm-qty' ); 33670 } 33671 33672 tmQuantity = epoHolder.find( '.tm-quantity' ); 33673 if ( ! epoObject.is_associated ) { 33674 tmQuantity = tmQuantity.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-quantity' ); 33675 } 33676 33677 selectSelector = epoHolder.find( 'select.tm-epo-field' ); 33678 if ( ! epoObject.is_associated ) { 33679 selectSelector = selectSelector.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' select.tm-epo-field' ); 33680 } 33681 // update price amount for select elements 33682 selectSelector 33683 .off( 'tm-select-change-html' ) 33684 .on( 'tm-select-change-html', function() { 33685 var field = $( this ); 33686 var e_tip; 33687 var e_description; 33688 var sign; 33689 var formatted_price; 33690 33691 if ( field.is( '.tc-epo-field-product' ) || field.is( '.tmcp-selectmultiple' ) ) { 33692 return; 33693 } 33694 33695 if ( main_cart && main_cart.data( 'per_product_pricing' ) !== undefined && ! main_cart.data( 'per_product_pricing' ) ) { 33696 return; 33697 } 33698 33699 formatted_price = tm_set_price( field.find( 'option:selected' ).data( 'price' ), totalsHolder, true, field ); 33700 e_tip = field.closest( '.tmcp-field-wrap' ).find( '.tc-tooltip' ); 33701 e_description = field.closest( '.tmcp-field-wrap' ).find( '.tc-inline-description' ); 33702 33703 // Prices are already taxed 33704 tm_update_price( { 33705 epoObject: epoObject, 33706 obj: field.closest( '.tmcp-field-wrap' ).find( '.tc-price' ), 33707 price: field.find( 'option:selected' ).data( 'price' ), 33708 original_price: field.find( 'option:selected' ).data( 'original_price' ), 33709 force: false, 33710 useFormattedPrice: false 33711 } ); 33712 33713 if ( e_tip.length > 0 ) { 33714 e_tip.attr( 'data-tm-tooltip-html', field.find( 'option:selected' ).attr( 'data-tm-tooltip-html' ) ).trigger( 'tc-tooltip-html-changed' ); 33715 } 33716 33717 if ( e_description.length > 0 ) { 33718 if ( field.find( 'option:selected' ).attr( 'data-tm-tooltip-html' ) ) { 33719 e_description.html( field.find( 'option:selected' ).attr( 'data-tm-tooltip-html' ) ); 33720 } else { 33721 e_description.html( '' ); 33722 } 33723 } 33724 33725 if ( 33726 ( field.find( 'option:selected' ).attr( 'data-hide-amount' ) === '0' || TMEPOJS.tm_epo_show_price_inside_option_hidden_even === 'yes' ) && 33727 TMEPOJS.tm_epo_show_price_inside_option === 'yes' && 33728 field.find( 'option:selected' ).attr( 'data-text' ) && 33729 ( field.find( 'option:selected' ).data( 'price' ) || ( TMEPOJS.tm_epo_no_hide_price_if_original_not_zero === 'yes' && field.find( 'option:selected' ).data( 'original_price' ) ) ) 33730 ) { 33731 if ( 33732 ( TMEPOJS.tm_epo_auto_hide_price_if_zero === 'yes' && $.epoAPI.util.isEmpty( field.find( 'option:selected' ).data( 'price' ) ) === false ) || 33733 ( TMEPOJS.tm_epo_auto_hide_price_if_zero !== 'yes' && field.find( 'option:selected' ).attr( 'data-
33733price' ) !== '' ) 33734 ) { 33735 sign = ''; 33736 field.find( 'option:selected' ).html( field.find( 'option:selected' ).attr( 'data-text' ) + ' (' + sign + formatted_price + ')' ); 33737 } else { 33738 field.find( 'option:selected' ).html( field.find( 'option:selected' ).attr( 'data-text' ) ); 33739 } 33740 } 33741 33742 if ( field.val() === '' ) { 33743 e_tip.addClass( 'tm-hidden' ); 33744 } else if ( field.find( 'option:selected' ).attr( 'data-tm-tooltip-html' ) ) { 33745 e_tip.removeClass( 'tm-hidden' ); 33746 } else { 33747 e_tip.addClass( 'tm-hidden' ); 33748 } 33749 } ) 33750 .off( 'tm-math-select-change-html-all tm-select-change-html-all tm-select-change-html-all-math' ) 33751 .on( 'tm-math-select-change-html-all tm-select-change-html-all tm-select-change-html-all-math', function( event ) { 33752 var field = $( this ); 33753 var e_tip; 33754 var e_description; 33755 var divider; 33756 var thisformatted_price; 33757 33758 if ( field.is( '.tc-epo-field-product' ) ) { 33759 return; 33760 } 33761 33762 e_tip = field.closest( '.tmcp-field-wrap' ).find( '.tc-tooltip' ); 33763 e_description = field.closest( '.tmcp-field-wrap' ).find( '.tc-inline-description' ); 33764 33765 if ( e_tip.length > 0 ) { 33766 e_tip.attr( 'data-tm-tooltip-html', field.find( 'option:selected' ).attr( 'data-tm-tooltip-html' ) ).trigger( 'tc-tooltip-html-changed' ); 33767 } 33768 33769 if ( field.val() === '' ) { 33770 e_tip.addClass( 'tm-hidden' ); 33771 } else if ( field.find( 'option:selected' ).attr( 'data-tm-tooltip-html' ) ) { 33772 e_tip.removeClass( 'tm-hidden' ); 33773 } else { 33774 e_tip.addClass( 'tm-hidden' ); 33775 } 33776 33777 if ( e_description.length > 0 ) { 33778 if ( field.find( 'option:selected' ).attr( 'data-tm-tooltip-html' ) ) { 33779 e_description.html( field.find( 'option:selected' ).attr( 'data-tm-tooltip-html' ) ); 33780 } else { 33781 e_description.html( '' ); 33782 } 33783 } 33784 33785 if ( main_cart && main_cart.data( 'per_product_pricing' ) !== undefined && ! main_cart.data( 'per_product_pricing' ) ) { 33786 return; 33787 } 33788 33789 if ( TMEPOJS.tm_epo_show_price_inside_option === 'yes' ) { 33790 field.find( 'option' ).toArray().forEach( function( thisoption ) { 33791 thisoption = $( thisoption ); 33792 if ( ! thisoption.val() ) { 33793 return true; 33794 } 33795 33796 if ( event.type === 'tm-select-change-html-all' ) { 33797 thisoption.removeClass( 'tm-epo-late-field' ).removeData( 'tm-price-for-late islate' ); 33798 tm_element_epo_rules( epoObject, field, undefined, thisoption, 1 ); 33799 } else if ( event.type === 'tm-math-select-change-html-all' ) { 33800 tm_element_epo_rules( epoObject, field, undefined, thisoption, 1, true ); 33801 } else if ( event.type === 'tm-select-change-html-all-math' ) { 33802 thisoption.removeClass( 'tm-epo-late-field' ).removeData( 'tm-price-for-late islate' ); 33803 tm_element_epo_rules( epoObject, field, undefined, thisoption, 1, true ); 33804 } 33805 divider = 1; 33806 33807 if ( TMEPOJS.tm_epo_multiply_price_inside_option !== 'yes' ) { 33808 divider = field.data( 'tm-quantity' ); 33809 } 33810 33811 if ( ! divider ) { 33812 divider = 1; 33813 } 33814 33815 if ( ( TMEPOJS.tm_epo_auto_hide_price_if_zero === 'yes' && $.epoAPI.util.isEmpty( thisoption.data( 'price' ) ) === false ) || ( TMEPOJS.tm_epo_auto_hide_price_if_zero !== 'yes' && thisoption.attr( 'data-price' ) !== '' ) ) { 33816 thisformatted_price = tm_set_price( thisoption.data( 'price' ) / divider, totalsHolder, true, field ); 33817 33818 if ( ( thisoption.attr( 'data-hide-amount' ) === '0' || TMEPOJS.tm_epo_show_price_inside_option_hidden_even === 'yes' ) && thisoption.attr( 'data-text' ) ) { 33819 thisoption.html( thisoption.attr( 'data-text' ) + ' (' + thisformatted_price + ')' ); 33820 } 33821 } else { 33822 thisoption.html( thisoption.attr( 'data-text' ) ); 33823 } 33824 } ); 33825 } 33826 } ) 33827 .off( 'tm-select-price-update-html-all' ) 33828 .on( 'tm-select-price-update-html-all', function() { 33829 var field = $( this ); 33830 var divider; 33831 var thisformatted_price; 33832 33833 if ( field.is( '.tc-epo-field-product' ) ) { 33834 return; 33835 } 33836 33837 if ( main_cart && main_cart.data( 'per_product_pricing' ) !== undefined && ! main_cart.data( 'per_product_pricing' ) ) { 33838 return; 33839 } 33840 33841 if ( TMEPOJS.tm_epo_show_price_inside_option === 'yes' ) {
33842 field.find( 'option' ).toArray().forEach( function( thisoption ) { 33843 thisoption = $( thisoption ); 33844 if ( ! thisoption.val() ) { 33845 return true; 33846 } 33847 33848 divider = 1; 33849 33850 if ( TMEPOJS.tm_epo_multiply_price_inside_option !== 'yes' ) { 33851 divider = field.data( 'tm-quantity' ); 33852 } 33853 33854 if ( ! divider ) { 33855 divider = 1; 33856 } 33857 33858 if ( ( TMEPOJS.tm_epo_auto_hide_price_if_zero === 'yes' && $.epoAPI.util.isEmpty( thisoption.data( 'price' ) ) === false ) || ( TMEPOJS.tm_epo_auto_hide_price_if_zero !== 'yes' && thisoption.attr( 'data-price' ) !== '' ) ) { 33859 thisformatted_price = tm_set_price( thisoption.data( 'price' ) / divider, totalsHolder, true, field ); 33860 33861 if ( ( thisoption.attr( 'data-hide-amount' ) === '0' || TMEPOJS.tm_epo_show_price_inside_option_hidden_even === 'yes' ) && thisoption.attr( 'data-text' ) ) { 33862 thisoption.html( thisoption.attr( 'data-text' ) + ' (' + thisformatted_price + ')' ); 33863 } 33864 } else { 33865 thisoption.html( thisoption.attr( 'data-text' ) ); 33866 } 33867 } ); 33868 } 33869 } ) 33870 .off( 'tm-select-change' ) 33871 .on( 'tm-select-change', function() { 33872 var field = $( this ); 33873 var thisElementId = field.closest( '.cpf-element' ).attr( 'data-uniqid' ); 33874 33875 if ( field.is( '.tc-epo-field-product' ) ) { 33876 return; 33877 } 33878 33879 if ( main_cart && main_cart.data( 'per_product_pricing' ) !== undefined && ! main_cart.data( 'per_product_pricing' ) ) { 33880 return; 33881 } 33882 33883 field.removeData( 'addedtcEpoBeforeOptionPriceCalculation' ); 33884 field.removeData( 'addedfieldtcEpoBeforeOptionPriceCalculation' ); 33885 jWindow.off( 'tcEpoBeforeOptionPriceCalculation.math' + thisElementId ); 33886 jWindow.off( 'tcEpoAfterNormalOptionPriceCalculation.math' + thisElementId ); 33887 33888 field.trigger( 'tm-select-change-html' ); 33889 field.trigger( 'tm-select-change-html-all' ); 33890 33891 currentCart.trigger( { 33892 type: 'tm-epo-update', 33893 norules: 1, 33894 element: field 33895 } ); 33896 } ).trigger( 'tm-select-change-html-all' ); 33897 33898 // Element quantity selector 33899 tmQty 33900 .off( 'focus.cpf' ) 33901 .on( 'focus.cpf', function() { 33902 var qtyField = $( this ); 33903 var field = qtyField.closest( '.tmcp-field-wrap' ).find( '.tm-epo-field' ); 33904 var currentVal = parseFloat( qtyField.val() ); 33905 var max = parseFloat( qtyField.attr( 'max' ) ); 33906 var min = parseFloat( qtyField.attr( 'min' ) ); 33907 var step = qtyField.attr( 'step' ); 33908 var check1 = tm_limit_c_selection( field, false ); 33909 var check2 = tm_exact_c_selection( field, false ); 33910 var check3 = true; 33911 33912 // Format values 33913 if ( ! currentVal || currentVal === '' || currentVal === 'NaN' ) { 33914 currentVal = 0; 33915 } 33916 if ( max === '' || max === 'NaN' ) { 33917 max = ''; 33918 } 33919 if ( min === '' || min === 'NaN' ) { 33920 min = 0; 33921 } 33922 if ( step === 'any' || step === '' || step === undefined || parseFloat( step ) === 'NaN' ) { 33923 step = 1; 33924 } 33925 33926 if ( currentVal < min || currentVal > max ) { 33927 check3 = false; 33928 } 33929 33930 if ( check1 && check2 && check3 ) { 33931 setQtyData( qtyField, currentVal ); 33932 } else { 33933 setQtyData( qtyField, min ); 33934 } 33935 } ) 33936 .off( 'change.cpf' ) 33937 .on( 'change.cpf', function( event, data ) { 33938 var qtyField = $( this ); 33939 var field = qtyField.closest( '.tmcp-field-wrap' ).find( '.tm-epo-field' ); 33940 var currentVal = parseFloat( qtyField.val() ); 33941 var max = parseFloat( qtyField.attr( 'max' ) ); 33942 var min = parseFloat( qtyField.attr( 'min' ) ); 33943 var step = qtyField.attr( 'step' ); 33944 var check1 = tm_limit_c_selection( field, false ); 33945 var check2 = tm_exact_c_selection( field, false ); 33946 var check3 = true; 33947 33948 // Format values 33949 if ( ! currentVal || currentVal === '' || currentVal === 'NaN' ) { 33950 currentVal = 0; 33951 } 33952 if ( max === '' || max === 'NaN' ) { 33953 max = ''; 33954 } 33955 if ( min === '' || min === 'NaN' ) { 33956 min = 0; 33957 } 33958 if ( step === 'any' || step === '' || step === undefined || parseFloat( step ) === 'NaN' ) { 33959 step = 1; 33960 } 33961 33962 if ( currentVal < min || currentVal > max ) { 33963 check3 = false; 33964 } 33965 33966 if ( check1 && check2 && check3 ) { 33967 if ( ! epoObject.noEpoUpdate ) { 33968 field.data( 'tm-quantity', qtyField.val() ).trigger( 'change', data ); 33969 } else { 33970 field.data( 'tm-quantity', qtyField.val() ).trigger( 'change.cpf', data ).trigger( 'change.cpfproduct', data ); 33971 } 33972 field.trigger( 'tm-select-change-html-all' ); 33973 } else if ( qtyField.data( 'epopreviousvalue' ) ) { 33974 qtyField.val( qtyField.data( 'epopreviousvalue' ) ); 33975 } else { 33976 qtyField.val( min ); 33977 } 33978 33979 qtyField.trigger( 'cpf-changed' ); 33980 } ) 33981 .off( 'tmaddquantity' ) 33982 .on( 'tmaddquantity', function() { 33983 var qtyField = $( this ); 33984 var field = qtyField.closest( '.tmcp-field-wrap' ).find( '.tm-epo-field' ); 33985 33986 field.data( 'tm-quantity', qtyField.val() ); 33987 } ); 33988 33989 // Insert characters remaining for text-areas and text-fields 33990 thismaxlength = epoHolder.find( '.tmcp-textfield.tm-epo-field[maxlength],textarea.tm-epo-field[maxlength]' ); 33991 if ( ! epoObject.is_associated ) { 33992 thismaxlength = thismaxlength.not( tcAPI.epoSelector + ' ' + tcAPI.associatedEpoSelector + ' .tm-epo-field' ); 33993 } 33994
33995 thismaxlength.toArray().forEach( function( field ) { 33996 var innerWrap; 33997 var html; 33998 field = $( field ); 33999 if ( field.data( 'tcmaxlength' ) ) { 34000 return; 34001 } 34002 field.data( 'tcmaxlength', 1 ); 34003 innerWrap = field.closest( '.tmcp-field-wrap-inner' ); 34004 html = $.epoAPI.template.html( tcAPI.templateEngine.tc_chars_remanining, { 34005 maxlength: field.attr( 'maxlength' ), 34006 characters_remaining: TMEPOJS.i18n_characters_remaining 34007 } ); 34008 innerWrap.append( $( html ) ); 34009 } ); 34010 thismaxlength 34011 .off( 'change.tc_maxlen input.tc_maxlen' ) 34012 .on( 'change.tc_maxlen input.tc_maxlen', function() { 34013 var field = $( this ); 34014 34015 field 34016 .closest( '.tmcp-field-wrap' ) 34017 .find( '.tc-chars-remanining' ) 34018 .html( parseInt( field.attr( 'maxlength' ), 10 ) - parseInt( field.val().length, 10 ) ); 34019 } ); 34020 34021 // Change product image event 34022 epoFieldAll 34023 .off( 'tm_trigger_product_image' ) 34024 .on( 'tm_trigger_product_image', function() { 34025 var field = $( this ); 34026 var currentElement; 34027 var uic; 34028 var variation_element_section; 34029 var is_variation_element; 34030 var src; 34031 34032 if ( field.is( '.tm-product-image:checkbox, .tm-product-image:radio, select.tm-product-image' ) ) { 34033 uic = field.closest( '.tmcp-field-wrap' ).find( 'label img' ); 34034 variation_element_section = field.closest( '.cpf-section' ); 34035 is_variation_element = variation_element_section.is( '.tm-epo-variation-section' ); 34036 34037 currentElement = field; 34038 if ( field.is( 'select.tm-product-image' ) ) { 34039 currentElement = field.children( 'option:selected' ); 34040 } 34041 if ( 34042 $( uic ).length > 0 || 34043 ( is_variation_element && currentElement.attr( 'data-image' ) !== undefined ) || 34044 ( currentElement.attr( 'data-image' ) !== undefined && currentElement.attr( 'data-image' ) !== '' ) || 34045 ( currentElement.attr( 'data-imagep' ) !== undefined && currentElement.attr( 'data-imagep' ) !== '' ) 34046 ) { 34047 if ( field.is( ':checked' ) || ( field.is( 'select.tm-product-image' ) && field.val() !== '' && ( field.find( 'option:selected' ).attr( 'data-rules' ) !== '' || field.is( '.tm-epo-variation-element' ) ) ) ) { 34048 src = $( uic ).first().attr( 'data-original' ); 34049 34050 if ( ! src && ! is_variation_element ) { 34051 src = $( uic ).first().attr( 'src' ); 34052 } 34053 if ( ! src ) { 34054 src = currentElement.attr( 'data-image' ); 34055 } 34056 if ( currentElement.attr( 'data-imagep' ) ) { 34057 src = currentElement.attr( 'data-imagep' ); 34058 } 34059 if ( src ) { 34060 main_product.trigger( 'tm_change_product_image', { 34061 src: src, 34062 element: field, 34063 element_current: currentElement, 34064 main_product: main_product, 34065 epo_holder: epoHolder 34066 } ); 34067 } else { 34068 main_product.trigger( 'tm_change_product_image', { 34069 src: false, 34070 element: field, 34071 element_current: currentElement, 34072 main_product: main_product, 34073 epo_holder: epoHolder 34074 } ); 34075 } 34076 } else { 34077 main_product.trigger( 'tm_restore_product_image', { 34078 element: field, 34079 element_current: currentElement, 34080 main_product: main_product, 34081 epo_holder: epoHolder 34082 } ); 34083 } 34084 } else { 34085 main_product.trigger( 'tm_restore_product_image', { 34086 element: field, 34087 element_current: currentElement, 34088 main_product: main_product, 34089 epo_holder: epoHolder 34090 } ); 34091 } 34092 } else { 34093 main_product.trigger( 'tm_attempt_product_image', { 34094 element: field, 34095 element_current: currentElement, 34096 main_product: main_product, 34097 epo_holder: epoHolder 34098 } ); 34099 } 34100 } ); 34101 34102 tmQuantity 34103 .off( 'showhide.cpfcustom' ) 34104 .on( 'showhide.cpfcustom', function() { 34105 var quantity_selector = $( this ); 34106 var field = quantity_selector.closest( '.tmcp-field-wrap' ).find( '.tm-epo-field' ); 34107 var show = false; 34108 var tmqty; 34109 var tmqtyval; 34110 var tmqtymin; 34111 var radios; 34112 var tmqtybuttons; 34113 34114 if ( ! field.is( '.tm-epo-variation-element' ) ) { 34115 if ( field.is( 'select' ) ) { 34116 if ( field.val() !== '' ) { 34117 show = true; 34118 } 34119 } else if ( field.is( ':checkbox' ) ) { 34120 if ( field.is( ':checked' ) ) { 34121 show = true; 34122 } 34123 } else if ( field.is( ':radio' ) ) { 34124 if ( field.is( ':checked' ) ) { 34125 show = true; 34126 if ( TMEPOJS.tm_epo_show_only_active_quantities === 'yes' ) { 34127 radios = field.closest( '.tc-element-inner-wrap' ).find( '.tm-epo-field.tmcp-radio' );
34128 radios.toArray().forEach( function( rd ) { 34129 $( rd ).closest( '.tmcp-field-wrap' ).find( '.tm-quantity' ).hide(); 34130 } ); 34131 } 34132 } 34133 } else if ( field.val() ) { 34134 show = true; 34135 } 34136 34137 tmqty = quantity_selector.find( '.tm-qty' ); 34138 tmqtybuttons = quantity_selector.find( '.tc-qty-button' ); 34139 tmqtyval = tmqty.val(); 34140 tmqtymin = tmqty.attr( 'min' ) || ''; 34141 34142 if ( show ) { 34143 if ( TMEPOJS.tm_epo_show_only_active_quantities === 'yes' ) { 34144 quantity_selector.show(); 34145 } 34146 34147 tmqty.removeClass( 'ignore' ).prop( 'disabled', false ); 34148 tmqtybuttons.prop( 'disabled', false ); 34149 } else { 34150 if ( TMEPOJS.tm_epo_show_only_active_quantities === 'yes' ) { 34151 quantity_selector.hide(); 34152 if ( ! tmqtyval ) { 34153 tmqty.val( tmqtymin ); 34154 } 34155 } 34156 34157 tmqty.addClass( 'ignore' ).prop( 'disabled', true ); 34158 tmqtybuttons.prop( 'disabled', true ); 34159 } 34160 34161 if ( epoHolder.is( '.tc-show' ) ) { 34162 setTimeout( function() { 34163 quantity_selector.closest( '.tcowl-carousel' ).trigger( 'refresh.owl.carousel' ); 34164 }, 200 ); 34165 } 34166 } 34167 } ); 34168 34169 epoFieldAll 34170 .off( 'change.cpfcustom' ) 34171 .on( 'change.cpfcustom', function() { 34172 $( this ).closest( '.tmcp-field-wrap' ).find( '.tm-quantity' ).trigger( 'showhide.cpfcustom' ); 34173 } ); 34174 34175 epoFieldAll 34176 .off( 'change.cpf' ) 34177 .on( 'change.cpf', function( event, data ) { 34178 var field = $( this ); 34179 var is_li = field.closest( '.tmcp-field-wrap' ); 34180 var is_ul = field.closest( '.tmcp-ul-wrap' ); 34181 var is_replace; 34182 var connector = is_ul.attr( 'data-tm-connector' ); 34183 34184 if ( field.is( ':checkbox, :radio' ) ) { 34185 if ( field.is( ':radio' ) ) { 34186 if ( ! data ) { 34187 if ( connector !== undefined ) { 34188 $( '[data-tm-connector="' + connector + '"]' ).find( '.tmcp-field-wrap' ).removeClass( 'tc-active' ).find( '.tm-epo-reset-radio' ).addClass( 'tm-hidden' ); 34189 } else { 34190 is_ul.find( '.tmcp-field-wrap' ).removeClass( 'tc-active' ); 34191 } 34192 } 34193 if ( connector !== undefined ) { 34194 $( '[data-tm-connector="' + connector + '"]' ).find( '.tmcp-field-wrap' ).removeClass( 'tc-active' ).find( '.tm-epo-reset-radio' ).addClass( 'tm-hidden' ); 34195 } 34196 } 34197 if ( field.is( ':checked' ) ) { 34198 is_li.addClass( 'tc-active' ); 34199 } else { 34200 is_li.removeClass( 'tc-active' ); 34201 } 34202 } 34203 34204 if ( ! field.is( '.tm-epo-variation-element' ) ) { 34205 if ( field.is( '.use_images:checkbox, .use_images:radio' ) && field.attr( 'data-imagec' ) ) { 34206 is_replace = is_li.find( '.radio-image,.checkbox-image' ).first(); 34207 if ( is_replace.length > 0 ) { 34208 if ( field.is( ':checked' ) ) { 34209 is_replace.prop( 'src', field.attr( 'data-imagec' ) ); 34210 } else { 34211 is_replace.prop( 'src', field.attr( 'data-image' ) ); 34212 } 34213 } 34214 } 34215 34216 if ( field.is( '.use_images:radio' ) && ! data ) { 34217 field 34218 .closest( '.cpf-type-radio' ) 34219 .find( '.use_images:radio' ) 34220 .not( field ) 34221 .toArray().forEach( function( r ) { 34222 r = $( r ); 34223 r.closest( '.tmcp-field-wrap' ).find( '.radio-image' ).first().prop( 'src', r.attr( 'data-image' ) ); 34224 } ); 34225 } 34226 34227 if ( field.is( '.tmcp-range' ) ) { 34228 field.trigger( 'change.cpflogic' ); 34229 } 34230 if ( field.is( 'select' ) ) { 34231 field.trigger( 'tm-select-change' ); 34232 } else { 34233 if ( field.is( '.tmcp-radio' ) ) { 34234 field 34235 .closest( '.cpf-element' ) 34236 .find( '.tm-quantity .tm-qty' ) 34237 .toArray().forEach( function( tmqty ) { 34238 tmqty = $( tmqty ); 34239 if ( ! tmqty.closest( 'li.tmcp-field-wrap' ).find( '.tmcp-radio' ).is( ':checked' ) ) { 34240 tmqty.attr( 'disabled', 'disabled' ); 34241 } else { 34242 tmqty.prop( 'disabled', false ); 34243 } 34244 } ); 34245 } 34246 priceCache = true; 34247 currentCart.trigger( { 34248 type: 'tm-epo-update', 34249 norules: 1, 34250 element: field 34251 } ); 34252 priceCache = false; 34253 } 34254 } 34255 34256 field.trigger( 'tm_trigger_product_image' ); 34257 34258 if ( epoHolder.is( '.tc-show' ) ) { 34259 setTimeout( function() {
34260 $( '.tm-owl-slider' ).toArray().forEach( function( slider ) { 34261 $( slider ).trigger( 'refresh.owl.carousel' ); 34262 } ); 34263 }, 200 ); 34264 } 34265 main_product.trigger( 'tm_attempt_product_image', { 34266 element: field, 34267 main_product: main_product, 34268 epo_holder: epoHolder 34269 } ); 34270 } ); 34271 34272 epoFieldAll.filter( '.tm-epo-field:text,input.tm-epo-field[type="number"],textarea.tm-epo-field' ) 34273 .off( 'input.cpf' ) 34274 .on( 'input.cpf', function() { 34275 $( this ).trigger( 'change.cpf', { autoload: 1 } ); 34276 } ); 34277 34278 epoFieldAll 34279 .filter( ':checkbox:checked, :radio:checked' ) 34280 .toArray().forEach( function( cb ) { 34281 $( cb ) 34282 .closest( '.tmcp-field-wrap' ) 34283 .addClass( 'tc-active' ) 34284 .trigger( 'change.cpf', { autoload: 1 } ); 34285 } ); 34286 34287 epoFieldHasClearButton 34288 .off( 'change.cpfclearbutton' ) 34289 .on( 'change.cpfclearbutton cpfclearbutton', function() { 34290 var field = $( this ); 34291 var radioResetElement; 34292 var fieldWrap = field.closest( '.tmcp-field-wrap' ); 34293 var fieldSearch; 34294 34295 if ( field.is( ':checked' ) ) { 34296 fieldSearch = field.closest( '.tc-element-inner-wrap' ); 34297 34298 if ( fieldSearch.find( '.tc-epo-element-product-li-container' ).length ) { 34299 fieldSearch = fieldSearch.find( '.tmcp-ul-wrap' ).first().children( '.tmcp-field-wrap' ).not( '.tc-epo-element-product-li-container' ); 34300 } 34301 34302 radioResetElement = fieldSearch.find( '.tm-epo-reset-radio' ); 34303 if ( ! radioResetElement.length ) { 34304 radioResetElement = field.closest( '.tc-element-inner-wrap' ).find( '.tm-epo-reset-radio' ).first(); 34305 } 34306 radioResetElement.removeClass( 'tm-hidden' ); 34307 34308 fieldWrap.append( radioResetElement ); 34309 } 34310 } ); 34311 34312 epoResetRadio 34313 .off( 'click.cpf' ) 34314 .on( 'click.cpf', function() { 34315 var radioResetElement = $( this ); 34316 var fieldContainer = radioResetElement.closest( '.tc-element-inner-wrap' ); 34317 var checkedRadios = fieldContainer.find( '.tm-epo-field.tmcp-radio:checked' ); 34318 34319 if ( checkedRadios.length ) { 34320 checkedRadios.prop( 'checked', false ); 34321 checkedRadios.trigger( 'change', { forced: 1 } ); 34322 } 34323 34324 radioResetElement.addClass( 'tm-hidden' ); 34325 } ); 34326 34327 if ( _ && _.debounce ) { 34328 epoFieldText.on( 'keyup', 34329 _.debounce( function() { 34330 var $this = $( this ); 34331 var mainform = currentCart; 34332 if ( epoObject.is_associated ) { 34333 mainform = epoObject.mainEpoObject.form; 34334 } 34335 34336 if ( TMEPOJS.tm_epo_global_enable_validation === 'yes' && $.tc_validator && $this.closest( '.tmcp-ul-wrap' ).data( 'tm-validation' ) && $this.tc_rules() ) { 34337 mainform.tc_validate().element( $this ); 34338 } 34339 $this.trigger( 'change.cpf' ); 34340 $this.closest( '.tmcp-field-wrap' ).find( '.tm-quantity' ).trigger( 'showhide.cpfcustom' ); 34341 }, 10 ) 34342 ); 34343 } 34344 34345 epoFieldUpload 34346 .off( 'change.cpfv tcupload' ) 34347 .on( 'change.cpfv tcupload', function() { 34348 var field = $( this ); 34349 var label = field.closest( 'label' ); 34350 var li = field.closest( '.tmcp-field-wrap' ); 34351 var cpfUploadContainer = li.find( '.cpf-upload-container' ); 34352 var name = li.find( '.tm-filename' ); 34353 var val = field.val().replace( 'C:\\fakepath\\', '' ); 34354 var valHidden = []; 34355 var num_uploads; 34356 var windowURL = window.URL || window.webkitURL; 34357 var files; 34358 var image; 34359 var uploadPreview = li.find( '.tc-upload-preview' ); 34360 var addImage; 34361 var uniqid; 34362 34363 if ( cpfUploadContainer.length && name.length <= 0 ) { 34364 name = $( '<span class="tm-filename"></span>' ); 34365 label.after( name ); 34366 } 34367 if ( val === undefined || val === 'undefined' ) { 34368 val = ''; 34369 } 34370 34371 field.next( '.tmcp-upload-hidden' ).remove(); 34372 34373 valHidden = field.attr( 'data-file' ); 34374 valHidden = valHidden ? valHidden.split( '|' ) : []; 34375 if ( this.files ) { 34376 files = Array.from( this.files ); 34377 } else if ( valHidden.length > 0 ) { 34378 files = valHidden; 34379 } 34380 34381 if ( files.length > 1 ) { 34382 name.html( '' + files.length + ' ' + ( files.length === 1 ? TMEPOJS.i18n_file : TMEPOJS.i18n_files ) ); 34383 } else if ( files.length === 1 ) { 34384 name.html( val ); 34385 } else { 34386 name.empty(); 34387 } 34388 if ( ! uploadPreview.length ) { 34389 uploadPreview = $( '<div class="tc-upload-preview tc-hidden"></div>' ); 34390 li.append( uploadPreview ); 34391 } 34392 34393 uploadPreview.empty(); 34394 34395 num_uploads = epoHolder.data( 'num_uploads' ); 34396 if ( ! num_uploads ) { 34397 num_uploads = []; 34398 } 34399 uniqid = field.closest( '.cpf-element' ).attr( 'data-uniqid' ); 34400 if ( ! num_uploads[ uniqid ] ) { 34401 num_uploads[ uniqid ] = []; 34402 } 34403 34404 if ( ( val || files.length > 0 ) && windowURL && windowURL.createObjectURL ) { 34405 if ( TMEPOJS.tm_epo_upload_inline_image_preview === 'yes' ) { 34406 if ( files.length > 1 ) { 34407 uploadPreview.addClass( 'multiple' ); 34408 } else { 34409 uploadPreview.removeClass( 'multiple' ); 34410 } 34411 uploadPreview.removeClass( 'tc-hidden' ); 34412 } 34413 addImage = function( dataFile, src, i, fileHolder, ext ) { 34414 var size = field[ 0 ].files && field[ 0 ].files[ i ] && field[ 0 ].files[ i ].size ? field[ 0 ].files[ i ].size : 0; 34415 var imageHTML = '<div class="tc-upload-image">'; 34416 if ( src ) { 34417 imageHTML = imageHTML + '<img src="' + src + '">'; 34418 } else { 34419 imageHTML = imageHTML + '<div class="tc-file-ext-overlay"></div>'; 34420 } 34421 imageHTML = imageHTML + '<div class="tc-file-name">' + dataFile.name + '</div>'; 34422 if ( ClipboardEvent || DataTransfer ) { 34423 imageHTML = imageHTML + '<button type="button" class="tc-upload-remove"><svg width="26" height="26" viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg"><path d="M11.586 13l-2.293 2.293a1 1 0 0 0 1.414 1.414L13 14.414l2.293 2.293a1 1 0 0 0 1.414-1.414L14.414 13l2.293-2.293a1 1 0 0 0-1.414-1.414L13 11.586l-2.293-2.293a1 1 0 0 0-1.414 1.414L11.586 13z" fill="currentColor" fill-rule="nonzero"/></svg></button>'; 34424 } 34425 if ( ext ) { 34426 imageHTML = imageHTML + '<div class="tc-file-ext">' + ext + '</div>'; 34427 } 34428 imageHTML = imageHTML + '<div class="tc-file-size">' + readableFileSize( size ) + '</div>'; 34429 imageHTML = imageHTML + '</div>'; 34430 fileHolder.append( imageHTML ); 34431 }; 34432
34433 files.forEach( function( dataFile, i ) { 34434 var fileHolder; 34435 if ( TMEPOJS.tm_epo_upload_inline_image_preview === 'yes' ) { 34436 fileHolder = $( '<div class="tc-upload-file"></div>' ); 34437 uploadPreview.append( fileHolder ); 34438 image = new Image(); 34439 image.onload = function() { 34440 addImage( dataFile, this.src, i, fileHolder ); 34441 }; 34442 image.onerror = function() { 34443 addImage( dataFile, false, i, fileHolder, dataFile.name.split( '.' ).pop() ); 34444 }; 34445 if ( valHidden.length > 0 ) { 34446 image.src = valHidden[ i ]; 34447 } else { 34448 image.src = windowURL.createObjectURL( dataFile ); 34449 windowURL.revokeObjectURL( dataFile ); 34450 } 34451 } 34452 num_uploads[ uniqid ].push( dataFile.name ); 34453 } ); 34454 epoHolder.data( 'num_uploads', num_uploads ); 34455 } else { 34456 delete num_uploads[ uniqid ]; 34457 } 34458 if ( num_uploads[ uniqid ] && num_uploads[ uniqid ].length === 0 ) { 34459 delete num_uploads[ uniqid ]; 34460 } 34461 } ); 34462 34463 jDocument.on( 'click', '.tc-upload-remove', function() { 34464 var $this = $( this ); 34465 var val; 34466 var cpfElement; 34467 var input; 34468 var fileWrap; 34469 var li; 34470 var uploadPreview; 34471 var name; 34472 var index; 34473 var files; 34474 var dT; 34475 var num_uploads; 34476 var uniqid; 34477 var uploadHidden; 34478 var dataFiles; 34479 34480 if ( ClipboardEvent || DataTransfer ) { 34481 cpfElement = $this.closest( '.cpf-element' ); 34482 input = cpfElement.find( '.tm-epo-field' ); 34483 fileWrap = $this.closest( '.tc-upload-file' ); 34484 li = $this.closest( '.tmcp-field-wrap' ); 34485 uploadPreview = li.find( '.tc-upload-preview' ); 34486 name = li.find( '.tm-filename' ); 34487 index = fileWrap.index(); 34488 val = input.val().replace( 'C:\\fakepath\\', '' ); 34489 if ( val === undefined || val === 'undefined' ) { 34490 val = ''; 34491 } 34492 34493 files = Array.from( input[ 0 ].files ); 34494 files.splice( index, 1 ); 34495 dT = new ClipboardEvent( '' ).clipboardData || new DataTransfer(); 34496 34497 files.forEach( function( dataFile ) { 34498 dT.items.add( dataFile ); 34499 } ); 34500 34501 if ( files.length > 1 ) { 34502 uploadPreview.addClass( 'multiple' ); 34503 } else { 34504 uploadPreview.removeClass( 'multiple' ); 34505 } 34506 34507 input[ 0 ].files = dT.files; 34508 fileWrap.remove(); 34509 if ( dT.files.length > 1 ) { 34510 name.html( '' + dT.files.length + ' ' + ( dT.files.length === 1 ? TMEPOJS.i18n_file : TMEPOJS.i18n_files ) ); 34511 } else if ( dT.files.length === 1 ) { 34512 name.html( val ); 34513 } else { 34514 name.empty(); 34515 } 34516 34517 num_uploads = epoHolder.data( 'num_uploads' ); 34518 if ( ! num_uploads ) { 34519 num_uploads = []; 34520 } 34521 uniqid = cpfElement.closest( '.cpf-element' ).attr( 'data-uniqid' ); 34522 if ( ! num_uploads[ uniqid ] ) { 34523 num_uploads[ uniqid ] = []; 34524 } 34525 34526 num_uploads[ uniqid ].splice( index, 1 ); 34527 if ( num_uploads[ uniqid ].length === 0 ) { 34528 delete num_uploads[ uniqid ]; 34529 input.val( '' ); 34530 } 34531 34532 uploadHidden = input.next( '.tmcp-upload-hidden' ); 34533 if ( uploadHidden.length ) { 34534 dataFiles = uploadHidden.val().split( '|' ); 34535 if ( dataFiles.length > 0 ) { 34536 dataFiles.splice( index, 1 ); 34537 } 34538 if ( dataFiles.length === 0 ) { 34539 uploadHidden.remove(); 34540 } else { 34541 uploadHidden.val( dataFiles.join( '|' ) ); 34542 } 34543 } 34544 34545 epoHolder.data( 'num_uploads', num_uploads ); 34546 } 34547 } ); 34548 34549 qtyElement 34550 .off( 'change.cpf input.cpf' ) 34551 .on( 'change.cpf input.cpf', function() { 34552 var field = $( this ); 34553 34554 currentCart.trigger( 'tm-epo-check-dpd' ); 34555 setQtyData( field ); 34556 // It is required than when you update the product quantity 34557 // to recalculate the option price to accommodate price types 34558 // that depend on quantity 34559 currentCart.trigger( { 34560 type: 'tm-epo-update', 34561 norules: 2 34562 } ); 34563 } ); 34564 setQtyData( qtyElement ); 34565 // Support for math formula on associated products when they are initially hidden 34566 epoHolder 34567 .find( '.cpf-type-product' ) 34568 .off( 'tc-logic' ) 34569 .on( 'tc-logic', function() { 34570 var $this = $( this ); 34571 if ( $this.find( '.tc-init' ).length ) { 34572 return; 34573 } 34574 if ( $this.data( 'isactive' ) && ! $this.data( 'donetclogic' ) ) { 34575 $this.data( 'donetclogic', true ); 34576 $this.find( '.tc-epo-field-product' ).trigger( 'change.cpfproduct', { forced: 3 } ); 34577 } 34578 } ); 34579 34580 // Product element checkbox required status fix 34581 epoHolder 34582 .find( '.cpf-type-product .tc-epo-field-product.tc-epo-field-product-checkbox' ) 34583 .off( 'change.cpfrequired' ) 34584 .on( 'change.cpfrequired', function() { 34585 var $this = $( this ); 34586 var cpfElement = $this.closest( '.cpf-element' ); 34587 var checkboxes; 34588 var checkboxesChecked; 34589 var checkboxesNotChecked; 34590 if ( cpfElement.is( '.tc-is-required' ) ) { 34591 checkboxes = cpfElement.find( '.tmcp-field.tc-epo-field-product-checkbox' ); 34592 checkboxesNotChecked = checkboxes.not( ':checked' ); 34593 checkboxesChecked = cpfElement.find( '.tmcp-field.tc-epo-field-product-checkbox:checked' ); 34594 34595 if ( checkboxesChecked.length > 0 ) { 34596 checkboxesNotChecked.prop( 'required', false ); 34597 checkboxesChecked.prop( 'required', true ); 34598 } else { 34599 checkboxes.attr( 'required', true ); 34600 checkboxes.prop( 'required', true ); 34601 } 34602 } 34603 } ); 34604 34605 // Product element variable product support 34606 epoHolder 34607 .find( '.cpf-type-product .tc-epo-field-product' ) 34608 .off( 'change.cpfproduct' ) 34609 .on( 'change.cpfproduct', function( e, data ) { 34610 var $this = $( this ); 34611 var value; 34612 var type; 34613 var selected; 34614 var variableProductContainers; 34615 var thisVariableProductContainer; 34616 var elementContainer = $this.closest( '.cpf-element' );
34617 var productContainerWraps = elementContainer.find( '.tc-epo-element-product-container-wrap' ); 34618 var thisProductContainerWrap = $this.closest( '.tmcp-field-wrap' ).find( '.tc-epo-element-product-container-wrap' ); 34619 var hasProductContainerWrap = thisProductContainerWrap.length > 0; 34620 var postData; 34621 var skip = false; 34622 var isTrigger = 1000; 34623 var qtyalt; 34624 var associatedSetter = $this; 34625 var associatedElement; 34626 var isFilled; 34627 var productPrice; 34628 var originalProductPrice; 34629 var epoField = elementContainer.find( '.tm-epo-field' ).not( '.tc-epo-element-product-li-container .tm-epo-field' ); 34630 var checked = epoField.filter( ':checked' ); 34631 var qty; 34632 var counter = $this.attr( 'data-counter' ); 34633 34634 if ( false === elementContainer.data( 'isactive' ) ) { 34635 return; 34636 } 34637 if ( data && data.forced === 2 ) { 34638 return; 34639 } 34640 34641 if ( e.isTrigger !== undefined && $this.data( 'triggeredonce' ) && ! ( data && data.forced ) ) { 34642 return; 34643 } 34644 34645 if ( $this.data( 'triggeredforced' ) === 3 ) { 34646 return; 34647 } 34648 34649 $this.data( 'triggeredonce', 1 ); 34650 34651 if ( ! $this.is( ':checkbox' ) ) { 34652 isTrigger = e.isTrigger; 34653 } 34654 34655 if ( epoField.is( ':radio' ) ) { 34656 if ( checked.length > 0 ) { 34657 qty = checked.closest( '.tmcp-field-wrap' ).find( 'input.tm-qty' ); 34658 } 34659 } else if ( epoField.is( ':checkbox' ) ) { 34660 if ( checked.length > 0 ) { 34661 qty = $this.closest( '.tmcp-field-wrap' ).find( 'input.tm-qty' ); 34662 } 34663 } else { 34664 qty = epoField.closest( '.tmcp-field-wrap' ).find( 'input.tm-qty' ); 34665 } 34666 34667 if ( $this.is( ':checkbox' ) ) { 34668 if ( $this.is( '.tc-epo-field-product-hidden' ) ) { 34669 if ( $this.is( ':checked' ) ) { 34670 productContainerWraps.addClass( 'tc-active-product' ); 34671 } else { 34672 productContainerWraps.removeClass( 'tc-active-product' ); 34673 } 34674 34675 value = $this.val(); 34676 type = $this.attr( 'data-type' ); 34677 elementContainer.find( '.tc-epo-element-product-li-container:not(.tc-hidden-container .tc-epo-element-product-li-container)' ).removeClass( 'tm-hidden' ); 34678 } else { 34679 if ( ! $this.is( ':checked' ) ) { 34680 if ( hasProductContainerWrap ) { 34681 thisProductContainerWrap.addClass( 'tm-hidden' ); 34682 } 34683 if ( ! ( data && data.forced ) ) { 34684 return; 34685 } 34686 skip = true; 34687 } else if ( hasProductContainerWrap ) { 34688 thisProductContainerWrap.removeClass( 'tm-hidden' ); 34689 } 34690 if ( ! skip ) { 34691 value = $this.val(); 34692 type = $this.attr( 'data-type' ); 34693 elementContainer.find( '.tc-epo-element-product-li-container:not(.tc-hidden-container .tc-epo-element-product-li-container)' ).removeClass( 'tm-hidden' ); 34694 } 34695 } 34696 } else if ( $this.is( ':radio' ) ) { 34697 if ( ! $this.is( ':checked' ) ) { 34698 if ( hasProductContainerWrap ) { 34699 thisProductContainerWrap.addClass( 'tm-hidden' ); 34700 } 34701 if ( ! ( data && data.forced ) ) { 34702 return; 34703 } 34704 skip = true; 34705 } else if ( hasProductContainerWrap ) { 34706 productContainerWraps.addClass( 'tm-hidden' ); 34707 thisProductContainerWrap.removeClass( 'tm-hidden' ); 34708 } 34709 if ( ! skip ) { 34710 value = $this.val(); 34711 type = $this.attr( 'data-type' ); 34712 elementContainer.find( '.tc-epo-element-product-li-container:not(.tc-hidden-container .tc-epo-element-product-li-container)' ).removeClass( 'tm-hidden' ); 34713 } 34714 } else if ( $this.is( 'select' ) ) { 34715 selected = $this.children( ':selected' ); 34716 associatedSetter = selected; 34717 counter = selected.index(); 34718 if ( $this.children( ':first' ).val() === '' ) { 34719 counter--; 34720 } 34721 value = $this.val(); 34722 type = selected.attr( 'data-type' ); 34723 elementContainer.find( '.tc-epo-element-product-li-container:not(.tc-hidden-container .tc-epo-element-product-li-container)' ).removeClass( 'tm-hidden' ); 34724 } 34725 34726 if ( $this.is( '.tc-epo-field-product-checkbox' ) ) { 34727 variableProductContainers = thisProductContainerWrap.find( '.tc-epo-element-product-container' ); 34728 } else { 34729 variableProductContainers = elementContainer.find( '.tc-epo-element-product-container' ); 34730 } 34731 34732 thisVariableProductContainer = variableProductContainers.filter( '[data-product_id="' + value + '"]' ); 34733 34734 qtyalt = thisVariableProductContainer.find( tcAPI.associateQtySelector ); 34735
34736 if ( productContainerWraps.html() !== '' && qty && qty.length > 0 && qtyalt.length === 0 ) { 34737 qty.val( 0 ); 34738 } 34739 if ( $this.is( ':checkbox' ) ) { 34740 if ( $this.is( '.tc-epo-field-product-hidden' ) ) { 34741 if ( $this.is( ':checked' ) ) { 34742 if ( qtyalt.val() === '0' ) { 34743 if ( qtyalt.attr( 'min' ) !== '0' ) { 34744 qtyalt.val( qtyalt.attr( 'min' ) ).trigger( 'change' ); 34745 } 34746 } 34747 } else { 34748 qtyalt.val( 0 ); 34749 qtyalt.closest( '.tm-quantity-alt' ).removeClass( 'tm-hidden' ); 34750 if ( data.forced !== 1 ) { 34751 qtyalt.closest( '.tm-quantity-alt' ).find( '.single_add_to_cart_product' ).trigger( 'cpfqtybutton' ); 34752 } 34753 productContainerWraps.find( tcAPI.associatedEpoCart ).trigger( 'tm-epo-update' ); 34754 } 34755 } 34756 } else if ( $this.is( ':radio' ) ) { 34757 if ( $this.val() && ! $this.data( 'set_initial' ) ) { 34758 if ( qtyalt.val() === '0' ) { 34759 if ( qtyalt.attr( 'min' ) !== '0' ) { 34760 qtyalt.val( qtyalt.attr( 'min' ) ).trigger( 'change' ); 34761 } 34762 $this.data( 'set_initial', 1 ); 34763 } 34764 } 34765 } else if ( $this.is( 'select' ) ) { 34766 if ( $this.val() && ! $this.data( 'set_initial' ) ) { 34767 if ( qtyalt.val() === '0' ) { 34768 if ( qtyalt.attr( 'min' ) !== '0' ) { 34769 qtyalt.val( qtyalt.attr( 'min' ) ).trigger( 'change' ); 34770 } 34771 $this.data( 'set_initial', 1 ); 34772 } 34773 } 34774 } else { 34775 return; 34776 } 34777 34778 if ( ! value ) { 34779 variableProductContainers.addClass( 'tm-hidden' ); 34780 productPrice = $.epoAPI.util.parseJSON( associatedSetter.attr( 'data-rules' ) ); 34781 productPrice = productPrice[ 0 ] || 0; 34782 originalProductPrice = $.epoAPI.util.parseJSON( associatedSetter.attr( 'data-original-rules' ) ); 34783 originalProductPrice = originalProductPrice || 0; 34784 if ( associatedSetter.is( '.tcenabled' ) ) { 34785 associatedSetter.data( 'associated_price_set', 1 ); 34786 } 34787 associatedSetter.data( 'price_set', 1 ); 34788 associatedSetter.data( 'raw_price', productPrice ); 34789 associatedSetter.data( 'raw_original_price', originalProductPrice ); 34790 associatedSetter.data( 'price', productPrice ); 34791 associatedSetter.data( 'original_price', originalProductPrice ); 34792 34793 associatedElement = associatedSetter; 34794 if ( associatedElement.is( 'option' ) ) { 34795 associatedElement = associatedSetter.closest( 'select' ); 34796 } 34797 isFilled = false; 34798 if ( associatedElement.is( '.tc-epo-field-product' ) ) { 34799 if ( associatedElement.is( 'select' ) ) { 34800 if ( associatedElement.val() !== '' ) { 34801 isFilled = true; 34802 } 34803 } else if ( ( associatedElement.is( ':checkbox' ) || associatedElement.is( ':radio' ) ) ) { 34804 if ( associatedElement.is( ':checked' ) ) { 34805 isFilled = true; 34806 } 34807 } else if ( associatedElement.val() !== '' ) { 34808 isFilled = true; 34809 } 34810 } 34811 tm_force_update_price( 34812 epoObject, 34813 associatedSetter 34814 .closest( '.tmcp-field-wrap' ) 34815 .find( '.tc-price' ) 34816 .not( tcAPI.associatedEpoSelector + ' .tc-price' ), 34817 productPrice, 34818 isFilled ? tm_set_price_totals( productPrice ) : associatedSetter.data( 'price-html' ), 34819 originalProductPrice, 34820 ! isFilled 34821 ); 34822 34823 qtyElement.trigger( 'change.cpf' ); 34824 34825 return; 34826 } 34827 34828 if ( thisVariableProductContainer.length === 0 ) { 34829 if ( data && data.forced === 3 ) { 34830 $this.data( 'triggeredforced', 3 ); 34831 } 34832 // parent_id is used for customization purposes. 34833 postData = { 34834 action: 'wc_epo_get_associated_product_html', 34835 product_id: value, 34836 parent_id: epoHolder.attr( 'data-product-id' ), 34837 mode: elementContainer.attr( 'data-mode' ), 34838 layout_mode: elementContainer.attr( 'data-product-layout-mode' ), 34839 uniqid: elementContainer.attr( 'data-uniqid' ), 34840 name: $this.attr( 'name' ), 34841 counter: counter, 34842 quantity_min: elementContainer.attr( 'data-quantity-min' ), 34843 quantity_max: elementContainer.attr( 'data-quantity-max' ), 34844 priced_individually: elementContainer.attr( 'data-priced-individually' ), 34845 discount: elementContainer.attr( 'data-discount' ), 34846 discount_type: elementContainer.attr( 'data-discount-type' ), 34847 discount_exclude_addons: elementContainer.attr( 'data-discount-exclude-
34847addons' ), 34848 show_image: elementContainer.attr( 'data-show-image' ), 34849 show_title: elementContainer.attr( 'data-show-title' ), 34850 show_title_link: elementContainer.attr( 'data-show-title-link' ), 34851 show_price: elementContainer.attr( 'data-show-price' ), 34852 show_description: elementContainer.attr( 'data-show-description' ), 34853 show_meta: elementContainer.attr( 'data-show-meta' ), 34854 disable_epo: elementContainer.attr( 'data-disable-epo' ) 34855 }; 34856 34857 elementContainer.block( { message: null, overlayCSS: { background: '#fff', opacity: 0.6 } } ); 34858 $.ajax( { 34859 url: TMEPOJS.ajax_url, 34860 type: 'POST', 34861 data: postData, 34862 dataType: 'json', 34863 success: function( response ) { 34864 if ( response.result === 200 ) { 34865 thisVariableProductContainer = $( response.html ); 34866 if ( hasProductContainerWrap ) { 34867 $this.closest( '.tmcp-field-wrap' ).find( '.tc-epo-element-product-container-wrap' ).empty().append( thisVariableProductContainer ); 34868 } else { 34869 elementContainer.find( '.tc-epo-element-product-container-wrap' ).append( thisVariableProductContainer ); 34870 } 34871 show_product_html( epoObject, main_product, thisVariableProductContainer, type, $this, currentCart, variableProductContainers, isTrigger, qtyalt ); 34872 thisVariableProductContainer.find( tcAPI.associateQtySelector ).trigger( 'change' ); 34873 jWindow.trigger( 'tc_apply_validation' ); 34874 } 34875 }, 34876 complete: function() { 34877 elementContainer.unblock(); 34878 } 34879 } ); 34880 } else { 34881 show_product_html( epoObject, main_product, thisVariableProductContainer, type, $this, currentCart, variableProductContainers, isTrigger, qtyalt ); 34882 thisVariableProductContainer.find( tcAPI.associateQtySelector ).trigger( 'change' ); 34883 } 34884 } ); 34885 34886 jDocument 34887 .off( 'click.cpfqtybutton cpfqtybutton', '.cpf-type-product .single_add_to_cart_product' ) 34888 .on( 'click.cpfqtybutton cpfqtybutton', '.cpf-type-product .single_add_to_cart_product', function() { 34889 var $this = $( this ); 34890 var qtyalt = $this.closest( '.tm-quantity-alt' ).find( tcAPI.associateQtySelector ); 34891 var isAdd = $this.is( '.alt' ); 34892 var productContainerWraps = $this.closest( '.cpf-element' ).find( '.tc-epo-element-product-container-wrap' ); 34893 var qtyMin; 34894 var qtyMax; 34895 34896 if ( $this.data( 'inittriggeredonce' ) ) { 34897 qtyMin = $.epoAPI.math.toInt( qtyalt.attr( 'data-min' ) ); 34898 qtyMax = $.epoAPI.math.toInt( qtyalt.attr( 'data-max' ) ); 34899 if ( isAdd ) { 34900 productContainerWraps.addClass( 'tc-active-product' ); 34901 qtyalt.attr( 'min', qtyMin ); 34902 if ( qtyMax ) { 34903 qtyalt.attr( 'max', qtyMax ); 34904 } 34905 if ( qtyalt.val() === '0' ) { 34906 if ( qtyalt.attr( 'min' ) === '0' ) { 34907 qtyalt.val( 1 ).trigger( 'change' ); 34908 } else { 34909 qtyalt.val( qtyalt.attr( 'min' ) ).trigger( 'change' ); 34910 } 34911 } 34912 $this.removeClass( 'alt' ).text( $this.attr( 'data-remove' ) ); 34913 } else { 34914 productContainerWraps.removeClass( 'tc-active-product' ); 34915 qtyalt.val( 0 ).trigger( 'change' ); 34916 qtyalt.closest( '.tm-quantity-alt' ).removeClass( 'tm-hidden' ); 34917 $this.addClass( 'alt' ).text( $this.attr( 'data-add' ) ); 34918 } 34919 } 34920 34921 $this.data( 'inittriggeredonce', 1 ); 34922 34923 productContainerWraps.find( tcAPI.associatedEpoCart ).trigger( 'tm-epo-update' ); 34924 } ); 34925 34926 jDocument 34927 .off( 'change.cpfqtyalt input.cpfqtyalt', '.cpf-type-product ' + tcAPI.associateQtySelector ) 34928 .on( 'change.cpfqtyalt input.cpfqtyalt', '.cpf-type-product ' + tcAPI.associateQtySelector, function() { 34929 var $this = $( this ); 34930 var epoField = $this.closest( '.cpf-element' ).find( '.tm-epo-field' ).not( '.tc-epo-element-product-li-container .tm-epo-field' ); 34931 var addButton = $this.closest( '.tm-quantity-alt' ).find( '.single_add_to_cart_product' ); 34932 var checked = epoField.filter( ':checked' ); 34933 var qty; 34934 var qtyMin; 34935 var qtyMax; 34936 var associatedEpoCart; 34937 34938 qtyMin = $.epoAPI.math.toInt( $this.attr( 'min' ) ); 34939 qtyMax = $.epoAPI.math.toInt( $this.attr( 'max' ) ); 34940 34941 if ( epoField.is( '.tc-epo-field-product-hidden' ) && epoField.is( ':checkbox' ) ) { 34942 if ( checked.length === 0 && $this.val() !== '0' ) { 34943 epoField.prop( 'checked', true ).trigger( 'change' ); 34944 checked = epoField.filter( ':checked' ); 34945 } else if ( $this.val() === '0' && checked.length ) { 34946 epoField.prop( 'checked', false ).trigger( 'change' ); 34947 } 34948 } 34949 34950 if ( epoField.is( ':radio' ) ) { 34951 if ( checked.length === 0 ) { 34952 return; 34953 }
34954 qty = checked.closest( '.tmcp-field-wrap' ).find( 'input.tm-qty' ).not( '.tc-element-qty' ); 34955 } else if ( epoField.is( ':checkbox' ) ) { 34956 if ( checked.length === 0 ) { 34957 return; 34958 } 34959 qty = $this.closest( '.tmcp-field-wrap' ).find( 'input.tm-qty' ).not( '.tc-element-qty' ); 34960 } else { 34961 qty = epoField.closest( '.tmcp-field-wrap' ).find( 'input.tm-qty' ).not( '.tc-element-qty' ); 34962 } 34963 34964 if ( qty.length === 0 ) { 34965 return; 34966 } 34967 34968 qty.attr( 'min', qtyMin ); 34969 if ( qtyMax ) { 34970 qty.attr( 'max', qtyMax ); 34971 } 34972 associatedEpoCart = $this.closest( '.tc-epo-element-product-container' ).find( tcAPI.associatedEpoCart ); 34973 associatedEpoCart.trigger( 'tm-epo-update' ); 34974 34975 qty.val( $this.val() ); 34976 34977 if ( $.epoAPI.math.toFloat( $this.val() ) > 0 ) { 34978 associatedEpoCart.find( '.tm-epo-field.tcenabled' ).removeClass( 'ignore' ); 34979 $this.removeClass( 'ignore' ); 34980 } else { 34981 associatedEpoCart.find( '.tm-epo-field.tcenabled' ).addClass( 'ignore' ); 34982 $this.addClass( 'ignore' ); 34983 } 34984 epoField.trigger( 'change.cpfproduct', { forced: 2 } ); 34985 if ( addButton.data( 'inittriggeredonce' ) ) { 34986 if ( $this.val() === '0' ) { 34987 addButton.removeClass( 'alt' ); 34988 } else { 34989 addButton.addClass( 'alt' ); 34990 } 34991 } 34992 addButton.trigger( 'cpfqtybutton' ); 34993 } ); 34994 34995 jDocument 34996 .off( 'click.cbsmel' ) 34997 .on( 'click.cbsmel', '.tc-choice-button-selector', function( e ) { 34998 var $field = $( this ).closest( '.tmcp-field-wrap' ).find( '.tm-epo-field' ); 34999 e.stopPropagation(); 35000 if ( $field.length ) { 35001 $field.trigger( 'click' ); 35002 } 35003 } ); 35004 35005 // Global update event 35006 currentCart.off( 'tm-epo-update' ).on( 'tm-epo-update', function( event ) { 35007 var cart = $( this ); 35008 var bundleid; 35009 var productPrice = false; 35010 var rawProductPrice = 0; 35011 var productRegularPrice = false; 35012 var rawProductRegularPrice = 0; 35013 var total = 0; 35014 var original_total = 0; 35015 var showTotal = false; 35016 var cartQty; 35017 var elementQty = 1; 35018 var priceOverrideMode; 35019 var perProductPricing = true; 35020 var floatingBoxData = []; 35021 var currentVariation; 35022 var cart_fee_options_total = 0; 35023 var cart_fee_options_original_total = 0; 35024 var _total; 35025 var _original_total; 35026 var late_total_price; 35027 var tc_totals_ob = {}; 35028 var formatted_options_total; 35029 var formatted_options_original_total; 35030 var formatted_fees_total; 35031 var formatted_fees_original_total; 35032 var formatted_final_total; 35033 var formatted_final_original_total; 35034 var extraFee = 0; 35035 var raw_extraFee = 0; 35036 var product_total_price; 35037 var product_total_original_price; 35038 var calculateFinalProductPrice; 35039 var total_plus_fee; 35040 var original_total_plus_fee; 35041 var product_total_price_without_options; 35042 var unit_price; 35043 var unit_original_price; 35044 var formatted_unit_price; 35045 var formatted_unit_original_price; 35046 var html; 35047 var show_options_total = false; 35048 var show_vat_options_total = false; 35049 var show_fees_total = false; 35050 var formatted_extra_fee = ''; 35051 var show_extra_fee = false; 35052 var show_final_total = false; 35053 var hide_native_price; 35054 var update_native_html; 35055 var _fprice; 35056 var _f_regular_price; 35057 var customerPriceFormat; 35058 var currentEpoObject; 35059 var raw_total; 35060 var raw__total; 35061 var raw_original_total; 35062 var raw__original_total; 35063 var raw_cart_fee_options_total; 35064 var raw_cart_fee_options_original_total; 35065 var raw_total_plus_fee; 35066 var raw_original_total_plus_fee; 35067 var raw_product_total_price_without_options; 35068 var raw_product_total_price; 35069 var raw_product_total_original_price; 35070 var fetch; 35071 var customer_price_format_wrap_start = ''; 35072 var customer_price_format_wrap_end = ''; 35073 var associatedSetter; 35074 var associatedPrice; 35075 var associatedRawPrice; 35076 var associatedOriginalPrice; 35077 var associatedRawOriginalPrice; 35078 var associatedFormattedPrice; 35079 var nativeProductPriceSelector; 35080 var elementsLength; 35081 var productFieldSyncVatTotal = 0; 35082 var productFieldSyncTotal = 0; 35083 var productFieldSyncOriginalTotal = 0; 35084 var productFieldSyncTotalTaxed = 0; 35085 var productFieldSyncOriginalTotalTaxed = 0; 35086 var totalProductField = 0; 35087 var originalTotalProductField = 0; 35088 var totalProductFieldTaxed = 0; 35089 var originalTotalProductFieldTaxed = 0; 35090 var _ftotal; 35091 var _foriginal_total; 35092 var totalsHolder_tc_totals_ob; 35093 var temp; 35094 var vat_options_total; 35095 var vat_options_total_plus_fee; 35096 var formatted_vat_options_total; 35097 var formatted_vat_options_total_plus_fee; 35098 var vat_total; 35099 var formatted_vat_total; 35100 var vat_product_base; 35101 var formatted_vat_product_base; 35102 var pricesIncludeTax; 35103 var dynamicCheck; 35104 var dynamicProductPrice = 0; 35105 35106 if ( event.epoObject ) { 35107 currentEpoObject = $.extend( true, {}, event.epoObject ); 35108 } else { 35109 currentEpoObject = $.extend( true, {}, epoObject ); 35110 } 35111 35112 if ( ! currentEpoObject ) { 35113 return; 35114 } 35115 35116 if ( currentEpoObject.noEpoUpdate ) { 35117 return; 35118 } 35119 35120 jWindow.trigger( 'tcEpoUpdateStart', { 35121 epo: currentEpoObject, 35122 alternativeCart: currentEpoObject, 35123 this_product_type: this_product_type, 35124 cart: cart, 35125 totalsHolder: totalsHolder, 35126 fetchOptionPrices: fetchOptionPrices, 35127 epoHolder: epoHolder 35128 } ); 35129 35130 bundleid = $.epoAPI.applyFilter( 'tc_get_bundleid', cart.attr( 'data-
35130product_id' ), cart, currentEpoObject ); 35131 priceOverrideMode = totalsHolder.attr( 'data-price-override' ); 35132 cartQty = getCurrentQty( cart ); 35133 currentVariation = getCurrentVariation( cart ); 35134 35135 if ( currentEpoObject.associated_connect && currentEpoObject.associated_connect.length === 1 ) { 35136 cartQty = parseFloat( 35137 currentEpoObject.main_product 35138 .find( tcAPI.associateQtySelector ) 35139 .not( tcAPI.associatedEpoSelector + ' ' + tcAPI.qtySelector ) 35140 .last() 35141 .val() 35142 ); 35143 } 35144 35145 event.stopImmediatePropagation(); 35146 35147 productPrice = $.epoAPI.applyFilter( 'tcGetCurrentProductPrice', tm_calculate_product_price( totalsHolder, true ), currentCart, totalsHolder ); 35148 35149 rawProductPrice = productPrice; 35150 35151 productRegularPrice = $.epoAPI.applyFilter( 'tcGetCurrentProductRegularPrice', tm_calculate_product_regular_price( totalsHolder, true ), currentCart, totalsHolder ); 35152 35153 rawProductRegularPrice = productRegularPrice; 35154 35155 productPrice = $.epoAPI.applyFilter( 'tcCalculateCurrentProductPrice', productPrice, { 35156 epo: currentEpoObject, 35157 alternativeCart: alternativeCart, 35158 cart: cart, 35159 main_product: main_product 35160 } ); 35161 35162 if ( ! Number.isFinite( cartQty ) || totalsHolder.attr( 'data-is-sold-individually' ) || getQtyElement( cart ).length === 0 ) { 35163 cartQty = 1; 35164 } 35165 if ( TMEPOJS.tm_epo_total_price_as_unit_price === 'yes' ) { 35166 cartQty = 1; 35167 } 35168 35169 // needed for inital math calculation 35170 totalsHolder_tc_totals_ob = { 35171 qty: cartQty, 35172 product_price: rawProductPrice, 35173 original_product_price: rawProductRegularPrice 35174 }; 35175 totalsHolder.data( 'totalsHolder_tc_totals_ob', totalsHolder_tc_totals_ob ); 35176 35177 if ( ! event.norules ) { 35178 tm_epo_rules( currentEpoObject, cart ); 35179 } else if ( event.norules ) { 35180 if ( event.norules === 1 ) { 35181 tm_element_epo_rules( currentEpoObject, event.element ); 35182 } 35183 $.tcepo.lateFieldsPrices[ epoEventId ] = []; 35184 35185 epoHolder 35186 .find( '.tm-epo-late-field' ) 35187 .toArray() 35188 .forEach( function( setter ) { 35189 setter = $( setter ); 35190 setter.data( 'price', 0 ); 35191 $.tcepo.lateFieldsPrices[ epoEventId ].push( { 35192 setter: setter, 35193 price: setter.data( 'tm-price-for-late' ), 35194 original_price: setter.data( 'tm-original-price-for-late' ), 35195 bundleid: bundleid, 35196 pricetype: get_type( currentEpoObject, setter, 'price_type' ) 35197 } ); 35198 } ); 35199 } 35200 35201 // Check for dynamic elements. 35202 dynamicCheck = epoHolder.find( '.tmcp-dynamic.dynamic-product-price:not(.tc-is-math-special, .tc-is-math-cumulative)' ); 35203 if ( currentEpoObject.is_associated === false ) { 35204 dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.dynamic-product-price:not(.tc-is-math-special, .tc-is-math-cumulative)' ); 35205 } 35206 dynamicCheck = dynamicCheck.filter( '.tcenabled' ); 35207 if ( dynamicCheck.length > 0 ) { 35208 fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-dynamic.dynamic-product-price:not(.tc-is-math-special, .tc-is-math-cumulative)', 0, 0, floatingBoxData, showTotal, undefined, undefined, undefined, true, undefined, undefined, cartQty ); 35209 productPrice = fetch.total; 35210 dynamicProductPrice = productPrice; 35211 rawProductRegularPrice = fetch.original_total; 35212 rawProductPrice = dynamicProductPrice; 35213 productRegularPrice = dynamicProductPrice; 35214 totalsHolderContainer.find( '.cpf-dynamic-product-price' ).val( dynamicProductPrice ); 35215 totalsHolder_tc_totals_ob.dynamic_product_price = dynamicProductPrice; 35216 totalsHolder.data( 'totalsHolder_tc_totals_ob', totalsHolder_tc_totals_ob ); 35217 } 35218 35219 if ( currentEpoObject.associated_connect && currentEpoObject.associated_connect.length === 1 ) { 35220 associatedSetter = currentEpoObject.associated_connect; 35221 if ( currentEpoObject.associated_connect.is( 'select' ) ) { 35222 associatedSetter = currentEpoObject.associated_connect.find( 'option:selected' ); 35223 } 35224 } 35225 35226 // No reason to continue if the product price is invalid 35227 if ( productPrice === false ) { 35228 totalsHolder.data( 'tm-floating-box-data', [] ); 35229 totalsHolder.empty(); 35230 if ( currentEpoObject.associated_connect && currentEpoObject.associated_connect.length === 1 ) { 35231 tm_force_update_price( 35232 epoObject, 35233 associatedSetter 35234 .closest( '.tmcp-field-wrap' ) 35235 .find( '.tc-price' ) 35236 .not( tcAPI.associatedEpoSelector + ' .tc-price' ), 35237 0, 35238 '', 35239 0 35240 ); 35241 } 35242 main_cart.trigger( 'tm-epo-short-update', { 35243 container: cartContainer 35244 } ); 35245 return; 35246 } 35247 35248 elementQty = $.epoAPI.applyFilter( 'tcAlterElementQty', elementQty, { 35249 epo: currentEpoObject, 35250 alternativeCart: alternativeCart, 35251 currentCart: currentCart, 35252 main_product: main_product 35253 } ); 35254 35255 if ( currentCart.data( 'per_product_pricing' ) !== undefined ) { 35256 perProductPricing = currentCart.data( 'per_product_pricing' ); 35257 } 35258 35259 perProductPricing = $.epoAPI.applyFilter( 'tcCalculatePerProductPricing', perProductPricing, { 35260 epo: currentEpoObject, 35261 alternativeCart: alternativeCart, 35262 cart: cart, 35263 main_product: main_product 35264 } ); 35265 35266 if ( main_epo_inside_form && TMEPOJS.tm_epo_totals_box_placement === 'woocommerce_before_add_to_cart_button' ) { 35267 if ( ( this_product_type === 'variable' || this_product_type === 'variable-subscription' ) && ! totalsHolder.data( 'moved_inside' ) ) { 35268 totalsHolder.data( 'moved_inside', 1 ); 35269 } 35270 } 35271 35272 jWindow.trigger( 'tcEpoBeforeOptionPriceCalculation', { 35273 epo: currentEpoObject, 35274 alternativeCart: currentEpoObject, 35275 this_product_type: this_product_type, 35276 cart: cart, 35277 totalsHolder: totalsHolder, 35278 fetchOptionPrices: fetchOptionPrices, 35279 epoHolder: epoHolder, 35280 total: total, 35281 original_total: original_total, 35282 floatingBoxData: floatingBoxData, 35283 showTotal: showTotal, 35284 cart_fee_options_total: cart_fee_options_total, 35285 cart_fee_options_original_total: cart_fee_options_original_total 35286 } ); 35287 35288 if ( ! currentEpoObject.associated_connect && ! event.noassociated ) { 35289 if ( TMEPOJS.tm_epo_global_product_element_quantity_sync === 'yes' && ! cart.is( $.tcAPI().associatedEpoCart ) ) { 35290 cart.find( $.tcAPI().associatedEpoCart ).filter( ':visible' ).toArray().forEac
35290h( function( acart ) { 35291 $( acart ).trigger( { 35292 type: 'tm-epo-update', 35293 noassociated: 1 35294 } ); 35295 } ); 35296 } 35297 } 35298 35299 fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-field:not(.tmcp-dynamic,.tc-epo-field-product, .tc-is-math-special, .tc-is-math-cumulative)', total, original_total, floatingBoxData, showTotal, undefined, undefined, undefined, undefined, undefined, undefined, cartQty ); 35300 total = fetch.total; 35301 original_total = fetch.original_total; 35302 floatingBoxData = fetch.floatingBoxData; 35303 showTotal = fetch.showTotal; 35304 elementsLength = fetch.elementsLength; 35305 35306 fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tc-epo-field-product', productFieldSyncTotal, productFieldSyncOriginalTotal, floatingBoxData, showTotal, undefined, undefined, undefined, undefined, undefined, undefined, cartQty ); 35307 productFieldSyncTotal = fetch.total; 35308 productFieldSyncOriginalTotal = fetch.original_total; 35309 productFieldSyncTotalTaxed = fetch.total_taxed; 35310 productFieldSyncOriginalTotalTaxed = fetch.original_total_taxed; 35311 productFieldSyncVatTotal = fetch.vat_total; 35312 floatingBoxData = fetch.floatingBoxData; 35313 showTotal = fetch.showTotal; 35314 elementsLength = elementsLength + fetch.elementsLength; 35315 35316 totalsHolder.data( 'tm-floating-box-data', floatingBoxData ); 35317 35318 fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-fee-field', cart_fee_options_total, cart_fee_options_original_total, floatingBoxData, showTotal, false, true, undefined, undefined, undefined, undefined, cartQty ); 35319 cart_fee_options_total = fetch.total; 35320 cart_fee_options_original_total = fetch.original_total; 35321 floatingBoxData = fetch.floatingBoxData; 35322 showTotal = fetch.showTotal; 35323 elementsLength = elementsLength + fetch.elementsLength; 35324 35325 jWindow.trigger( 'tcEpoAfterNormalOptionPriceCalculation', { 35326 epo: currentEpoObject, 35327 alternativeCart: currentEpoObject, 35328 this_product_type: this_product_type, 35329 cart: cart, 35330 totalsHolder: totalsHolder, 35331 fetchOptionPrices: fetchOptionPrices, 35332 epoHolder: epoHolder, 35333 total: total, 35334 original_total: original_total, 35335 floatingBoxData: floatingBoxData, 35336 showTotal: showTotal, 35337 cart_fee_options_total: cart_fee_options_total, 35338 cart_fee_options_original_total: cart_fee_options_original_total 35339 } ); 35340 35341 // Original price + options price type requires this here. 35342 _total = total; 35343 _original_total = original_total; 35344 35345 late_total_price = add_late_fields_prices( currentEpoObject, parseFloat( productPrice ), parseFloat( rawProductRegularPrice ), parseFloat( _total + productFieldSyncTotal ), parseFloat( _original_total + productFieldSyncOriginalTotal ), bundleid, totalsHolder ); 35346 35347 fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-field.tc-is-math-special:not(.tmcp-dynamic)', total, original_total, floatingBoxData, showTotal, undefined, undefined, undefined, true, undefined, undefined, cartQty ); 35348 total = fetch.total; 35349 original_total = fetch.original_total; 35350 floatingBoxData = fetch.floatingBoxData; 35351 showTotal = fetch.showTotal; 35352 elementsLength = elementsLength + fetch.elementsLength; 35353 35354 _total = total; 35355 _original_total = original_total; 35356 35357 _total = _total + late_total_price.normal[ 0 ]; 35358 _original_total = _original_total + late_total_price.normal[ 1 ]; 35359 35360 cart_fee_options_total = cart_fee_options_total + late_total_price.fees[ 0 ]; 35361 cart_fee_options_original_total = cart_fee_options_original_total + late_total_price.fees[ 1 ]; 35362 35363 total = _total; 35364 original_total = _original_total; 35365 fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-field.tc-is-math-cumulative:not(.tmcp-dynamic)', total, original_total, floatingBoxData, showTotal, undefined, undefined, undefined, true, true, undefined, cartQty ); 35366 total = fetch.total; 35367 original_total = fetch.original_total; 35368 floatingBoxData = fetch.floatingBoxData; 35369 showTotal = fetch.showTotal; 35370 elementsLength = elementsLength + fetch.elementsLength; 35371 35372 _total = total; 35373 _original_total = original_total; 35374 35375 // Check for dynamic elements. 35376 dynamicCheck = epoHolder.find( '.tmcp-dynamic.dynamic-product-price.tc-is-math-special' ); 35377 if ( currentEpoObject.is_associated === false ) { 35378 dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.dynamic-product-price.tc-is-math-special' ); 35379 } 35380 dynamicCheck = dynamicCheck.filter( '.tcenabled' ); 35381 if ( dynamicCheck.length > 0 ) { 35382 fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-field.tmcp-dynamic.dynamic-product-price.tc-is-math-special', dynamicProductPrice + total, dynamicProductPrice + original_total, floatingBoxData, showTotal, undefined, undefined, undefined, true, undefined, undefined, cartQty );
35383 dynamicProductPrice = $.epoAPI.math.toFloat( fetch.total ) - $.epoAPI.math.toFloat( total ); 35384 productPrice = dynamicProductPrice; 35385 rawProductRegularPrice = $.epoAPI.math.toFloat( fetch.original_total ) - $.epoAPI.math.toFloat( original_total ); 35386 rawProductPrice = dynamicProductPrice; 35387 productRegularPrice = dynamicProductPrice; 35388 totalsHolderContainer.find( '.cpf-dynamic-product-price' ).val( dynamicProductPrice ); 35389 totalsHolder_tc_totals_ob.dynamic_product_price = dynamicProductPrice; 35390 totalsHolder.data( 'totalsHolder_tc_totals_ob', totalsHolder_tc_totals_ob ); 35391 } 35392 35393 dynamicCheck = epoHolder.find( '.tmcp-dynamic.dynamic-product-price.tc-is-math-cumulative' ); 35394 if ( currentEpoObject.is_associated === false ) { 35395 dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.dynamic-product-price.tc-is-math-cumulative' ); 35396 } 35397 dynamicCheck = dynamicCheck.filter( '.tcenabled' ); 35398 if ( dynamicCheck.length > 0 ) { 35399 fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-field.tmcp-dynamic.dynamic-product-price.tc-is-math-cumulative', dynamicProductPrice + total, dynamicProductPrice + original_total, floatingBoxData, showTotal, undefined, undefined, undefined, true, undefined, undefined, cartQty ); 35400 dynamicProductPrice = $.epoAPI.math.toFloat( fetch.total ) - $.epoAPI.math.toFloat( total ); 35401 productPrice = dynamicProductPrice; 35402 rawProductRegularPrice = $.epoAPI.math.toFloat( fetch.original_total ) - $.epoAPI.math.toFloat( original_total ); 35403 rawProductPrice = dynamicProductPrice; 35404 productRegularPrice = dynamicProductPrice; 35405 totalsHolderContainer.find( '.cpf-dynamic-product-price' ).val( dynamicProductPrice ); 35406 totalsHolder_tc_totals_ob.dynamic_product_price = dynamicProductPrice; 35407 totalsHolder.data( 'totalsHolder_tc_totals_ob', totalsHolder_tc_totals_ob ); 35408 } 35409 35410 // Check if there are any dynamic product price elements 35411 dynamicCheck = epoHolder.find( '.tmcp-dynamic.dynamic-product-price' ); 35412 if ( currentEpoObject.is_associated === false ) { 35413 dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.dynamic-product-price' ); 35414 } 35415 dynamicCheck = dynamicCheck.filter( '.tcenabled' ); 35416 if ( ! dynamicCheck.length > 0 ) { 35417 totalsHolderContainer.find( '.cpf-dynamic-product-price' ).val( '' ); 35418 } 35419 35420 // Dynamic Calculation 35421 dynamicProductPrice = 0; 35422 dynamicCheck = epoHolder.find( '.tmcp-dynamic.calculation:not(.tc-is-math-special, .tc-is-math-cumulative)' ); 35423 if ( currentEpoObject.is_associated === false ) { 35424 dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.calculation:not(.tc-is-math-special, .tc-is-math-cumulative)' ); 35425 } 35426 dynamicCheck = dynamicCheck.filter( '.tcenabled' ); 35427 if ( dynamicCheck.length > 0 ) { 35428 dynamicCheck.toArray().forEach( function( setter ) { 35429 var f; 35430 var ulWrap; 35431 var setterVal; 35432 setter = $( setter ); 35433 ulWrap = setter.closest( '.tmcp-ul-wrap' ); 35434 f = fetchOptionPrices( epoObject, ulWrap, '.tmcp-dynamic.calculation:not(.tc-is-math-special, .tc-is-math-cumulative)', dynamicProductPrice, dynamicProductPrice, [], true, true, undefined, undefined, undefined, true, undefined, undefined, cartQty ); 35435 setterVal = f.total; 35436 if ( setter.is( '.result-as-price' ) ) { 35437 setterVal = tm_set_price_totals( setterVal, totalsHolder, true ); 35438 } 35439 ulWrap.find( '.tc-result' ).html( setterVal ); 35440 } ); 35441 } 35442 35443 dynamicCheck = epoHolder.find( '.tmcp-dynamic.calculation.tc-is-math-special' ); 35444 if ( currentEpoObject.is_associated === false ) { 35445 dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.calculation.tc-is-math-special' ); 35446 } 35447 dynamicCheck = dynamicCheck.filter( '.tcenabled' ); 35448 if ( dynamicCheck.length > 0 ) { 35449 dynamicCheck.toArray().forEach( function( setter ) { 35450 var f; 35451 var ulWrap; 35452 var setterVal; 35453 setter = $( setter ); 35454 ulWrap = setter.closest( '.tmcp-ul-wrap' ); 35455 f = fetchOptionPrices( epoObject, ulWrap, '.tmcp-field.tmcp-dynamic.calculation.tc-is-math-special', dynamicProductPrice + total, dynamicProductPrice + original_total, [], true, true, undefined, undefined, true );
35456 setterVal = $.epoAPI.math.toFloat( f.total ) - $.epoAPI.math.toFloat( total ); 35457 if ( setter.is( '.result-as-price' ) ) { 35458 setterVal = tm_set_price_totals( setterVal, totalsHolder, true ); 35459 } 35460 ulWrap.find( '.tc-result' ).html( setterVal ); 35461 } ); 35462 } 35463 35464 dynamicCheck = epoHolder.find( '.tmcp-dynamic.calculation.tc-is-math-cumulative' ); 35465 if ( currentEpoObject.is_associated === false ) { 35466 dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.calculation.tc-is-math-cumulative' ); 35467 } 35468 dynamicCheck = dynamicCheck.filter( '.tcenabled' ); 35469 if ( dynamicCheck.length > 0 ) { 35470 dynamicCheck.toArray().forEach( function( setter ) { 35471 var f; 35472 var ulWrap; 35473 var setterVal; 35474 setter = $( setter ); 35475 ulWrap = setter.closest( '.tmcp-ul-wrap' ); 35476 f = fetchOptionPrices( epoObject, ulWrap, '.tmcp-field.tmcp-dynamic.calculation.tc-is-math-cumulative', dynamicProductPrice + total, dynamicProductPrice + original_total, [], true, true, undefined, undefined, true, undefined, undefined, undefined, cartQty ); 35477 setterVal = $.epoAPI.math.toFloat( f.total ) - $.epoAPI.math.toFloat( total ); 35478 if ( setter.is( '.result-as-price' ) ) { 35479 setterVal = tm_set_price_totals( setterVal, totalsHolder, true ); 35480 } 35481 ulWrap.find( '.tc-result' ).html( setterVal ); 35482 } ); 35483 } 35484 35485 // Dynamic Weight 35486 dynamicProductPrice = 0; 35487 dynamicCheck = epoHolder.find( '.tmcp-dynamic.change-product-weight:not(.tc-is-math-special, .tc-is-math-cumulative)' ); 35488 if ( currentEpoObject.is_associated === false ) { 35489 dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.change-product-weight:not(.tc-is-math-special, .tc-is-math-cumulative)' ); 35490 } 35491 dynamicCheck = dynamicCheck.filter( '.tcenabled' ); 35492 if ( dynamicCheck.length > 0 ) { 35493 dynamicCheck.toArray().forEach( function( setter ) { 35494 var f; 35495 var ulWrap; 35496 setter = $( setter ); 35497 ulWrap = setter.closest( '.tmcp-ul-wrap' ); 35498 f = fetchOptionPrices( epoObject, ulWrap, '.tmcp-dynamic.change-product-weight:not(.tc-is-math-special, .tc-is-math-cumulative)', dynamicProductPrice, dynamicProductPrice, [], true, true, undefined, undefined, undefined, undefined, undefined, undefined, cartQty ); 35499 ulWrap.find( '.tc-result' ).html( f.total ); 35500 } ); 35501 } 35502 35503 dynamicCheck = epoHolder.find( '.tmcp-dynamic.change-product-weight.tc-is-math-special' ); 35504 if ( currentEpoObject.is_associated === false ) { 35505 dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.change-product-weight.tc-is-math-special' ); 35506 } 35507 dynamicCheck = dynamicCheck.filter( '.tcenabled' ); 35508 if ( dynamicCheck.length > 0 ) { 35509 dynamicCheck.toArray().forEach( function( setter ) { 35510 var f; 35511 var ulWrap; 35512 setter = $( setter ); 35513 ulWrap = setter.closest( '.tmcp-ul-wrap' ); 35514 f = fetchOptionPrices( epoObject, ulWrap, '.tmcp-field.tmcp-dynamic.change-product-weight.tc-is-math-special', dynamicProductPrice + total, dynamicProductPrice + original_total, [], true, true, undefined, undefined, true, undefined, undefined, undefined, cartQty ); 35515 ulWrap.find( '.tc-result' ).html( $.epoAPI.math.toFloat( f.total ) - $.epoAPI.math.toFloat( total ) ); 35516 } ); 35517 } 35518 35519 dynamicCheck = epoHolder.find( '.tmcp-dynamic.change-product-weight.tc-is-math-cumulative' ); 35520 if ( currentEpoObject.is_associated === false ) { 35521 dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.change-product-weight.tc-is-math-cumulative' ); 35522 } 35523 dynamicCheck = dynamicCheck.filter( '.tcenabled' ); 35524 if ( dynamicCheck.length > 0 ) { 35525 dynamicCheck.toArray().forEach( function( setter ) { 35526 var f; 35527 var ulWrap; 35528 setter = $( setter ); 35529 ulWrap = setter.closest( '.tmcp-ul-wrap' ); 35530 f = fetchOptionPrices( epoObject, ulWrap, '.tmcp-field.tmcp-dynamic.change-product-weight.tc-is-math-cumulative', dynamicProductPrice + total, dynamicProductPrice + original_total, [], true, true, undefined, undefined, true, undefined, undefined, undefined, cartQty );
35531 ulWrap.find( '.tc-result' ).html( $.epoAPI.math.toFloat( f.total ) - $.epoAPI.math.toFloat( total ) ); 35532 } ); 35533 } 35534 35535 // Check for dynamic override elements 35536 dynamicProductPrice = 0; 35537 dynamicCheck = epoHolder.find( '.tmcp-dynamic.override-product-price:not(.tc-is-math-special, .tc-is-math-cumulative)' ); 35538 if ( currentEpoObject.is_associated === false ) { 35539 dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.override-product-price:not(.tc-is-math-special, .tc-is-math-cumulative)' ); 35540 } 35541 dynamicCheck = dynamicCheck.filter( '.tcenabled' ); 35542 if ( dynamicCheck.length > 0 ) { 35543 fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-dynamic.override-product-price:not(.tc-is-math-special, .tc-is-math-cumulative)', dynamicProductPrice, dynamicProductPrice, floatingBoxData, showTotal, undefined, undefined, undefined, undefined, undefined, undefined, cartQty ); 35544 dynamicProductPrice = fetch.total; 35545 productPrice = dynamicProductPrice; 35546 rawProductRegularPrice = fetch.original_total; 35547 rawProductPrice = dynamicProductPrice; 35548 productRegularPrice = dynamicProductPrice; 35549 _total = dynamicProductPrice; 35550 _original_total = dynamicProductPrice; 35551 totalsHolderContainer.find( '.cpf-override-product-price' ).val( dynamicProductPrice ); 35552 totalsHolder_tc_totals_ob.override_product_price = dynamicProductPrice; 35553 totalsHolder.data( 'totalsHolder_tc_totals_ob', totalsHolder_tc_totals_ob ); 35554 } 35555 35556 dynamicCheck = epoHolder.find( '.tmcp-dynamic.override-product-price.tc-is-math-special' ); 35557 if ( currentEpoObject.is_associated === false ) { 35558 dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.override-product-price.tc-is-math-special' ); 35559 } 35560 dynamicCheck = dynamicCheck.filter( '.tcenabled' ); 35561 if ( dynamicCheck.length > 0 ) { 35562 fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-field.tmcp-dynamic.override-product-price.tc-is-math-special', dynamicProductPrice + total, dynamicProductPrice + original_total, floatingBoxData, showTotal, undefined, undefined, undefined, true, undefined, undefined, cartQty ); 35563 dynamicProductPrice = $.epoAPI.math.toFloat( fetch.total ) - $.epoAPI.math.toFloat( total ); 35564 productPrice = dynamicProductPrice; 35565 rawProductRegularPrice = $.epoAPI.math.toFloat( fetch.original_total ) - $.epoAPI.math.toFloat( original_total ); 35566 rawProductPrice = dynamicProductPrice; 35567 productRegularPrice = dynamicProductPrice; 35568 _total = dynamicProductPrice; 35569 _original_total = dynamicProductPrice; 35570 totalsHolderContainer.find( '.cpf-override-product-price' ).val( dynamicProductPrice ); 35571 totalsHolder_tc_totals_ob.override_product_price = dynamicProductPrice; 35572 totalsHolder.data( 'totalsHolder_tc_totals_ob', totalsHolder_tc_totals_ob ); 35573 } 35574 35575 dynamicCheck = epoHolder.find( '.tmcp-dynamic.override-product-price.tc-is-math-cumulative' ); 35576 if ( currentEpoObject.is_associated === false ) { 35577 dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.override-product-price.tc-is-math-cumulative' ); 35578 } 35579 dynamicCheck = dynamicCheck.filter( '.tcenabled' ); 35580 if ( dynamicCheck.length > 0 ) { 35581 fetch = fetchOptionPrices( currentEpoObject, epoHolder, '.tmcp-field.tmcp-dynamic.override-product-price.tc-is-math-cumulative', dynamicProductPrice + total, dynamicProductPrice + original_total, floatingBoxData, showTotal, undefined, undefined, undefined, true, undefined, undefined, cartQty ); 35582 dynamicProductPrice = $.epoAPI.math.toFloat( fetch.total ) - $.epoAPI.math.toFloat( total ); 35583 productPrice = dynamicProductPrice; 35584 rawProductRegularPrice = $.epoAPI.math.toFloat( fetch.original_total ) - $.epoAPI.math.toFloat( original_total ); 35585 rawProductPrice = dynamicProductPrice; 35586 productRegularPrice = dynamicProductPrice; 35587 _total = dynamicProductPrice; 35588 _original_total = dynamicProductPrice; 35589 totalsHolderContainer.find( '.cpf-override-product-price' ).val( dynamicProductPrice ); 35590 totalsHolder_tc_totals_ob.override_product_price = dynamicProductPrice; 35591 totalsHolder.data( 'totalsHolder_tc_totals_ob', totalsHolder_tc_totals_ob ); 35592 } 35593 35594 // Check if there are any dynamic override elements 35595 dynamicCheck = epoHolder.find( '.tmcp-dynamic.override-product-price' ); 35596 if ( currentEpoObject.is_associated === false ) { 35597 dynamicCheck = dynamicCheck.not( tcAPI.associatedEpoSelector + ' ' + '.tmcp-dynamic.override-product-price' ); 35598 } 35599 dynamicCheck = dynamicCheck.filter( '.tcenabled' ); 35600 if ( ! dynamicCheck.length > 0 ) { 35601 totalsHolderContainer.find( '.cpf-override-product-price' ).val( '' ); 35602 } else { 35603 _total = 0; 35604 _original_total = 0; 35605 } 35606 35607 jWindow.trigger( 'tcEpoAfterOptionPriceCalculation', { 35608 epo: currentEpoObject, 35609 alternativeCart: currentEpoObject, 35610 this_product_type: this_product_type, 35611 cart: cart, 35612 totalsHolder: totalsHolder, 35613 fetchOptionPrices: fetchOptionPrices, 35614 epoHolder: epoHolder, 35615 total: total, 35616 original_total: original_total, 35617 floatingBoxData: floatingBoxData, 35618 showTotal: showTotal, 35619 cart_fee_options_total: cart_fee_options_total, 35620 cart_fee_options_original_total: cart_fee_options_original_total 35621 } ); 35622 35623 setTimeout( function() { 35624 epoHolder.find( 'select.tm-epo-field' ).trigger( 'tm-select-price-update-html-all' ); 35625 }, 1 ); 35626 35627 $.tcepo.oneOptionIsSelected[ epoEventId ] = showTotal; 35628 currentEpoObject = addShowHidetoEpoObject( currentEpoObject, epoEventId, elementsLength ); 35629 tm_show_hide_add_to_cart_button( main_product, currentEpoObject ); 35630 35631 if ( cart_fee_options_total > 0 ) { 35632 showTotal = true; 35633 } 35634 35635 if ( alternativeCart && ! perProductPricing ) { 35636 showTotal = false;
35637 } 35638 35639 if ( 35640 finalTotalBoxMode === 'enable' || 35641 finalTotalBoxMode === 'hideifoptionsiszero' || 35642 finalTotalBoxMode === 'hideiftotaliszero' 35643 ) { 35644 showTotal = true; 35645 } 35646 35647 if ( cartQty > 1 ) { 35648 showTotal = true; 35649 } 35650 if ( ( this_product_type === 'variable' || this_product_type === 'variable-subscription' ) && ! $.epoAPI.math.toFloat( currentVariation ) ) { 35651 showTotal = false; 35652 } 35653 35654 if ( finalTotalBoxMode === 'disable' ) { 35655 showTotal = false; 35656 } 35657 if ( TMEPOJS.tm_epo_change_variation_price === 'yes' || TMEPOJS.tm_epo_change_original_price === 'yes' ) { 35658 showTotal = true; 35659 } 35660 35661 if ( currentEpoObject.is_associated && ! perProductPricing ) { 35662 showTotal = false; 35663 } 35664 35665 product_total_price = parseFloat( productPrice * cartQty ); 35666 35667 if ( TMEPOJS.extraFee ) { 35668 extraFee = parseFloat( TMEPOJS.extraFee ); 35669 if ( ! Number.isFinite( extraFee ) ) { 35670 extraFee = 0; 35671 } 35672 } 35673 35674 calculateFinalProductPrice = $.epoAPI.applyFilter( 'tcCalculateFinalProductPrice', false, { 35675 alternativeCart: alternativeCart, 35676 product_price: productPrice, 35677 product_total_price: product_total_price, 35678 v_product_price: rawProductPrice, 35679 tm_set_tax_price: tm_set_tax_price, 35680 main_product: main_product, 35681 totalsHolder: totalsHolder, 35682 cartQty: cartQty 35683 } ); 35684 35685 if ( 35686 calculateFinalProductPrice !== false && 35687 typeof calculateFinalProductPrice === 'object' && 35688 Object.prototype.hasOwnProperty.call( calculateFinalProductPrice, 'productPrice' ) && 35689 Object.prototype.hasOwnProperty.call( calculateFinalProductPrice, 'productTotalPrice' ) 35690 ) { 35691 productPrice = calculateFinalProductPrice.productPrice; 35692 product_total_price = calculateFinalProductPrice.productTotalPrice; 35693 } 35694 35695 _total = $.epoAPI.applyFilter( 'tc_adjust_options_price_per_unit', _total, product_total_price ); 35696 total = parseFloat( _total * cartQty * elementQty ); 35697 total = $.epoAPI.applyFilter( 'tc_adjust_options_total_price', total, cartQty, elementQty, _total, totalsHolder ); 35698 if ( TMEPOJS.tm_epo_global_product_element_quantity_sync === 'no' ) { 35699 totalProductField = parseFloat( productFieldSyncTotal ); 35700 totalProductFieldTaxed = parseFloat( productFieldSyncTotalTaxed ); 35701 } else { 35702 totalProductField = parseFloat( productFieldSyncTotal * cartQty * elementQty ); 35703 totalProductFieldTaxed = parseFloat( productFieldSyncTotalTaxed * cartQty * elementQty ); 35704 } 35705 totalProductField = $.epoAPI.applyFilter( 'tc_adjust_options_productfield_total_price', totalProductField, cartQty, elementQty, _total, totalsHolder ); 35706 totalProductFieldTaxed = $.epoAPI.applyFilter( 'tc_adjust_options_productfield_total_price_taxed', totalProductFieldTaxed, cartQty, elementQty, _total, totalsHolder ); 35707 35708 _original_total = $.epoAPI.applyFilter( 'tc_adjust_options_price_per_unit', _original_total, product_total_price ); 35709 original_total = parseFloat( _original_total * cartQty * elementQty ); 35710 original_total = $.epoAPI.applyFilter( 'tc_adjust_options_original_total_price', original_total, cartQty, elementQty, _original_total, totalsHolder ); 35711 if ( TMEPOJS.tm_epo_global_product_element_quantity_sync === 'no' ) { 35712 originalTotalProductField = parseFloat( productFieldSyncOriginalTotal ); 35713 originalTotalProductFieldTaxed = parseFloat( productFieldSyncOriginalTotalTaxed ); 35714 } else { 35715 originalTotalProductField = parseFloat( productFieldSyncOriginalTotal * cartQty * elementQty ); 35716 originalTotalProductFieldTaxed = parseFloat( productFieldSyncOriginalTotalTaxed * cartQty * elementQty ); 35717 } 35718 originalTotalProductField = $.epoAPI.applyFilter( 'tc_adjust_options_productfield_original_total_price', originalTotalProductField, cartQty, elementQty, _original_total, totalsHolder ); 35719 originalTotalProductFieldTaxed = $.epoAPI.applyFilter( 'tc_adjust_options_productfield_original_total_price_taxed', originalTotalProductFieldTaxed, cartQty, elementQty, _original_total, totalsHolder ); 35720 35721 if ( priceOverrideMode === '1' && parseFloat( total ) > 0 ) { 35722 productPrice = 0; 35723 rawProductPrice = 0; 35724 product_total_price = 0; 35725 } 35726 35727 product_total_price = $.epoAPI.applyFilter( 'tc_adjust_product_total_price_without_options', product_total_price ); 35728 35729 total = $.epoAPI.applyFilter( 'tcAdjustTotal', total, { 35730 epo: currentEpoObject, 35731 totalsHolder: totalsHolder, 35732 cart: cart, 35733 main_product: main_product 35734 } ); 35735 totalProductField = $.epoAPI.applyFilter( 'tcAdjustProductFieldTotal', totalProductField, { 35736 epo: currentEpoObject, 35737 totalsHolder: totalsHolder, 35738 cart: cart, 35739 main_product: main_product 35740 } ); 35741 totalProductFieldTaxed = $.epoAPI.applyFilter( 'tcAdjustProductFieldTotalTaxed', totalProductFieldTaxed, { 35742 epo: currentEpoObject, 35743 totalsHolder: totalsHolder, 35744 cart: cart, 35745 main_product: main_product 35746 } ); 35747 original_total = $.epoAPI.applyFilter( 'tcAdjustOriginalTotal', original_total, { 35748 epo: currentEpoObject, 35749 totalsHolder: totalsHolder, 35750 cart: cart, 35751 main_product: main_product 35752 } ); 35753 originalTotalProductField = $.epoAPI.applyFilter( 'tcAdjustProductFieldOriginalTotal', originalTotalProductField, { 35754 epo: currentEpoObject, 35755 totalsHolder: totalsHolder, 35756 cart: cart, 35757 main_product: main_product 35758 } ); 35759 originalTotalProductFieldTaxed = $.epoAPI.applyFilter( 'tcAdjustProductFieldOriginalTotalTaxed', originalTotalProductFieldTaxed, { 35760 epo: currentEpoObject, 35761 totalsHolder: totalsHolder, 35762 cart: cart, 35763 main_product: main_product 35764 } ); 35765 35766 total = parseFloat( $.epoAPI.applyFilter( 'tc_adjust_total', total, totalsHolder ) ); 35767 cart_fee_options_total = parseFloat( $.epoAPI.applyFilter( 'tc_adjust_totals_fee', cart_fee_options_total, totalsHolder ) ); 35768 original_total = parseFloat( $.epoAPI.applyFilter( 'tc_adjust_original_total', original_total, totalsHolder ) ); 35769 cart_fee_options_original_total = parseFloat( $.epoAPI.applyFilter( 'tc_adjust_original_total_fee', cart_fee_options_original_total, totalsHolder ) ); 35770 raw_extraFee = extraFee; 35771 35772 total_plus_fee = total + cart_fee_options_total; 35773 original_total_plus_fee = original_total + cart_fee_options_original_total; 35774 35775 raw_total = total; 35776 raw__total = _total; 35777 35778 raw_cart_fee_options_total = cart_fee_options_total; 35779 raw_total_plus_fee = total_plus_fee; 35780 35781 raw_original_total = original_total; 35782 raw__original_total = _original_total; 35783 35784 raw_cart_fee_options_original_total = cart_fee_options_original_total; 35785 raw_original_total_plus_fee = original_total_plus_fee; 35786 35787 raw_product_total_price_without_options = product_total_price; 35788 raw_product_total_price = parseFloat( product_total_price + total_plus_fee + raw_extraFee ); 35789 raw_product_total_original_price = parseFloat( rawProductRegularPrice + original_total_plus_fee + raw_extraFee ); 35790 35791 productPrice = tm_set_tax_price( productPrice, totalsHolder, undefined, undefined, undefined, undefined, true ); 35792 productRegularPrice = tm_set_tax_price( productRegularPrice, totalsHolder, undefined, undefined, undefined, undefined, true ); 35793 product_total_price = tm_set_tax_price( product_total_price, totalsHolder, undefined, undefined, undefined, undefined, true ); 35794 35795 total = tm_set_tax_price( total, totalsHolder, undefined, undefined, undefined, undefined, true ); 35796 _total = tm_set_tax_price( _total, totalsHolder, undefined, undefined, undefined, undefined, true ); 35797 35798 total_plus_fee = parseFloat( cart_fee_options_total ) + parseFloat( total ); 35799 35800 original_total = tm_set_tax_price( original_total, totalsHolder, undefined, undefined, undefined, undefined, true ); 35801 _original_total = tm_set_tax_price( _original_total, totalsHolder, undefined, undefined, undefined, undefined, true ); 35802 35803 original_total_plus_fee = parseFloat( cart_fee_options_original_total ) + parseFloat( original_total ); 35804 35805 extraFee = tm_set_tax_price( extraFee, totalsHolder, undefined, undefined, undefined, undefined, true ); 35806 35807 // Calculate product price 35808 product_total_price_without_options = product_total_price; 35809 product_total_price = $.epoAPI.applyFilter( 'tc_adjust_product_total_price', parseFloat( product_total_price + total_plus_fee + extraFee ), product_total_price_without_options, total_plus_fee, extraFee, total, cart_fee_options_total, totalsHolder ); 35810 product_total_original_price = $.epoAPI.applyFilter( 'tc_adjust_product_total_original_price', parseFloat( product_total_price_without_options + original_total_plus_fee + extraFee ), product_total_price_without_options, original_total_plus_fee, extraFee, original_total, cart_fee_options_original_total, totalsHolder ); 35811 35812 // Calculate vat options total
35813 pricesIncludeTax = totalsHolder.attr( 'data-prices-include-tax' ) || TMEPOJS.prices_include_tax; 35814 if ( pricesIncludeTax === '1' ) { 35815 vat_options_total = productFieldSyncVatTotal + parseFloat( calculateTaxAmount( total, totalsHolder ) ); 35816 vat_options_total_plus_fee = productFieldSyncVatTotal + parseFloat( calculateTaxAmount( total_plus_fee, totalsHolder ) ); 35817 vat_total = productFieldSyncVatTotal + parseFloat( calculateTaxAmount( product_total_price, totalsHolder ) ); 35818 vat_product_base = parseFloat( calculateTaxAmount( product_total_price_without_options, totalsHolder ) ); 35819 } else { 35820 vat_options_total = productFieldSyncVatTotal + parseFloat( total - raw_total ); 35821 vat_options_total_plus_fee = productFieldSyncVatTotal + parseFloat( total_plus_fee - raw_total_plus_fee ); 35822 vat_total = productFieldSyncVatTotal + parseFloat( product_total_price - raw_product_total_price ); 35823 vat_product_base = parseFloat( product_total_price_without_options - raw_product_total_price_without_options ); 35824 } 35825 35826 raw_total = raw_total + totalProductField; 35827 raw__total = raw__total + totalProductField; 35828 raw_total_plus_fee = raw_total_plus_fee + totalProductField; 35829 raw_original_total = raw_original_total + originalTotalProductField; 35830 raw__original_total = raw__original_total + originalTotalProductField; 35831 raw_original_total_plus_fee = raw_original_total_plus_fee + originalTotalProductField; 35832 raw_product_total_price = raw_product_total_price + totalProductField; 35833 raw_product_total_original_price = raw_product_total_original_price + originalTotalProductField; 35834 total = total + totalProductFieldTaxed; 35835 _total = _total + totalProductFieldTaxed; 35836 total_plus_fee = total_plus_fee + totalProductFieldTaxed; 35837 original_total = original_total + originalTotalProductFieldTaxed; 35838 _original_total = _original_total + originalTotalProductFieldTaxed; 35839 original_total_plus_fee = original_total_plus_fee + originalTotalProductFieldTaxed; 35840 product_total_price = product_total_price + totalProductFieldTaxed; 35841 product_total_original_price = product_total_original_price + originalTotalProductFieldTaxed; 35842 35843 // Calculate unit price 35844 unit_price = parseFloat( productPrice + parseFloat( _total ) ); 35845 unit_original_price = parseFloat( productPrice + parseFloat( _original_total ) ); 35846 if ( TMEPOJS.tm_epo_fees_on_unit_price === 'yes' ) { 35847 unit_price = parseFloat( productPrice + parseFloat( _total ) + parseFloat( parseFloat( cart_fee_options_total ) / cartQty ) ); 35848 unit_original_price = parseFloat( productPrice + parseFloat( _original_total ) + parseFloat( parseFloat( cart_fee_options_original_total ) / cartQty ) ); 35849 } 35850 35851 // Format unit price 35852 formatted_unit_price = tm_set_price_totals( unit_price, totalsHolder, true ); 35853 formatted_unit_original_price = tm_set_price_totals( unit_original_price, totalsHolder, true ); 35854 35855 // Format extra fee 35856 if ( extraFee ) { 35857 show_extra_fee = true; 35858 formatted_extra_fee = tm_set_price_totals( extraFee, totalsHolder, true ); 35859 } 35860 35861 // Format final total 35862 formatted_final_total = tm_set_price_totals( product_total_price, totalsHolder, true ); 35863 formatted_final_original_total = tm_set_price_totals( product_total_original_price, totalsHolder, true ); 35864 35865 // Format options total 35866 formatted_options_total = tm_set_price_totals( total, totalsHolder, true ); 35867 35868 // Format fees total 35869 formatted_fees_total = tm_set_price_totals( cart_fee_options_total, totalsHolder, true ); 35870 35871 // Format options original total 35872 formatted_options_original_total = tm_set_price_totals( original_total, totalsHolder, true ); 35873 35874 // Format fees original total 35875 formatted_fees_original_total = tm_set_price_totals( cart_fee_options_original_total, totalsHolder, true ); 35876 35877 // Format vat options total 35878 formatted_vat_options_total = tm_set_price_totals( vat_options_total ); 35879 formatted_vat_options_total_plus_fee = tm_set_price_totals( vat_options_total_plus_fee ); 35880 formatted_vat_total = tm_set_price_totals( vat_total ); 35881 formatted_vat_product_base = tm_set_price_totals( vat_product_base ); 35882 35883 // Backwards compatibility 35884 formatted_unit_price = $.epoAPI.applyFilter( 'tc_adjust_formatted_unit_price', formatted_unit_price, productPrice, _total, cart_fee_options_total, cartQty ); 35885 formatted_options_total = $.epoAPI.applyFilter( 'tc_adjust_formatted_options_total', formatted_options_total, total, _total, cartQty ); 35886 formatted_fees_total = $.epoAPI.applyFilter( 'tc_adjust_formatted_fees_total', formatted_fees_total, cart_fee_options_total ); 35887 formatted_final_total = $.epoAPI.applyFilter( 'tc_adjust_formatted_final_total', formatted_final_total, product_total_price, product_total_price_without_options, total_plus_fee, extraFee, cartQty ); 35888 35889 formatted_unit_price = $.epoAPI.applyFilter( 'tcAdjustFormattedUnitPrice', formatted_unit_price, { 35890 epo: currentEpoObject, 35891 totalsHolder: totalsHolder, 35892 event: event, 35893 unit_price: unit_price, 35894 productPrice: productPrice, 35895 _total: _total, 35896 total_plcart_fee_options_totals_fee: cart_fee_options_total, 35897 cartQty: cartQty 35898 } ); 35899 formatted_unit_original_price = $.epoAPI.applyFilter( 'tcAdjustFormattedUnitOriginalPrice', formatted_unit_original_price, { 35900 epo: currentEpoObject, 35901 totalsHolder: totalsHolder, 35902 event: event, 35903 unit_original_price: unit_original_price, 35904 productPrice: productPrice, 35905 _original_total: _original_total, 35906 total_plcart_fee_options_totals_fee: cart_fee_options_total, 35907 cartQty: cartQty 35908 } ); 35909 formatted_options_total = $.epoAPI.applyFilter( 'tcAdjustFormattedOptionsTotal', formatted_options_total, { 35910 epo: currentEpoObject, 35911 totalsHolder: totalsHolder, 35912 event: event, 35913 total: total, 35914 _total: _total, 35915 total_plus_fee: total_plus_fee, 35916 extraFee: extraFee, 35917 cartQty: cartQty 35918 } ); 35919 formatted_options_original_total = $.epoAPI.applyFilter( 'tcAdjustFormattedOptionsOriginalTotal', formatted_options_original_total, { 35920 epo: currentEpoObject, 35921 totalsHolder: totalsHolder, 35922 event: event, 35923 original_total: original_total, 35924 _original_total: _original_total, 35925 original_total_plus_fee: original_total_plus_fee, 35926 extraFee: extraFee, 35927 cartQty: cartQty 35928 } ); 35929 formatted_fees_total = $.epoAPI.applyFilter( 'tcAdjustFormattedFeesTotal', formatted_fees_total, { 35930 epo: currentEpoObject, 35931 totalsHolder: totalsHolder, 35932 event: event, 35933 cart_fee_options_total: cart_fee_options_total, 35934 extraFee: extraFee, 35935 cartQty: cartQty 35936 } ); 35937 formatted_fees_original_total = $.epoAPI.applyFilter( 'tcAdjustFormattedFeesOriginalTotal', formatted_fees_original_total, { 35938 epo: currentEpoObject, 35939 totalsHolder: totalsHolder, 35940 event: event, 35941 cart_fee_options_original_total: cart_fee_options_original_total, 35942 extraFee: extraFee, 35943 cartQty: cartQty 35944 } ); 35945 formatted_final_total = $.epoAPI.applyFilter( 'tcAdjustFormattedFinalTotal', formatted_final_total, { 35946 epo: currentEpoObject, 35947 totalsHolder: totalsHolder, 35948 event: event, 35949 product_total_price: product_total_price, 35950 product_total_price_without_options: product_total_price_without_options, 35951 total_plus_fee: total_plus_fee, 35952 extraFee: extraFee, 35953 cartQty: cartQty 35954 } ); 35955 formatted_final_original_total = $.epoAPI.applyFilter( 'tcAdjustFormattedFinalOriginalTotal', formatted_final_original_total, { 35956 epo: currentEpoObject, 35957 totalsHolder: totalsHolder, 35958 event: event, 35959 product_total_original_price: product_total_original_price, 35960 product_total_price_without_options: product_total_price_without_options, 35961 original_total_plus_fee: original_total_plus_fee, 35962 extraFee: extraFee, 35963 cartQty: cartQty 35964 } ); 35965 35966 if ( ( total > 0 && finalTotalBoxShowOptions === 'showtgz' ) || finalTotalBoxShowOptions === 'show' ) { 35967 show_options_total = true; 35968 if ( TMEPOJS.tm_epo_enable_vat_options_total === 'yes' ) { 35969 show_vat_options_total = true; 35970 } 35971 } 35972 if ( cart_fee_options_total !== 0 ) { 35973 show_fees_total = true; 35974 } 35975 35976 if ( formatted_final_total && finalTotalBoxShowFinal === 'show' ) { 35977 show_final_total = true; 35978 } 35979 35980 tc_totals_ob = { 35981 qty: cartQty, 35982 product_price: productPrice, 35983 raw_product_price: rawProductPrice, 35984 product_regular_price: productRegularPrice, 35985 raw_product_regular_price: rawProductRegularPrice, 35986 formatted_product_price: tm_set_price_totals( parseFloat( productPrice ) * cartQty ), 35987 35988 late_total_prices: late_total_price, 35989 late_total_price: tm_set_tax_price( late_total_price[ 0 ], totalsHolder ), 35990 late_total_original_price: tm_set_tax_price( late_total_price[ 1 ], totalsHolder ), 35991 35992 raw_options_price_per_unit: raw__total, 35993 raw_options_total_price: raw_total, 35994 raw_cart_fee_options_total_price: raw_cart_fee_options_total, 35995 raw_total_plus_fee: raw_total_plus_fee, 35996 35997 raw_options_original_price_per_unit: raw__original_total, 35998 raw_options_original_total_price: raw_original_total, 35999 raw_cart_fee_options_original_total_price: raw_cart_fee_options_original_total, 36000 raw_original_total_plus_fee: raw_original_total_plus_fee, 36001 36002 raw_product_total_price: raw_product_total_price, 36003 raw_product_total_original_price: raw_product_total_original_price, 36004 raw_product_total_price_without_options: raw_product_total_price_without_options, 36005 36006 options_price_per_unit: _total, 36007 options_total_price: total, 36008 cart_fee_options_total_price: cart_fee_options_total, 36009 total_plus_fee: total_plus_fee, 36010 36011 options_original_price_per_unit: _original_total, 36012 options_original_total_price: original_total, 36013 cart_fee_options_total_original_price: cart_fee_options_original_total, 36014 original_total_plus_fee: original_total_plus_fee, 36015 36016 vat_options_total: vat_options_total, 36017 vat_options_total_plus_fee: vat_options_total_plus_fee, 36018 formatted_vat_options_total: formatted_vat_options_total, 36019 formatted_vat_options_total_plus_fee: formatted_vat_options_total_plus_fee, 36020 vat_total: vat_total, 36021 formatted_vat_total: formatted_vat_total, 36022 vat_product_base: vat_product_base, 36023 formatted_vat_product_base: formatted_vat_product_base, 36024 36025 product_total_price: product_total_price, 36026 product_total_original_price: product_total_original_price, 36027 product_total_price_without_options: product_total_price_without_options, 36028 36029 product_unit_price: unit_price, 36030 product_unit_original_price: unit_original_price, 36031 formatted_unit_price: formatted_unit_price, 36032 formatted_options_total: formatted_options_total, 36033 formatted_fees_total: formatted_fees_total, 36034 formatted_final_total: formatted_final_total, 36035 36036 formatted_unit_original_price: formatted_unit_original_price, 36037 formatted_options_original_total: formatted_options_original_total, 36038 formatted_fees_original_total: formatted_fees_original_total, 36039 formatted_final_original_total: formatted_final_original_total, 36040 36041 formatted_extra_fee: formatted_extra_fee, 36042 36043 show_options_total: show_options_total, 36044 show_fees_total: show_fees_total, 36045 show_extra_fee: show_extra_fee, 36046 show_final_total: show_final_total, 36047 show_options_vat: show_vat_options_total, 36048 36049 show_unit_price: TMEPOJS.tm_epo_show_unit_price === 'yes', 36050 unit_price: currentEpoObject.is_associated ? TMEPOJS.i18n_item_unit_price : TMEPOJS.i18n_unit_price, 36051 options_total: currentEpoObject.is_associated ? TMEPOJS.i18n_item_options_total : TMEPOJS.i18n_options_total, 36052 options_vat_total: currentEpoObject.is_associated ? TMEPOJS.i18n_item_vat_options_total : TMEPOJS.i18n_vat_options_total, 36053 final_total: currentEpoObject.is_associated ? TMEPOJS.i18n_item_final_total : TMEPOJS.i18n_final_total, 36054 fees_total: TMEPOJS.i18n_fees_total, 36055 extra_fee: TMEPOJS.i18n_extra_fee, 36056 36057 totals_box_before_unit_price: TMEPOJS.totals_box_before_unit_price, 36058 totals_box_after_unit_price: TMEPOJS.totals_box_after_unit_price, 36059 totals_box_before_vat_options_totals_price: TMEPOJS.totals_box_before_vat_options_totals_price, 36060 totals_box_after_vat_options_totals_price: TMEPOJS.totals_box_after_vat_options_totals_price, 36061 totals_box_before_options_totals_price: TMEPOJS.totals_box_before_options_totals_price, 36062 totals_box_after_options_totals_price: TMEPOJS.totals_box_after_options_totals_price, 36063 totals_box_before_fee_totals_price: TMEPOJS.totals_box_before_fee_totals_price, 36064 totals_box_after_fee_totals_price: TMEPOJS.totals_box_after_fee_totals_price, 36065 totals_box_before_extra_fee_price: TMEPOJS.totals_box_before_extra_fee_price, 36066 totals_box_after_extra_fee_price: TMEPOJS.totals_box_after_extra_fee_price, 36067 totals_box_before_final_totals_price: TMEPOJS.totals_box_before_final_totals_price, 36068 totals_box_after_final_totals_price: TMEPOJS.totals_box_after_final_totals_price 36069 }; 36070 36071 if ( TMEPOJS.customer_price_format ) { 36072 customer_price_format_wrap_start = TMEPOJS.customer_price_format_wrap_start; 36073 customer_price_format_wrap_end = TMEPOJS.customer_price_format_wrap_end; 36074 customerPriceFormat = TMEPOJS.customer_price_format; 36075 } 36076 36077 if ( formatted_options_total && total >= 0 ) { 36078 _ftotal = formatPrice( total ); 36079 _foriginal_total = formatPrice( original_total ); 36080 if ( customerPriceFormat ) { 36081 _ftotal = customerPriceFormat.replaceAll( '__PRICE__', _ftotal ).replaceAll( '__CODE__', TMEPOJS.current_currency ); 36082 if ( ! totalsHolder.data( 'is-on-sale' ) ) { 36083 _foriginal_total = customerPriceFormat.replaceAll( '__PRICE__', _foriginal_total ).replaceAll( '__CODE__', TMEPOJS.current_currency ); 36084 } 36085 } 36086 _ftotal = $.epoAPI.applyFilter( 'tcFilterFormattedFTotal', _ftotal, { 36087 epo: currentEpoObject, 36088 totalsHolder: totalsHolder, 36089 event: event, 36090 total: total, 36091 _total: _total, 36092 total_plus_fee: total_plus_fee, 36093 extraFee: extraFee, 36094 cartQty: cartQty 36095 } ); 36096 _foriginal_total = $.epoAPI.applyFilter( 'tcFilterFormattedFOriginalTotal', _foriginal_total, { 36097 epo: currentEpoObject, 36098 totalsHolder: totalsHolder, 36099 event: event, 36100 original_total: original_total, 36101 total: original_total, 36102 _total: _total, 36103 total_plus_fee: total_plus_fee, 36104 extraFee: extraFee, 36105 cartQty: cartQty 36106 } ); 36107 if ( TMEPOJS.tm_epo_enable_original_final_total === 'yes' && total !== original_total ) { 36108 tc_totals_ob.formatted_options_total = $.epoAPI.util.decodeHTML( 36109 $.epoAPI.template.html( tcAPI.templateEngine.tc_formatted_sale_price, { 36110 price: _foriginal_total, 36111 sale_price: _ftotal, 36112 customer_price_format_wrap_start: customer_price_format_wrap_start, 36113 customer_price_format_wrap_end: customer_price_format_wrap_end 36114 } ) 36115 ); 36116 tc_totals_ob._foriginal_total = _foriginal_total; 36117 tc_totals_ob._ftotal = _ftotal; 36118 } else { 36119 tc_totals_ob.formatted_options_total = $.epoAPI.util.decodeHTML( 36120 $.epoAPI.util.decodeHTML( 36121 $.epoAPI.template.html( tcAPI.templateEngine.tc_formatted_price, { 36122 price: _ftotal, 36123 customer_price_format_wrap_start: customer_price_format_wrap_start, 36124 customer_price_format_wrap_end: customer_price_format_wrap_end 36125 } ) 36126 ) 36127 ); 36128 } 36129 } 36130 36131 if ( formatted_final_total && product_total_price >= 0 ) { 36132 _fprice = formatPrice( product_total_price ); 36133 if ( priceOverrideMode === '1' && parseFloat( total ) > 0 ) { 36134 _f_regular_price = parseFloat( raw_original_total + extraFee ); 36135 } else { 36136 _f_regular_price = parseFloat( parseFloat( rawProductRegularPrice * cartQty ) + raw_original_total ); 36137 } 36138 if ( customerPriceFormat ) { 36139 _fprice = customerPriceFormat.replaceAll( '__PRICE__', _fprice ).replaceAll( '__CODE__', TMEPOJS.current_currency ); 36140 if ( ! totalsHolder.data( 'is-on-sale' ) ) { 36141 _f_regular_price = customerPriceFormat.replaceAll( '__PRICE__', _f_regular_price ).replaceAll( '__CODE__', TMEPOJS.current_currency ); 36142 } 36143 } 36144 36145 _fprice = $.epoAPI.applyFilter( 'tc_adjust_native_price', _fprice, product_total_price ); 36146 _f_regular_price = tm_set_tax_price( _f_regular_price, totalsHolder, undefined, undefined, undefined, undefined, true ) + parseFloat( cart_fee_options_original_total ) + parseFloat( extraFee ); 36147 _f_regular_price = formatPrice( _f_regular_price ); 36148 _f_regular_price = $.epoAPI.applyFilter( 'tc_adjust_native_regular_price', _f_regular_price, product_total_price ); 36149 36150 if ( TMEPOJS.tm_epo_enable_original_final_total =
36150== 'yes' && ( ( totalsHolder.data( 'is-on-sale' ) && priceOverrideMode !== '1' ) || _f_regular_price !== _fprice ) ) { 36151 tc_totals_ob.formatted_final_total = $.epoAPI.util.decodeHTML( 36152 $.epoAPI.template.html( tcAPI.templateEngine.tc_formatted_sale_price, { 36153 price: _f_regular_price, 36154 sale_price: _fprice, 36155 customer_price_format_wrap_start: customer_price_format_wrap_start, 36156 customer_price_format_wrap_end: customer_price_format_wrap_end 36157 } ) 36158 ); 36159 } else { 36160 tc_totals_ob.formatted_final_total = $.epoAPI.util.decodeHTML( 36161 $.epoAPI.util.decodeHTML( 36162 $.epoAPI.template.html( tcAPI.templateEngine.tc_formatted_price, { 36163 price: _fprice, 36164 customer_price_format_wrap_start: customer_price_format_wrap_start, 36165 customer_price_format_wrap_end: customer_price_format_wrap_end 36166 } ) 36167 ) 36168 ); 36169 } 36170 tc_totals_ob._f_regular_price = _f_regular_price; 36171 tc_totals_ob._fprice = _fprice; 36172 } 36173 36174 // Add the suffix. 36175 tc_totals_ob.formatted_unit_price = tc_totals_ob.formatted_unit_price + $.epoAPI.util.decodeHTML( 36176 $.epoAPI.util.decodeHTML( 36177 $.epoAPI.template.html( tcAPI.templateEngine.suffix ) 36178 ) 36179 ); 36180 36181 tc_totals_ob.formatted_options_total = tc_totals_ob.formatted_options_total + $.epoAPI.util.decodeHTML( 36182 $.epoAPI.util.decodeHTML( 36183 $.epoAPI.template.html( tcAPI.templateEngine.suffix ) 36184 ) 36185 ); 36186 36187 tc_totals_ob.formatted_final_total = tc_totals_ob.formatted_final_total + $.epoAPI.util.decodeHTML( 36188 $.epoAPI.util.decodeHTML( 36189 $.epoAPI.template.html( tcAPI.templateEngine.suffix ) 36190 ) 36191 ); 36192 36193 tc_totals_ob = replace_suffixes( 'formatted_fees_original_total', 'cart_fee_options_total_original_price', tc_totals_ob, totalsHolder ); 36194 tc_totals_ob = replace_suffixes( 'formatted_fees_total', 'cart_fee_options_total_price', tc_totals_ob, totalsHolder ); 36195 tc_totals_ob = replace_suffixes( 'formatted_final_original_total', 'product_total_original_price', tc_totals_ob, totalsHolder ); 36196 tc_totals_ob = replace_suffixes( 'formatted_final_total', 'product_total_price', tc_totals_ob, totalsHolder ); 36197 tc_totals_ob = replace_suffixes( 'formatted_options_original_total', 'options_original_total_price', tc_totals_ob, totalsHolder ); 36198 tc_totals_ob = replace_suffixes( 'formatted_options_total', 'options_total_price', tc_totals_ob, totalsHolder ); 36199 tc_totals_ob = replace_suffixes( 'formatted_unit_original_price', 'product_unit_original_price', tc_totals_ob, totalsHolder ); 36200 tc_totals_ob = replace_suffixes( 'formatted_unit_price', 'product_unit_price', tc_totals_ob, totalsHolder ); 36201 36202 if ( $.tcepo.showHideTotal !== undefined && $.tcepo.showHideTotal[ epoEventId ] !== undefined ) { 36203 showTotal = $.tcepo.showHideTotal[ epoEventId ]; 36204 } 36205 36206 tc_totals_ob = $.epoAPI.applyFilter( 'tc_adjust_tc_totals_ob', tc_totals_ob, { 36207 epo_object: currentEpoObject, 36208 showTotal: showTotal, 36209 epoHolder: epoHolder, 36210 totalsHolder: totalsHolder, 36211 replace_suffixes: replace_suffixes, 36212 replace_suffixes_in_html: replace_suffixes_in_html, 36213 tm_set_tax_price: tm_set_tax_price, 36214 tm_set_price: tm_set_price, 36215 tm_set_price_totals: tm_set_price_totals, 36216 product_total_price: product_total_price, 36217 product_price: productPrice, 36218 qty: cartQty 36219 } ); 36220 36221 if ( tc_totals_ob.showTotal !== undefined ) { 36222 showTotal = tc_totals_ob.showTotal; 36223 } 36224 36225 currentEpoObject.tc_totals_ob = tc_totals_ob; 36226 36227 showTotal = $.epoAPI.applyFilter( 'tcFinalTotalsBoxVisibility', showTotal, { 36228 epo: currentEpoObject, 36229 alternativeCart: alternativeCart, 36230 cart: cart, 36231 main_product: main_product, 36232 totalsHolder: totalsHolder, 36233 this_epo_totals_container: this_epo_totals_container 36234 } ); 36235 36236 html = $.epoAPI.template.html( tcAPI.templateEngine.tc_final_totals, tc_totals_ob ); 36237 36238 totalsHolder.data( 'tm-html', html ); 36239 totalsHolder.data( 'tc_totals_ob', tc_totals_ob ); 36240 36241 if ( currentEpoObject.associated_connect && currentEpoObject.associated_connect.length === 1 ) { 36242 if ( currentEpoObject.associated_connect.attr( 'data-no-price' ) === '1' ) { 36243 associatedPrice = 0; 36244 associatedRawPrice = 0; 36245 associatedOriginalPrice = 0; 36246 associatedRawOriginalPrice = 0; 36247 associatedFormattedPrice = ''; 36248 tm_force_update_price( 36249 epoObject, 36250 associatedSetter 36251 .closest( '.tmcp-field-wrap' ) 36252 .find( '.tc-price' ) 36253 .not( tcAPI.associatedEpoSelector + ' .tc-price' ), 36254 associatedPrice, 36255 associatedFormattedPrice, 36256 associatedOriginalPrice 36257 ); 36258 } else { 36259 associatedPrice = tc_totals_ob.product_price + tc_totals_ob.options_price_per_unit + ( tc_totals_ob.cart_fee_options_total_price / tc_totals_ob.qty ); 36260 associatedRawPrice = tc_totals_ob.raw_product_price + tc_totals_ob.raw_options_price_per_unit + ( tc_totals_ob.raw_cart_fee_options_total_price / tc_totals_ob.qty ); 36261 associatedOriginalPrice = tc_totals_ob.product_regular_price + tc_totals_ob.options_original_price_per_unit + ( tc_totals_ob.cart_fee_options_total_original_price / tc_totals_ob.qty ); 36262 associatedRawOriginalPrice = tc_totals_ob.raw_product_regular_price + tc_totals_ob.raw_options_original_price_per_unit + ( tc_totals_ob.raw_cart_fee_options_original_total_price / tc_totals_ob.qty ); 36263 36264 associatedFormattedPrice = tm_set_price( associatedPrice, currentEpoObject.this_epo_totals_container, false, associatedSetter ); 36265 36266 // Mainly used to update the price of the associated element when the associated product is variable. 36267 tm_force_update_price( 36268 epoObject, 36269 associatedSetter 36270 .closest( '.tmcp-field-wrap' ) 36271 .find( '.tc-price' ) 36272 .not( tcAPI.associatedEpoSelector + ' .tc-price' ), 36273 associatedPrice, 36274 associatedFormattedPrice, 36275 associatedOriginalPrice 36276 ); 36277 36278 currentEpoObject.associated_connect.data( 'tm-quantity', tc_totals_ob.qty ); 36279 36280 if ( currentEpoObject.associated_connect.data( 'tm-quantity' ) ) { 36281 associatedPrice = associatedPrice * parseFloat( currentEpoObject.associated_connect.data( 'tm-quantity' ) ); 36282 associatedRawPrice = associatedRawPrice * parseFloat( currentEpoObject.associated_connect.data( 'tm-quantity' ) ); 36283 associatedOriginalPrice = associatedOriginalPrice * parseFloat( currentEpoObject.associated_connect.data( 'tm-quantity' ) ); 36284 associatedRawOriginalPrice = associatedRawOriginalPrice * parseFloat( currentEpoObject.associated_connect.data( 'tm-quantity' ) ); 36285 } 36286 36287 associatedFormattedPrice = tm_set_price( associatedPrice, currentEpoObject.this_epo_totals_container, false, associatedSetter ); 36288 } 36289 36290 currentEpoObject.associated_connect.data( 'price_set', 1 ); 36291 if ( associatedSetter.is( '.tcenabled' ) ) { 36292 associatedSetter.data( 'associated_price_set', 1 ); 36293 } 36294 associatedSetter.data( 'price_set', 1 ); 36295 associatedSetter.data( 'raw_price', associatedRawPrice ); 36296 associatedSetter.data( 'raw_original_price', associatedRawOriginalPrice ); 36297 associatedSetter.data( 'price', tm_set_tax_price( associatedPrice, currentEpoObject.this_epo_totals_container, associatedSetter ) ); 36298 associatedSetter.data( 'original_price', tm_set_tax_price( associatedOriginalPrice, currentEpoObject.this_epo_totals_container, associatedSetter ) ); 36299 36300 currentEpoObject.associated_connect.data( 'price-changed', 1 ); 36301 36302 setTimeout( function() { 36303 if ( ! ( currentEpoObject.associated_connect && event.noassociated ) ) { 36304 currentEpoObject.mainEpoObject.main_cart.trigger( { 36305 type: 'tm-epo-update', 36306 norules: 2 36307 } ); 36308 } 36309 }, 20 ); 36310 } 36311 36312 jWindow.trigger( 'tcEpoAfterCalculateTotals', { 36313 epo: currentEpoObject, 36314 alternativeCart: alternativeCart, 36315 this_product_type: this_product_type, 36316 cart: cart, 36317 bundleid: bundleid, 36318 totalsObject: tc_totals_ob, 36319 main_product: main_product, 36320 per_product_pricing: perProductPricing, 36321 event: event 36322 } ); 36323 36324 hide_native_price = $.epoAPI.applyFilter( 'hide_native_price', true ); 36325 36326 if ( cartQty > 0 ) { 36327 // hide native prices 36328 if ( TMEPOJS.tm_epo_change_variation_price === 'yes' ) { 36329 if ( hide_native_price === true && finalTotalBoxMode !== 'disable' ) { 36330 tm_get_native_prices_block( cart ).hide(); 36331 } else { 36332 tm_get_native_prices_block( cart ).show(); 36333 } 36334 } 36335 36336 if ( ! showTotal || 36337 finalTotalBoxMode === 'disable' || 36338 ( finalTotalBoxMode === 'hideiftotaliszero' && product_total_price === 0 ) || 36339 ( finalTotalBoxMode === 'hideifoptionsiszero' && total_plus_fee === 0 ) 36340 ) { 36341 html = ''; 36342 totalsHolder.html( html ); 36343 totalsHolder.data( 'tm-floating-box-data', [] ); 36344 } else { 36345 totalsHolder.html( html ); 36346 36347 jWindow.trigger( 'tc-totals-container', { 36348 epo: tc_totals_ob, 36349 totals_holder: totalsHolder, 36350 data: { 36351 epo_object: currentEpoObject, 36352 tm_set_price: tm_set_price, 36353 tm_set_price_totals: tm_set_price_totals, 36354 product_total_price: product_total_price, 36355 product_price: productPrice, 36356 qty: cartQty 36357 }, 36358 tm_epo_js: TMEPOJS 36359 } ); 36360 } 36361 36362 if ( formatted_final_total && product_total_price >= 0 ) { 36363 if ( TMEPOJS.tm_epo_change_variation_price === 'yes' ) { 36364 setTimeout( function() { 36365 update_native_html = tm_get_native_prices_block( cart ); 36366 if ( totalsHolder.data( 'is-on-sale' ) ) { 36367 temp = $.epoAPI.util.decodeHTML( 36368 $.epoAPI.template.html( tcAPI.templateEngine.tc_formatted_sale_price, { 36369 price: _f_regular_price, 36370 sale_price: _fprice, 36371 customer_price_format_wrap_start: customer_price_format_wrap_start, 36372 customer_price_format_wrap_end: customer_price_format_wrap_end, 36373 before_price_text: TMEPOJS.variation_price_before_price_text, 36374 after_price_text: TMEPOJS.variation_price_after_price_text 36375 } ) 36376 ); 36377 temp = temp + $.epoAPI.util.decodeHTML( 36378 $.epoAPI.util.decodeHTML( 36379 $.epoAPI.template.html( tcAPI.templateEngine.main_suffix ) 36380 ) 36381 ); 36382 temp = { 36383 formatted: temp, 36384 raw: tc_totals_ob.product_total_price 36385 }; 36386 temp = replace_suffixes( 'formatted', 'raw', temp, totalsHolder ); 36387 temp = temp.formatted; 36388 update_native_html 36389 .html( temp ) 36390 .show(); 36391 } else { 36392 temp = $.epoAPI.util.decodeHTML( 36393 $.epoAPI.template.html( tcAPI.templateEngine.tc_formatted_price, { 36394 price: _fprice, 36395 customer_price_format_wrap_start: customer_price_format_wrap_start, 36396 customer_price_format_wrap_end: customer_price_format_wrap_end, 36397 before_price_text: TMEPOJS.variation_price_before_price_text, 36398 after_price_text: TMEPOJS.variation_price_after_price_text 36399 } ) 36400 ); 36401 temp = temp + $.epoAPI.util.decodeHTML( 36402 $.epoAPI.util.decodeHTML( 36403 $.epoAPI.template.html( tcAPI.templateEngine.main_suffix ) 36404 ) 36405 ); 36406 temp = { 36407 formatted: temp, 36408 raw: tc_totals_ob.product_total_price 36409 }; 36410 temp = replace_suffixes( 'formatted', 'raw', temp, totalsHolder ); 36411 temp = temp.formatted; 36412 update_native_html 36413 .html( temp ) 36414 .show(); 36415 } 36416 }, 310 ); // WooCommerce uses 300ms timeout for changing the price. 36417 } 36418 36419 if ( TMEPOJS.tm_epo_change_original_price === 'yes' ) { 36420 if ( ! alternativeCart || main_product.find( '.cpf-bto-price' ).length === 0 ) { 36421 if ( currentEpoObject.associated_connect ) { 36422 nativeProductPriceSelector = currentEpoObject.main_product.find( tcAPI.associatedNativeProductPriceSelector ); 36423 } else { 36424 // shop/archive pages. 36425 nativeProductPriceSelector = currentEpoObject.main_product.find( tcAPI.nativeProductPriceSelector ); 36426 // product page.
36427 if ( nativeProductPriceSelector.length === 0 ) { 36428 nativeProductPriceSelector = $( tcAPI.nativeProductPriceSelector ); 36429 } 36430 } 36431 36432 if ( nativeProductPriceSelector.length === 0 && main_product.is( '.tc-after-shop-loop' ) ) { 36433 nativeProductPriceSelector = main_product.closest( '.product' ).find( '.price' ).not( '.tc-after-shop-loop .price' ); 36434 } 36435 if ( nativeProductPriceSelector.data( 'tc-original-html' ) === undefined ) { 36436 nativeProductPriceSelector.data( 'tc-original-html', nativeProductPriceSelector.html() ); 36437 } 36438 if ( product_total_price > 0 ) { 36439 if ( totalsHolder.data( 'is-on-sale' ) ) { 36440 temp = $.epoAPI.util.decodeHTML( 36441 $.epoAPI.template.html( tcAPI.templateEngine.tc_formatted_sale_price, { 36442 price: _f_regular_price, 36443 sale_price: _fprice, 36444 customer_price_format_wrap_start: customer_price_format_wrap_start, 36445 customer_price_format_wrap_end: customer_price_format_wrap_end, 36446 before_price_text: TMEPOJS.product_price_before_price_text, 36447 after_price_text: TMEPOJS.product_price_after_price_text 36448 } ) 36449 ); 36450 temp = temp + $.epoAPI.util.decodeHTML( 36451 $.epoAPI.util.decodeHTML( 36452 $.epoAPI.template.html( tcAPI.templateEngine.main_suffix ) 36453 ) 36454 ); 36455 temp = { 36456 formatted: temp, 36457 raw: tc_totals_ob.product_total_price 36458 }; 36459 temp = replace_suffixes( 'formatted', 'raw', temp, totalsHolder ); 36460 temp = temp.formatted; 36461 nativeProductPriceSelector 36462 .html( temp ) 36463 .show(); 36464 } else { 36465 temp = $.epoAPI.util.decodeHTML( 36466 $.epoAPI.template.html( tcAPI.templateEngine.tc_formatted_price, { 36467 price: _fprice, 36468 customer_price_format_wrap_start: customer_price_format_wrap_start, 36469 customer_price_format_wrap_end: customer_price_format_wrap_end, 36470 before_price_text: TMEPOJS.product_price_before_price_text, 36471 after_price_text: TMEPOJS.product_price_after_price_text 36472 } ) 36473 ); 36474 temp = temp + $.epoAPI.util.decodeHTML( 36475 $.epoAPI.util.decodeHTML( 36476 $.epoAPI.template.html( tcAPI.templateEngine.main_suffix ) 36477 ) 36478 ); 36479 temp = { 36480 formatted: temp, 36481 raw: tc_totals_ob.product_total_price 36482 }; 36483 temp = replace_suffixes( 'formatted', 'raw', temp, totalsHolder ); 36484 temp = temp.formatted; 36485 nativeProductPriceSelector 36486 .html( temp ) 36487 .show(); 36488 } 36489 } else if ( this_product_type && this_product_type !== 'composite' ) { 36490 if ( currentEpoObject.associated_connect ) { 36491 if ( currentEpoObject.variations_form.length ) { 36492 temp = currentEpoObject.this_epo_totals_container.data( 'variationIdElement' ); 36493 if ( temp.length > 0 ) { 36494 temp = parseFloat( temp.val() ); 36495 if ( ! ( ! temp || temp === 0 ) ) { 36496 nativeProductPriceSelector.html( $.epoAPI.util.decodeHTML( TMEPOJS.assoc_current_free_text ) ); 36497 } 36498 } 36499 } else { 36500 nativeProductPriceSelector.html( $.epoAPI.util.decodeHTML( TMEPOJS.assoc_current_free_text ) ); 36501 } 36502 } else { 36503 nativeProductPriceSelector.html( $.epoAPI.util.decodeHTML( TMEPOJS.current_free_text ) ); 36504 } 36505 } 36506 } 36507 36508 jWindow.trigger( 'tcEpoMaybeChangePriceHtml', { 36509 epo: currentEpoObject, 36510 alternativeCart: alternativeCart, 36511 this_product_type: this_product_type, 36512 cart: cart, 36513 bundleid: bundleid, 36514 totalsObject: tc_totals_ob, 36515 main_product: main_product, 36516 nativePrice: _fprice 36517 } ); 36518 } 36519 } 36520 36521 if ( alternativeCart ) { 36522 main_cart.trigger( { 36523 type: 'tm-epo-update', 36524 norules: 1 36525 } ); 36526 } else { 36527 this_epo_totals_container.data( 'is_active', true ); 36528 } 36529 } else { 36530 if ( currentEpoObject.associated_connect ) { 36531 nativeProductPriceSelector = currentEpoObject.main_product.find( tcAPI.associatedNativeProductPriceSelector ); 36532 nativeProductPriceSelector.html( nativeProductPriceSelector.data( 'tc-original-html' ) ); 36533 } 36534
36535 tm_get_native_prices_block( cart ).toArray().forEach( function( npb ) { 36536 var $npb = $( npb ); 36537 if ( ! $npb.data( 'tm-original-html' ) ) { 36538 $npb.data( 'tm-original-html', $npb.html() ); 36539 } else { 36540 $npb.html( $npb.data( 'tm-original-html' ) ); 36541 } 36542 } ); 36543 36544 if ( rawProductPrice === 0 && TMEPOJS.tm_epo_remove_free_price_label === 'yes' ) { 36545 tm_get_native_prices_block( cart ).hide(); 36546 } else if ( TMEPOJS.tm_epo_change_variation_price === 'yes' && ! ( hide_native_price === true && finalTotalBoxMode !== 'disable' ) ) { 36547 tm_get_native_prices_block( cart ).show(); 36548 } 36549 36550 totalsHolder.empty(); 36551 36552 if ( alternativeCart ) { 36553 main_cart.trigger( { 36554 type: 'tm-epo-update', 36555 norules: 1 36556 } ); 36557 } 36558 } 36559 36560 main_cart.trigger( 'tm-epo-after-update', { 36561 container: cartContainer 36562 } ); 36563 36564 jWindow.trigger( 'tc-epo-after-update', { 36565 epo: tc_totals_ob, 36566 totals_holder: totalsHolder, 36567 data: { 36568 epo_object: currentEpoObject, 36569 add_late_fields_prices: add_late_fields_prices, 36570 tm_set_price: tm_set_price, 36571 tm_set_price_totals: tm_set_price_totals, 36572 product_total_price: product_total_price, 36573 replace_suffixes_in_html: replace_suffixes_in_html, 36574 product_price: productPrice, 36575 qty: cartQty, 36576 bundleid: bundleid, 36577 currentCart: currentCart 36578 }, 36579 tm_epo_js: TMEPOJS 36580 } ); 36581 } ); 36582 36583 if ( this_product_type === 'variable' || this_product_type === 'variable-subscription' ) { 36584 epoVariationSection = epoHolder.find( '.tm-epo-variation-section' ).first(); 36585 36586 // Custom variation events 36587 epoVariationSection 36588 .find( '.tm-epo-reset-variation' ) 36589 .off( 'click.cpfv' ) 36590 .on( 'click.cpfv', function() { 36591 var field = $( this ); 36592 var id = $.epoAPI.dom.id( field.attr( 'data-tm-for-variation' ) ); 36593 var section = field.closest( '.cpf-type-variations' ); 36594 var inputs = field.closest( '.cpf-element' ).find( '.tm-epo-variation-element' ); 36595 var lis = field.closest( '.cpf-element' ).find( '.tmcp-field-wrap' ); 36596 36597 inputs.prop( 'checked', false ); 36598 lis.removeClass( 'tc-active' ); 36599 variationForm 36600 .find( "[data-attribute_name='attribute_" + id + "']" ) 36601 .val( '' ) 36602 .trigger( 'change' ); 36603 variationForm.find( "[data-attribute_name='attribute_" + id + "']" ).trigger( 'focusin' ); 36604 36605 main_product 36606 .find( '.cpf-type-variations' ) 36607 .not( section ) 36608 .toArray().forEach( function( el ) { 36609 variationForm.find( "[data-attribute_name='attribute_" + $.epoAPI.dom.id( $( el ).find( '.tm-epo-variation-element' ).first().attr( 'data-tm-for-variation' ) ) + "']" ).trigger( 'focusin' ); 36610 } ); 36611 field.trigger( 'blur' ); 36612 variationForm.trigger( 'woocommerce_update_variation_values_tmlogic' ); 36613 } ); 36614 36615 epoVariationSection
36616 .find( 'input.tm-epo-variation-element,input.tm-epo-variation-element + span' ) 36617 .off( 'mouseup.cpfv' ) 36618 .on( 'mouseup.cpfv', function() { 36619 var field = $( this ); 36620 var id; 36621 36622 if ( field.is( 'span' ) ) { 36623 field = field.prev( 'input' ); 36624 } 36625 if ( field.attr( 'disabled' ) ) { 36626 variationForm.find( '.reset_variations' ).trigger( 'click' ); 36627 } 36628 id = $.epoAPI.dom.id( field.attr( 'data-tm-for-variation' ) ); 36629 variationForm.find( "[data-attribute_name='attribute_" + id + "']" ).trigger( 'focusin' ); 36630 } ); 36631 36632 epoVariationSection 36633 .off( 'click.' + eventName + '.tmepo', '.reset_variations, .tc-epo-element-variable-reset-variations' ) 36634 .on( 'click.' + eventName + '.tmepo', '.reset_variations, .tc-epo-element-variable-reset-variations', { _epoObject: epoObject }, function( event ) { 36635 var _nativeProductPriceSelector; 36636 if ( TMEPOJS.tm_epo_change_original_price === 'yes' ) { 36637 if ( ! alternativeCart || main_product.find( '.cpf-bto-price' ).length === 0 ) { 36638 if ( event.data._epoObject.associated_connect ) { 36639 _nativeProductPriceSelector = event.data._epoObject.main_product.find( tcAPI.associatedNativeProductPriceSelector ); 36640 } else { 36641 _nativeProductPriceSelector = $( tcAPI.nativeProductPriceSelector ); 36642 } 36643 if ( _nativeProductPriceSelector.data( 'tc-original-html' ) ) { 36644 _nativeProductPriceSelector.html( _nativeProductPriceSelector.data( 'tc-original-html' ) ); 36645 } 36646 } 36647 } 36648 variationForm.find( '.variations .reset_variations, .tc-epo-element-variable-reset-variations' ).first().trigger( 'click' ); 36649 } ); 36650 36651 epoVariationSection 36652 .find( '.tm-epo-variation-element' ) 36653 .off( 'change.cpfv tm_epo_variation_element_change' ) 36654 .on( 'change.cpfv tm_epo_variation_element_change', function( e ) { 36655 var field = $( this ); 36656 var id = $.epoAPI.dom.id( field.attr( 'data-tm-for-variation' ) ); 36657 var value = field.val(); 36658 var section = field.closest( '.cpf-type-variations' ); 36659 var nativeSelect = variationForm.find( "[data-attribute_name='attribute_" + id + "']" ); 36660 var exists; 36661 36662 if ( field.closest( '.tm-epo-variation-section' ).is( '.tm-hidden' ) ) { 36663 return; 36664 } 36665 36666 if ( ! ( e && e.type && e.type === 'tm_epo_variation_element_change' ) ) { 36667 exists = false; 36668 nativeSelect.each( function() { 36669 if ( this.value === value ) { 36670 exists = true; 36671 return false; 36672 } 36673 } ); 36674 if ( ! exists ) { 36675 nativeSelect.trigger( 'focusin' ); 36676 } 36677 nativeSelect.val( value ).trigger( 'change' ); 36678 } 36679 36680 if ( ! value ) { 36681 nativeSelect.trigger( 'focusin' ); 36682 } 36683 36684 main_product 36685 .find( '.cpf-type-variations' ) 36686 .not( section ) 36687 .toArray().forEach( function( vr ) { 36688 variationForm.find( '#' + $.epoAPI.dom.id( $( vr ).find( '.tm-epo-variation-element' ).first().attr( 'data-tm-for-variation' ) ) ).trigger( 'focusin' ); 36689 } ); 36690 36691 field.trigger( 'blur' ); 36692 variationForm.trigger( 'woocommerce_update_variation_values_tmlogic' ); 36693 } ) 36694 .off( 'focusin.cpfv' ) 36695 .on( 'focusin.cpfv', function() { 36696 var field = $( this ); 36697 var id; 36698 36699 if ( ! field.is( 'select' ) ) { 36700 return; 36701 } 36702 36703 id = $.epoAPI.dom.id( field.attr( 'data-tm-for-variation' ) ); 36704 variationForm.find( "[data-attribute_name='attribute_" + id + "']" ).trigger( 'focusin' ); 36705 variationForm.trigger( 'woocommerce_update_variation_values_tmlogic' ); 36706 } ); 36707
36708 variationForm.off( eventNamePrefix + 'found_variation.tmepo tm_fix_stock', '.single_variation_wrap' ).on( eventNamePrefix + 'found_variation.tmepo tm_fix_stock', '.single_variation_wrap', function() { 36709 fix_stock( $( this ), cartContainer ); 36710 } ); 36711 36712 // update prices when a variation is found 36713 variationForm 36714 .off( eventNamePrefix + 'found_variation.tmepo' ) 36715 .on( eventNamePrefix + 'found_variation.tmepo', function( event, variation ) { 36716 var form = $( this ); 36717 36718 totalsHolder.data( 'is-on-sale', variation.tc_is_on_sale ); 36719 totalsHolder.data( 'regular-price', tm_set_backend_price( variation.display_regular_price, totalsHolder, variation ) ); 36720 36721 jWindow.trigger( 'tm-epo-found-variation', { 36722 epo: epoObject, 36723 totalsHolder: totalsHolder, 36724 totalsHolderContainer: totalsHolderContainer, 36725 currentCart: currentCart, 36726 variationForm: form, 36727 variation: variation 36728 } ); 36729 36730 found_variation_tmepo( { 36731 epoHolder: epoHolder, 36732 totalsHolder: totalsHolder, 36733 totalsHolderContainer: totalsHolderContainer, 36734 currentCart: currentCart, 36735 variationForm: form, 36736 variation: variation 36737 } ); 36738 36739 fix_stock( form, cartContainer ); 36740 } ) 36741 .off( eventNamePrefix + 'hide_variation.tmepo' ) 36742 .on( eventNamePrefix + 'hide_variation.tmepo', { _epoObject: epoObject }, function( event ) { 36743 var _nativeProductPriceSelector; 36744 if ( TMEPOJS.tm_epo_change_original_price === 'yes' ) { 36745 if ( ! alternativeCart || main_product.find( '.cpf-bto-price' ).length === 0 ) { 36746 if ( event.data._epoObject.associated_connect ) { 36747 _nativeProductPriceSelector = event.data._epoObject.main_product.find( tcAPI.associatedNativeProductPriceSelector ); 36748 } else { 36749 _nativeProductPriceSelector = $( tcAPI.nativeProductPriceSelector ); 36750 } 36751 if ( _nativeProductPriceSelector.data( 'tc-original-html' ) ) { 36752 _nativeProductPriceSelector.html( _nativeProductPriceSelector.data( 'tc-original-html' ) ); 36753 } 36754 } 36755 } 36756 totalsHolder.data( 'price', false ); 36757 // Fancy product Designer 36758 totalsHolder.removeData( 'tcprice' ); 36759 currentCart.trigger( { 36760 type: 'tm-epo-update', 36761 norules: 2 36762 } ); 36763 } ) 36764 .off( eventNamePrefix + 'check_variations.tmepo' ) 36765 .on( eventNamePrefix + 'check_variations.tmepo', function() { 36766 var data = {}; 36767 var chosen = 0; 36768 var reset = epoVariationSection.find( '.reset_variations' ); 36769 36770 variationForm.find( '.variations select, .tc-epo-variable-product-selector' ).toArray().forEach( function( sl ) { 36771 var $this = $( sl ); 36772 var attribute_name = $this.data( 'attribute_name' ) || $this.attr( 'name' ); 36773 var value = $this.val() || ''; 36774 36775 if ( value.length > 0 ) { 36776 chosen++; 36777 } 36778 36779 data[ attribute_name ] = value; 36780 } ); 36781 36782 if ( chosen > 0 ) { 36783 if ( reset.css( 'visibility' ) === 'hidden' ) { 36784 reset.css( 'visibility', 'visible' ).hide().fadeIn(); 36785 } 36786 } else { 36787 reset.css( 'visibility', 'hidden' ); 36788 } 36789 } ) 36790 .trigger( eventNamePrefix + 'check_variations' ); 36791 36792 tm_custom_variations( epoObject, cartContainer, itemId, main_product, epoHolder ); 36793 } 36794 36795 selectSelector.trigger( 'tm-select-change-html' ); 36796 tmQty.trigger( 'change.cpf', { init: 1 } ); 36797 tmQuantity.trigger( 'showhide.cpfcustom' ); 36798 epoFieldHasClearButton.filter( ':checked' ).trigger( 'cpfclearbutton' ); 36799 36800 jWindow.on( 'tm-do-epo-update', function() { 36801 // This must be run every time to get correct results for percent price types 36802 // if set norules then discount will not auto work upon chosing a variation 36803 currentCart.trigger( { 36804 type: 'tm-epo-update' 36805 //"norules": 2 36806 } ); 36807 } ); 36808 36809 jWindow.trigger( 'tm-epo-init-events', { 36810 epo: { 36811 epo_id: epo_id, 36812 form: epoObject.form, 36813 currentCart: currentCart, 36814 cart_container: cartContainer, 36815 epo_holder: epoHolder, 36816 totals_holder_container: totalsHolderContainer, 36817 totals_holder: totalsHolder, 36818 main_cart: main_cart, 36819 main_epo_inside_form: main_epo_inside_form, 36820 product_id_selector: product_id_selector, 36821 epo_id_selector: epo_id_selector, 36822 product_id: product_id, 36823 this_epo_container: this_epo_container, 36824 this_totals_container: this_totals_container, 36825 this_epo_totals_container: this_epo_totals_container 36826 } 36827 } ); 36828 36829 jWindow.trigger( 'epoEventHandlers', { 36830 epo: epoObject, 36831 currentCart: currentCart, 36832 cartContainer: cartContainer, 36833 qtyElement: qtyElement, 36834 epoHolder: epoHolder, 36835 totalsHolderContainer: totalsHolderContainer, 36836 totalsHolder: totalsHolder, 36837 variationForm: variationForm, 36838 variation_id_selector: variation_id_selector, 36839 main_epo_inside_form: main_epo_inside_form, 36840 this_product_type: this_product_type, 36841 get_price_excluding_tax: get_price_excluding_tax, 36842 get_price_including_tax: get_price_including_tax 36843 } ); 36844 36845 // show final totals 36846 if ( finalTotalBoxMode !== 'disable' ) { 36847 totalsHolderContainer.addClass( 'tc-show' ); 36848 } 36849 36850 // show extra options 36851 jWindow.trigger( 'epo_options_before_visible' ); 36852 36853 if ( TMEPOJS.tm_epo_progressive_display === 'yes' ) { 36854 setTimeout( function() { 36855 epoHolder 36856 .css( 'opacity', 0 ) 36857 .addClass( 'tc-show' ) 36858 .animate( 36859 { 36860 opacity: 1 36861 }, 36862 tcAPI.epoAnimationDelay, 36863 'easeOutExpo', 36864 function() { 36865 jWindow.trigger( 'epo_options_visible' ); 36866 jWindow.trigger( 'tmlazy' ); 36867 } 36868 ); 36869 }, tcAPI.epoDelay ); 36870 } else { 36871 epoHolder.addClass( 'tc-show' ); 36872 jWindow.trigger( 'epo_options_visible' ); 36873 jWindow.trigger( 'tmlazy' ); 36874 } 36875 36876 main_product.addClass( 'tc-init' ); 36877 } 36878 36879 function run_wc_variation_form_cpf( epoObject ) { 36880 var form = epoObject.variations_form; 36881 var cart = epoObject.main_cart; 36882 var this_epo_container = epoObject.this_epo_container; 36883 var eventName = epoObject.is_associated ? 'tc_variation_form.cpf' : 'wc_variation_form.cpf'; 36884 36885 form.off( eventName ).on( eventName, function() { 36886 if ( form.data( 'epo_loaded' ) ) { 36887 return; 36888 } 36889 36890 // Start Condition Logic 36891 cpf_section_logic( epoObject ); 36892 cpf_element_logic( epoObject ); 36893 36894 jWindow.on( 'epoEventHandlers', function() { 36895 run_cpfdependson( this_epo_container ); 36896 tm_lazyload(); 36897 } ); 36898 36899 // Init field price rules 36900 $.tcepo.lateFieldsPrices[ epoObject.epoEventId ] = []; 36901 36902 epoEventHandlers( epoObject ); 36903 tm_set_upload_fields( epoObject ); 36904 tm_product_image( epoObject ); 36905 36906 jWindow.trigger( 'epo-after-init-in-timeout', { epo: epoObject } ); 36907 epoObject.noEpoUpdate = false;
36908 cart.trigger( 'tm-epo-check-dpd' ); 36909 cart.trigger( { 36910 type: 'tm-epo-update', 36911 rules: 'init' 36912 } ); 36913 36914 form.data( 'epo_loaded', true ); 36915 } ); 36916 36917 if ( variationsFormIsLoaded ) { 36918 form.trigger( eventName ); 36919 } 36920 36921 jWindow.trigger( 'epo-after-init', { epo: epoObject } ); 36922 } 36923 36924 function detect_variation_swatches_interval( epoObject ) { 36925 var $id = requestAnimationFrame( function() { 36926 detect_variation_swatches_interval( epoObject ); 36927 } ); 36928 var obj = epoObject.variations_form; 36929 var bound = obj.data( 'bound' ); 36930 var eventName = epoObject.is_associated ? 'tc_variation_form.cpf' : 'wc_variation_form.cpf'; 36931 36932 if ( bound ) { 36933 cancelAnimationFrame( $id ); 36934 run_wc_variation_form_cpf( epoObject ); 36935 obj.trigger( eventName ); 36936 } 36937 } 36938 36939 function manualInitEPO( epoObject, item, itemCart, itemEpoContainer, main_product ) { 36940 var epoObjectOriginal = $.extend( true, {}, epoObject ); 36941 var product_id = itemEpoContainer.attr( 'data-product-id' ); 36942 var epo_id = itemEpoContainer.attr( 'data-epo-id' ); 36943 var product_id_selector = '.tm-product-id-' + product_id; 36944 var epo_id_selector = "[data-epo-id='" + epo_id + "']"; 36945 var epoEventId = 'p' + product_id + 'e' + epo_id; 36946 var this_epo_container = $( tcAPI.epoSelector + product_id_selector + epo_id_selector ); 36947 var this_totals_container = $( '.tc-totals-form' + product_id_selector + epo_id_selector ); 36948 var this_epo_totals_container = $( '.tc-epo-totals' + product_id_selector + epo_id_selector ); 36949 36950 epoObject.isManual = true; 36951 36952 $.tcepo.formSubmitEvents[ epoEventId ] = []; 36953 $.tcepo.errorObject[ epoEventId ] = false; 36954 $.tcepo.initialActivation[ epoEventId ] = false; 36955 36956 epoObject.product_id = product_id; 36957 epoObject.product_id_selector = product_id_selector; 36958 epoObject.epo_id = epo_id; 36959 epoObject.epo_id_selector = epo_id_selector; 36960 epoObject.epoEventId = epoEventId; 36961 epoObject.noEpoUpdate = true; 36962 epoObject.thisForm = item; 36963 epoObject.this_epo_container = this_epo_container; 36964 epoObject.this_totals_container = this_totals_container; 36965 epoObject.this_epo_totals_container = this_epo_totals_container; 36966 36967 tm_lazyload(); 36968 main_product.find( '.tm-collapse' ).tmtoggle(); 36969 main_product.find( '.tm-section-link' ).tmsectionpoplink(); 36970 36971 tm_set_datepicker( item ); 36972 setRangePickers( item ); 36973 setRangePickersEvents(); 36974 tm_set_repeaters( item, epoObject ); 36975 tm_css_styles( item ); 36976 tm_set_color_pickers( itemEpoContainer ); 36977 tm_set_lightbox( itemEpoContainer.find( '.tc-lightbox-image' ).not( '.tm-extra-product-options-variations .radio-image' ) ); 36978 36979 // Start Condition Logic 36980 cpf_section_logic( epoObject ); 36981 cpf_element_logic( epoObject ); 36982 run_cpfdependson( itemEpoContainer ); 36983 36984 $.tcToolTip( item.find( '.tm-tooltip' ) ); 36985 epoEventHandlers( epoObject, item, itemCart ); 36986 36987 epoObject.noEpoUpdate = false; 36988 36989 itemCart.trigger( { 36990 type: 'tm-epo-update', 36991 norules: 2 36992 } ); 36993 setTimeout( function() { 36994 epoObject.main_cart.trigger( { 36995 type: 'tm-epo-update', 36996 epoObject: epoObjectOriginal, 36997 norules: 1 36998 } ); 36999 }, 200 ); 37000 fix_stock( itemCart, item ); 37001 } 37002 37003 function tm_init_epo( main_product, is_quickview, product_id, epo_id, associated_connect, mainEpoObject, reactivate ) { 37004 // Holds the main cart when using Composite Products 37005 var main_cart = false; 37006 var main_epo_inside_form = false; 37007 var main_totals_inside_form = false; 37008 var epoEventId; 37009 var has_epo = typeof product_id !== 'undefined'; 37010 var not_has_epo = false; 37011 var add_to_cart_field; 37012 var product_id_selector; 37013 var epo_id_selector; 37014 var this_epo_container; 37015 var this_totals_container; 37016 var this_epo_totals_container; 37017 var epo_object; 37018 var variations_form; 37019 var detect_variation_swatches = $( '.variation_form_section .variations-table' ).length > 0; 37020 var is_associated = false; 37021 37022 main_product = $( main_product ); 37023 37024 if ( main_product.is( '.tc-init' ) && ! reactivate ) { 37025 return true; 37026 } 37027 37028 if ( is_quickview ) { 37029 errorContainer = main_product; 37030 } else { 37031 errorContainer = $( window ); 37032 } 37033 37034 jWindow.trigger( 'tm-epo-init-start' ); 37035 37036 if ( ! has_epo ) { 37037 if ( main_product.is( '.product' ) ) { 37038 not_has_epo = true; 37039 has_epo = jBody.find( tcAPI.epoSelector ).length; 37040 } 37041 } 37042 37043 // return if product has no extra options and the totals box is not enabled for all products 37044 if ( ! has_epo && TMEPOJS.tm_epo_enable_final_total_box_all === 'no' && ! main_product.is( '.tm-no-options-composite' ) ) { 37045 jWindow.trigger( 'tm-epo-init-end-no-options' ); 37046 return; 37047 } 37048 37049 // set the main_product variable again for products that have no extra options 37050 if ( not_has_epo ) { 37051 jWindow.trigger( 'tm-epo-init-no-options' ); 37052 if ( main_product.is( '.product' ) && ! ( main_product.is( '.tm-no-options-pxq' ) || main_product.is( '.tm-no-options-composite' ) ) ) { 37053 main_product = jBody; 37054 } 37055 } 37056 37057 if ( ! product_id ) { 37058 add_to_cart_field = main_product.find( tcAPI.addToCartSelector ).last(); 37059 if ( add_to_cart_field.length > 0 ) { 37060 product_id = add_to_cart_field.val(); 37061 } else { 37062 add_to_cart_field = $( '.tc-totals-form.tm-totals-form-main' );
37063 product_id = add_to_cart_field.attr( 'data-product-id' ); 37064 } 37065 if ( ! product_id ) { 37066 product_id = ''; 37067 } 37068 } 37069 37070 if ( ! epo_id ) { 37071 epo_id = parseInt( main_product.find( 'input.tm-epo-counter' ).last().val(), 10 ); 37072 37073 if ( ! Number.isFinite( epo_id ) ) { 37074 epo_id = ''; 37075 } 37076 } 37077 37078 product_id_selector = '.tm-product-id-' + product_id; 37079 epo_id_selector = "[data-epo-id='" + epo_id + "']"; 37080 this_epo_container = $( tcAPI.epoSelector + product_id_selector + epo_id_selector ); 37081 this_totals_container = $( '.tc-totals-form' + product_id_selector + epo_id_selector ); 37082 this_epo_totals_container = $( '.tc-epo-totals' + product_id_selector + epo_id_selector ); 37083 variations_form = main_product.find( '.variations_form' ).not( '.composite_component .variations_form' ).first(); 37084 epoEventId = 'p' + product_id + 'e' + epo_id; 37085 37086 if ( variations_form && variations_form.attr( 'data-product_id' ) ) { 37087 if ( variations_form.attr( 'data-product_id' ) !== product_id ) { 37088 variations_form = main_product.find( ".variations_form[data-product_id='" + product_id + "']" ); 37089 } 37090 } 37091 37092 main_cart = get_main_cart( main_product, main_product, 'form', product_id ); 37093 if ( main_cart.length === 0 ) { 37094 if ( main_product.is( '.tc-shortcode-wrap' ) ) { 37095 main_cart = get_main_cart( this_totals_container, this_totals_container, '.tc-totals-form', product_id ); 37096 } else if ( main_product.is( '.tc-epo-element-product-container' ) ) { 37097 main_cart = main_product.find( tcAPI.associatedEpoCart ); 37098 // should never be 0 37099 if ( main_cart.length === 0 ) { 37100 main_cart = this_epo_container.parent( tcAPI.associatedEpoSelector ); 37101 if ( main_cart.length === 0 ) { 37102 main_cart = main_product.find( '.tc-epo-element-product-container-right' ); 37103 } 37104 } 37105 is_associated = true; 37106 } 37107 } 37108 37109 if ( is_associated && variations_form.length === 0 && main_product.is( '.variations_form' ) ) { 37110 variations_form = main_product; 37111 } 37112 37113 $.tcepo.formSubmitEvents[ epoEventId ] = []; 37114 $.tcepo.errorObject[ epoEventId ] = false; 37115 $.tcepo.initialActivation[ epoEventId ] = false; 37116 37117 if ( main_cart.find( tcAPI.epoSelector ).length > 0 ) { 37118 main_epo_inside_form = true; 37119 } 37120 if ( main_cart.find( '.tc-totals-form' ).length > 0 ) { 37121 main_totals_inside_form = true; 37122 } 37123 37124 if ( ! main_totals_inside_form ) { 37125 $.tcepo.formSubmitEvents[ epoEventId ][ $.tcepo.formSubmitEvents[ epoEventId ].length ] = { 37126 trigger: function() { 37127 return true; 37128 }, 37129 on_true: function() { 37130 // hidden fields see totals.php 37131 var epos_hidden = $( '.tc-totals-form.tm-product-id-' + product_id + "[data-epo-id='" + epo_id + "']" ).tcClone(); 37132 var formepo = $( '<div class="tm-hidden tm-formepo-normal"></div>' ); 37133 37134 main_cart.find( '.tm-formepo-normal' ).remove(); 37135 formepo.append( epos_hidden ); 37136 main_cart.append( formepo ); 37137 return true; 37138 }, 37139 on_false: function() { 37140 setTimeout( function() { 37141 $( '.tm-formepo-normal' ).remove(); 37142 }, 100 ); 37143 } 37144 }; 37145 } 37146 if ( ! main_epo_inside_form ) { 37147 $.tcepo.formSubmitEvents[ epoEventId ][ $.tcepo.formSubmitEvents[ epoEventId ].length ] = { 37148 trigger: function() { 37149 return true; 37150 }, 37151 on_true: function() { 37152 // visible fields 37153 var epos = $( tcAPI.epoSelector + '.tm-product-id-' + product_id + "[data-epo-id='" + epo_id + "']" ) 37154 .tcClone() 37155 .addClass( 'formepo' ); 37156 var formepo = $( '<div class="tm-hidden tm-formepo"></div>' ); 37157 37158 main_cart.find( '.tm-formepo' ).remove(); 37159 formepo.append( epos ); 37160 37161 main_cart.append( formepo ); 37162 return true; 37163 }, 37164 on_false: function() { 37165 setTimeout( function() { 37166 $( '.tm-formepo' ).remove(); 37167 }, 100 ); 37168 } 37169 }; 37170 } 37171 37172 epo_object = { 37173 main_product: main_product, 37174 main_cart: main_cart, 37175 epo_id: epo_id, 37176 form: get_main_form( main_product ), 37177 main_epo_inside_form: main_epo_inside_form, 37178 product_id_selector: product_id_selector, 37179 epo_id_selector: epo_id_selector, 37180 product_id: product_id, 37181 this_epo_container: this_epo_container, 37182 this_totals_container: this_totals_container, 37183 this_epo_totals_container: this_epo_totals_container, 37184 qtySelector: tcAPI.qtySelector, 37185 manualInitEPO: manualInitEPO, 37186 epoEventId: epoEventId, 37187 variations_form: variations_form, 37188 has_epo: has_epo, 37189 is_quickview: is_quickview, 37190 is_associated: is_associated, 37191 is_epo_shortcode: this_epo_container.is( '.tc-shortcode' ), 37192 mainEpoObject: mainEpoObject, 37193 associated_connect: associated_connect, 37194 noEpoUpdate: true 37195 }; 37196 37197 $( epo_object.form ).data( 'epo_object', epo_object ); 37198 this_epo_container.data( 'epo_object', epo_object ); 37199 37200 main_cart.data( 'product_id', product_id ).data( 'epo_id', epo_id ).data( 'product_id_selector', product_id_selector ).data( 'epo_id_selector', epo_id_selector ); 37201 37202 // tm_set_expanables(); 37203 tm_set_checkboxes_rules( epo_object ); 37204 tm_set_upload_rules( epo_object ); 37205 tm_set_datepicker( this_epo_container ); 37206 setRangePickers( this_epo_container ); 37207 setRangePickersEvents(); 37208 tm_set_repeaters( this_epo_container, epo_object ); 37209 tm_set_url_fields(); 37210 37211 $.tcToolTip( this_epo_container.find( '.tm-tooltip' ) ); 37212 37213 this_epo_container.find( '.tm-collapse' ).tmtoggle(); 37214 this_epo_container.find( '.tm-section-link' ).tmsectionpoplink(); 37215 37216 if ( reactivate ) { 37217 this_epo_container.addClass( 'reactivate' ); 37218 } 37219 37220 if ( variations_form.length > 0 ) { 37221 if ( reactivate ) { 37222 variations_form.data( 'epo_loaded', false ); 37223 } 37224 this_epo_totals_container.data( 'price', false ); 37225 if ( detect_variation_swatches ) { 37226 detect_variation_swatches_interval( epo_object ); 37227 } else { 37228 run_wc_variation_form_cpf( epo_object ); 37229 } 37230 } else { 37231 setTimeout( function() { 37232 // Start Condition Logic 37233 cpf_section_logic( epo_object ); 37234 cpf_element_logic( epo_object ); 37235 37236 jWindow.on( 'epoEventHandlers', function() { 37237 run_cpfdependson( this_epo_container ); 37238 tm_lazyload(); 37239 } ); 37240 37241 // Init field price rules 37242 $.tcepo.lateFieldsPrices[ epoEventId ] = []; 37243 epoEventHandlers( epo_object ); 37244 tm_set_upload_fields( epo_object ); 37245 tm_product_image( epo_object ); 37246 37247 jWindow.trigger( 'epo-after-init-in-timeout', { epo: epo_object } ); 37248 main_cart.trigger( 'tm-epo-check-dpd' ); 37249 epo_object.noEpoUpdate = false;
37250 main_cart.trigger( { 37251 type: 'tm-epo-update', 37252 rules: 'init' 37253 } ); 37254 }, 20 ); 37255 jWindow.trigger( 'epo-after-init', { epo: epo_object } ); 37256 } 37257 37258 tm_css_styles( this_epo_container ); 37259 tm_set_color_pickers( this_epo_container ); 37260 tm_set_lightbox( this_epo_container.find( '.tc-lightbox-image' ).not( '.tm-extra-product-options-variations .radio-image' ) ); 37261 tm_theme_specific_actions( epo_object ); 37262 tc_compatibility( epo_object ); 37263 37264 if ( ! is_associated ) { 37265 tm_floating_totals( this_epo_totals_container, is_quickview, main_cart ); 37266 tm_form_submit_event( epo_object ); 37267 epo_object = addShowHidetoEpoObject( epo_object, epoEventId, epo_object ); 37268 tm_show_hide_add_to_cart_button( main_product, epo_object ); 37269 } 37270 37271 jWindow.trigger( 'tm-epo-init-end', { 37272 epo: epo_object, 37273 replace_suffixes_in_html: replace_suffixes_in_html 37274 } ); 37275 37276 return epo_object; 37277 } 37278 37279 function manual_init( container, reactivate ) { 37280 var $this = $( container ); 37281 var product_id = $this.attr( 'data-product-id' ); 37282 var epo_id = $this.attr( 'data-epo-id' ); 37283 var quickview_floating = false; 37284 var testForm = $this.parent(); 37285 if ( ! testForm.is( 'form' ) ) { 37286 testForm = $this.closest( 'form' ); 37287 if ( ! testForm.is( 'form' ) ) { 37288 testForm = $this.parent(); 37289 } 37290 } 37291 testForm = testForm.parent(); 37292 37293 tm_init_epo( testForm, quickview_floating, product_id, epo_id, undefined, undefined, reactivate ); 37294 } 37295 37296 function init_epo_plugin() { 37297 var epo_container; 37298 var epo_options_container; 37299 37300 if ( TMEPOJS.tm_epo_no_lazy_load === 'no' ) { 37301 $.extend( $.lazyLoadXT, { 37302 autoInit: false, 37303 selector: 'img.tmlazy', 37304 srcAttr: 'data-original', 37305 visibleOnly: false, 37306 updateEvent: $.lazyLoadXT.updateEvent + ' tmlazy' 37307 } ); 37308 } 37309 /* 37310 * tm-no-options-pxq = product has not options but the "Enable Final total box for all products" is on 37311 * tm-no-options-composite = product is a composite product with no options but at least one of its bundles have options 37312 */ 37313 epo_container = $( '.tm-no-options-pxq, .tm-no-options-composite' ); 37314 37315 if ( epo_container.length > 0 ) { 37316 // Special cases 37317 // ------------- 37318 // Price x Quantity display (.tm-no-options-pxq) & composite 37319 // without option but a component has extra options 37320 // (.tm-no-options-composite) 37321 37322 epo_container.addClass( 'initializing' ); 37323 37324 epo_container.toArray().forEach( function( product_wrap ) { 37325 var inputepoid; 37326 product_wrap = $( product_wrap ); 37327 inputepoid = product_wrap.find( 'input.tm-epo-counter' ); 37328 if ( inputepoid.length > 1 ) { 37329 inputepoid.toArray().forEach( function( ec ) { 37330 var currentepoid = $( ec ); 37331 var currentcart = currentepoid.closest( '.cart' ); 37332 var currentcartparent = currentcart.parent(); 37333 if ( currentcartparent.is( 'form' ) ) { 37334 currentcartparent = currentcartparent.parent(); 37335 } 37336 37337 if ( ! currentcartparent.is( '.initializing' ) ) { 37338 tm_init_epo( currentcartparent, false, undefined, parseInt( currentepoid.val(), 10 ) ); 37339 } 37340 } ); 37341 } else { 37342 tm_init_epo( product_wrap, false ); 37343 } 37344 epo_container.removeClass( 'initializing' ); 37345 } ); 37346 } 37347 37348 // The setTimeout is used for compatibility with 37349 // skeleton screen mode that some themes have 37350 37351 setTimeout( function() { 37352 try { 37353 // new main way of calling tm_init_epo 37354 // ----------------------------------- 37355 // Normal product pages 37356 37357 epo_options_container = $( tcAPI.epoSelector ).not( tcAPI.associatedEpoSelector + ' ' + tcAPI.epoSelector + ', .tm-no-options-pxq, .tm-no-options-composite, .wc-product-table ' + tcAPI.epoSelector ); 37358 37359 if ( epo_options_container.length > 0 ) { 37360 epo_container.addClass( 'initializing' ); 37361 epo_options_container.toArray().forEach( function( ec ) { 37362 var $this = $( ec ); 37363 var product_id = $this.attr( 'data-product-id' ); 37364 var epo_id = $this.attr( 'data-epo-id' ); 37365 var quickview_floating = false; 37366 var jProductWrap;
37367 var addInputs = false; 37368 var inputepoid; 37369 37370 // First check if we are in a loop. 37371 jProductWrap = $this.closest( '.tc-after-shop-loop.tm-has-options' ); 37372 37373 if ( jProductWrap.length === 0 ) { 37374 // Check based on plugin add to cart selector. 37375 jProductWrap = $( tcAPI.tcAddToCartSelector + "[data-epo-id='" + epo_id + "'][value='" + product_id + "']" ) 37376 .closest( 'form,.cart' ) 37377 .first() 37378 .parent(); 37379 // Check based on native add to cart selector. 37380 if ( jProductWrap.length === 0 ) { 37381 jProductWrap = $( tcAPI.addToCartSelector + "[value='" + product_id + "']" ) 37382 .closest( 'form,.cart' ) 37383 .first() 37384 .parent(); 37385 if ( jProductWrap.length === 0 ) { 37386 // Check if we are in a shortcode 37387 jProductWrap = $this.closest( 'form,.cart' ).first().parent( '.tm-has-options' ); 37388 if ( jProductWrap.length === 0 ) { 37389 if ( $this.is( '.tc-shortcode' ) ) { 37390 jProductWrap = $this.wrap( '<div class="tc-shortcode-wrap tc-wrap-' + epo_id + '"></div>' ); 37391 jProductWrap = $this.parent(); 37392 } 37393 if ( jProductWrap.length > 0 ) { 37394 addInputs = true; 37395 } 37396 } 37397 } 37398 } 37399 } else { 37400 addInputs = true; 37401 } 37402 37403 if ( jProductWrap.length > 0 ) { 37404 if ( addInputs ) { 37405 // in shop (variation logic will not work here) 37406 quickview_floating = true; 37407 $this 37408 .closest( 'form,.cart' ) 37409 .first() 37410 .append( $( '<input name="add-to-cart" value="' + product_id + '" type="hidden">' ) ); 37411 $this.closest( 'form,.cart' ).first().append( $( '<input type="hidden" value="" class="variation_id" name="variation_id">' ) ); 37412 } 37413 37414 if ( jProductWrap.is( 'form' ) ) { 37415 jProductWrap = jProductWrap.parent(); 37416 } 37417 37418 inputepoid = jProductWrap.find( 'input.tm-epo-counter' ); 37419 if ( inputepoid.length > 1 ) { 37420 inputepoid.toArray().forEach( function( c ) { 37421 var currentepoid = $( c ); 37422 var currentcart = currentepoid.closest( '.cart' ); 37423 var currentcartparent = currentcart.parent(); 37424 if ( currentcartparent.is( 'form' ) ) { 37425 currentcartparent = currentcartparent.parent(); 37426 } 37427 37428 if ( ! currentcartparent.is( '.initializing' ) ) { 37429 tm_init_epo( currentcartparent, quickview_floating, product_id, parseInt( currentepoid.val(), 10 ) ); 37430 } 37431 } ); 37432 } else { 37433 tm_init_epo( jProductWrap, quickview_floating, product_id, epo_id ); 37434 } 37435 } 37436 } ); 37437 epo_container.removeClass( 'initializing' ); 37438 } 37439 } catch ( err ) { 37440 window.console.log( err ); 37441 errorObject = err; 37442 } 37443 }, 1 ); 37444 } 37445 37446 $.tcepo.tm_init_epo = function( main_product, is_quickview, product_id, epo_id ) { 37447 tm_init_epo( main_product, is_quickview, product_id, epo_id ); 37448 }; 37449 37450 $.tcepo.tmLazyloadContainer = function( container ) { 37451 tmLazyloadContainer = container; 37452 }; 37453 37454 jWindow.on( 'tc_manual_init', function( evt, container ) { 37455 var reactivate; 37456 if ( 'container' in container && 'reactivate' in container ) { 37457 reactivate = container.reactivate; 37458 container = container.container; 37459 } 37460 manual_init( container, reactivate ); 37461 } ); 37462 37463 function tcAjaxAddToCart( $this ) { 37464 var _pid; 37465 var epos; 37466 var _cpf_product_price; 37467 var _dynamic_product_price; 37468 var _override_product_price; 37469 var form_prefix; 37470 var epoid; 37471 var obj; 37472 var data; 37473 var tcTotalsForm; 37474 37475 currentAjaxButton = $this; 37476 _pid = currentAjaxButton.attr( 'data-product_id' ); 37477 if ( undefined === _pid ) { 37478 _pid = currentAjaxButton.val(); 37479 } 37480 37481 if ( undefined !== _pid ) { 37482 epoid = currentAjaxButton.closest( '.cart' ).find( '.tm-epo-counter' ).val(); 37483 if ( ! epoid ) { 37484 epoid = currentAjaxButton.attr( 'data-epo-id' ); 37485 if ( ! epoid ) { 37486 return; 37487 } 37488 } 37489 if ( currentAjaxButton.closest( '.tm-has-options' ).length !== 1 && currentAjaxButton.attr( 'data-epo-id' ) === undefined ) { 37490 return; 37491 } 37492 37493 obj = {}; 37494 37495 epos = $( tcAPI.epoSelector + '.tm-product-id-' + _pid + '[data-epo-id="' + epoid + '"]' ); 37496 37497 if ( epos.length > 1 ) { 37498 if ( epos.filter( '.formepo' ) ) { 37499 epos = epos.filter( '.formepo' ); 37500 } else { 37501 epos = epos.first(); 37502 } 37503 } 37504 37505 if ( epos.length === 1 ) { 37506 tcTotalsForm = $( '.tc-totals-form.tm-product-id-' + _pid + '[data-epo-id="' + epoid + '"]' ); 37507 _cpf_product_price = tcTotalsForm.find( '.cpf-product-price' ).val(); 37508 _dynamic_product_price = tcTotalsForm.find( '.cpf-dynamic-product-price' ).val(); 37509 _override_product_price = tcTotalsForm.find( '.cpf-override-product-price' ).val(); 37510 form_prefix = tcTotalsForm.find( '.tc_form_prefix' ).val(); 37511 37512 obj = $.extend( obj, { 37513 tcajax: 1, 37514 tcaddtocart: _pid, 37515 cpf_product_price: _cpf_product_price, 37516 dynamic_product_price: _dynamic_product_price, 37517 override_product_price: _override_product_price 37518 } ); 37519 if ( form_prefix ) { 37520 obj.tc_form_prefix = form_prefix; 37521 } 37522 } 37523 37524 data = currentAjaxButton.data(); 37525 TMEPOJS.ajaxbuttondata = $.epoAPI.util.deepCopyArray( data ); 37526 TMEPOJS.ajaxbutton = currentAjaxButton; 37527 37528 currentAjaxButton.removeData(); 37529 currentAjaxButton.data( $.extend( data, epos.tcSerializeObject(), obj ) ); 37530 37531 TMEPOJS.ajaxdata = { 37532 epos: epos, 37533 _pid: _pid, 37534 data: data 37535 }; 37536 } 37537 } 37538 37539 function ajaxAddToCartFunctions() { 37540 // Betheme ajax add to cart. 37541 $( document ).on( 'click.tcajax', 'body.mfn-ajax-add-to-cart .single_add_to_cart_button:not(.disabled)', function() { 37542 var formepo; 37543 var $this = $( this ); 37544 tcAjaxAddToCart( $this ); 37545 TMEPOJS.ajaxdata.cart = $this.closest( '.cart' ); 37546 TMEPOJS.ajaxdata.cart.find( '.tm-formepo' ).remove(); 37547 formepo = $( "<div class='tm-hidden tm-formepo'></div>" ); 37548 formepo.append( TMEPOJS.ajaxdata.epos.tcClone().addClass( 'formepo' ) ); 37549 $this.after( formepo ); 37550 } ); 37551 37552 jBody.on( 'click.tcajax', '.ajax_add_to_cart', function() { 37553 tcAjaxAddToCart( $( this ) ); 37554 if ( undefined !== TMEPOJS.ajaxdata ) { 37555 delete TMEPOJS.ajaxdata; 37556 } 37557 } ); 37558 37559 jBody.on( 'click.tcajax', '.single_add_to_cart_button', function() { 37560 currentAddToCartButton = $( this ); 37561 } ); 37562 37563 $( document.body ).on( 'added_to_cart', function() { 37564 if ( TMEPOJS.ajaxbuttondata && TMEPOJS.ajaxbutton instanceof $ ) { 37565 TMEPOJS.ajaxbutton.removeData(); 37566 TMEPOJS.ajaxbutton.data( TMEPOJS.ajaxbuttondata ); 37567 } 37568 } ); 37569 } 37570 37571 // This needs to run here to register our event handlers before WooCommerce. 37572 ajaxAddToCartFunctions(); 37573 37574 // document ready 37575 $( function() { 37576 tcAPI = $.epoAPI.applyFilter( 'tc_api', tcAPI ); 37577 37578 jWindow.on( 'lazyLoadXToncomplete', function() {
37579 $( '.tm-owl-slider' ).toArray().forEach( function( slider ) { 37580 $( slider ).trigger( 'refresh.owl.carousel' ); 37581 } ); 37582 } ); 37583 37584 jWindow.on( 'tc_init_epo_plugin', function( evt ) { 37585 init_epo_plugin( evt ); 37586 } ); 37587 37588 jWindow.on( 'tcShowLastError', function() { 37589 window.console.log( errorObject ); 37590 } ); 37591 37592 $.ajaxPrefilter( function( options, originalOptions ) { 37593 var found = false; 37594 var hashes; 37595 var hash; 37596 var i; 37597 var params; 37598 var $thisbutton; 37599 var _data; 37600 var _urldata; 37601 var _pid; 37602 var epos; 37603 var _cpf_product_price; 37604 var _dynamic_product_price; 37605 var _override_product_price; 37606 var form_prefix; 37607 var obj; 37608 var oldData; 37609 var formData; 37610 var can_be_added = false; 37611 var associativeArray = {}; 37612 var tcTotalsForm; 37613 37614 if ( TMEPOJS.tm_epo_enable_in_shop === 'yes' ) { 37615 hashes = options.url.split( '?' ); 37616 37617 if ( hashes && hashes.length >= 1 ) { 37618 hashes = hashes[ 1 ]; 37619 if ( hashes ) { 37620 hash = hashes.split( '&' ); 37621 for ( i = 0; i < hash.length; i += 1 ) { 37622 params = hash[ i ].split( '=' ); 37623 if ( params.length >= 1 ) { 37624 if ( params[ 0 ] && params[ 1 ] && params[ 0 ] === 'wc-ajax' && params[ 1 ] === 'add_to_cart' ) { 37625 found = true; 37626 } 37627 } 37628 } 37629 if ( found ) { 37630 options.originalsuccess = options.success; 37631 options.success = function( response ) { 37632 if ( response && response.error && response.product_url ) { 37633 if ( currentAjaxButton && currentAjaxButton.length === 1 ) { 37634 $thisbutton = currentAjaxButton; 37635 } 37636 $thisbutton = $( ".ajax_add_to_cart[data-product_id='" + originalOptions.data.product_id + "']" ); 37637 $thisbutton.removeClass( 'added' ); 37638 $thisbutton.removeClass( 'loading' ); 37639 } else { 37640 options.originalsuccess.call( null, response ); 37641 } 37642 }; 37643 } 37644 } 37645 } 37646 } 37647 37648 if ( FormData && originalOptions.data ) { 37649 _data = originalOptions.data; 37650 if ( typeof originalOptions.data === 'string' ) { 37651 _data = $.epoAPI.util.parseParams( originalOptions.data ); 37652 } 37653 if ( typeof _data[ 0 ] === 'object' ) { 37654 _data.forEach( function( item ) { 37655 associativeArray[ item.name ] = item.value; 37656 } ); 37657 _data = associativeArray; 37658 } 37659 37660 _urldata = []; 37661 if ( originalOptions.url && originalOptions.url.indexOf ) { 37662 _urldata = $.epoAPI.util.parseParams( originalOptions.url.slice( originalOptions.url.indexOf( '?' ) + 1 ) ); 37663 } 37664 37665 if ( 'quantity' in _data && _data.tcaddtocart && ( _data.product_id || _data[ 'add-to-cart' ] || _urldata.product_id || _urldata[ 'add-to-cart' ] ) ) { 37666 can_be_added = true; 37667 _pid = _data.tcaddtocart; 37668 } else if ( Array.isArray( _data ) ) { 37669 can_be_added = _data.some( function( item ) { 37670 return item.name === 'quantity'; 37671 } ) && _data.some( function( item ) { 37672 return item.name === 'add-to-cart'; 37673 } ) && _data.some( function( item ) { 37674 return item.name === 'tcaddtocart'; 37675 } ); 37676 _pid = _data.find( function( item ) { 37677 return item.name === 'tcaddtocart'; 37678 } ); 37679 if ( _pid ) { 37680 _pid = _pid.value; 37681 } else { 37682 _pid = false; 37683 } 37684 } 37685 37686 if ( ! _pid ) { 37687 if ( 'qty' in _data && _data.tcaddtocart ) { 37688 can_be_added = true; 37689 _pid = _data.tcaddtocart; 37690 } 37691 } 37692 37693 if ( can_be_added ) { 37694 if ( currentAjaxButton && currentAjaxButton.length === 1 && currentAjaxButton.closest( '.tm-has-options' ).length === 1 ) { 37695 epos = currentAjaxButton.closest( '.tm-has-options' ).find( tcAPI.epoSelector + '.tm-product-id-' + _pid ); 37696 } else { 37697 epos = $( tcAPI.epoSelector + '.tm-product-id-' + _pid ); 37698 } 37699 37700 if ( epos.length > 1 ) { 37701 if ( epos.filter( '.formepo' ) ) { 37702 epos = epos.filter( '.formepo' ); 37703 } else { 37704 epos = epos.first(); 37705 } 37706 } 37707 if ( epos.length === 1 ) { 37708 tcTotalsForm = $( '.tc-totals-form.tm-product-id-' + _pid ); 37709 _cpf_product_price = tcTotalsForm.find( '.cpf-product-price' ).val(); 37710 _dynamic_product_price = tcTotalsForm.find( '.cpf-dynamic-product-price' ).val(); 37711 _override_product_price = tcTotalsForm.find( '.cpf-override-product-price' ).val(); 37712 form_prefix = tcTotalsForm.find( '.tc_form_prefix' ).val(); 37713 obj = { 37714 tcajax: 1, 37715 tcaddtocart: _pid, 37716 cpf_product_price: _cpf_product_price, 37717 dynamic_product_price: _dynamic_product_price, 37718 override_product_price: _override_product_price 37719 }; 37720 if ( form_prefix ) { 37721 obj.tc_form_prefix = form_prefix; 37722 } 37723 37724 oldData = $.epoAPI.util.parseParams( options.data, true ); 37725 oldData = $.extend( oldData, epos.tcSerializeObject(), obj ); 37726 formData = new FormData(); 37727 37728 Object.keys( oldData ).forEach( function( key ) { 37729 if ( key ) { 37730 formData.append( key, oldData[ key ] ); 37731 } 37732 } ); 37733 37734 epos.find( ':file' ) 37735 .toArray() 37736 .forEach( function( el ) { 37737 for ( i = 0; i < $( el )[ 0 ].files.length; i++ ) { 37738 if ( ! el.multiple ) { 37739 formData.delete( $( el ).attr( 'name' ) ); 37740 } 37741 formData.append( $( el ).attr( 'name' ), $( el )[ 0 ].files[ i ] ); 37742 } 37743 } ); 37744 37745 options.data = formData; 37746 options.contentType = false;
37747 options.cache = false; 37748 options.processData = false; 37749 } 37750 } 37751 } 37752 } ); 37753 37754 jDocument.ajaxSuccess( function( event, request, settings ) { 37755 // quickview plugins 37756 var qv_container = TMEPOJS.quickview_array || 'null'; 37757 var fromaddons = TMEPOJS.quickview_container || 'null'; 37758 var added = {}; 37759 var selectors; 37760 var container; 37761 var product_id; 37762 var epo_id; 37763 var noProductCheck; 37764 var testContainer; 37765 var parsedUrl; 37766 var time = 1; 37767 var detectContainer; 37768 var requestContainer; 37769 37770 if ( undefined !== TMEPOJS.ajaxdata ) { 37771 TMEPOJS.ajaxdata.cart.find( '.tm-formepo' ).remove(); 37772 delete TMEPOJS.ajaxdata; 37773 } 37774 37775 parsedUrl = $.epoAPI.util.parseParams( settings.data ); 37776 if ( parsedUrl.action === 'wc_epo_get_associated_product_html' ) { 37777 return; 37778 } 37779 37780 $( '.tm-formepo-normal' ).remove(); 37781 $( '.tm-formepo' ).remove(); 37782 37783 //fix for menu cart pop up 37784 $( '.tm-cart-link' ).tmpoplink(); 37785 37786 qv_container = $.epoAPI.util.parseJSON( qv_container ); 37787 37788 fromaddons = $.epoAPI.util.parseJSON( fromaddons ); 37789 37790 for ( selectors in fromaddons ) { 37791 if ( Object.prototype.hasOwnProperty.call( fromaddons, selectors ) ) { 37792 added[ fromaddons[ selectors ][ 0 ] ] = $( fromaddons[ selectors ][ 1 ] ); 37793 } 37794 } 37795 37796 $.extend( qv_container, added ); 37797 37798 detectContainer = function() { 37799 var keyfound = false; 37800 Object.keys( qv_container ).forEach( function( key ) { 37801 if ( $( qv_container[ key ] ).length ) { 37802 keyfound = key; 37803 } 37804 } ); 37805 return keyfound; 37806 }; 37807 requestContainer = function( times ) { 37808 var id = requestAnimationFrame( function() { 37809 setTimeout( function() { 37810 requestContainer( times - 1 ); 37811 }, 200 ); 37812 } ); 37813 var key = detectContainer(); 37814 var epoContainer; 37815 var initepo; 37816 37817 if ( key || 0 === times ) { 37818 cancelAnimationFrame( id ); 37819 if ( key ) { 37820 noProductCheck = false; 37821 container = $( qv_container[ key ] ); 37822 if ( container.length > 1 && currentAddToCartButton && currentAddToCartButton.length ) { 37823 container = currentAddToCartButton.closest( qv_container[ key ] ); 37824 } 37825 if ( container.length > 1 && key !== 'quickview_pro' ) { 37826 return true; 37827 } 37828 37829 if ( key === 'woothemes_quick_view' && container.is( '.fusion-woocommerce-quick-view-container' ) ) { 37830 return true; 37831 } 37832 37833 if ( key === 'fusion_quick_view_load' && container.find( tcAPI.epoSelector ).length === 0 ) { 37834 return true; 37835 } 37836 37837 if ( key === 'woodmart_quick_shop' ) { 37838 parsedUrl = $.epoAPI.util.parseParams( settings.url ); 37839 if ( parsedUrl.action === 'woodmart_quick_shop' ) { 37840 testContainer = $( $.epoAPI.util.escapeSelector( qv_container[ key ] + '.post-' + parsedUrl.id ) ); 37841 if ( testContainer.length ) { 37842 container = testContainer; 37843 noProductCheck = true; 37844 } 37845 } 37846 } 37847 if ( key === 'woodmart_quick_view' ) { 37848 parsedUrl = $.epoAPI.util.parseParams( settings.url ); 37849 if ( parsedUrl.action === 'woodmart_quick_view' ) { 37850 testContainer = $( $.epoAPI.util.escapeSelector( qv_container[ key ] + '.post-' + parsedUrl.id ) ); 37851 if ( testContainer.length ) { 37852 container = testContainer; 37853 noProductCheck = true; 37854 } 37855 } 37856 } 37857 37858 if ( key === 'quickview_pro' ) { 37859 parsedUrl = settings.url.split( '/' ); 37860 if ( parsedUrl.length ) { 37861 testContainer = $( $.epoAPI.util.escapeSelector( qv_container[ key ] + ' .post-' + parsedUrl[ parsedUrl.length - 1 ] ) ); 37862 if ( testContainer.length ) { 37863 container = testContainer; 37864 noProductCheck = true; 37865 } 37866 } 37867 } 37868 37869 if ( key === 'exwoofood_booking_info' || key === 'wqv_popup_content' || key === 'wp_food' || key === 'jet_popup_get_content' ) { 37870 noProductCheck = true; 37871 } 37872 37873 if ( key === 'woofood' && settings.data ) { 37874 parsedUrl = $.epoAPI.util.parseParams( settings.data ); 37875 if ( parsedUrl.action === 'woofood_quickview_ajax' ) { 37876 testContainer = testContainer = container.find( 'form' ).parent(); 37877 if ( testContainer.length ) { 37878 container = testContainer; 37879 noProductCheck = true; 37880 } 37881 } 37882 } 37883 37884 if ( container.find( '.product' ).length === 0 && container.is( '.product' ) ) { 37885 noProductCheck = true; 37886 } 37887 37888 if ( ( container.find( '.product' ).length > 0 || noProductCheck ) ) { 37889 container.removeClass( 'tc-init' ); 37890 37891 if ( 37892 key === 'fusion_quick_view_load' || 37893 key === 'jet_popup_get_content' || 37894 key === 'wp_food' || 37895 key === 'woodmart_quick_shop' || 37896 key === 'woodmart_quick_view' || 37897 key === 'lightboxpro' || 37898 key === 'jckqv_quick_view' || 37899 key === 'yith_quick_view' || 37900 key === 'theme_flatsome_quick_view' 37901 ) { 37902 variationsFormIsLoaded = true; 37903 } 37904 tmLazyloadContainer = container; 37905 if ( tmLazyloadContainer.length > 1 ) { 37906 while ( tmLazyloadContainer.length > 1 ) { 37907 tmLazyloadContainer = tmLazyloadContainer.filter( function() { 37908 return $( this ).find( tcAPI.epoSelector ).length > 0; 37909 } ); 37910 if ( tmLazyloadContainer.length === 0 ) { 37911 break; 37912 } 37913 } 37914 if ( tmLazyloadContainer.length === 0 ) { 37915 setTimeout( function() { 37916 requestContainer( 10 ); 37917 }, 1000 ); 37918 37919 return true; 37920 } 37921 } 37922 37923 epoContainer = tmLazyloadContainer.find( tcAPI.epoSelector ); 37924 if ( epoContainer.length === 0 ) { 37925 delete qv_container[ key ]; 37926 requestContainer( 10 ); 37927 return true; 37928 } 37929 37930 if ( key === 'fusion_quick_view_load' ) { 37931 time = 1400; 37932 } 37933 37934 initepo = function( redo ) { 37935 setTimeout( function() {
37936 product_id = epoContainer.attr( 'data-product-id' ); 37937 epo_id = epoContainer.attr( 'data-epo-id' ); 37938 if ( key === 'woodmart_quick_shop' ) { 37939 container.addClass( 'has-options' ); 37940 } 37941 37942 // Reset element cache 37943 tcAPI.getElementFromFieldCache = []; 37944 tm_init_epo( tmLazyloadContainer, true, product_id, epo_id, undefined, undefined, redo ); 37945 jWindow.trigger( 'tmlazy' ); 37946 jWindow.trigger( 'tm_epo_loaded_quickview' ); 37947 if ( $.jMaskGlobals ) { 37948 tmLazyloadContainer.find( $.jMaskGlobals.maskElements ).toArray().forEach( function( t ) { 37949 t = $( t ); 37950 37951 if ( t.attr( 'data-mask' ) ) { 37952 t.mask( t.attr( 'data-mask' ) ); 37953 } 37954 } ); 37955 } 37956 }, time ); 37957 }; 37958 37959 initepo(); 37960 37961 if ( key === 'minimog_product_quick_view' ) { 37962 $( '.minimog-product' ).on( 'click', '.quick-view-btn', function( evt ) { 37963 var $button = $( this ); 37964 var productID = $button.data( 'pid' ); 37965 var $template = jBody.children( '#' + 'modal-quick-view-product-' + productID ); 37966 evt.preventDefault(); 37967 evt.stopPropagation(); 37968 if ( $button.hasClass( 'loading' ) ) { 37969 return; 37970 } 37971 if ( ! $.fn.MinimogModal ) { 37972 return; 37973 } 37974 if ( $template.length > 0 ) { 37975 tmLazyloadContainer = $( '.modal-quick-view-popup' ); 37976 initepo( true ); 37977 } 37978 } ); 37979 } 37980 } 37981 } 37982 } 37983 }; 37984 requestContainer( 10 ); 37985 } ); 37986 37987 init_epo_plugin(); 37988 37989 $( '.tm-cart-link' ).tmpoplink(); 37990 jBody.on( 'updated_checkout wc_fragments_loaded wc_fragments_refreshed wc_fragment_refresh', function() { 37991 $( '.tm-cart-link' ).tmpoplink(); 37992 } ); 37993 37994 jWindow.trigger( 'tmlazy' ); 37995 37996 jWindow.trigger( 'tm_epo_loaded' ); 37997 } ); 37998 37999 function associated_table_item() { 38000 $( '.tc-associated-table-product td.product-name' ).toArray().forEach( function( el ) { 38001 el = $( el ); 38002 if ( el.find( '.product-name' ).length === 0 ) { 38003 el.wrapInner( $( '<div class="tc-associated-table-product-indent"></div>' ) ); 38004 } 38005 } ); 38006 } 38007 38008 // Associated product cart indent 38009 jBody.on( 'updated_checkout updated_cart_totals', function() { 38010 associated_table_item(); 38011 } ); 38012 38013 associated_table_item(); 38014 38015 // document ready 38016 $( function() { 38017 // Remove accept attribute from upload buttons when in Facebook or Instagram internral browser 38018 var ua = navigator.userAgent || navigator.vendor || window.opera; 38019 ua = ( ua.indexOf( 'FBAN' ) > -1 ) || ( ua.indexOf( 'FBAV' ) > -1 ) || ( ua.indexOf( 'Instagram' ) > -1 ); 38020 if ( ua ) { 38021 $( '.tmcp-upload' ).removeAttr( 'accept' ); 38022 } 38023 38024 // Fix several custom quantity buttons on themes 38025 jDocument.on( 'click', '.quantity .jckqv-qty-spinner, .quantity .ui-spinner-button', function() { 38026 $( this ).closest( '.quantity' ).find( tcAPI.qtySelector ).trigger( 'change' ); 38027 } ); 38028 38029 // Quantity selector buttons 38030 $( document ).on( 'click', '.tm-quantity .tc-qty-button, .tm-quantity-alt .tc-qty-button', function() { 38031 var qty = $( this ).closest( '.tm-quantity, .tm-quantity-alt' ).find( '.tm-qty, .tm-qty-alt' ); 38032 var val = parseFloat( qty.val() ); 38033 var max = parseFloat( qty.attr( 'max' ) ); 38034 var min = parseFloat( qty.attr( 'min' ) ); 38035 var step = parseFloat( qty.attr( 'step' ) ); 38036 if ( isNaN( step ) ) { 38037 step = 1; 38038 } 38039 38040 // Change the value if plus or minus 38041 if ( $( this ).is( '.plus' ) ) { 38042 if ( ! isNaN( max ) && ( max <= val ) ) { 38043 qty.val( max ); 38044 } else { 38045 qty.val( val + step ); 38046 } 38047 } else if ( ! isNaN( min ) && ( min >= val ) ) { 38048 qty.val( min ); 38049 } else if ( val > 0 ) { 38050 qty.val( val - step ); 38051 } 38052 38053 $( this ).closest( '.tm-quantity, .tm-quantity-alt' ).find( 'input.tm-qty, input.tm-qty-alt' ).trigger( 'change' ); 38054 } ); 38055 38056 // bulk variations forms plugin 38057 $( '#wholesale_form' ).on( 'submit', function() { 38058 var _product_id = $( 'form.cart' ).find( tcAPI.addToCartSelector ).val(); 38059 // visible fields 38060 var epos = $( tcAPI.epoSelector + ".tm-cart-main[data-product-id='" + _product_id + "']" ).tcClone(); 38061 // hidden fields see totals.php 38062 var epos_hidden = $( ".tm-totals-form-main[data-product-id='" + _product_id + "']" ).tcClone(); 38063 var formepo = $( "<div class='tm-hidden tm-formepo'></div>" ); 38064 38065 formepo.append( epos ); 38066 formepo.append( epos_hidden ); 38067 $( this ).append( formepo ); 38068 return true; 38069 } ); 38070 38071 // Disable quote button if option validation fails 38072 jDocument.on( 'click', '#add_to_quote', function( e ) { 38073 var form; 38074 var epo_id; 38075 var epos; 38076 38077 if ( TMEPOJS && TMEPOJS.tm_epo_global_enable_validation === 'yes' ) { 38078 form = $( this ).parents( 'form' ); 38079 epo_id = parseInt( form.find( '.tm-epo-counter' ).val(), 10 ); 38080 epos = $( tcAPI.epoSelector + "[data-epo-id='" + epo_id + "']" ); 38081
38082 // not validated 38083 if ( TMEPOJS.tm_epo_global_enable_validation === 'yes' && $.tc_validator && form.length > 0 && epos.length > 0 && ! form.tc_validate().form() ) { 38084 e.stopImmediatePropagation(); 38085 } 38086 } 38087 } ); 38088 38089 // PayPal for WooCommerce (PayPal Express Checkout button fix) 38090 $( '.single_add_to_cart_button.paypal_checkout_button' ).on( 'click', function( event ) { 38091 // this is the selector used by the paypal checkout plugin 38092 var form = $( '.cart' ); 38093 var validator; 38094 38095 if ( form.data( 'tc_validator' ) ) { 38096 validator = form.data( 'tc_validator' ); 38097 if ( validator.errorList ) { 38098 event.stopImmediatePropagation(); 38099 } 38100 } 38101 } ); 38102 38103 $( '.wc-product-table' ).on( 'init.wcpt', function( event, table ) { 38104 table.$table.find( tcAPI.epoSelector ).addClass( 'hidden' ); 38105 table.$table.find( 'thead tr' ).append( '<th> </th>' ); 38106 setTimeout( function() { 38107 table.$table.find( '.cart:not(.cart_group)' ).toArray().forEach( function( c ) { 38108 var epo = $( c ).find( tcAPI.epoSelector ); 38109 var tr = epo.closest( 'tr' ); 38110 38111 $( "<td class='wc-product-table-epo'></td>" ).appendTo( tr ).append( epo ); 38112 $( window ).trigger( 'tc_manual_init', epo ); 38113 epo.removeClass( 'hidden' ); 38114 } ); 38115 }, 500 ); 38116 } ); 38117 38118 // Generate product link. 38119 $( '.generate-product-link' ).on( 'click', function( e ) { 38120 var url = new URL( window.location.href ); 38121 var params = url.searchParams; 38122 var newUrl; 38123 var processedRadios = {}; 38124 38125 e.preventDefault(); 38126 38127 /* Build the query-string from the fields inside #myFormDiv */ 38128 $( tcAPI.epoSelector + ':visible' ).find( '.tm-epo-field:enabled' ).each( function() { 38129 var name = this.name; 38130 var value; 38131 var checkedRadio; 38132 if ( this.type === 'radio' ) { 38133 if ( processedRadios[ name ] ) { 38134 return; 38135 } 38136 processedRadios[ name ] = true; 38137 38138 // Find the checked radio in this group 38139 checkedRadio = $( tcAPI.epoSelector + ':visible' ) 38140 .find( '.tm-epo-field[name="' + name + '"]:checked' ); 38141 38142 value = checkedRadio.length ? checkedRadio.val() : ''; 38143 } else if ( this.type === 'checkbox' ) { 38144 value = this.checked ? this.value : ''; 38145 } else { 38146 value = $( this ).val(); 38147 } 38148 38149 if ( name && value !== '' ) { 38150 params.set( name, value ); 38151 } 38152 if ( value === '' ) { 38153 params.delete( name ); 38154 } 38155 } ); 38156 38157 /* Remove empty values we just stored above */ 38158 for ( const [ key, val ] of params.entries() ) { 38159 if ( val === '' ) { 38160 params.delete( key ); 38161 } 38162 } 38163 38164 /* Update the browser URL without reloading the page */ 38165 newUrl = url.toString(); 38166 history.replaceState( null, null, newUrl ); 38167 navigator.clipboard.writeText( newUrl ).then( function() { 38168 window.alert( 'Link copied to clipboard:\n' + newUrl ); 38169 } ).catch( function( err ) { 38170 window.console.error( 'Could not copy: ', err ); 38171 } ); 38172 } ); 38173 } ); 38174}( window, document, window.jQuery ) ); 38175; 38176(()=>{"use strict";var t={d:(e,i)=>{for(var s in i)t.o(i,s)&&!t.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:i[s]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};function i(t){if(this.formData={},this.tree={},!(t instanceof FormData))return this;this.formData=t;const e=()=>{const t=new Map;return t.largestIndex=0,t.set=function(e,i){""===e?e=t.largestIndex++:/^[0-9]+$/.test(e)&&(e=parseInt(e),t.largestIndex<=e&&(t.largestIndex=e+1)),Map.prototype.set.call(t,e,i)},t};this.tree=e();const i=/^(?<name>[a-z][-a-z0-9_:]*)(?<array>(?:\[(?:[a-z][-a-z0-9_:]*|[0-9]*)\])*)/i;for(const[t,s]of this.formData){const o=t.match(i);if(o)if(""===o.groups.array)this.tree.set(o.groups.name,s);else{const t=[...o.groups.array.matchAll(/\[([a-z][-a-z0-9_:]*|[0-9]*)\]/gi)].map((([t,e])=>e));t.unshift(o.groups.name);const i=t.pop();t.reduce(((t,i)=>{if(/^[0-9]+$/.test(i)&&(i=parseInt(i)),t.get(i)instanceof Map)return t.get(i);const s=e();return t.set(i,s),s}),this.tree).set(i,s)}}}t.r(e),t.d(e,{all:()=>D,any:()=>M,date:()=>m,dayofweek:()=>u,email:()=>r,enum:()=>h,file:()=>d,maxdate:()=>z,maxfilesize:()=>j,maxitems:()=>v,maxlength:()=>x,maxnumber:()=>y,mindate:()=>A,minfilesize:()=>$,minitems:()=>w,minlength:()=>g,minnumber:()=>b,number:()=>c,required:()=>n,requiredfile:()=>a,stepnumber:()=>I,tel:()=>l,time:()=>f,url:()=>p}),i.prototype.entries=function(){return this.tree.entries()},i.prototype.get=function(t){return this.tree.get(t)},i.prototype.getAll=function(t){if(!this.has(t))return[];const e=t=>{const i=[];if(t instanceof Map)for(const[s,o]of t)i.push(...e(o));else""!==t&&i.push(t);return i};return e(this.get(t))},i.prototype.has=function(t){return this.tree.has(t)},i.prototype.keys=function(){return this.tree.keys()},i.prototype.values=function(){return this.tree.values()};const s=i;function o({rule:t,field:e,error:i,...s}){this.rule=t,this.field=e,this.error=i,this.properties=s}const n=function(t){if(0===t.getAll(this.field).map((t=>t.trim())).filter((t=>""!==t)).length)throw new o(this)},a=function(t){if(0===t.getAll(this.field).length)throw new o(this)},r=function(t){if(!t.getAll(this.field).map((t=>t.trim())).filter((t=>""!==t)).every((t=>{if(t.length<6)return!1;if(-1===t.indexOf("@",1))return!1;if(t.indexOf("@")!==t.lastIndexOf("@"))return!1;const[e,i]=t.split("@",2);if(!/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]+$/.test(e))return!1;if(/\.{2,}/.test(i))return!1;if(/(?:^[ \t\n\r\0\x0B.]|[ \t\n\r\0\x0B.]$)/.test(i))return!1;const s=i.split(".");if(s.length<2)return!1;for(const t of s){if(/(?:^[ \t\n\r\0\x0B-]|[ \t\n\r\0\x0B-]$)/.test(t))return!1;if(!/^[a-z0-9-]+$/i.test(t))return!1}return!0})))throw new o(this)},p=function(t){const e=t.getAll(this.field).map((t=>t.trim())).filter((t=>""!==t));if(!e.every((t=>{try{return(t=>-1!==["http","https","ftp","ftps","mailto","news","irc","irc6","ircs","gopher","nntp","feed","telnet","mms","rtsp","sms","svn","tel","fax","xmpp","webcal","urn"].indexOf(t))(new URL(t).protocol.replace(/:$/,""))}catch{return!1}}
38176)))throw new o(this)},l=function(t){if(!t.getAll(this.field).map((t=>t.trim())).filter((t=>""!==t)).every((t=>(((t=(t=t.replace(/[#*].*$/,"")).replaceAll(/[()/.*#\s-]+/g,"")).startsWith("+")||t.startsWith("00"))&&(t=`+${t.replace(/^[+0]+/,"")}`),!!/^[+]?[0-9]+$/.test(t)&&5<t.length&&t.length<16))))throw new o(this)},c=function(t){if(!t.getAll(this.field).map((t=>t.trim())).filter((t=>""!==t)).every((t=>!!/^[-]?[0-9]+(?:[eE][+-]?[0-9]+)?$/.test(t)||!!/^[-]?(?:[0-9]+)?[.][0-9]+(?:[eE][+-]?[0-9]+)?$/.test(t))))throw new o(this)},m=function(t){if(!t.getAll(this.field).map((t=>t.trim())).filter((t=>""!==t)).every((t=>{if(!/^[0-9]{4,}-[0-9]{2}-[0-9]{2}$/.test(t))return!1;const e=new Date(t);return!Number.isNaN(e.valueOf())})))throw new o(this)},f=function(t){if(!t.getAll(this.field).map((t=>t.trim())).filter((t=>""!==t)).every((t=>{const e=t.match(/^([0-9]{2})\:([0-9]{2})(?:\:([0-9]{2}))?$/);if(!e)return!1;const i=parseInt(e[1]),s=parseInt(e[2]),o=e[3]?parseInt(e[3]):0;return 0<=i&&i<=23&&0<=s&&s<=59&&0<=o&&o<=59})))throw new o(this)},d=function(t){if(!t.getAll(this.field).every((t=>t instanceof File&&this.accept?.some((e=>/^\.[a-z0-9]+$/i.test(e)?t.name.toLowerCase().endsWith(e.toLowerCase()):(t=>{const e=[],i=t.match(/^(?<toplevel>[a-z]+)\/(?<sub>[*]|[a-z0-9.+-]+)$/i);if(i){const t=i.groups.toplevel.toLowerCase(),s=i.groups.sub.toLowerCase();for(const[o,n]of(()=>{const t=new Map;return t.set("jpg|jpeg|jpe","image/jpeg"),t.set("gif","image/gif"),t.set("png","image/png"),t.set("bmp","image/bmp"),t.set("tiff|tif","image/tiff"),t.set("webp","image/webp"),t.set("ico","image/x-icon"),t.set("heic","image/heic"),t.set("asf|asx","video/x-ms-asf"),t.set("wmv","video/x-ms-wmv"),t.set("wmx","video/x-ms-wmx"),t.set("wm","video/x-ms-wm"),t.set("avi","video/avi"),t.set("divx","video/divx"),t.set("flv","video/x-flv"),t.set("mov|qt","video/quicktime"),t.set("mpeg|mpg|mpe","video/mpeg"),t.set("mp4|m4v","video/mp4"),t.set("ogv","video/ogg"),t.set("webm","video/webm"),t.set("mkv","video/x-matroska"),t.set("3gp|3gpp","video/3gpp"),t.set("3g2|3gp2","video/3gpp2"),t.set("txt|asc|c|cc|h|srt","text/plain"),t.set("csv","text/csv"),t.set("tsv","text/tab-separated-values"),t.set("ics","text/calendar"),t.set("rtx","text/richtext"),t.set("css","text/css"),t.set("htm|html","text/html"),t.set("vtt","text/vtt"),t.set("dfxp","application/ttaf+xml"),t.set("mp3|m4a|m4b","audio/mpeg"),t.set("aac","audio/aac"),t.set("ra|ram","audio/x-realaudio"),t.set("wav","audio/wav"),t.set("ogg|oga","audio/ogg"),t.set("flac","audio/flac"),t.set("mid|midi","audio/midi"),t.set("wma","audio/x-ms-wma"),t.set("wax","audio/x-ms-wax"),t.set("mka","audio/x-matroska"),t.set("rtf","application/rtf"),t.set("js","application/javascript"),t.set("pdf","application/pdf"),t.set("swf","application/x-shockwave-flash"),t.set("class","application/java"),t.set("tar","application/x-tar"),t.set("zip","application/zip"),t.set("gz|gzip","application/x-gzip"),t.set("rar","application/rar"),t.set("7z","application/x-7z-compressed"),t.set("exe","application/x-msdownload"),t.set("psd","application/octet-stream"),t.set("xcf","application/octet-stream"),t.set("doc","application/msword"),t.set("pot|pps|ppt","application/vnd.ms-powerpoint"),t.set("wri","application/vnd.ms-write"),t.set("xla|xls|xlt|xlw","application/vnd.ms-excel"),t.set("mdb","application/vnd.ms-access"),t.set("mpp","application/vnd.ms-project"),t.set("docx","application/vnd.openxmlformats-officedocument.wordprocessingml.document"),t.set("docm","application/vnd.ms-word.document.macroEnabled.12"),t.set("dotx","application/vnd.openxmlformats-officedocument.wordprocessingml.template"),t.set("dotm","application/vnd.ms-word.template.macroEnabled.12"),t.set("xlsx","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),t.set("xlsm","application/vnd.ms-excel.sheet.macroEnabled.12"),t.set("xlsb","application/vnd.ms-excel.sheet.binary.macroEnabled.12"),t.set("xltx","application/vnd.openxmlformats-officedocument.spreadsheetml.template"),t.set("xltm","application/vnd.ms-excel.template.macroEnabled.12"),t.set("xlam","application/vnd.ms-excel.addin.macroEnabled.12"),t.set("pptx","application/vnd.openxmlformats-officedocument.presentationml.presentation"),t.set("pptm","application/vnd.ms-powerpoint.presentation.macroEnabled.12"),t.set("ppsx","application/vnd.openxmlformats-officedocument.presentationml.slideshow"),t.set("ppsm","application/vnd.ms-powerpoint.slideshow.macroEnabled.12"),t.set("potx","application/vnd.openxmlformats-officedocument.presentationml.template"),t.set("potm","application/vnd.ms-powerpoint.template.macroEnabled.12"),t.set("ppam","application/vnd.ms-powerpoint.addin.macroEnabled.12"),t.set("sldx","application/vnd.openxmlformats-officedocument.presentationml.slide"),t.set("sldm","application/vnd.ms-powerpoint.slide.macroEnabled.12"),t.set("onetoc|onetoc2|onetmp|onepkg","application/onenote"),t.set("oxps","application/oxps"),t.set("xps","application/vnd.ms-xpsdocument"),t.set("odt","application/vnd.oasis.opendocument.text"),t.set("odp","application/vnd.oasis.opendocument.presentation"),t.set("ods","application/vnd.oasis.opendocument.spreadsheet"),t.set("odg","application/vnd.oasis.opendocument.graphics"),t.set("odc","application/vnd.oasis.opendocument.chart"),t.set("odb","application/vnd.oasis.opendocument.database"),t.set("odf","application/vnd.oasis.opendocument.formula"),t.set("wp|wpd","application/wordperfect"),t.set("key","application/vnd.apple.keynote"),t.set("numbers","application/vnd.apple.numbers"),t.set("pages","application/vnd.apple.pages"),t})())("*"===s&&n.startsWith(t+"/")||n===i[0])&&e.push(...o.split("|"))}return e})(e).some((e=>(e="."+e.trim(),t.name.toLowerCase().endsWith(e.toLowerCase())))))))))throw new o(this)},h=function(t){if(!t.getAll(this.field).map((t=>t.trim())).filter((t=>""!==t)).every((t=>this.accept?.some((e=>
38176t===String(e))))))throw new o(this)},u=function(t){if(!t.getAll(this.field).map((t=>t.trim())).filter((t=>""!==t)).every((t=>{const e=0===(i=new Date(t).getDay())?7:i;var i;return this.accept?.some((t=>e===parseInt(t)))})))throw new o(this)},w=function(t){if(t.getAll(this.field).map((t=>t.trim())).filter((t=>""!==t)).length<parseInt(this.threshold))throw new o(this)},v=function(t){const e=t.getAll(this.field).map((t=>t.trim())).filter((t=>""!==t));if(parseInt(this.threshold)<e.length)throw new o(this)},g=function(t){const e=t.getAll(this.field).map((t=>t.trim())).filter((t=>""!==t));let i=0;if(e.forEach((t=>{"string"==typeof t&&(i+=t.length)})),0!==i&&i<parseInt(this.threshold))throw new o(this)},x=function(t){const e=t.getAll(this.field).map((t=>t.trim())).filter((t=>""!==t));let i=0;if(e.forEach((t=>{"string"==typeof t&&(i+=t.length)})),parseInt(this.threshold)<i)throw new o(this)},b=function(t){if(!t.getAll(this.field).map((t=>t.trim())).filter((t=>""!==t)).every((t=>!(parseFloat(t)<parseFloat(this.threshold)))))throw new o(this)},y=function(t){if(!t.getAll(this.field).map((t=>t.trim())).filter((t=>""!==t)).every((t=>!(parseFloat(this.threshold)<parseFloat(t)))))throw new o(this)},A=function(t){if(!t.getAll(this.field).map((t=>t.trim())).filter((t=>""!==t)).every((t=>!(/^[0-9]{4,}-[0-9]{2}-[0-9]{2}$/.test(t)&&/^[0-9]{4,}-[0-9]{2}-[0-9]{2}$/.test(this.threshold)&&t<this.threshold))))throw new o(this)},z=function(t){if(!t.getAll(this.field).map((t=>t.trim())).filter((t=>""!==t)).every((t=>!(/^[0-9]{4,}-[0-9]{2}-[0-9]{2}$/.test(t)&&/^[0-9]{4,}-[0-9]{2}-[0-9]{2}$/.test(this.threshold)&&this.threshold<t))))throw new o(this)},$=function(t){const e=t.getAll(this.field);let i=0;if(e.forEach((t=>{t instanceof File&&(i+=t.size)})),i<parseInt(this.threshold))throw new o(this)},j=function(t){const e=t.getAll(this.field);let i=0;if(e.forEach((t=>{t instanceof File&&(i+=t.size)})),parseInt(this.threshold)<i)throw new o(this)},I=function(t){const e=t.getAll(this.field).map((t=>t.trim())).filter((t=>""!==t)),i=parseFloat(this.base),s=parseFloat(this.interval);if(!(0<s))return!0;if(!e.every((t=>{const e=(parseFloat(t)-i)%s;return"0.000000"===Math.abs(e).toFixed(6)||"0.000000"===Math.abs(e-s).toFixed(6)})))throw new o(this)},O=({ruleObj:t,options:i})=>{const{rule:s,...o}=t;return"function"==typeof e[s]&&("function"!=typeof e[s].matches||e[s].matches(o,i))},E=({ruleObj:t,formDataTree:i,options:s})=>{const{rule:o}=t;e[o].call(t,i,s)},k=[],F=t=>[...k].reduce(((t,e)=>i=>e(i,t)),t),D=function(t,e={}){const i=(this.rules??[]).filter((t=>O({ruleObj:t,options:e}))),s=F(E);if(!i.every((i=>{try{s({ruleObj:i,formDataTree:t,options:e})}catch(t){if(!(t instanceof o))throw t;if(void 0!==t.error)throw t;return!1}return!0})))throw new o(this)},M=function(t,e={}){const i=(this.rules??[]).filter((t=>O({ruleObj:t,options:e}))),s=F(E);if(!i.some((i=>{try{s({ruleObj:i,formDataTree:t,options:e})}catch(t){if(!(t instanceof o))throw t;return!1}return!0})))throw new o(this)};var L;window.swv={validators:e,validate:(t,e,i={})=>{const n=(t.rules??[]).filter((t=>O({ruleObj:t,options:i})));if(!n.length)return new Map;const a=F(E),r=new s(e),p=n.reduce(((t,e)=>{try{a({ruleObj:e,formDataTree:r,options:i})}catch(e){if(!(e instanceof o))throw e;if(void 0!==e.field&&!t.has(e.field)&&void 0!==e.error)return t.set(e.field,e)}return t}),new Map);for(const t of r.keys())p.has(t)||p.set(t,{validInputs:r.getAll(t)});return p},use:t=>{k.push(t)},...null!==(L=window.swv)&&void 0!==L?L:{}}})();;
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.