1window.theme = window.theme || {}; 2 3/* ================ SLATE ================ */ 4window.theme = window.theme || {}; 5 6theme.Sections = function Sections() { 7 this.constructors = {}; 8 this.instances = []; 9 10 $(document) 11 .on('shopify:section:load', this._onSectionLoad.bind(this)) 12 .on('shopify:section:unload', this._onSectionUnload.bind(this)) 13 .on('shopify:section:select', this._onSelect.bind(this)) 14 .on('shopify:section:deselect', this._onDeselect.bind(this)) 15 .on('shopify:block:select', this._onBlockSelect.bind(this)) 16 .on('shopify:block:deselect', this._onBlockDeselect.bind(this)); 17}; 18 19theme.Sections.prototype = _.assignIn({}, theme.Sections.prototype, { 20 _createInstance: function(container, constructor) { 21 var $container = $(container); 22 var id = $container.attr('data-section-id'); 23 var type = $container.attr('data-section-type'); 24 25 constructor = constructor || this.constructors[type]; 26 27 if (_.isUndefined(constructor)) { 28 return; 29 } 30 31 var instance = _.assignIn(new constructor(container), { 32 id: id, 33 type: type, 34 container: container 35 }); 36 37 this.instances.push(instance); 38 }, 39 40 _onSectionLoad: function(evt) { 41 var container = $('[data-section-id]', evt.target)[0]; 42 if (container) { 43 this._createInstance(container); 44 } 45 }, 46 47 _onSectionUnload: function(evt) { 48 this.instances = _.filter(this.instances, function(instance) { 49 var isEventInstance = instance.id === evt.detail.sectionId; 50 51 if (isEventInstance) { 52 if (_.isFunction(instance.onUnload)) { 53 instance.onUnload(evt); 54 } 55 } 56 57 return !isEventInstance; 58 }); 59 }, 60 61 _onSelect: function(evt) { 62 // eslint-disable-next-line no-shadow 63 var instance = _.find(this.instances, function(instance) { 64 return instance.id === evt.detail.sectionId; 65 }); 66 67 if (!_.isUndefined(instance) && _.isFunction(instance.onSelect)) { 68 instance.onSelect(evt); 69 } 70 }, 71 72 _onDeselect: function(evt) { 73 // eslint-disable-next-line no-shadow 74 var instance = _.find(this.instances, function(instance) { 75 return instance.id === evt.detail.sectionId; 76 }); 77 78 if (!_.isUndefined(instance) && _.isFunction(instance.onDeselect)) { 79 instance.onDeselect(evt); 80 } 81 }, 82 83 _onBlockSelect: function(evt) { 84 // eslint-disable-next-line no-shadow 85 var instance = _.find(this.instances, function(instance) { 86 return instance.id === evt.detail.sectionId; 87 }); 88 89 if (!_.isUndefined(instance) && _.isFunction(instance.onBlockSelect)) { 90 instance.onBlockSelect(evt); 91 } 92 }, 93 94 _onBlockDeselect: function(evt) { 95 // eslint-disable-next-line no-shadow 96 var instance = _.find(this.instances, function(instance) { 97 return instance.id === evt.detail.sectionId; 98 }); 99 100 if (!_.isUndefined(instance) && _.isFunction(instance.onBlockDeselect)) { 101 instance.onBlockDeselect(evt); 102 } 103 }, 104 105 register: function(type, constructor) { 106 this.constructors[type] = constructor; 107 108 $('[data-section-type=' + type + ']').each( 109 function(index, container) { 110 this._createInstance(container, constructor); 111 }.bind(this) 112 ); 113 } 114}); 115 116 117/* ================ MODULES ================ */ 118/*============================================================================ 119 Money Format 120 - Shopify.format money is defined in option_selection.js. 121 If that file is not included, it is redefined here. 122==============================================================================*/ 123if (typeof Shopify === 'undefined') { 124 Shopify = {}; 125} 126if (!Shopify.formatMoney) { 127 Shopify.formatMoney = function(cents, format) { 128 var value = '', 129 placeholderRegex = /\{\{\s*(\w+)\s*\}\}/, 130 formatString = format || this.money_format; 131 132 if (typeof cents === 'string') { 133 cents = cents.replace('.', ''); 134 } 135 136 function defaultOption(opt, def) { 137 return typeof opt === 'undefined' ? def : opt; 138 } 139 140 function formatWithDelimiters(number, precision, thousands, decimal) { 141 precision = defaultOption(precision, 2); 142 thousands = defaultOption(thousands, ','); 143 decimal = defaultOption(decimal, '.'); 144 145 if (isNaN(number) || number === null) { 146 return 0; 147 } 148 149 number = (number / 100.0).toFixed(precision); 150 151 var parts = number.split('.'), 152 dollars = parts[0].replace( 153 /(\d)(?=(\d\d\d)+(?!\d))/g, 154 '$1' + thousands 155 ), 156 cents = parts[1] ? decimal + parts[1] : ''; 157 158 return dollars + cents; 159 } 160 161 switch (formatString.match(placeholderRegex)[1]) { 162 case 'amount': 163 value = formatWithDelimiters(cents, 2); 164 break; 165 case 'amount_no_decimals': 166 value = formatWithDelimiters(cents, 0); 167 break; 168 case 'amount_with_comma_separator': 169 value = formatWithDelimiters(cents, 2, '.', ','); 170 break; 171 case 'amount_no_decimals_with_comma_separator': 172 value = formatWithDelimiters(cents, 0, '.', ','); 173 break; 174 } 175 176 return formatString.replace(placeholderRegex, value); 177 }; 178} 179 180// Timber functions 181window.timber = window.timber || {}; 182 183timber.cacheSelectors = function() { 184 timber.cache = { 185 // General 186 $window: $(window), 187 $html: $('html'), 188 $body: $('body'), 189 190 // Navigation 191 $navigation: $('#AccessibleNav'), 192 $navBar: $('.nav-bar'), 193 $mobileSubNavToggle: $('.mobile-nav__toggle'), 194 $header: $('.site-header'), 195 $mobileMenuButton: $('#menu-opener'), 196 197 // Collection Pages 198 $changeView: $('.change-view'), 199 200 // Product Page 201 $productImage: $('#ProductPhotoImg'), 202 $thumbImages: $('#ProductThumbs').find('a.product-single__thumbnail'), 203 204 // Cart Page 205 $cartSection: $('#CartSection'),
206 cartNoCookies: 'cart--no-cookies', 207 208 // Customer Pages 209 $recoverPasswordLink: $('#RecoverPassword'), 210 $hideRecoverPasswordLink: $('#HideRecoverPasswordLink'), 211 $recoverPasswordForm: $('#RecoverPasswordForm'), 212 $customerLoginForm: $('#CustomerLoginForm'), 213 $passwordResetSuccess: $('#ResetSuccess') 214 }; 215}; 216 217timber.init = function() { 218 timber.cacheSelectors(); 219 timber.drawersInit(); 220 timber.cartInit(); 221 timber.mobileNavToggle(); 222 timber.productImageSwitch(); 223 timber.collectionViews(); 224 timber.loginForms(); 225}; 226 227timber.openDrawerMenu = function() { 228 var $allLinks = $('button, a', timber.cache.$navBar); 229 230 timber.cache.$body.addClass('opened-drawer'); 231 timber.cache.$navBar.addClass('opened').attr('aria-hidden', 'false'); 232 timber.cache.$mobileMenuButton 233 .attr('aria-expanded', 'true') 234 .addClass('opened'); 235 236 // Set focus on drawer 237 timber.trapFocus({ 238 $container: timber.cache.$navBar, 239 namespace: 'drawer_focus' 240 }); 241 242 // Reset tabindex 243 $allLinks.attr('tabindex', ''); 244 245 // Escape key closes menu 246 timber.cache.$html.on('keyup.drawerMenu', function(evt) { 247 if (evt.keyCode === 27) { 248 timber.closeDrawerMenu(); 249 } 250 }); 251}; 252 253timber.closeDrawerMenu = function() { 254 var $allLinks = $('button, a', timber.cache.$navBar); 255 256 timber.cache.$body.removeClass('opened-drawer'); 257 258 timber.cache.$navBar.removeClass('opened').attr('aria-hidden', 'true'); 259 260 timber.cache.$mobileMenuButton 261 .attr('aria-expanded', 'false') 262 .removeClass('opened'); 263 264 // Remove focus on drawer 265 timber.removeTrapFocus({ 266 $container: timber.cache.$navBar, 267 namespace: 'drawer_focus' 268 }); 269 270 // Reset tabindex 271 $allLinks.attr('tabindex', '-1'); 272 273 timber.cache.$html.off('keyup.drawerMenu'); 274}; 275 276timber.drawersInit = function() { 277 timber.LeftDrawer = new timber.Drawers('NavDrawer', 'left'); 278 timber.RightDrawer = new timber.Drawers('CartDrawer', 'right', { 279 onDrawerOpen: theme.settings.ajax_cart_enable 280 }); 281}; 282 283timber.cartInit = function() { 284 if (!timber.cookiesEnabled()) { 285 timber.cache.$cartSection.addClass(timber.cache.cartNoCookies); 286 } 287}; 288 289timber.cookiesEnabled = function() { 290 var cookieEnabled = navigator.cookieEnabled; 291 292 if (!cookieEnabled) { 293 document.cookie = 'testcookie'; 294 cookieEnabled = document.cookie.indexOf('testcookie') !== -1; 295 } 296 return cookieEnabled; 297}; 298 299timber.mobileNavToggle = function() { 300 timber.cache.$mobileSubNavToggle.on('click', function() { 301 $(this) 302 .parent() 303 .toggleClass('mobile-nav--expanded'); 304 }); 305}; 306 307/** 308 * Traps the focus in a particular container 309 * 310* @param {object} options - Options to be used 311* @param {jQuery} options.$container - Container to trap focus within 312* @param {jQuery} options.$elementToFocus - Element to be focused when focus leaves container 313* @param {string} options.namespace - Namespace used for new focus event handler 314*/ 315timber.trapFocus = function(options) { 316 var eventName = options.namespace 317 ? 'focusin.' + options.namespace 318 : 'focusin'; 319 320 if (!options.$elementToFocus) { 321 options.$elementToFocus = options.$container; 322 options.$container.attr('tabindex', '-1'); 323 } 324 325 options.$elementToFocus.focus(); 326 327 $(document).on(eventName, function(evt) { 328 if ( 329 options.$container[0] !== evt.target && 330 !options.$container.has(evt.target).length 331 ) { 332 options.$container.focus(); 333 } 334 }); 335}; 336 337/** 338 * Removes the trap of focus in a particular container 339 * 340 * @param {object} options - Options to be used 341 * @param {jQuery} options.$container - Container to trap focus within 342 * @param {string} options.namespace - Namespace used for new focus event handler 343 */ 344timber.removeTrapFocus = function(options) { 345 var eventName = options.namespace 346 ? 'focusin.' + options.namespace 347 : 'focusin'; 348 349 if (options.$container && options.$container.length) { 350 options.$container.removeAttr('tabindex'); 351 } 352 353 $(document).off(eventName); 354}; 355 356timber.getHash = function() { 357 return window.location.hash; 358}; 359 360timber.updateHash = function(hash) { 361 window.location.hash = '#' + hash; 362 $('#' + hash) 363 .attr('tabindex', -1) 364 .focus(); 365}; 366 367timber.productPage = function(options) { 368 var moneyFormat = options.money_format, 369 variant = options.variant; 370 371 // Selectors 372 var $productImage = $('#ProductPhotoImg'), 373 $addToCart = $('#AddToCart'), 374 $productPrice = $('#ProductPrice'), 375 $comparePrice = $('#ComparePrice'), 376 $quantityElements = $('.quantity-selector, label + .js-qty'), 377 $addToCartText = $('#AddToCartText'); 378 379 if (variant) { 380 // Update variant image, if one is set 381 if (variant.featured_image) { 382 var newImg = variant.featured_image, 383 el = $productImage[0]; 384 Shopify.Image.switchImage(newImg, el, timber.switchImage); 385 } 386 387 // Select a valid variant if available 388 if (variant.available) { 389 // Available, enable the submit button, change text, show quantity elements 390 $addToCart.removeClass('disabled').prop('disabled', false); 391 $addToCartText.html(theme.strings.add_to_cart); 392 $quantityElements.show(); 393 } else { 394 // Sold out, disable the submit button, change text, hide quantity elements 395 $addToCart.addClass('disabled').prop('disabled', true); 396 $addToCartText.html(theme.strings.sold_out); 397 $quantityElements.hide(); 398 } 399 400 // Regardless of stock, update the product price
401 $productPrice.html(Shopify.formatMoney(variant.price, moneyFormat)); 402 403 // Also update and show the product's compare price if necessary 404 if (variant.compare_at_price > variant.price) { 405 $comparePrice 406 .html(Shopify.formatMoney(variant.compare_at_price, moneyFormat)) 407 .show(); 408 } else { 409 $comparePrice.hide(); 410 } 411 } else { 412 // The variant doesn't exist, disable submit button. 413 // This may be an error or notice that a specific variant is not available. 414 // To only show available variants, implement linked product options: 415 // - http://docs.shopify.com/manual/configuration/store-customization/advanced-navigation/linked-product-options 416 $addToCart.addClass('disabled').prop('disabled', true); 417 $addToCartText.html(theme.strings.unavailable); 418 $quantityElements.hide(); 419 } 420}; 421 422timber.productImageSwitch = function() { 423 if (timber.cache.$thumbImages.length) { 424 // Switch the main image with one of the thumbnails 425 // Note: this does not change the variant selected, just the image 426 timber.cache.$thumbImages.on('click', function(evt) { 427 evt.preventDefault(); 428 var newImage = $(this).attr('href'); 429 timber.switchImage(newImage, null, timber.cache.$productImage); 430 }); 431 } 432}; 433 434timber.switchImage = function(src, imgObject, el) { 435 // Make sure element is a jquery object 436 var $el = $(el); 437 $el.attr('src', src); 438}; 439 440timber.collectionViews = function() { 441 if (timber.cache.$changeView.length) { 442 timber.cache.$changeView.on('click', function() { 443 var view = $(this).data('view'), 444 url = document.URL, 445 hasParams = url.indexOf('?') > -1; 446 447 if (hasParams) { 448 window.location = replaceUrlParam(url, 'view', view); 449 } else { 450 window.location = url + '?view=' + view; 451 } 452 }); 453 } 454}; 455 456timber.loginForms = function() { 457 function showRecoverPasswordForm() { 458 timber.cache.$recoverPasswordForm.show(); 459 timber.cache.$customerLoginForm.hide(); 460 } 461 462 function hideRecoverPasswordForm() { 463 timber.cache.$recoverPasswordForm.hide(); 464 timber.cache.$customerLoginForm.show(); 465 } 466 467 timber.cache.$recoverPasswordLink.on('click', function(evt) { 468 evt.preventDefault(); 469 showRecoverPasswordForm(); 470 }); 471 472 timber.cache.$hideRecoverPasswordLink.on('click', function(evt) { 473 evt.preventDefault(); 474 hideRecoverPasswordForm(); 475 }); 476 477 // Allow deep linking to recover password form 478 if (timber.getHash() === '#recover') { 479 showRecoverPasswordForm(); 480 } 481}; 482 483timber.resetPasswordSuccess = function() { 484 timber.cache.$passwordResetSuccess.show(); 485}; 486 487/*============================================================================ 488 Drawer modules 489 - Docs http://shopify.github.io/Timber/#drawers 490==============================================================================*/ 491timber.Drawers = (function() { 492 var Drawer = function(id, position, options) { 493 var defaults = { 494 close: '.js-drawer-close', 495 open: '.js-drawer-open-' + position, 496 openClass: 'js-drawer-open', 497 dirOpenClass: 'js-drawer-open-' + position 498 }; 499 500 this.nodes = { 501 $parent: $('body, html'), 502 $page: $('#PageContainer'), 503 $moved: $('.is-moved-by-drawer') 504 }; 505 506 this.config = $.extend(defaults, options); 507 this.position = position; 508 509 this.$drawer = $('#' + id); 510 511 if (!this.$drawer.length) { 512 return false; 513 } 514 515 this.drawerIsOpen = false; 516 this.init(); 517 }; 518 519 Drawer.prototype.init = function() { 520 $(this.config.open).on('click', $.proxy(this.open, this)); 521 this.$drawer.find(this.config.close).on('click', $.proxy(this.close, this)); 522 }; 523 524 Drawer.prototype.open = function(evt) { 525 // Keep track if drawer was opened from a click, or called by another function 526 var externalCall = false; 527 528 // Prevent following href if link is clicked 529 if (evt) { 530 evt.preventDefault(); 531 } else { 532 externalCall = true; 533 } 534 535 // Without this, the drawer opens, the click event bubbles up to $nodes.page 536 // which closes the drawer. 537 if (evt && evt.stopPropagation) { 538 evt.stopPropagation(); 539 // save the source of the click, we'll focus to this on close 540 this.$activeSource = $(evt.currentTarget); 541 } 542 543 if (this.drawerIsOpen && !externalCall) { 544 return this.close(); 545 } 546 547 // Add is-transitioning class to moved elements on open so drawer can have 548 // transition for close animation 549 this.nodes.$moved.addClass('is-transitioning'); 550 this.$drawer.prepareTransition(); 551 552 this.nodes.$parent.addClass( 553 this.config.openClass + ' ' + this.config.dirOpenClass 554 ); 555 this.drawerIsOpen = true; 556 557 // Set focus on drawer 558 this.trapFocus(this.$drawer, 'drawer_focus'); 559 560 // Run function when draw opens if set 561 if ( 562 this.config.onDrawerOpen && 563 typeof this.config.onDrawerOpen === 'function' 564 ) { 565 if (!externalCall) { 566 this.config.onDrawerOpen(); 567 } 568 } 569 570 if (this.$activeSource && this.$activeSource.attr('aria-expanded')) { 571 this.$activeSource.attr('aria-expanded', 'true'); 572 } 573 574 // Lock scrolling on mobile 575 this.nodes.$page.on('touchmove.drawer', function() { 576 return false;
577 }); 578 579 this.nodes.$page.on( 580 'click.drawer', 581 $.proxy(function() { 582 this.close(); 583 return false; 584 }, this) 585 ); 586 }; 587 588 Drawer.prototype.close = function() { 589 if (!this.drawerIsOpen) { 590 // don't close a closed drawer 591 return; 592 } 593 594 // deselect any focused form elements 595 $(document.activeElement).trigger('blur'); 596 597 // Ensure closing transition is applied to moved elements, like the nav 598 this.nodes.$moved.prepareTransition({ disableExisting: true }); 599 this.$drawer.prepareTransition({ disableExisting: true }); 600 601 this.nodes.$parent.removeClass( 602 this.config.dirOpenClass + ' ' + this.config.openClass 603 ); 604 605 this.drawerIsOpen = false; 606 607 // Remove focus on drawer 608 this.removeTrapFocus(this.$drawer, 'drawer_focus'); 609 610 this.nodes.$page.off('.drawer'); 611 }; 612 613 Drawer.prototype.trapFocus = function($container, eventNamespace) { 614 var eventName = eventNamespace ? 'focusin.' + eventNamespace : 'focusin'; 615 616 $container.attr('tabindex', '-1'); 617 618 $container.focus(); 619 620 $(document).on(eventName, function(evt) { 621 if ($container[0] !== evt.target && !$container.has(evt.target).length) { 622 $container.focus(); 623 } 624 }); 625 }; 626 627 Drawer.prototype.removeTrapFocus = function($container, eventNamespace) { 628 var eventName = eventNamespace ? 'focusin.' + eventNamespace : 'focusin'; 629 630 $container.removeAttr('tabindex'); 631 $(document).off(eventName); 632 }; 633 634 return Drawer; 635})(); 636 637// Initialize Timber's JS on docready 638$(timber.init); 639 640window.theme = window.theme || {}; 641 642theme.Header = (function() { 643 var cache = {}; 644 645 function cacheSelectors() { 646 cache = { 647 $html: $('html'), 648 $body: $('body'), 649 $wrapper: $('.wrapper'), 650 $sidebar: $('#sidebar'), 651 $logo: $('#logo'), 652 $meta: $('#meta'), 653 $announcementBar: $('.announcement-bar'), 654 $siteHeader: $('.site-header'), 655 $menu: $('#menu'), 656 $nav: $('.site-nav'), 657 $siteLogo: $('.site-header__logo'), 658 $siteLogoLink: $('.site-header__logo-link') || null, 659 $siteLogoLinkInverted: $('.site-header__logo-link--inverted') || null, 660 $mobileMenu: $('.nav-bar'), 661 $mobileMenuButton: $('#menu-opener'), 662 $mobileCloseMenuButton: $('#menu-closer'), 663 $pageContainer: $('#PageContainer'), 664 $responsiveMenu: $('#meta').find('.responsive-menu'), 665 $responsiveClose: $('.responsive-close'), 666 $options: $('#options'), 667 $footer: $('#footer'), 668 $content: $('#content'), 669 $allLinks: $('button, a', cache.$mobileMenu), 670 $siteNavs: $('.site-nav'), 671 isindexTemplate: $('body').hasClass('template-index'), 672 menuStyle: $('.site-header').data('menu-style'), 673 touchM: 'ontouchstart' in window, 674 iOS: /(iPad|iPhone|iPod)/g.test(navigator.userAgent), 675 navWidth: 0, 676 logoWidth: 0, 677 navigation: { 678 activeClass: 'opened', 679 childClass: 'site-nav__link--child', 680 active: '.opened', 681 parents: '.site-nav--has-dropdown', 682 links: '.site-nav__link', 683 dropdown: '.site-nav__dropdown' 684 } 685 }; 686 } 687 688 function init() { 689 cacheSelectors(); 690 if (cache.touchM) { 691 cache.$body.addClass('touch'); 692 } else { 693 cache.$body.addClass('no-touch'); 694 } 695 696 if ($('header').hasClass('is-dark')) { 697 cache.$pageContainer.addClass('is-dark'); 698 cache.$pageContainer.removeClass('is-light'); 699 } else if ($('header').hasClass('is-light')) { 700 cache.$pageContainer.addClass('is-light'); 701 cache.$pageContainer.removeClass('is-dark'); 702 } 703 704 cache.$footer.removeClass('loading'); 705 706 /* Enable fit vid & custom solution for posts videos */ 707 708 $( 709 'p[style="text-align: center;"] img, p[style="text-align: center;"] iframe' 710 ).each(function() { 711 $(this) 712 .parent() 713 .addClass('centered-media'); 714 }); 715 716 $('.main-content').fitVids(); 717 718 menuStyleCheck(); 719 stickyHeader(); 720 721 if ($('.link-list').length > 0) { 722 $('.link-list') 723 .clone() 724 .appendTo($('.nav-bar')) 725 .find('a') 726 .attr('tabindex', '-1'); 727 } 728 729 menuDrawerButtons(); 730 dropDownMenus(); 731 } 732 733 /* Function that decides whether to show a hamburger icon or all the links */ 734 function fitNav() { 735 var navWiderThanWrapper = 736 cache.$wrapper.width() < cache.navWidth + cache.logoWidth; 737 if ( 738 navWiderThanWrapper && 739 cache.$siteHeader.hasClass('site-header--classic') 740 ) { 741 collapseMenu(); 742 hideInvertedLogo(); 743 } else if ( 744 !navWiderThanWrapper && 745 cache.$siteHeader.hasClass('site-header--drawer') && 746 cache.menuStyle !== 'drawer' 747 ) { 748 timber.closeDrawerMenu(); 749 expandMenu(); 750 showInvertedLogo(); 751 } 752 if (navWiderThanWrapper) { 753 cache.$mobileMenu.css('height', $(window).height()); 754 } 755 cache.$siteLogo.css('opacity', '1'); 756 cache.$nav.css('opacity', '1'); 757 } 758 759 function menuStyleCheck() { 760 timber.cache.$window.on('load', function() {
761 cache.logoWidth = cache.$siteLogo.width() || 0; 762 cache.$nav.children('li').each(function() { 763 cache.navWidth += $(this).outerWidth(true); 764 }); 765 // Make drawer a11y accessible 766 timber.cache.$navBar.attr('aria-hidden', 'false'); 767 fitNav(); 768 $(window).on('resize', $.debounce(250, fitNav)); 769 }); 770 } 771 772 function collapseMenu() { 773 cache.$mobileMenu.removeClass('animate'); 774 cache.$announcementBar.addClass('mobile'); 775 cache.$siteHeader 776 .addClass('site-header--drawer mobile sticky') 777 .removeClass('site-header--classic active') 778 .find('.btn__buy a') 779 .removeClass('btn--small btn--dark') 780 .addClass('btn--regular btn--light'); 781 // Make drawer a11y unaccessible 782 timber.cache.$navBar.attr('aria-hidden', 'true'); 783 cache.$allLinks.attr('tabindex', '-1'); 784 } 785 786 function expandMenu() { 787 cache.$announcementBar.removeClass('mobile'); 788 cache.$siteHeader 789 .addClass('site-header--classic active') 790 .removeClass('site-header--drawer mobile sticky') 791 .find('.btn__buy a') 792 .addClass('btn--small btn--dark') 793 .removeClass('btn--regular btn--light'); 794 cache.$mobileMenu.css('height', '100%'); 795 // Make drawer a11y accessible 796 timber.cache.$navBar.attr('aria-hidden', 'false'); 797 cache.$allLinks.attr('tabindex', ''); 798 } 799 800 function stickyHeader() { 801 if (cache.menuStyle === 'drawer') return; 802 803 cache.$siteHeader 804 .attr('aria-hidden', true) 805 .find('a, button') 806 .attr('tabIndex', -1); 807 808 $(window).on('scroll', function() { 809 if ( 810 cache.$siteHeader.hasClass('mobile') || 811 cache.$siteHeader.hasClass('site-header--drawer') 812 ) 813 return; 814 if ($(window).scrollTop() > 300) { 815 startAnimateHeader(); 816 } else if ($(window).scrollTop() < 300) { 817 stopAnimateHeader(); 818 var $menus = cache.$siteNavs.find(cache.navigation.active); 819 closeAllMenus($menus); 820 } 821 }); 822 } 823 824 function startAnimateHeader() { 825 cache.$siteHeader.addClass('sticky'); 826 hideInvertedLogo(); 827 setTimeout(function() { 828 cache.$siteHeader.addClass('active'); 829 }, 500); 830 } 831 832 function stopAnimateHeader() { 833 cache.$siteHeader.removeClass('active sticky'); 834 showInvertedLogo(); 835 } 836 837 function hideInvertedLogo() { 838 if (!cache.isindexTemplate || !cache.$siteLogoLinkInverted.length) return; 839 cache.$siteLogoLink.removeClass('logo--hidden'); 840 cache.$siteLogoLinkInverted.addClass('logo--hidden'); 841 } 842 843 function showInvertedLogo() { 844 if (!cache.isindexTemplate || !cache.$siteLogoLinkInverted.length) return; 845 cache.$siteLogoLink.addClass('logo--hidden'); 846 cache.$siteLogoLinkInverted.removeClass('logo--hidden'); 847 } 848 849 function menuDrawerButtons() { 850 cache.$mobileMenuButton.on('click', function(e) { 851 timber.openDrawerMenu(); 852 e.preventDefault(); 853 }); 854 855 cache.$mobileCloseMenuButton.on('click', function(e) { 856 timber.closeDrawerMenu(); 857 e.preventDefault(); 858 }); 859 860 setTimeout(function() { 861 cache.$mobileMenu.addClass('animate'); 862 }, 500); 863 } 864 865 function dropDownMenus() { 866 $(cache.navigation.parents) 867 .children(cache.navigation.links) 868 .on('click', function() { 869 var $link = $(this), 870 $parent = $link.parent(), 871 $menus; 872 873 // If I click on an active dropdown parent, close it. 874 if ($parent.hasClass(cache.navigation.activeClass)) { 875 closeMenu($parent); 876 return; 877 } 878 879 if ($link.hasClass(cache.navigation.childClass)) { 880 $menus = $parent.siblings(); 881 } else { 882 $menus = cache.$siteNavs.find(cache.navigation.active); 883 } 884 885 closeAllMenus($menus); 886 openMenu($parent); 887 }); 888 } 889 890 function openMenu($menu) { 891 $menu.addClass(cache.navigation.activeClass); 892 $menu.children(cache.navigation.links).attr('aria-expanded', true); 893 $menu 894 .children(cache.navigation.dropdown) 895 .stop() 896 .slideDown(200); 897 898 setTimeout(function() { 899 timber.cache.$body.on('click.outsideMegaNav', function(e) { 900 if ($(e.target).is(cache.navigation.links)) return; 901 var $menus = cache.$siteNavs.find(cache.navigation.active); 902 closeAllMenus($menus); 903 }); 904 }, 250); 905 } 906 907 function closeMenu($menu) { 908 $menu.removeClass(cache.navigation.activeClass); 909 $menu.children(cache.navigation.links).attr('aria-expanded', false); 910 $menu 911 .children(cache.navigation.dropdown) 912 .stop()
913 .slideUp(150); 914 } 915 916 function closeAllMenus($menus) { 917 $.each($menus, function() { 918 closeMenu($(this)); 919 }); 920 921 timber.cache.$body.off('click.outsideMegaNav'); 922 } 923 924 function onSelect() { 925 if (cache.menuStyle === 'drawer') return; 926 cache.navWidth = 0; 927 cache.logoWidth = cache.$siteLogo.width() || 0; 928 cache.$nav.children('li').each(function() { 929 cache.navWidth += $(this).outerWidth(true); 930 }); 931 // Make drawer a11y accessible 932 timber.cache.$navBar.attr('aria-hidden', 'false'); 933 fitNav(); 934 timber.cache.$window.on('resize', $.debounce(250, fitNav)); 935 } 936 937 function unload() { 938 if (cache.$body.hasClass('opened-drawer')) { 939 cache.$body.removeClass('opened-drawer'); 940 } 941 } 942 943 return { 944 init: init, 945 unload: unload, 946 onSelect: onSelect 947 }; 948})(); 949 950window.theme = window.theme || {}; 951 952theme.Slideshow = function(el) { 953 this.cache = { 954 $slider: $(el), 955 sliderArgs: { 956 animation: 'slider', 957 animationSpeed: 300, 958 slideshow: false, 959 slideshowSpeed: 5000, 960 directionNav: true, 961 controlNav: true, 962 keyboard: true, 963 prevText: $.themeAssets.arrow_left, 964 nextText: $.themeAssets.arrow_right, 965 smoothHeight: true, 966 before: function(slider) { 967 $(slider) 968 .find('.slide') 969 .not('.flex-active-slide') 970 .removeClass('slide-hide'); 971 }, 972 after: function(slider) { 973 $(slider) 974 .find('.slide') 975 .not('.flex-active-slide') 976 .addClass('slide-hide'); 977 $(slider).resize(); 978 }, 979 start: function(slider) { 980 $(slider) 981 .find('.slide') 982 .not('.flex-active-slide') 983 .addClass('slide-hide'); 984 if ( 985 $(slider) 986 .find('.slide') 987 .not('.clone').length === 1 988 ) { 989 $(slider) 990 .find('.flex-direction-nav') 991 .remove(); 992 } 993 $(slider).addClass('loaded'); 994 if ($('#slider').data('loaded-index') !== undefined) { 995 $('#slider').flexslider($('#slider').data('loaded-index')); 996 } 997 } 998 } 999 }; 1000 1001 if (this.cache.$slider.find('li').length === 1) { 1002 this.cache.sliderArgs.touch = false; 1003 } 1004 1005 this.cache.$slider.flexslider(this.cache.sliderArgs); 1006 if ( 1007 $(el) 1008 .attr('id') 1009 .indexOf('flexslider--') >= 0 1010 ) { 1011 this.cache.$slider.flexslider('play'); 1012 } 1013}; 1014 1015 1016/* ================ SECTIONS ================ */ 1017window.theme = window.theme || {}; 1018 1019theme.HeaderSection = (function() { 1020 function HeaderSection() { 1021 timber.cacheSelectors(); 1022 timber.drawersInit(); 1023 timber.cartInit(); 1024 timber.mobileNavToggle(); 1025 theme.Header.init(); 1026 } 1027 1028 return HeaderSection; 1029})(); 1030 1031theme.HeaderSection.prototype = _.assignIn({}, theme.HeaderSection.prototype, { 1032 onUnload: function() { 1033 theme.Header.unload(); 1034 }, 1035 onSelect: function() { 1036 theme.Header.onSelect(); 1037 } 1038}); 1039 1040/* eslint-disable no-new */ 1041theme.Product = (function() { 1042 var defaults = { 1043 selectors: { 1044 addToCart: '#AddToCart', 1045 productPrice: '#ProductPrice', 1046 comparePrice: '#ComparePrice', 1047 addToCartText: '#AddToCartText', 1048 quantityElements: '.quantity-selector', 1049 optionSelector: 'productSelect' 1050 } 1051 }; 1052 1053 function Product(container) { 1054 var $container = (this.$container = $(container)); 1055 var sectionId = $container.attr('data-section-id'); 1056 1057 this.settings = $.extend({}, defaults, { 1058 sectionId: sectionId, 1059 enableHistoryState: true, 1060 $container: this.$container, 1061 selectors: { 1062 originalSelectorId: 'productSelect-' + sectionId, 1063 productSection: '#ProductSection-' + sectionId, 1064 productLink: '.product__content--link-' + sectionId, 1065 addToCart: '#AddToCart-' + sectionId, 1066 productPrice: '#ProductPrice-' + sectionId, 1067 comparePrice: '#ComparePrice-' + sectionId, 1068 addToCartText: '#AddToCartText-' + sectionId, 1069 quantityElements: '#quantity-selector-' + sectionId, 1070 slider: '#slider-' + sectionId, 1071 selectorWrapper: '.selector-wrapper' + sectionId, 1072 SKU: '.variant-sku', 1073 shopifyPaymentButton: '.shopify-payment-button' 1074 } 1075 }); 1076 1077 // disable history state if on homepage 1078 if ($('body').hasClass('template-index')) { 1079 this.settings.enableHistoryState = false;
1080 } 1081 1082 // Stop parsing if we don't have the product json script tag when loading 1083 // section in the Theme Editor 1084 if (!$('#ProductJson-' + sectionId).html()) { 1085 this.addQuantityButtons(); 1086 return; 1087 } 1088 1089 this.productSingleObject = JSON.parse( 1090 document.getElementById('ProductJson-' + sectionId).innerHTML 1091 ); 1092 this.init(); 1093 } 1094 1095 Product.prototype = _.assignIn({}, Product.prototype, { 1096 init: function() { 1097 this.stringOverrides(); 1098 this.initProductVariant(); 1099 this.initSliderImages(); 1100 this.addQuantityButtons(); 1101 theme.customSelectorArrow(this.$container); 1102 1103 $('.image-popup', this.$container).magnificPopup({ 1104 type: 'image', 1105 gallery: { 1106 enabled: true, 1107 tCounter: '' 1108 }, 1109 mainClass: 'mfp-fade' 1110 }); 1111 }, 1112 1113 onUnload: function() { 1114 delete theme.slideshows[this.settings.selectors.slider]; 1115 }, 1116 1117 stringOverrides: function() { 1118 // Override defaults in theme.strings with potential 1119 // template overrides 1120 1121 theme.productStrings = theme.productStrings || {}; 1122 $.extend(theme.strings, theme.productStrings); 1123 }, 1124 1125 addQuantityButtons: function() { 1126 if ( 1127 $(this.settings.selectors.quantityElements).children('input#Quantity') 1128 .length > 0 1129 ) { 1130 $(this.settings.selectors.quantityElements) 1131 .children('input#Quantity') 1132 .after( 1133 '<div class="input-holder plus"><button type="button" value="" class="plus" aria-label="' + 1134 theme.strings.increase_quantity + 1135 '">' + 1136 $.themeAssets.plus + 1137 '</button></div>' 1138 ) 1139 .before( 1140 '<div class="input-holder minus"><button type="button" value="" class="minus" aria-label="' + 1141 theme.strings.reduce_quantity + 1142 '">' + 1143 $.themeAssets.minus + 1144 '</button></div>' 1145 ); 1146 } 1147 }, 1148 1149 initProductVariant: function() { 1150 // this.productSingleObject is a global JSON object defined in theme.liquid 1151 if (!this.productSingleObject) { 1152 return; 1153 } 1154 1155 var self = this; 1156 this.optionSelector = new Shopify.OptionSelectors( 1157 self.settings.selectors.originalSelectorId, 1158 { 1159 selectorClass: self.settings.selectors.optionSelectorClass, 1160 product: self.productSingleObject, 1161 onVariantSelected: self.productVariantCallback, 1162 enableHistoryState: self.settings.enableHistoryState, 1163 settings: self.settings 1164 } 1165 ); 1166 1167 // Clean up variant labels if the Shopify-defined 1168 // defaults are the only ones left 1169 this.simplifyVariantLabels(this.productSingleObject); 1170 }, 1171 1172 simplifyVariantLabels: function(productObject) { 1173 // Hide variant dropdown if only one exists and title contains 'Default' 1174 if ( 1175 productObject.variants.length === 1 && 1176 productObject.options.length === 1 && 1177 productObject.options[0].toLowerCase().indexOf('title') >= 0 && 1178 productObject.variants[0].title 1179 .toLowerCase() 1180 .indexOf('default title') >= 0 1181 ) { 1182 $(this.settings.selectors.productSection + ' .selector-wrapper').hide(); 1183 } 1184 }, 1185 1186 initSliderImages: function() { 1187 var slideshow = this.settings.selectors.slider; 1188 $('img', this.slideshow).addClass('lazypreload'); 1189 // $(slideshow).imagesLoaded().done( function( instance ) { 1190 theme.slideshows[slideshow] = new theme.Slideshow(slideshow); 1191 // }); 1192 }, 1193 1194 // **WARNING** This function actually inherits `this` from `this.optionSelector` not 1195 // from `product` when passed in as a callback for `option_selection.js` 1196 productVariantCallback: function(variant) { 1197 if (variant) { 1198 // Update variant image, if one is set 1199 if (variant.featured_image) { 1200 var $slider = $(this.settings.selectors.slider); 1201 var $newImg = $slider.find( 1202 '.slide[data-variant-img="' + variant.featured_image.id + '"]' 1203 ); 1204 if ($newImg.length > 0) { 1205 if ($slider.hasClass('loaded')) { 1206 $slider.flexslider($newImg.data('index')); 1207 } else { 1208 $slider.data('loaded-index', $newImg.data('index')); 1209 } 1210 } 1211 } 1212 1213 // Update the product link to the current variant 1214 var $productLink = $(this.settings.selectors.productLink); 1215 if ($productLink.length) { 1216 $productLink.attr( 1217 'href', 1218 updateUrlParameter($productLink.attr('href'), 'variant', variant.id) 1219 ); 1220 } 1221 1222 // Update the product price 1223 $(this.settings.selectors.productPrice).html( 1224 Shopify.formatMoney(variant.price, theme.settings.moneyFormat) 1225 ); 1226 1227 // Show SKU 1228 $(this.settings.selectors.SKU).html(variant.sku); 1229 1230 // Update and show the product's compare price if necessary 1231 if (variant.compare_at_price > variant.price) { 1232 $(this.settings.selectors.comparePrice) 1233 .html( 1234 Shopify.formatMoney( 1235 variant.compare_at_price, 1236 theme.settings.moneyFormat 1237 ) 1238 ) 1239 .show(); 1240 } else { 1241 $(this.settings.selectors.comparePrice).hide(); 1242 } 1243 1244 // Select a valid variant if available 1245 if (variant.available) { 1246 // We have a valid product variant, so enable the submit button 1247 $(this.settings.selectors.addToCart) 1248 .removeClass('btn--disabled') 1249 .prop('disabled', false); 1250 $(this.settings.selectors.addToCartText).text( 1251 theme.strings.add_to_cart 1252 ); 1253 $(this.settings.selectors.quantityElements).removeClass('hidden'); 1254 $( 1255 this.settings.selectors.shopifyPaymentButton, 1256 this.settings.$container 1257 ).show(); 1258 } else { 1259 // Variant is sold out, disable the submit button and change the text 1260 $(this.settings.selectors.addToCart) 1261 .addClass('btn--disabled') 1262 .prop('disabled', true); 1263 $(this.settings.selectors.addToCartText).text(theme.strings.sold_out); 1264 $(this.settings.selectors.quantityElements).addClass('hidden'); 1265 $( 1266 this.settings.selectors.shopifyPaymentButton, 1267 this.settings.$container 1268 ).hide(); 1269 } 1270 } else { 1271 // The variant doesn't exist, disable submit button and change the text. 1272 // This may be an error or notice that a specific variant is not available. 1273 $(this.settings.selectors.addToCart) 1274 .addClass('btn--disabled') 1275 .prop('disabled', true); 1276 $(this.settings.selectors.addToCartText).text( 1277 theme.strings.unavailable 1278 ); 1279 $(this.settings.selectors.quantityElements).addClass('hidden'); 1280 $( 1281 this.settings.selectors.shopifyPaymentButton, 1282 this.settings.$container 1283 ).hide(); 1284 } 1285 1286 function updateUrlParameter(url, key, value) { 1287 var re = new RegExp('([?&])' + key + '=.*?(&|$)', 'i'); 1288 var separator = url.indexOf('?') === -1 ? '?' : '&'; 1289 1290 if (url.match(re)) { 1291 return url.replace(re, '$1' + key + '=' + value + '$2'); 1292 } else { 1293 return url + separator + key + '=' + value; 1294 } 1295 } 1296 } 1297 }); 1298 1299 return Product; 1300})(); 1301 1302theme.slideshows = {}; 1303 1304theme.SlideshowSection = (function() { 1305 function SlideshowSection(container) { 1306 var $container = (this.$container = $(container)); 1307 var id = $container.attr('data-section-id'); 1308 var slideshow = (this.slideshow = '#flexslider--' + id); 1309 theme.slideshows[slideshow] = new theme.Slideshow(slideshow); 1310 } 1311 1312 return SlideshowSection; 1313})(); 1314 1315theme.SlideshowSection.prototype = _.assignIn( 1316 {}, 1317 theme.SlideshowSection.prototype, 1318 { 1319 onUnload: function() { 1320 delete theme.slideshows[this.slideshow]; 1321 }, 1322 onBlockSelect: function(evt) { 1323 var $slideshow = $(this.slideshow); 1324 // Ignore the cloned version 1325 var $slide = $('#slide-' + evt.detail.blockId + ':not(.clone)'); 1326 var slideIndex = $slide.data('flexslider-index'); 1327 var $slideImg = $slide.find('img') || $slide.find('svg'); 1328 1329 $slide.imagesLoaded($slideImg, function() { 1330 $slideshow.flexslider(slideIndex); 1331 $slideshow.resize(); 1332 $slideshow.flexslider('pause'); 1333 }); 1334 }, 1335 onBlockDeselect: function() { 1336 // Resume autoplay 1337 var $slideshow = $(this.slideshow); 1338 $slideshow.flexslider('play'); 1339 } 1340 } 1341); 1342 1343window.theme = window.theme || {}; 1344 1345theme.Kickstarter = (function() { 1346 function Kickstarter(container) { 1347 this.$container = $(container); 1348 theme.crowdCampaign(this.$container); 1349 } 1350 1351 Kickstarter.prototype = _.assignIn({}, Kickstarter.prototype, { 1352 init: function() { 1353 theme.crowdCampaign(this.$container); 1354 }, 1355 onSelect: function() { 1356 theme.crowdCampaign(this.$container); 1357 } 1358 }); 1359 1360 return Kickstarter; 1361})(); 1362 1363window.theme = window.theme || {}; 1364 1365theme.FAQs = (function() { 1366 function FAQs(container) { 1367 var $container = (this.$container = $(container)); 1368 1369 this.faqSelector = '.jumpstart-accordion-' + this.sectionId; 1370 1371 theme.accordionFAQs(this.$container); 1372 1373 this.$blocks = $('.section', $container); 1374 this.$opened = $('.opened', $container); 1375 } 1376 1377 FAQs.prototype = _.assignIn({}, FAQs.prototype, { 1378 init: function() { 1379 this.$opened.find('.content').slidedown(0); 1380 1381 this.$blocks 1382 .find('.title') 1383 .prepend($.themeAssets.plus + $.themeAssets.minus); 1384 1385 this.$blocks.on('click', function(evt) { 1386 var blockId = $(evt.target).attr('data-block-id'); 1387 this.focusFAQ(blockId); 1388 }); 1389 }, 1390 focusFAQ: function(blockId, isEditorEvent) { 1391 var $accordionItem = $('.section-' + blockId); 1392 1393 if ($accordionItem.hasClass('opened') && !isEditorEvent) { 1394 $accordionItem.removeClass('opened'); 1395 $accordionItem 1396 .children('div') 1397 .stop() 1398 .slideUp(300); 1399 } else { 1400 $accordionItem.addClass('opened'); 1401 $accordionItem 1402 .children('div') 1403 .stop() 1404 .slideDown(300); 1405 this.$blocks 1406 .not($accordionItem) 1407 .removeClass('opened') 1408 .children('div') 1409 .stop() 1410 .slideUp(300); 1411 } 1412 }, 1413 onBlockSelect: function(evt) { 1414 this.focusFAQ(evt.detail.blockId, true); 1415 }, 1416 onload: function() { 1417 theme.accordionFAQs(this.$container); 1418 } 1419 }); 1420 1421 return FAQs; 1422})(); 1423 1424theme.Maps = (function() { 1425 var config = { 1426 zoom: 14 1427 }; 1428 var apiStatus = null; 1429 var mapsToLoad = []; 1430 1431 function Map(container) { 1432 theme.$currentMapContainer = this.$container = $(container); 1433 var key = this.$container.data('api-key'); 1434 1435 if (typeof key !== 'string' || key === '') { 1436 return; 1437 } 1438 1439 if (apiStatus === 'loaded') { 1440 var self = this; 1441 1442 // Check if the script has previously been loaded with this key 1443 var $script = $('script[src*="' + key + '&"]'); 1444 if ($script.length === 0) { 1445 $.getScript(
1446 'https://maps.googleapis.com/maps/api/js?key=' + key 1447 ).then(function() { 1448 apiStatus = 'loaded'; 1449 self.createMap(); 1450 }); 1451 } else { 1452 this.createMap(); 1453 } 1454 } else { 1455 mapsToLoad.push(this); 1456 1457 if (apiStatus !== 'loading') { 1458 apiStatus = 'loading'; 1459 if (typeof window.google === 'undefined') { 1460 $.getScript( 1461 'https://maps.googleapis.com/maps/api/js?key=' + key 1462 ).then(function() { 1463 apiStatus = 'loaded'; 1464 initAllMaps(); 1465 }); 1466 } 1467 } 1468 } 1469 } 1470 1471 function initAllMaps() { 1472 // API has loaded, load all Map instances in queue 1473 $.each(mapsToLoad, function(index, instance) { 1474 instance.createMap(); 1475 }); 1476 } 1477 1478 function geolocate($map) { 1479 var deferred = $.Deferred(); 1480 var geocoder = new google.maps.Geocoder(); 1481 var address = $map.data('address-setting'); 1482 1483 geocoder.geocode({ address: address }, function(results, status) { 1484 if (status !== google.maps.GeocoderStatus.OK) { 1485 deferred.reject(status); 1486 } 1487 1488 deferred.resolve(results); 1489 }); 1490 1491 return deferred; 1492 } 1493 1494 Map.prototype = _.assignIn({}, Map.prototype, { 1495 createMap: function() { 1496 var $map = this.$container.find('.map-section__container'); 1497 1498 return geolocate($map) 1499 .then( 1500 function(results) { 1501 var mapOptions = { 1502 zoom: config.zoom, 1503 styles: config.styles, 1504 center: results[0].geometry.location, 1505 draggable: false, 1506 clickableIcons: false, 1507 scrollwheel: false, 1508 disableDoubleClickZoom: true, 1509 disableDefaultUI: true 1510 }; 1511 1512 var map = (this.map = new google.maps.Map($map[0], mapOptions)); 1513 var center = (this.center = map.getCenter()); 1514 1515 //eslint-disable-next-line no-unused-vars 1516 var marker = new google.maps.Marker({ 1517 map: map, 1518 position: center 1519 }); 1520 1521 google.maps.event.addDomListener( 1522 window, 1523 'resize', 1524 $.debounce(250, function() { 1525 google.maps.event.trigger(map, 'resize'); 1526 map.setCenter(center); 1527 }) 1528 ); 1529 }.bind(this) 1530 ) 1531 .fail(function() { 1532 var errorMessage; 1533 1534 switch (status) { 1535 case 'ZERO_RESULTS': 1536 errorMessage = theme.strings.addressNoResults; 1537 break; 1538 case 'OVER_QUERY_LIMIT': 1539 errorMessage = theme.strings.addressQueryLimit; 1540 break; 1541 default: 1542 errorMessage = theme.strings.addressError; 1543 break; 1544 } 1545 1546 var $mapContainer = $map.parents('.map-section'); 1547 1548 // Only show error in the theme editor 1549 if (Shopify.designMode) { 1550 $mapContainer.addClass('page-width map-section--load-error'); 1551 $mapContainer.find('.map-section__content-wrapper').remove(); 1552 $mapContainer 1553 .find('.map-section__wrapper') 1554 .html( 1555 '<div class="errors text-center" style="width: 100%;">' + 1556 errorMessage + 1557 '</div>' 1558 ); 1559 } else { 1560 $mapContainer.removeClass('map-section--display-map'); 1561 } 1562 }); 1563 }, 1564 1565 onUnload: function() { 1566 if (typeof window.google !== 'undefined') { 1567 google.maps.event.clearListeners(this.map, 'resize'); 1568 } 1569 } 1570 }); 1571 1572 return Map; 1573})(); 1574 1575// Global function called by Google on auth errors. 1576// Show an auto error message on all map instances. 1577// eslint-disable-next-line camelcase, no-unused-vars 1578function gm_authFailure() { 1579 if (Shopify.designMode) { 1580 theme.$currentMapContainer.addClass('page-width map-section--load-error'); 1581 theme.$currentMapContainer.find('.map-section__content-wrapper').remove(); 1582 theme.$currentMapContainer 1583 .find('.map-section__wrapper') 1584 .html( 1585 '<div class="errors text-center" style="width: 100%;">
1585' + 1586 theme.strings.authError + 1587 '</div>' 1588 ); 1589 } else { 1590 theme.$currentMapContainer.removeClass('map-section--display-map'); 1591 } 1592} 1593 1594 1595/* ================ TEMPLATES ================ */ 1596window.theme = window.theme || {}; 1597 1598theme.Collection = (function() { 1599 function Collection() { 1600 theme.collectionGridMasonry(); 1601 } 1602 1603 Collection.prototype = _.assignIn({}, Collection.prototype, { 1604 init: function() { 1605 theme.collectionGridMasonry(); 1606 }, 1607 onSelect: function() { 1608 theme.collectionGridMasonry(); 1609 } 1610 }); 1611 1612 return Collection; 1613})(); 1614 1615window.theme = window.theme || {}; 1616 1617theme.Search = (function() { 1618 function Search() { 1619 theme.collectionGridMasonry(); 1620 } 1621 1622 Search.prototype = _.assignIn({}, Search.prototype, { 1623 init: function() { 1624 theme.collectionGridMasonry(); 1625 }, 1626 onSelect: function() { 1627 theme.collectionGridMasonry(); 1628 } 1629 }); 1630 1631 return Search; 1632})(); 1633 1634 1635theme.cacheSelectors = function() { 1636 theme.cache = { 1637 $html: $('html'), 1638 $body: $('body'), 1639 $wrapper: $('.wrapper'), 1640 $sidebar: $('#sidebar'), 1641 $logo: $('#logo'), 1642 $meta: $('#meta'), 1643 $siteHeader: $('.site-header'), 1644 $menu: $('#menu'), 1645 $nav: $('#AccessibleNav'), 1646 $siteLogo: $('.site-header__logo'), 1647 $mobileMenu: $('.nav-bar'), 1648 $mobileMenuButton: $('#menu-opener'), 1649 $responsiveMenu: $('#meta').find('.responsive-menu'), 1650 $responsiveClose: $('.responsive-close'), 1651 $options: $('#options'), 1652 $footer: $('#footer'), 1653 $content: $('#content'), 1654 touchM: 'ontouchstart' in window, 1655 iOS: /(iPad|iPhone|iPod)/g.test(navigator.userAgent), 1656 navWidth: 0, 1657 logoWidth: 0 1658 }; 1659}; 1660 1661theme.customSelectorArrow = function(el) { 1662 var scope = el || document; 1663 $('select', $(scope)).each(function() { 1664 $(this).wrap('<div class="jumpstart-selector"></div>'); 1665 $(this) 1666 .parent() 1667 .attr('style', $(this).attr('style')); 1668 $(this) 1669 .parent() 1670 .append('<span class="arrow">' + $.themeAssets.arrow_down + '</span>'); 1671 }); 1672}; 1673 1674theme.collectionGridMasonry = function() { 1675 if (typeof $.fn.packery !== 'undefined' && $('.collection-list').length > 0) { 1676 $('.collection-list').imagesLoaded(function() { 1677 $('.collection-list').packery({ 1678 itemSelector: '.product', 1679 transitionDuration: 0 1680 }); 1681 }); 1682 } 1683}; 1684 1685theme.parallaxBg = function() { 1686 if (!$('.parallax-bg').length > 0 || !$('#section-a').length > 0) return; 1687 1688 var $prlxBg, $prlxTxt; 1689 1690 if ($('#section-a').length > 0) { 1691 $prlxBg = $('#section-a span.prlx-bg'); 1692 $prlxTxt = $('#section-a .wrapper').addClass('prlx-txt'); 1693 $prlxBg.parent().addClass('parallax-bg'); 1694 } else { 1695 $prlxBg = $('.prlx-bg'); 1696 $prlxTxt = $('.prlx-txt'); 1697 } 1698 $(window).on('scroll', function() { 1699 if (!$(window).scrollTop() < $prlxBg.height()) return; 1700 1701 $prlxBg.css( 1702 'transform', 1703 'translate3d(0px, ' + $(window).scrollTop() / 4 + 'px, 0px)' 1704 ); 1705 $prlxTxt.css( 1706 'transform', 1707 'translate3d(0px, ' + $(window).scrollTop() / 8 + 'px, 0px)' 1708 ); 1709 }); 1710}; 1711 1712theme.quantityButtons = function() { 1713 if ($('input#Quantity').length > 0) { 1714 $(document).on('click', '.plus, .minus', function() { 1715 var $qty = $(this).siblings('#Quantity'), 1716 currentVal = parseFloat($qty.val()), 1717 max = parseFloat($qty.attr('max')), 1718 min = parseFloat($qty.attr('min')), 1719 step = $qty.attr('step'); 1720 1721 if (!currentVal || currentVal === '' || currentVal === 'NaN') 1722 currentVal = 0; 1723 if (max === '' || max === 'NaN') max = ''; 1724 if (min === '' || min === 'NaN') min = 0; 1725 if ( 1726 step === 'any' || 1727 step === '' || 1728 step === undefined || 1729 parseFloat(step) === 'NaN' 1730 ) 1731 step = 1; 1732 1733 if ($(this).is('.plus')) { 1734 if (max && (max === currentVal || currentVal > max)) { 1735 $qty.val(max); 1736 } else { 1737 $qty.val(currentVal + parseFloat(step)); 1738 } 1739 } else { 1740 if (min && (min === currentVal || currentVal < min)) { 1741 $qty.val(min); 1742 } else if (currentVal > 0) { 1743 $qty.val(currentVal - parseFloat(step)); 1744 } 1745 } 1746 $qty.trigger('change'); 1747 }); 1748 } 1749}; 1750 1751theme.passwordFooter = function() { 1752 if (!$('.template-password').length > 0) return; 1753
1754 var $pageContainer = $('#PageContainer'), 1755 $passwordFooter = $('#password-footer'); 1756 $(window) 1757 .on('resize', function() { 1758 if ($(window).height() < $pageContainer.height()) { 1759 $passwordFooter.removeClass('full'); 1760 } else { 1761 $passwordFooter.addClass('full'); 1762 } 1763 }) 1764 .trigger('resize'); 1765}; 1766 1767theme.infiniteBlog = function() { 1768 var $infiniteLink = $('#infinite-link'), 1769 $infiniteURL = $infiniteLink.children('a'), 1770 $blogList = $('.blog-list'); 1771 1772 if ($infiniteLink.length > 0) { 1773 $infiniteURL.on('click', function(e) { 1774 $infiniteURL.addClass('btn--disabled').text('Loading ...'); 1775 var href = $(this).attr('href'); 1776 $.ajax({ 1777 url: href, 1778 dataType: 'html', 1779 success: function(data) { 1780 var $data = $(data), 1781 $posts = $data.find('a.article'), 1782 $infinite = $data.find('#infinite-link'); 1783 $posts.imagesLoaded(function() { 1784 $posts.css('display', 'none'); 1785 $blogList.append($posts); 1786 $posts.slideDown(300); 1787 if ($infinite.length > 0) { 1788 $infiniteURL 1789 .removeClass('btn--disabled') 1790 .text('More posts') 1791 .prop('href', $infinite.children('a').prop('href')); 1792 } else { 1793 $infiniteURL.text('All posts loaded'); 1794 } 1795 }); 1796 } 1797 }); 1798 e.preventDefault(); 1799 }); 1800 } 1801}; 1802 1803theme.homeGallery = function() { 1804 if ($('.home-gallery').length > 0) { 1805 $('.home-gallery').imagesLoaded(function() { 1806 $('.home-gallery') 1807 .find('.item') 1808 .each(function() { 1809 var $img = $(this).find('img'); 1810 if ($img[0].naturalWidth <= $img[0].naturalHeight) { 1811 $(this).addClass('one-quarter medium-down--one-half'); 1812 } else { 1813 $(this).addClass('one-half medium-down--one-whole'); 1814 } 1815 }); 1816 $('.home-gallery') 1817 .find('.packery-container') 1818 .packery({ 1819 itemSelector: '.grid__item', 1820 gutter: 0, 1821 percentPosition: true, 1822 transitionDuration: 0 1823 }); 1824 $('.home-gallery').addClass('init'); 1825 $('.home-gallery') 1826 .find('.packery-container') 1827 .packery(); 1828 }); 1829 } 1830}; 1831 1832theme.iframePopUp = function() { 1833 $('.video-overlay').magnificPopup({ 1834 type: 'iframe', 1835 mainClass: 'mfp-fade' 1836 }); 1837}; 1838 1839theme.accordionFAQs = function(el) { 1840 var scope = el || document; 1841 1842 if ($('.jumpstart-accordion', $(scope)).length > 0) { 1843 $('.jumpstart-accordion', $(scope)).each(function() { 1844 var $sections = $(this).children('div'); 1845 var $opened = $sections.filter('.opened'); 1846 $opened.children('div').slideDown(0); 1847 $(this) 1848 .children('div') 1849 .children('h3') 1850 .prepend($.themeAssets.plus + $.themeAssets.minus) 1851 .click(function() { 1852 var $this = $(this).parent(); 1853 if ($this.hasClass('opened')) { 1854 $this.removeClass('opened'); 1855 $this 1856 .children('div') 1857 .stop() 1858 .slideUp(300); 1859 } else { 1860 $this.addClass('opened'); 1861 $this 1862 .children('div') 1863 .stop() 1864 .slideDown(300); 1865 $sections 1866 .not($this) 1867 .removeClass('opened') 1868 .children('div') 1869 .stop() 1870 .slideUp(300); 1871 } 1872 }); 1873 }); 1874 } 1875}; 1876 1877theme.crowdCampaign = function($campaignContainer) { 1878 if (!$('.home-kickstarter').length > 0) return; 1879 1880 var sectionId = $campaignContainer.data('section-id'); 1881 1882 // PIE 1883 $('.kickstarter__graphic.pie', $campaignContainer).html( 1884 '<canvas id="kickstarter__pie--help--' + 1885 sectionId + 1886 '" width="110" height="110"></canvas><canvas id="kickstarter__pie--' + 1887 sectionId + 1888 '" width="110" height="110"></canvas>' 1889 ); 1890 1891 var progress = 0, 1892 pieI = null, 1893 pieValue = Math.min( 1894 parseInt($('.kickstarter__graphic', $campaignContainer).data('value')) / 1895 100, 1896 1 1897 ), 1898 pieColor = $('.kickstarter__graphic', $campaignContainer).data('color'), 1899 pieCanvas = document.getElementById('kickstarter__pie--' + sectionId), 1900 context = pieCanvas.getContext('2d'), 1901 centerX = pieCanvas.width / 2, 1902 centerY = pieCanvas.height / 2, 1903 radius = 45; 1904 1905 context.lineWidth = 15; 1906 context.strokeStyle = pieColor; 1907 context.lineCap = 'round'; 1908 1909 pieI = setInterval(function() { 1910 progress = progress + 0.0025; 1911 context.clearRect(0, 0, pieCanvas.width, pieCanvas.height); 1912 context.beginPath(); 1913 context.arc(centerX, centerY, radius, 0, 2 * progress * Math.PI, false); 1914 context.stroke(); 1915 if (progress >= pieValue) { 1916 clearInterval(pieI); 1917 } 1918 }, 5); 1919 1920 var pieCanvasHelp = document.getElementById( 1921 'kickstarter__pie--help--' + sectionId 1922 ), 1923 contextHelp = pieCanvasHelp.getContext('2d'), 1924 centerXHelp = pieCanvasHelp.width / 2, 1925 centerYHelp = pieCanvasHelp.height / 2, 1926 radiusHelp = 45; 1927 1928 contextHelp.lineWidth = 15; 1929 contextHelp.strokeStyle = '#e9e9e9'; 1930 contextHelp.lineCap = 'round'; 1931 contextHelp.beginPath(); 1932 contextHelp.arc(centerXHelp, centerYHelp, radiusHelp, 0, 2 * Math.PI, false); 1933 contextHelp.stroke(); 1934 1935 // BAR 1936 1937 var barValue = Math.min( 1938 parseInt($('.kickstarter__graphic.bar', $campaignContainer).data('value')), 1939 100 1940 ); 1941 $('.kickstarter__graphic.bar', $campaignContainer).append( 1942 '<div class="value"></div>' 1943 ); 1944 $('.kickstarter__graphic.bar .value', $campaignContainer).css( 1945 'width', 1946 barValue + '%' 1947 ); 1948}; 1949 1950$(document).ready(function() { 1951 var sections = new theme.Sections(); 1952 1953 sections.register('header-section', theme.HeaderSection); 1954 sections.register('slideshow-section', theme.SlideshowSection); 1955 sections.register('product', theme.Product); 1956 sections.register('home-product', theme.Product); 1957 sections.register('collection-template', theme.Collection); 1958 sections.register('list-collection-template', theme.Collection); 1959 sections.register('home-kickstarter', theme.Kickstarter); 1960 sections.register('home-faq', theme.FAQs); 1961 sections.register('feature-collection', theme.Collection); 1962 sections.register('map-section', theme.Maps); 1963 sections.register('search', theme.Search); 1964}); 1965 1966(function($) { 1967 $(document).ready(function($) { 1968 'use strict'; 1969 1970 /* Elements */ 1971 1972 /* eslint-disable */ 1973 var $html = $('html'), 1974 $body = $('body'), 1975 $wrapper = $('.wrapper'), 1976 $sidebar = $('#sidebar'), 1977 $logo = $('#logo'), 1978 $meta = $('#meta'), 1979 $siteHeader = $('.site-header'), 1980 $menu = $('#menu'), 1981 $nav = $('#AccessibleNav'), 1982 $siteLogo = $('.site-header__logo'), 1983 $mobileMenu = $('.nav-bar'), 1984 $mobileMenuButton = $('#menu-opener'), 1985 $responsiveMenu = $meta.find('.responsive-menu'), 1986 $responsiveClose = $('.responsive-close'), 1987 $options = $('#options'), 1988 $footer = $('#footer'), 1989 $content = $('#content'), 1990 touchM = 'ontouchstart' in window, 1991 iOS = /(iPad|iPhone|iPod)/g.test(navigator.userAgent), 1992 navWidth = 0, 1993 logoWidth = 0; 1994 /* eslint-enable */ 1995 }); 1996})(jQuery); 1997 1998theme.init = function() { 1999 theme.cacheSelectors(); 2000 theme.parallaxBg(); 2001 theme.customSelectorArrow(); 2002 theme.quantityButtons(); 2003 theme.passwordFooter(); 2004 theme.infiniteBlog(); 2005 theme.homeGallery(); 2006 theme.iframePopUp(); 2007 2008 if (theme.cache.$body.hasClass('template-index')) { 2009 if ( 2010 $('.main-content') 2011 .children('.index-sections') 2012 .children('.shopify-section').length % 2013 2 !== 2014 0 2015 ) { 2016 $('.social-footer').addClass('even'); 2017 } 2018 } 2019}; 2020$(theme.init);
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.