1/** 2 * Check if Cash has been replaced by jQuery. If it has not, set jQuery 3 * as a `window` element. 4 */ 5 if (typeof jQuery === 'undefined') { 6 window.jQuery = cash = $; 7} 8 9 10(function (mivaJS) {}(window.mivaJS || (window.mivaJS = {}))); 11 12/** 13 * Cash/jQuery Extensions 14 */ 15$.extend({ 16 debounced: function (fn, timeout, invokeAsap, ctx) { 17 /** 18 * Custom function to allow us to delay events until after the 19 * trigger has ended. 20 * 21 * Example: $(window).on('resize', $.debounced(function () {...DO SOMETHING...}, 100)); 22 */ 23 if (arguments.length === 3 && typeof invokeAsap !== 'boolean') { 24 ctx = invokeAsap; 25 invokeAsap = false; 26 } 27 var timer; 28 29 return function () { 30 var args = arguments; 31 32 ctx = ctx || this; 33 invokeAsap && !timer && fn.apply(ctx, args); 34 clearTimeout(timer); 35 timer = setTimeout(function () { 36 invokeAsap || fn.apply(ctx, args); 37 timer = null; 38 }, timeout); 39 }; 40 }, 41 hook: function (hookName) { 42 /** 43 * Custom function to allow us to unify event triggers/binding 44 * using `data-` elements. 45 * 46 * Usage: $.hook('HOOK NAME')... 47 * Example: $.hook('open-menu').on('click', function (e) {e.preventDefault(); ELEMENT.show();}); 48 */ 49 var selector; 50 51 if (!hookName || hookName === '*') { 52 // select all data-hooks 53 selector = '[data-hook]'; 54 } 55 else { 56 // select specific data-hook 57 selector = '[data-hook~="' + hookName + '"]'; 58 } 59 return $(selector); 60 }, 61 loadScript: function (url, callback) { 62 /** 63 * Loads a JavaScript file asynchronously with a callback, like 64 * jQuery's `$.getScript()` except without jQuery. 65 * 66 * Usage: 67 * $.loadScript(FILE_PATH, function () { 68 * DO SOMETHING... 69 * }); 70 */ 71 var head = document.getElementsByTagName('head')[0]; 72 var scriptCalled = document.createElement('script'); 73 74 scriptCalled.async = true; 75 scriptCalled.src = url; 76 scriptCalled.onload = scriptCalled.onreadystatechange = function () { 77 if (!scriptCalled.readyState || /loaded|complete/.test(scriptCalled.readyState)) { 78 scriptCalled.onload = scriptCalled.onreadystatechange = null; 79 80 if (head && scriptCalled.parentNode) { 81 head.removeChild(scriptCalled) 82 } 83 84 scriptCalled = undefined; 85 86 if (callback) { 87 callback(); 88 } 89 } 90 }; 91 //head.insertBefore(scriptCalled, head.firstChild); 92 head.appendChild(scriptCalled) 93 } 94}); 95 96 97/** 98 * HTML Class Name 99 * This function will check if JavaScript is enabled, detect touch and hover 100 * capabilities, and modify the class list as needed. 101 */ 102(function () { 103 'use strict'; 104 105 var html = document.documentElement; 106 107 html.classList.remove('no-js'); 108 html.classList.add('js'); 109 110 /** 111 * Detect if the user is utilizing a touch interface. 112 */ 113 window.addEventListener('touchstart', function onFirstTouch() { 114 html.classList.add('touch'); 115 html.setAttribute('data-touch', ''); 116 window.USER_IS_TOUCHING = true; 117 sessionStorage.setItem('USER_IS_TOUCHING', true); 118 window.USER_CAN_HOVER = false; 119 sessionStorage.setItem('USER_CAN_HOVER', false); 120 window.removeEventListener('touchstart', onFirstTouch, false); 121 }, false); 122 123 /** 124 * Detect if the user can hover over elements. 125 */ 126 window.addEventListener('mouseover', function onFirstHover() { 127 window.USER_CAN_HOVER = true; 128 sessionStorage.setItem('USER_CAN_HOVER', true); 129 html.classList.remove('touch'); 130 html.removeAttribute('data-touch'); 131 window.USER_IS_TOUCHING = false; 132 sessionStorage.setItem('USER_IS_TOUCHING', false); 133 window.removeEventListener('mouseover', onFirstHover, false); 134 }, false); 135}()); 136 137 138/** 139 * Breakpoints 140 * This function will retrieve the breakpoint value set via CSS. You can use 141 * this to trigger a function based on the predefined breakpoints rather than 142 * a randomly chosen one. 143 * 144 * Usage: 145 * if (breakpoint === 'medium') { 146 * yourFunctionCall(); 147 * } 148 */ 149// Setup the breakpoint variable 150var breakpoint; 151 152// Get the current breakpoint 153var getBreakpoint = function () { 154 return window.getComputedStyle(document.body, '::before').content.replace(/\"/g, ''); 155};
156 157// Setup a timer 158var timeout; 159 160// Calculate breakpoint on page load 161breakpoint = getBreakpoint(); 162 163// Listen for resize events 164window.addEventListener('resize', function (event) { 165 // If there's a timer, cancel it 166 if (timeout) { 167 window.cancelAnimationFrame(timeout); 168 } 169 170 // Setup the new requestAnimationFrame() 171 timeout = window.requestAnimationFrame(function () { 172 breakpoint = getBreakpoint(); 173 }); 174 175}, false); 176 177 178/** 179 * CSS Feature Detect - Used in place of Modernizr 180 * Returns true or false depending on your browser. Let's hope it's true. 181 * NOTE: This may be removed in future versions of the framework as 182 * browser compatibility and support changes. 183 * 184 * Usage: detectCSSFeature('transition'); 185 */ 186function detectCSSFeature(featureName) { 187 'use strict'; 188 189 var feature = false, 190 domPrefixes = 'Moz ms Webkit'.split(' '), 191 elm = document.createElement('div'), 192 featureNameCapital = null; 193 194 featureName = featureName.toLowerCase(); 195 if (elm.style[featureName] !== undefined) { 196 feature = true; 197 } 198 if (feature === false) { 199 featureNameCapital = featureName.charAt(0).toUpperCase() + featureName.substr(1); 200 for (var i = 0; i < domPrefixes.length; i++) { 201 if (elm.style[domPrefixes[i] + featureNameCapital] !== undefined) { 202 feature = true; 203 break; 204 } 205 } 206 } 207 return feature; 208} 209 210 211/** 212 * A complete cookies reader/writer framework with full unicode support. 213 * 214 * Revision #1 - September 4, 2014 215 * https://developer.mozilla.org/en-US/docs/Web/API/document.cookie 216 * https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie/Simple_document.cookie_framework 217 * https://developer.mozilla.org/User:fusionchess 218 * https://github.com/madmurphy/cookies.js 219 * 220 * This framework is released under the GNU Public License, version 3 or later. 221 * http://www.gnu.org/licenses/gpl-3.0-standalone.html 222 * 223 * Syntax: 224 * docCookies.setItem(name, value[, end[, path[, domain[, secure]]]]); 225 * docCookies.getItem(name); 226 * docCookies.removeItem(name[, path[, domain]]); 227 * docCookies.hasItem(name); 228 * docCookies.keys(); 229 */ 230var docCookies = { 231 getItem: function (sKey) { 232 if (!sKey) { 233 return null; 234 } 235 return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; 236 }, 237 setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { 238 if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { 239 return false; 240 } 241 var sExpires = ""; 242 if (vEnd) { 243 switch (vEnd.constructor) { 244 case Number: 245 sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd; 246 break; 247 case String: 248 sExpires = "; expires=" + vEnd; 249 break; 250 case Date: 251 sExpires = "; expires=" + vEnd.toUTCString(); 252 break; 253 } 254 } 255 document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : ""); 256 return true; 257 }, 258 removeItem: function (sKey, sPath, sDomain) { 259 if (!this.hasItem(sKey)) { 260 return false; 261 } 262 document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : ""); 263 return true; 264 }, 265 hasItem: function (sKey) { 266 if (!sKey) { 267 return false; 268 } 269 return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); 270 }, 271 keys: function () { 272 var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/); 273 for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) { 274 aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); 275 } 276 return aKeys; 277 } 278}; 279 280 281var elementsUI = { 282 site: function () { 283 /** 284 * Load the `polyfills.js` file and initialise functions. 285 * NOTE: This may be removed in future versions of the framework as 286 * browser compatibility and support changes. 287 */ 288 if (!window.CSS || !window.CSS.supports('(--foo: red)')) { 289 $.loadScript(theme_path + 'core/js/polyfills.js', function () { 290 sessionStorage.setItem('outdated', true); 291 cssCapabilities.init(); 292 }); 293 } 294 295 296 /** 297 * Load the `mini-modal.js` file and initialize functions if modal elements exist. 298 * This is the default set of modal/light box functionality supplied with the framework. 299 */ 300 var targets = document.querySelectorAll('[data-mini-modal]'); 301 302 if (targets.length) { 303 $.loadScript(theme_path + 'core/js/mini-modal.js', function () { 304 for (var i = 0; i < targets.length; i += 1) { 305 var modal = minimodal(targets[i], { 306 // If you would like a global onLoaded callback, add your function here 307 //onLoaded: function () {}, 308 // If you would like a global onClosed callback, add your function here 309 //onClosed: function () {}, 310 // If you are using, and have, a Google Maps API Key, enter it here. 311 googleMapsAPIKey: '' 312 });
313 314 if (!targets[i].id) { 315 targets[i].id = 'miniModal_' + i; 316 } 317 modal.init(); 318 } 319 }); 320 } 321 322 323 /** 324 * Although NodeList is not an Array, it is possible to iterate on it using forEach(). 325 * It can also be converted to an Array using Array.from(). 326 * However some older browsers have not yet implemented NodeList.forEach() nor Array.from(). 327 * But those limitations can be circumvented by using Array.prototype.forEach(). 328 * This polyfill adds compatibility to browsers which do not support NodeList.forEach(). [IE11] 329 */ 330 if (window.NodeList && !NodeList.prototype.forEach) { 331 NodeList.prototype.forEach = function (callback, thisArg) { 332 thisArg = thisArg || window; 333 for (var i = 0; i < this.length; i++) { 334 callback.call(thisArg, this[i], i, this); 335 } 336 }; 337 } 338 339 }, 340 341 pages: { 342 /* ---------- 343 Common : 344 ---------- */ 345 common: function () { 346 /** 347 * Add `ID` and `CLASS` attributes to `INPUT` and `SELECT` elements 348 * dynamically created by Miva. 349 */ 350 var mvtInputWraps = document.querySelectorAll('[data-hook~="mvt-input"]'); 351 var mvtSelectWraps = document.querySelectorAll('[data-hook~="mvt-select"]'); 352 353 mvtInputWraps.forEach(function (element) { 354 var classes = element.getAttribute('data-classlist'); 355 var id = element.getAttribute('data-id'); 356 var mvtInputs = element.querySelectorAll('input'); 357 358 mvtInputs.forEach(function (mvtInput) { 359 if (mvtInput.getAttribute('type') !== 'hidden') { 360 mvtInput.setAttribute('class', classes); 361 mvtInput.setAttribute('id', id); 362 } 363 }); 364 }); 365 366 mvtSelectWraps.forEach(function (element) { 367 var classes = element.getAttribute('data-classlist'); 368 var id = element.getAttribute('data-id'); 369 var mvtSelects = element.querySelectorAll('select'); 370 371 mvtSelects.forEach(function (mvtSelect) { 372 mvtSelect.setAttribute('class', classes); 373 mvtSelect.setAttribute('id', id); 374 }); 375 }); 376 377 }, 378 379 jsSFNT: function () { 380 }, 381 382 jsCTGY: function () { 383 }, 384 385 jsPROD: function () { 386 /** 387 * This removes the default Miva `closeup_backing` container. 388 */ 389 var closeupBacking = document.querySelector('div.closeup_backing'); 390 391 window.addEventListener('load', function () { 392 if (closeupBacking) { 393 closeupBacking.parentNode.removeChild(document.querySelector('div.closeup_backing')); 394 } 395 }); 396 397 }, 398 399 jsPATR: function () { 400 }, 401 402 jsBASK: function () { 403 /** 404 * Estimate Shipping 405 */ 406 mivaJS.estimateShipping = function (element) { 407 'use strict'; 408 409 var currentModal = document.querySelector('[data-hook="' + element + '"]'); 410 var formElement = currentModal.querySelector('[data-hook="shipping-estimate-form"]'); 411 var formButton = formElement.querySelector('[data-hook="calculate-shipping-estimate"]'); 412 413 function createCalculation () { 414 var processor = document.createElement('iframe'); 415 416 processor.id = 'calculate-shipping'; 417 processor.name = 'calculate-shipping'; 418 processor.style.display = 'none'; 419 formElement.before(processor); 420 processor.addEventListener('load', function () { 421 displayResults(processor); 422 }); 423 formElement.submit(); 424 } 425 426 function displayResults (source) { 427 var content = source.contentWindow.document.body.innerHTML; 428 429 formElement.querySelector('[data-hook="shipping-estimate-fields"]').classList.add('u-hidden'); 430 formElement.querySelector('[data-hook="shipping-estimate-results"]').innerHTML = content; 431 formElement.setAttribute('data-status', 'idle'); 432 433 formElement.querySelector('[data-hook="shipping-estimate-recalculate"]').addEventListener('click', function () { 434 formElement.querySelector('[data-hook="shipping-estimate-results"]').innerHTML = ''; 435 formElement.querySelector('[data-hook="shipping-estimate-fields"]').classList.remove('u-hidden'); 436 }); 437 438 setTimeout( 439 function () { 440 source.parentNode.removeChild(source); 441 }, 1 442 ); 443 } 444 445 formButton.addEventListener('click', function (event) { 446 event.preventDefault(); 447 createCalculation(); 448 }, false); 449 }; 450 451 }, 452 453 jsORDL: function () { 454 }, 455 456 jsOCST: function () { 457 /** 458 * Use AJAX for coupon form to prevent page refresh. 459 * https://github.com/mivaecommerce/readytheme-shadows/issues/54 460 */ 461 (function (document) { 462 'use strict'; 463 464 document.addEventListener('click', function (evt) { 465 var submitButton = document.querySelector('[data-hook="basket__coupon-form-submit"]'); 466 var submitButtonText = ((submitButton.nodeName.toLowerCase() === 'input') ? submitButton.value : submitButton.textContent); 467 var ajaxForm = document.querySelector('[data-hook="basket__coupon-form"]'); 468 469 if (evt.target.matches('[data-hook="basket__coupon-form-submit"]')) { 470 evt.preventDefault(); 471 evt.stopImmediatePropagation(); 472 473 var data = new FormData(ajaxForm); 474 var request = new XMLHttpRequest(); // Set up our HTTP request 475 476 ajaxForm.setAttribute('data-status', 'idle'); 477 478 if (ajaxForm.getAttribute('data-status') !== 'submitting') { 479 ajaxForm.setAttribute('data-status', 'submitting'); 480 submitButton.setAttribute('disabled', 'disabled'); 481 482 if (submitButton.nodeName.toLowerCase() === 'input') { 483 submitButton.value = 'Processing...'; 484 } 485 else { 486 submitButton.textContent = 'Processing...'; 487 } 488 489 document.querySelector('#messages').parentNode.removeChild(document.querySelector('#messages')); 490 491 // Setup our listener to process completed requests 492 request.onreadystatechange = function () { 493 // Only run if the request is complete 494 if (request.readyState !== 4) { 495 return; 496 } 497 498 // Process our return data 499 if (request.status === 200) { 500 // What do when the request is successful 501 var response = request.response; 502 var basketSummary = response.querySelector('#checkout_basket_summary'); 503 var responseMessage = response.querySelector('#messages'); 504 505 response.querySelector('[data-hook="basket__coupon-form"]').parentElement.prepe
505nd(responseMessage); 506 document.querySelector('#checkout_basket_summary').innerHTML = basketSummary.innerHTML; 507 508 509 // Reset button text and form status 510 submitButton.removeAttribute('disabled'); 511 512 if (submitButton.nodeName.toLowerCase() === 'input') { 513 submitButton.value = submitButtonText; 514 } 515 else { 516 submitButton.textContent = submitButtonText; 517 } 518 519 ajaxForm.setAttribute('data-status', 'idle'); 520 } 521 else { 522 // What do when the request fails 523 console.warn('The request failed!'); 524 ajaxForm.setAttribute('data-status', 'idle'); 525 } 526 }; 527 528 /** 529 * Create and send a request 530 * The first argument is the post type (GET, POST, PUT, DELETE, etc.) 531 * The second argument is the endpoint URL 532 */ 533 request.open(ajaxForm.method, ajaxForm.action, true); 534 request.responseType = 'document'; 535 request.send(data); 536 } 537 } 538 }, false); 539 540 }(document)); 541 542 }, 543 544 jsOSEL: function () { 545 }, 546 547 jsOPAY: function () { 548 /** 549 * Credit Card Detection 550 */ 551 $.loadScript(theme_path + 'core/js/payment-method.js', function () { 552 $.hook('detect-card').on('input paste', function () { 553 var cardInput = this; 554 555 if (isNaN(this.value)) { 556 this.classList.add('has-error'); 557 } 558 paymentMethod(this, function (paymentDetected) { 559 if (paymentDetected) { 560 cardInput.classList.remove('has-error'); 561 $.hook('payment-method-display').text(paymentDetected.display); 562 $.hook('payment-method').val(supportedPaymentMethods.findPaymentMethod(paymentDetected.name)); 563 } 564 }); 565 }); 566 }); 567 568 /** 569 * Added functionality to help style the default Miva output payment 570 * fields. 571 */ 572 $.hook('mvt-input').each(function () { 573 var dataHook = $(this).attr('data-datahook'); 574 575 if (dataHook) { 576 $(this).find('input').attr('data-hook', dataHook); 577 } 578 579 Array.prototype.forEach.call($(this), function (el) { 580 el.innerHTML = el.innerHTML.replace(/ /gi, ''); 581 }); 582 }); 583 584 $.hook('detect-card').attr('type', 'tel'); 585 586 $('[data-id="cvv"]').find('input').attr('type', 'tel'); 587 588 /**$.hook('mvt-select').find('select').each(function () { 589 var wrapDiv = document.createElement('div'); 590 var select = this; 591 592 select.attr('data-no-custom', ''); 593 wrapDiv.classList.add('c-form-select'); 594 select.parentNode.insertBefore(wrapDiv, select); 595 wrapDiv.appendChild(select); 596 });*/ 597 598 }, 599 600 jsINVC: function () { 601 /** 602 * Launch Printer Dialog 603 */ 604 $.hook('print-invoice').on('click', function (element) { 605 element.preventDefault(); 606 window.print(); 607 }); 608 }, 609 610 jsORDS: function () { 611 /** 612 * Launch Printer Dialog 613 */ 614 $.hook('print-invoice').on('click', function (element) { 615 element.preventDefault(); 616 window.print(); 617 }); 618 }, 619 620 jsLOGN: function () { 621 }, 622 623 jsACAD: function () { 624 }, 625 626 jsACED: function () { 627 }, 628 629 jsCABK: function () { 630 }, 631 632 jsCADA: function () { 633 }, 634 635 jsCADE: function () { 636 }, 637 638 jsAFCL: function () { 639 }, 640 641 jsAFAD: function () { 642 }, 643 644 jsAFED: function () { 645 }, 646 647 jsORHL: function () { 648 }, 649 650 jsCTUS: function () { 651 } 652 }, 653 654 theme: function (pageID) { 655 if (pageID.toLowerCase() === 'jsprodquick' ) { 656 $.loadScript(theme_path + 'ui/js/theme_quickview.js'); 657 return; 658 } 659 660 /** 661 * Call in additional functions as developed for theme. 662 */ 663 $.loadScript(theme_path + 'ui/js/theme.js', function () { 664 window.addEventListener('load', 665 $.debounced(function () { 666 themeFunctionality.init(); 667 668 if (themeFunctionality[pageID]) { 669 themeFunctionality[pageID](); 670 } 671 }, 300), 672 false 673 ); 674 }); 675 } 676}; 677 678 679(function () { 680 String.prototype.toCamelCase = function (cap1st) { 681 'use strict'; 682 683 return ((cap1st ? '-' : '') + this).replace(/-+([^-])/g, function (a, b) { 684 return b.toUpperCase(); 685 }); 686 }; 687 var pageID = document.body.id.toCamelCase(); 688 689 /** 690 * Initialize Global Site Functions 691 */ 692 elementsUI.site(); 693 694 /** 695 * Initialize Common Page Functions 696 */ 697 elementsUI.pages.common(); 698 699 /** 700 * Initialize Page Specific Functions 701 */ 702 if (elementsUI.pages[pageID]) { 703 elementsUI.pages[pageID]();
704 } 705 706 /** 707 * Initialize Theme Specific Function 708 */ 709 elementsUI.theme(pageID); 710}());
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.