");n.customDirectionNav?n.directionNav=n.customDirectionNav:n.controlsContainer?($(n.controlsContainer).append(e),n.directionNav=$("."+i+"direction-nav li a",n.controlsContainer)):(n.append(e),n.directionNav=$("."+i+"direction-nav li a",n)),f.directionNav.update(),n.directionNav.bind(o,function(e){e.preventDefault();var t;""!==l&&l!==e.type||(t=$(this).hasClass(i+"next")?n.getTarget("next"):n.getTarget("prev"),n.flexAnimate(t,n.vars.pauseOnAction)),""===l&&(l=e.type),f.setToClearWatchedEvent()})},update:function(){var e=i+"disabled";1===n.pagingCount?n.directionNav.addClass(e).attr("tabindex","-1"):n.vars.animationLoop?n.directionNav.removeClass(e).removeAttr("tabindex"):0===n.animatingTo?n.directionNav.removeClass(e).filter("."+i+"prev").addClass(e).attr("tabindex","-1"):n.animatingTo===n.last?n.directionNav.removeClass(e).filter("."+i+"next").addClass(e).attr("tabindex","-1"):n.directionNav.removeClass(e).removeAttr("tabindex")}},pausePlay:{setup:function(){var e=$('
',srcAction:"iframe_src",patterns:{youtube:{index:"youtube.com",id:"v=",src:"//www.youtube.com/embed/%id%?autoplay=1"},vimeo:{index:"vimeo.com/",id:"/",src:"//player.vimeo.com/video/%id%?autoplay=1"},gmaps:{index:"//maps.google.",src:"%id%&output=embed"}}},proto:{initIframe:function(){b.types.push(P),w("BeforeChange",function(a,b,c){b!==c&&(b===P?R():c===P&&R(!0))}),w(h+"."+P,function(){R()})},getIframe:function(c,d){var e=c.src,f=b.st.iframe;a.each(f.patterns,function(){return e.indexOf(this.index)>-1?(this.id&&(e="string"==typeof this.id?e.substr(e.lastIndexOf(this.id)+this.id.length,e.length):this.id.call(this,e)),e=this.src.replace("%id%",e),!1):void 0});var g={};return f.srcAction&&(g[f.srcAction]=e),b._parseMarkup(d,g,c),b.updateStatus("ready"),d}}});var S=function(a){var c=b.items.length;return a>c-1?a-c:0>a?c+a:a},T=function(a,b,c){return a.replace(/%curr%/gi,b+1).replace(/%total%/gi,c)};a.magnificPopup.registerModule("gallery",{options:{enabled:!1,arrowMarkup:'',preload:[0,2],navigateByImgClick:!0,arrows:!0,tPrev:"Previous (Left arrow key)",tNext:"Next (Right arrow key)",tCounter:"%curr% of %total%"},proto:{initGallery:function(){var c=b.st.gallery,e=".mfp-gallery",g=Boolean(a.fn.mfpFastClick);return b.direction=!0,c&&c.enabled?(f+=" mfp-gallery",w(m+e,function(){c.navigateByImgClick&&b.wrap.on("click"+e,".mfp-img",function(){return b.items.length>1?(b.next(),!1):void 0}),d.on("keydown"+e,function(a){37===a.keyCode?b.prev():39===a.keyCode&&b.next()})}),w("UpdateStatus"+e,function(a,c){c.text&&(c.text=T(c.text,b.currItem.index,b.items.length))}),w(l+e,function(a,d,e,f){var g=b.items.length;e.counter=g>1?T(c.tCounter,f.index,g):""}),w("BuildControls"+e,function(){if(b.items.length>1&&c.arrows&&!b.arrowLeft){var d=c.arrowMarkup,e=b.arrowLeft=a(d.replace(/%title%/gi,c.tPrev).replace(/%dir%/gi,"left")).addClass(s),f=b.arrowRight=a(d.replace(/%title%/gi,c.tNext).replace(/%dir%/gi,"right")).addClass(s),h=g?"mfpFastClick":"click";e[h](function(){b.prev()}),f[h](function(){b.next()}),b.isIE7&&(x("b",e[0],!1,!0),x("a",e[0],!1,!0),x("b",f[0],!1,!0),x("a",f[0],!1,!0)),b.container.append(e.add(f))}}),w(n+e,function(){b._preloadTimeout&&clearTimeout(b._preloadTimeout),b._preloadTimeout=setTimeout(function(){b.preloadNearbyImages(),b._preloadTimeout=null},16)}),void w(h+e,function(){d.off(e),b.wrap.off("click"+e),b.arrowLeft&&g&&b.arrowLeft.add(b.arrowRight).destroyMfpFastClick(),b.arrowRight=b.arrowLeft=null})):!1},next:function(){b.direction=!0,b.index=S(b.index+1),b.updateItemHTML()},prev:function(){b.direction=!1,b.index=S(b.index-1),b.updateItemHTML()},goTo:function(a){b.direction=a>=b.index,b.index=a,b.updateItemHTML()},preloadNearbyImages:function(){var a,c=b.st.gallery.preload,d=Math.min(c[0],b.items.length),e=Math.min(c[1],b.items.length);for(a=1;a<=(b.direction?e:d);a++)b._preloadItem(b.index+a);for(a=1;a<=(b.direction?d:e);a++)b._preloadItem(b.index-a)},_preloadItem:function(c){if(c=S(c),!b.items[c].preloaded){var d=b.items[c];d.parsed||(d=b.parseEl(c)),y("LazyLoad",d),"image"===d.type&&(d.img=a('').on("load.mfploader",function(){d.hasSize=!0}).on("error.mfploader",function(){d.hasSize=!0,d.loadError=!0,y("LazyLoadError",d)}).attr("src",d.src)),d.preloaded=!0}}}});var U="retina";a.magnificPopup.registerModule(U,{options:{replaceSrc:function(a){return a.src.replace(/\.\w+$/,function(a){return"@2x"+a})},ratio:1},proto:{initRetina:function(){if(window.devicePixelRatio>1){var a=b.st.retina,c=a.ratio;c=isNaN(c)?c():c,c>1&&(w("ImageHasSize."+U,function(a,b){b.img.css({"max-width":b.img[0].naturalWidth/c,width:"100%"})}),w("ElementParse."+U,function(b,d){d.src=a.replaceSrc(d,c)}))}}}}),function(){var b=1e3,c="ontouchstart"in window,d=function(){v.off("touchmove"+f+" touchend"+f)},e="mfpFastClick",f="."+e;a.fn.mfpFastClick=function(e){return a(this).each(function(){var g,h=a(this);if(c){var i,j,k,l,m,n;h.on("touchstart"+f,function(a){l=!1,n=1,m=a.originalEvent?a.originalEvent.touches[0]:a.touches[0],j=m.clientX,k=m.clientY,v.on("touchmove"+f,function(a){m=a.originalEvent?a.originalEvent.touches:a.touches,n=m.length,m=m[0],(Math.abs(m.clientX-j)>10||Math.abs(m.clientY-k)>10)&&(l=!0,d())}).on("touchend"+f,function(a){d(),l||n>1||(g=!0,a.preventDefault(),clearTimeout(i),i=setTimeout(function(){g=!1},b),e())})})}h.on("click"+f,function(){g||e()})})},a.fn.destroyMfpFastClick=function(){a(this).off("touchstart"+f+" click"+f),c&&v.off("touchmove"+f+" touchend"+f)}}(),A()});
/*================ TIMBER ================*/
// Timber functions
window.timber = window.timber || {};
timber.cacheSelectors = function() {
timber.cache = {
// General
$html: $('html'),
$body: $('body'),
$window: $(window),
// Navigation
$navigation: $('#AccessibleNav')
};
};
timber.init = function() {
timber.cacheSelectors();
timber.accessibleNav();
timber.autoResponsiveElements();
};
timber.accessibleNav = function() {
var classes = {
active: 'nav-hover',
focus: 'nav-focus',
outside: 'nav-outside',
hasDropdown: 'site-nav--has-dropdown'
};
var selectors = {
active: '.nav-hover',
hasDropdown: '.site-nav--has-dropdown',
dropdown: '[data-meganav-dropdown]',
link: '.site-nav__link',
nextLink: '> .site-nav__link',
parentLink: '[data-meganav-type="parent"]',
childLink: '[data-meganav-type="child"]'
};
var $nav = timber.cache.$navigation,
$allLinks = $nav.find(selectors.link),
$parents = $nav.find(selectors.hasDropdown),
$childLinks = $nav.find(selectors.childLink),
$topLevel = $parents.find(selectors.nextLink),
$dropdowns = $nav.find(selectors.dropdown),
$subMenuLinks = $dropdowns.find(selectors.link);
// Mouseenter
$parents.on('mouseenter touchstart', function(evt) {
var $el = $(this);
var evtType = evt.type;
var $dropdowns = $nav.find(selectors.active);
if (!$el.hasClass(classes.active)) {
// force stop the click from happening
evt.preventDefault();
evt.stopImmediatePropagation();
}
// Make sure we close any opened same level dropdown before opening a new one
if (evtType === 'touchstart' && $dropdowns.length > 0) {
hideDropdown($el);
}
showDropdown($el);
});
$childLinks.on('touchstart', function(evt) {
evt.stopImmediatePropagation();
});
$parents.on('mouseleave', function() {
hideDropdown($(this));
});
$allLinks.on('focus', function() {
handleFocus($(this));
});
$allLinks.on('blur', function() {
removeFocus($topLevel);
});
// accessibleNav private methods
function handleFocus($el) {
var $newFocus = null,
$previousItem = $el.parent().prev();
// Always put tabindex -1 on previous element just in case the user is going backward.
// In that case, we want to focus on the previous parent and not the previous parent childs
$allLinks.attr('tabindex', '');
if ($previousItem.hasClass(classes.hasDropdown)) {
$previousItem.find(selectors.dropdown + ' a').attr('tabindex', -1);
}
$newFocus = $el.parents(selectors.hasDropdown).find('> a');
addFocus($newFocus);
}
function showDropdown($el) {
var $toplevel = $el.find(selectors.nextLink);
$toplevel.attr('aria-expanded', true);
$el.addClass(classes.active);
setTimeout(function() {
timber.cache.$body.on('touchstart.MegaNav', function() {
hideDropdowns();
});
}, 250);
}
function hideDropdown($el) {
var $dropdowns = $el.parent().find(selectors.active);
var $parentLink = $dropdowns.find(selectors.nextLink);
$parentLink.attr('aria-expanded', false);
$dropdowns.removeClass(classes.active);
timber.cache.$body.off('touchstart.MegaNav');
}
function hideDropdowns() {
var $dropdowns = $nav.find(selectors.active);
$.each($dropdowns, function() {
hideDropdown($(this));
});
}
function addFocus($el) {
$el.addClass(classes.focus);
if ($el.attr('aria-expanded') !== undefined) {
$el.attr('aria-expanded', true);
}
}
function removeFocus($el) {
$el.removeClass(classes.focus);
$subMenuLinks.attr('tabindex', -1);
if ($el.attr('aria-expanded') !== undefined) {
$el.attr('aria-expanded', false);
}
}
// Check if dropdown is outside of viewport
function handleDropdownOffset($dropdowns) {
var viewportSize = $(window).width();
$dropdowns.removeClass(classes.outside);
$.each($dropdowns, function() {
var $dropdown = $(this);
var dropdownOffset = $dropdown.offset().left + $dropdown.width();
if (dropdownOffset > viewportSize) {
$dropdown.addClass(classes.outside);
}
});
}
timber.cache.$window.load(function() {
handleDropdownOffset($dropdowns);
});
timber.cache.$window.resize(function() {
afterResize(function() {
handleDropdownOffset($dropdowns);
}, 250);
});
};
timber.autoResponsiveElements = function() {
var $iframeVideo = $(
'iframe[src*="youtube.com/embed"], iframe[src*="player.vimeo"]'
);
var $iframeReset = $iframeVideo.add('iframe#admin_bar_iframe');
$('table').wrap('');
$iframeVideo.each(function() {
// Add wrapper to make video responsive
if (!$(this).parents('.video-wrapper').length) {
$(this).wrap('');
}
});
$iframeReset.each(function() {
// Re-set the src attribute on each iframe after page load
// for Chrome's 'incorrect iFrame content on 'back'' bug.
// https://code.google.com/p/chromium/issues/detail?id=395791
// Need to specifically target video and admin bar
this.src = this.src;
});
};
// Initialize Timber's JS on docready
$(timber.init);
/* ================ SLATE ================ */
theme.Sections = function Sections() {
this.constructors = {};
this.instances = [];
$(document)
.on('shopify:section:load', this._onSectionLoad.bind(this))
.on('shopify:section:unload', this._onSectionUnload.bind(this))
.on('shopify:section:select', this._onSelect.bind(this))
.on('shopify:section:deselect', this._onDeselect.bind(this))
.on('shopify:block:select', this._onBlockSelect.bind(this))
.on('shopify:block:deselect', this._onBlockDeselect.bind(this));
};
theme.Sections.prototype = _.assignIn({}, theme.Sections.prototype, {
_createInstance: function(container, constructor) {
var $container = $(container);
var id = $container.attr('data-section-id');
var type = $container.attr('data-section-type');
constructor = constructor || this.constructors[type];
if (_.isUndefined(constructor)) {
return;
}
var instance = _.assignIn(new constructor(container), {
id: id,
type: type,
container: container
});
this.instances.push(instance);
},
_onSectionLoad: function(evt) {
var container = $('[data-section-id]', evt.target)[0];
if (container) {
this._createInstance(container);
}
},
_onSectionUnload: function(evt) {
this.instances = _.filter(this.instances, function(instance) {
var isEventInstance = instance.id === evt.detail.sectionId;
if (isEventInstance) {
if (_.isFunction(instance.onUnload)) {
instance.onUnload(evt);
}
}
return !isEventInstance;
});
},
_onSelect: function(evt) {
// eslint-disable-next-line no-shadow
var instance = _.find(this.instances, function(instance) {
return instance.id === evt.detail.sectionId;
});
if (!_.isUndefined(instance) && _.isFunction(instance.onSelect)) {
instance.onSelect(evt);
}
},
_onDeselect: function(evt) {
// eslint-disable-next-line no-shadow
var instance = _.find(this.instances, function(instance) {
return instance.id === evt.detail.sectionId;
});
if (!_.isUndefined(instance) && _.isFunction(instance.onDeselect)) {
instance.onDeselect(evt);
}
},
_onBlockSelect: function(evt) {
// eslint-disable-next-line no-shadow
var instance = _.find(this.instances, function(instance) {
return instance.id === evt.detail.sectionId;
});
if (!_.isUndefined(instance) && _.isFunction(instance.onBlockSelect)) {
instance.onBlockSelect(evt);
}
},
_onBlockDeselect: function(evt) {
// eslint-disable-next-line no-shadow
var instance = _.find(this.instances, function(instance) {
return instance.id === evt.detail.sectionId;
});
if (!_.isUndefined(instance) && _.isFunction(instance.onBlockDeselect)) {
instance.onBlockDeselect(evt);
}
},
register: function(type, constructor) {
this.constructors[type] = constructor;
$('[data-section-type=' + type + ']').each(
function(index, container) {
this._createInstance(container, constructor);
}.bind(this)
);
}
});
/**
* A11y Helpers
* -----------------------------------------------------------------------------
* A collection of useful functions that help make your theme more accessible
* to users with visual impairments.
*/
theme.a11y = {
/**
* For use when focus shifts to a container rather than a link
* eg for In-page links, after scroll, focus shifts to content area so that
* next `tab` is where user expects if focusing a link, just $link.focus();
*
* @param {JQuery} $element - The element to be acted upon
*/
pageLinkFocus: function($element) {
var focusClass = 'js-focus-hidden';
$element
.first()
.attr('tabIndex', '-1')
.focus()
.addClass(focusClass)
.one('blur', callback);
function callback() {
$element
.first()
.removeClass(focusClass)
.removeAttr('tabindex');
}
},
/**
* If there's a hash in the url, focus the appropriate element
*/
focusHash: function() {
var hash = window.location.hash;
// is there a hash in the url? is it an element on the page?
if (hash && document.getElementById(hash.slice(1))) {
this.pageLinkFocus($(hash));
}
},
/**
* When an in-page (url w/hash) link is clicked, focus the appropriate element
*/
bindInPageLinks: function() {
$('a[href*=#]').on(
'click',
function(evt) {
this.pageLinkFocus($(evt.currentTarget.hash));
}.bind(this)
);
},
/**
* Traps the focus in a particular container
*
* @param {object} options - Options to be used
* @param {jQuery} options.$container - Container to trap focus within
* @param {jQuery} options.$elementToFocus - Element to be focused when focus leaves container
* @param {string} options.namespace - Namespace used for new focus event handler
*/
trapFocus: function(options) {
var eventName = options.namespace
? 'focusin.' + options.namespace
: 'focusin';
if (!options.$elementToFocus) {
options.$elementToFocus = options.$container;
}
options.$container.attr('tabindex', '-1');
options.$elementToFocus.focus();
$(document).on(eventName, function(evt) {
if (
options.$container[0] !== evt.target &&
!options.$container.has(evt.target).length
) {
options.$container.focus();
}
});
},
/**
* Removes the trap of focus in a particular container
*
* @param {object} options - Options to be used
* @param {jQuery} options.$container - Container to trap focus within
* @param {string} options.namespace - Namespace used for new focus event handler
*/
removeTrapFocus: function(options) {
var eventName = options.namespace
? 'focusin.' + options.namespace
: 'focusin';
if (options.$container && options.$container.length) {
options.$container.removeAttr('tabindex');
}
$(document).off(eventName);
}
};
/* ================ MODULES ================ */
theme.Hero = (function() {
theme.sliders = function(slider, sectionId) {
this.$slider = $(slider);
this.$sliderContainer = this.$slider.parent();
this.sectionId = sectionId;
this.selectors = {
slide: '[data-slider-item]',
activeSlide: '.flex-active-slide',
navigationButton: '[data-slider-navigation]',
previousArrow: '[data-slider-prev]',
pauseButton: '[data-slider-pause]',
textContentMobile: '[data-text-mobile]',
indicatorDotsContainer: '.flex-control-nav'
};
$.extend(theme.strings, {
loadSlideA11yString: this.$slider.data('slide-nav-a11y'),
activeSlideA11yString: this.$slider.data('slide-nav-active-a11y')
});
this.sliderArgs = {
animation: this.$slider.data('transition'),
animationSpeed: 500,
pauseOnHover: true,
keyboard: false,
slideshow: this.$slider.data('autoplay'),
slideshowSpeed: this.$slider.data('speed'),
controlNav: true,
directionNav: false,
smoothHeight: false,
// eslint-disable-next-line shopify/jquery-dollar-sign-reference
controlsContainer: this.$sliderContainer.find('[data-slider-controls]'),
before: function(slider) {
var $slider = $(slider);
$slider.resize();
$slider
.find(this.selectors.slide)
.not(this.selectors.activeSlide)
.removeClass('slide-hide');
this.showMobileText(slider.animatingTo);
}.bind(this),
start: function(slider) {
this.slideshowA11y(slider);
}.bind(this),
after: function(slider) {
var $slider = $(slider);
var $slides = $slider.find(this.selectors.slide);
var $activeSlide = $slider.find(this.selectors.activeSlide);
var $indicatorDots = this.$sliderContainer.find(
this.selectors.indicatorDotsContainer + ' a'
);
var currentSlide = slider.currentSlide;
$slider
.find(this.selectors.slide)
.not(this.selectors.activeSlide)
.addClass('slide-hide');
$slider.resize();
$slides.attr('aria-hidden', true);
$activeSlide.attr('aria-hidden', false);
$indicatorDots.each(function(index) {
var $element = $(this);
$element.attr('aria-label', slideLabel(currentSlide, index));
if (index === currentSlide) {
$element.attr('aria-current', true);
} else {
$element.removeAttr('aria-current');
}
});
}.bind(this),
init: function(slider) {
var $slider = $(slider);
var previousArrow = this.selectors.previousArrow;
$slider.find(this.selectors.activeSlide).removeClass('slide-hide');
this.$sliderContainer
.find(this.selectors.navigationButton)
.on('click keyup', function(evt) {
if (
evt.type === 'keyup' &&
!(evt.keyCode === '13' || evt.keyCode === '32')
) {
return;
}
if ($(this).is(previousArrow)) {
$slider.flexslider('prev');
} else {
$slider.flexslider('next');
}
});
if (this.sliderArgs.slideshow) {
var $pauseButton = this.$sliderContainer.find(
this.selectors.pauseButton
);
var pausedClass = 'is-paused';
$pauseButton.on('click', function() {
var $element = $(this);
var isPaused = $element.hasClass(pausedClass);
$element.toggleClass(pausedClass, !isPaused).attr({
'aria-label': isPaused
? $element.data('label-pause')
: $element.data('label-play'),
'aria-pressed': !isPaused
});
if (isPaused) {
$slider.flexslider('play');
} else {
$slider.flexslider('pause');
}
});
}
}.bind(this)
};
this.slideshowA11y = function(slider) {
var $slider = $(slider);
var $sliderContainer = this.$sliderContainer;
var $slides = $slider.find(this.selectors.slide);
var $activeSlide = $slider.find(this.selectors.activeSlide);
var sectionId = this.sectionId;
var $indicatorsContainer = $sliderContainer.find(
this.selectors.indicatorDotsContainer
);
var $indicatorDots = $indicatorsContainer.find('a');
$sliderContainer
.on('keyup', this.keyboardNavigation.bind(this))
.on('focusin', function(evt) {
if (
$(this).has(evt.target).length &&
$slider.attr('aria-live') === 'polite'
) {
return;
}
$slider.attr('aria-live', 'polite');
})
.on('focusout', function(evt) {
if ($(this).has(evt.relatedTarget).length) {
return;
}
$slider.removeAttr('aria-live');
});
$slides.each(function() {
$(this).attr('aria-hidden', true);
});
$activeSlide.attr('aria-hidden', false);
// Turn off default listeners set by flexslider
$indicatorsContainer.off('click touchend MSPointerUp keyup', 'a, img');
$indicatorDots.each(function(index) {
var $element = $(this);
$element
.attr({
'aria-label': slideLabel(0, index),
'data-slide-number': index + 1,
'aria-controls': 'slide--' + sectionId + '-' + index,
href: '#flexslider--' + sectionId
})
.on('keyup click', function(evt) {
if (evt.type === 'keyup') {
if (evt.which === 9) {
evt.stopImmediatePropagation();
}
if (evt.which !== 13) {
return;
}
}
evt.preventDefault();
var slideNumber = $(evt.target).data('slide-number') - 1;
$slider.flexslider(slideNumber);
if (evt.type === 'keyup' || evt.detail === 0) {
$sliderContainer.focus();
}
});
if (index === 0) {
$element.attr('aria-current', true);
}
});
};
this.showMobileText = function(slideIndex) {
var $allTextContent = this.$sliderContainer.find(
this.selectors.textContentMobile
);
var $currentTextContent = $allTextContent.filter(
'[data-mobile-slide-text=' + slideIndex + ']'
);
$allTextContent.hide();
$currentTextContent.show();
};
this.keyboardNavigation = function(evt) {
if (evt.keyCode === 37) {
this.$slider.flexslider('prev');
}
if (evt.keyCode === 39) {
this.$slider.flexslider('next');
}
};
if (this.$slider.length) {
if (this.$slider.find('li').length === 1) {
this.sliderArgs.slideshow = false;
this.sliderArgs.slideshowSpeed = 0;
this.sliderArgs.controlNav = false;
this.sliderArgs.directionNav = false;
this.sliderArgs.touch = false;
}
// eslint-disable-next-line shopify/jquery-dollar-sign-reference
var slideshow = this.$slider.flexslider(this.sliderArgs);
this.showMobileText(0);
return slideshow;
}
};
function slideLabel(activeSlideIndex, currentIndex) {
var label =
activeSlideIndex === currentIndex
? theme.strings.activeSlideA11yString
: theme.strings.loadSlideA11yString;
return label.replace('[slide_number]', currentIndex + 1);
}
return theme.sliders;
})();
/*================ SECTIONS ================*/
theme.Product = (function() {
function Product(container) {
this.$container = $(container);
this.sectionId = this.$container.attr('data-section-id');
this.selectors = {
$html: $('html'),
$productImageGallery: $('.gallery__item', this.$container),
$productImages: $('.product-single__image-wrapper', this.$container),
$thumbImages: $('#ProductThumbs', this.$container).find(
'a.product-single__thumbnail'
),
$addToCart: $('#AddToCart', this.$container),
$productPrice: $('#ProductPrice', this.$container),
$comparePrice: $('#ComparePrice', this.$container),
$comparePriceA11y: $('#ComparePriceA11y', this.$container),
$priceA11y: $('#PriceA11y', this.$container),
$quantityElements: $('.product-single__quantity', this.$container),
$addToCartText: $('#AddToCartText', this.$container),
$tabTrigger: $('.tab-switch__trigger', this.$container),
$tabContent: $('.tab-switch__content', this.$container),
$productFullDetails: $('.product-single__full-details', this.$container),
$SKU: $('.variant-sku', this.$container),
$shopifyPaymentButton: $('.shopify-payment-button', this.$container),
$unitPrice: $('[data-unit-price]', this.$container),
$unitPriceBaseUnit: $('[data-unit-price-base-unit]', this.$container),
$unitPriceContainer: $('[data-unit-price-container]', this.$container)
};
this.classes = {
hide: 'hide'
};
if (!$('#ProductJson-' + this.sectionId).html()) {
return;
}
this.zoomType = this.$container.data('image-zoom-type');
this.showExtraTab = this.$container.data('show-extra-tab') || false;
this.extraTabContent = this.$container.data('extra-tab-content') || '';
this.enableHistoryState =
this.$container.data('enable-history-state') || false;
this.productSingleObject = JSON.parse(
document.getElementById('ProductJson-' + this.sectionId).innerHTML
);
this.init();
}
Product.prototype = _.assignIn({}, Product.prototype, {
init: function() {
this.initBreakpoints();
this.initProductVariant();
this.productImageSwitch();
timber.autoResponsiveElements();
if (this.zoomType === 'lightbox') {
this.productImageGallery();
} else if (this.zoomType === 'zoom-in') {
this.productImageZoom();
}
if (!this.showExtraTab || this.extraTabContent) {
this.initProductTabs();
}
},
initBreakpoints: function() {
var self = this;
enquire.register(theme.variables.mediaQueryMedium, {
match: function() {
if (self.zoomType === 'zoom-in') {
if (self.selectors.$productImages.length) {
// remove event handlers for product zoom on mobile
self.selectors.$productImages.trigger('zoom.destroy');
self.selectors.$productImages.off();
self.selectors.$productImages.removeClass('image-zoom');
}
} else if (self.zoomType === 'lightbox') {
// remove event handlers for lightbox on mobile
self.selectors.$productImageGallery.off();
self.selectors.$productImages.each(function() {
$(this).removeClass('zoom-lightbox');
});
}
theme.variables.bpSmall = true;
},
unmatch: function() {
theme.variables.bpSmall = false;
if (self.zoomType === 'zoom-in') {
// reinit product zoom
self.productImageZoom();
} else if (self.zoomType === 'lightbox') {
// reinit lightbox
self.selectors.$productImages.each(function() {
$(this).addClass('zoom-lightbox');
});
self.productImageGallery();
}
}
});
},
productImageGallery: function() {
if (theme.variables.bpSmall) return;
if (!this.selectors.$productImageGallery.length) return;
this.selectors.$productImageGallery.magnificPopup({
type: 'image',
mainClass: 'mfp-fade',
closeOnBgClick: true,
closeBtnInside: false,
closeOnContentClick: true,
tClose: theme.strings.zoomClose,
removalDelay: 500,
callbacks: {
open: function() {
$('html').css('overflow-y', 'hidden');
},
close: function() {
$('html').css('overflow-y', '');
}
},
gallery: {
enabled: true,
navigateByImgClick: false,
arrowMarkup:
'',
tPrev: theme.strings.zoomPrev,
tNext: theme.strings.zoomNext
}
});
var $productImageGallery = this.selectors.$productImageGallery;
this.selectors.$productImages.each(function() {
$(this).bind('click', function() {
var imageId = $(this).attr('data-image-id');
$productImageGallery
.filter('[data-image-id="' + imageId + '"]')
.trigger('click');
});
});
},
productImageSwitch: function() {
if (!this.selectors.$thumbImages.length) {
return;
}
var self = this;
// Switch the main image with one of the thumbnails
// Note: this does not change the variant selected, just the image
this.selectors.$thumbImages.on('click', function(evt) {
evt.preventDefault();
var newImageId = $(this).attr('data-image-id');
self.switchImage(newImageId);
});
},
initProductTabs: function() {
if (!this.selectors.$tabTrigger.length) {
return;
}
var $trigger = this.selectors.$tabTrigger,
$content = this.selectors.$tabContent,
$el,
link;
// Hide extra content areas with JS and set active tab
$content.filter(':gt(0)').addClass('is-hidden');
$trigger.first().addClass('is-active');
$trigger.on('click', function(evt) {
evt.preventDefault();
// set active tab
$trigger.removeClass('is-active');
$el = $(this).addClass('is-active');
// hide all content areas, then show desired one
link = $el.data('link');
$content.addClass('is-hidden');
$content
.filter('[data-content="' + link + '"]')
.removeClass('is-hidden');
});
},
initProductVariant: function() {
var self = this;
var product = this.productSingleObject;
var selectCallback = function(variant, selector) {
self.productPage({
money_format: theme.moneyFormat,
variant: variant,
selector: selector,
translations: {
add_to_cart: theme.strings.addToCart,
sold_out: theme.strings.soldOut,
unavailable: theme.strings.unavailable
}
});
};
this.optionSelector = new Shopify.OptionSelectors(
'ProductSelect-' + this.sectionId,
{
product: product,
onVariantSelected: selectCallback,
enableHistoryState: this.enableHistoryState
}
);
// Add label if only one product option and it isn't 'Title'. Could be 'Size'.
if (product.options.length === 1 && product.options[0] !== 'Title') {
$('.selector-wrapper:eq(0)', this.$container).prepend(
''
);
}
// Hide selectors if we only have 1 variant and its title contains 'Default'.
if (
product.variants.length === 1 &&
product.variants[0].title.toLowerCase().indexOf('default') !== -1
) {
$('.selector-wrapper', this.$container).hide();
}
},
productPage: function(options) {
var self = this;
var moneyFormat = options.money_format;
var variant = options.variant;
var translations = options.translations;
if (variant) {
// Update variant image, if one is set
if (variant.featured_image) {
var newImg = variant.featured_image;
self.switchImage(newImg.id);
}
// Select a valid variant if available
if (variant.available) {
// Available, enable the submit button, change text, show quantity elements
this.selectors.$addToCart
.removeClass('disabled')
.prop('disabled', false);
this.selectors.$addToCartText.html(translations.add_to_cart);
this.selectors.$quantityElements.show();
this.selectors.$shopifyPaymentButton.show();
var $link = $(this.selectors.$productFullDetails, this.$container);
if ($link.length) {
$link.attr(
'href',
this.updateUrlParameter($link.attr('href'), 'variant', variant.id)
);
}
} else {
// Sold out, disable the submit button, change text, hide quantity elements
this.selectors.$addToCart.addClass('disabled').prop('disabled', true);
this.selectors.$addToCartText.html(translations.sold_out);
this.selectors.$quantityElements.hide();
this.selectors.$shopifyPaymentButton.hide();
}
// Regardless of stock, update the product price
this.selectors.$productPrice.html(
Shopify.formatMoney(variant.price, moneyFormat)
);
// Show SKU
this.selectors.$SKU.html(variant.sku);
// Also update and show the product's compare price if necessary
if (variant.compare_at_price > variant.price) {
this.selectors.$comparePrice
.html(Shopify.formatMoney(variant.compare_at_price, moneyFormat))
.removeClass(this.classes.hide);
this.selectors.$comparePriceA11y.attr('aria-hidden', 'false');
this.selectors.$priceA11y.attr('aria-hidden', 'false');
} else {
this.selectors.$comparePrice.addClass(this.classes.hide).html('');
this.selectors.$comparePriceA11y.attr('aria-hidden', 'true');
}
// Unit price
this.selectors.$unitPriceContainer.addClass(this.classes.hide);
if (variant.unit_price) {
this.selectors.$unitPrice.html(
Shopify.formatMoney(variant.unit_price, theme.moneyFormat)
);
this.selectors.$unitPriceBaseUnit.html(this.getBaseUnit(variant));
this.selectors.$unitPriceContainer.removeClass(this.classes.hide);
}
} else {
// The variant doesn't exist, disable submit button.
// This may be an error or notice that a specific variant is not available.
// To only show available variants, implement linked product options:
// - http://docs.shopify.com/manual/configuration/store-customization/advanced-navigation/linked-product-options
this.selectors.$addToCart.addClass('disabled').prop('disabled', true);
this.selectors.$addToCartText.html(translations.unavailable);
this.selectors.$quantityElements.hide();
this.selectors.$shopifyPaymentButton.hide();
}
},
updateUrlParameter: function(url, key, value) {
var re = new RegExp('([?&])' + key + '=.*?(&|$)', 'i');
var separator = url.indexOf('?') === -1 ? '?' : '&';
if (url.match(re)) {
return url.replace(re, '$1' + key + '=' + value + '$2');
} else {
return url + separator + key + '=' + value;
}
},
switchImage: function(imageId) {
var $newImage = $(
this.selectors.$productImages.selector +
"[data-image-id='" +
imageId +
"']",
this.$container
);
var $otherImages = $(
this.selectors.$productImages.selector +
":not([data-image-id='" +
imageId +
"'])",
this.$container
);
$newImage.removeClass(this.classes.hide);
$otherImages.addClass(this.classes.hide);
},
productImageZoom: function() {
if (theme.variables.bpSmall && this.zoomType !== 'zoom-in') return;
if (
!this.selectors.$productImages.length ||
this.selectors.$html.hasClass('supports-touch')
)
return;
// Destroy zoom (in case it was already set), then set it up again
this.selectors.$productImages.trigger('zoom.destroy');
this.selectors.$productImages.each(function() {
$(this)
.addClass('image-zoom')
.zoom({
url: $(this)
.find('img')
.attr('data-zoom')
});
});
},
getBaseUnit: function(variant) {
return variant.unit_price_measurement.reference_value === 1
? variant.unit_price_measurement.reference_unit
: variant.unit_price_measurement.reference_value +
variant.unit_price_measurement.reference_unit;
}
});
return Product;
})();
theme.Collection = (function() {
function Collection(container) {
this.$container = $(container);
this.selectors = {
productGridImages: '.grid-link__image--product'
};
this.sortEnabled = this.$container.data('sort-enabled');
this.tagsEnabled = this.$container.data('tags-enabled');
this.$productGridImages = $(
this.selectors.productGridImages,
this.$container
);
this.init();
}
Collection.prototype = _.assignIn({}, Collection.prototype, {
init: function() {
this.stringOverrides();
theme.cacheSelectors();
theme.equalHeights(this.$productGridImages);
if (this.sortEnabled) {
this.collectionSorting();
}
if (this.tagsEnabled) {
this.collectionTags();
}
},
stringOverrides: function() {
// Override defaults in theme.strings with potential
// template overrides
theme.productStrings = theme.productStrings || {};
$.extend(theme.strings, theme.productStrings);
},
collectionSorting: function() {
/*============================================================================
Initialised here because collection liquid object is only available
on collection pages, and not external JS files
==============================================================================*/
Shopify.queryParams = {};
if (location.search.length && location.search.indexOf('sort_by')) {
for (
var aKeyValue, i = 0, aCouples = location.search.substr(1).split('&');
i < aCouples.length;
i++
) {
aKeyValue = aCouples[i].split('=');
if (aKeyValue.length > 1) {
Shopify.queryParams[
decodeURIComponent(aKeyValue[0])
] = decodeURIComponent(aKeyValue[1]);
}
}
}
$(function() {
$('#SortBy')
.val(theme.strings.sortBy)
.bind('change', function() {
Shopify.queryParams.sort_by = $(this).val();
location.search = $.param(Shopify.queryParams);
});
});
},
collectionTags: function() {
var $browseBy = $('#BrowseBy');
$(function() {
$browseBy.bind('change', function() {
location.href = $browseBy.val();
});
});
}
});
return Collection;
})();
theme.ListCollections = (function() {
function ListCollections(container) {
this.$container = $(container);
this.selectors = {
collectionGridImages: '.grid-link__image--collection'
};
this.$collectionGridImages = $(
this.selectors.collectionGridImages,
this.$container
);
this.init();
}
ListCollections.prototype = _.assignIn({}, ListCollections.prototype, {
init: function() {
theme.cacheSelectors();
theme.equalHeights(this.$collectionGridImages);
}
});
return ListCollections;
})();
theme.Cart = (function() {
var selectors = {
body: 'body',
cartSection: '#CartSection',
cartNoteAdd: '.cart__note-add',
cartNote: '.cart__note',
cartNoCookies: 'cart--no-cookies'
};
function Cart() {
if (!cookiesEnabled()) {
$(selectors.cartSection).addClass(selectors.cartNoCookies);
}
if (!$(selectors.cartSection).data('notes-enable')) {
return;
}
$(selectors.body).on('click', selectors.cartNoteAdd, function() {
$(this).addClass('is-hidden');
$(selectors.cartNote).addClass('is-active');
});
}
function cookiesEnabled() {
var cookieEnabled = navigator.cookieEnabled;
if (!cookieEnabled) {
document.cookie = 'testcookie';
cookieEnabled = document.cookie.indexOf('testcookie') !== -1;
}
return cookieEnabled;
}
return Cart;
})();
theme.Header = (function() {
function Header() {
this.selectors = {
headerBar: '.header-bar',
mobileNavTrigger: '#MobileNavTrigger',
mobileNav: '#MobileNav',
mobileSublistTrigger: '.mobile-nav__sublist-trigger',
showDropdownClass: 'show-dropdown',
hasDropdownItem: '.site-nav--has-dropdown',
body: 'body'
};
this.init();
}
Header.prototype = _.assignIn({}, Header.prototype, {
init: function() {
var self = this;
this.cacheSelectors();
cache.$mobileNavTrigger.on('click.mobileNavTrigger', function(evt) {
evt.preventDefault();
var isExpanded = $(this).attr('aria-expanded');
if (isExpanded === 'true') {
self.menuClose();
} else {
self.menuOpen();
}
});
cache.$mobileSublistTrigger.on('click.mobileSublistTrigger', function(
evt
) {
var $el = $(this);
var isExpanded = $el.attr('aria-expanded') === 'true';
// Enable commented out if statement to allow direct clicking on trigger link
//if (!$el.hasClass('is-active')) {
evt.preventDefault();
$el
.toggleClass('is-active')
.next('.mobile-nav__sublist')
.stop()
.slideToggle(200);
$el.attr('aria-expanded', !isExpanded);
if (
!$el.hasClass(self.selectors.showDropdownClass) &&
timber.vars.isTouch
) {
evt.preventDefault();
$el.addClass(self.selectors.showDropdownClass);
cache.$doc.on('click.mobileNav', handleClickOutsideDropdown);
}
function handleClickOutsideDropdown(evt) {
var $target = $(evt.target);
if (!$target.is($el) && !$.contains($el[0], $target[0])) {
$el.removeClass(self.selectors.showDropdownClass);
cache.$doc.off('.mobileNav');
}
}
});
},
cacheSelectors: function() {
window.cache = window.cache || {};
$.extend(window.cache, {
$doc: $(document),
$headerBar: $(this.selectors.headerBar),
$mobileNavTrigger: $(this.selectors.mobileNavTrigger),
$mobileNav: $(this.selectors.mobileNav),
$mobileSublistTrigger: $(this.selectors.mobileSublistTrigger),
$hasDropdownItem: $(this.selectors.hasDropdownItem)
});
},
onUnload: function() {
cache.$mobileNavTrigger.off('.mobileNavTrigger');
cache.$mobileSublistTrigger.off('.mobileSublistTrigger');
},
menuOpen: function() {
var self = this;
cache.$mobileNavTrigger.attr('aria-expanded', 'true');
cache.$mobileNav.slideDown(220);
theme.a11y.trapFocus({
$container: cache.$headerBar,
$elementToFocus: cache.$mobileNav.find('> li:first-child a'),
namespace: 'drawerMenu'
});
// Escape key closes menu
theme.cache.$html.on('keyup.drawerMenu', function(evt) {
if (evt.keyCode === 27) {
self.menuClose();
}
});
$(self.selectors.body).on('mousedown', function(evt) {
if (evt.target.closest(self.selectors.headerBar)) return;
theme.a11y.removeTrapFocus({
$container: cache.$headerBar,
namespace: 'drawerMenu'
});
});
},
menuClose: function() {
cache.$mobileNavTrigger.attr('aria-expanded', 'false');
cache.$mobileNav.slideUp(220);
theme.cache.$html.off('keyup.drawerMenu');
theme.a11y.removeTrapFocus({
$container: cache.$headerBar,
namespace: 'drawerMenu'
});
}
});
return Header;
})();
theme.slideshows = {};
theme.SlideshowSection = (function() {
function SlideshowSection(container) {
this.$container = $(container);
var id = this.$container.attr('data-section-id');
var slideshow = (this.slideshow = '#flexslider--' + id);
theme.slideshows[slideshow] = new theme.Hero(slideshow, id);
}
return SlideshowSection;
})();
theme.SlideshowSection.prototype = _.assignIn(
{},
theme.SlideshowSection.prototype,
{
onUnload: function() {
delete theme.slideshows[this.slideshow];
},
onBlockSelect: function(evt) {
var $slideshow = $(this.slideshow);
var $slide = $('#slide--' + evt.detail.blockId + ':not(.clone)');
var slideIndex = $slide.data('flexslider-index');
var $slideImg = $slide.find('img');
$slideshow.flexslider(slideIndex, true);
$slideshow.flexslider('pause');
$slideImg.on('load', this.resizeOnImageLoad($slideImg)).bind(this);
},
onSelect: function() {
var $slideshow = $(this.slideshow);
var $slideImg = $slideshow.find('img').first();
$slideImg.on('load', this.resizeOnImageLoad($slideImg)).bind(this);
},
onBlockDeselect: function() {
var $slideshow = $(this.slideshow);
// Check if we need to resume autoplay
if ($slideshow.data('autoplay')) {
$(this.slideshow).flexslider('play');
}
},
resizeOnImageLoad: function($slideImg) {
var intervalAttempts = 0;
var $slideshow = $(this.slideshow);
// Needed to resize the slider as the on('load') listener doesn't wait until the image has loaded.
var imageHeightCheck = setInterval(function() {
intervalAttempts++;
if (
$slideImg.length &&
$slideImg.height() === 0 &&
intervalAttempts < 10
) {
sizeSlideshow($slideshow);
} else {
// clear interval
sizeSlideshow($slideshow);
clearInterval(imageHeightCheck);
}
}, 500);
function sizeSlideshow($slideshow) {
$slideshow.resize();
}
}
}
);
theme.CollectionList = (function() {
function CollectionList(container) {
this.$container = $(container);
this.selectors = {
collectionGridImages: '.grid-link__image--collection'
};
this.$collectionGridImages = $(
this.selectors.collectionGridImages,
this.$container
);
this.init();
}
CollectionList.prototype = _.assignIn({}, CollectionList.prototype, {
init: function() {
theme.cacheSelectors();
theme.equalHeights(this.$collectionGridImages);
}
});
return CollectionList;
})();
theme.FeaturedProducts = (function() {
function FeaturedProducts(container) {
this.$container = $(container);
this.selectors = {
productGridImages: '.grid-link__image--product'
};
this.$productGridImages = $(
this.selectors.productGridImages,
this.$container
);
this.init();
}
FeaturedProducts.prototype = _.assignIn({}, FeaturedProducts.prototype, {
init: function() {
theme.cacheSelectors();
theme.equalHeights(this.$productGridImages);
}
});
return FeaturedProducts;
})();
theme.Maps = (function() {
var config = {
zoom: 14
};
var apiStatus = null;
var mapsToLoad = [];
function Map(container) {
theme.$currentMapContainer = this.$container = $(container);
var key = this.$container.data('api-key');
if (typeof key !== 'string' || key === '') {
return;
}
if (apiStatus === 'loaded') {
var self = this;
// Check if the script has previously been loaded with this key
var $script = $('script[src*="' + key + '&"]');
if ($script.length === 0) {
$.getScript(
'https://maps.googleapis.com/maps/api/js?key=' + key
).then(function() {
apiStatus = 'loaded';
self.createMap();
});
} else {
this.createMap();
}
} else {
mapsToLoad.push(this);
if (apiStatus !== 'loading') {
apiStatus = 'loading';
if (typeof window.google === 'undefined') {
$.getScript(
'https://maps.googleapis.com/maps/api/js?key=' + key
).then(function() {
apiStatus = 'loaded';
initAllMaps();
});
}
}
}
}
function initAllMaps() {
// API has loaded, load all Map instances in queue
$.each(mapsToLoad, function(index, instance) {
instance.createMap();
});
}
function geolocate($map) {
var deferred = $.Deferred();
var geocoder = new google.maps.Geocoder();
var address = $map.data('address-setting');
geocoder.geocode({ address: address }, function(results, status) {
if (status !== google.maps.GeocoderStatus.OK) {
deferred.reject(status);
}
deferred.resolve(results);
});
return deferred;
}
Map.prototype = _.assignIn({}, Map.prototype, {
createMap: function() {
var $map = this.$container.find('.map-section__container');
return geolocate($map)
.then(
function(results) {
var mapOptions = {
zoom: config.zoom,
styles: config.styles,
center: results[0].geometry.location,
draggable: false,
clickableIcons: false,
scrollwheel: false,
disableDoubleClickZoom: true,
disableDefaultUI: true
};
var map = (this.map = new google.maps.Map($map[0], mapOptions));
var center = (this.center = map.getCenter());
//eslint-disable-next-line no-unused-vars
var marker = new google.maps.Marker({
map: map,
position: center
});
google.maps.event.addDomListener(window, 'resize', function() {
google.maps.event.trigger(map, 'resize');
map.setCenter(center);
});
}.bind(this)
)
.fail(function() {
var errorMessage;
switch (status) {
case 'ZERO_RESULTS':
errorMessage = theme.strings.addressNoResults;
break;
case 'OVER_QUERY_LIMIT':
errorMessage = theme.strings.addressQueryLimit;
break;
default:
errorMessage = theme.strings.addressError;
break;
}
// Only show error in the theme editor
if (Shopify.designMode) {
var $mapContainer = $map.parents('.map-section');
$mapContainer.addClass('page-width map-section--load-error');
$mapContainer
.find('.map-section__wrapper')
.html(
'
' + errorMessage + '
'
);
}
});
},
onUnload: function() {
if (typeof window.google !== 'undefined') {
google.maps.event.clearListeners(this.map, 'resize');
}
}
});
return Map;
})();
// Global function called by Google on auth errors.
// Show an auto error message on all map instances.
// eslint-disable-next-line camelcase, no-unused-vars
function gm_authFailure() {
if (!Shopify.designMode) return;
theme.$currentMapContainer.addClass('page-width map-section--load-error');
theme.$currentMapContainer
.find('.map-section__wrapper')
.html(
'
' + theme.strings.authError + '
'
);
}
window.theme = window.theme || {};
theme.PasswordHeader = (function() {
function PasswordHeader() {
this.init();
}
PasswordHeader.prototype = _.assignIn({}, PasswordHeader.prototype, {
init: function() {
$('.js-toggle-login-modal').magnificPopup({
type: 'inline',
mainClass: 'mfp-fade',
closeOnBgClick: false,
closeBtnInside: false,
closeOnContentClick: false,
tClose: password.strings.pageClose,
removalDelay: 500,
callbacks: {
open: function() {
window.setTimeout(function() {
document.getElementById('password').focus();
}, 50);
}
}
});
if ($('.storefront-password-form .errors').size()) {
$('.js-toggle-login-modal').click();
}
}
});
return PasswordHeader;
})();
theme.ProductRecommendations = (function() {
var selectors = {
productGridImages: '[data-image-wrapper]'
};
function ProductRecommendations(container) {
this.$container = $(container);
var baseUrl = this.$container.data('baseUrl');
var productId = this.$container.data('productId');
var recommendationsSectionUrl =
baseUrl +
'?section_id=product-recommendations&product_id=' +
productId +
'&limit=4';
$.get(recommendationsSectionUrl).then(
function(section) {
var recommendationsMarkup = $(section).html();
if (recommendationsMarkup.trim() !== '') {
this.$container.html(recommendationsMarkup);
theme.equalHeights(this.$container.find(selectors.productGridImages));
}
}.bind(this)
);
}
return ProductRecommendations;
})();
$(document).ready(function() {
var sections = new theme.Sections();
sections.register('product-template', theme.Product);
sections.register('collection-template', theme.Collection);
sections.register('list-collections-template', theme.ListCollections);
sections.register('cart-template', theme.Cart);
sections.register('article-template', theme.Article);
sections.register('header-section', theme.Header);
sections.register('slideshow-section', theme.SlideshowSection);
sections.register('collection-list-section', theme.CollectionList);
sections.register('featured-products-section', theme.FeaturedProducts);
sections.register('map-section', theme.Maps);
sections.register('password-header', theme.PasswordHeader);
sections.register('product-recommendations', theme.ProductRecommendations);
});
theme.cacheSelectors = function() {
theme.cache = {
// General
$w: $(window),
$html: $('html')
};
};
timber.cacheVariables = function() {
timber.vars = {
isTouch: timber.cache.$html.hasClass('supports-touch')
};
};
theme.init = function() {
theme.cacheSelectors();
timber.cacheVariables();
theme.productCardImageLoadingAnimation();
};
theme.productCardImageLoadingAnimation = function() {
var selectors = {
image: '[data-image]',
imageWrapper: '[data-image-wrapper]'
};
var classes = {
loadingAnimation: 'grid-link__image--loading',
lazyloaded: '.lazyloaded'
};
$(document).on('lazyloaded', function(e) {
var $target = $(e.target);
if (!$target.is(selectors.image)) {
return;
}
$target
.closest(selectors.imageWrapper)
.removeClass(classes.loadingAnimation);
});
// When the theme loads, lazysizes might load images before the "lazyloaded"
// event listener has been attached. When this happens, the following function
// hides the loading placeholders.
$(selectors.image + classes.lazyloaded)
.closest(selectors.imageWrapper)
.removeClass(classes.loadingAnimation);
};
theme.equalHeights = function($selector) {
theme.cache.$w.on('load', resizeElements($selector));
theme.cache.$w.on(
'resize',
afterResize(
function() {
resizeElements($selector);
},
250,
'equal-heights'
)
);
function resizeElements($selector) {
$selector.imagesLoaded(function() {
$selector.css('height', 'auto').equalHeights();
});
}
};
// Initialize theme's JS on docready
$(theme.init);