Adds SFRA 6.0
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
## cartridge.properties for cartridge app_storefront_base
|
||||
#Thu Jun 09 11:30:40 EDT 2016
|
||||
demandware.cartridges.app_storefront_base.multipleLanguageStorefront=true
|
||||
demandware.cartridges.app_storefront_base.id=app_storefront_base
|
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"env": {
|
||||
"jquery": true
|
||||
},
|
||||
"rules": {
|
||||
"global-require": "off",
|
||||
"no-var": "off",
|
||||
"prefer-const": "off"
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var processInclude = require('./util');
|
||||
|
||||
$(document).ready(function () {
|
||||
processInclude(require('./addressBook/addressBook'));
|
||||
});
|
@@ -0,0 +1,105 @@
|
||||
'use strict';
|
||||
|
||||
var formValidation = require('../components/formValidation');
|
||||
|
||||
var url;
|
||||
var isDefault;
|
||||
|
||||
/**
|
||||
* Create an alert to display the error message
|
||||
* @param {Object} message - Error message to display
|
||||
*/
|
||||
function createErrorNotification(message) {
|
||||
var errorHtml = '<div class="alert alert-danger alert-dismissible valid-cart-error ' +
|
||||
'fade show" role="alert">' +
|
||||
'<button type="button" class="close" data-dismiss="alert" aria-label="Close">' +
|
||||
'<span aria-hidden="true">×</span>' +
|
||||
'</button>' + message + '</div>';
|
||||
|
||||
$('.error-messaging').append(errorHtml);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
removeAddress: function () {
|
||||
$('.remove-address').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
isDefault = $(this).data('default');
|
||||
if (isDefault) {
|
||||
url = $(this).data('url')
|
||||
+ '?addressId='
|
||||
+ $(this).data('id')
|
||||
+ '&isDefault='
|
||||
+ isDefault;
|
||||
} else {
|
||||
url = $(this).data('url') + '?addressId=' + $(this).data('id');
|
||||
}
|
||||
$('.product-to-remove').empty().append($(this).data('id'));
|
||||
});
|
||||
},
|
||||
|
||||
removeAddressConfirmation: function () {
|
||||
$('.delete-confirmation-btn').click(function (e) {
|
||||
e.preventDefault();
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'get',
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
$('#uuid-' + data.UUID).remove();
|
||||
if (isDefault) {
|
||||
var addressId = $('.card .address-heading').first().text();
|
||||
var addressHeading = addressId + ' (' + data.defaultMsg + ')';
|
||||
$('.card .address-heading').first().text(addressHeading);
|
||||
$('.card .card-make-default-link').first().remove();
|
||||
$('.remove-address').data('default', true);
|
||||
if (data.message) {
|
||||
var toInsert = '<div><h3>' +
|
||||
data.message +
|
||||
'</h3><div>';
|
||||
$('.addressList').after(toInsert);
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function (err) {
|
||||
if (err.responseJSON.redirectUrl) {
|
||||
window.location.href = err.responseJSON.redirectUrl;
|
||||
} else {
|
||||
createErrorNotification(err.responseJSON.errorMessage);
|
||||
}
|
||||
$.spinner().stop();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
submitAddress: function () {
|
||||
$('form.address-form').submit(function (e) {
|
||||
var $form = $(this);
|
||||
e.preventDefault();
|
||||
url = $form.attr('action');
|
||||
$form.spinner().start();
|
||||
$('form.address-form').trigger('address:submit', e);
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
data: $form.serialize(),
|
||||
success: function (data) {
|
||||
$form.spinner().stop();
|
||||
if (!data.success) {
|
||||
formValidation($form, data);
|
||||
} else {
|
||||
location.href = data.redirectUrl;
|
||||
}
|
||||
},
|
||||
error: function (err) {
|
||||
if (err.responseJSON.redirectUrl) {
|
||||
window.location.href = err.responseJSON.redirectUrl;
|
||||
}
|
||||
$form.spinner().stop();
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
};
|
@@ -0,0 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
$(document).ready(function () {
|
||||
if (window.resetCampaignBannerSessionToken) {
|
||||
window.sessionStorage.removeItem('hide_campaign_banner');
|
||||
}
|
||||
|
||||
var campaignBannerStatus = window.sessionStorage.getItem('hide_campaign_banner');
|
||||
$('.campaign-banner .close').on('click', function () {
|
||||
$('.campaign-banner').addClass('d-none');
|
||||
window.sessionStorage.setItem('hide_campaign_banner', '1');
|
||||
});
|
||||
|
||||
if (!campaignBannerStatus || campaignBannerStatus < 0) {
|
||||
$('.campaign-banner').removeClass('d-none');
|
||||
}
|
||||
});
|
@@ -0,0 +1,174 @@
|
||||
'use strict';
|
||||
var debounce = require('lodash/debounce');
|
||||
|
||||
/**
|
||||
* Get display information related to screen size
|
||||
* @param {jQuery} element - the current carousel that is being used
|
||||
* @returns {Object} an object with display information
|
||||
*/
|
||||
function screenSize(element) {
|
||||
var result = {
|
||||
itemsToDisplay: null,
|
||||
sufficientSlides: true
|
||||
};
|
||||
var viewSize = $(window).width();
|
||||
var extraSmallDisplay = element.data('xs');
|
||||
var smallDisplay = element.data('sm');
|
||||
var mediumDisplay = element.data('md');
|
||||
var numberOfSlides = element.data('number-of-slides');
|
||||
|
||||
if (viewSize <= 575.98) {
|
||||
result.itemsToDisplay = extraSmallDisplay;
|
||||
} else if ((viewSize >= 576) && (viewSize <= 768.98)) {
|
||||
result.itemsToDisplay = smallDisplay;
|
||||
} else if (viewSize >= 769) {
|
||||
result.itemsToDisplay = mediumDisplay;
|
||||
}
|
||||
|
||||
if (result.itemsToDisplay && numberOfSlides <= result.itemsToDisplay) {
|
||||
result.sufficientSlides = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the next element to be displayed next unreachable for screen readers and keyboard nav
|
||||
* @param {jQuery} element - the current carousel that is being used
|
||||
*/
|
||||
function hiddenSlides(element) {
|
||||
var carousel;
|
||||
|
||||
if (element) {
|
||||
carousel = element;
|
||||
} else {
|
||||
carousel = $('.experience-commerce_layouts-carousel .carousel, .experience-einstein-einsteinCarousel .carousel, .experience-einstein-einsteinCarouselCategory .carousel, .experience-einstein-einsteinCarouselProduct .carousel');
|
||||
}
|
||||
|
||||
var screenSizeInfo = screenSize(carousel);
|
||||
|
||||
var lastDisplayedElement;
|
||||
var elementToBeDisplayed;
|
||||
|
||||
switch (screenSizeInfo.itemsToDisplay) {
|
||||
case 2:
|
||||
lastDisplayedElement = carousel.find('.active.carousel-item + .carousel-item');
|
||||
elementToBeDisplayed = carousel.find('.active.carousel-item + .carousel-item + .carousel-item');
|
||||
break;
|
||||
case 3:
|
||||
lastDisplayedElement = carousel.find('.active.carousel-item + .carousel-item + .carousel-item');
|
||||
elementToBeDisplayed = carousel.find('.active.carousel-item + .carousel-item + .carousel-item + .carousel-item');
|
||||
break;
|
||||
case 4:
|
||||
lastDisplayedElement = carousel.find('.active.carousel-item + .carousel-item + .carousel-item + .carousel-item');
|
||||
elementToBeDisplayed = carousel.find('.active.carousel-item + .carousel-item + .carousel-item + .carousel-item + .carousel-item');
|
||||
break;
|
||||
case 6:
|
||||
lastDisplayedElement = carousel.find('.active.carousel-item + .carousel-item + .carousel-item + .carousel-item + .carousel-item + .carousel-item');
|
||||
elementToBeDisplayed = carousel.find('.active.carousel-item + .carousel-item + .carousel-item + .carousel-item + .carousel-item + .carousel-item + .carousel-item');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
carousel.find('.active.carousel-item').removeAttr('tabindex').removeAttr('aria-hidden');
|
||||
carousel.find('.active.carousel-item').find('a, button, details, input, textarea, select')
|
||||
.removeAttr('tabindex')
|
||||
.removeAttr('aria-hidden');
|
||||
|
||||
if (lastDisplayedElement) {
|
||||
lastDisplayedElement.removeAttr('tabindex').removeAttr('aria-hidden');
|
||||
lastDisplayedElement.find('a, button, details, input, textarea, select')
|
||||
.removeAttr('tabindex')
|
||||
.removeAttr('aria-hidden');
|
||||
}
|
||||
|
||||
if (elementToBeDisplayed) {
|
||||
elementToBeDisplayed.attr('tabindex', -1).attr('aria-hidden', true);
|
||||
elementToBeDisplayed.find('a, button, details, input, textarea, select')
|
||||
.attr('tabindex', -1)
|
||||
.attr('aria-hidden', true);
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
hiddenSlides();
|
||||
|
||||
$(window).on('resize', debounce(function () {
|
||||
hiddenSlides();
|
||||
}, 500));
|
||||
|
||||
$('body').on('carousel:setup', function () {
|
||||
hiddenSlides();
|
||||
});
|
||||
|
||||
$('.experience-commerce_layouts-carousel .carousel, .experience-einstein-einsteinCarousel .carousel, .experience-einstein-einsteinCarouselCategory .carousel, .experience-einstein-einsteinCarouselProduct .carousel').on('touchstart', function (touchStartEvent) {
|
||||
var screenSizeInfo = screenSize($(this));
|
||||
|
||||
if (screenSizeInfo.sufficientSlides) {
|
||||
var xClick = touchStartEvent.originalEvent.touches[0].pageX;
|
||||
$(this).one('touchmove', function (touchMoveEvent) {
|
||||
var xMove = touchMoveEvent.originalEvent.touches[0].pageX;
|
||||
if (Math.floor(xClick - xMove) > 5) {
|
||||
$(this).carousel('next');
|
||||
} else if (Math.floor(xClick - xMove) < -5) {
|
||||
$(this).carousel('prev');
|
||||
}
|
||||
});
|
||||
$('.experience-commerce_layouts-carousel .carousel, .experience-einstein-einsteinCarousel .carousel, .experience-einstein-einsteinCarouselCategory .carousel, .experience-einstein-einsteinCarouselProduct .carousel').on('touchend', function () {
|
||||
$(this).off('touchmove');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('.experience-commerce_layouts-carousel .carousel, .experience-einstein-einsteinCarousel .carousel, .experience-einstein-einsteinCarouselCategory .carousel, .experience-einstein-einsteinCarouselProduct .carousel').on('slide.bs.carousel', function (e) {
|
||||
var activeCarouselPosition = $(e.relatedTarget).data('position');
|
||||
$(this).find('.pd-carousel-indicators .active').removeClass('active');
|
||||
$(this).find(".pd-carousel-indicators [data-position='" + activeCarouselPosition + "']").addClass('active');
|
||||
|
||||
var extraSmallDisplay = $(this).data('xs');
|
||||
var smallDisplay = $(this).data('sm');
|
||||
var mediumDisplay = $(this).data('md');
|
||||
|
||||
var arrayOfSlidesToDisplay = [];
|
||||
|
||||
if (!$(this).hasClass('insufficient-xs-slides')) {
|
||||
arrayOfSlidesToDisplay.push(extraSmallDisplay);
|
||||
}
|
||||
|
||||
if (!$(this).hasClass('insufficient-sm-slides')) {
|
||||
arrayOfSlidesToDisplay.push(smallDisplay);
|
||||
}
|
||||
|
||||
if (!$(this).hasClass('insufficient-md-slides')) {
|
||||
arrayOfSlidesToDisplay.push(mediumDisplay);
|
||||
}
|
||||
|
||||
var itemsToDisplay = Math.max.apply(Math, arrayOfSlidesToDisplay);
|
||||
|
||||
var elementIndex = $(e.relatedTarget).index();
|
||||
var numberOfSlides = $('.carousel-item', this).length;
|
||||
var carouselInner = $(this).find('.carousel-inner');
|
||||
var carouselItem;
|
||||
|
||||
if (elementIndex >= numberOfSlides - (itemsToDisplay - 1)) {
|
||||
var it = itemsToDisplay - (numberOfSlides - elementIndex);
|
||||
for (var i = 0; i < it; i++) {
|
||||
// append slides to end
|
||||
if (e.direction === 'left') {
|
||||
carouselItem = $('.carousel-item', this).eq(i);
|
||||
|
||||
$(carouselItem).appendTo($(carouselInner));
|
||||
} else {
|
||||
carouselItem = $('.carousel-item', this).eq(0);
|
||||
|
||||
$(carouselItem).appendTo($(carouselInner));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('.experience-commerce_layouts-carousel .carousel, .experience-einstein-einsteinCarousel .carousel, .experience-einstein-einsteinCarouselCategory .carousel, .experience-einstein-einsteinCarouselProduct .carousel').on('slid.bs.carousel', function () {
|
||||
hiddenSlides($(this));
|
||||
});
|
||||
});
|
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var processInclude = require('./util');
|
||||
|
||||
$(document).ready(function () {
|
||||
processInclude(require('./cart/cart'));
|
||||
});
|
@@ -0,0 +1,766 @@
|
||||
'use strict';
|
||||
|
||||
var base = require('../product/base');
|
||||
var focusHelper = require('../components/focus');
|
||||
|
||||
/**
|
||||
* appends params to a url
|
||||
* @param {string} url - Original url
|
||||
* @param {Object} params - Parameters to append
|
||||
* @returns {string} result url with appended parameters
|
||||
*/
|
||||
function appendToUrl(url, params) {
|
||||
var newUrl = url;
|
||||
newUrl += (newUrl.indexOf('?') !== -1 ? '&' : '?') + Object.keys(params).map(function (key) {
|
||||
return key + '=' + encodeURIComponent(params[key]);
|
||||
}).join('&');
|
||||
|
||||
return newUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the basket is valid. if invalid displays error message and disables
|
||||
* checkout button
|
||||
* @param {Object} data - AJAX response from the server
|
||||
*/
|
||||
function validateBasket(data) {
|
||||
if (data.valid.error) {
|
||||
if (data.valid.message) {
|
||||
var errorHtml = '<div class="alert alert-danger alert-dismissible valid-cart-error ' +
|
||||
'fade show" role="alert">' +
|
||||
'<button type="button" class="close" data-dismiss="alert" aria-label="Close">' +
|
||||
'<span aria-hidden="true">×</span>' +
|
||||
'</button>' + data.valid.message + '</div>';
|
||||
|
||||
$('.cart-error').append(errorHtml);
|
||||
} else {
|
||||
$('.cart').empty().append('<div class="row"> ' +
|
||||
'<div class="col-12 text-center"> ' +
|
||||
'<h1>' + data.resources.emptyCartMsg + '</h1> ' +
|
||||
'</div> ' +
|
||||
'</div>'
|
||||
);
|
||||
$('.number-of-items').empty().append(data.resources.numberOfItems);
|
||||
$('.minicart-quantity').empty().append(data.numItems);
|
||||
$('.minicart-link').attr({
|
||||
'aria-label': data.resources.minicartCountOfItems,
|
||||
title: data.resources.minicartCountOfItems
|
||||
});
|
||||
$('.minicart .popover').empty();
|
||||
$('.minicart .popover').removeClass('show');
|
||||
}
|
||||
|
||||
$('.checkout-btn').addClass('disabled');
|
||||
} else {
|
||||
$('.checkout-btn').removeClass('disabled');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* re-renders the order totals and the number of items in the cart
|
||||
* @param {Object} data - AJAX response from the server
|
||||
*/
|
||||
function updateCartTotals(data) {
|
||||
$('.number-of-items').empty().append(data.resources.numberOfItems);
|
||||
$('.shipping-cost').empty().append(data.totals.totalShippingCost);
|
||||
$('.tax-total').empty().append(data.totals.totalTax);
|
||||
$('.grand-total').empty().append(data.totals.grandTotal);
|
||||
$('.sub-total').empty().append(data.totals.subTotal);
|
||||
$('.minicart-quantity').empty().append(data.numItems);
|
||||
$('.minicart-link').attr({
|
||||
'aria-label': data.resources.minicartCountOfItems,
|
||||
title: data.resources.minicartCountOfItems
|
||||
});
|
||||
if (data.totals.orderLevelDiscountTotal.value > 0) {
|
||||
$('.order-discount').removeClass('hide-order-discount');
|
||||
$('.order-discount-total').empty()
|
||||
.append('- ' + data.totals.orderLevelDiscountTotal.formatted);
|
||||
} else {
|
||||
$('.order-discount').addClass('hide-order-discount');
|
||||
}
|
||||
|
||||
if (data.totals.shippingLevelDiscountTotal.value > 0) {
|
||||
$('.shipping-discount').removeClass('hide-shipping-discount');
|
||||
$('.shipping-discount-total').empty().append('- ' +
|
||||
data.totals.shippingLevelDiscountTotal.formatted);
|
||||
} else {
|
||||
$('.shipping-discount').addClass('hide-shipping-discount');
|
||||
}
|
||||
|
||||
data.items.forEach(function (item) {
|
||||
if (data.totals.orderLevelDiscountTotal.value > 0) {
|
||||
$('.coupons-and-promos').empty().append(data.totals.discountsHtml);
|
||||
}
|
||||
if (item.renderedPromotions) {
|
||||
$('.item-' + item.UUID).empty().append(item.renderedPromotions);
|
||||
} else {
|
||||
$('.item-' + item.UUID).empty();
|
||||
}
|
||||
$('.uuid-' + item.UUID + ' .unit-price').empty().append(item.renderedPrice);
|
||||
$('.line-item-price-' + item.UUID + ' .unit-price').empty().append(item.renderedPrice);
|
||||
$('.item-total-' + item.UUID).empty().append(item.priceTotal.renderedPrice);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* re-renders the order totals and the number of items in the cart
|
||||
* @param {Object} message - Error message to display
|
||||
*/
|
||||
function createErrorNotification(message) {
|
||||
var errorHtml = '<div class="alert alert-danger alert-dismissible valid-cart-error ' +
|
||||
'fade show" role="alert">' +
|
||||
'<button type="button" class="close" data-dismiss="alert" aria-label="Close">' +
|
||||
'<span aria-hidden="true">×</span>' +
|
||||
'</button>' + message + '</div>';
|
||||
|
||||
$('.cart-error').append(errorHtml);
|
||||
}
|
||||
|
||||
/**
|
||||
* re-renders the approaching discount messages
|
||||
* @param {Object} approachingDiscounts - updated approaching discounts for the cart
|
||||
*/
|
||||
function updateApproachingDiscounts(approachingDiscounts) {
|
||||
var html = '';
|
||||
$('.approaching-discounts').empty();
|
||||
if (approachingDiscounts.length > 0) {
|
||||
approachingDiscounts.forEach(function (item) {
|
||||
html += '<div class="single-approaching-discount text-center">'
|
||||
+ item.discountMsg + '</div>';
|
||||
});
|
||||
}
|
||||
$('.approaching-discounts').append(html);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the availability of a product line item
|
||||
* @param {Object} data - AJAX response from the server
|
||||
* @param {string} uuid - The uuid of the product line item to update
|
||||
*/
|
||||
function updateAvailability(data, uuid) {
|
||||
var lineItem;
|
||||
var messages = '';
|
||||
|
||||
for (var i = 0; i < data.items.length; i++) {
|
||||
if (data.items[i].UUID === uuid) {
|
||||
lineItem = data.items[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lineItem != null) {
|
||||
$('.availability-' + lineItem.UUID).empty();
|
||||
|
||||
if (lineItem.availability) {
|
||||
if (lineItem.availability.messages) {
|
||||
lineItem.availability.messages.forEach(function (message) {
|
||||
messages += '<p class="line-item-attributes">' + message + '</p>';
|
||||
});
|
||||
}
|
||||
|
||||
if (lineItem.availability.inStockDate) {
|
||||
messages += '<p class="line-item-attributes line-item-instock-date">'
|
||||
+ lineItem.availability.inStockDate
|
||||
+ '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
$('.availability-' + lineItem.UUID).html(messages);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an element in the array that matches search parameter
|
||||
* @param {array} array - array of items to search
|
||||
* @param {function} match - function that takes an element and returns a boolean indicating if the match is made
|
||||
* @returns {Object|null} - returns an element of the array that matched the query.
|
||||
*/
|
||||
function findItem(array, match) { // eslint-disable-line no-unused-vars
|
||||
for (var i = 0, l = array.length; i < l; i++) {
|
||||
if (match.call(this, array[i])) {
|
||||
return array[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates details of a product line item
|
||||
* @param {Object} data - AJAX response from the server
|
||||
* @param {string} uuid - The uuid of the product line item to update
|
||||
*/
|
||||
function updateProductDetails(data, uuid) {
|
||||
$('.card.product-info.uuid-' + uuid).replaceWith(data.renderedTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the modal window on the first call.
|
||||
*
|
||||
*/
|
||||
function getModalHtmlElement() {
|
||||
if ($('#editProductModal').length !== 0) {
|
||||
$('#editProductModal').remove();
|
||||
}
|
||||
var htmlString = '<!-- Modal -->'
|
||||
+ '<div class="modal fade" id="editProductModal" tabindex="-1" role="dialog">'
|
||||
+ '<span class="enter-message sr-only" ></span>'
|
||||
+ '<div class="modal-dialog quick-view-dialog">'
|
||||
+ '<!-- Modal content-->'
|
||||
+ '<div class="modal-content">'
|
||||
+ '<div class="modal-header">'
|
||||
+ ' <button type="button" class="close pull-right" data-dismiss="modal">'
|
||||
+ ' <span aria-hidden="true">×</span>'
|
||||
+ ' <span class="sr-only"> </span>'
|
||||
+ ' </button>'
|
||||
+ '</div>'
|
||||
+ '<div class="modal-body"></div>'
|
||||
+ '<div class="modal-footer"></div>'
|
||||
+ '</div>'
|
||||
+ '</div>'
|
||||
+ '</div>';
|
||||
$('body').append(htmlString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the html for a modal window
|
||||
* @param {string} html - representing the body and footer of the modal window
|
||||
*
|
||||
* @return {Object} - Object with properties body and footer.
|
||||
*/
|
||||
function parseHtml(html) {
|
||||
var $html = $('<div>').append($.parseHTML(html));
|
||||
|
||||
var body = $html.find('.product-quickview');
|
||||
var footer = $html.find('.modal-footer').children();
|
||||
|
||||
return { body: body, footer: footer };
|
||||
}
|
||||
|
||||
/**
|
||||
* replaces the content in the modal window for product variation to be edited.
|
||||
* @param {string} editProductUrl - url to be used to retrieve a new product model
|
||||
*/
|
||||
function fillModalElement(editProductUrl) {
|
||||
$('.modal-body').spinner().start();
|
||||
$.ajax({
|
||||
url: editProductUrl,
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
var parsedHtml = parseHtml(data.renderedTemplate);
|
||||
|
||||
$('#editProductModal .modal-body').empty();
|
||||
$('#editProductModal .modal-body').html(parsedHtml.body);
|
||||
$('#editProductModal .modal-footer').html(parsedHtml.footer);
|
||||
$('#editProductModal .modal-header .close .sr-only').text(data.closeButtonText);
|
||||
$('#editProductModal .enter-message').text(data.enterDialogMessage);
|
||||
$('#editProductModal').modal('show');
|
||||
$('body').trigger('editproductmodal:ready');
|
||||
$.spinner().stop();
|
||||
},
|
||||
error: function () {
|
||||
$.spinner().stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* replace content of modal
|
||||
* @param {string} actionUrl - url to be used to remove product
|
||||
* @param {string} productID - pid
|
||||
* @param {string} productName - product name
|
||||
* @param {string} uuid - uuid
|
||||
*/
|
||||
function confirmDelete(actionUrl, productID, productName, uuid) {
|
||||
var $deleteConfirmBtn = $('.cart-delete-confirmation-btn');
|
||||
var $productToRemoveSpan = $('.product-to-remove');
|
||||
|
||||
$deleteConfirmBtn.data('pid', productID);
|
||||
$deleteConfirmBtn.data('action', actionUrl);
|
||||
$deleteConfirmBtn.data('uuid', uuid);
|
||||
|
||||
$productToRemoveSpan.empty().append(productName);
|
||||
}
|
||||
|
||||
module.exports = function () {
|
||||
$('body').on('click', '.remove-product', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var actionUrl = $(this).data('action');
|
||||
var productID = $(this).data('pid');
|
||||
var productName = $(this).data('name');
|
||||
var uuid = $(this).data('uuid');
|
||||
confirmDelete(actionUrl, productID, productName, uuid);
|
||||
});
|
||||
|
||||
$('body').on('afterRemoveFromCart', function (e, data) {
|
||||
e.preventDefault();
|
||||
confirmDelete(data.actionUrl, data.productID, data.productName, data.uuid);
|
||||
});
|
||||
|
||||
$('.optional-promo').click(function (e) {
|
||||
e.preventDefault();
|
||||
$('.promo-code-form').toggle();
|
||||
});
|
||||
|
||||
$('body').on('click', '.cart-delete-confirmation-btn', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var productID = $(this).data('pid');
|
||||
var url = $(this).data('action');
|
||||
var uuid = $(this).data('uuid');
|
||||
var urlParams = {
|
||||
pid: productID,
|
||||
uuid: uuid
|
||||
};
|
||||
|
||||
url = appendToUrl(url, urlParams);
|
||||
|
||||
$('body > .modal-backdrop').remove();
|
||||
|
||||
$.spinner().start();
|
||||
|
||||
$('body').trigger('cart:beforeUpdate');
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'get',
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
if (data.basket.items.length === 0) {
|
||||
$('.cart').empty().append('<div class="row"> ' +
|
||||
'<div class="col-12 text-center"> ' +
|
||||
'<h1>' + data.basket.resources.emptyCartMsg + '</h1> ' +
|
||||
'</div> ' +
|
||||
'</div>'
|
||||
);
|
||||
$('.number-of-items').empty().append(data.basket.resources.numberOfItems);
|
||||
$('.minicart-quantity').empty().append(data.basket.numItems);
|
||||
$('.minicart-link').attr({
|
||||
'aria-label': data.basket.resources.minicartCountOfItems,
|
||||
title: data.basket.resources.minicartCountOfItems
|
||||
});
|
||||
$('.minicart .popover').empty();
|
||||
$('.minicart .popover').removeClass('show');
|
||||
$('body').removeClass('modal-open');
|
||||
$('html').removeClass('veiled');
|
||||
} else {
|
||||
if (data.toBeDeletedUUIDs && data.toBeDeletedUUIDs.length > 0) {
|
||||
for (var i = 0; i < data.toBeDeletedUUIDs.length; i++) {
|
||||
$('.uuid-' + data.toBeDeletedUUIDs[i]).remove();
|
||||
}
|
||||
}
|
||||
$('.uuid-' + uuid).remove();
|
||||
if (!data.basket.hasBonusProduct) {
|
||||
$('.bonus-product').remove();
|
||||
}
|
||||
$('.coupons-and-promos').empty().append(data.basket.totals.discountsHtml);
|
||||
updateCartTotals(data.basket);
|
||||
updateApproachingDiscounts(data.basket.approachingDiscounts);
|
||||
$('body').trigger('setShippingMethodSelection', data.basket);
|
||||
validateBasket(data.basket);
|
||||
}
|
||||
|
||||
$('body').trigger('cart:update', data);
|
||||
|
||||
$.spinner().stop();
|
||||
},
|
||||
error: function (err) {
|
||||
if (err.responseJSON.redirectUrl) {
|
||||
window.location.href = err.responseJSON.redirectUrl;
|
||||
} else {
|
||||
createErrorNotification(err.responseJSON.errorMessage);
|
||||
$.spinner().stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('body').on('change', '.quantity-form > .quantity', function () {
|
||||
var preSelectQty = $(this).data('pre-select-qty');
|
||||
var quantity = $(this).val();
|
||||
var productID = $(this).data('pid');
|
||||
var url = $(this).data('action');
|
||||
var uuid = $(this).data('uuid');
|
||||
|
||||
var urlParams = {
|
||||
pid: productID,
|
||||
quantity: quantity,
|
||||
uuid: uuid
|
||||
};
|
||||
url = appendToUrl(url, urlParams);
|
||||
|
||||
$(this).parents('.card').spinner().start();
|
||||
|
||||
$('body').trigger('cart:beforeUpdate');
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'get',
|
||||
context: this,
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
$('.quantity[data-uuid="' + uuid + '"]').val(quantity);
|
||||
$('.coupons-and-promos').empty().append(data.totals.discountsHtml);
|
||||
updateCartTotals(data);
|
||||
updateApproachingDiscounts(data.approachingDiscounts);
|
||||
updateAvailability(data, uuid);
|
||||
validateBasket(data);
|
||||
$(this).data('pre-select-qty', quantity);
|
||||
|
||||
$('body').trigger('cart:update', data);
|
||||
|
||||
$.spinner().stop();
|
||||
if ($(this).parents('.product-info').hasClass('bonus-product-line-item') && $('.cart-page').length) {
|
||||
location.reload();
|
||||
}
|
||||
},
|
||||
error: function (err) {
|
||||
if (err.responseJSON.redirectUrl) {
|
||||
window.location.href = err.responseJSON.redirectUrl;
|
||||
} else {
|
||||
createErrorNotification(err.responseJSON.errorMessage);
|
||||
$(this).val(parseInt(preSelectQty, 10));
|
||||
$.spinner().stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('.shippingMethods').change(function () {
|
||||
var url = $(this).attr('data-actionUrl');
|
||||
var urlParams = {
|
||||
methodID: $(this).find(':selected').attr('data-shipping-id')
|
||||
};
|
||||
// url = appendToUrl(url, urlParams);
|
||||
|
||||
$('.totals').spinner().start();
|
||||
$('body').trigger('cart:beforeShippingMethodSelected');
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
data: urlParams,
|
||||
success: function (data) {
|
||||
if (data.error) {
|
||||
window.location.href = data.redirectUrl;
|
||||
} else {
|
||||
$('.coupons-and-promos').empty().append(data.totals.discountsHtml);
|
||||
updateCartTotals(data);
|
||||
updateApproachingDiscounts(data.approachingDiscounts);
|
||||
validateBasket(data);
|
||||
}
|
||||
|
||||
$('body').trigger('cart:shippingMethodSelected', data);
|
||||
$.spinner().stop();
|
||||
},
|
||||
error: function (err) {
|
||||
if (err.redirectUrl) {
|
||||
window.location.href = err.redirectUrl;
|
||||
} else {
|
||||
createErrorNotification(err.responseJSON.errorMessage);
|
||||
$.spinner().stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('.promo-code-form').submit(function (e) {
|
||||
e.preventDefault();
|
||||
$.spinner().start();
|
||||
$('.coupon-missing-error').hide();
|
||||
$('.coupon-error-message').empty();
|
||||
if (!$('.coupon-code-field').val()) {
|
||||
$('.promo-code-form .form-control').addClass('is-invalid');
|
||||
$('.promo-code-form .form-control').attr('aria-describedby', 'missingCouponCode');
|
||||
$('.coupon-missing-error').show();
|
||||
$.spinner().stop();
|
||||
return false;
|
||||
}
|
||||
var $form = $('.promo-code-form');
|
||||
$('.promo-code-form .form-control').removeClass('is-invalid');
|
||||
$('.coupon-error-message').empty();
|
||||
$('body').trigger('promotion:beforeUpdate');
|
||||
|
||||
$.ajax({
|
||||
url: $form.attr('action'),
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
data: $form.serialize(),
|
||||
success: function (data) {
|
||||
if (data.error) {
|
||||
$('.promo-code-form .form-control').addClass('is-invalid');
|
||||
$('.promo-code-form .form-control').attr('aria-describedby', 'invalidCouponCode');
|
||||
$('.coupon-error-message').empty().append(data.errorMessage);
|
||||
$('body').trigger('promotion:error', data);
|
||||
} else {
|
||||
$('.coupons-and-promos').empty().append(data.totals.discountsHtml);
|
||||
updateCartTotals(data);
|
||||
updateApproachingDiscounts(data.approachingDiscounts);
|
||||
validateBasket(data);
|
||||
$('body').trigger('promotion:success', data);
|
||||
}
|
||||
$('.coupon-code-field').val('');
|
||||
$.spinner().stop();
|
||||
},
|
||||
error: function (err) {
|
||||
$('body').trigger('promotion:error', err);
|
||||
if (err.responseJSON.redirectUrl) {
|
||||
window.location.href = err.responseJSON.redirectUrl;
|
||||
} else {
|
||||
createErrorNotification(err.errorMessage);
|
||||
$.spinner().stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
$('body').on('click', '.remove-coupon', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var couponCode = $(this).data('code');
|
||||
var uuid = $(this).data('uuid');
|
||||
var $deleteConfirmBtn = $('.delete-coupon-confirmation-btn');
|
||||
var $productToRemoveSpan = $('.coupon-to-remove');
|
||||
|
||||
$deleteConfirmBtn.data('uuid', uuid);
|
||||
$deleteConfirmBtn.data('code', couponCode);
|
||||
|
||||
$productToRemoveSpan.empty().append(couponCode);
|
||||
});
|
||||
|
||||
$('body').on('click', '.delete-coupon-confirmation-btn', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var url = $(this).data('action');
|
||||
var uuid = $(this).data('uuid');
|
||||
var couponCode = $(this).data('code');
|
||||
var urlParams = {
|
||||
code: couponCode,
|
||||
uuid: uuid
|
||||
};
|
||||
|
||||
url = appendToUrl(url, urlParams);
|
||||
|
||||
$('body > .modal-backdrop').remove();
|
||||
|
||||
$.spinner().start();
|
||||
$('body').trigger('promotion:beforeUpdate');
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'get',
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
$('.coupon-uuid-' + uuid).remove();
|
||||
updateCartTotals(data);
|
||||
updateApproachingDiscounts(data.approachingDiscounts);
|
||||
validateBasket(data);
|
||||
$.spinner().stop();
|
||||
$('body').trigger('promotion:success', data);
|
||||
},
|
||||
error: function (err) {
|
||||
$('body').trigger('promotion:error', err);
|
||||
if (err.responseJSON.redirectUrl) {
|
||||
window.location.href = err.responseJSON.redirectUrl;
|
||||
} else {
|
||||
createErrorNotification(err.responseJSON.errorMessage);
|
||||
$.spinner().stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
$('body').on('click', '.cart-page .bonus-product-button', function () {
|
||||
$.spinner().start();
|
||||
$(this).addClass('launched-modal');
|
||||
$.ajax({
|
||||
url: $(this).data('url'),
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
base.methods.editBonusProducts(data);
|
||||
$.spinner().stop();
|
||||
},
|
||||
error: function () {
|
||||
$.spinner().stop();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('body').on('hidden.bs.modal', '#chooseBonusProductModal', function () {
|
||||
$('#chooseBonusProductModal').remove();
|
||||
$('.modal-backdrop').remove();
|
||||
$('body').removeClass('modal-open');
|
||||
|
||||
if ($('.cart-page').length) {
|
||||
$('.launched-modal .btn-outline-primary').trigger('focus');
|
||||
$('.launched-modal').removeClass('launched-modal');
|
||||
} else {
|
||||
$('.product-detail .add-to-cart').focus();
|
||||
}
|
||||
});
|
||||
|
||||
$('body').on('click', '.cart-page .product-edit .edit, .cart-page .bundle-edit .edit', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var editProductUrl = $(this).attr('href');
|
||||
getModalHtmlElement();
|
||||
fillModalElement(editProductUrl);
|
||||
});
|
||||
|
||||
$('body').on('shown.bs.modal', '#editProductModal', function () {
|
||||
$('#editProductModal').siblings().attr('aria-hidden', 'true');
|
||||
$('#editProductModal .close').focus();
|
||||
});
|
||||
|
||||
$('body').on('hidden.bs.modal', '#editProductModal', function () {
|
||||
$('#editProductModal').siblings().attr('aria-hidden', 'false');
|
||||
});
|
||||
|
||||
$('body').on('keydown', '#editProductModal', function (e) {
|
||||
var focusParams = {
|
||||
event: e,
|
||||
containerSelector: '#editProductModal',
|
||||
firstElementSelector: '.close',
|
||||
lastElementSelector: '.update-cart-product-global',
|
||||
nextToLastElementSelector: '.modal-footer .quantity-select'
|
||||
};
|
||||
focusHelper.setTabNextFocus(focusParams);
|
||||
});
|
||||
|
||||
$('body').on('product:updateAddToCart', function (e, response) {
|
||||
// update global add to cart (single products, bundles)
|
||||
var dialog = $(response.$productContainer)
|
||||
.closest('.quick-view-dialog');
|
||||
|
||||
$('.update-cart-product-global', dialog).attr('disabled',
|
||||
!$('.global-availability', dialog).data('ready-to-order')
|
||||
|| !$('.global-availability', dialog).data('available')
|
||||
);
|
||||
});
|
||||
|
||||
$('body').on('product:updateAvailability', function (e, response) {
|
||||
// bundle individual products
|
||||
$('.product-availability', response.$productContainer)
|
||||
.data('ready-to-order', response.product.readyToOrder)
|
||||
.data('available', response.product.available)
|
||||
.find('.availability-msg')
|
||||
.empty()
|
||||
.html(response.message);
|
||||
|
||||
|
||||
var dialog = $(response.$productContainer)
|
||||
.closest('.quick-view-dialog');
|
||||
|
||||
if ($('.product-availability', dialog).length) {
|
||||
// bundle all products
|
||||
var allAvailable = $('.product-availability', dialog).toArray()
|
||||
.every(function (item) { return $(item).data('available'); });
|
||||
|
||||
var allReady = $('.product-availability', dialog).toArray()
|
||||
.every(function (item) { return $(item).data('ready-to-order'); });
|
||||
|
||||
$('.global-availability', dialog)
|
||||
.data('ready-to-order', allReady)
|
||||
.data('available', allAvailable);
|
||||
|
||||
$('.global-availability .availability-msg', dialog).empty()
|
||||
.html(allReady ? response.message : response.resources.info_selectforstock);
|
||||
} else {
|
||||
// single product
|
||||
$('.global-availability', dialog)
|
||||
.data('ready-to-order', response.product.readyToOrder)
|
||||
.data('available', response.product.available)
|
||||
.find('.availability-msg')
|
||||
.empty()
|
||||
.html(response.message);
|
||||
}
|
||||
});
|
||||
|
||||
$('body').on('product:afterAttributeSelect', function (e, response) {
|
||||
if ($('.modal.show .product-quickview .bundle-items').length) {
|
||||
$('.modal.show').find(response.container).data('pid', response.data.product.id);
|
||||
$('.modal.show').find(response.container).find('.product-id').text(response.data.product.id);
|
||||
} else {
|
||||
$('.modal.show .product-quickview').data('pid', response.data.product.id);
|
||||
}
|
||||
});
|
||||
|
||||
$('body').on('change', '.quantity-select', function () {
|
||||
var selectedQuantity = $(this).val();
|
||||
$('.modal.show .update-cart-url').data('selected-quantity', selectedQuantity);
|
||||
});
|
||||
|
||||
$('body').on('change', '.options-select', function () {
|
||||
var selectedOptionValueId = $(this).children('option:selected').data('value-id');
|
||||
$('.modal.show .update-cart-url').data('selected-option', selectedOptionValueId);
|
||||
});
|
||||
|
||||
$('body').on('click', '.update-cart-product-global', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var updateProductUrl = $(this).closest('.cart-and-ipay').find('.update-cart-url').val();
|
||||
var selectedQuantity = $(this).closest('.cart-and-ipay').find('.update-cart-url').data('selected-quantity');
|
||||
var selectedOptionValueId = $(this).closest('.cart-and-ipay').find('.update-cart-url').data('selected-option');
|
||||
var uuid = $(this).closest('.cart-and-ipay').find('.update-cart-url').data('uuid');
|
||||
|
||||
var form = {
|
||||
uuid: uuid,
|
||||
pid: base.getPidValue($(this)),
|
||||
quantity: selectedQuantity,
|
||||
selectedOptionValueId: selectedOptionValueId
|
||||
};
|
||||
|
||||
$(this).parents('.card').spinner().start();
|
||||
|
||||
$('body').trigger('cart:beforeUpdate');
|
||||
|
||||
if (updateProductUrl) {
|
||||
$.ajax({
|
||||
url: updateProductUrl,
|
||||
type: 'post',
|
||||
context: this,
|
||||
data: form,
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
$('#editProductModal').modal('hide');
|
||||
|
||||
$('.coupons-and-promos').empty().append(data.cartModel.totals.discountsHtml);
|
||||
updateCartTotals(data.cartModel);
|
||||
updateApproachingDiscounts(data.cartModel.approachingDiscounts);
|
||||
updateAvailability(data.cartModel, uuid);
|
||||
updateProductDetails(data, uuid);
|
||||
|
||||
if (data.uuidToBeDeleted) {
|
||||
$('.uuid-' + data.uuidToBeDeleted).remove();
|
||||
}
|
||||
|
||||
validateBasket(data.cartModel);
|
||||
|
||||
$('body').trigger('cart:update', data);
|
||||
|
||||
$.spinner().stop();
|
||||
},
|
||||
error: function (err) {
|
||||
if (err.responseJSON.redirectUrl) {
|
||||
window.location.href = err.responseJSON.redirectUrl;
|
||||
} else {
|
||||
createErrorNotification(err.responseJSON.errorMessage);
|
||||
$.spinner().stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
base.selectAttribute();
|
||||
base.colorAttribute();
|
||||
base.removeBonusProduct();
|
||||
base.selectBonusProduct();
|
||||
base.enableBonusProductSelection();
|
||||
base.showMoreBonusProducts();
|
||||
base.addBonusProductsToCart();
|
||||
base.focusChooseBonusProductModal();
|
||||
base.trapChooseBonusProductModalFocus();
|
||||
base.onClosingChooseBonusProductModal();
|
||||
};
|
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var processInclude = require('./util');
|
||||
|
||||
$(document).ready(function () {
|
||||
processInclude(require('./checkout/checkout'));
|
||||
});
|
@@ -0,0 +1,187 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Populate the Billing Address Summary View
|
||||
* @param {string} parentSelector - the top level DOM selector for a unique address summary
|
||||
* @param {Object} address - the address data
|
||||
*/
|
||||
function populateAddressSummary(parentSelector, address) {
|
||||
$.each(address, function (attr) {
|
||||
var val = address[attr];
|
||||
$('.' + attr, parentSelector).text(val || '');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a formed <option /> element
|
||||
* @param {Object} shipping - the shipping object (shipment model)
|
||||
* @param {boolean} selected - current shipping is selected (for PLI)
|
||||
* @param {order} order - the Order model
|
||||
* @param {Object} [options] - options
|
||||
* @returns {Object} - the jQuery / DOMElement
|
||||
*/
|
||||
function optionValueForAddress(shipping, selected, order, options) {
|
||||
var safeOptions = options || {};
|
||||
var isBilling = safeOptions.type && safeOptions.type === 'billing';
|
||||
var className = safeOptions.className || '';
|
||||
var isSelected = selected;
|
||||
var isNew = !shipping;
|
||||
if (typeof shipping === 'string') {
|
||||
return $('<option class="' + className + '" disabled>' + shipping + '</option>');
|
||||
}
|
||||
var safeShipping = shipping || {};
|
||||
var shippingAddress = safeShipping.shippingAddress || {};
|
||||
|
||||
if (isBilling && isNew && !order.billing.matchingAddressId) {
|
||||
shippingAddress = order.billing.billingAddress.address || {};
|
||||
isNew = false;
|
||||
isSelected = true;
|
||||
safeShipping.UUID = 'manual-entry';
|
||||
}
|
||||
|
||||
var uuid = safeShipping.UUID ? safeShipping.UUID : 'new';
|
||||
var optionEl = $('<option class="' + className + '" />');
|
||||
optionEl.val(uuid);
|
||||
|
||||
var title;
|
||||
|
||||
if (isNew) {
|
||||
title = order.resources.addNewAddress;
|
||||
} else {
|
||||
title = [];
|
||||
if (shippingAddress.firstName) {
|
||||
title.push(shippingAddress.firstName);
|
||||
}
|
||||
if (shippingAddress.lastName) {
|
||||
title.push(shippingAddress.lastName);
|
||||
}
|
||||
if (shippingAddress.address1) {
|
||||
title.push(shippingAddress.address1);
|
||||
}
|
||||
if (shippingAddress.address2) {
|
||||
title.push(shippingAddress.address2);
|
||||
}
|
||||
if (shippingAddress.city) {
|
||||
if (shippingAddress.state) {
|
||||
title.push(shippingAddress.city + ',');
|
||||
} else {
|
||||
title.push(shippingAddress.city);
|
||||
}
|
||||
}
|
||||
if (shippingAddress.stateCode) {
|
||||
title.push(shippingAddress.stateCode);
|
||||
}
|
||||
if (shippingAddress.postalCode) {
|
||||
title.push(shippingAddress.postalCode);
|
||||
}
|
||||
if (!isBilling && safeShipping.selectedShippingMethod) {
|
||||
title.push('-');
|
||||
title.push(safeShipping.selectedShippingMethod.displayName);
|
||||
}
|
||||
|
||||
if (title.length > 2) {
|
||||
title = title.join(' ');
|
||||
} else {
|
||||
title = order.resources.newAddress;
|
||||
}
|
||||
}
|
||||
optionEl.text(title);
|
||||
|
||||
var keyMap = {
|
||||
'data-first-name': 'firstName',
|
||||
'data-last-name': 'lastName',
|
||||
'data-address1': 'address1',
|
||||
'data-address2': 'address2',
|
||||
'data-city': 'city',
|
||||
'data-state-code': 'stateCode',
|
||||
'data-postal-code': 'postalCode',
|
||||
'data-country-code': 'countryCode',
|
||||
'data-phone': 'phone'
|
||||
};
|
||||
$.each(keyMap, function (key) {
|
||||
var mappedKey = keyMap[key];
|
||||
var mappedValue = shippingAddress[mappedKey];
|
||||
// In case of country code
|
||||
if (mappedValue && typeof mappedValue === 'object') {
|
||||
mappedValue = mappedValue.value;
|
||||
}
|
||||
|
||||
optionEl.attr(key, mappedValue || '');
|
||||
});
|
||||
|
||||
var giftObj = {
|
||||
'data-is-gift': 'isGift',
|
||||
'data-gift-message': 'giftMessage'
|
||||
};
|
||||
|
||||
$.each(giftObj, function (key) {
|
||||
var mappedKey = giftObj[key];
|
||||
var mappedValue = safeShipping[mappedKey];
|
||||
optionEl.attr(key, mappedValue || '');
|
||||
});
|
||||
|
||||
if (isSelected) {
|
||||
optionEl.attr('selected', true);
|
||||
}
|
||||
|
||||
return optionEl;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns address properties from a UI form
|
||||
* @param {Form} form - the Form element
|
||||
* @returns {Object} - a JSON object with all values
|
||||
*/
|
||||
function getAddressFieldsFromUI(form) {
|
||||
var address = {
|
||||
firstName: $('input[name$=_firstName]', form).val(),
|
||||
lastName: $('input[name$=_lastName]', form).val(),
|
||||
address1: $('input[name$=_address1]', form).val(),
|
||||
address2: $('input[name$=_address2]', form).val(),
|
||||
city: $('input[name$=_city]', form).val(),
|
||||
postalCode: $('input[name$=_postalCode]', form).val(),
|
||||
stateCode: $('select[name$=_stateCode],input[name$=_stateCode]', form).val(),
|
||||
countryCode: $('select[name$=_country]', form).val(),
|
||||
phone: $('input[name$=_phone]', form).val()
|
||||
};
|
||||
return address;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
methods: {
|
||||
populateAddressSummary: populateAddressSummary,
|
||||
optionValueForAddress: optionValueForAddress,
|
||||
getAddressFieldsFromUI: getAddressFieldsFromUI
|
||||
},
|
||||
|
||||
showDetails: function () {
|
||||
$('.btn-show-details').on('click', function () {
|
||||
var form = $(this).closest('form');
|
||||
|
||||
form.attr('data-address-mode', 'details');
|
||||
form.find('.multi-ship-address-actions').removeClass('d-none');
|
||||
form.find('.multi-ship-action-buttons .col-12.btn-save-multi-ship').addClass('d-none');
|
||||
});
|
||||
},
|
||||
|
||||
addNewAddress: function () {
|
||||
$('.btn-add-new').on('click', function () {
|
||||
var $el = $(this);
|
||||
if ($el.parents('#dwfrm_billing').length > 0) {
|
||||
// Handle billing address case
|
||||
$('body').trigger('checkout:clearBillingForm');
|
||||
var $option = $($el.parents('form').find('.addressSelector option')[0]);
|
||||
$option.attr('value', 'new');
|
||||
var $newTitle = $('#dwfrm_billing input[name=localizedNewAddressTitle]').val();
|
||||
$option.text($newTitle);
|
||||
$option.prop('selected', 'selected');
|
||||
$el.parents('[data-address-mode]').attr('data-address-mode', 'new');
|
||||
} else {
|
||||
// Handle shipping address case
|
||||
var $newEl = $el.parents('form').find('.addressSelector option[value=new]');
|
||||
$newEl.prop('selected', 'selected');
|
||||
$newEl.parent().trigger('change');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
@@ -0,0 +1,327 @@
|
||||
'use strict';
|
||||
|
||||
var addressHelpers = require('./address');
|
||||
var cleave = require('../components/cleave');
|
||||
|
||||
/**
|
||||
* updates the billing address selector within billing forms
|
||||
* @param {Object} order - the order model
|
||||
* @param {Object} customer - the customer model
|
||||
*/
|
||||
function updateBillingAddressSelector(order, customer) {
|
||||
var shippings = order.shipping;
|
||||
|
||||
var form = $('form[name$=billing]')[0];
|
||||
var $billingAddressSelector = $('.addressSelector', form);
|
||||
var hasSelectedAddress = false;
|
||||
|
||||
if ($billingAddressSelector && $billingAddressSelector.length === 1) {
|
||||
$billingAddressSelector.empty();
|
||||
// Add New Address option
|
||||
$billingAddressSelector.append(addressHelpers.methods.optionValueForAddress(
|
||||
null,
|
||||
false,
|
||||
order,
|
||||
{ type: 'billing' }));
|
||||
|
||||
// Separator -
|
||||
$billingAddressSelector.append(addressHelpers.methods.optionValueForAddress(
|
||||
order.resources.shippingAddresses, false, order, {
|
||||
// className: 'multi-shipping',
|
||||
type: 'billing'
|
||||
}
|
||||
));
|
||||
|
||||
shippings.forEach(function (aShipping) {
|
||||
var isSelected = order.billing.matchingAddressId === aShipping.UUID;
|
||||
hasSelectedAddress = hasSelectedAddress || isSelected;
|
||||
// Shipping Address option
|
||||
$billingAddressSelector.append(
|
||||
addressHelpers.methods.optionValueForAddress(aShipping, isSelected, order,
|
||||
{
|
||||
// className: 'multi-shipping',
|
||||
type: 'billing'
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
if (customer.addresses && customer.addresses.length > 0) {
|
||||
$billingAddressSelector.append(addressHelpers.methods.optionValueForAddress(
|
||||
order.resources.accountAddresses, false, order));
|
||||
customer.addresses.forEach(function (address) {
|
||||
var isSelected = order.billing.matchingAddressId === address.ID;
|
||||
hasSelectedAddress = hasSelectedAddress || isSelected;
|
||||
// Customer Address option
|
||||
$billingAddressSelector.append(
|
||||
addressHelpers.methods.optionValueForAddress({
|
||||
UUID: 'ab_' + address.ID,
|
||||
shippingAddress: address
|
||||
}, isSelected, order, { type: 'billing' })
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (hasSelectedAddress
|
||||
|| (!order.billing.matchingAddressId && order.billing.billingAddress.address)) {
|
||||
// show
|
||||
$(form).attr('data-address-mode', 'edit');
|
||||
} else {
|
||||
$(form).attr('data-address-mode', 'new');
|
||||
}
|
||||
|
||||
$billingAddressSelector.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the billing address form values within payment forms without any payment instrument validation
|
||||
* @param {Object} order - the order model
|
||||
*/
|
||||
function updateBillingAddress(order) {
|
||||
var billing = order.billing;
|
||||
if (!billing.billingAddress || !billing.billingAddress.address) return;
|
||||
|
||||
var form = $('form[name=dwfrm_billing]');
|
||||
if (!form) return;
|
||||
|
||||
$('input[name$=_firstName]', form).val(billing.billingAddress.address.firstName);
|
||||
$('input[name$=_lastName]', form).val(billing.billingAddress.address.lastName);
|
||||
$('input[name$=_address1]', form).val(billing.billingAddress.address.address1);
|
||||
$('input[name$=_address2]', form).val(billing.billingAddress.address.address2);
|
||||
$('input[name$=_city]', form).val(billing.billingAddress.address.city);
|
||||
$('input[name$=_postalCode]', form).val(billing.billingAddress.address.postalCode);
|
||||
$('select[name$=_stateCode],input[name$=_stateCode]', form)
|
||||
.val(billing.billingAddress.address.stateCode);
|
||||
$('select[name$=_country]', form).val(billing.billingAddress.address.countryCode.value);
|
||||
$('input[name$=_phone]', form).val(billing.billingAddress.address.phone);
|
||||
$('input[name$=_email]', form).val(order.orderEmail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate and update payment instrument form fields
|
||||
* @param {Object} order - the order model
|
||||
*/
|
||||
function validateAndUpdateBillingPaymentInstrument(order) {
|
||||
var billing = order.billing;
|
||||
if (!billing.payment || !billing.payment.selectedPaymentInstruments
|
||||
|| billing.payment.selectedPaymentInstruments.length <= 0) return;
|
||||
|
||||
var form = $('form[name=dwfrm_billing]');
|
||||
if (!form) return;
|
||||
|
||||
var instrument = billing.payment.selectedPaymentInstruments[0];
|
||||
$('select[name$=expirationMonth]', form).val(instrument.expirationMonth);
|
||||
$('select[name$=expirationYear]', form).val(instrument.expirationYear);
|
||||
// Force security code and card number clear
|
||||
$('input[name$=securityCode]', form).val('');
|
||||
$('input[name$=cardNumber]').data('cleave').setRawValue('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the billing address form values within payment forms
|
||||
* @param {Object} order - the order model
|
||||
*/
|
||||
function updateBillingAddressFormValues(order) {
|
||||
module.exports.methods.updateBillingAddress(order);
|
||||
module.exports.methods.validateAndUpdateBillingPaymentInstrument(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* clears the billing address form values
|
||||
*/
|
||||
function clearBillingAddressFormValues() {
|
||||
updateBillingAddressFormValues({
|
||||
billing: {
|
||||
billingAddress: {
|
||||
address: {
|
||||
countryCode: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* update billing address summary and contact information
|
||||
* @param {Object} order - checkout model to use as basis of new truth
|
||||
*/
|
||||
function updateBillingAddressSummary(order) {
|
||||
// update billing address summary
|
||||
addressHelpers.methods.populateAddressSummary('.billing .address-summary',
|
||||
order.billing.billingAddress.address);
|
||||
|
||||
// update billing parts of order summary
|
||||
$('.order-summary-email').text(order.orderEmail);
|
||||
|
||||
if (order.billing.billingAddress.address) {
|
||||
$('.order-summary-phone').text(order.billing.billingAddress.address.phone);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the billing information in checkout, based on the supplied order model
|
||||
* @param {Object} order - checkout model to use as basis of new truth
|
||||
* @param {Object} customer - customer model to use as basis of new truth
|
||||
* @param {Object} [options] - options
|
||||
*/
|
||||
function updateBillingInformation(order, customer) {
|
||||
updateBillingAddressSelector(order, customer);
|
||||
|
||||
// update billing address form
|
||||
updateBillingAddressFormValues(order);
|
||||
|
||||
// update billing address summary and billing parts of order summary
|
||||
updateBillingAddressSummary(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the payment information in checkout, based on the supplied order model
|
||||
* @param {Object} order - checkout model to use as basis of new truth
|
||||
*/
|
||||
function updatePaymentInformation(order) {
|
||||
// update payment details
|
||||
var $paymentSummary = $('.payment-details');
|
||||
var htmlToAppend = '';
|
||||
|
||||
if (order.billing.payment && order.billing.payment.selectedPaymentInstruments
|
||||
&& order.billing.payment.selectedPaymentInstruments.length > 0) {
|
||||
htmlToAppend += '<span>' + order.resources.cardType + ' '
|
||||
+ order.billing.payment.selectedPaymentInstruments[0].type
|
||||
+ '</span><div>'
|
||||
+ order.billing.payment.selectedPaymentInstruments[0].maskedCreditCardNumber
|
||||
+ '</div><div><span>'
|
||||
+ order.resources.cardEnding + ' '
|
||||
+ order.billing.payment.selectedPaymentInstruments[0].expirationMonth
|
||||
+ '/' + order.billing.payment.selectedPaymentInstruments[0].expirationYear
|
||||
+ '</span></div>';
|
||||
}
|
||||
|
||||
$paymentSummary.empty().append(htmlToAppend);
|
||||
}
|
||||
|
||||
/**
|
||||
* clears the credit card form
|
||||
*/
|
||||
function clearCreditCardForm() {
|
||||
$('input[name$="_cardNumber"]').data('cleave').setRawValue('');
|
||||
$('select[name$="_expirationMonth"]').val('');
|
||||
$('select[name$="_expirationYear"]').val('');
|
||||
$('input[name$="_securityCode"]').val('');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
methods: {
|
||||
updateBillingAddressSelector: updateBillingAddressSelector,
|
||||
updateBillingAddressFormValues: updateBillingAddressFormValues,
|
||||
clearBillingAddressFormValues: clearBillingAddressFormValues,
|
||||
updateBillingInformation: updateBillingInformation,
|
||||
updatePaymentInformation: updatePaymentInformation,
|
||||
clearCreditCardForm: clearCreditCardForm,
|
||||
updateBillingAddress: updateBillingAddress,
|
||||
validateAndUpdateBillingPaymentInstrument: validateAndUpdateBillingPaymentInstrument,
|
||||
updateBillingAddressSummary: updateBillingAddressSummary
|
||||
},
|
||||
|
||||
showBillingDetails: function () {
|
||||
$('.btn-show-billing-details').on('click', function () {
|
||||
$(this).parents('[data-address-mode]').attr('data-address-mode', 'new');
|
||||
});
|
||||
},
|
||||
|
||||
hideBillingDetails: function () {
|
||||
$('.btn-hide-billing-details').on('click', function () {
|
||||
$(this).parents('[data-address-mode]').attr('data-address-mode', 'shipment');
|
||||
});
|
||||
},
|
||||
|
||||
selectBillingAddress: function () {
|
||||
$('.payment-form .addressSelector').on('change', function () {
|
||||
var form = $(this).parents('form')[0];
|
||||
var selectedOption = $('option:selected', this);
|
||||
var optionID = selectedOption[0].value;
|
||||
|
||||
if (optionID === 'new') {
|
||||
// Show Address
|
||||
$(form).attr('data-address-mode', 'new');
|
||||
} else {
|
||||
// Hide Address
|
||||
$(form).attr('data-address-mode', 'shipment');
|
||||
}
|
||||
|
||||
// Copy fields
|
||||
var attrs = selectedOption.data();
|
||||
var element;
|
||||
|
||||
Object.keys(attrs).forEach(function (attr) {
|
||||
element = attr === 'countryCode' ? 'country' : attr;
|
||||
if (element === 'cardNumber') {
|
||||
$('.cardNumber').data('cleave').setRawValue(attrs[attr]);
|
||||
} else {
|
||||
$('[name$=' + element + ']', form).val(attrs[attr]);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
handleCreditCardNumber: function () {
|
||||
cleave.handleCreditCardNumber('.cardNumber', '#cardType');
|
||||
},
|
||||
|
||||
santitizeForm: function () {
|
||||
$('body').on('checkout:serializeBilling', function (e, data) {
|
||||
var serializedForm = cleave.serializeData(data.form);
|
||||
|
||||
data.callback(serializedForm);
|
||||
});
|
||||
},
|
||||
|
||||
selectSavedPaymentInstrument: function () {
|
||||
$(document).on('click', '.saved-payment-instrument', function (e) {
|
||||
e.preventDefault();
|
||||
$('.saved-payment-security-code').val('');
|
||||
$('.saved-payment-instrument').removeClass('selected-payment');
|
||||
$(this).addClass('selected-payment');
|
||||
$('.saved-payment-instrument .card-image').removeClass('checkout-hidden');
|
||||
$('.saved-payment-instrument .security-code-input').addClass('checkout-hidden');
|
||||
$('.saved-payment-instrument.selected-payment' +
|
||||
' .card-image').addClass('checkout-hidden');
|
||||
$('.saved-payment-instrument.selected-payment ' +
|
||||
'.security-code-input').removeClass('checkout-hidden');
|
||||
});
|
||||
},
|
||||
|
||||
addNewPaymentInstrument: function () {
|
||||
$('.btn.add-payment').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
$('.payment-information').data('is-new-payment', true);
|
||||
clearCreditCardForm();
|
||||
$('.credit-card-form').removeClass('checkout-hidden');
|
||||
$('.user-payment-instruments').addClass('checkout-hidden');
|
||||
});
|
||||
},
|
||||
|
||||
cancelNewPayment: function () {
|
||||
$('.cancel-new-payment').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
$('.payment-information').data('is-new-payment', false);
|
||||
clearCreditCardForm();
|
||||
$('.user-payment-instruments').removeClass('checkout-hidden');
|
||||
$('.credit-card-form').addClass('checkout-hidden');
|
||||
});
|
||||
},
|
||||
|
||||
clearBillingForm: function () {
|
||||
$('body').on('checkout:clearBillingForm', function () {
|
||||
clearBillingAddressFormValues();
|
||||
});
|
||||
},
|
||||
|
||||
paymentTabs: function () {
|
||||
$('.payment-options .nav-item').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
var methodID = $(this).data('method-id');
|
||||
$('.payment-information').data('payment-method-id', methodID);
|
||||
});
|
||||
}
|
||||
};
|
@@ -0,0 +1,633 @@
|
||||
'use strict';
|
||||
|
||||
var customerHelpers = require('./customer');
|
||||
var addressHelpers = require('./address');
|
||||
var shippingHelpers = require('./shipping');
|
||||
var billingHelpers = require('./billing');
|
||||
var summaryHelpers = require('./summary');
|
||||
var formHelpers = require('./formErrors');
|
||||
var scrollAnimate = require('../components/scrollAnimate');
|
||||
|
||||
|
||||
/**
|
||||
* Create the jQuery Checkout Plugin.
|
||||
*
|
||||
* This jQuery plugin will be registered on the dom element in checkout.isml with the
|
||||
* id of "checkout-main".
|
||||
*
|
||||
* The checkout plugin will handle the different state the user interface is in as the user
|
||||
* progresses through the varying forms such as shipping and payment.
|
||||
*
|
||||
* Billing info and payment info are used a bit synonymously in this code.
|
||||
*
|
||||
*/
|
||||
(function ($) {
|
||||
$.fn.checkout = function () { // eslint-disable-line
|
||||
var plugin = this;
|
||||
|
||||
//
|
||||
// Collect form data from user input
|
||||
//
|
||||
var formData = {
|
||||
// Customer Data
|
||||
customer: {},
|
||||
|
||||
// Shipping Address
|
||||
shipping: {},
|
||||
|
||||
// Billing Address
|
||||
billing: {},
|
||||
|
||||
// Payment
|
||||
payment: {},
|
||||
|
||||
// Gift Codes
|
||||
giftCode: {}
|
||||
};
|
||||
|
||||
//
|
||||
// The different states/stages of checkout
|
||||
//
|
||||
var checkoutStages = [
|
||||
'customer',
|
||||
'shipping',
|
||||
'payment',
|
||||
'placeOrder',
|
||||
'submitted'
|
||||
];
|
||||
|
||||
/**
|
||||
* Updates the URL to determine stage
|
||||
* @param {number} currentStage - The current stage the user is currently on in the checkout
|
||||
*/
|
||||
function updateUrl(currentStage) {
|
||||
history.pushState(
|
||||
checkoutStages[currentStage],
|
||||
document.title,
|
||||
location.pathname
|
||||
+ '?stage='
|
||||
+ checkoutStages[currentStage]
|
||||
+ '#'
|
||||
+ checkoutStages[currentStage]
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Local member methods of the Checkout plugin
|
||||
//
|
||||
var members = {
|
||||
|
||||
// initialize the currentStage variable for the first time
|
||||
currentStage: 0,
|
||||
|
||||
/**
|
||||
* Set or update the checkout stage (AKA the shipping, billing, payment, etc... steps)
|
||||
* @returns {Object} a promise
|
||||
*/
|
||||
updateStage: function () {
|
||||
var stage = checkoutStages[members.currentStage];
|
||||
var defer = $.Deferred(); // eslint-disable-line
|
||||
|
||||
if (stage === 'customer') {
|
||||
//
|
||||
// Clear Previous Errors
|
||||
//
|
||||
customerHelpers.methods.clearErrors();
|
||||
//
|
||||
// Submit the Customer Form
|
||||
//
|
||||
var customerFormSelector = customerHelpers.methods.isGuestFormActive() ? customerHelpers.vars.GUEST_FORM : customerHelpers.vars.REGISTERED_FORM;
|
||||
var customerForm = $(customerFormSelector);
|
||||
$.ajax({
|
||||
url: customerForm.attr('action'),
|
||||
type: 'post',
|
||||
data: customerForm.serialize(),
|
||||
success: function (data) {
|
||||
if (data.redirectUrl) {
|
||||
window.location.href = data.redirectUrl;
|
||||
} else {
|
||||
customerHelpers.methods.customerFormResponse(defer, data);
|
||||
}
|
||||
},
|
||||
error: function (err) {
|
||||
if (err.responseJSON && err.responseJSON.redirectUrl) {
|
||||
window.location.href = err.responseJSON.redirectUrl;
|
||||
}
|
||||
// Server error submitting form
|
||||
defer.reject(err.responseJSON);
|
||||
}
|
||||
});
|
||||
return defer;
|
||||
} else if (stage === 'shipping') {
|
||||
//
|
||||
// Clear Previous Errors
|
||||
//
|
||||
formHelpers.clearPreviousErrors('.shipping-form');
|
||||
|
||||
//
|
||||
// Submit the Shipping Address Form
|
||||
//
|
||||
var isMultiShip = $('#checkout-main').hasClass('multi-ship');
|
||||
var formSelector = isMultiShip ?
|
||||
'.multi-shipping .active form' : '.single-shipping .shipping-form';
|
||||
var form = $(formSelector);
|
||||
|
||||
if (isMultiShip && form.length === 0) {
|
||||
// disable the next:Payment button here
|
||||
$('body').trigger('checkout:disableButton', '.next-step-button button');
|
||||
// in case the multi ship form is already submitted
|
||||
var url = $('#checkout-main').attr('data-checkout-get-url');
|
||||
$.ajax({
|
||||
url: url,
|
||||
method: 'GET',
|
||||
success: function (data) {
|
||||
// enable the next:Payment button here
|
||||
$('body').trigger('checkout:enableButton', '.next-step-button button');
|
||||
if (!data.error) {
|
||||
$('body').trigger('checkout:updateCheckoutView',
|
||||
{ order: data.order, customer: data.customer });
|
||||
defer.resolve();
|
||||
} else if (data.message && $('.shipping-error .alert-danger').length < 1) {
|
||||
var errorMsg = data.message;
|
||||
var errorHtml = '<div class="alert alert-danger alert-dismissible valid-cart-error ' +
|
||||
'fade show" role="alert">' +
|
||||
'<button type="button" class="close" data-dismiss="alert" aria-label="Close">' +
|
||||
'<span aria-hidden="true">×</span>' +
|
||||
'</button>' + errorMsg + '</div>';
|
||||
$('.shipping-error').append(errorHtml);
|
||||
scrollAnimate($('.shipping-error'));
|
||||
defer.reject();
|
||||
} else if (data.redirectUrl) {
|
||||
window.location.href = data.redirectUrl;
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
// enable the next:Payment button here
|
||||
$('body').trigger('checkout:enableButton', '.next-step-button button');
|
||||
// Server error submitting form
|
||||
defer.reject();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
var shippingFormData = form.serialize();
|
||||
|
||||
$('body').trigger('checkout:serializeShipping', {
|
||||
form: form,
|
||||
data: shippingFormData,
|
||||
callback: function (data) {
|
||||
shippingFormData = data;
|
||||
}
|
||||
});
|
||||
// disable the next:Payment button here
|
||||
$('body').trigger('checkout:disableButton', '.next-step-button button');
|
||||
$.ajax({
|
||||
url: form.attr('action'),
|
||||
type: 'post',
|
||||
data: shippingFormData,
|
||||
success: function (data) {
|
||||
// enable the next:Payment button here
|
||||
$('body').trigger('checkout:enableButton', '.next-step-button button');
|
||||
shippingHelpers.methods.shippingFormResponse(defer, data);
|
||||
},
|
||||
error: function (err) {
|
||||
// enable the next:Payment button here
|
||||
$('body').trigger('checkout:enableButton', '.next-step-button button');
|
||||
if (err.responseJSON && err.responseJSON.redirectUrl) {
|
||||
window.location.href = err.responseJSON.redirectUrl;
|
||||
}
|
||||
// Server error submitting form
|
||||
defer.reject(err.responseJSON);
|
||||
}
|
||||
});
|
||||
}
|
||||
return defer;
|
||||
} else if (stage === 'payment') {
|
||||
//
|
||||
// Submit the Billing Address Form
|
||||
//
|
||||
|
||||
formHelpers.clearPreviousErrors('.payment-form');
|
||||
|
||||
var billingAddressForm = $('#dwfrm_billing .billing-address-block :input').serialize();
|
||||
|
||||
$('body').trigger('checkout:serializeBilling', {
|
||||
form: $('#dwfrm_billing .billing-address-block'),
|
||||
data: billingAddressForm,
|
||||
callback: function (data) {
|
||||
if (data) {
|
||||
billingAddressForm = data;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var contactInfoForm = $('#dwfrm_billing .contact-info-block :input').serialize();
|
||||
|
||||
$('body').trigger('checkout:serializeBilling', {
|
||||
form: $('#dwfrm_billing .contact-info-block'),
|
||||
data: contactInfoForm,
|
||||
callback: function (data) {
|
||||
if (data) {
|
||||
contactInfoForm = data;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var activeTabId = $('.tab-pane.active').attr('id');
|
||||
var paymentInfoSelector = '#dwfrm_billing .' + activeTabId + ' .payment-form-fields :input';
|
||||
var paymentInfoForm = $(paymentInfoSelector).serialize();
|
||||
|
||||
$('body').trigger('checkout:serializeBilling', {
|
||||
form: $(paymentInfoSelector),
|
||||
data: paymentInfoForm,
|
||||
callback: function (data) {
|
||||
if (data) {
|
||||
paymentInfoForm = data;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var paymentForm = billingAddressForm + '&' + contactInfoForm + '&' + paymentInfoForm;
|
||||
|
||||
if ($('.data-checkout-stage').data('customer-type') === 'registered') {
|
||||
// if payment method is credit card
|
||||
if ($('.payment-information').data('payment-method-id') === 'CREDIT_CARD') {
|
||||
if (!($('.payment-information').data('is-new-payment'))) {
|
||||
var cvvCode = $('.saved-payment-instrument.' +
|
||||
'selected-payment .saved-payment-security-code').val();
|
||||
|
||||
if (cvvCode === '') {
|
||||
var cvvElement = $('.saved-payment-instrument.' +
|
||||
'selected-payment ' +
|
||||
'.form-control');
|
||||
cvvElement.addClass('is-invalid');
|
||||
scrollAnimate(cvvElement);
|
||||
defer.reject();
|
||||
return defer;
|
||||
}
|
||||
|
||||
var $savedPaymentInstrument = $('.saved-payment-instrument' +
|
||||
'.selected-payment'
|
||||
);
|
||||
|
||||
paymentForm += '&storedPaymentUUID=' +
|
||||
$savedPaymentInstrument.data('uuid');
|
||||
|
||||
paymentForm += '&securityCode=' + cvvCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
// disable the next:Place Order button here
|
||||
$('body').trigger('checkout:disableButton', '.next-step-button button');
|
||||
|
||||
$.ajax({
|
||||
url: $('#dwfrm_billing').attr('action'),
|
||||
method: 'POST',
|
||||
data: paymentForm,
|
||||
success: function (data) {
|
||||
// enable the next:Place Order button here
|
||||
$('body').trigger('checkout:enableButton', '.next-step-button button');
|
||||
// look for field validation errors
|
||||
if (data.error) {
|
||||
if (data.fieldErrors.length) {
|
||||
data.fieldErrors.forEach(function (error) {
|
||||
if (Object.keys(error).length) {
|
||||
formHelpers.loadFormErrors('.payment-form', error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (data.serverErrors.length) {
|
||||
data.serverErrors.forEach(function (error) {
|
||||
$('.error-message').show();
|
||||
$('.error-message-text').text(error);
|
||||
scrollAnimate($('.error-message'));
|
||||
});
|
||||
}
|
||||
|
||||
if (data.cartError) {
|
||||
window.location.href = data.redirectUrl;
|
||||
}
|
||||
|
||||
defer.reject();
|
||||
} else {
|
||||
//
|
||||
// Populate the Address Summary
|
||||
//
|
||||
$('body').trigger('checkout:updateCheckoutView',
|
||||
{ order: data.order, customer: data.customer });
|
||||
|
||||
if (data.renderedPaymentInstruments) {
|
||||
$('.stored-payments').empty().html(
|
||||
data.renderedPaymentInstruments
|
||||
);
|
||||
}
|
||||
|
||||
if (data.customer.registeredUser
|
||||
&& data.customer.customerPaymentInstruments.length
|
||||
) {
|
||||
$('.cancel-new-payment').removeClass('checkout-hidden');
|
||||
}
|
||||
|
||||
scrollAnimate();
|
||||
defer.resolve(data);
|
||||
}
|
||||
},
|
||||
error: function (err) {
|
||||
// enable the next:Place Order button here
|
||||
$('body').trigger('checkout:enableButton', '.next-step-button button');
|
||||
if (err.responseJSON && err.responseJSON.redirectUrl) {
|
||||
window.location.href = err.responseJSON.redirectUrl;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return defer;
|
||||
} else if (stage === 'placeOrder') {
|
||||
// disable the placeOrder button here
|
||||
$('body').trigger('checkout:disableButton', '.next-step-button button');
|
||||
$.ajax({
|
||||
url: $('.place-order').data('action'),
|
||||
method: 'POST',
|
||||
success: function (data) {
|
||||
// enable the placeOrder button here
|
||||
$('body').trigger('checkout:enableButton', '.next-step-button button');
|
||||
if (data.error) {
|
||||
if (data.cartError) {
|
||||
window.location.href = data.redirectUrl;
|
||||
defer.reject();
|
||||
} else {
|
||||
// go to appropriate stage and display error message
|
||||
defer.reject(data);
|
||||
}
|
||||
} else {
|
||||
var redirect = $('<form>')
|
||||
.appendTo(document.body)
|
||||
.attr({
|
||||
method: 'POST',
|
||||
action: data.continueUrl
|
||||
});
|
||||
|
||||
$('<input>')
|
||||
.appendTo(redirect)
|
||||
.attr({
|
||||
name: 'orderID',
|
||||
value: data.orderID
|
||||
});
|
||||
|
||||
$('<input>')
|
||||
.appendTo(redirect)
|
||||
.attr({
|
||||
name: 'orderToken',
|
||||
value: data.orderToken
|
||||
});
|
||||
|
||||
redirect.submit();
|
||||
defer.resolve(data);
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
// enable the placeOrder button here
|
||||
$('body').trigger('checkout:enableButton', $('.next-step-button button'));
|
||||
}
|
||||
});
|
||||
|
||||
return defer;
|
||||
}
|
||||
var p = $('<div>').promise(); // eslint-disable-line
|
||||
setTimeout(function () {
|
||||
p.done(); // eslint-disable-line
|
||||
}, 500);
|
||||
return p; // eslint-disable-line
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize the checkout stage.
|
||||
*
|
||||
* TODO: update this to allow stage to be set from server?
|
||||
*/
|
||||
initialize: function () {
|
||||
// set the initial state of checkout
|
||||
members.currentStage = checkoutStages
|
||||
.indexOf($('.data-checkout-stage').data('checkout-stage'));
|
||||
$(plugin).attr('data-checkout-stage', checkoutStages[members.currentStage]);
|
||||
|
||||
$('body').on('click', '.submit-customer-login', function (e) {
|
||||
e.preventDefault();
|
||||
members.nextStage();
|
||||
});
|
||||
|
||||
$('body').on('click', '.submit-customer', function (e) {
|
||||
e.preventDefault();
|
||||
members.nextStage();
|
||||
});
|
||||
|
||||
//
|
||||
// Handle Payment option selection
|
||||
//
|
||||
$('input[name$="paymentMethod"]', plugin).on('change', function () {
|
||||
$('.credit-card-form').toggle($(this).val() === 'CREDIT_CARD');
|
||||
});
|
||||
|
||||
//
|
||||
// Handle Next State button click
|
||||
//
|
||||
$(plugin).on('click', '.next-step-button button', function () {
|
||||
members.nextStage();
|
||||
});
|
||||
|
||||
//
|
||||
// Handle Edit buttons on shipping and payment summary cards
|
||||
//
|
||||
$('.customer-summary .edit-button', plugin).on('click', function () {
|
||||
members.gotoStage('customer');
|
||||
});
|
||||
|
||||
$('.shipping-summary .edit-button', plugin).on('click', function () {
|
||||
if (!$('#checkout-main').hasClass('multi-ship')) {
|
||||
$('body').trigger('shipping:selectSingleShipping');
|
||||
}
|
||||
|
||||
members.gotoStage('shipping');
|
||||
});
|
||||
|
||||
$('.payment-summary .edit-button', plugin).on('click', function () {
|
||||
members.gotoStage('payment');
|
||||
});
|
||||
|
||||
//
|
||||
// remember stage (e.g. shipping)
|
||||
//
|
||||
updateUrl(members.currentStage);
|
||||
|
||||
//
|
||||
// Listen for foward/back button press and move to correct checkout-stage
|
||||
//
|
||||
$(window).on('popstate', function (e) {
|
||||
//
|
||||
// Back button when event state less than current state in ordered
|
||||
// checkoutStages array.
|
||||
//
|
||||
if (e.state === null ||
|
||||
checkoutStages.indexOf(e.state) < members.currentStage) {
|
||||
members.handlePrevStage(false);
|
||||
} else if (checkoutStages.indexOf(e.state) > members.currentStage) {
|
||||
// Forward button pressed
|
||||
members.handleNextStage(false);
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Set the form data
|
||||
//
|
||||
plugin.data('formData', formData);
|
||||
},
|
||||
|
||||
/**
|
||||
* The next checkout state step updates the css for showing correct buttons etc...
|
||||
*/
|
||||
nextStage: function () {
|
||||
var promise = members.updateStage();
|
||||
|
||||
promise.done(function () {
|
||||
// Update UI with new stage
|
||||
$('.error-message').hide();
|
||||
members.handleNextStage(true);
|
||||
});
|
||||
|
||||
promise.fail(function (data) {
|
||||
// show errors
|
||||
if (data) {
|
||||
if (data.errorStage) {
|
||||
members.gotoStage(data.errorStage.stage);
|
||||
|
||||
if (data.errorStage.step === 'billingAddress') {
|
||||
var $billingAddressSameAsShipping = $(
|
||||
'input[name$="_shippingAddressUseAsBillingAddress"]'
|
||||
);
|
||||
if ($billingAddressSameAsShipping.is(':checked')) {
|
||||
$billingAddressSameAsShipping.prop('checked', false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data.errorMessage) {
|
||||
$('.error-message').show();
|
||||
$('.error-message-text').text(data.errorMessage);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* The next checkout state step updates the css for showing correct buttons etc...
|
||||
*
|
||||
* @param {boolean} bPushState - boolean when true pushes state using the history api.
|
||||
*/
|
||||
handleNextStage: function (bPushState) {
|
||||
if (members.currentStage < checkoutStages.length - 1) {
|
||||
// move stage forward
|
||||
members.currentStage++;
|
||||
|
||||
//
|
||||
// show new stage in url (e.g.payment)
|
||||
//
|
||||
if (bPushState) {
|
||||
updateUrl(members.currentStage);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the next stage on the DOM
|
||||
$(plugin).attr('data-checkout-stage', checkoutStages[members.currentStage]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Previous State
|
||||
*/
|
||||
handlePrevStage: function () {
|
||||
if (members.currentStage > 0) {
|
||||
// move state back
|
||||
members.currentStage--;
|
||||
updateUrl(members.currentStage);
|
||||
}
|
||||
|
||||
$(plugin).attr('data-checkout-stage', checkoutStages[members.currentStage]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Use window history to go to a checkout stage
|
||||
* @param {string} stageName - the checkout state to goto
|
||||
*/
|
||||
gotoStage: function (stageName) {
|
||||
members.currentStage = checkoutStages.indexOf(stageName);
|
||||
updateUrl(members.currentStage);
|
||||
$(plugin).attr('data-checkout-stage', checkoutStages[members.currentStage]);
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Initialize the checkout
|
||||
//
|
||||
members.initialize();
|
||||
|
||||
return this;
|
||||
};
|
||||
}(jQuery));
|
||||
|
||||
|
||||
var exports = {
|
||||
initialize: function () {
|
||||
$('#checkout-main').checkout();
|
||||
},
|
||||
|
||||
updateCheckoutView: function () {
|
||||
$('body').on('checkout:updateCheckoutView', function (e, data) {
|
||||
if (data.csrfToken) {
|
||||
$("input[name*='csrf_token']").val(data.csrfToken);
|
||||
}
|
||||
customerHelpers.methods.updateCustomerInformation(data.customer, data.order);
|
||||
shippingHelpers.methods.updateMultiShipInformation(data.order);
|
||||
summaryHelpers.updateTotals(data.order.totals);
|
||||
data.order.shipping.forEach(function (shipping) {
|
||||
shippingHelpers.methods.updateShippingInformation(
|
||||
shipping,
|
||||
data.order,
|
||||
data.customer,
|
||||
data.options
|
||||
);
|
||||
});
|
||||
billingHelpers.methods.updateBillingInformation(
|
||||
data.order,
|
||||
data.customer,
|
||||
data.options
|
||||
);
|
||||
billingHelpers.methods.updatePaymentInformation(data.order, data.options);
|
||||
summaryHelpers.updateOrderProductSummaryInformation(data.order, data.options);
|
||||
});
|
||||
},
|
||||
|
||||
disableButton: function () {
|
||||
$('body').on('checkout:disableButton', function (e, button) {
|
||||
$(button).prop('disabled', true);
|
||||
});
|
||||
},
|
||||
|
||||
enableButton: function () {
|
||||
$('body').on('checkout:enableButton', function (e, button) {
|
||||
$(button).prop('disabled', false);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
[customerHelpers, billingHelpers, shippingHelpers, addressHelpers].forEach(function (library) {
|
||||
Object.keys(library).forEach(function (item) {
|
||||
if (typeof library[item] === 'object') {
|
||||
exports[item] = $.extend({}, exports[item], library[item]);
|
||||
} else {
|
||||
exports[item] = library[item];
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = exports;
|
@@ -0,0 +1,143 @@
|
||||
'use strict';
|
||||
|
||||
var formHelpers = require('./formErrors');
|
||||
var scrollAnimate = require('../components/scrollAnimate');
|
||||
var createErrorNotification = require('../components/errorNotification');
|
||||
var GUEST_FORM = '#guest-customer';
|
||||
var REGISTERED_FORM = '#registered-customer';
|
||||
var ERROR_SECTION = '.customer-error';
|
||||
|
||||
/**
|
||||
* @returns {boolean} If guest is active, registered is not visible
|
||||
*/
|
||||
function isGuestFormActive() {
|
||||
return $(REGISTERED_FORM).hasClass('d-none');
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear any previous errors in the customer form.
|
||||
*/
|
||||
function clearErrors() {
|
||||
$(ERROR_SECTION).children().remove();
|
||||
formHelpers.clearPreviousErrors('.customer-information-block');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} customerData - data includes checkout related customer information
|
||||
* @param {Object} orderData - data includes checkout related order information
|
||||
*/
|
||||
function updateCustomerInformation(customerData, orderData) {
|
||||
var $container = $('.customer-summary');
|
||||
var $summaryDetails = $container.find('.summary-details');
|
||||
var email = customerData.profile && customerData.profile.email ? customerData.profile.email : orderData.orderEmail;
|
||||
$summaryDetails.find('.customer-summary-email').text(email);
|
||||
if (customerData.registeredUser) {
|
||||
$container.find('.edit-button').hide();
|
||||
} else {
|
||||
$container.find('.edit-button').show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle response from the server for valid or invalid form fields.
|
||||
* @param {Object} defer - the deferred object which will resolve on success or reject.
|
||||
* @param {Object} data - the response data with the invalid form fields or
|
||||
* valid model data.
|
||||
*/
|
||||
function customerFormResponse(defer, data) {
|
||||
var parentForm = isGuestFormActive() ? GUEST_FORM : REGISTERED_FORM;
|
||||
var formSelector = '.customer-section ' + parentForm;
|
||||
|
||||
// highlight fields with errors
|
||||
if (data.error) {
|
||||
if (data.fieldErrors.length) {
|
||||
data.fieldErrors.forEach(function (error) {
|
||||
if (Object.keys(error).length) {
|
||||
formHelpers.loadFormErrors(formSelector, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (data.customerErrorMessage) {
|
||||
createErrorNotification(ERROR_SECTION, data.customerErrorMessage);
|
||||
}
|
||||
|
||||
if (data.fieldErrors.length || data.customerErrorMessage || (data.serverErrors && data.serverErrors.length)) {
|
||||
defer.reject(data);
|
||||
}
|
||||
|
||||
if (data.cartError) {
|
||||
window.location.href = data.redirectUrl;
|
||||
defer.reject();
|
||||
}
|
||||
} else {
|
||||
// Populate the Address Summary
|
||||
|
||||
$('body').trigger('checkout:updateCheckoutView', {
|
||||
order: data.order,
|
||||
customer: data.customer,
|
||||
csrfToken: data.csrfToken
|
||||
});
|
||||
scrollAnimate($('.shipping-form'));
|
||||
defer.resolve(data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {boolean} registered - wether a registered login block will be used
|
||||
*/
|
||||
function chooseLoginBlock(registered) {
|
||||
$(ERROR_SECTION).find('.alert').remove();
|
||||
$('#password').val('');
|
||||
if (registered) {
|
||||
$(REGISTERED_FORM).removeClass('d-none');
|
||||
$(GUEST_FORM).addClass('d-none');
|
||||
$('#email').val($('#email-guest').val());
|
||||
} else {
|
||||
$(REGISTERED_FORM).addClass('d-none');
|
||||
$(GUEST_FORM).removeClass('d-none');
|
||||
$('#email').val('');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
/**
|
||||
* Listeners for customer form
|
||||
*/
|
||||
initListeners: function () {
|
||||
// 1. password
|
||||
var customerLogin = '.js-login-customer';
|
||||
var cancelLogin = '.js-cancel-login';
|
||||
var registered;
|
||||
if (customerLogin.length !== 0) {
|
||||
$('body').on('click', customerLogin, function (e) {
|
||||
registered = true;
|
||||
e.preventDefault();
|
||||
chooseLoginBlock(registered);
|
||||
});
|
||||
}
|
||||
if (cancelLogin.length !== 0) {
|
||||
$('body').on('click', cancelLogin, function (e) {
|
||||
registered = false;
|
||||
e.preventDefault();
|
||||
chooseLoginBlock(registered);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
clearErrors: clearErrors,
|
||||
updateCustomerInformation: updateCustomerInformation,
|
||||
customerFormResponse: customerFormResponse,
|
||||
isGuestFormActive: isGuestFormActive
|
||||
},
|
||||
|
||||
vars: {
|
||||
GUEST_FORM: GUEST_FORM,
|
||||
REGISTERED_FORM: REGISTERED_FORM
|
||||
}
|
||||
|
||||
};
|
@@ -0,0 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
var scrollAnimate = require('../components/scrollAnimate');
|
||||
|
||||
/**
|
||||
* Display error messages and highlight form fields with errors.
|
||||
* @param {string} parentSelector - the form which contains the fields
|
||||
* @param {Object} fieldErrors - the fields with errors
|
||||
*/
|
||||
function loadFormErrors(parentSelector, fieldErrors) { // eslint-disable-line
|
||||
// Display error messages and highlight form fields with errors.
|
||||
$.each(fieldErrors, function (attr) {
|
||||
$('*[name=' + attr + ']', parentSelector)
|
||||
.addClass('is-invalid')
|
||||
.siblings('.invalid-feedback')
|
||||
.html(fieldErrors[attr]);
|
||||
});
|
||||
// Animate to top of form that has errors
|
||||
scrollAnimate($(parentSelector));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the form errors.
|
||||
* @param {string} parentSelector - the parent form selector.
|
||||
*/
|
||||
function clearPreviousErrors(parentSelector) {
|
||||
$(parentSelector).find('.form-control.is-invalid').removeClass('is-invalid');
|
||||
$('.error-message').hide();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
loadFormErrors: loadFormErrors,
|
||||
clearPreviousErrors: clearPreviousErrors
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,146 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* updates the totals summary
|
||||
* @param {Array} totals - the totals data
|
||||
*/
|
||||
function updateTotals(totals) {
|
||||
$('.shipping-total-cost').text(totals.totalShippingCost);
|
||||
$('.tax-total').text(totals.totalTax);
|
||||
$('.sub-total').text(totals.subTotal);
|
||||
$('.grand-total-sum').text(totals.grandTotal);
|
||||
|
||||
if (totals.orderLevelDiscountTotal.value > 0) {
|
||||
$('.order-discount').removeClass('hide-order-discount');
|
||||
$('.order-discount-total').text('- ' + totals.orderLevelDiscountTotal.formatted);
|
||||
} else {
|
||||
$('.order-discount').addClass('hide-order-discount');
|
||||
}
|
||||
|
||||
if (totals.shippingLevelDiscountTotal.value > 0) {
|
||||
$('.shipping-discount').removeClass('hide-shipping-discount');
|
||||
$('.shipping-discount-total').text('- ' +
|
||||
totals.shippingLevelDiscountTotal.formatted);
|
||||
} else {
|
||||
$('.shipping-discount').addClass('hide-shipping-discount');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* updates the order product shipping summary for an order model
|
||||
* @param {Object} order - the order model
|
||||
*/
|
||||
function updateOrderProductSummaryInformation(order) {
|
||||
var $productSummary = $('<div />');
|
||||
order.shipping.forEach(function (shipping) {
|
||||
shipping.productLineItems.items.forEach(function (lineItem) {
|
||||
var pli = $('[data-product-line-item=' + lineItem.UUID + ']');
|
||||
$productSummary.append(pli);
|
||||
});
|
||||
|
||||
var address = shipping.shippingAddress || {};
|
||||
var selectedMethod = shipping.selectedShippingMethod;
|
||||
|
||||
var nameLine = address.firstName ? address.firstName + ' ' : '';
|
||||
if (address.lastName) nameLine += address.lastName;
|
||||
|
||||
var address1Line = address.address1;
|
||||
var address2Line = address.address2;
|
||||
|
||||
var phoneLine = address.phone;
|
||||
|
||||
var shippingCost = selectedMethod ? selectedMethod.shippingCost : '';
|
||||
var methodNameLine = selectedMethod ? selectedMethod.displayName : '';
|
||||
var methodArrivalTime = selectedMethod && selectedMethod.estimatedArrivalTime
|
||||
? '( ' + selectedMethod.estimatedArrivalTime + ' )'
|
||||
: '';
|
||||
|
||||
var tmpl = $('#pli-shipping-summary-template').clone();
|
||||
|
||||
if (shipping.productLineItems.items && shipping.productLineItems.items.length > 1) {
|
||||
$('h5 > span').text(' - ' + shipping.productLineItems.items.length + ' '
|
||||
+ order.resources.items);
|
||||
} else {
|
||||
$('h5 > span').text('');
|
||||
}
|
||||
|
||||
var stateRequiredAttr = $('#shippingState').attr('required');
|
||||
var isRequired = stateRequiredAttr !== undefined && stateRequiredAttr !== false;
|
||||
var stateExists = (shipping.shippingAddress && shipping.shippingAddress.stateCode)
|
||||
? shipping.shippingAddress.stateCode
|
||||
: false;
|
||||
var stateBoolean = false;
|
||||
if ((isRequired && stateExists) || (!isRequired)) {
|
||||
stateBoolean = true;
|
||||
}
|
||||
|
||||
var shippingForm = $('.multi-shipping input[name="shipmentUUID"][value="' + shipping.UUID + '"]').parent();
|
||||
|
||||
if (shipping.shippingAddress
|
||||
&& shipping.shippingAddress.firstName
|
||||
&& shipping.shippingAddress.address1
|
||||
&& shipping.shippingAddress.city
|
||||
&& stateBoolean
|
||||
&& shipping.shippingAddress.countryCode
|
||||
&& (shipping.shippingAddress.phone || shipping.productLineItems.items[0].fromStoreId)) {
|
||||
$('.ship-to-name', tmpl).text(nameLine);
|
||||
$('.ship-to-address1', tmpl).text(address1Line);
|
||||
$('.ship-to-address2', tmpl).text(address2Line);
|
||||
$('.ship-to-city', tmpl).text(address.city);
|
||||
if (address.stateCode) {
|
||||
$('.ship-to-st', tmpl).text(address.stateCode);
|
||||
}
|
||||
$('.ship-to-zip', tmpl).text(address.postalCode);
|
||||
$('.ship-to-phone', tmpl).text(phoneLine);
|
||||
|
||||
if (!address2Line) {
|
||||
$('.ship-to-address2', tmpl).hide();
|
||||
}
|
||||
|
||||
if (!phoneLine) {
|
||||
$('.ship-to-phone', tmpl).hide();
|
||||
}
|
||||
|
||||
shippingForm.find('.ship-to-message').text('');
|
||||
} else {
|
||||
shippingForm.find('.ship-to-message').text(order.resources.addressIncomplete);
|
||||
}
|
||||
|
||||
if (shipping.isGift) {
|
||||
$('.gift-message-summary', tmpl).text(shipping.giftMessage);
|
||||
} else {
|
||||
$('.gift-summary', tmpl).addClass('d-none');
|
||||
}
|
||||
|
||||
// checking h5 title shipping to or pickup
|
||||
var $shippingAddressLabel = $('.shipping-header-text', tmpl);
|
||||
$('body').trigger('shipping:updateAddressLabelText',
|
||||
{ selectedShippingMethod: selectedMethod, resources: order.resources, shippingAddressLabel: $shippingAddressLabel });
|
||||
|
||||
if (shipping.selectedShippingMethod) {
|
||||
$('.display-name', tmpl).text(methodNameLine);
|
||||
$('.arrival-time', tmpl).text(methodArrivalTime);
|
||||
$('.price', tmpl).text(shippingCost);
|
||||
}
|
||||
|
||||
var $shippingSummary = $('<div class="multi-shipping" data-shipment-summary="'
|
||||
+ shipping.UUID + '" />');
|
||||
$shippingSummary.html(tmpl.html());
|
||||
$productSummary.append($shippingSummary);
|
||||
});
|
||||
|
||||
$('.product-summary-block').html($productSummary.html());
|
||||
|
||||
// Also update the line item prices, as they might have been altered
|
||||
$('.grand-total-price').text(order.totals.subTotal);
|
||||
order.items.items.forEach(function (item) {
|
||||
if (item.priceTotal && item.priceTotal.renderedPrice) {
|
||||
$('.item-total-' + item.UUID).empty().append(item.priceTotal.renderedPrice);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
updateTotals: updateTotals,
|
||||
updateOrderProductSummaryInformation: updateOrderProductSummaryInformation
|
||||
};
|
@@ -0,0 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
var formValidation = require('./components/formValidation');
|
||||
|
||||
$(document).ready(function () {
|
||||
$('form.checkout-registration').submit(function (e) {
|
||||
var form = $(this);
|
||||
e.preventDefault();
|
||||
var url = form.attr('action');
|
||||
form.spinner().start();
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
data: form.serialize(),
|
||||
success: function (data) {
|
||||
form.spinner().stop();
|
||||
if (!data.success) {
|
||||
formValidation(form, data);
|
||||
} else {
|
||||
location.href = data.redirectUrl;
|
||||
}
|
||||
},
|
||||
error: function (err) {
|
||||
if (err.responseJSON.redirectUrl) {
|
||||
window.location.href = err.responseJSON.redirectUrl;
|
||||
}
|
||||
form.spinner().stop();
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
@@ -0,0 +1,45 @@
|
||||
'use strict';
|
||||
|
||||
var Cleave = require('cleave.js').default;
|
||||
|
||||
module.exports = {
|
||||
handleCreditCardNumber: function (cardFieldSelector, cardTypeSelector) {
|
||||
var cleave = new Cleave(cardFieldSelector, {
|
||||
creditCard: true,
|
||||
onCreditCardTypeChanged: function (type) {
|
||||
var creditCardTypes = {
|
||||
visa: 'Visa',
|
||||
mastercard: 'Master Card',
|
||||
amex: 'Amex',
|
||||
discover: 'Discover',
|
||||
unknown: 'Unknown'
|
||||
};
|
||||
|
||||
var cardType = creditCardTypes[Object.keys(creditCardTypes).indexOf(type) > -1
|
||||
? type
|
||||
: 'unknown'];
|
||||
$(cardTypeSelector).val(cardType);
|
||||
$('.card-number-wrapper').attr('data-type', type);
|
||||
if (type === 'visa' || type === 'mastercard' || type === 'discover') {
|
||||
$('#securityCode').attr('maxlength', 3);
|
||||
} else {
|
||||
$('#securityCode').attr('maxlength', 4);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(cardFieldSelector).data('cleave', cleave);
|
||||
},
|
||||
|
||||
serializeData: function (form) {
|
||||
var serializedArray = form.serializeArray();
|
||||
|
||||
serializedArray.forEach(function (item) {
|
||||
if (item.name.indexOf('cardNumber') > -1) {
|
||||
item.value = $('#cardNumber').data('cleave').getRawValue(); // eslint-disable-line
|
||||
}
|
||||
});
|
||||
|
||||
return $.param(serializedArray);
|
||||
}
|
||||
};
|
@@ -0,0 +1,83 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Validate whole form. Requires `this` to be set to form object
|
||||
* @param {jQuery.event} event - Event to be canceled if form is invalid.
|
||||
* @returns {boolean} - Flag to indicate if form is valid
|
||||
*/
|
||||
function validateForm(event) {
|
||||
var valid = true;
|
||||
if (this.checkValidity && !this.checkValidity()) {
|
||||
// safari
|
||||
valid = false;
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
$(this).find('input, select').each(function () {
|
||||
if (!this.validity.valid) {
|
||||
$(this).trigger('invalid', this.validity);
|
||||
}
|
||||
});
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all validation. Should be called every time before revalidating form
|
||||
* @param {element} form - Form to be cleared
|
||||
* @returns {void}
|
||||
*/
|
||||
function clearForm(form) {
|
||||
$(form).find('.form-control.is-invalid').removeClass('is-invalid');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
invalid: function () {
|
||||
$('form input, form select').on('invalid', function (e) {
|
||||
e.preventDefault();
|
||||
this.setCustomValidity('');
|
||||
if (!this.validity.valid) {
|
||||
var validationMessage = this.validationMessage;
|
||||
$(this).addClass('is-invalid');
|
||||
if (this.validity.patternMismatch && $(this).data('pattern-mismatch')) {
|
||||
validationMessage = $(this).data('pattern-mismatch');
|
||||
}
|
||||
if ((this.validity.rangeOverflow || this.validity.rangeUnderflow)
|
||||
&& $(this).data('range-error')) {
|
||||
validationMessage = $(this).data('range-error');
|
||||
}
|
||||
if ((this.validity.tooLong || this.validity.tooShort)
|
||||
&& $(this).data('range-error')) {
|
||||
validationMessage = $(this).data('range-error');
|
||||
}
|
||||
if (this.validity.valueMissing && $(this).data('missing-error')) {
|
||||
validationMessage = $(this).data('missing-error');
|
||||
}
|
||||
$(this).parents('.form-group').find('.invalid-feedback')
|
||||
.text(validationMessage);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
submit: function () {
|
||||
$('form').on('submit', function (e) {
|
||||
return validateForm.call(this, e);
|
||||
});
|
||||
},
|
||||
|
||||
buttonClick: function () {
|
||||
$('form button[type="submit"], form input[type="submit"]').on('click', function () {
|
||||
// clear all errors when trying to submit the form
|
||||
clearForm($(this).parents('form'));
|
||||
});
|
||||
},
|
||||
|
||||
functions: {
|
||||
validateForm: function (form, event) {
|
||||
validateForm.call($(form), event || null);
|
||||
},
|
||||
clearForm: clearForm
|
||||
}
|
||||
};
|
@@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
module.exports = function () {
|
||||
var sizes = ['xs', 'sm', 'md', 'lg', 'xl'];
|
||||
|
||||
sizes.forEach(function (size) {
|
||||
var selector = '.collapsible-' + size + ' .title';
|
||||
$('body').on('click', selector, function (e) {
|
||||
e.preventDefault();
|
||||
$(this).parents('.collapsible-' + size).toggleClass('active');
|
||||
|
||||
if ($(this).parents('.collapsible-' + size).hasClass('active')) {
|
||||
$(this).attr('aria-expanded', true);
|
||||
} else {
|
||||
$(this).attr('aria-expanded', false);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
@@ -0,0 +1,107 @@
|
||||
'use strict';
|
||||
|
||||
var focusHelper = require('../components/focus');
|
||||
|
||||
/**
|
||||
* Renders a modal window that will track the users consenting to accepting site tracking policy
|
||||
*/
|
||||
function showConsentModal() {
|
||||
if (!$('.tracking-consent').data('caonline')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var urlContent = $('.tracking-consent').data('url');
|
||||
var urlAccept = $('.tracking-consent').data('accept');
|
||||
var urlReject = $('.tracking-consent').data('reject');
|
||||
var textYes = $('.tracking-consent').data('accepttext');
|
||||
var textNo = $('.tracking-consent').data('rejecttext');
|
||||
var textHeader = $('.tracking-consent').data('heading');
|
||||
|
||||
var htmlString = '<!-- Modal -->'
|
||||
+ '<div class="modal show" id="consent-tracking" aria-modal="true" role="dialog" style="display: block;">'
|
||||
+ '<div class="modal-dialog">'
|
||||
+ '<!-- Modal content-->'
|
||||
+ '<div class="modal-content">'
|
||||
+ '<div class="modal-header">'
|
||||
+ textHeader
|
||||
+ '</div>'
|
||||
+ '<div class="modal-body"></div>'
|
||||
+ '<div class="modal-footer">'
|
||||
+ '<div class="button-wrapper">'
|
||||
+ '<button class="affirm btn btn-primary" data-url="' + urlAccept + '" autofocus data-dismiss="modal">'
|
||||
+ textYes
|
||||
+ '</button>'
|
||||
+ '<button class="decline btn btn-primary" data-url="' + urlReject + '" data-dismiss="modal" >'
|
||||
+ textNo
|
||||
+ '</button>'
|
||||
+ '</div>'
|
||||
+ '</div>'
|
||||
+ '</div>'
|
||||
+ '</div>'
|
||||
+ '</div>';
|
||||
$.spinner().start();
|
||||
$('body').append(htmlString);
|
||||
|
||||
$.ajax({
|
||||
url: urlContent,
|
||||
type: 'get',
|
||||
dataType: 'html',
|
||||
success: function (response) {
|
||||
$('.modal-body').html(response);
|
||||
$('#consent-tracking').modal('show');
|
||||
},
|
||||
error: function () {
|
||||
$('#consent-tracking').remove();
|
||||
}
|
||||
});
|
||||
|
||||
$('#consent-tracking .button-wrapper button').click(function (e) {
|
||||
e.preventDefault();
|
||||
var url = $(this).data('url');
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'get',
|
||||
dataType: 'json',
|
||||
success: function () {
|
||||
$('#consent-tracking').remove();
|
||||
$.spinner().stop();
|
||||
},
|
||||
error: function () {
|
||||
$('#consent-tracking').remove();
|
||||
$.spinner().stop();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = function () {
|
||||
if ($('.consented').length === 0 && $('.tracking-consent').hasClass('api-true')) {
|
||||
showConsentModal();
|
||||
}
|
||||
|
||||
if ($('.tracking-consent').hasClass('api-true')) {
|
||||
$('.tracking-consent').click(function () {
|
||||
showConsentModal();
|
||||
});
|
||||
}
|
||||
|
||||
$('body').on('shown.bs.modal', '#consent-tracking', function () {
|
||||
$('#consent-tracking').siblings().attr('aria-hidden', 'true');
|
||||
$('#consent-tracking .close').focus();
|
||||
});
|
||||
|
||||
$('body').on('hidden.bs.modal', '#consent-tracking', function () {
|
||||
$('#consent-tracking').siblings().attr('aria-hidden', 'false');
|
||||
});
|
||||
|
||||
$('body').on('keydown', '#consent-tracking', function (e) {
|
||||
var focusParams = {
|
||||
event: e,
|
||||
containerSelector: '#consent-tracking',
|
||||
firstElementSelector: '.affirm',
|
||||
lastElementSelector: '.decline',
|
||||
nextToLastElementSelector: '.affirm'
|
||||
};
|
||||
focusHelper.setTabNextFocus(focusParams);
|
||||
});
|
||||
};
|
@@ -0,0 +1,44 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Get cookie value by cookie name from browser
|
||||
* @param {string} cookieName - name of the cookie
|
||||
* @returns {string} cookie value of the found cookie name
|
||||
*/
|
||||
function getCookie(cookieName) {
|
||||
var name = cookieName + '=';
|
||||
var decodedCookie = decodeURIComponent(document.cookie);
|
||||
var cookieArray = decodedCookie.split(';');
|
||||
for (var i = 0; i < cookieArray.length; i++) {
|
||||
var cookieItem = cookieArray[i];
|
||||
while (cookieItem.charAt(0) === ' ') {
|
||||
cookieItem = cookieItem.substring(1);
|
||||
}
|
||||
if (cookieItem.indexOf(name) === 0) {
|
||||
return cookieItem.substring(name.length, cookieItem.length);
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
module.exports = function () {
|
||||
if ($('.valid-cookie-warning').length > 0) {
|
||||
var previousSessionID = window.localStorage.getItem('previousSid');
|
||||
var currentSessionID = getCookie('sid');
|
||||
if (!previousSessionID && currentSessionID) {
|
||||
// When a user first time visit the home page,
|
||||
// set the previousSessionID to currentSessionID
|
||||
// and Show the cookie alert
|
||||
previousSessionID = currentSessionID;
|
||||
window.localStorage.setItem('previousSid', previousSessionID);
|
||||
$('.cookie-warning-messaging').show();
|
||||
} else if (previousSessionID && previousSessionID === currentSessionID) {
|
||||
// Hide the cookie alert if user is in the same session
|
||||
$('.cookie-warning-messaging').hide();
|
||||
} else {
|
||||
// Clear the previousSessionID from localStorage
|
||||
// when user session is changed or expired
|
||||
window.localStorage.removeItem('previousSid');
|
||||
}
|
||||
}
|
||||
};
|
@@ -0,0 +1,72 @@
|
||||
'use strict';
|
||||
|
||||
var keyboardAccessibility = require('./keyboardAccessibility');
|
||||
|
||||
module.exports = function () {
|
||||
$('.country-selector a').click(function (e) {
|
||||
e.preventDefault();
|
||||
var action = $('.page').data('action');
|
||||
var localeCode = $(this).data('locale');
|
||||
var localeCurrencyCode = $(this).data('currencycode');
|
||||
var queryString = $('.page').data('querystring');
|
||||
var url = $('.country-selector').data('url');
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'get',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
code: localeCode,
|
||||
queryString: queryString,
|
||||
CurrencyCode: localeCurrencyCode,
|
||||
action: action
|
||||
},
|
||||
success: function (response) {
|
||||
$.spinner().stop();
|
||||
if (response && response.redirectUrl) {
|
||||
window.location.href = response.redirectUrl;
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
$.spinner().stop();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
keyboardAccessibility('.navbar-header .country-selector',
|
||||
{
|
||||
40: function ($countryOptions) { // down
|
||||
if ($(this).is(':focus')) {
|
||||
$countryOptions.first().focus();
|
||||
} else {
|
||||
$(':focus').next().focus();
|
||||
}
|
||||
},
|
||||
38: function ($countryOptions) { // up
|
||||
if ($countryOptions.first().is(':focus') || $(this).is(':focus')) {
|
||||
$(this).focus();
|
||||
$(this).removeClass('show');
|
||||
} else {
|
||||
$(':focus').prev().focus();
|
||||
}
|
||||
},
|
||||
27: function () { // escape
|
||||
$(this).focus();
|
||||
$(this).removeClass('show').children('.dropdown-menu').removeClass('show');
|
||||
},
|
||||
9: function () { // tab
|
||||
$(this).removeClass('show').children('.dropdown-menu').removeClass('show');
|
||||
}
|
||||
},
|
||||
function () {
|
||||
if (!($(this).hasClass('show'))) {
|
||||
$(this).addClass('show');
|
||||
}
|
||||
return $(this).find('.dropdown-country-selector').children('a');
|
||||
}
|
||||
);
|
||||
|
||||
$('.navbar-header .country-selector').on('focusin', function () {
|
||||
$(this).addClass('show').children('.dropdown-menu').addClass('show');
|
||||
});
|
||||
};
|
@@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function (element, message) {
|
||||
var errorHtml = '<div class="alert alert-danger alert-dismissible ' +
|
||||
'fade show" role="alert">' +
|
||||
'<button type="button" class="close" data-dismiss="alert" aria-label="Close">' +
|
||||
'<span aria-hidden="true">×</span>' +
|
||||
'</button>' + message + '</div>';
|
||||
|
||||
$(element).append(errorHtml);
|
||||
};
|
@@ -0,0 +1,35 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
setTabNextFocus: function (focusParams) {
|
||||
var KEYCODE_TAB = 9;
|
||||
var isTabPressed = (focusParams.event.key === 'Tab' || focusParams.event.keyCode === KEYCODE_TAB);
|
||||
|
||||
if (!isTabPressed) {
|
||||
return;
|
||||
}
|
||||
|
||||
var firstFocusableEl = $(focusParams.containerSelector + ' ' + focusParams.firstElementSelector);
|
||||
var lastFocusableEl = $(focusParams.containerSelector + ' ' + focusParams.lastElementSelector);
|
||||
|
||||
if ($(focusParams.containerSelector + ' ' + focusParams.lastElementSelector).is(':disabled')) {
|
||||
lastFocusableEl = $(focusParams.containerSelector + ' ' + focusParams.nextToLastElementSelector);
|
||||
if ($('.product-quickview.product-set').length > 0) {
|
||||
var linkElements = $(focusParams.containerSelector + ' a#fa-link.share-icons');
|
||||
lastFocusableEl = linkElements[linkElements.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
if (focusParams.event.shiftKey) /* shift + tab */ {
|
||||
if ($(':focus').is(firstFocusableEl)) {
|
||||
lastFocusableEl.focus();
|
||||
focusParams.event.preventDefault();
|
||||
}
|
||||
} else /* tab */ {
|
||||
if ($(':focus').is(lastFocusableEl)) { // eslint-disable-line
|
||||
firstFocusableEl.focus();
|
||||
focusParams.event.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
@@ -0,0 +1,60 @@
|
||||
'use strict';
|
||||
|
||||
var scrollAnimate = require('./scrollAnimate');
|
||||
|
||||
/**
|
||||
* appends params to a url
|
||||
* @param {string} data - data returned from the server's ajax call
|
||||
* @param {Object} button - button that was clicked for email sign-up
|
||||
*/
|
||||
function displayMessage(data, button) {
|
||||
$.spinner().stop();
|
||||
var status;
|
||||
if (data.success) {
|
||||
status = 'alert-success';
|
||||
} else {
|
||||
status = 'alert-danger';
|
||||
}
|
||||
|
||||
if ($('.email-signup-message').length === 0) {
|
||||
$('body').append(
|
||||
'<div class="email-signup-message"></div>'
|
||||
);
|
||||
}
|
||||
$('.email-signup-message')
|
||||
.append('<div class="email-signup-alert text-center ' + status + '">' + data.msg + '</div>');
|
||||
|
||||
setTimeout(function () {
|
||||
$('.email-signup-message').remove();
|
||||
button.removeAttr('disabled');
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
module.exports = function () {
|
||||
$('.back-to-top').click(function () {
|
||||
scrollAnimate();
|
||||
});
|
||||
|
||||
$('.subscribe-email').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
var url = $(this).data('href');
|
||||
var button = $(this);
|
||||
var emailId = $('input[name=hpEmailSignUp]').val();
|
||||
$.spinner().start();
|
||||
$(this).attr('disabled', true);
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
emailId: emailId
|
||||
},
|
||||
success: function (data) {
|
||||
displayMessage(data, button);
|
||||
},
|
||||
error: function (err) {
|
||||
displayMessage(err, button);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
@@ -0,0 +1,43 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Remove all validation. Should be called every time before revalidating form
|
||||
* @param {element} form - Form to be cleared
|
||||
* @returns {void}
|
||||
*/
|
||||
function clearFormErrors(form) {
|
||||
$(form).find('.form-control.is-invalid').removeClass('is-invalid');
|
||||
}
|
||||
|
||||
module.exports = function (formElement, payload) {
|
||||
// clear form validation first
|
||||
clearFormErrors(formElement);
|
||||
$('.alert', formElement).remove();
|
||||
|
||||
if (typeof payload === 'object' && payload.fields) {
|
||||
Object.keys(payload.fields).forEach(function (key) {
|
||||
if (payload.fields[key]) {
|
||||
var feedbackElement = $(formElement).find('[name="' + key + '"]')
|
||||
.parent()
|
||||
.children('.invalid-feedback');
|
||||
|
||||
if (feedbackElement.length > 0) {
|
||||
if (Array.isArray(payload[key])) {
|
||||
feedbackElement.html(payload.fields[key].join('<br/>'));
|
||||
} else {
|
||||
feedbackElement.html(payload.fields[key]);
|
||||
}
|
||||
feedbackElement.siblings('.form-control').addClass('is-invalid');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (payload && payload.error) {
|
||||
var form = $(formElement).prop('tagName') === 'FORM'
|
||||
? $(formElement)
|
||||
: $(formElement).parents('form');
|
||||
|
||||
form.prepend('<div class="alert alert-danger" role="alert">'
|
||||
+ payload.error.join('<br/>') + '</div>');
|
||||
}
|
||||
};
|
@@ -0,0 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function (selector, keyFunctions, preFunction) {
|
||||
$(selector).on('keydown', function (e) {
|
||||
var key = e.which;
|
||||
var supportedKeyCodes = [37, 38, 39, 40, 27];
|
||||
if (supportedKeyCodes.indexOf(key) >= 0) {
|
||||
e.preventDefault();
|
||||
}
|
||||
var returnedScope = preFunction.call(this);
|
||||
if (keyFunctions[key]) {
|
||||
keyFunctions[key].call(this, returnedScope);
|
||||
}
|
||||
});
|
||||
};
|
@@ -0,0 +1,252 @@
|
||||
'use strict';
|
||||
|
||||
var keyboardAccessibility = require('./keyboardAccessibility');
|
||||
|
||||
var clearSelection = function (element) {
|
||||
$(element).closest('.dropdown').children('.dropdown-menu').children('.top-category')
|
||||
.detach();
|
||||
$(element).closest('.dropdown.show').children('.nav-link').attr('aria-expanded', 'false');
|
||||
$(element).closest('.dropdown.show').children('.dropdown-menu').attr('aria-hidden', 'true');
|
||||
$(element).closest('.dropdown.show').removeClass('show');
|
||||
$('div.menu-group > ul.nav.navbar-nav > li.nav-item > a').attr('aria-hidden', 'false');
|
||||
$(element).closest('li').detach();
|
||||
};
|
||||
|
||||
module.exports = function () {
|
||||
var isDesktop = function (element) {
|
||||
return $(element).parents('.menu-toggleable-left').css('position') !== 'fixed';
|
||||
};
|
||||
|
||||
var headerBannerStatus = window.sessionStorage.getItem('hide_header_banner');
|
||||
$('.header-banner .close').on('click', function () {
|
||||
$('.header-banner').addClass('d-none');
|
||||
window.sessionStorage.setItem('hide_header_banner', '1');
|
||||
});
|
||||
|
||||
if (!headerBannerStatus || headerBannerStatus < 0) {
|
||||
$('.header-banner').removeClass('d-none');
|
||||
}
|
||||
|
||||
keyboardAccessibility('.main-menu .nav-link, .main-menu .dropdown-link',
|
||||
{
|
||||
40: function (menuItem) { // down
|
||||
if (menuItem.hasClass('nav-item')) { // top level
|
||||
$('.navbar-nav .show').removeClass('show')
|
||||
.children('.dropdown-menu')
|
||||
.removeClass('show');
|
||||
menuItem.addClass('show').children('.dropdown-menu').addClass('show');
|
||||
menuItem.find('ul > li > a')
|
||||
.first()
|
||||
.focus();
|
||||
} else {
|
||||
menuItem.removeClass('show').children('.dropdown-menu').removeClass('show');
|
||||
if (!(menuItem.next().length > 0)) { // if this is the last menuItem
|
||||
menuItem.parent().parent().find('li > a') // set focus to the first menuitem
|
||||
.first()
|
||||
.focus();
|
||||
} else {
|
||||
menuItem.next().children().first().focus();
|
||||
}
|
||||
}
|
||||
},
|
||||
39: function (menuItem) { // right
|
||||
if (menuItem.hasClass('nav-item')) { // top level
|
||||
menuItem.removeClass('show').children('.dropdown-menu').removeClass('show');
|
||||
$(this).attr('aria-expanded', 'false');
|
||||
menuItem.next().children().first().focus();
|
||||
} else if (menuItem.hasClass('dropdown')) {
|
||||
menuItem.addClass('show').children('.dropdown-menu').addClass('show');
|
||||
$(this).attr('aria-expanded', 'true');
|
||||
menuItem.find('ul > li > a')
|
||||
.first()
|
||||
.focus();
|
||||
}
|
||||
},
|
||||
38: function (menuItem) { // up
|
||||
if (menuItem.hasClass('nav-item')) { // top level
|
||||
menuItem.removeClass('show').children('.dropdown-menu').removeClass('show');
|
||||
} else if (menuItem.prev().length === 0) { // first menuItem
|
||||
menuItem.parent().parent().removeClass('show')
|
||||
.children('.nav-link')
|
||||
.attr('aria-expanded', 'false');
|
||||
menuItem.parent().children().last().children() // set the focus to the last menuItem
|
||||
.first()
|
||||
.focus();
|
||||
} else {
|
||||
menuItem.prev().children().first().focus();
|
||||
}
|
||||
},
|
||||
37: function (menuItem) { // left
|
||||
if (menuItem.hasClass('nav-item')) { // top level
|
||||
menuItem.removeClass('show').children('.dropdown-menu').removeClass('show');
|
||||
$(this).attr('aria-expanded', 'false');
|
||||
menuItem.prev().children().first().focus();
|
||||
} else {
|
||||
menuItem.closest('.show').removeClass('show')
|
||||
.closest('li.show').removeClass('show')
|
||||
.children()
|
||||
.first()
|
||||
.focus()
|
||||
.attr('aria-expanded', 'false');
|
||||
}
|
||||
},
|
||||
27: function (menuItem) { // escape
|
||||
var parentMenu = menuItem.hasClass('show')
|
||||
? menuItem
|
||||
: menuItem.closest('li.show');
|
||||
parentMenu.children('.show').removeClass('show');
|
||||
parentMenu.removeClass('show').children('.nav-link')
|
||||
.attr('aria-expanded', 'false');
|
||||
parentMenu.children().first().focus();
|
||||
}
|
||||
},
|
||||
function () {
|
||||
return $(this).parent();
|
||||
}
|
||||
);
|
||||
|
||||
$('.dropdown:not(.disabled) [data-toggle="dropdown"]')
|
||||
.on('click', function (e) {
|
||||
if (!isDesktop(this)) {
|
||||
$('.modal-background').show();
|
||||
// copy parent element into current UL
|
||||
var li = $('<li class="dropdown-item top-category" role="button"></li>');
|
||||
var link = $(this).clone().removeClass('dropdown-toggle')
|
||||
.removeAttr('data-toggle')
|
||||
.removeAttr('aria-expanded')
|
||||
.attr('aria-haspopup', 'false');
|
||||
li.append(link);
|
||||
var closeMenu = $('<li class="nav-menu"></li>');
|
||||
closeMenu.append($('.close-menu').first().clone());
|
||||
$(this).parent().children('.dropdown-menu')
|
||||
.prepend(li)
|
||||
.prepend(closeMenu)
|
||||
.attr('aria-hidden', 'false');
|
||||
// copy navigation menu into view
|
||||
$(this).parent().addClass('show');
|
||||
$(this).attr('aria-expanded', 'true');
|
||||
$(link).focus();
|
||||
$('div.menu-group > ul.nav.navbar-nav > li.nav-item > a').attr('aria-hidden', 'true');
|
||||
e.preventDefault();
|
||||
}
|
||||
})
|
||||
.on('mouseenter', function () {
|
||||
if (isDesktop(this)) {
|
||||
var eventElement = this;
|
||||
$('.navbar-nav > li').each(function () {
|
||||
if (!$.contains(this, eventElement)) {
|
||||
$(this).find('.show').each(function () {
|
||||
clearSelection(this);
|
||||
});
|
||||
if ($(this).hasClass('show')) {
|
||||
$(this).removeClass('show');
|
||||
$(this).children('ul.dropdown-menu').removeClass('show');
|
||||
$(this).children('.nav-link').attr('aria-expanded', 'false');
|
||||
}
|
||||
}
|
||||
});
|
||||
// need to close all the dropdowns that are not direct parent of current dropdown
|
||||
$(this).parent().addClass('show');
|
||||
$(this).siblings('.dropdown-menu').addClass('show');
|
||||
$(this).attr('aria-expanded', 'true');
|
||||
}
|
||||
})
|
||||
.parent()
|
||||
.on('mouseleave', function () {
|
||||
if (isDesktop(this)) {
|
||||
$(this).removeClass('show');
|
||||
$(this).children('.dropdown-menu').removeClass('show');
|
||||
$(this).children('.nav-link').attr('aria-expanded', 'false');
|
||||
}
|
||||
});
|
||||
|
||||
$('.navbar>.close-menu>.close-button').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
$('.menu-toggleable-left').removeClass('in');
|
||||
$('.modal-background').hide();
|
||||
|
||||
$('.navbar-toggler').focus();
|
||||
|
||||
$('.main-menu').attr('aria-hidden', 'true');
|
||||
$('.main-menu').siblings().attr('aria-hidden', 'false');
|
||||
$('header').siblings().attr('aria-hidden', 'false');
|
||||
});
|
||||
|
||||
$('.navbar-nav').on('click', '.back', function (e) {
|
||||
e.preventDefault();
|
||||
clearSelection(this);
|
||||
});
|
||||
|
||||
$('.navbar-nav').on('click', '.close-button', function (e) {
|
||||
e.preventDefault();
|
||||
$('.navbar-nav').find('.top-category').detach();
|
||||
$('.navbar-nav').find('.nav-menu').detach();
|
||||
$('.navbar-nav').find('.show').removeClass('show');
|
||||
$('.menu-toggleable-left').removeClass('in');
|
||||
|
||||
$('.main-menu').siblings().attr('aria-hidden', 'false');
|
||||
$('header').siblings().attr('aria-hidden', 'false');
|
||||
|
||||
$('.modal-background').hide();
|
||||
});
|
||||
|
||||
$('.navbar-toggler').click(function (e) {
|
||||
e.preventDefault();
|
||||
$('.main-menu').toggleClass('in');
|
||||
$('.modal-background').show();
|
||||
|
||||
$('.main-menu').removeClass('d-none');
|
||||
$('.main-menu').attr('aria-hidden', 'false');
|
||||
$('.main-menu').siblings().attr('aria-hidden', 'true');
|
||||
$('header').siblings().attr('aria-hidden', 'true');
|
||||
|
||||
$('.main-menu .nav.navbar-nav .nav-link').first().focus();
|
||||
});
|
||||
|
||||
keyboardAccessibility('.navbar-header .user',
|
||||
{
|
||||
40: function ($popover) { // down
|
||||
if ($popover.children('a').first().is(':focus')) {
|
||||
$popover.next().children().first().focus();
|
||||
} else {
|
||||
$popover.children('a').first().focus();
|
||||
}
|
||||
},
|
||||
38: function ($popover) { // up
|
||||
if ($popover.children('a').first().is(':focus')) {
|
||||
$(this).focus();
|
||||
$popover.removeClass('show');
|
||||
} else {
|
||||
$popover.children('a').first().focus();
|
||||
}
|
||||
},
|
||||
27: function () { // escape
|
||||
$('.navbar-header .user .popover').removeClass('show');
|
||||
$('.user').attr('aria-expanded', 'false');
|
||||
},
|
||||
9: function () { // tab
|
||||
$('.navbar-header .user .popover').removeClass('show');
|
||||
$('.user').attr('aria-expanded', 'false');
|
||||
}
|
||||
},
|
||||
function () {
|
||||
var $popover = $('.user .popover li.nav-item');
|
||||
return $popover;
|
||||
}
|
||||
);
|
||||
|
||||
$('.navbar-header .user').on('mouseenter focusin', function () {
|
||||
if ($('.navbar-header .user .popover').length > 0) {
|
||||
$('.navbar-header .user .popover').addClass('show');
|
||||
$('.user').attr('aria-expanded', 'true');
|
||||
}
|
||||
});
|
||||
|
||||
$('.navbar-header .user').on('mouseleave', function () {
|
||||
$('.navbar-header .user .popover').removeClass('show');
|
||||
$('.user').attr('aria-expanded', 'false');
|
||||
});
|
||||
$('body').on('click', '#myaccount', function () {
|
||||
event.preventDefault();
|
||||
});
|
||||
};
|
@@ -0,0 +1,68 @@
|
||||
'use strict';
|
||||
|
||||
var cart = require('../cart/cart');
|
||||
|
||||
var updateMiniCart = true;
|
||||
|
||||
module.exports = function () {
|
||||
cart();
|
||||
|
||||
$('.minicart').on('count:update', function (event, count) {
|
||||
if (count && $.isNumeric(count.quantityTotal)) {
|
||||
$('.minicart .minicart-quantity').text(count.quantityTotal);
|
||||
$('.minicart .minicart-link').attr({
|
||||
'aria-label': count.minicartCountOfItems,
|
||||
title: count.minicartCountOfItems
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('.minicart').on('mouseenter focusin touchstart', function () {
|
||||
if ($('.search:visible').length === 0) {
|
||||
return;
|
||||
}
|
||||
var url = $('.minicart').data('action-url');
|
||||
var count = parseInt($('.minicart .minicart-quantity').text(), 10);
|
||||
|
||||
if (count !== 0 && $('.minicart .popover.show').length === 0) {
|
||||
if (!updateMiniCart) {
|
||||
$('.minicart .popover').addClass('show');
|
||||
return;
|
||||
}
|
||||
|
||||
$('.minicart .popover').addClass('show');
|
||||
$('.minicart .popover').spinner().start();
|
||||
$.get(url, function (data) {
|
||||
$('.minicart .popover').empty();
|
||||
$('.minicart .popover').append(data);
|
||||
updateMiniCart = false;
|
||||
$.spinner().stop();
|
||||
});
|
||||
}
|
||||
});
|
||||
$('body').on('touchstart click', function (e) {
|
||||
if ($('.minicart').has(e.target).length <= 0) {
|
||||
$('.minicart .popover').removeClass('show');
|
||||
}
|
||||
});
|
||||
$('.minicart').on('mouseleave focusout', function (event) {
|
||||
if ((event.type === 'focusout' && $('.minicart').has(event.target).length > 0)
|
||||
|| (event.type === 'mouseleave' && $(event.target).is('.minicart .quantity'))
|
||||
|| $('body').hasClass('modal-open')) {
|
||||
event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
$('.minicart .popover').removeClass('show');
|
||||
});
|
||||
$('body').on('change', '.minicart .quantity', function () {
|
||||
if ($(this).parents('.bonus-product-line-item').length && $('.cart-page').length) {
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
$('body').on('product:afterAddToCart', function () {
|
||||
updateMiniCart = true;
|
||||
});
|
||||
$('body').on('cart:update', function () {
|
||||
updateMiniCart = true;
|
||||
});
|
||||
};
|
@@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function (element) {
|
||||
var position = element && element.length ? element.offset().top : 0;
|
||||
$('html, body').animate({
|
||||
scrollTop: position
|
||||
}, 500);
|
||||
if (!element) {
|
||||
$('.logo-home').focus();
|
||||
}
|
||||
};
|
@@ -0,0 +1,269 @@
|
||||
'use strict';
|
||||
|
||||
var debounce = require('lodash/debounce');
|
||||
var endpoint = $('.suggestions-wrapper').data('url');
|
||||
var minChars = 1;
|
||||
var UP_KEY = 38;
|
||||
var DOWN_KEY = 40;
|
||||
var DIRECTION_DOWN = 1;
|
||||
var DIRECTION_UP = -1;
|
||||
|
||||
/**
|
||||
* Retrieves Suggestions element relative to scope
|
||||
*
|
||||
* @param {Object} scope - Search input field DOM element
|
||||
* @return {JQuery} - .suggestions-wrapper element
|
||||
*/
|
||||
function getSuggestionsWrapper(scope) {
|
||||
return $(scope).siblings('.suggestions-wrapper');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether DOM element is inside the .search-mobile class
|
||||
*
|
||||
* @param {Object} scope - DOM element, usually the input.search-field element
|
||||
* @return {boolean} - Whether DOM element is inside div.search-mobile
|
||||
*/
|
||||
function isMobileSearch(scope) {
|
||||
return !!$(scope).closest('.search-mobile').length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove modal classes needed for mobile suggestions
|
||||
*
|
||||
*/
|
||||
function clearModals() {
|
||||
$('body').removeClass('modal-open');
|
||||
$('header').siblings().attr('aria-hidden', 'false');
|
||||
$('.suggestions').removeClass('modal');
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply modal classes needed for mobile suggestions
|
||||
*
|
||||
* @param {Object} scope - Search input field DOM element
|
||||
*/
|
||||
function applyModals(scope) {
|
||||
if (isMobileSearch(scope)) {
|
||||
$('body').addClass('modal-open');
|
||||
$('header').siblings().attr('aria-hidden', 'true');
|
||||
getSuggestionsWrapper(scope).find('.suggestions').addClass('modal');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tear down Suggestions panel
|
||||
*/
|
||||
function tearDownSuggestions() {
|
||||
$('input.search-field').val('');
|
||||
clearModals();
|
||||
$('.search-mobile .suggestions').unbind('scroll');
|
||||
$('.suggestions-wrapper').empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle search field icon from search to close and vice-versa
|
||||
*
|
||||
* @param {string} action - Action to toggle to
|
||||
*/
|
||||
function toggleSuggestionsIcon(action) {
|
||||
var mobileSearchIcon = '.search-mobile button.';
|
||||
var iconSearch = 'fa-search';
|
||||
var iconSearchClose = 'fa-close';
|
||||
|
||||
if (action === 'close') {
|
||||
$(mobileSearchIcon + iconSearch).removeClass(iconSearch).addClass(iconSearchClose).attr('type', 'button');
|
||||
} else {
|
||||
$(mobileSearchIcon + iconSearchClose).removeClass(iconSearchClose).addClass(iconSearch).attr('type', 'submit');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the "More Content Below" icon should be displayed
|
||||
*
|
||||
* @param {Object} scope - DOM element, usually the input.search-field element
|
||||
*/
|
||||
function handleMoreContentBelowIcon(scope) {
|
||||
if (($(scope).scrollTop() + $(scope).innerHeight()) >= $(scope)[0].scrollHeight) {
|
||||
$('.more-below').fadeOut();
|
||||
} else {
|
||||
$('.more-below').fadeIn();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Positions Suggestions panel on page
|
||||
*
|
||||
* @param {Object} scope - DOM element, usually the input.search-field element
|
||||
*/
|
||||
function positionSuggestions(scope) {
|
||||
var outerHeight;
|
||||
var $scope;
|
||||
var $suggestions;
|
||||
var top;
|
||||
|
||||
if (isMobileSearch(scope)) {
|
||||
$scope = $(scope);
|
||||
top = $scope.offset().top;
|
||||
outerHeight = $scope.outerHeight();
|
||||
$suggestions = getSuggestionsWrapper(scope).find('.suggestions');
|
||||
$suggestions.css('top', top + outerHeight);
|
||||
|
||||
handleMoreContentBelowIcon(scope);
|
||||
|
||||
// Unfortunately, we have to bind this dynamically, as the live scroll event was not
|
||||
// properly detecting dynamic suggestions element's scroll event
|
||||
$suggestions.scroll(function () {
|
||||
handleMoreContentBelowIcon(this);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process Ajax response for SearchServices-GetSuggestions
|
||||
*
|
||||
* @param {Object|string} response - Empty object literal if null response or string with rendered
|
||||
* suggestions template contents
|
||||
*/
|
||||
function processResponse(response) {
|
||||
var $suggestionsWrapper = getSuggestionsWrapper(this).empty();
|
||||
|
||||
$.spinner().stop();
|
||||
|
||||
if (typeof (response) !== 'object') {
|
||||
$suggestionsWrapper.append(response).show();
|
||||
$(this).siblings('.reset-button').addClass('d-sm-block');
|
||||
positionSuggestions(this);
|
||||
|
||||
if (isMobileSearch(this)) {
|
||||
toggleSuggestionsIcon('close');
|
||||
applyModals(this);
|
||||
}
|
||||
|
||||
// Trigger screen reader by setting aria-describedby with the new suggestion message.
|
||||
var suggestionsList = $('.suggestions .item');
|
||||
if ($(suggestionsList).length) {
|
||||
$('input.search-field').attr('aria-describedby', 'search-result-count');
|
||||
} else {
|
||||
$('input.search-field').removeAttr('aria-describedby');
|
||||
}
|
||||
} else {
|
||||
$suggestionsWrapper.hide();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve suggestions
|
||||
*
|
||||
* @param {Object} scope - Search field DOM element
|
||||
*/
|
||||
function getSuggestions(scope) {
|
||||
if ($(scope).val().length >= minChars) {
|
||||
$.spinner().start();
|
||||
$.ajax({
|
||||
context: scope,
|
||||
url: endpoint + encodeURIComponent($(scope).val()),
|
||||
method: 'GET',
|
||||
success: processResponse,
|
||||
error: function () {
|
||||
$.spinner().stop();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
toggleSuggestionsIcon('search');
|
||||
$(scope).siblings('.reset-button').removeClass('d-sm-block');
|
||||
clearModals();
|
||||
getSuggestionsWrapper(scope).empty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Search Suggestion Keyboard Arrow Keys
|
||||
*
|
||||
* @param {Integer} direction takes positive or negative number constant, DIRECTION_UP (-1) or DIRECTION_DOWN (+1)
|
||||
*/
|
||||
function handleArrow(direction) {
|
||||
// get all li elements in the suggestions list
|
||||
var suggestionsList = $('.suggestions .item');
|
||||
if (suggestionsList.filter('.selected').length === 0) {
|
||||
suggestionsList.first().addClass('selected');
|
||||
$('input.search-field').each(function () {
|
||||
$(this).attr('aria-activedescendant', suggestionsList.first()[0].id);
|
||||
});
|
||||
} else {
|
||||
suggestionsList.each(function (index) {
|
||||
var idx = index + direction;
|
||||
if ($(this).hasClass('selected')) {
|
||||
$(this).removeClass('selected');
|
||||
$(this).removeAttr('aria-selected');
|
||||
if (suggestionsList.eq(idx).length !== 0) {
|
||||
suggestionsList.eq(idx).addClass('selected');
|
||||
suggestionsList.eq(idx).attr('aria-selected', true);
|
||||
$(this).removeProp('aria-selected');
|
||||
$('input.search-field').each(function () {
|
||||
$(this).attr('aria-activedescendant', suggestionsList.eq(idx)[0].id);
|
||||
});
|
||||
} else {
|
||||
suggestionsList.first().addClass('selected');
|
||||
suggestionsList.first().attr('aria-selected', true);
|
||||
$('input.search-field').each(function () {
|
||||
$(this).attr('aria-activedescendant', suggestionsList.first()[0].id);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function () {
|
||||
$('form[name="simpleSearch"]').submit(function (e) {
|
||||
var suggestionsList = $('.suggestions .item');
|
||||
if (suggestionsList.filter('.selected').length !== 0) {
|
||||
e.preventDefault();
|
||||
suggestionsList.filter('.selected').find('a')[0].click();
|
||||
}
|
||||
});
|
||||
|
||||
$('input.search-field').each(function () {
|
||||
/**
|
||||
* Use debounce to avoid making an Ajax call on every single key press by waiting a few
|
||||
* hundred milliseconds before making the request. Without debounce, the user sees the
|
||||
* browser blink with every key press.
|
||||
*/
|
||||
var debounceSuggestions = debounce(getSuggestions, 300);
|
||||
$(this).on('keyup focus', function (e) {
|
||||
// Capture Down/Up Arrow Key Events
|
||||
switch (e.which) {
|
||||
case DOWN_KEY:
|
||||
handleArrow(DIRECTION_DOWN);
|
||||
e.preventDefault(); // prevent moving the cursor
|
||||
break;
|
||||
case UP_KEY:
|
||||
handleArrow(DIRECTION_UP);
|
||||
e.preventDefault(); // prevent moving the cursor
|
||||
break;
|
||||
default:
|
||||
debounceSuggestions(this, e);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('body').on('click', function (e) {
|
||||
if (!$('.suggestions').has(e.target).length && !$(e.target).hasClass('search-field')) {
|
||||
$('.suggestions').hide();
|
||||
}
|
||||
});
|
||||
|
||||
$('body').on('click touchend', '.search-mobile button.fa-close', function (e) {
|
||||
e.preventDefault();
|
||||
$('.suggestions').hide();
|
||||
toggleSuggestionsIcon('search');
|
||||
tearDownSuggestions();
|
||||
});
|
||||
|
||||
$('.site-search .reset-button').on('click', function () {
|
||||
$(this).removeClass('d-sm-block');
|
||||
});
|
||||
};
|
@@ -0,0 +1,75 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Show a spinner inside a given element
|
||||
* @param {element} $target - Element to block by the veil and spinner.
|
||||
* Pass body to block the whole page.
|
||||
*/
|
||||
function addSpinner($target) {
|
||||
var $veil = $('<div class="veil"><div class="underlay"></div></div>');
|
||||
$veil.append('<div class="spinner"><div class="dot1"></div><div class="dot2"></div></div>');
|
||||
if ($target.get(0).tagName === 'IMG') {
|
||||
$target.after($veil);
|
||||
$veil.css({ width: $target.width(), height: $target.height() });
|
||||
if ($target.parent().css('position') === 'static') {
|
||||
$target.parent().css('position', 'relative');
|
||||
}
|
||||
} else {
|
||||
$target.append($veil);
|
||||
if ($target.css('position') === 'static') {
|
||||
$target.parent().css('position', 'relative');
|
||||
$target.parent().addClass('veiled');
|
||||
}
|
||||
if ($target.get(0).tagName === 'BODY') {
|
||||
$veil.find('.spinner').css('position', 'fixed');
|
||||
}
|
||||
}
|
||||
$veil.click(function (e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove existing spinner
|
||||
* @param {element} $veil - jQuery pointer to the veil element
|
||||
*/
|
||||
function removeSpinner($veil) {
|
||||
if ($veil.parent().hasClass('veiled')) {
|
||||
$veil.parent().css('position', '');
|
||||
$veil.parent().removeClass('veiled');
|
||||
}
|
||||
$veil.off('click');
|
||||
$veil.remove();
|
||||
}
|
||||
|
||||
// element level spinner:
|
||||
$.fn.spinner = function () {
|
||||
var $element = $(this);
|
||||
var Fn = function () {
|
||||
this.start = function () {
|
||||
if ($element.length) {
|
||||
addSpinner($element);
|
||||
}
|
||||
};
|
||||
this.stop = function () {
|
||||
if ($element.length) {
|
||||
var $veil = $('.veil');
|
||||
removeSpinner($veil);
|
||||
}
|
||||
};
|
||||
};
|
||||
return new Fn();
|
||||
};
|
||||
|
||||
// page-level spinner:
|
||||
$.spinner = function () {
|
||||
var Fn = function () {
|
||||
this.start = function () {
|
||||
addSpinner($('body'));
|
||||
};
|
||||
this.stop = function () {
|
||||
removeSpinner($('.veil'));
|
||||
};
|
||||
};
|
||||
return new Fn();
|
||||
};
|
@@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function () {
|
||||
$('.info-icon').on('mouseenter focusin', function () {
|
||||
$(this).find('.tooltip').removeClass('d-none');
|
||||
});
|
||||
|
||||
$('.info-icon').on('mouseleave focusout', function () {
|
||||
$(this).find('.tooltip').addClass('d-none');
|
||||
});
|
||||
};
|
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var processInclude = require('./util');
|
||||
|
||||
$(document).ready(function () {
|
||||
processInclude(require('./contactUs/contactUs'));
|
||||
});
|
@@ -0,0 +1,58 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Display the returned message.
|
||||
* @param {string} data - data returned from the server's ajax call
|
||||
* @param {Object} button - button that was clicked for contact us sign-up
|
||||
*/
|
||||
function displayMessage(data, button) {
|
||||
$.spinner().stop();
|
||||
var status;
|
||||
if (data.success) {
|
||||
status = 'alert-success';
|
||||
} else {
|
||||
status = 'alert-danger';
|
||||
}
|
||||
|
||||
if ($('.contact-us-signup-message').length === 0) {
|
||||
$('body').append(
|
||||
'<div class="contact-us-signup-message"></div>'
|
||||
);
|
||||
}
|
||||
$('.contact-us-signup-message')
|
||||
.append('<div class="contact-us-signup-alert text-center ' + status + '" role="alert">' + data.msg + '</div>');
|
||||
|
||||
setTimeout(function () {
|
||||
$('.contact-us-signup-message').remove();
|
||||
button.removeAttr('disabled');
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
subscribeContact: function () {
|
||||
$('form.contact-us').submit(function (e) {
|
||||
e.preventDefault();
|
||||
var form = $(this);
|
||||
var button = $('.subscribe-contact-us');
|
||||
var url = form.attr('action');
|
||||
|
||||
$.spinner().start();
|
||||
button.attr('disabled', true);
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
data: form.serialize(),
|
||||
success: function (data) {
|
||||
displayMessage(data, button);
|
||||
if (data.success) {
|
||||
$('.contact-us').trigger('reset');
|
||||
}
|
||||
},
|
||||
error: function (err) {
|
||||
displayMessage(err, button);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
@@ -0,0 +1,170 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Validates and Return the cquotient namespace provided by the commerce cloud platform
|
||||
* @returns {Object} - einsteinUtils or null
|
||||
*/
|
||||
function getEinsteinUtils() {
|
||||
var einsteinUtils = window.CQuotient;
|
||||
if (einsteinUtils && (typeof einsteinUtils.getCQUserId === 'function') && (typeof einsteinUtils.getCQCookieId === 'function')) {
|
||||
return einsteinUtils;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the einstein response into a given dom element
|
||||
* @param {jQuery} $parentElement parent element where recommendations will show.
|
||||
*/
|
||||
function showControls($parentElement) {
|
||||
var $liTemplate = $parentElement.find('.hidden-indicators-template li');
|
||||
var $carouselItems = $parentElement.find('.carousel-item');
|
||||
|
||||
$carouselItems.each(function (index) {
|
||||
var $newIndiator = $liTemplate.clone();
|
||||
if (index === 0) {
|
||||
$parentElement.find('.pd-carousel-indicators').append($newIndiator);
|
||||
} else {
|
||||
$newIndiator.removeClass('active');
|
||||
$parentElement.find('.pd-carousel-indicators').append($newIndiator);
|
||||
}
|
||||
$parentElement.find('.pd-carousel-indicators li').last().attr('data-position', index);
|
||||
$parentElement.removeClass('hide-indicators');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* fills in the carousel with product tile html objects
|
||||
* @param {string} einsteinResponse string html for product tiles
|
||||
* @param {jQuery} $parentElement parent element where recommendations will show.
|
||||
*/
|
||||
function fillDomElement(einsteinResponse, $parentElement) {
|
||||
var recommender = $parentElement.data('recommender');
|
||||
var recommendedProducts = einsteinResponse[recommender].recs;
|
||||
if (recommendedProducts && recommendedProducts.length > 0) {
|
||||
var template = $parentElement.data('template');
|
||||
var swatches = $parentElement.data('swatches');
|
||||
var displayRatings = $parentElement.data('displayratings');
|
||||
var components = [];
|
||||
components = recommendedProducts.map(function (recommendedProduct) {
|
||||
var tiledefinition = {};
|
||||
tiledefinition.classxs = $parentElement.data('bsxs');
|
||||
tiledefinition.classsm = $parentElement.data('bssm');
|
||||
tiledefinition.classmd = $parentElement.data('bsmd');
|
||||
tiledefinition.template = template;
|
||||
tiledefinition.swatches = swatches;
|
||||
tiledefinition.displayratings = displayRatings;
|
||||
tiledefinition.model = {
|
||||
type: 'product',
|
||||
id: recommendedProduct.id
|
||||
};
|
||||
return tiledefinition;
|
||||
});
|
||||
|
||||
var url = new URL($parentElement.data('product-load-url'));
|
||||
url.searchParams.append('components', JSON.stringify(components));
|
||||
url.searchParams.append('limit', $parentElement.data('limit'));
|
||||
url.searchParams.append('recommender', recommender);
|
||||
$.ajax({
|
||||
url: url.href,
|
||||
type: 'get',
|
||||
dataType: 'html',
|
||||
success: function (html) {
|
||||
$parentElement.find('.carousel-inner').html(html);
|
||||
showControls($parentElement);
|
||||
$('body').trigger('carousel:setup', {});
|
||||
},
|
||||
error: function () {
|
||||
$parentElement.spinner().stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a recommendation tile, with an already initialized category specific anchors array
|
||||
* @param {jQuery} $parentElement parent element where recommendations will show.
|
||||
* @param {Object} einsteinUtils cquotient object
|
||||
* @param {Array} anchorsArray array of objects representing anchors
|
||||
*/
|
||||
function processRecommendationsTile($parentElement, einsteinUtils, anchorsArray) {
|
||||
var recommender = $parentElement.data('recommender');
|
||||
|
||||
var params = {
|
||||
userId: einsteinUtils.getCQUserId(),
|
||||
cookieId: einsteinUtils.getCQCookieId(),
|
||||
ccver: '1.01'
|
||||
};
|
||||
|
||||
if (anchorsArray) {
|
||||
params.anchors = anchorsArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a recommendation responses
|
||||
* @param {Object} einsteinResponse cquotient object
|
||||
*/
|
||||
function recommendationsReceived(einsteinResponse) {
|
||||
fillDomElement(einsteinResponse, $parentElement);
|
||||
$parentElement.spinner().stop();
|
||||
}
|
||||
|
||||
if (einsteinUtils.getRecs) {
|
||||
einsteinUtils.getRecs(einsteinUtils.clientId, recommender, params, recommendationsReceived);
|
||||
} else {
|
||||
einsteinUtils.widgets = einsteinUtils.widgets || []; // eslint-disable-line no-param-reassign
|
||||
einsteinUtils.widgets.push({
|
||||
recommenderName: recommender,
|
||||
parameters: params,
|
||||
callback: recommendationsReceived
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a recommendation tile, with an already initialized product specific anchors array
|
||||
* @param {jQuery} $parentElement parent element where recommendations will show.
|
||||
* @returns {Array} - containing an anchor object
|
||||
*/
|
||||
function createProductAnchor($parentElement) {
|
||||
return [{
|
||||
id: $parentElement.data('primaryProductId'),
|
||||
sku: $parentElement.data('secondaryProductId'),
|
||||
type: $parentElement.data('alternativeGroupType'),
|
||||
alt_id: $parentElement.data('alternativeGroupId')
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* Rerieves data attributes from parent element and converts to gretel compatible recommenders array
|
||||
* @param {jQuery} $parentElement parent element where recommendations will show.
|
||||
* @returns {Array} - containing an anchor object
|
||||
*/
|
||||
function createCategoryAnchor($parentElement) {
|
||||
return [{ id: $parentElement.data('categoryId') }];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all placeholder elements, which hold einstein recommendations queries the details from the
|
||||
* einstein engine and feeds them back to the dom element
|
||||
*/
|
||||
function loadRecommendations() {
|
||||
var einsteinUtils = getEinsteinUtils();
|
||||
if (einsteinUtils) {
|
||||
var $recommendationTiles = $('.einstein-carousel');
|
||||
$recommendationTiles.each(function () {
|
||||
var $parentElement = $(this);
|
||||
$parentElement.spinner().start();
|
||||
if ($(this).closest('.experience-einstein-einsteinCarouselProduct').length) {
|
||||
return processRecommendationsTile($parentElement, einsteinUtils, createProductAnchor($parentElement));
|
||||
} else if ($(this).closest('.experience-einstein-einsteinCarouselCategory').length) {
|
||||
return processRecommendationsTile($parentElement, einsteinUtils, createCategoryAnchor($parentElement));
|
||||
}
|
||||
return processRecommendationsTile($parentElement, einsteinUtils);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
loadRecommendations();
|
||||
});
|
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var processInclude = require('./util');
|
||||
|
||||
$(document).ready(function () {
|
||||
processInclude(require('./login/login'));
|
||||
});
|
@@ -0,0 +1,125 @@
|
||||
'use strict';
|
||||
|
||||
var formValidation = require('../components/formValidation');
|
||||
var createErrorNotification = require('../components/errorNotification');
|
||||
|
||||
module.exports = {
|
||||
login: function () {
|
||||
$('form.login').submit(function (e) {
|
||||
var form = $(this);
|
||||
e.preventDefault();
|
||||
var url = form.attr('action');
|
||||
form.spinner().start();
|
||||
$('form.login').trigger('login:submit', e);
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
data: form.serialize(),
|
||||
success: function (data) {
|
||||
form.spinner().stop();
|
||||
if (!data.success) {
|
||||
formValidation(form, data);
|
||||
$('form.login').trigger('login:error', data);
|
||||
} else {
|
||||
$('form.login').trigger('login:success', data);
|
||||
location.href = data.redirectUrl;
|
||||
}
|
||||
},
|
||||
error: function (data) {
|
||||
if (data.responseJSON.redirectUrl) {
|
||||
window.location.href = data.responseJSON.redirectUrl;
|
||||
} else {
|
||||
$('form.login').trigger('login:error', data);
|
||||
form.spinner().stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
register: function () {
|
||||
$('form.registration').submit(function (e) {
|
||||
var form = $(this);
|
||||
e.preventDefault();
|
||||
var url = form.attr('action');
|
||||
form.spinner().start();
|
||||
$('form.registration').trigger('login:register', e);
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
data: form.serialize(),
|
||||
success: function (data) {
|
||||
form.spinner().stop();
|
||||
if (!data.success) {
|
||||
$('form.registration').trigger('login:register:error', data);
|
||||
formValidation(form, data);
|
||||
} else {
|
||||
$('form.registration').trigger('login:register:success', data);
|
||||
location.href = data.redirectUrl;
|
||||
}
|
||||
},
|
||||
error: function (err) {
|
||||
if (err.responseJSON.redirectUrl) {
|
||||
window.location.href = err.responseJSON.redirectUrl;
|
||||
} else {
|
||||
createErrorNotification($('.error-messaging'), err.responseJSON.errorMessage);
|
||||
}
|
||||
|
||||
form.spinner().stop();
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
resetPassword: function () {
|
||||
$('.reset-password-form').submit(function (e) {
|
||||
var form = $(this);
|
||||
e.preventDefault();
|
||||
var url = form.attr('action');
|
||||
form.spinner().start();
|
||||
$('.reset-password-form').trigger('login:register', e);
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
data: form.serialize(),
|
||||
success: function (data) {
|
||||
form.spinner().stop();
|
||||
if (!data.success) {
|
||||
formValidation(form, data);
|
||||
} else {
|
||||
$('.request-password-title').text(data.receivedMsgHeading);
|
||||
$('.request-password-body').empty()
|
||||
.append('<p>' + data.receivedMsgBody + '</p>');
|
||||
if (!data.mobile) {
|
||||
$('#submitEmailButton').text(data.buttonText)
|
||||
.attr('data-dismiss', 'modal');
|
||||
} else {
|
||||
$('.send-email-btn').empty()
|
||||
.html('<a href="'
|
||||
+ data.returnUrl
|
||||
+ '" class="btn btn-primary btn-block">'
|
||||
+ data.buttonText + '</a>'
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
form.spinner().stop();
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
clearResetForm: function () {
|
||||
$('#login .modal').on('hidden.bs.modal', function () {
|
||||
$('#reset-password-email').val('');
|
||||
$('.modal-dialog .form-control.is-invalid').removeClass('is-invalid');
|
||||
});
|
||||
}
|
||||
};
|
@@ -0,0 +1,18 @@
|
||||
window.jQuery = window.$ = require('jquery');
|
||||
var processInclude = require('./util');
|
||||
|
||||
$(document).ready(function () {
|
||||
processInclude(require('./components/menu'));
|
||||
processInclude(require('./components/cookie'));
|
||||
processInclude(require('./components/consentTracking'));
|
||||
processInclude(require('./components/footer'));
|
||||
processInclude(require('./components/miniCart'));
|
||||
processInclude(require('./components/collapsibleItem'));
|
||||
processInclude(require('./components/search'));
|
||||
processInclude(require('./components/clientSideValidation'));
|
||||
processInclude(require('./components/countrySelector'));
|
||||
processInclude(require('./components/toolTip'));
|
||||
});
|
||||
|
||||
require('./thirdParty/bootstrap');
|
||||
require('./components/spinner');
|
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
$(document).ready(function () {
|
||||
$('body').on('click', '.show-more-button', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var $set2Element = $(this).closest('.look-book-layout').find('.look-book-set2');
|
||||
$set2Element.removeClass('hide-set');
|
||||
|
||||
var $showMoreElement = $(this).closest('.look-book-layout').find('.show-more');
|
||||
$showMoreElement.addClass('d-none');
|
||||
});
|
||||
});
|
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var processInclude = require('./util');
|
||||
|
||||
$(document).ready(function () {
|
||||
processInclude(require('./orderHistory/orderHistory'));
|
||||
});
|
@@ -0,0 +1,24 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function () {
|
||||
$('body').on('change', '.order-history-select', function (e) {
|
||||
var $ordersContainer = $('.order-list-container');
|
||||
$ordersContainer.empty();
|
||||
$.spinner().start();
|
||||
$('.order-history-select').trigger('orderHistory:sort', e);
|
||||
$.ajax({
|
||||
url: e.currentTarget.value,
|
||||
method: 'GET',
|
||||
success: function (data) {
|
||||
$ordersContainer.html(data);
|
||||
$.spinner().stop();
|
||||
},
|
||||
error: function (err) {
|
||||
if (err.responseJSON.redirectUrl) {
|
||||
window.location.href = err.responseJSON.redirectUrl;
|
||||
}
|
||||
$.spinner().stop();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var processInclude = require('./util');
|
||||
|
||||
$(document).ready(function () {
|
||||
processInclude(require('./paymentInstruments/paymentInstruments'));
|
||||
});
|
@@ -0,0 +1,81 @@
|
||||
'use strict';
|
||||
|
||||
var formValidation = require('../components/formValidation');
|
||||
var cleave = require('../components/cleave');
|
||||
|
||||
var url;
|
||||
|
||||
module.exports = {
|
||||
removePayment: function () {
|
||||
$('.remove-payment').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
url = $(this).data('url') + '?UUID=' + $(this).data('id');
|
||||
$('.payment-to-remove').empty().append($(this).data('card'));
|
||||
|
||||
$('.delete-confirmation-btn').click(function (f) {
|
||||
f.preventDefault();
|
||||
$('.remove-payment').trigger('payment:remove', f);
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'get',
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
$('#uuid-' + data.UUID).remove();
|
||||
if (data.message) {
|
||||
var toInsert = '<div class="row justify-content-center h3 no-saved-payments"><p>' +
|
||||
data.message +
|
||||
'</p></div>';
|
||||
$('.paymentInstruments').empty().append(toInsert);
|
||||
}
|
||||
},
|
||||
error: function (err) {
|
||||
if (err.responseJSON.redirectUrl) {
|
||||
window.location.href = err.responseJSON.redirectUrl;
|
||||
}
|
||||
$.spinner().stop();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
submitPayment: function () {
|
||||
$('form.payment-form').submit(function (e) {
|
||||
var $form = $(this);
|
||||
e.preventDefault();
|
||||
url = $form.attr('action');
|
||||
$form.spinner().start();
|
||||
$('form.payment-form').trigger('payment:submit', e);
|
||||
|
||||
var formData = cleave.serializeData($form);
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
data: formData,
|
||||
success: function (data) {
|
||||
$form.spinner().stop();
|
||||
if (!data.success) {
|
||||
formValidation($form, data);
|
||||
} else {
|
||||
location.href = data.redirectUrl;
|
||||
}
|
||||
},
|
||||
error: function (err) {
|
||||
if (err.responseJSON.redirectUrl) {
|
||||
window.location.href = err.responseJSON.redirectUrl;
|
||||
}
|
||||
$form.spinner().stop();
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
handleCreditCardNumber: function () {
|
||||
if ($('#cardNumber').length && $('#cardType').length) {
|
||||
cleave.handleCreditCardNumber('#cardNumber', '#cardType');
|
||||
}
|
||||
}
|
||||
};
|
@@ -0,0 +1,848 @@
|
||||
'use strict';
|
||||
var focusHelper = require('../components/focus');
|
||||
|
||||
/**
|
||||
* Retrieves the relevant pid value
|
||||
* @param {jquery} $el - DOM container for a given add to cart button
|
||||
* @return {string} - value to be used when adding product to cart
|
||||
*/
|
||||
function getPidValue($el) {
|
||||
var pid;
|
||||
|
||||
if ($('#quickViewModal').hasClass('show') && !$('.product-set').length) {
|
||||
pid = $($el).closest('.modal-content').find('.product-quickview').data('pid');
|
||||
} else if ($('.product-set-detail').length || $('.product-set').length) {
|
||||
pid = $($el).closest('.product-detail').find('.product-id').text();
|
||||
} else {
|
||||
pid = $('.product-detail:not(".bundle-item")').data('pid');
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve contextual quantity selector
|
||||
* @param {jquery} $el - DOM container for the relevant quantity
|
||||
* @return {jquery} - quantity selector DOM container
|
||||
*/
|
||||
function getQuantitySelector($el) {
|
||||
var quantitySelected;
|
||||
if ($el && $('.set-items').length) {
|
||||
quantitySelected = $($el).closest('.product-detail').find('.quantity-select');
|
||||
} else if ($el && $('.product-bundle').length) {
|
||||
var quantitySelectedModal = $($el).closest('.modal-footer').find('.quantity-select');
|
||||
var quantitySelectedPDP = $($el).closest('.bundle-footer').find('.quantity-select');
|
||||
if (quantitySelectedModal.val() === undefined) {
|
||||
quantitySelected = quantitySelectedPDP;
|
||||
} else {
|
||||
quantitySelected = quantitySelectedModal;
|
||||
}
|
||||
} else {
|
||||
quantitySelected = $('.quantity-select');
|
||||
}
|
||||
return quantitySelected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the value associated with the Quantity pull-down menu
|
||||
* @param {jquery} $el - DOM container for the relevant quantity
|
||||
* @return {string} - value found in the quantity input
|
||||
*/
|
||||
function getQuantitySelected($el) {
|
||||
return getQuantitySelector($el).val();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the attribute values for an attribute that has image swatches
|
||||
*
|
||||
* @param {Object} attr - Attribute
|
||||
* @param {string} attr.id - Attribute ID
|
||||
* @param {Object[]} attr.values - Array of attribute value objects
|
||||
* @param {string} attr.values.value - Attribute coded value
|
||||
* @param {string} attr.values.url - URL to de/select an attribute value of the product
|
||||
* @param {boolean} attr.values.isSelectable - Flag as to whether an attribute value can be
|
||||
* selected. If there is no variant that corresponds to a specific combination of attribute
|
||||
* values, an attribute may be disabled in the Product Detail Page
|
||||
* @param {jQuery} $productContainer - DOM container for a given product
|
||||
* @param {Object} msgs - object containing resource messages
|
||||
*/
|
||||
function processSwatchValues(attr, $productContainer, msgs) {
|
||||
attr.values.forEach(function (attrValue) {
|
||||
var $attrValue = $productContainer.find('[data-attr="' + attr.id + '"] [data-attr-value="' +
|
||||
attrValue.value + '"]');
|
||||
var $swatchButton = $attrValue.parent();
|
||||
|
||||
if (attrValue.selected) {
|
||||
$attrValue.addClass('selected');
|
||||
$attrValue.siblings('.selected-assistive-text').text(msgs.assistiveSelectedText);
|
||||
} else {
|
||||
$attrValue.removeClass('selected');
|
||||
$attrValue.siblings('.selected-assistive-text').empty();
|
||||
}
|
||||
|
||||
if (attrValue.url) {
|
||||
$swatchButton.attr('data-url', attrValue.url);
|
||||
} else {
|
||||
$swatchButton.removeAttr('data-url');
|
||||
}
|
||||
|
||||
// Disable if not selectable
|
||||
$attrValue.removeClass('selectable unselectable');
|
||||
|
||||
$attrValue.addClass(attrValue.selectable ? 'selectable' : 'unselectable');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Process attribute values associated with an attribute that does not have image swatches
|
||||
*
|
||||
* @param {Object} attr - Attribute
|
||||
* @param {string} attr.id - Attribute ID
|
||||
* @param {Object[]} attr.values - Array of attribute value objects
|
||||
* @param {string} attr.values.value - Attribute coded value
|
||||
* @param {string} attr.values.url - URL to de/select an attribute value of the product
|
||||
* @param {boolean} attr.values.isSelectable - Flag as to whether an attribute value can be
|
||||
* selected. If there is no variant that corresponds to a specific combination of attribute
|
||||
* values, an attribute may be disabled in the Product Detail Page
|
||||
* @param {jQuery} $productContainer - DOM container for a given product
|
||||
*/
|
||||
function processNonSwatchValues(attr, $productContainer) {
|
||||
var $attr = '[data-attr="' + attr.id + '"]';
|
||||
var $defaultOption = $productContainer.find($attr + ' .select-' + attr.id + ' option:first');
|
||||
$defaultOption.attr('value', attr.resetUrl);
|
||||
|
||||
attr.values.forEach(function (attrValue) {
|
||||
var $attrValue = $productContainer
|
||||
.find($attr + ' [data-attr-value="' + attrValue.value + '"]');
|
||||
$attrValue.attr('value', attrValue.url)
|
||||
.removeAttr('disabled');
|
||||
|
||||
if (!attrValue.selectable) {
|
||||
$attrValue.attr('disabled', true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Routes the handling of attribute processing depending on whether the attribute has image
|
||||
* swatches or not
|
||||
*
|
||||
* @param {Object} attrs - Attribute
|
||||
* @param {string} attr.id - Attribute ID
|
||||
* @param {jQuery} $productContainer - DOM element for a given product
|
||||
* @param {Object} msgs - object containing resource messages
|
||||
*/
|
||||
function updateAttrs(attrs, $productContainer, msgs) {
|
||||
// Currently, the only attribute type that has image swatches is Color.
|
||||
var attrsWithSwatches = ['color'];
|
||||
|
||||
attrs.forEach(function (attr) {
|
||||
if (attrsWithSwatches.indexOf(attr.id) > -1) {
|
||||
processSwatchValues(attr, $productContainer, msgs);
|
||||
} else {
|
||||
processNonSwatchValues(attr, $productContainer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the availability status in the Product Detail Page
|
||||
*
|
||||
* @param {Object} response - Ajax response object after an
|
||||
* attribute value has been [de]selected
|
||||
* @param {jQuery} $productContainer - DOM element for a given product
|
||||
*/
|
||||
function updateAvailability(response, $productContainer) {
|
||||
var availabilityValue = '';
|
||||
var availabilityMessages = response.product.availability.messages;
|
||||
if (!response.product.readyToOrder) {
|
||||
availabilityValue = '<li><div>' + response.resources.info_selectforstock + '</div></li>';
|
||||
} else {
|
||||
availabilityMessages.forEach(function (message) {
|
||||
availabilityValue += '<li><div>' + message + '</div></li>';
|
||||
});
|
||||
}
|
||||
|
||||
$($productContainer).trigger('product:updateAvailability', {
|
||||
product: response.product,
|
||||
$productContainer: $productContainer,
|
||||
message: availabilityValue,
|
||||
resources: response.resources
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates html for product attributes section
|
||||
*
|
||||
* @param {array} attributes - list of attributes
|
||||
* @return {string} - Compiled HTML
|
||||
*/
|
||||
function getAttributesHtml(attributes) {
|
||||
if (!attributes) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var html = '';
|
||||
|
||||
attributes.forEach(function (attributeGroup) {
|
||||
if (attributeGroup.ID === 'mainAttributes') {
|
||||
attributeGroup.attributes.forEach(function (attribute) {
|
||||
html += '<div class="attribute-values">' + attribute.label + ': '
|
||||
+ attribute.value + '</div>';
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef UpdatedOptionValue
|
||||
* @type Object
|
||||
* @property {string} id - Option value ID for look up
|
||||
* @property {string} url - Updated option value selection URL
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef OptionSelectionResponse
|
||||
* @type Object
|
||||
* @property {string} priceHtml - Updated price HTML code
|
||||
* @property {Object} options - Updated Options
|
||||
* @property {string} options.id - Option ID
|
||||
* @property {UpdatedOptionValue[]} options.values - Option values
|
||||
*/
|
||||
|
||||
/**
|
||||
* Updates DOM using post-option selection Ajax response
|
||||
*
|
||||
* @param {OptionSelectionResponse} optionsHtml - Ajax response optionsHtml from selecting a product option
|
||||
* @param {jQuery} $productContainer - DOM element for current product
|
||||
*/
|
||||
function updateOptions(optionsHtml, $productContainer) {
|
||||
// Update options
|
||||
$productContainer.find('.product-options').empty().html(optionsHtml);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically creates Bootstrap carousel from response containing images
|
||||
* @param {Object[]} imgs - Array of large product images,along with related information
|
||||
* @param {jQuery} $productContainer - DOM element for a given product
|
||||
*/
|
||||
function createCarousel(imgs, $productContainer) {
|
||||
var carousel = $productContainer.find('.carousel');
|
||||
$(carousel).carousel('dispose');
|
||||
var carouselId = $(carousel).attr('id');
|
||||
$(carousel).empty().append('<ol class="carousel-indicators"></ol><div class="carousel-inner" role="listbox"></div><a class="carousel-control-prev" href="#' + carouselId + '" role="button" data-slide="prev"><span class="fa icon-prev" aria-hidden="true"></span><span class="sr-only">' + $(carousel).data('prev') + '</span></a><a class="carousel-control-next" href="#' + carouselId + '" role="button" data-slide="next"><span class="fa icon-next" aria-hidden="true"></span><span class="sr-only">' + $(carousel).data('next') + '</span></a>');
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
$('<div class="carousel-item"><img src="' + imgs[i].url + '" class="d-block img-fluid" alt="' + imgs[i].alt + ' image number ' + parseInt(imgs[i].index, 10) + '" title="' + imgs[i].title + '" itemprop="image" /></div>').appendTo($(carousel).find('.carousel-inner'));
|
||||
$('<li data-target="#' + carouselId + '" data-slide-to="' + i + '" class=""></li>').appendTo($(carousel).find('.carousel-indicators'));
|
||||
}
|
||||
$($(carousel).find('.carousel-item')).first().addClass('active');
|
||||
$($(carousel).find('.carousel-indicators > li')).first().addClass('active');
|
||||
if (imgs.length === 1) {
|
||||
$($(carousel).find('.carousel-indicators, a[class^="carousel-control-"]')).detach();
|
||||
}
|
||||
$(carousel).carousel();
|
||||
$($(carousel).find('.carousel-indicators')).attr('aria-hidden', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses JSON from Ajax call made whenever an attribute value is [de]selected
|
||||
* @param {Object} response - response from Ajax call
|
||||
* @param {Object} response.product - Product object
|
||||
* @param {string} response.product.id - Product ID
|
||||
* @param {Object[]} response.product.variationAttributes - Product attributes
|
||||
* @param {Object[]} response.product.images - Product images
|
||||
* @param {boolean} response.product.hasRequiredAttrsSelected - Flag as to whether all required
|
||||
* attributes have been selected. Used partially to
|
||||
* determine whether the Add to Cart button can be enabled
|
||||
* @param {jQuery} $productContainer - DOM element for a given product.
|
||||
*/
|
||||
function handleVariantResponse(response, $productContainer) {
|
||||
var isChoiceOfBonusProducts =
|
||||
$productContainer.parents('.choose-bonus-product-dialog').length > 0;
|
||||
var isVaraint;
|
||||
if (response.product.variationAttributes) {
|
||||
updateAttrs(response.product.variationAttributes, $productContainer, response.resources);
|
||||
isVaraint = response.product.productType === 'variant';
|
||||
if (isChoiceOfBonusProducts && isVaraint) {
|
||||
$productContainer.parent('.bonus-product-item')
|
||||
.data('pid', response.product.id);
|
||||
|
||||
$productContainer.parent('.bonus-product-item')
|
||||
.data('ready-to-order', response.product.readyToOrder);
|
||||
}
|
||||
}
|
||||
|
||||
// Update primary images
|
||||
var primaryImageUrls = response.product.images.large;
|
||||
createCarousel(primaryImageUrls, $productContainer);
|
||||
|
||||
// Update pricing
|
||||
if (!isChoiceOfBonusProducts) {
|
||||
var $priceSelector = $('.prices .price', $productContainer).length
|
||||
? $('.prices .price', $productContainer)
|
||||
: $('.prices .price');
|
||||
$priceSelector.replaceWith(response.product.price.html);
|
||||
}
|
||||
|
||||
// Update promotions
|
||||
$productContainer.find('.promotions').empty().html(response.product.promotionsHtml);
|
||||
|
||||
updateAvailability(response, $productContainer);
|
||||
|
||||
if (isChoiceOfBonusProducts) {
|
||||
var $selectButton = $productContainer.find('.select-bonus-product');
|
||||
$selectButton.trigger('bonusproduct:updateSelectButton', {
|
||||
product: response.product, $productContainer: $productContainer
|
||||
});
|
||||
} else {
|
||||
// Enable "Add to Cart" button if all required attributes have been selected
|
||||
$('button.add-to-cart, button.add-to-cart-global, button.update-cart-product-global').trigger('product:updateAddToCart', {
|
||||
product: response.product, $productContainer: $productContainer
|
||||
}).trigger('product:statusUpdate', response.product);
|
||||
}
|
||||
|
||||
// Update attributes
|
||||
$productContainer.find('.main-attributes').empty()
|
||||
.html(getAttributesHtml(response.product.attributes));
|
||||
}
|
||||
|
||||
/**
|
||||
* @typespec UpdatedQuantity
|
||||
* @type Object
|
||||
* @property {boolean} selected - Whether the quantity has been selected
|
||||
* @property {string} value - The number of products to purchase
|
||||
* @property {string} url - Compiled URL that specifies variation attributes, product ID, options,
|
||||
* etc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Updates the quantity DOM elements post Ajax call
|
||||
* @param {UpdatedQuantity[]} quantities -
|
||||
* @param {jQuery} $productContainer - DOM container for a given product
|
||||
*/
|
||||
function updateQuantities(quantities, $productContainer) {
|
||||
if ($productContainer.parent('.bonus-product-item').length <= 0) {
|
||||
var optionsHtml = quantities.map(function (quantity) {
|
||||
var selected = quantity.selected ? ' selected ' : '';
|
||||
return '<option value="' + quantity.value + '" data-url="' + quantity.url + '"' +
|
||||
selected + '>' + quantity.value + '</option>';
|
||||
}).join('');
|
||||
getQuantitySelector($productContainer).empty().html(optionsHtml);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* updates the product view when a product attribute is selected or deselected or when
|
||||
* changing quantity
|
||||
* @param {string} selectedValueUrl - the Url for the selected variation value
|
||||
* @param {jQuery} $productContainer - DOM element for current product
|
||||
*/
|
||||
function attributeSelect(selectedValueUrl, $productContainer) {
|
||||
if (selectedValueUrl) {
|
||||
$('body').trigger('product:beforeAttributeSelect',
|
||||
{ url: selectedValueUrl, container: $productContainer });
|
||||
|
||||
$.ajax({
|
||||
url: selectedValueUrl,
|
||||
method: 'GET',
|
||||
success: function (data) {
|
||||
handleVariantResponse(data, $productContainer);
|
||||
updateOptions(data.product.optionsHtml, $productContainer);
|
||||
updateQuantities(data.product.quantities, $productContainer);
|
||||
$('body').trigger('product:afterAttributeSelect',
|
||||
{ data: data, container: $productContainer });
|
||||
$.spinner().stop();
|
||||
},
|
||||
error: function () {
|
||||
$.spinner().stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves url to use when adding a product to the cart
|
||||
*
|
||||
* @return {string} - The provided URL to use when adding a product to the cart
|
||||
*/
|
||||
function getAddToCartUrl() {
|
||||
return $('.add-to-cart-url').val();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the html for a modal window
|
||||
* @param {string} html - representing the body and footer of the modal window
|
||||
*
|
||||
* @return {Object} - Object with properties body and footer.
|
||||
*/
|
||||
function parseHtml(html) {
|
||||
var $html = $('<div>').append($.parseHTML(html));
|
||||
|
||||
var body = $html.find('.choice-of-bonus-product');
|
||||
var footer = $html.find('.modal-footer').children();
|
||||
|
||||
return { body: body, footer: footer };
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves url to use when adding a product to the cart
|
||||
*
|
||||
* @param {Object} data - data object used to fill in dynamic portions of the html
|
||||
*/
|
||||
function chooseBonusProducts(data) {
|
||||
$('.modal-body').spinner().start();
|
||||
|
||||
if ($('#chooseBonusProductModal').length !== 0) {
|
||||
$('#chooseBonusProductModal').remove();
|
||||
}
|
||||
var bonusUrl;
|
||||
if (data.bonusChoiceRuleBased) {
|
||||
bonusUrl = data.showProductsUrlRuleBased;
|
||||
} else {
|
||||
bonusUrl = data.showProductsUrlListBased;
|
||||
}
|
||||
|
||||
var htmlString = '<!-- Modal -->'
|
||||
+ '<div class="modal fade" id="chooseBonusProductModal" tabindex="-1" role="dialog">'
|
||||
+ '<span class="enter-message sr-only" ></span>'
|
||||
+ '<div class="modal-dialog choose-bonus-product-dialog" '
|
||||
+ 'data-total-qty="' + data.maxBonusItems + '"'
|
||||
+ 'data-UUID="' + data.uuid + '"'
|
||||
+ 'data-pliUUID="' + data.pliUUID + '"'
|
||||
+ 'data-addToCartUrl="' + data.addToCartUrl + '"'
|
||||
+ 'data-pageStart="0"'
|
||||
+ 'data-pageSize="' + data.pageSize + '"'
|
||||
+ 'data-moreURL="' + data.showProductsUrlRuleBased + '"'
|
||||
+ 'data-bonusChoiceRuleBased="' + data.bonusChoiceRuleBased + '">'
|
||||
+ '<!-- Modal content-->'
|
||||
+ '<div class="modal-content">'
|
||||
+ '<div class="modal-header">'
|
||||
+ ' <span class="">' + data.labels.selectprods + '</span>'
|
||||
+ ' <button type="button" class="close pull-right" data-dismiss="modal">'
|
||||
+ ' <span aria-hidden="true">×</span>'
|
||||
+ ' <span class="sr-only"> </span>'
|
||||
+ ' </button>'
|
||||
+ '</div>'
|
||||
+ '<div class="modal-body"></div>'
|
||||
+ '<div class="modal-footer"></div>'
|
||||
+ '</div>'
|
||||
+ '</div>'
|
||||
+ '</div>';
|
||||
$('body').append(htmlString);
|
||||
$('.modal-body').spinner().start();
|
||||
|
||||
$.ajax({
|
||||
url: bonusUrl,
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
success: function (response) {
|
||||
var parsedHtml = parseHtml(response.renderedTemplate);
|
||||
$('#chooseBonusProductModal .modal-body').empty();
|
||||
$('#chooseBonusProductModal .enter-message').text(response.enterDialogMessage);
|
||||
$('#chooseBonusProductModal .modal-header .close .sr-only').text(response.closeButtonText);
|
||||
$('#chooseBonusProductModal .modal-body').html(parsedHtml.body);
|
||||
$('#chooseBonusProductModal .modal-footer').html(parsedHtml.footer);
|
||||
$('#chooseBonusProductModal').modal('show');
|
||||
$.spinner().stop();
|
||||
},
|
||||
error: function () {
|
||||
$.spinner().stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the Mini-Cart quantity value after the customer has pressed the "Add to Cart" button
|
||||
* @param {string} response - ajax response from clicking the add to cart button
|
||||
*/
|
||||
function handlePostCartAdd(response) {
|
||||
$('.minicart').trigger('count:update', response);
|
||||
var messageType = response.error ? 'alert-danger' : 'alert-success';
|
||||
// show add to cart toast
|
||||
if (response.newBonusDiscountLineItem
|
||||
&& Object.keys(response.newBonusDiscountLineItem).length !== 0) {
|
||||
chooseBonusProducts(response.newBonusDiscountLineItem);
|
||||
} else {
|
||||
if ($('.add-to-cart-messages').length === 0) {
|
||||
$('body').append(
|
||||
'<div class="add-to-cart-messages"></div>'
|
||||
);
|
||||
}
|
||||
|
||||
$('.add-to-cart-messages').append(
|
||||
'<div class="alert ' + messageType + ' add-to-basket-alert text-center" role="alert">'
|
||||
+ response.message
|
||||
+ '</div>'
|
||||
);
|
||||
|
||||
setTimeout(function () {
|
||||
$('.add-to-basket-alert').remove();
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the bundle product item ID's for the Controller to replace bundle master product
|
||||
* items with their selected variants
|
||||
*
|
||||
* @return {string[]} - List of selected bundle product item ID's
|
||||
*/
|
||||
function getChildProducts() {
|
||||
var childProducts = [];
|
||||
$('.bundle-item').each(function () {
|
||||
childProducts.push({
|
||||
pid: $(this).find('.product-id').text(),
|
||||
quantity: parseInt($(this).find('label.quantity').data('quantity'), 10)
|
||||
});
|
||||
});
|
||||
|
||||
return childProducts.length ? JSON.stringify(childProducts) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve product options
|
||||
*
|
||||
* @param {jQuery} $productContainer - DOM element for current product
|
||||
* @return {string} - Product options and their selected values
|
||||
*/
|
||||
function getOptions($productContainer) {
|
||||
var options = $productContainer
|
||||
.find('.product-option')
|
||||
.map(function () {
|
||||
var $elOption = $(this).find('.options-select');
|
||||
var urlValue = $elOption.val();
|
||||
var selectedValueId = $elOption.find('option[value="' + urlValue + '"]')
|
||||
.data('value-id');
|
||||
return {
|
||||
optionId: $(this).data('option-id'),
|
||||
selectedValueId: selectedValueId
|
||||
};
|
||||
}).toArray();
|
||||
|
||||
return JSON.stringify(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a call to the server to report the event of adding an item to the cart
|
||||
*
|
||||
* @param {string | boolean} url - a string representing the end point to hit so that the event can be recorded, or false
|
||||
*/
|
||||
function miniCartReportingUrl(url) {
|
||||
if (url) {
|
||||
$.ajax({
|
||||
url: url,
|
||||
method: 'GET',
|
||||
success: function () {
|
||||
// reporting urls hit on the server
|
||||
},
|
||||
error: function () {
|
||||
// no reporting urls hit on the server
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
attributeSelect: attributeSelect,
|
||||
methods: {
|
||||
editBonusProducts: function (data) {
|
||||
chooseBonusProducts(data);
|
||||
}
|
||||
},
|
||||
|
||||
focusChooseBonusProductModal: function () {
|
||||
$('body').on('shown.bs.modal', '#chooseBonusProductModal', function () {
|
||||
$('#chooseBonusProductModal').siblings().attr('aria-hidden', 'true');
|
||||
$('#chooseBonusProductModal .close').focus();
|
||||
});
|
||||
},
|
||||
|
||||
onClosingChooseBonusProductModal: function () {
|
||||
$('body').on('hidden.bs.modal', '#chooseBonusProductModal', function () {
|
||||
$('#chooseBonusProductModal').siblings().attr('aria-hidden', 'false');
|
||||
});
|
||||
},
|
||||
|
||||
trapChooseBonusProductModalFocus: function () {
|
||||
$('body').on('keydown', '#chooseBonusProductModal', function (e) {
|
||||
var focusParams = {
|
||||
event: e,
|
||||
containerSelector: '#chooseBonusProductModal',
|
||||
firstElementSelector: '.close',
|
||||
lastElementSelector: '.add-bonus-products'
|
||||
};
|
||||
focusHelper.setTabNextFocus(focusParams);
|
||||
});
|
||||
},
|
||||
|
||||
colorAttribute: function () {
|
||||
$(document).on('click', '[data-attr="color"] button', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
if ($(this).attr('disabled')) {
|
||||
return;
|
||||
}
|
||||
var $productContainer = $(this).closest('.set-item');
|
||||
if (!$productContainer.length) {
|
||||
$productContainer = $(this).closest('.product-detail');
|
||||
}
|
||||
|
||||
attributeSelect($(this).attr('data-url'), $productContainer);
|
||||
});
|
||||
},
|
||||
|
||||
selectAttribute: function () {
|
||||
$(document).on('change', 'select[class*="select-"], .options-select', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var $productContainer = $(this).closest('.set-item');
|
||||
if (!$productContainer.length) {
|
||||
$productContainer = $(this).closest('.product-detail');
|
||||
}
|
||||
attributeSelect(e.currentTarget.value, $productContainer);
|
||||
});
|
||||
},
|
||||
|
||||
availability: function () {
|
||||
$(document).on('change', '.quantity-select', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var $productContainer = $(this).closest('.product-detail');
|
||||
if (!$productContainer.length) {
|
||||
$productContainer = $(this).closest('.modal-content').find('.product-quickview');
|
||||
}
|
||||
|
||||
if ($('.bundle-items', $productContainer).length === 0) {
|
||||
attributeSelect($(e.currentTarget).find('option:selected').data('url'),
|
||||
$productContainer);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
addToCart: function () {
|
||||
$(document).on('click', 'button.add-to-cart, button.add-to-cart-global', function () {
|
||||
var addToCartUrl;
|
||||
var pid;
|
||||
var pidsObj;
|
||||
var setPids;
|
||||
|
||||
$('body').trigger('product:beforeAddToCart', this);
|
||||
|
||||
if ($('.set-items').length && $(this).hasClass('add-to-cart-global')) {
|
||||
setPids = [];
|
||||
|
||||
$('.product-detail').each(function () {
|
||||
if (!$(this).hasClass('product-set-detail')) {
|
||||
setPids.push({
|
||||
pid: $(this).find('.product-id').text(),
|
||||
qty: $(this).find('.quantity-select').val(),
|
||||
options: getOptions($(this))
|
||||
});
|
||||
}
|
||||
});
|
||||
pidsObj = JSON.stringify(setPids);
|
||||
}
|
||||
|
||||
pid = getPidValue($(this));
|
||||
|
||||
var $productContainer = $(this).closest('.product-detail');
|
||||
if (!$productContainer.length) {
|
||||
$productContainer = $(this).closest('.quick-view-dialog').find('.product-detail');
|
||||
}
|
||||
|
||||
addToCartUrl = getAddToCartUrl();
|
||||
|
||||
var form = {
|
||||
pid: pid,
|
||||
pidsObj: pidsObj,
|
||||
childProducts: getChildProducts(),
|
||||
quantity: getQuantitySelected($(this))
|
||||
};
|
||||
|
||||
if (!$('.bundle-item').length) {
|
||||
form.options = getOptions($productContainer);
|
||||
}
|
||||
|
||||
$(this).trigger('updateAddToCartFormData', form);
|
||||
if (addToCartUrl) {
|
||||
$.ajax({
|
||||
url: addToCartUrl,
|
||||
method: 'POST',
|
||||
data: form,
|
||||
success: function (data) {
|
||||
handlePostCartAdd(data);
|
||||
$('body').trigger('product:afterAddToCart', data);
|
||||
$.spinner().stop();
|
||||
miniCartReportingUrl(data.reportingURL);
|
||||
},
|
||||
error: function () {
|
||||
$.spinner().stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
selectBonusProduct: function () {
|
||||
$(document).on('click', '.select-bonus-product', function () {
|
||||
var $choiceOfBonusProduct = $(this).parents('.choice-of-bonus-product');
|
||||
var pid = $(this).data('pid');
|
||||
var maxPids = $('.choose-bonus-product-dialog').data('total-qty');
|
||||
var submittedQty = parseInt($choiceOfBonusProduct.find('.bonus-quantity-select').val(), 10);
|
||||
var totalQty = 0;
|
||||
$.each($('#chooseBonusProductModal .selected-bonus-products .selected-pid'), function () {
|
||||
totalQty += $(this).data('qty');
|
||||
});
|
||||
totalQty += submittedQty;
|
||||
var optionID = $choiceOfBonusProduct.find('.product-option').data('option-id');
|
||||
var valueId = $choiceOfBonusProduct.find('.options-select option:selected').data('valueId');
|
||||
if (totalQty <= maxPids) {
|
||||
var selectedBonusProductHtml = ''
|
||||
+ '<div class="selected-pid row" '
|
||||
+ 'data-pid="' + pid + '"'
|
||||
+ 'data-qty="' + submittedQty + '"'
|
||||
+ 'data-optionID="' + (optionID || '') + '"'
|
||||
+ 'data-option-selected-value="' + (valueId || '') + '"'
|
||||
+ '>'
|
||||
+ '<div class="col-sm-11 col-9 bonus-product-name" >'
|
||||
+ $choiceOfBonusProduct.find('.product-name').html()
|
||||
+ '</div>'
|
||||
+ '<div class="col-1"><i class="fa fa-times" aria-hidden="true"></i></div>'
|
||||
+ '</div>'
|
||||
;
|
||||
$('#chooseBonusProductModal .selected-bonus-products').append(selectedBonusProductHtml);
|
||||
$('.pre-cart-products').html(totalQty);
|
||||
$('.selected-bonus-products .bonus-summary').removeClass('alert-danger');
|
||||
} else {
|
||||
$('.selected-bonus-products .bonus-summary').addClass('alert-danger');
|
||||
}
|
||||
});
|
||||
},
|
||||
removeBonusProduct: function () {
|
||||
$(document).on('click', '.selected-pid', function () {
|
||||
$(this).remove();
|
||||
var $selected = $('#chooseBonusProductModal .selected-bonus-products .selected-pid');
|
||||
var count = 0;
|
||||
if ($selected.length) {
|
||||
$selected.each(function () {
|
||||
count += parseInt($(this).data('qty'), 10);
|
||||
});
|
||||
}
|
||||
|
||||
$('.pre-cart-products').html(count);
|
||||
$('.selected-bonus-products .bonus-summary').removeClass('alert-danger');
|
||||
});
|
||||
},
|
||||
enableBonusProductSelection: function () {
|
||||
$('body').on('bonusproduct:updateSelectButton', function (e, response) {
|
||||
$('button.select-bonus-product', response.$productContainer).attr('disabled',
|
||||
(!response.product.readyToOrder || !response.product.available));
|
||||
var pid = response.product.id;
|
||||
$('button.select-bonus-product', response.$productContainer).data('pid', pid);
|
||||
});
|
||||
},
|
||||
showMoreBonusProducts: function () {
|
||||
$(document).on('click', '.show-more-bonus-products', function () {
|
||||
var url = $(this).data('url');
|
||||
$('.modal-content').spinner().start();
|
||||
$.ajax({
|
||||
url: url,
|
||||
method: 'GET',
|
||||
success: function (html) {
|
||||
var parsedHtml = parseHtml(html);
|
||||
$('.modal-body').append(parsedHtml.body);
|
||||
$('.show-more-bonus-products:first').remove();
|
||||
$('.modal-content').spinner().stop();
|
||||
},
|
||||
error: function () {
|
||||
$('.modal-content').spinner().stop();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
addBonusProductsToCart: function () {
|
||||
$(document).on('click', '.add-bonus-products', function () {
|
||||
var $readyToOrderBonusProducts = $('.choose-bonus-product-dialog .selected-pid');
|
||||
var queryString = '?pids=';
|
||||
var url = $('.choose-bonus-product-dialog').data('addtocarturl');
|
||||
var pidsObject = {
|
||||
bonusProducts: []
|
||||
};
|
||||
|
||||
$.each($readyToOrderBonusProducts, function () {
|
||||
var qtyOption =
|
||||
parseInt($(this)
|
||||
.data('qty'), 10);
|
||||
|
||||
var option = null;
|
||||
if (qtyOption > 0) {
|
||||
if ($(this).data('optionid') && $(this).data('option-selected-value')) {
|
||||
option = {};
|
||||
option.optionId = $(this).data('optionid');
|
||||
option.productId = $(this).data('pid');
|
||||
option.selectedValueId = $(this).data('option-selected-value');
|
||||
}
|
||||
pidsObject.bonusProducts.push({
|
||||
pid: $(this).data('pid'),
|
||||
qty: qtyOption,
|
||||
options: [option]
|
||||
});
|
||||
pidsObject.totalQty = parseInt($('.pre-cart-products').html(), 10);
|
||||
}
|
||||
});
|
||||
queryString += JSON.stringify(pidsObject);
|
||||
queryString = queryString + '&uuid=' + $('.choose-bonus-product-dialog').data('uuid');
|
||||
queryString = queryString + '&pliuuid=' + $('.choose-bonus-product-dialog').data('pliuuid');
|
||||
$.spinner().start();
|
||||
$.ajax({
|
||||
url: url + queryString,
|
||||
method: 'POST',
|
||||
success: function (data) {
|
||||
$.spinner().stop();
|
||||
if (data.error) {
|
||||
$('#chooseBonusProductModal').modal('hide');
|
||||
if ($('.add-to-cart-messages').length === 0) {
|
||||
$('body').append('<div class="add-to-cart-messages"></div>');
|
||||
}
|
||||
$('.add-to-cart-messages').append(
|
||||
'<div class="alert alert-danger add-to-basket-alert text-center"'
|
||||
+ ' role="alert">'
|
||||
+ data.errorMessage + '</div>'
|
||||
);
|
||||
setTimeout(function () {
|
||||
$('.add-to-basket-alert').remove();
|
||||
}, 3000);
|
||||
} else {
|
||||
$('.configure-bonus-product-attributes').html(data);
|
||||
$('.bonus-products-step2').removeClass('hidden-xl-down');
|
||||
$('#chooseBonusProductModal').modal('hide');
|
||||
|
||||
if ($('.add-to-cart-messages').length === 0) {
|
||||
$('body').append('<div class="add-to-cart-messages"></div>');
|
||||
}
|
||||
$('.minicart-quantity').html(data.totalQty);
|
||||
$('.add-to-cart-messages').append(
|
||||
'<div class="alert alert-success add-to-basket-alert text-center"'
|
||||
+ ' role="alert">'
|
||||
+ data.msgSuccess + '</div>'
|
||||
);
|
||||
setTimeout(function () {
|
||||
$('.add-to-basket-alert').remove();
|
||||
if ($('.cart-page').length) {
|
||||
location.reload();
|
||||
}
|
||||
}, 1500);
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
$.spinner().stop();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
getPidValue: getPidValue,
|
||||
getQuantitySelected: getQuantitySelected,
|
||||
miniCartReportingUrl: miniCartReportingUrl
|
||||
};
|
@@ -0,0 +1,151 @@
|
||||
'use strict';
|
||||
var base = require('./base');
|
||||
|
||||
/**
|
||||
* Enable/disable UI elements
|
||||
* @param {boolean} enableOrDisable - true or false
|
||||
*/
|
||||
function updateAddToCartEnableDisableOtherElements(enableOrDisable) {
|
||||
$('button.add-to-cart-global').attr('disabled', enableOrDisable);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
methods: {
|
||||
updateAddToCartEnableDisableOtherElements: updateAddToCartEnableDisableOtherElements
|
||||
},
|
||||
|
||||
availability: base.availability,
|
||||
|
||||
addToCart: base.addToCart,
|
||||
|
||||
updateAttributesAndDetails: function () {
|
||||
$('body').on('product:statusUpdate', function (e, data) {
|
||||
var $productContainer = $('.product-detail[data-pid="' + data.id + '"]');
|
||||
|
||||
$productContainer.find('.description-and-detail .product-attributes')
|
||||
.empty()
|
||||
.html(data.attributesHtml);
|
||||
|
||||
if (data.shortDescription) {
|
||||
$productContainer.find('.description-and-detail .description')
|
||||
.removeClass('hidden-xl-down');
|
||||
$productContainer.find('.description-and-detail .description .content')
|
||||
.empty()
|
||||
.html(data.shortDescription);
|
||||
} else {
|
||||
$productContainer.find('.description-and-detail .description')
|
||||
.addClass('hidden-xl-down');
|
||||
}
|
||||
|
||||
if (data.longDescription) {
|
||||
$productContainer.find('.description-and-detail .details')
|
||||
.removeClass('hidden-xl-down');
|
||||
$productContainer.find('.description-and-detail .details .content')
|
||||
.empty()
|
||||
.html(data.longDescription);
|
||||
} else {
|
||||
$productContainer.find('.description-and-detail .details')
|
||||
.addClass('hidden-xl-down');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
showSpinner: function () {
|
||||
$('body').on('product:beforeAddToCart product:beforeAttributeSelect', function () {
|
||||
$.spinner().start();
|
||||
});
|
||||
},
|
||||
updateAttribute: function () {
|
||||
$('body').on('product:afterAttributeSelect', function (e, response) {
|
||||
if ($('.product-detail>.bundle-items').length) {
|
||||
response.container.data('pid', response.data.product.id);
|
||||
response.container.find('.product-id').text(response.data.product.id);
|
||||
} else if ($('.product-set-detail').eq(0)) {
|
||||
response.container.data('pid', response.data.product.id);
|
||||
response.container.find('.product-id').text(response.data.product.id);
|
||||
} else {
|
||||
$('.product-id').text(response.data.product.id);
|
||||
$('.product-detail:not(".bundle-item")').data('pid', response.data.product.id);
|
||||
}
|
||||
});
|
||||
},
|
||||
updateAddToCart: function () {
|
||||
$('body').on('product:updateAddToCart', function (e, response) {
|
||||
// update local add to cart (for sets)
|
||||
$('button.add-to-cart', response.$productContainer).attr('disabled',
|
||||
(!response.product.readyToOrder || !response.product.available));
|
||||
|
||||
var enable = $('.product-availability').toArray().every(function (item) {
|
||||
return $(item).data('available') && $(item).data('ready-to-order');
|
||||
});
|
||||
module.exports.methods.updateAddToCartEnableDisableOtherElements(!enable);
|
||||
});
|
||||
},
|
||||
updateAvailability: function () {
|
||||
$('body').on('product:updateAvailability', function (e, response) {
|
||||
$('div.availability', response.$productContainer)
|
||||
.data('ready-to-order', response.product.readyToOrder)
|
||||
.data('available', response.product.available);
|
||||
|
||||
$('.availability-msg', response.$productContainer)
|
||||
.empty().html(response.message);
|
||||
|
||||
if ($('.global-availability').length) {
|
||||
var allAvailable = $('.product-availability').toArray()
|
||||
.every(function (item) { return $(item).data('available'); });
|
||||
|
||||
var allReady = $('.product-availability').toArray()
|
||||
.every(function (item) { return $(item).data('ready-to-order'); });
|
||||
|
||||
$('.global-availability')
|
||||
.data('ready-to-order', allReady)
|
||||
.data('available', allAvailable);
|
||||
|
||||
$('.global-availability .availability-msg').empty()
|
||||
.html(allReady ? response.message : response.resources.info_selectforstock);
|
||||
}
|
||||
});
|
||||
},
|
||||
sizeChart: function () {
|
||||
$('.size-chart a').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
var url = $(this).attr('href');
|
||||
var $prodSizeChart = $(this).closest('.size-chart').find('.size-chart-collapsible');
|
||||
if ($prodSizeChart.is(':empty')) {
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'get',
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
$prodSizeChart.append(data.content);
|
||||
}
|
||||
});
|
||||
}
|
||||
$prodSizeChart.toggleClass('active');
|
||||
});
|
||||
|
||||
var $sizeChart = $('.size-chart-collapsible');
|
||||
$('body').on('click touchstart', function (e) {
|
||||
if ($('.size-chart').has(e.target).length <= 0) {
|
||||
$sizeChart.removeClass('active');
|
||||
}
|
||||
});
|
||||
},
|
||||
copyProductLink: function () {
|
||||
$('body').on('click', '#fa-link', function () {
|
||||
event.preventDefault();
|
||||
var $temp = $('<input>');
|
||||
$('body').append($temp);
|
||||
$temp.val($('#shareUrl').val()).select();
|
||||
document.execCommand('copy');
|
||||
$temp.remove();
|
||||
$('.copy-link-message').attr('role', 'alert');
|
||||
$('.copy-link-message').removeClass('d-none');
|
||||
setTimeout(function () {
|
||||
$('.copy-link-message').addClass('d-none');
|
||||
}, 3000);
|
||||
});
|
||||
},
|
||||
|
||||
focusChooseBonusProductModal: base.focusChooseBonusProductModal()
|
||||
};
|
@@ -0,0 +1,201 @@
|
||||
'use strict';
|
||||
var base = require('./base');
|
||||
var focusHelper = require('../components/focus');
|
||||
|
||||
/**
|
||||
* Generates the modal window on the first call.
|
||||
*
|
||||
*/
|
||||
function getModalHtmlElement() {
|
||||
if ($('#quickViewModal').length !== 0) {
|
||||
$('#quickViewModal').remove();
|
||||
}
|
||||
var htmlString = '<!-- Modal -->'
|
||||
+ '<div class="modal fade" id="quickViewModal" role="dialog">'
|
||||
+ '<span class="enter-message sr-only" ></span>'
|
||||
+ '<div class="modal-dialog quick-view-dialog">'
|
||||
+ '<!-- Modal content-->'
|
||||
+ '<div class="modal-content">'
|
||||
+ '<div class="modal-header">'
|
||||
+ ' <a class="full-pdp-link" href=""></a>'
|
||||
+ ' <button type="button" class="close pull-right" data-dismiss="modal">'
|
||||
+ ' <span aria-hidden="true">×</span>'
|
||||
+ ' <span class="sr-only"> </span>'
|
||||
+ ' </button>'
|
||||
+ '</div>'
|
||||
+ '<div class="modal-body"></div>'
|
||||
+ '<div class="modal-footer"></div>'
|
||||
+ '</div>'
|
||||
+ '</div>'
|
||||
+ '</div>';
|
||||
$('body').append(htmlString);
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} QuickViewHtml
|
||||
* @property {string} body - Main Quick View body
|
||||
* @property {string} footer - Quick View footer content
|
||||
*/
|
||||
|
||||
/**
|
||||
* Parse HTML code in Ajax response
|
||||
*
|
||||
* @param {string} html - Rendered HTML from quickview template
|
||||
* @return {QuickViewHtml} - QuickView content components
|
||||
*/
|
||||
function parseHtml(html) {
|
||||
var $html = $('<div>').append($.parseHTML(html));
|
||||
|
||||
var body = $html.find('.product-quickview');
|
||||
var footer = $html.find('.modal-footer').children();
|
||||
|
||||
return { body: body, footer: footer };
|
||||
}
|
||||
|
||||
/**
|
||||
* replaces the content in the modal window on for the selected product variation.
|
||||
* @param {string} selectedValueUrl - url to be used to retrieve a new product model
|
||||
*/
|
||||
function fillModalElement(selectedValueUrl) {
|
||||
$('.modal-body').spinner().start();
|
||||
$.ajax({
|
||||
url: selectedValueUrl,
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
var parsedHtml = parseHtml(data.renderedTemplate);
|
||||
|
||||
$('.modal-body').empty();
|
||||
$('.modal-body').html(parsedHtml.body);
|
||||
$('.modal-footer').html(parsedHtml.footer);
|
||||
$('.full-pdp-link').text(data.quickViewFullDetailMsg);
|
||||
$('#quickViewModal .full-pdp-link').attr('href', data.productUrl);
|
||||
$('#quickViewModal .size-chart').attr('href', data.productUrl);
|
||||
$('#quickViewModal .modal-header .close .sr-only').text(data.closeButtonText);
|
||||
$('#quickViewModal .enter-message').text(data.enterDialogMessage);
|
||||
$('#quickViewModal').modal('show');
|
||||
$('body').trigger('quickview:ready');
|
||||
|
||||
$.spinner().stop();
|
||||
},
|
||||
error: function () {
|
||||
$.spinner().stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
showQuickview: function () {
|
||||
$('body').on('click', '.quickview', function (e) {
|
||||
e.preventDefault();
|
||||
var selectedValueUrl = $(this).closest('a.quickview').attr('href');
|
||||
$(e.target).trigger('quickview:show');
|
||||
getModalHtmlElement();
|
||||
fillModalElement(selectedValueUrl);
|
||||
});
|
||||
},
|
||||
focusQuickview: function () {
|
||||
$('body').on('shown.bs.modal', '#quickViewModal', function () {
|
||||
$('#quickViewModal .close').focus();
|
||||
});
|
||||
},
|
||||
trapQuickviewFocus: function () {
|
||||
$('body').on('keydown', '#quickViewModal', function (e) {
|
||||
var focusParams = {
|
||||
event: e,
|
||||
containerSelector: '#quickViewModal',
|
||||
firstElementSelector: '.full-pdp-link',
|
||||
lastElementSelector: '.add-to-cart-global',
|
||||
nextToLastElementSelector: '.modal-footer .quantity-select'
|
||||
};
|
||||
focusHelper.setTabNextFocus(focusParams);
|
||||
});
|
||||
},
|
||||
availability: base.availability,
|
||||
addToCart: base.addToCart,
|
||||
showSpinner: function () {
|
||||
$('body').on('product:beforeAddToCart', function (e, data) {
|
||||
$(data).closest('.modal-content').spinner().start();
|
||||
});
|
||||
},
|
||||
hideDialog: function () {
|
||||
$('body').on('product:afterAddToCart', function () {
|
||||
$('#quickViewModal').modal('hide');
|
||||
});
|
||||
},
|
||||
beforeUpdateAttribute: function () {
|
||||
$('body').on('product:beforeAttributeSelect', function () {
|
||||
$('.modal.show .modal-content').spinner().start();
|
||||
});
|
||||
},
|
||||
updateAttribute: function () {
|
||||
$('body').on('product:afterAttributeSelect', function (e, response) {
|
||||
if ($('.modal.show .product-quickview>.bundle-items').length) {
|
||||
$('.modal.show').find(response.container).data('pid', response.data.product.id);
|
||||
$('.modal.show').find(response.container)
|
||||
.find('.product-id').text(response.data.product.id);
|
||||
} else if ($('.set-items').length) {
|
||||
response.container.find('.product-id').text(response.data.product.id);
|
||||
} else {
|
||||
$('.modal.show .product-quickview').data('pid', response.data.product.id);
|
||||
$('.modal.show .full-pdp-link')
|
||||
.attr('href', response.data.product.selectedProductUrl);
|
||||
}
|
||||
});
|
||||
},
|
||||
updateAddToCart: function () {
|
||||
$('body').on('product:updateAddToCart', function (e, response) {
|
||||
// update local add to cart (for sets)
|
||||
$('button.add-to-cart', response.$productContainer).attr('disabled',
|
||||
(!response.product.readyToOrder || !response.product.available));
|
||||
|
||||
// update global add to cart (single products, bundles)
|
||||
var dialog = $(response.$productContainer)
|
||||
.closest('.quick-view-dialog');
|
||||
|
||||
$('.add-to-cart-global', dialog).attr('disabled',
|
||||
!$('.global-availability', dialog).data('ready-to-order')
|
||||
|| !$('.global-availability', dialog).data('available')
|
||||
);
|
||||
});
|
||||
},
|
||||
updateAvailability: function () {
|
||||
$('body').on('product:updateAvailability', function (e, response) {
|
||||
// bundle individual products
|
||||
$('.product-availability', response.$productContainer)
|
||||
.data('ready-to-order', response.product.readyToOrder)
|
||||
.data('available', response.product.available)
|
||||
.find('.availability-msg')
|
||||
.empty()
|
||||
.html(response.message);
|
||||
|
||||
|
||||
var dialog = $(response.$productContainer)
|
||||
.closest('.quick-view-dialog');
|
||||
|
||||
if ($('.product-availability', dialog).length) {
|
||||
// bundle all products
|
||||
var allAvailable = $('.product-availability', dialog).toArray()
|
||||
.every(function (item) { return $(item).data('available'); });
|
||||
|
||||
var allReady = $('.product-availability', dialog).toArray()
|
||||
.every(function (item) { return $(item).data('ready-to-order'); });
|
||||
|
||||
$('.global-availability', dialog)
|
||||
.data('ready-to-order', allReady)
|
||||
.data('available', allAvailable);
|
||||
|
||||
$('.global-availability .availability-msg', dialog).empty()
|
||||
.html(allReady ? response.message : response.resources.info_selectforstock);
|
||||
} else {
|
||||
// single product
|
||||
$('.global-availability', dialog)
|
||||
.data('ready-to-order', response.product.readyToOrder)
|
||||
.data('available', response.product.available)
|
||||
.find('.availability-msg')
|
||||
.empty()
|
||||
.html(response.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var processInclude = require('./util');
|
||||
|
||||
$(document).ready(function () {
|
||||
processInclude(require('./product/detail'));
|
||||
});
|
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var processInclude = require('./util');
|
||||
|
||||
$(document).ready(function () {
|
||||
processInclude(require('./product/quickView'));
|
||||
});
|
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var processInclude = require('./util');
|
||||
|
||||
$(document).ready(function () {
|
||||
processInclude(require('./profile/profile'));
|
||||
});
|
@@ -0,0 +1,67 @@
|
||||
'use strict';
|
||||
|
||||
var formValidation = require('../components/formValidation');
|
||||
|
||||
module.exports = {
|
||||
submitProfile: function () {
|
||||
$('form.edit-profile-form').submit(function (e) {
|
||||
var $form = $(this);
|
||||
e.preventDefault();
|
||||
var url = $form.attr('action');
|
||||
$form.spinner().start();
|
||||
$('form.edit-profile-form').trigger('profile:edit', e);
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
data: $form.serialize(),
|
||||
success: function (data) {
|
||||
$form.spinner().stop();
|
||||
if (!data.success) {
|
||||
formValidation($form, data);
|
||||
} else {
|
||||
location.href = data.redirectUrl;
|
||||
}
|
||||
},
|
||||
error: function (err) {
|
||||
if (err.responseJSON.redirectUrl) {
|
||||
window.location.href = err.responseJSON.redirectUrl;
|
||||
}
|
||||
$form.spinner().stop();
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
submitPassword: function () {
|
||||
$('form.change-password-form').submit(function (e) {
|
||||
var $form = $(this);
|
||||
e.preventDefault();
|
||||
var url = $form.attr('action');
|
||||
$form.spinner().start();
|
||||
$('form.change-password-form').trigger('password:edit', e);
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
data: $form.serialize(),
|
||||
success: function (data) {
|
||||
$form.spinner().stop();
|
||||
if (!data.success) {
|
||||
formValidation($form, data);
|
||||
} else {
|
||||
location.href = data.redirectUrl;
|
||||
}
|
||||
},
|
||||
error: function (err) {
|
||||
if (err.responseJSON.redirectUrl) {
|
||||
window.location.href = err.responseJSON.redirectUrl;
|
||||
}
|
||||
$form.spinner().stop();
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
};
|
@@ -0,0 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
var processInclude = require('./util');
|
||||
|
||||
$(document).ready(function () {
|
||||
processInclude(require('./search/search'));
|
||||
processInclude(require('./product/quickView'));
|
||||
});
|
@@ -0,0 +1,223 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Update DOM elements with Ajax results
|
||||
*
|
||||
* @param {Object} $results - jQuery DOM element
|
||||
* @param {string} selector - DOM element to look up in the $results
|
||||
* @return {undefined}
|
||||
*/
|
||||
function updateDom($results, selector) {
|
||||
var $updates = $results.find(selector);
|
||||
$(selector).empty().html($updates.html());
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep refinement panes expanded/collapsed after Ajax refresh
|
||||
*
|
||||
* @param {Object} $results - jQuery DOM element
|
||||
* @return {undefined}
|
||||
*/
|
||||
function handleRefinements($results) {
|
||||
$('.refinement.active').each(function () {
|
||||
$(this).removeClass('active');
|
||||
var activeDiv = $results.find('.' + $(this)[0].className.replace(/ /g, '.'));
|
||||
activeDiv.addClass('active');
|
||||
activeDiv.find('button.title').attr('aria-expanded', 'true');
|
||||
});
|
||||
|
||||
updateDom($results, '.refinements');
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse Ajax results and updated select DOM elements
|
||||
*
|
||||
* @param {string} response - Ajax response HTML code
|
||||
* @return {undefined}
|
||||
*/
|
||||
function parseResults(response) {
|
||||
var $results = $(response);
|
||||
var specialHandlers = {
|
||||
'.refinements': handleRefinements
|
||||
};
|
||||
|
||||
// Update DOM elements that do not require special handling
|
||||
[
|
||||
'.grid-header',
|
||||
'.header-bar',
|
||||
'.header.page-title',
|
||||
'.product-grid',
|
||||
'.show-more',
|
||||
'.filter-bar'
|
||||
].forEach(function (selector) {
|
||||
updateDom($results, selector);
|
||||
});
|
||||
|
||||
Object.keys(specialHandlers).forEach(function (selector) {
|
||||
specialHandlers[selector]($results);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This function retrieves another page of content to display in the content search grid
|
||||
* @param {JQuery} $element - the jquery element that has the click event attached
|
||||
* @param {JQuery} $target - the jquery element that will receive the response
|
||||
* @return {undefined}
|
||||
*/
|
||||
function getContent($element, $target) {
|
||||
var showMoreUrl = $element.data('url');
|
||||
$.spinner().start();
|
||||
$.ajax({
|
||||
url: showMoreUrl,
|
||||
method: 'GET',
|
||||
success: function (response) {
|
||||
$target.append(response);
|
||||
$.spinner().stop();
|
||||
},
|
||||
error: function () {
|
||||
$.spinner().stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update sort option URLs from Ajax response
|
||||
*
|
||||
* @param {string} response - Ajax response HTML code
|
||||
* @return {undefined}
|
||||
*/
|
||||
function updateSortOptions(response) {
|
||||
var $tempDom = $('<div>').append($(response));
|
||||
var sortOptions = $tempDom.find('.grid-footer').data('sort-options').options;
|
||||
sortOptions.forEach(function (option) {
|
||||
$('option.' + option.id).val(option.url);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
filter: function () {
|
||||
// Display refinements bar when Menu icon clicked
|
||||
$('.container').on('click', 'button.filter-results', function () {
|
||||
$('.refinement-bar, .modal-background').show();
|
||||
$('.refinement-bar').siblings().attr('aria-hidden', true);
|
||||
$('.refinement-bar').closest('.row').siblings().attr('aria-hidden', true);
|
||||
$('.refinement-bar').closest('.tab-pane.active').siblings().attr('aria-hidden', true);
|
||||
$('.refinement-bar').closest('.container.search-results').siblings().attr('aria-hidden', true);
|
||||
$('.refinement-bar .close').focus();
|
||||
});
|
||||
},
|
||||
|
||||
closeRefinements: function () {
|
||||
// Refinements close button
|
||||
$('.container').on('click', '.refinement-bar button.close, .modal-background', function () {
|
||||
$('.refinement-bar, .modal-background').hide();
|
||||
$('.refinement-bar').siblings().attr('aria-hidden', false);
|
||||
$('.refinement-bar').closest('.row').siblings().attr('aria-hidden', false);
|
||||
$('.refinement-bar').closest('.tab-pane.active').siblings().attr('aria-hidden', false);
|
||||
$('.refinement-bar').closest('.container.search-results').siblings().attr('aria-hidden', false);
|
||||
$('.btn.filter-results').focus();
|
||||
});
|
||||
},
|
||||
|
||||
resize: function () {
|
||||
// Close refinement bar and hide modal background if user resizes browser
|
||||
$(window).resize(function () {
|
||||
$('.refinement-bar, .modal-background').hide();
|
||||
$('.refinement-bar').siblings().attr('aria-hidden', false);
|
||||
$('.refinement-bar').closest('.row').siblings().attr('aria-hidden', false);
|
||||
$('.refinement-bar').closest('.tab-pane.active').siblings().attr('aria-hidden', false);
|
||||
$('.refinement-bar').closest('.container.search-results').siblings().attr('aria-hidden', false);
|
||||
});
|
||||
},
|
||||
|
||||
sort: function () {
|
||||
// Handle sort order menu selection
|
||||
$('.container').on('change', '[name=sort-order]', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
$.spinner().start();
|
||||
$(this).trigger('search:sort', this.value);
|
||||
$.ajax({
|
||||
url: this.value,
|
||||
data: { selectedUrl: this.value },
|
||||
method: 'GET',
|
||||
success: function (response) {
|
||||
$('.product-grid').empty().html(response);
|
||||
$.spinner().stop();
|
||||
},
|
||||
error: function () {
|
||||
$.spinner().stop();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
showMore: function () {
|
||||
// Show more products
|
||||
$('.container').on('click', '.show-more button', function (e) {
|
||||
e.stopPropagation();
|
||||
var showMoreUrl = $(this).data('url');
|
||||
e.preventDefault();
|
||||
|
||||
$.spinner().start();
|
||||
$(this).trigger('search:showMore', e);
|
||||
$.ajax({
|
||||
url: showMoreUrl,
|
||||
data: { selectedUrl: showMoreUrl },
|
||||
method: 'GET',
|
||||
success: function (response) {
|
||||
$('.grid-footer').replaceWith(response);
|
||||
updateSortOptions(response);
|
||||
$.spinner().stop();
|
||||
},
|
||||
error: function () {
|
||||
$.spinner().stop();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
applyFilter: function () {
|
||||
// Handle refinement value selection and reset click
|
||||
$('.container').on(
|
||||
'click',
|
||||
'.refinements li button, .refinement-bar button.reset, .filter-value button, .swatch-filter button',
|
||||
function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
$.spinner().start();
|
||||
$(this).trigger('search:filter', e);
|
||||
$.ajax({
|
||||
url: $(this).data('href'),
|
||||
data: {
|
||||
page: $('.grid-footer').data('page-number'),
|
||||
selectedUrl: $(this).data('href')
|
||||
},
|
||||
method: 'GET',
|
||||
success: function (response) {
|
||||
parseResults(response);
|
||||
$.spinner().stop();
|
||||
},
|
||||
error: function () {
|
||||
$.spinner().stop();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
showContentTab: function () {
|
||||
// Display content results from the search
|
||||
$('.container').on('click', '.content-search', function () {
|
||||
if ($('#content-search-results').html() === '') {
|
||||
getContent($(this), $('#content-search-results'));
|
||||
}
|
||||
});
|
||||
|
||||
// Display the next page of content results from the search
|
||||
$('.container').on('click', '.show-more-content button', function () {
|
||||
getContent($(this), $('#content-search-results'));
|
||||
$('.show-more-content').remove();
|
||||
});
|
||||
}
|
||||
};
|
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var processInclude = require('./util');
|
||||
|
||||
$(document).ready(function () {
|
||||
processInclude(require('./storeLocator/storeLocator'));
|
||||
});
|
@@ -0,0 +1,264 @@
|
||||
/* globals google */
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* appends params to a url
|
||||
* @param {string} url - Original url
|
||||
* @param {Object} params - Parameters to append
|
||||
* @returns {string} result url with appended parameters
|
||||
*/
|
||||
function appendToUrl(url, params) {
|
||||
var newUrl = url;
|
||||
newUrl += (newUrl.indexOf('?') !== -1 ? '&' : '?') + Object.keys(params).map(function (key) {
|
||||
return key + '=' + encodeURIComponent(params[key]);
|
||||
}).join('&');
|
||||
|
||||
return newUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses google maps api to render a map
|
||||
*/
|
||||
function maps() {
|
||||
var map;
|
||||
var infowindow = new google.maps.InfoWindow();
|
||||
|
||||
// Init U.S. Map in the center of the viewport
|
||||
var latlng = new google.maps.LatLng(37.09024, -95.712891);
|
||||
var mapOptions = {
|
||||
scrollwheel: false,
|
||||
zoom: 4,
|
||||
center: latlng
|
||||
};
|
||||
|
||||
map = new google.maps.Map($('.map-canvas')[0], mapOptions);
|
||||
var mapdiv = $('.map-canvas').attr('data-locations');
|
||||
|
||||
mapdiv = JSON.parse(mapdiv);
|
||||
|
||||
var bounds = new google.maps.LatLngBounds();
|
||||
|
||||
// Customized google map marker icon with svg format
|
||||
var markerImg = {
|
||||
path: 'M13.5,30.1460153 L16.8554555,25.5 L20.0024287,25.5 C23.039087,25.5 25.5,' +
|
||||
'23.0388955 25.5,20.0024287 L25.5,5.99757128 C25.5,2.96091298 23.0388955,0.5 ' +
|
||||
'20.0024287,0.5 L5.99757128,0.5 C2.96091298,0.5 0.5,2.96110446 0.5,5.99757128 ' +
|
||||
'L0.5,20.0024287 C0.5,23.039087 2.96110446,25.5 5.99757128,25.5 L10.1445445,' +
|
||||
'25.5 L13.5,30.1460153 Z',
|
||||
fillColor: '#0070d2',
|
||||
fillOpacity: 1,
|
||||
scale: 1.1,
|
||||
strokeColor: 'white',
|
||||
strokeWeight: 1,
|
||||
anchor: new google.maps.Point(13, 30),
|
||||
labelOrigin: new google.maps.Point(12, 12)
|
||||
};
|
||||
|
||||
Object.keys(mapdiv).forEach(function (key) {
|
||||
var item = mapdiv[key];
|
||||
var lable = parseInt(key, 10) + 1;
|
||||
var storeLocation = new google.maps.LatLng(item.latitude, item.longitude);
|
||||
var marker = new google.maps.Marker({
|
||||
position: storeLocation,
|
||||
map: map,
|
||||
title: item.name,
|
||||
icon: markerImg,
|
||||
label: { text: lable.toString(), color: 'white', fontSize: '16px' }
|
||||
});
|
||||
|
||||
marker.addListener('click', function () {
|
||||
infowindow.setOptions({
|
||||
content: item.infoWindowHtml
|
||||
});
|
||||
infowindow.open(map, marker);
|
||||
});
|
||||
|
||||
// Create a minimum bound based on a set of storeLocations
|
||||
bounds.extend(marker.position);
|
||||
});
|
||||
// Fit the all the store marks in the center of a minimum bounds when any store has been found.
|
||||
if (mapdiv && mapdiv.length !== 0) {
|
||||
map.fitBounds(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the results of the search and updates the map
|
||||
* @param {Object} data - Response from the server
|
||||
*/
|
||||
function updateStoresResults(data) {
|
||||
var $resultsDiv = $('.results');
|
||||
var $mapDiv = $('.map-canvas');
|
||||
var hasResults = data.stores.length > 0;
|
||||
|
||||
if (!hasResults) {
|
||||
$('.store-locator-no-results').show();
|
||||
} else {
|
||||
$('.store-locator-no-results').hide();
|
||||
}
|
||||
|
||||
$resultsDiv.empty()
|
||||
.data('has-results', hasResults)
|
||||
.data('radius', data.radius)
|
||||
.data('search-key', data.searchKey);
|
||||
|
||||
$mapDiv.attr('data-locations', data.locations);
|
||||
|
||||
if ($mapDiv.data('has-google-api')) {
|
||||
maps();
|
||||
} else {
|
||||
$('.store-locator-no-apiKey').show();
|
||||
}
|
||||
|
||||
if (data.storesResultsHtml) {
|
||||
$resultsDiv.append(data.storesResultsHtml);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for stores with new zip code
|
||||
* @param {HTMLElement} element - the target html element
|
||||
* @returns {boolean} false to prevent default event
|
||||
*/
|
||||
function search(element) {
|
||||
var dialog = element.closest('.in-store-inventory-dialog');
|
||||
var spinner = dialog.length ? dialog.spinner() : $.spinner();
|
||||
spinner.start();
|
||||
var $form = element.closest('.store-locator');
|
||||
var radius = $('.results').data('radius');
|
||||
var url = $form.attr('action');
|
||||
var urlParams = { radius: radius };
|
||||
|
||||
var payload = $form.is('form') ? $form.serialize() : { postalCode: $form.find('[name="postalCode"]').val() };
|
||||
|
||||
url = appendToUrl(url, urlParams);
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: $form.attr('method'),
|
||||
data: payload,
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
spinner.stop();
|
||||
updateStoresResults(data);
|
||||
$('.select-store').prop('disabled', true);
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function () {
|
||||
if ($('.map-canvas').data('has-google-api')) {
|
||||
maps();
|
||||
} else {
|
||||
$('.store-locator-no-apiKey').show();
|
||||
}
|
||||
|
||||
if (!$('.results').data('has-results')) {
|
||||
$('.store-locator-no-results').show();
|
||||
}
|
||||
},
|
||||
|
||||
detectLocation: function () {
|
||||
// clicking on detect location.
|
||||
$('.detect-location').on('click', function () {
|
||||
$.spinner().start();
|
||||
if (!navigator.geolocation) {
|
||||
$.spinner().stop();
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.geolocation.getCurrentPosition(function (position) {
|
||||
var $detectLocationButton = $('.detect-location');
|
||||
var url = $detectLocationButton.data('action');
|
||||
var radius = $('.results').data('radius');
|
||||
var urlParams = {
|
||||
radius: radius,
|
||||
lat: position.coords.latitude,
|
||||
long: position.coords.longitude
|
||||
};
|
||||
|
||||
url = appendToUrl(url, urlParams);
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'get',
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
$.spinner().stop();
|
||||
updateStoresResults(data);
|
||||
$('.select-store').prop('disabled', true);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
search: function () {
|
||||
$('.store-locator-container form.store-locator').submit(function (e) {
|
||||
e.preventDefault();
|
||||
search($(this));
|
||||
});
|
||||
$('.store-locator-container .btn-storelocator-search[type="button"]').click(function (e) {
|
||||
e.preventDefault();
|
||||
search($(this));
|
||||
});
|
||||
},
|
||||
|
||||
changeRadius: function () {
|
||||
$('.store-locator-container .radius').change(function () {
|
||||
var radius = $(this).val();
|
||||
var searchKeys = $('.results').data('search-key');
|
||||
var url = $(this).data('action-url');
|
||||
var urlParams = {};
|
||||
|
||||
if (searchKeys.postalCode) {
|
||||
urlParams = {
|
||||
radius: radius,
|
||||
postalCode: searchKeys.postalCode
|
||||
};
|
||||
} else if (searchKeys.lat && searchKeys.long) {
|
||||
urlParams = {
|
||||
radius: radius,
|
||||
lat: searchKeys.lat,
|
||||
long: searchKeys.long
|
||||
};
|
||||
}
|
||||
|
||||
url = appendToUrl(url, urlParams);
|
||||
var dialog = $(this).closest('.in-store-inventory-dialog');
|
||||
var spinner = dialog.length ? dialog.spinner() : $.spinner();
|
||||
spinner.start();
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'get',
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
spinner.stop();
|
||||
updateStoresResults(data);
|
||||
$('.select-store').prop('disabled', true);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
selectStore: function () {
|
||||
$('.store-locator-container').on('click', '.select-store', (function (e) {
|
||||
e.preventDefault();
|
||||
var selectedStore = $(':checked', '.results-card .results');
|
||||
var data = {
|
||||
storeID: selectedStore.val(),
|
||||
searchRadius: $('#radius').val(),
|
||||
searchPostalCode: $('.results').data('search-key').postalCode,
|
||||
storeDetailsHtml: selectedStore.siblings('label').find('.store-details').html(),
|
||||
event: e
|
||||
};
|
||||
|
||||
$('body').trigger('store:selected', data);
|
||||
}));
|
||||
},
|
||||
updateSelectStoreButton: function () {
|
||||
$('body').on('change', '.select-store-input', (function () {
|
||||
$('.select-store').prop('disabled', false);
|
||||
}));
|
||||
}
|
||||
};
|
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"env": {
|
||||
"es6": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
require('bootstrap/js/src/util.js');
|
||||
require('bootstrap/js/src/alert.js');
|
||||
// require('bootstrap/js/src/button.js');
|
||||
require('bootstrap/js/src/carousel.js');
|
||||
require('bootstrap/js/src/collapse.js');
|
||||
// require('bootstrap/js/src/dropdown.js');
|
||||
require('bootstrap/js/src/modal.js');
|
||||
require('bootstrap/js/src/scrollspy.js');
|
||||
require('bootstrap/js/src/tab.js');
|
||||
// require('bootstrap/js/src/tooltip.js');
|
||||
// require('bootstrap/js/src/popover.js');
|
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function (include) {
|
||||
if (typeof include === 'function') {
|
||||
include();
|
||||
} else if (typeof include === 'object') {
|
||||
Object.keys(include).forEach(function (key) {
|
||||
if (typeof include[key] === 'function') {
|
||||
include[key]();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
@@ -0,0 +1,35 @@
|
||||
@import "bootstrap/scss/functions";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins";
|
||||
@import "bootstrap/scss/root";
|
||||
@import "bootstrap/scss/reboot";
|
||||
@import "bootstrap/scss/type";
|
||||
@import "bootstrap/scss/images";
|
||||
@import "bootstrap/scss/code";
|
||||
@import "bootstrap/scss/grid";
|
||||
@import "bootstrap/scss/tables";
|
||||
@import "bootstrap/scss/forms";
|
||||
@import "bootstrap/scss/buttons";
|
||||
@import "bootstrap/scss/transitions";
|
||||
@import "bootstrap/scss/dropdown";
|
||||
@import "bootstrap/scss/button-group";
|
||||
@import "bootstrap/scss/input-group";
|
||||
@import "bootstrap/scss/custom-forms";
|
||||
@import "bootstrap/scss/nav";
|
||||
@import "bootstrap/scss/navbar";
|
||||
@import "bootstrap/scss/card";
|
||||
@import "bootstrap/scss/breadcrumb";
|
||||
@import "bootstrap/scss/pagination";
|
||||
@import "bootstrap/scss/badge";
|
||||
@import "bootstrap/scss/jumbotron";
|
||||
@import "bootstrap/scss/alert";
|
||||
@import "bootstrap/scss/progress";
|
||||
@import "bootstrap/scss/media";
|
||||
@import "bootstrap/scss/list-group";
|
||||
@import "bootstrap/scss/close";
|
||||
@import "bootstrap/scss/modal";
|
||||
@import "bootstrap/scss/tooltip";
|
||||
@import "bootstrap/scss/popover";
|
||||
@import "bootstrap/scss/carousel";
|
||||
@import "bootstrap/scss/utilities";
|
||||
@import "bootstrap/scss/print";
|
@@ -0,0 +1,86 @@
|
||||
.carousel {
|
||||
.icon-prev,
|
||||
.icon-next {
|
||||
background-color: $white;
|
||||
font-size: 1.875em;
|
||||
// width and height here need to use rem units because the font size used here is 30px
|
||||
height: 3rem;
|
||||
padding-top: 0.24em;
|
||||
width: 3rem;
|
||||
|
||||
&::before {
|
||||
color: black;
|
||||
font-family: 'FontAwesome';
|
||||
}
|
||||
}
|
||||
|
||||
.icon-prev {
|
||||
&::before {
|
||||
content: '\f104';
|
||||
}
|
||||
}
|
||||
|
||||
.icon-next {
|
||||
&::before {
|
||||
content: '\f105';
|
||||
}
|
||||
}
|
||||
|
||||
.carousel-control-prev {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.carousel-control-next {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
border-bottom: $border-width solid $grey3;
|
||||
|
||||
.nav-link {
|
||||
font-size: 1.1rem;
|
||||
color: $nav-tabs-link-hover-border-color;
|
||||
|
||||
&.active {
|
||||
border-bottom: 0.188em solid #{var(--skin-primary-color-1)};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.card-header h4 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.modal .modal-body {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
dt {
|
||||
color: $gray-700;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.custom-checkbox .custom-control-label::before {
|
||||
border: 1px solid black;
|
||||
background: $grey1; /* For browsers that do not support gradients */
|
||||
background: linear-gradient($grey1, $grey3); /* Standard syntax */
|
||||
}
|
||||
|
||||
.custom-checkbox .custom-control-input:checked ~ .custom-control-label::after {
|
||||
background-image: $svg-check;
|
||||
}
|
||||
|
||||
.custom-radio .custom-control-label::before {
|
||||
border: 1px solid black;
|
||||
background: $grey3; /* For browsers that do not support gradients */
|
||||
background: linear-gradient($grey3, $grey5); /* Standard syntax */
|
||||
}
|
||||
|
||||
.form-control.is-invalid {
|
||||
background-image: none;
|
||||
}
|
@@ -0,0 +1,116 @@
|
||||
@import "variables";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins/breakpoints";
|
||||
@import "productCard";
|
||||
|
||||
.minicart {
|
||||
position: relative;
|
||||
|
||||
h1 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.cart {
|
||||
padding-top: 0.625em;
|
||||
padding-bottom: 0.625em;
|
||||
background-color: $body-bg;
|
||||
}
|
||||
|
||||
.remove-btn {
|
||||
color: $slightly-darker-gray;
|
||||
float: right;
|
||||
background-color: white;
|
||||
border: none;
|
||||
font-size: 1.625em;
|
||||
margin-top: -0.313em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.product-summary {
|
||||
margin-right: -0.938em;
|
||||
max-height: 21.875em;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding-right: 0.938em;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding: 0.625em;
|
||||
}
|
||||
|
||||
.quantity-label {
|
||||
font-size: 0.813em;
|
||||
}
|
||||
|
||||
.quantity {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.popover {
|
||||
top: 100%;
|
||||
left: auto;
|
||||
right: 0;
|
||||
min-width: 23.44rem;
|
||||
max-width: 23.44rem;
|
||||
min-height: 22.7rem;
|
||||
display: none;
|
||||
|
||||
&::before {
|
||||
left: auto;
|
||||
right: 15px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
left: auto;
|
||||
right: 16px;
|
||||
}
|
||||
|
||||
&.show {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.minicart-footer {
|
||||
border-top: 1px solid $grey3;
|
||||
}
|
||||
|
||||
.estimated-total {
|
||||
margin-top: 0.625em;
|
||||
}
|
||||
|
||||
.sub-total-label {
|
||||
font-size: 1em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.sub-total {
|
||||
font-size: 1em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.line-item-divider {
|
||||
margin: 0.625em -0.625em 0.625em -1.325em;
|
||||
}
|
||||
|
||||
.line-item-name {
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
.hide-link-med {
|
||||
|
||||
@include media-breakpoint-only(sm) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.hide-no-link {
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
display: none;
|
||||
}
|
||||
}
|
@@ -0,0 +1,108 @@
|
||||
@import "variables";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins/breakpoints";
|
||||
|
||||
.item-attributes {
|
||||
vertical-align: top;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.line-item-attributes,
|
||||
.line-item-option {
|
||||
font-size: 0.813rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.line-item-name {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
color: $darker-gray;
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.313em;
|
||||
}
|
||||
|
||||
.line-item-pricing-info {
|
||||
margin-bottom: 0;
|
||||
|
||||
+ .price {
|
||||
font-size: 1em;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
+ .unit-price .price {
|
||||
font-size: 1em;
|
||||
font-weight: bolder;
|
||||
}
|
||||
}
|
||||
|
||||
.line-item-price-quantity-info {
|
||||
margin-top: 0.625em;
|
||||
border-top: 1px solid $horizontal-rule-grey;
|
||||
}
|
||||
|
||||
.line-item-total-text {
|
||||
font-size: 0.813em;
|
||||
}
|
||||
|
||||
.pricing {
|
||||
font-size: 1em;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.item-image {
|
||||
height: 5.625em;
|
||||
width: 5.625em;
|
||||
margin-right: 0.938em;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
|
||||
img.product-image {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
max-height: 5.625em;
|
||||
}
|
||||
}
|
||||
|
||||
.non-adjusted-price {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.line-item-promo {
|
||||
color: $success;
|
||||
font-size: 0.813em;
|
||||
}
|
||||
|
||||
.line-item-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.bundled-line-item + .bundled-line-item {
|
||||
margin-top: 0.625em;
|
||||
}
|
||||
|
||||
.bundle-includes {
|
||||
font-size: 0.813em;
|
||||
margin-bottom: 0.625em;
|
||||
}
|
||||
|
||||
.line-item-divider {
|
||||
margin: 0.625em -1.225em 0.625em -1.325em;
|
||||
}
|
||||
|
||||
.line-dotted {
|
||||
border-top: 0.063em dashed #ccc;
|
||||
}
|
||||
|
||||
.line-item-availability {
|
||||
font-size: 0.813rem;
|
||||
}
|
||||
|
||||
.product-line-item-details {
|
||||
overflow-y: auto;
|
||||
}
|
@@ -0,0 +1,83 @@
|
||||
@import "bootstrap/scss/functions";
|
||||
|
||||
// font-awesome font file locations in relation to target location of the css file.
|
||||
$fa-font-path: "../fonts" !default;
|
||||
|
||||
// flag icons location in relation to target location of the css file.
|
||||
$flag-icon-css-path: "../fonts/flags/" !default;
|
||||
|
||||
$white: #fff !default;
|
||||
$black: #000 !default;
|
||||
$blue: #0070d2 !default;
|
||||
$green: #008827 !default;
|
||||
// primary is replaced by css variable --skin-primary-color-1
|
||||
$primary: #00a1e0 !default;
|
||||
$red: #c00 !default;
|
||||
$success: $green !default;
|
||||
$danger: $red !default;
|
||||
$light-blue: #7ed0ee !default;
|
||||
|
||||
// Consolidated values
|
||||
$grey1: #f9f9f9 !default;
|
||||
$grey2: #eee !default;
|
||||
$grey3: #ccc !default;
|
||||
$grey4: #999 !default;
|
||||
$grey5: #666 !default;
|
||||
$grey6: #444 !default;
|
||||
$grey7: #222 !default;
|
||||
$grey8: #333 !default;
|
||||
$grey-transparent-1: rgba(0, 0, 0, 0.65) !default;
|
||||
$grey-transparent-2: rgba(0, 0, 0, 0.25) !default;
|
||||
|
||||
$light-gray: $grey1 !default;
|
||||
$slightly-darker-gray: $grey4 !default;
|
||||
$dark-gray: $grey6 !default;
|
||||
$darker-gray: $grey7 !default;
|
||||
$horizontal-rule-grey: $grey3 !default;
|
||||
$product-number-grey: $grey3 !default;
|
||||
$horizontal-border-grey: $grey4 !default;
|
||||
$menu-link: $grey6 !default;
|
||||
$close-menu-bg: $grey2 !default;
|
||||
$link-color: $dark-gray !default;
|
||||
$hr-border-color: $grey3 !default;
|
||||
|
||||
$grid-breakpoints: (
|
||||
xs: 0,
|
||||
sm: 544px,
|
||||
md: 769px,
|
||||
lg: 992px,
|
||||
xl: 1200px
|
||||
) !default;
|
||||
|
||||
$container-max-widths: (
|
||||
md: 720px,
|
||||
lg: 940px,
|
||||
xl: 1140px
|
||||
) !default;
|
||||
|
||||
$border-radius: 0.1875rem !default;
|
||||
$border-radius-lg: $border-radius !default;
|
||||
$border-radius-sm: $border-radius !default;
|
||||
|
||||
$state-danger-text: #fff !default;
|
||||
$alert-success-text: #fff !default;
|
||||
|
||||
// Font sizes
|
||||
$base16-14px: 0.875em !default;
|
||||
|
||||
// Bootstrap overrides
|
||||
$body-bg: $grey1 !default;
|
||||
$card-cap-bg: $white !default;
|
||||
|
||||
// Tabs
|
||||
$nav-tabs-border-width: 0 !default;
|
||||
$nav-tabs-border-radius: 0 !default;
|
||||
$nav-tabs-active-link-hover-bg: transparent !default;
|
||||
|
||||
// breadcrumb
|
||||
$breadcrumb-bg: transparent !default;
|
||||
|
||||
// table border
|
||||
$table-border-color: $grey3 !default;
|
||||
|
||||
$svg-check: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23ff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E") !default;
|
@@ -0,0 +1,62 @@
|
||||
@import "../variables";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins/breakpoints";
|
||||
@import "../components/formFields";
|
||||
|
||||
.account-image {
|
||||
background-image: url(../../images/account.jpg);
|
||||
background-position-y: 40%;
|
||||
}
|
||||
|
||||
.card-footer > a {
|
||||
color: #{var(--skin-primary-color-1)};
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.card-header > a {
|
||||
color: #{var(--skin-primary-color-1)};
|
||||
float: right;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.card-info-group {
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
div {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
div:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.order-history-control,
|
||||
.order-history {
|
||||
h2 {
|
||||
font-weight: bold;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-order-card-image {
|
||||
width: 7rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.dashboard-order-card-footer-columns:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.dashboard-order-card-footer-value {
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.card-header h2,
|
||||
.card-header h3 {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 0;
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
@import "../variables";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins/breakpoints";
|
||||
@import "account";
|
||||
@import "../utilities/deleteCardButton";
|
||||
|
||||
.card-body-positioning {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.card-make-default-link {
|
||||
margin-top: 0.625em; /* 10/16 */
|
||||
}
|
||||
|
||||
.remove-btn {
|
||||
@include delete-card-button();
|
||||
|
||||
width: 3rem;
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
@import "../variables";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins/breakpoints";
|
||||
@import "account";
|
||||
|
||||
.card-footer-border {
|
||||
border-top: 1px dashed $horizontal-border-grey;
|
||||
}
|
||||
|
||||
.card-make-default-link {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.dashboard-cards-block-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.dashboard-order-card-status {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.dashboard-order-card-image {
|
||||
width: 7rem;
|
||||
}
|
||||
|
||||
.account-landing-ordercard {
|
||||
padding: 0;
|
||||
height: 1rem;
|
||||
margin-left: 1.25rem;
|
||||
border-bottom: 0 none;
|
||||
margin-top: 1rem;
|
||||
|
||||
h4 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
div.order-number {
|
||||
padding-top: 0.2rem;
|
||||
}
|
||||
|
||||
.dashboard-cards-block-title {
|
||||
margin-bottom: 1em;
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
@import "../variables";
|
||||
@import "../checkout/checkoutComponents";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins/breakpoints";
|
||||
|
||||
.section-label {
|
||||
font-size: $receipt-font-size;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.my-account {
|
||||
text-align: center;
|
||||
margin-bottom: 0.938em;
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
@import "../variables";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins/breakpoints";
|
||||
@import "account";
|
||||
@import "../utilities/deleteCardButton";
|
||||
@import "../components/creditCardField";
|
||||
|
||||
.back-to-account-link {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.card-body-positioning {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.make-default-payment {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.masked-card-number {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.payment-to-remove {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.remove-btn {
|
||||
@include delete-card-button();
|
||||
|
||||
width: 3rem;
|
||||
}
|
||||
|
||||
.no-saved-payments {
|
||||
font-family: var(--skin-header-font), sans-serif;
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
@import "../variables";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins/breakpoints";
|
||||
@import "account";
|
||||
|
||||
.profile-back-to-account-link {
|
||||
color: #{var(--skin-primary-color-1)};
|
||||
text-decoration: underline;
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tracking-consent {
|
||||
color: #{var(--skin-link-color-1)};
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
@@ -0,0 +1,314 @@
|
||||
@import "variables";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins/breakpoints";
|
||||
@import "utilities/deleteCardButton";
|
||||
@import "components/quickView";
|
||||
|
||||
$spacer: 0.625em;
|
||||
$negative-spacer: -0.625rem;
|
||||
|
||||
.single-approaching-discount {
|
||||
border: 1px solid rgba(0, 0, 0, 0.125);
|
||||
background-color: $white;
|
||||
color: $success;
|
||||
margin-bottom: 0.3125rem;
|
||||
}
|
||||
|
||||
.checkout-continue {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
background-color: rgba(255, 255, 255, 0.95);
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
||||
|
||||
div {
|
||||
padding: $spacer;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
position: static;
|
||||
padding-right: 0.938em;
|
||||
padding-left: 0.938em;
|
||||
}
|
||||
}
|
||||
|
||||
.edit {
|
||||
margin-right: 0.625em;
|
||||
}
|
||||
|
||||
.product-edit {
|
||||
margin-top: auto;
|
||||
|
||||
a {
|
||||
font-size: 0.813em;
|
||||
}
|
||||
}
|
||||
|
||||
.line-item-attributes {
|
||||
font-size: 0.813rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.item-attributes {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.line-item-divider {
|
||||
margin: $spacer $negative-spacer $spacer $negative-spacer;
|
||||
}
|
||||
|
||||
.line-item-name {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
font-size: 1em;
|
||||
color: $darker-gray;
|
||||
font-weight: bold;
|
||||
margin-bottom: $spacer;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.line-item-price {
|
||||
font-size: 1em;
|
||||
color: $darker-gray;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.line-item-price-info {
|
||||
font-size: 0.75em;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.no-margin-top {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.number-of-items {
|
||||
font-size: 1.25rem;
|
||||
margin-top: 1rem;
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.optional-promo {
|
||||
color: #{var(--skin-primary-color-1)};
|
||||
}
|
||||
|
||||
.product-info {
|
||||
margin-bottom: 0.313em;
|
||||
padding: $spacer;
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.product-to-remove {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.item-image {
|
||||
height: 5.625em;
|
||||
width: 5.625em;
|
||||
margin-right: 0.938em;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
|
||||
img.product-image {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
max-height: 5.625em;
|
||||
}
|
||||
}
|
||||
|
||||
.promo-code-form {
|
||||
display: none;
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.promo-code-submit {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.quantity-form {
|
||||
margin-bottom: 0;
|
||||
margin-top: -0.313em;
|
||||
}
|
||||
|
||||
.product-info {
|
||||
.remove-btn {
|
||||
color: $slightly-darker-gray;
|
||||
font-size: 1.625em;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
top: $negative-spacer;
|
||||
right: 0.25rem;
|
||||
border: none;
|
||||
background-color: $white;
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: $negative-spacer;
|
||||
margin-top: $negative-spacer;
|
||||
margin-bottom: $negative-spacer;
|
||||
}
|
||||
}
|
||||
|
||||
.remove-btn-lg {
|
||||
@include delete-card-button();
|
||||
|
||||
padding-left: 0.3125rem;
|
||||
padding-right: 0.3125rem;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.bonus-product {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.remove-line-item {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.remove-coupon {
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.sub-total {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.grand-total {
|
||||
font-size: 1em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.coupon-price-adjustment + .coupon-price-adjustment {
|
||||
margin-top: 0.625rem;
|
||||
}
|
||||
|
||||
.coupon-price-adjustment {
|
||||
background-color: $white;
|
||||
padding: 0.625em;
|
||||
border: 1px solid rgba(0, 0, 0, 0.125);
|
||||
border-radius: 0.1875rem;
|
||||
}
|
||||
|
||||
.coupon-promotion-relationship {
|
||||
font-size: 0.813em;
|
||||
padding-left: 1rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.coupons-and-promos {
|
||||
margin-bottom: 0.625rem;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.coupon-code {
|
||||
font-size: 1.125em;
|
||||
}
|
||||
|
||||
.coupon-applied {
|
||||
color: $success;
|
||||
font-size: 0.813em;
|
||||
}
|
||||
|
||||
.coupon-not-applied {
|
||||
color: $danger;
|
||||
font-size: 0.813em;
|
||||
}
|
||||
|
||||
.coupon-error {
|
||||
color: $danger;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.coupon-missing-error {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.applied-promotion-discount {
|
||||
color: $success;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.promotion-information {
|
||||
margin-bottom: 0.625rem;
|
||||
margin-top: 0.625rem;
|
||||
}
|
||||
|
||||
.line-item-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.bundle-includes {
|
||||
font-size: 0.813em;
|
||||
margin-bottom: 0.625em;
|
||||
}
|
||||
|
||||
.cart-page .bundled-line-item + .bundled-line-item::before,
|
||||
.cart-page .bonus-line-item-row + .bonus-line-item-msg::before {
|
||||
content: "";
|
||||
display: block;
|
||||
border-bottom: 0.063em dashed $horizontal-rule-grey;
|
||||
margin: 0.625em -0.625em;
|
||||
}
|
||||
|
||||
.quantity-label {
|
||||
font-size: 0.813em;
|
||||
}
|
||||
|
||||
.quantity {
|
||||
width: 100%;
|
||||
min-width: 5em;
|
||||
}
|
||||
|
||||
.bundle-misc {
|
||||
font-size: 0.813rem;
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
margin-bottom: 0.625em;
|
||||
}
|
||||
}
|
||||
|
||||
.cart-error-messaging.cart-error {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.valid-cart-error {
|
||||
min-height: 6.5rem;
|
||||
}
|
||||
|
||||
.bundled-line-item {
|
||||
.item-attributes {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.bonus-product-button {
|
||||
margin-right: 1.5em;
|
||||
}
|
@@ -0,0 +1,225 @@
|
||||
@import "bootstrap/scss/functions";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins/breakpoints";
|
||||
|
||||
$checkout-font-weight: 600;
|
||||
|
||||
$receipt-font-size: 0.875rem;
|
||||
$receipt-spacing: 0.625em;
|
||||
$stored-payment-spacing: 1rem;
|
||||
|
||||
.page {
|
||||
background-color: $light-gray;
|
||||
}
|
||||
|
||||
.checkout-card-header {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.grand-total-price {
|
||||
float: right;
|
||||
font-weight: $checkout-font-weight;
|
||||
}
|
||||
|
||||
.grand-total-label {
|
||||
font-weight: $checkout-font-weight;
|
||||
}
|
||||
|
||||
.grand-total {
|
||||
font-size: 1.125rem !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.order-receipt-label {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.product-divider {
|
||||
margin-left: -$receipt-spacing;
|
||||
margin-right: -$receipt-spacing;
|
||||
|
||||
hr {
|
||||
border-top: dashed 0.063em;
|
||||
}
|
||||
}
|
||||
|
||||
.product-line-item + .product-line-item::before,
|
||||
.multi-shipping + .product-line-item::before {
|
||||
content: "";
|
||||
display: block;
|
||||
border-bottom: 0.063em dashed $horizontal-rule-grey;
|
||||
margin: $receipt-spacing -0.625em;
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
margin: $receipt-spacing -1.225em;
|
||||
}
|
||||
}
|
||||
|
||||
.shipment-block + .shipment-block::before {
|
||||
content: "";
|
||||
display: block;
|
||||
border-bottom: 0.063em dashed $horizontal-rule-grey;
|
||||
margin: $receipt-spacing -0.625em;
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
margin: $receipt-spacing -1.225em;
|
||||
}
|
||||
}
|
||||
|
||||
.shipping-method {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hero-confirmation {
|
||||
background-image: url('../../images/thankyou.jpg');
|
||||
background-position-y: -8.125em;
|
||||
}
|
||||
|
||||
.product-summary-block {
|
||||
margin: 1em 0;
|
||||
|
||||
h3 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.leading-lines {
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
|
||||
label {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.start-lines {
|
||||
padding: 1px;
|
||||
|
||||
span {
|
||||
position: relative;
|
||||
background-color: white;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&::before {
|
||||
float: left;
|
||||
width: 0;
|
||||
white-space: nowrap;
|
||||
content: ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ";
|
||||
z-index: 1;
|
||||
color: #adadad;
|
||||
}
|
||||
}
|
||||
|
||||
.end-lines {
|
||||
padding: 1px;
|
||||
|
||||
span {
|
||||
position: relative;
|
||||
background-color: white;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.summary-details {
|
||||
font-size: 0.938em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.summary-details .address-summary {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.summary-section-label {
|
||||
font-size: 1em;
|
||||
font-weight: $checkout-font-weight;
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.add-payment {
|
||||
margin-top: $stored-payment-spacing;
|
||||
}
|
||||
|
||||
.selected-payment {
|
||||
background-color: $gray-200;
|
||||
}
|
||||
|
||||
.saved-security-code {
|
||||
margin-top: $stored-payment-spacing;
|
||||
}
|
||||
|
||||
.saved-credit-card-type {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.saved-payment-information {
|
||||
margin-top: $stored-payment-spacing;
|
||||
margin-bottom: $stored-payment-spacing;
|
||||
}
|
||||
|
||||
.payment-information {
|
||||
margin-bottom: $stored-payment-spacing;
|
||||
}
|
||||
|
||||
.checkout-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.card-image {
|
||||
margin-top: 0.5rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cancel-new-payment {
|
||||
margin-top: $stored-payment-spacing;
|
||||
}
|
||||
|
||||
.form-check.start-lines {
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
|
||||
.multi-ship .single-shipping .shipping-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.multi-ship .shipping-summary .single-shipping {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.gift-message-block {
|
||||
padding-bottom: 1em;
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
.single-shipping .summary-section-label {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.confirm-details .shipping-method,
|
||||
.confirm-details .shipping-method-price {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.multi-ship .confirm-details .single-shipping {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.multi-shipping {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.contact-info-block {
|
||||
border-bottom: 0.063em dashed $horizontal-rule-grey;
|
||||
}
|
||||
|
||||
.view-address-block h3,
|
||||
.shipping-method-block h3 {
|
||||
font-size: 1.25rem;
|
||||
}
|
@@ -0,0 +1,339 @@
|
||||
@import "../variables";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "checkoutComponents";
|
||||
@import "bootstrap/scss/mixins/breakpoints";
|
||||
@import "../components/formFields";
|
||||
@import "../components/creditCardField";
|
||||
|
||||
$checkout-font-weight: 600;
|
||||
|
||||
.card.ghost {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.arrival-time {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.billing-address {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.checkout-checkbox {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
.customer-information-block .btn-link {
|
||||
color: #{var(--skin-link-color-2)};
|
||||
padding: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
.edit-button,
|
||||
.btn-show-details,
|
||||
.btn-add-new {
|
||||
color: #{var(--skin-primary-color-1)};
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-button {
|
||||
border: none;
|
||||
padding: 0;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.next-step-button {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
z-index: 3;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
background-color: rgba(255, 255, 255, 0.95);
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
||||
|
||||
div {
|
||||
padding: $spacer;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
position: static;
|
||||
padding-right: 0.938em;
|
||||
padding-left: 0.938em;
|
||||
}
|
||||
}
|
||||
|
||||
.shipping-methods {
|
||||
font-size: 1.125em;
|
||||
font-weight: $checkout-font-weight;
|
||||
}
|
||||
|
||||
.shipping-method-option {
|
||||
font-size: 0.938em;
|
||||
}
|
||||
|
||||
.shipping-method-pricing {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.multi-ship .multi-shipping {
|
||||
display: block;
|
||||
}
|
||||
|
||||
span.ship-to-name,
|
||||
span.ship-to-address1,
|
||||
span.ship-to-address2,
|
||||
span.ship-to-phone,
|
||||
span.ship-to-city-st-zip {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.data-checkout-stage {
|
||||
// Initial states ------------------------
|
||||
&[data-checkout-stage] {
|
||||
.card.payment-summary,
|
||||
.shipping-summary {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button.place-order {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button.submit-payment {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button.submit-shipping {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Customer ------------------------------
|
||||
&[data-checkout-stage=customer] {
|
||||
.card.ghost.customer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.card.customer-summary {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.card.shipping-section {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.card.payment-form {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button.submit-customer {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
// Shipping ------------------------------
|
||||
&[data-checkout-stage=shipping] {
|
||||
.card.customer-section {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button.submit-customer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.card.ghost.customer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.card.ghost {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.multi-ship .order-product-summary {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.card.payment-form {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button.submit-shipping {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.shipment-selector-block {
|
||||
.btn-show-details,
|
||||
.btn-add-new {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
[data-address-mode=customer] {
|
||||
.shipping-address-block {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
[data-address-mode=shipment] {
|
||||
.shipping-address-form {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
[data-address-mode=edit] {
|
||||
.shipping-address-block {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
[data-address-mode=new] {
|
||||
.btn-show-details,
|
||||
.btn-add-new {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Payment -------------------------------
|
||||
&[data-checkout-stage=payment] {
|
||||
button.submit-customer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.customer-section,
|
||||
.shipping-section,
|
||||
.card.ghost {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.card.payment-form,
|
||||
.shipping-summary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
button.submit-payment {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.address-selector-block {
|
||||
.btn-show-details,
|
||||
.btn-add-new {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
[data-address-mode=customer] {
|
||||
.billing-address {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
[data-address-mode=shipment] {
|
||||
.billing-address {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
[data-address-mode=edit] {
|
||||
.billing-address {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
[data-address-mode=new] {
|
||||
.btn-show-details,
|
||||
.btn-add-new {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
[data-address-mode=details] {
|
||||
.btn-show-details,
|
||||
.btn-add-new {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Place Order -----------------------------
|
||||
&[data-checkout-stage=placeOrder] {
|
||||
button.submit-customer,
|
||||
.customer-section,
|
||||
.shipping-section,
|
||||
.card.payment-form,
|
||||
.card.ghost {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.card.payment-summary,
|
||||
.shipping-summary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
button.place-order {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
&[data-checkout-stage=submitted] {
|
||||
.shipping-form,
|
||||
.card.payment-form,
|
||||
button.submit-customer,
|
||||
.card.ghost {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.summary-section-label.shipping-addr-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.card.payment-summary,
|
||||
.shipping-summary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
button.place-order {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
option[value=new] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
h5 > span {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
[data-customer-type=guest] .single-shipping .shipment-selector-block {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.single-shipping .multi-ship-action-buttons {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.single-shipping .view-address-block {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.btn-show-details {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.multi-ship-address-actions .btn-save-multi-ship {
|
||||
margin-left: 10px;
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
@import "../variables";
|
||||
@import "bootstrap/scss/functions";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins/breakpoints";
|
||||
@import "../components/formFields";
|
||||
|
||||
.login-oauth {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.total-items-label {
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.total-price {
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
@@ -0,0 +1,4 @@
|
||||
.container .breadcrumb {
|
||||
border-radius: 0;
|
||||
border-bottom: $border-width solid $grey3;
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
.category-tile {
|
||||
position: relative;
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
font-size: 1.75rem;
|
||||
position: absolute;
|
||||
bottom: 1.875rem;
|
||||
left: 1.875rem;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: linear-gradient(to bottom, transparent 60%, rgba(0, 0, 0, 0.5) 100%);
|
||||
}
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
@each $size in map-keys($grid-breakpoints) {
|
||||
|
||||
@include media-breakpoint-down($size) {
|
||||
.collapsible-#{$size} {
|
||||
.title {
|
||||
line-height: 2.5rem; /* 40/16 */
|
||||
|
||||
@include clearfix;
|
||||
|
||||
&::after {
|
||||
float: right;
|
||||
content: "\f078";
|
||||
font-family: "FontAwesome";
|
||||
}
|
||||
}
|
||||
|
||||
.content,
|
||||
.card-body {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.active {
|
||||
.title::after {
|
||||
content: "\f077";
|
||||
margin-top: -0.125em; /* 2/16 */
|
||||
}
|
||||
|
||||
.content,
|
||||
.card-body {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.container div.collapsible-#{$size} button.title {
|
||||
color: $black;
|
||||
text-decoration: none;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
.modal-background {
|
||||
background-color: $black;
|
||||
display: none;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
opacity: 0.5;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
input[placeholder] {
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
header ~ #maincontent .container a:not(.btn-primary, .btn-outline-primary) {
|
||||
color: #{var(--skin-link-color-2)};
|
||||
}
|
||||
|
||||
.hide-order-discount {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.hide-shipping-discount {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.order-discount {
|
||||
color: $success;
|
||||
}
|
||||
|
||||
.shipping-discount {
|
||||
color: $success;
|
||||
}
|
||||
|
||||
.error-messaging {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.error-hero {
|
||||
background-image: url('../images/storelocator.jpg');
|
||||
margin-bottom: 0.625em;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
margin-top: 3.125rem;
|
||||
margin-bottom: 3.125rem;
|
||||
}
|
||||
|
||||
.error.continue-shopping {
|
||||
margin-bottom: 6.25em;
|
||||
}
|
||||
|
||||
.error-unassigned-category {
|
||||
color: $red;
|
||||
}
|
||||
|
||||
.skip {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: -4.2em;
|
||||
overflow: hidden;
|
||||
padding: 1em 1.5em;
|
||||
background: $white;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
a.skip:active,
|
||||
a.skip:focus,
|
||||
a.skip:hover {
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: auto;
|
||||
height: auto;
|
||||
z-index: 10000000;
|
||||
background: $white;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.card-header-custom {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 0;
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
.card-number-wrapper {
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url('../../images/credit.png');
|
||||
background-size: contain;
|
||||
width: 48px;
|
||||
height: 30px;
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
&[data-type="visa"]::after {
|
||||
background-image: url('../../images/payment-types.png');
|
||||
background-size: auto;
|
||||
background-position: -162px -110px;
|
||||
}
|
||||
|
||||
&[data-type="mastercard"]::after {
|
||||
background-image: url('../../images/payment-types.png');
|
||||
background-size: auto;
|
||||
background-position: -295px -110px;
|
||||
}
|
||||
|
||||
&[data-type="amex"]::after {
|
||||
background-image: url('../../images/payment-types.png');
|
||||
background-size: auto;
|
||||
background-position: -230px -15px;
|
||||
}
|
||||
|
||||
&[data-type="discover"]::after {
|
||||
background-image: url('../../images/payment-types.png');
|
||||
background-size: auto;
|
||||
background-position: -95px -110px;
|
||||
}
|
||||
}
|
@@ -0,0 +1,145 @@
|
||||
@import "collapsibleItem";
|
||||
@import "toastMessage";
|
||||
|
||||
footer {
|
||||
background-color: $gray-200;
|
||||
padding-top: 1.25em; /* 20/16 */
|
||||
padding-bottom: 1.25em;
|
||||
|
||||
h2 {
|
||||
font-size: $font-size-base;
|
||||
margin-bottom: 0;
|
||||
line-height: 2.5em; /* 40/16 */
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.social {
|
||||
h2 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@include clearfix;
|
||||
}
|
||||
|
||||
.copyright,
|
||||
.social {
|
||||
margin-top: 1.25em;
|
||||
}
|
||||
|
||||
.footer-container .footer-item.collapsible-xs button {
|
||||
font-family: 'Dosis', sans-serif;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.social-links {
|
||||
|
||||
@include clearfix;
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
float: left;
|
||||
|
||||
li {
|
||||
float: left;
|
||||
margin: 0.313em;
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
width: 20%;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: 2.25em;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.store {
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
border-bottom: 1px solid $dark-gray;
|
||||
|
||||
.content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@include clearfix;
|
||||
|
||||
&::after {
|
||||
font-family: "FontAwesome";
|
||||
float: right;
|
||||
content: "\f041";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
font-size: 0.875em;
|
||||
|
||||
li {
|
||||
height: 1.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.copyright,
|
||||
.postscript {
|
||||
font-size: 0.8125em;
|
||||
}
|
||||
|
||||
.copyright {
|
||||
margin-bottom: 0.625em;
|
||||
}
|
||||
|
||||
.back-to-top {
|
||||
margin: 0.1em 0.313em;
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
-webkit-appearance: none;
|
||||
|
||||
i {
|
||||
&.fa-arrow-up {
|
||||
color: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
&.fa-circle {
|
||||
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer-item {
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
border-bottom: 1px solid $dark-gray;
|
||||
}
|
||||
}
|
||||
|
||||
#consent-tracking {
|
||||
.button-wrapper {
|
||||
button {
|
||||
margin: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.email-signup-message {
|
||||
@include toast-message();
|
||||
}
|
||||
|
||||
.email-signup-alert {
|
||||
@include toast-alert();
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
|
||||
.form-group {
|
||||
&.required .form-control-label::before {
|
||||
content: "*";
|
||||
color: $danger;
|
||||
}
|
||||
}
|
@@ -0,0 +1,197 @@
|
||||
@import "menu";
|
||||
|
||||
$banner-padding: 0.3125em;
|
||||
$menu-padding: 0.5em;
|
||||
$menu-item-margin: 0.625em;
|
||||
|
||||
.header {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.navbar-header {
|
||||
height: 4.375em; /* 70/16 */
|
||||
|
||||
.user,
|
||||
.country-selector,
|
||||
.search,
|
||||
.minicart {
|
||||
display: inline-block;
|
||||
margin: 1.125em 0 0 0.5em;
|
||||
}
|
||||
|
||||
.user,
|
||||
.country-selector,
|
||||
.minicart,
|
||||
.navbar-toggler {
|
||||
line-height: 2.25em; /* 36/16 */
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.navbar-toggler {
|
||||
font-size: 1.6em;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.user {
|
||||
position: relative;
|
||||
|
||||
.popover {
|
||||
position: absolute;
|
||||
display: none;
|
||||
padding: 1em;
|
||||
top: 85%;
|
||||
left: 0;
|
||||
|
||||
a {
|
||||
white-space: nowrap;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
&::before {
|
||||
left: 1.5rem;
|
||||
}
|
||||
|
||||
&::after {
|
||||
left: 1.5rem;
|
||||
}
|
||||
|
||||
&.show {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.brand {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
display: block;
|
||||
text-align: center;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
width: 14.125em; /* 226/16 */
|
||||
margin-left: -7.0625em; /* 113/16 */
|
||||
padding-top: 0.5em;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
width: 4em; /* 64/16 */
|
||||
margin-left: -2em;
|
||||
padding-top: 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
.main-menu {
|
||||
background-color: $dark-gray;
|
||||
|
||||
.navbar .close-menu button,
|
||||
.navbar .close-button button {
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
}
|
||||
|
||||
.header-banner {
|
||||
background-color: $darker-gray;
|
||||
text-align: center;
|
||||
color: $white;
|
||||
|
||||
.close-button {
|
||||
width: 1.5em + $banner-padding * 2;
|
||||
|
||||
.close {
|
||||
opacity: 1;
|
||||
color: $white;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #{var(--skin-primary-color-1)};
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-right: 1.5em;
|
||||
padding-top: $banner-padding;
|
||||
padding-bottom: $banner-padding;
|
||||
}
|
||||
}
|
||||
|
||||
.minicart {
|
||||
margin-top: 0.1875em; /* 3/16 */
|
||||
vertical-align: top;
|
||||
|
||||
.minicart-icon {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
a.minicart-link {
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.minicart-quantity {
|
||||
background-color: #{var(--skin-primary-color-1)};
|
||||
border-radius: 50%;
|
||||
width: 1.25em; /* 20/16 */
|
||||
height: 1.25em; /* 20/16 */
|
||||
line-height: normal;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
font-size: 0.8125em; /* 13/16 */
|
||||
position: relative;
|
||||
top: -0.9375em; /* 15/16 */
|
||||
left: -0.9375em; /* 15/16 */
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
a.normal {
|
||||
color: #{var(--skin-primary-color-1)};
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.slide-up {
|
||||
transition-duration: 0.5s;
|
||||
transition-timing-function: ease-in;
|
||||
max-height: 100px;
|
||||
overflow: hidden;
|
||||
|
||||
&.hide {
|
||||
max-height: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-country-selector {
|
||||
margin-top: -0.0625em;
|
||||
}
|
||||
|
||||
.cookie-warning-messaging.cookie-warning {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
text-align: center;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.valid-cookie-warning {
|
||||
background-color: #{var(--skin-link-color-1)};
|
||||
color: $white;
|
||||
white-space: nowrap;
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.2em;
|
||||
padding-right: 2em;
|
||||
}
|
||||
}
|
@@ -0,0 +1,149 @@
|
||||
@import "../utilities/swatch";
|
||||
@import "../variables";
|
||||
|
||||
.site-search {
|
||||
position: relative;
|
||||
height: 2.5em; /* 40/16 */
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
margin-right: 0.5em; /* 20/16 */
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(xl) {
|
||||
width: 20em; /* 320/16 */
|
||||
}
|
||||
|
||||
@include media-breakpoint-only(md) {
|
||||
width: 14.0625em; /* 225/16 */
|
||||
}
|
||||
|
||||
@include media-breakpoint-only(sm) {
|
||||
width: 12.5em; /* 200/16 */
|
||||
}
|
||||
|
||||
.fa-close,
|
||||
.fa-search {
|
||||
position: absolute;
|
||||
border: none;
|
||||
top: 0.5625em; /* 9/16 */
|
||||
right: 0.5625em; /* 9/16 */
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.reset-button {
|
||||
position: absolute;
|
||||
border: none;
|
||||
top: 0.5625em; /* 9/16 */
|
||||
right: 2em; /* 32/16 */
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
input {
|
||||
padding-right: 2rem;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
.header-search {
|
||||
.site-search {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.suggestions-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.suggestions {
|
||||
display: block;
|
||||
position: absolute;
|
||||
border: 1px solid $grey3;
|
||||
background-color: $white;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 21.875rem;
|
||||
z-index: 3;
|
||||
|
||||
@include media-breakpoint-only(xs) {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.swatch-circle {
|
||||
@include swatch(2.5em, $white);
|
||||
}
|
||||
|
||||
.header {
|
||||
color: $grey4;
|
||||
font-size: 0.875em;
|
||||
padding-top: 0.625em;
|
||||
|
||||
&:not(:first-child) {
|
||||
border-top: 1px solid $grey3;
|
||||
}
|
||||
}
|
||||
|
||||
.items {
|
||||
padding: 0.313em 0;
|
||||
}
|
||||
|
||||
.item {
|
||||
padding-bottom: 0.625em;
|
||||
|
||||
.name {
|
||||
margin-top: 0.313em;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
padding-bottom: 0.938em;
|
||||
}
|
||||
}
|
||||
|
||||
.category-parent {
|
||||
color: $grey4;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
.selected {
|
||||
background-color: $grey2;
|
||||
}
|
||||
|
||||
.container {
|
||||
list-style-type: none;
|
||||
}
|
||||
}
|
||||
|
||||
.more-below {
|
||||
-moz-border-radius: 1.25em;
|
||||
background: $grey3;
|
||||
border: 0.063em solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 1.25em;
|
||||
bottom: 1.875em;
|
||||
box-shadow: 0 1px 7px rgba(0, 0, 0, 0.3);
|
||||
display: none;
|
||||
height: 2.5em;
|
||||
position: fixed;
|
||||
right: 1.875em;
|
||||
width: 2.5em;
|
||||
|
||||
i.fa-long-arrow-down {
|
||||
border-radius: 50%;
|
||||
color: $white;
|
||||
display: table-caption;
|
||||
height: 0.75em;
|
||||
font-size: 1.5rem;
|
||||
left: 0.57em;
|
||||
line-height: 0.8em;
|
||||
position: absolute;
|
||||
top: 0.4em;
|
||||
width: 0.8em;
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-family: 'Dosis', sans-serif;
|
||||
}
|
@@ -0,0 +1,104 @@
|
||||
@import "../variables";
|
||||
|
||||
.hero {
|
||||
height: 25vw;
|
||||
background-size: cover;
|
||||
background-position: 50%;
|
||||
position: relative;
|
||||
|
||||
h1.page-title {
|
||||
top: 50%;
|
||||
margin: -1em 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.slant-down {
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 0 solid transparent;
|
||||
border-right-width: 0;
|
||||
border-left-width: 90vw;
|
||||
border-bottom: 4vw solid $body-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.slant-up {
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 0 solid transparent;
|
||||
border-left-width: 0;
|
||||
border-right-width: 90vw;
|
||||
border-top: 4vw solid $body-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h1.page-title {
|
||||
position: relative;
|
||||
color: white;
|
||||
padding: 0.3125em 0.625em 0.3125em $grid-gutter-width / 2;
|
||||
background-color: #{var(--skin-primary-color-1)};
|
||||
display: inline-block;
|
||||
margin: 0.9375em 0;
|
||||
font-size: 1.5rem;
|
||||
|
||||
@include media-breakpoint-up(sm) { font-size: 2rem; }
|
||||
|
||||
@include media-breakpoint-up(md) { font-size: 3rem; }
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
background-color: #{var(--skin-primary-color-1)};
|
||||
height: 100%;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
|
||||
@include media-breakpoint-only(xl) {
|
||||
width: calc((100vw - #{map-get($container-max-widths, xl)}) / 2);
|
||||
left: calc((100vw - #{map-get($container-max-widths, xl)}) / 2 * -1);
|
||||
}
|
||||
|
||||
@include media-breakpoint-only(lg) {
|
||||
width: calc((100vw - #{map-get($container-max-widths, lg)}) / 2);
|
||||
left: calc((100vw - #{map-get($container-max-widths, lg)}) / 2 * -1);
|
||||
}
|
||||
|
||||
@include media-breakpoint-only(md) {
|
||||
width: calc((100vw - #{map-get($container-max-widths, md)}) / 2);
|
||||
left: calc((100vw - #{map-get($container-max-widths, md)}) / 2 * -1);
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-only(xl) {
|
||||
left: calc((100% - #{map-get($container-max-widths, xl)}) / 2);
|
||||
}
|
||||
|
||||
@include media-breakpoint-only(lg) {
|
||||
left: calc((100% - #{map-get($container-max-widths, lg)}) / 2);
|
||||
}
|
||||
|
||||
@include media-breakpoint-only(md) {
|
||||
left: calc((100% - #{map-get($container-max-widths, md)}) / 2);
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
left: 0;
|
||||
}
|
||||
}
|
@@ -0,0 +1,227 @@
|
||||
$breakpoint-name: 'sm';
|
||||
$breakpoint-name: 'sm' !default;
|
||||
$breakpoint-index: index(map-keys($grid-breakpoints), $breakpoint-name);
|
||||
$prev-breakpoint: nth(map-keys($grid-breakpoints), $breakpoint-index - 1);
|
||||
$next-breakpoint: nth(map-keys($grid-breakpoints), $breakpoint-index + 1);
|
||||
|
||||
$slide-out-animation: left 0.5s cubic-bezier(0, 1, 0.5, 1);
|
||||
|
||||
@mixin caret-left() {
|
||||
border-top: 0.3em solid transparent;
|
||||
border-bottom: 0.3em solid transparent;
|
||||
border-right: 0.3em solid;
|
||||
border-left: 0.3 solid transparent;
|
||||
width: 0;
|
||||
height: 0;
|
||||
display: inline-block;
|
||||
margin-bottom: 0.125em;
|
||||
}
|
||||
|
||||
@mixin caret-right() {
|
||||
border-top: 0.3em solid transparent;
|
||||
border-bottom: 0.3em solid transparent;
|
||||
border-left: 0.3em solid;
|
||||
position: absolute;
|
||||
right: 0.3em;
|
||||
margin-top: 0.55em;
|
||||
}
|
||||
|
||||
@each $size in map-keys($grid-breakpoints) {
|
||||
|
||||
@include media-breakpoint-down($size) {
|
||||
.menu-toggleable-left.navbar-toggleable-#{$size} {
|
||||
position: fixed;
|
||||
left: -100%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
transition: $slide-out-animation;
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
|
||||
&.in {
|
||||
min-width: 50%;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.navbar.bg-inverse {
|
||||
background-color: transparent !important;
|
||||
padding: 0;
|
||||
|
||||
@include media-breakpoint-up($next-breakpoint) {
|
||||
.navbar-nav .nav-item + .nav-item {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.navbar-nav .nav-link {
|
||||
padding: 0.8rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-expand-md .navbar-nav.nav-center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.navbar-expand-md .navbar-nav.nav-spaced {
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.navbar-expand-md .navbar-nav.nav-right {
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
.nav-item .nav-link:hover,
|
||||
.nav-item .nav-link:focus,
|
||||
.nav-item.show .nav-link {
|
||||
background-color: $white;
|
||||
color: $menu-link;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up($next-breakpoint) {
|
||||
.nav-item > .nav-link {
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
.main-menu.menu-toggleable-left {
|
||||
|
||||
@include media-breakpoint-down($breakpoint-name) {
|
||||
background-color: $white;
|
||||
z-index: 4;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-toggleable-left {
|
||||
.close-menu {
|
||||
padding: 15px;
|
||||
background-color: $close-menu-bg;
|
||||
border-bottom: 1px solid $grey3;
|
||||
flex: 0 0 100%;
|
||||
|
||||
@include media-breakpoint-up($next-breakpoint) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-group {
|
||||
flex: 0 0 100%;
|
||||
}
|
||||
|
||||
li > .close-menu {
|
||||
margin-right: 0;
|
||||
margin-top: -0.6rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down($breakpoint-name) {
|
||||
.bg-inverse {
|
||||
background-color: white !important;
|
||||
color: $grey7;
|
||||
}
|
||||
}
|
||||
|
||||
&.in {
|
||||
|
||||
@include media-breakpoint-down($prev-breakpoint) {
|
||||
right: 0;
|
||||
margin-right: 1.25em; /* 20/16 */
|
||||
}
|
||||
|
||||
@include media-breakpoint-down($breakpoint-name) {
|
||||
.nav-item + .nav-item {
|
||||
border-top: 1px solid $grey2;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
display: block;
|
||||
position: static;
|
||||
}
|
||||
|
||||
.dropdown-toggle {
|
||||
padding-left: 1rem;
|
||||
|
||||
&::after {
|
||||
@include caret-right();
|
||||
}
|
||||
}
|
||||
|
||||
.nav-item .nav-link {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
.show > .dropdown-menu {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
position: absolute;
|
||||
left: -100%;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0 none;
|
||||
transition: $slide-out-animation;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.multilevel-dropdown {
|
||||
.dropdown-menu {
|
||||
top: 90%;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
|
||||
@include media-breakpoint-up($next-breakpoint) {
|
||||
box-shadow: 0 3px 5px rgba(43, 36, 25, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-item.dropdown > .dropdown-toggle::after {
|
||||
@include caret-right();
|
||||
}
|
||||
|
||||
.dropdown-menu > .dropdown > .dropdown-menu {
|
||||
|
||||
@include media-breakpoint-up($next-breakpoint) {
|
||||
top: -0.65em;
|
||||
left: 99%;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar > .close-menu > .back {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.close-menu .back {
|
||||
.caret-left {
|
||||
@include caret-left();
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
padding: 0 0 0 1em;
|
||||
|
||||
.dropdown-link {
|
||||
display: block;
|
||||
padding: 0.425em 5em 0.425em 0;
|
||||
}
|
||||
|
||||
+ .dropdown-item {
|
||||
border-top: 1px solid $close-menu-bg;
|
||||
}
|
||||
|
||||
&.top-category {
|
||||
font-weight: bold;
|
||||
|
||||
> .nav-link {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,4 @@
|
||||
.notify {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
@import "../variables";
|
||||
|
||||
.price {
|
||||
color: $grey7;
|
||||
|
||||
.strike-through {
|
||||
text-decoration: line-through;
|
||||
color: $grey4;
|
||||
margin-right: 0.938rem;
|
||||
}
|
||||
|
||||
.starting,
|
||||
.range,
|
||||
.sales {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tiered {
|
||||
color: $grey7;
|
||||
|
||||
table {
|
||||
border-top: 1px solid $grey3;
|
||||
margin: 0 auto;
|
||||
|
||||
tr {
|
||||
&:nth-child(odd) {
|
||||
background-color: $grey2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
td,
|
||||
span.price {
|
||||
font-size: 0.875rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 0.313rem;
|
||||
|
||||
&.quantity {
|
||||
font-weight: normal;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&.value {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.table-header {
|
||||
font-size: 1.125rem;
|
||||
padding: 0.313rem;
|
||||
}
|
||||
|
||||
.column-header {
|
||||
font-size: 1rem;
|
||||
padding: 0.313rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.column-header.quantity {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,112 @@
|
||||
@import "toastMessage";
|
||||
|
||||
.attribute {
|
||||
margin-top: 0.938em;
|
||||
|
||||
label {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.swatch a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.primary-images {
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.prices-add-to-cart-actions {
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
z-index: 50;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
left: 0;
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
background-color: rgba(255, 255, 255, 0.95);
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
position: static;
|
||||
padding: 0 0.9375em;
|
||||
}
|
||||
|
||||
.price {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.prices {
|
||||
padding-bottom: 0.5em;
|
||||
padding-top: 0.5em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cart-and-ipay {
|
||||
text-align: center;
|
||||
|
||||
@include media-breakpoint-only(xs) {
|
||||
padding-bottom: 26px;
|
||||
|
||||
.btn {
|
||||
width: 98%;
|
||||
margin: 1%;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add-to-cart-messages {
|
||||
@include toast-message();
|
||||
}
|
||||
|
||||
.add-to-basket-alert {
|
||||
@include toast-alert();
|
||||
}
|
||||
|
||||
.simple-quantity {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.main-attributes {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.size-chart {
|
||||
margin-top: 1.071em;
|
||||
}
|
||||
|
||||
div.availability {
|
||||
margin-top: 1.071em;
|
||||
}
|
||||
|
||||
.bundle-item {
|
||||
padding-bottom: 1em;
|
||||
border-bottom: 1px solid $hr-border-color;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.container.product-detail {
|
||||
margin-top: 2em;
|
||||
margin-bottom: 2em;
|
||||
|
||||
@include media-breakpoint-only(xs) {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.product-option:not(:first-child) {
|
||||
margin-top: 1.071em;
|
||||
}
|
@@ -0,0 +1,176 @@
|
||||
@import "../utilities/swatch";
|
||||
@import "productCommon";
|
||||
@import "quickView";
|
||||
|
||||
.product-tile {
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
min-height: 23.4375em;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
min-height: 19.6875em;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
min-height: 13.4375em;
|
||||
}
|
||||
|
||||
border: 0;
|
||||
margin-bottom: 0;
|
||||
|
||||
.tile-body {
|
||||
padding: 0.625em 0 1.875em;
|
||||
|
||||
.color-swatches {
|
||||
min-height: 2.25em;
|
||||
|
||||
.product-tile-color-label {
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
font-size: 0.9375em;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
font-size: 0.8125em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.price {
|
||||
font-size: 1.125em;
|
||||
margin-bottom: 0;
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
font-size: 1.0625em;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.tiered {
|
||||
font-size: 0.875em;
|
||||
|
||||
.value {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.coming-soon-tile {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pdp-link {
|
||||
line-height: 1.2;
|
||||
|
||||
a {
|
||||
font-size: 1em;
|
||||
text-decoration: none;
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
font-size: 0.9375em;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
font-size: 0.8125em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ratings {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
|
||||
.image-container {
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
|
||||
.quickview {
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
right: 1rem;
|
||||
|
||||
i {
|
||||
&.fa-expand {
|
||||
color: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
&.fa-circle {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
display: block;
|
||||
|
||||
.tile-image {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.swatches {
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.swatch-circle {
|
||||
// $white will be replaced by color image background via Javascript
|
||||
@include swatch(1.8em, $white);
|
||||
}
|
||||
}
|
||||
|
||||
#chooseBonusProductModal {
|
||||
.modal-footer {
|
||||
.container {
|
||||
margin-left: 0;
|
||||
width: 100%;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.select-cbp-container {
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
|
||||
.product-name-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.bonus-quantity,
|
||||
.bonus-option {
|
||||
margin-top: 0.938em;
|
||||
}
|
||||
|
||||
.bonus-quantity-select {
|
||||
min-width: 5em;
|
||||
}
|
||||
|
||||
.select-bonus-product {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.selected-pid {
|
||||
border: 1px solid $grey3;
|
||||
|
||||
.bonus-product-name {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.bonus-product-price {
|
||||
text-align: center;
|
||||
margin-top: 1em;
|
||||
}
|
||||
}
|
@@ -0,0 +1,124 @@
|
||||
@import "../utilities/swatch";
|
||||
@import "productCommon";
|
||||
|
||||
.quick-view-dialog,
|
||||
.choose-bonus-product-dialog {
|
||||
max-width: 56.25em;
|
||||
|
||||
.selectable-bonus-product-line-item {
|
||||
margin-top: 0.2em;
|
||||
margin-bottom: 0.2em;
|
||||
padding-top: 0.3em;
|
||||
padding-bottom: 0.3em;
|
||||
}
|
||||
|
||||
.beenSelected {
|
||||
background-color: $grey2;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
background-color: $grey2;
|
||||
border-bottom: 2px solid #ccc;
|
||||
border-top-left-radius: 0.1875rem;
|
||||
border-top-right-radius: 0.1875rem;
|
||||
|
||||
.full-pdp-link {
|
||||
color: #{var(--skin-primary-color-1)};
|
||||
}
|
||||
|
||||
.close {
|
||||
font-size: 2rem;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.product-name {
|
||||
font-size: 1.875em;
|
||||
}
|
||||
|
||||
.swatch-circle {
|
||||
// $white will be replaced by color image background via Javascript
|
||||
@include swatch(2.5em, $white);
|
||||
}
|
||||
|
||||
a[disabled] .swatch-circle {
|
||||
cursor: not-allowed;
|
||||
|
||||
&.color-value.selected::after {
|
||||
background-color: $gray-700;
|
||||
}
|
||||
}
|
||||
|
||||
.availablity-container {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.availablity-container,
|
||||
.size-chart {
|
||||
margin-top: 0.938em;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
max-height: 28.125em; /* 450/16 */
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
button.close {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
background-color: $white;
|
||||
border: none;
|
||||
border-bottom-right-radius: 0.1875rem;
|
||||
border-bottom-left-radius: 0.1875rem;
|
||||
|
||||
.prices .price {
|
||||
font-size: 1.6em;
|
||||
}
|
||||
}
|
||||
|
||||
.prices .sales {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.promotions {
|
||||
text-align: left;
|
||||
color: $red;
|
||||
}
|
||||
|
||||
.bonus-summary {
|
||||
@include media-breakpoint-down(sm) {
|
||||
font-size: 0.625em;
|
||||
}
|
||||
|
||||
.bonus-product-name {
|
||||
@include media-breakpoint-down(sm) {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pre-cart-products {
|
||||
margin-right: 0.125em;
|
||||
}
|
||||
|
||||
.color-attribute {
|
||||
border: none;
|
||||
padding: 0;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.non-input-label {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
.veil {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
text-align: center;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.underlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.5;
|
||||
background-color: $black;
|
||||
}
|
||||
}
|
||||
|
||||
$spinner-size: 80px;
|
||||
|
||||
.spinner {
|
||||
width: $spinner-size;
|
||||
height: $spinner-size;
|
||||
text-align: center;
|
||||
animation: sk-rotate 2s infinite linear;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-top: $spinner-size / 2 * -1;
|
||||
margin-left: $spinner-size / 2 * -1;
|
||||
}
|
||||
|
||||
.dot1,
|
||||
.dot2 {
|
||||
width: 60%;
|
||||
height: 60%;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
background-color: $white;
|
||||
border-radius: 100%;
|
||||
animation: sk-bounce 2s infinite ease-in-out;
|
||||
}
|
||||
|
||||
.dot2 {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
animation-delay: -1s;
|
||||
}
|
||||
|
||||
@keyframes sk-rotate {
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@keyframes sk-bounce {
|
||||
0%,
|
||||
100% { transform: scale(0); }
|
||||
50% { transform: scale(1); }
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
@import "../variables";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins/breakpoints";
|
||||
|
||||
.form-nav .nav-tabs .nav-link {
|
||||
color: $grey8;
|
||||
}
|
||||
|
||||
.form-nav .nav-tabs .nav-link.active,
|
||||
.form-nav .nav-tabs .nav-link.active:focus,
|
||||
.form-nav .nav-tabs .nav-link.active:hover {
|
||||
background-color: $white;
|
||||
color: $grey8;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-link.active {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
.form-nav .nav-item > .nav-link {
|
||||
color: $grey8;
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
@mixin toast-message() {
|
||||
transform: translate(-50%, -50%);
|
||||
position: fixed;
|
||||
top: 15%;
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
@mixin toast-alert() {
|
||||
animation: fade 5s linear forwards;
|
||||
box-shadow: 1px 1px 5px grey;
|
||||
padding: 1em;
|
||||
|
||||
@keyframes fade {
|
||||
0% { opacity: 0; }
|
||||
10% { opacity: 1; }
|
||||
90% { opacity: 1; }
|
||||
100% { opacity: 0; }
|
||||
}
|
||||
|
||||
&.show {
|
||||
display: block;
|
||||
}
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
$arrow-height: 1.25em; /* 20/16 */
|
||||
|
||||
.info-icon {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
border: none;
|
||||
padding: 0;
|
||||
background: inherit;
|
||||
|
||||
.icon {
|
||||
border-radius: 1.25rem;
|
||||
background-color: #{var(--skin-primary-color-1)};
|
||||
width: 1.5625rem;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
padding: 0.312rem;
|
||||
border-radius: $border-radius;
|
||||
background-color: $grey6;
|
||||
color: $white;
|
||||
font-size: 0.928rem;
|
||||
min-width: 20rem;
|
||||
max-width: 15rem;
|
||||
transform: translate(-50%, -$arrow-height/2);
|
||||
left: 50%;
|
||||
margin-left: 4px;
|
||||
animation: fade-in 0.5s linear forwards;
|
||||
|
||||
@keyframes fade-in {
|
||||
0% { opacity: 0; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
display: block;
|
||||
height: $arrow-height; /* 20/16 */
|
||||
left: 0;
|
||||
bottom: -$arrow-height;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&::after {
|
||||
border-left: solid transparent $arrow-height/2; /* 10/16 */
|
||||
border-right: solid transparent $arrow-height/2; /* 10/16 */
|
||||
border-top: solid $grey6 $arrow-height/2;
|
||||
bottom: -$arrow-height/2;
|
||||
content: " ";
|
||||
height: 0;
|
||||
left: 50%;
|
||||
margin-left: -13px;
|
||||
position: absolute;
|
||||
width: 0;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
@import "variables";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins/breakpoints";
|
||||
@import "components/formFields";
|
||||
@import "components/toastMessage";
|
||||
|
||||
.contact-us-banner {
|
||||
background-image: url('../images/contact-us.jpg');
|
||||
background-position-y: 20%;
|
||||
}
|
||||
|
||||
.contact-us-signup-message {
|
||||
@include toast-message();
|
||||
}
|
||||
|
||||
.contact-us-signup-alert {
|
||||
@include toast-alert();
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
@import "variables";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins/breakpoints";
|
||||
|
||||
.sorry-hero {
|
||||
background-image: url('../images/storelocator.jpg');
|
||||
margin-bottom: 0.625em;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
margin-bottom: 3.125rem;
|
||||
}
|
||||
|
||||
.error-page-content {
|
||||
margin-top: 3.125rem;
|
||||
margin-bottom: 6.25em;
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
@mixin carousel-right-most-element($right) {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: $right;
|
||||
z-index: -1;
|
||||
display: block;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
@mixin carousel-left-most-element($left) {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: $left;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
@mixin carousel-transform($x) {
|
||||
transform: translateX($x);
|
||||
@supports (transform-style: preserve-3d) {
|
||||
transform: translate3d($x, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin carousel-indicators() {
|
||||
padding-bottom: 4.375rem;
|
||||
|
||||
.pd-carousel-indicators {
|
||||
display: flex;
|
||||
}
|
||||
}
|
@@ -0,0 +1,186 @@
|
||||
@import "../../variables";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins/breakpoints";
|
||||
@import "carouselMixins";
|
||||
|
||||
@include media-breakpoint-only(xs) {
|
||||
.carousel.indicators-xs {
|
||||
@include carousel-indicators();
|
||||
}
|
||||
|
||||
.experience-einstein-einsteinCarousel .carousel.insufficient-xs-slides .carousel-control-next,
|
||||
.experience-einstein-einsteinCarousel .carousel.insufficient-xs-slides .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel.insufficient-xs-slides .carousel-control-next,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel.insufficient-xs-slides .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel.insufficient-xs-slides .carousel-control-next,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel.insufficient-xs-slides .carousel-control-prev,
|
||||
.experience-commerce_layouts-carousel .carousel.insufficient-xs-slides .carousel-control-next,
|
||||
.experience-commerce_layouts-carousel .carousel.insufficient-xs-slides .carousel-control-prev {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.experience-einstein-einsteinCarousel .carousel.insufficient-xs-slides,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel.insufficient-xs-slides,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel.insufficient-xs-slides,
|
||||
.experience-commerce_layouts-carousel .carousel.insufficient-xs-slides {
|
||||
padding-bottom: 0 !important;
|
||||
|
||||
.pd-carousel-indicators {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.carousel.controls-xs .carousel-control-next {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.carousel.controls-xs .carousel-control-prev {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
// =============================================================================================
|
||||
|
||||
.experience-einstein-einsteinCarousel .carousel-xs-2 .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarousel .carousel-xs-2 .carousel-control-next,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel-xs-2 .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel-xs-2 .carousel-control-next,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel-xs-2 .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel-xs-2 .carousel-control-next,
|
||||
.experience-commerce_layouts-carousel .carousel-xs-2 .carousel-control-prev,
|
||||
.experience-commerce_layouts-carousel .carousel-xs-2 .carousel-control-next {
|
||||
top: 30%;
|
||||
}
|
||||
|
||||
.carousel-xs-2.indicators-xs {
|
||||
.carousel-control-prev,
|
||||
.carousel-control-next {
|
||||
top: 23%;
|
||||
}
|
||||
}
|
||||
|
||||
.carousel-xs-2 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left),
|
||||
.carousel-xs-2 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left) + .carousel-item {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.carousel-xs-2 .carousel-item-next,
|
||||
.carousel-xs-2 .carousel-item-prev {
|
||||
position: relative;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
.carousel-xs-2 .active.carousel-item + .carousel-item + .carousel-item {
|
||||
@include carousel-right-most-element(-50%);
|
||||
}
|
||||
|
||||
.carousel-xs-2 .carousel-item-prev.carousel-item-right {
|
||||
@include carousel-left-most-element(-50%);
|
||||
@include carousel-transform(100%);
|
||||
}
|
||||
|
||||
.carousel-xs-2 .active.carousel-item-left + .carousel-item-next.carousel-item-left,
|
||||
.carousel-xs-2 .carousel-item-next.carousel-item-left + .carousel-item,
|
||||
.carousel-xs-2 .carousel-item-next.carousel-item-left + .carousel-item + .carousel-item {
|
||||
position: relative;
|
||||
visibility: visible;
|
||||
|
||||
@include carousel-transform(-100%);
|
||||
}
|
||||
|
||||
.carousel-xs-2 .active.carousel-item-right + .carousel-item-prev.carousel-item-right,
|
||||
.carousel-xs-2 .carousel-item-prev.carousel-item-right + .carousel-item,
|
||||
.carousel-xs-2 .carousel-item-prev.carousel-item-right + .carousel-item + .carousel-item {
|
||||
position: relative;
|
||||
visibility: visible;
|
||||
display: block;
|
||||
|
||||
@include carousel-transform(100%);
|
||||
}
|
||||
|
||||
.carousel-xs-2 .active,
|
||||
.carousel-xs-2 .active + .carousel-item {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.experience-einstein-einsteinCarousel .carousel.carousel-xs-2.insufficient-xs-slides .carousel-item,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel.carousel-xs-2.insufficient-xs-slides .carousel-item,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel.carousel-xs-2.insufficient-xs-slides .carousel-item,
|
||||
.experience-commerce_layouts-carousel .carousel.carousel-xs-2.insufficient-xs-slides .carousel-item {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
// =============================================================================================
|
||||
|
||||
.experience-einstein-einsteinCarousel .carousel-xs-3 .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarousel .carousel-xs-3 .carousel-control-next,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel-xs-3 .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel-xs-3 .carousel-control-next,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel-xs-3 .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel-xs-3 .carousel-control-next,
|
||||
.experience-commerce_layouts-carousel .carousel-xs-3 .carousel-control-prev,
|
||||
.experience-commerce_layouts-carousel .carousel-xs-3 .carousel-control-next {
|
||||
top: 20%;
|
||||
}
|
||||
|
||||
.carousel-xs-3.indicators-xs {
|
||||
.carousel-control-prev,
|
||||
.carousel-control-next {
|
||||
top: 13%;
|
||||
}
|
||||
}
|
||||
|
||||
.carousel-xs-3 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left),
|
||||
.carousel-xs-3 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left) + .carousel-item,
|
||||
.carousel-xs-3 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left) + .carousel-item + .carousel-item {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.carousel-xs-3 .carousel-item-next,
|
||||
.carousel-xs-3 .carousel-item-prev {
|
||||
position: relative;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
.carousel-xs-3 .active.carousel-item + .carousel-item + .carousel-item + .carousel-item {
|
||||
@include carousel-right-most-element(-33.3333%);
|
||||
}
|
||||
|
||||
.carousel-xs-3 .carousel-item-prev.carousel-item-right {
|
||||
@include carousel-left-most-element(-33.3333%);
|
||||
@include carousel-transform(100%);
|
||||
}
|
||||
|
||||
.carousel-xs-3 .active.carousel-item-left + .carousel-item-next.carousel-item-left,
|
||||
.carousel-xs-3 .carousel-item-next.carousel-item-left + .carousel-item,
|
||||
.carousel-xs-3 .carousel-item-next.carousel-item-left + .carousel-item + .carousel-item,
|
||||
.carousel-xs-3 .carousel-item-next.carousel-item-left + .carousel-item + .carousel-item + .carousel-item {
|
||||
position: relative;
|
||||
visibility: visible;
|
||||
|
||||
@include carousel-transform(-100%);
|
||||
}
|
||||
|
||||
.carousel-xs-3 .active.carousel-item-right + .carousel-item-prev.carousel-item-right,
|
||||
.carousel-xs-3 .carousel-item-prev.carousel-item-right + .carousel-item,
|
||||
.carousel-xs-3 .carousel-item-prev.carousel-item-right + .carousel-item + .carousel-item,
|
||||
.carousel-xs-3 .carousel-item-prev.carousel-item-right + .carousel-item + .carousel-item + .carousel-item {
|
||||
position: relative;
|
||||
visibility: visible;
|
||||
display: block;
|
||||
|
||||
@include carousel-transform(100%);
|
||||
}
|
||||
|
||||
.carousel-xs-3 .active,
|
||||
.carousel-xs-3 .active + .carousel-item,
|
||||
.carousel-xs-3 .active + .carousel-item + .carousel-item {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.experience-einstein-einsteinCarousel .carousel.carousel-xs-3.insufficient-xs-slides .carousel-item,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel.carousel-xs-3.insufficient-xs-slides .carousel-item,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel.carousel-xs-3.insufficient-xs-slides .carousel-item,
|
||||
.experience-commerce_layouts-carousel .carousel.carousel-xs-3.insufficient-xs-slides .carousel-item {
|
||||
display: block !important;
|
||||
}
|
||||
}
|
@@ -0,0 +1,354 @@
|
||||
@import "../../variables";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins/breakpoints";
|
||||
@import "carouselMixins";
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
.experience-einstein-einsteinCarousel .carousel.insufficient-md-slides .carousel-control-next,
|
||||
.experience-einstein-einsteinCarousel .carousel.insufficient-md-slides .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel.insufficient-md-slides .carousel-control-next,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel.insufficient-md-slides .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel.insufficient-md-slides .carousel-control-next,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel.insufficient-md-slides .carousel-control-prev,
|
||||
.experience-commerce_layouts-carousel .carousel.insufficient-md-slides .carousel-control-next,
|
||||
.experience-commerce_layouts-carousel .carousel.insufficient-md-slides .carousel-control-prev {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.experience-einstein-einsteinCarousel .carousel.insufficient-md-slides,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel.insufficient-md-slides,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel.insufficient-md-slides,
|
||||
.experience-commerce_layouts-carousel .carousel.insufficient-md-slides {
|
||||
padding-bottom: 0 !important;
|
||||
|
||||
.pd-carousel-indicators {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.carousel.indicators-md {
|
||||
@include carousel-indicators();
|
||||
}
|
||||
|
||||
.experience-einstein-einsteinCarousel .carousel.controls-md .carousel-control-next,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel.controls-md .carousel-control-next,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel.controls-md .carousel-control-next,
|
||||
.experience-commerce_layouts-carousel .carousel.controls-md .carousel-control-next {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.experience-einstein-einsteinCarousel .carousel.controls-md .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel.controls-md .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel.controls-md .carousel-control-prev,
|
||||
.experience-commerce_layouts-carousel .carousel.controls-md .carousel-control-prev {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
// =============================================================================================
|
||||
.experience-einstein-einsteinCarousel .carousel-md-2 .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarousel .carousel-md-2 .carousel-control-next,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel-md-2 .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel-md-2 .carousel-control-next,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel-md-2 .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel-md-2 .carousel-control-next,
|
||||
.experience-commerce_layouts-carousel .carousel-md-2 .carousel-control-prev,
|
||||
.experience-commerce_layouts-carousel .carousel-md-2 .carousel-control-next {
|
||||
top: 43%;
|
||||
}
|
||||
|
||||
.carousel-md-2.indicators-md {
|
||||
.carousel-control-prev,
|
||||
.carousel-control-next {
|
||||
top: 36%;
|
||||
}
|
||||
}
|
||||
|
||||
.carousel-md-2 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left),
|
||||
.carousel-md-2 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left) + .carousel-item {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.carousel-md-2 .carousel-item-next,
|
||||
.carousel-md-2 .carousel-item-prev {
|
||||
position: relative;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
.carousel-md-2 .active.carousel-item + .carousel-item + .carousel-item {
|
||||
@include carousel-right-most-element(-50%);
|
||||
}
|
||||
|
||||
.carousel-md-2 .carousel-item-prev.carousel-item-right {
|
||||
@include carousel-left-most-element(-50%);
|
||||
@include carousel-transform(100%);
|
||||
}
|
||||
|
||||
.carousel-md-2 .active.carousel-item-left + .carousel-item-next.carousel-item-left,
|
||||
.carousel-md-2 .carousel-item-next.carousel-item-left + .carousel-item,
|
||||
.carousel-md-2 .carousel-item-next.carousel-item-left + .carousel-item + .carousel-item {
|
||||
position: relative;
|
||||
visibility: visible;
|
||||
|
||||
@include carousel-transform(-100%);
|
||||
}
|
||||
|
||||
.carousel-md-2 .active.carousel-item-right + .carousel-item-prev.carousel-item-right,
|
||||
.carousel-md-2 .carousel-item-prev.carousel-item-right + .carousel-item,
|
||||
.carousel-md-2 .carousel-item-prev.carousel-item-right + .carousel-item + .carousel-item {
|
||||
position: relative;
|
||||
visibility: visible;
|
||||
display: block;
|
||||
|
||||
@include carousel-transform(100%);
|
||||
}
|
||||
|
||||
.carousel-md-2 .active,
|
||||
.carousel-md-2 .active + .carousel-item {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.experience-einstein-einsteinCarousel .carousel.carousel-md-2.insufficient-md-slides .carousel-item,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel.carousel-md-2.insufficient-md-slides .carousel-item,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel.carousel-md-2.insufficient-md-slides .carousel-item,
|
||||
.experience-commerce_layouts-carousel .carousel.carousel-md-2.insufficient-md-slides .carousel-item {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
// =============================================================================================
|
||||
.experience-einstein-einsteinCarousel .carousel-md-3 .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarousel .carousel-md-3 .carousel-control-next,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel-md-3 .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel-md-3 .carousel-control-next,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel-md-3 .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel-md-3 .carousel-control-next,
|
||||
.experience-commerce_layouts-carousel .carousel-md-3 .carousel-control-prev,
|
||||
.experience-commerce_layouts-carousel .carousel-md-3 .carousel-control-next {
|
||||
top: 40%;
|
||||
}
|
||||
|
||||
.carousel-md-3.indicators-md {
|
||||
.carousel-control-prev,
|
||||
.carousel-control-next {
|
||||
top: 33%;
|
||||
}
|
||||
}
|
||||
|
||||
.carousel-md-3 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left),
|
||||
.carousel-md-3 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left) + .carousel-item,
|
||||
.carousel-md-3 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left) + .carousel-item + .carousel-item {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.carousel-md-3 .carousel-item-next,
|
||||
.carousel-md-3 .carousel-item-prev {
|
||||
position: relative;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
.carousel-md-3 .active.carousel-item + .carousel-item + .carousel-item + .carousel-item {
|
||||
@include carousel-right-most-element(-33.3333%);
|
||||
}
|
||||
|
||||
.carousel-md-3 .carousel-item-prev.carousel-item-right {
|
||||
@include carousel-left-most-element(-33.3333%);
|
||||
@include carousel-transform(100%);
|
||||
}
|
||||
|
||||
.carousel-md-3 .active.carousel-item-left + .carousel-item-next.carousel-item-left,
|
||||
.carousel-md-3 .carousel-item-next.carousel-item-left + .carousel-item,
|
||||
.carousel-md-3 .carousel-item-next.carousel-item-left + .carousel-item + .carousel-item,
|
||||
.carousel-md-3 .carousel-item-next.carousel-item-left + .carousel-item + .carousel-item + .carousel-item {
|
||||
position: relative;
|
||||
visibility: visible;
|
||||
|
||||
@include carousel-transform(-100%);
|
||||
}
|
||||
|
||||
.carousel-md-3 .active.carousel-item-right + .carousel-item-prev.carousel-item-right,
|
||||
.carousel-md-3 .carousel-item-prev.carousel-item-right + .carousel-item,
|
||||
.carousel-md-3 .carousel-item-prev.carousel-item-right + .carousel-item + .carousel-item,
|
||||
.carousel-md-3 .carousel-item-prev.carousel-item-right + .carousel-item + .carousel-item + .carousel-item {
|
||||
position: relative;
|
||||
visibility: visible;
|
||||
display: block;
|
||||
|
||||
@include carousel-transform(100%);
|
||||
}
|
||||
|
||||
.carousel-md-3 .active,
|
||||
.carousel-md-3 .active + .carousel-item,
|
||||
.carousel-md-3 .active + .carousel-item + .carousel-item {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.experience-einstein-einsteinCarousel .carousel.carousel-md-3.insufficient-md-slides .carousel-item,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel.carousel-md-3.insufficient-md-slides .carousel-item,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel.carousel-md-3.insufficient-md-slides .carousel-item,
|
||||
.experience-commerce_layouts-carousel .carousel.carousel-md-3.insufficient-md-slides .carousel-item {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
// =============================================================================================
|
||||
.experience-einstein-einsteinCarousel .carousel-md-4 .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarousel .carousel-md-4 .carousel-control-next,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel-md-4 .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel-md-4 .carousel-control-next,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel-md-4 .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel-md-4 .carousel-control-next,
|
||||
.experience-commerce_layouts-carousel .carousel-md-4 .carousel-control-prev,
|
||||
.experience-commerce_layouts-carousel .carousel-md-4 .carousel-control-next {
|
||||
top: 37%;
|
||||
}
|
||||
|
||||
.carousel-md-4.indicators-md {
|
||||
.carousel-control-prev,
|
||||
.carousel-control-next {
|
||||
top: 30%;
|
||||
}
|
||||
}
|
||||
|
||||
.carousel-md-4 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left),
|
||||
.carousel-md-4 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left) + .carousel-item,
|
||||
.carousel-md-4 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left) + .carousel-item + .carousel-item,
|
||||
.carousel-md-4 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left) + .carousel-item + .carousel-item + .carousel-item {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.carousel-md-4 .carousel-item-next,
|
||||
.carousel-md-4 .carousel-item-prev {
|
||||
position: relative;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
.carousel-md-4 .active.carousel-item + .carousel-item + .carousel-item + .carousel-item + .carousel-item {
|
||||
@include carousel-right-most-element(-25%);
|
||||
}
|
||||
|
||||
.carousel-md-4 .carousel-item-prev.carousel-item-right {
|
||||
@include carousel-left-most-element(-25%);
|
||||
@include carousel-transform(100%);
|
||||
}
|
||||
|
||||
.carousel-md-4 .active.carousel-item-left + .carousel-item-next.carousel-item-left,
|
||||
.carousel-md-4 .carousel-item-next.carousel-item-left + .carousel-item,
|
||||
.carousel-md-4 .carousel-item-next.carousel-item-left + .carousel-item + .carousel-item,
|
||||
.carousel-md-4 .carousel-item-next.carousel-item-left + .carousel-item + .carousel-item + .carousel-item,
|
||||
.carousel-md-4 .carousel-item-next.carousel-item-left + .carousel-item + .carousel-item + .carousel-item + .carousel-item {
|
||||
position: relative;
|
||||
visibility: visible;
|
||||
|
||||
@include carousel-transform(-100%);
|
||||
}
|
||||
|
||||
.carousel-md-4 .active.carousel-item-right + .carousel-item-prev.carousel-item-right,
|
||||
.carousel-md-4 .carousel-item-prev.carousel-item-right + .carousel-item,
|
||||
.carousel-md-4 .carousel-item-prev.carousel-item-right + .carousel-item + .carousel-item,
|
||||
.carousel-md-4 .carousel-item-prev.carousel-item-right + .carousel-item + .carousel-item + .carousel-item,
|
||||
.carousel-md-4 .carousel-item-prev.carousel-item-right + .carousel-item + .carousel-item + .carousel-item + .carousel-item {
|
||||
position: relative;
|
||||
visibility: visible;
|
||||
display: block;
|
||||
|
||||
@include carousel-transform(100%);
|
||||
}
|
||||
|
||||
.carousel-md-4 .active,
|
||||
.carousel-md-4 .active + .carousel-item,
|
||||
.carousel-md-4 .active + .carousel-item + .carousel-item,
|
||||
.carousel-md-4 .active + .carousel-item + .carousel-item + .carousel-item {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.experience-einstein-einsteinCarousel .carousel.carousel-md-4.insufficient-md-slides .carousel-item,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel.carousel-md-4.insufficient-md-slides .carousel-item,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel.carousel-md-4.insufficient-md-slides .carousel-item,
|
||||
.experience-commerce_layouts-carousel .carousel.carousel-md-4.insufficient-md-slides .carousel-item {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
// =============================================================================================
|
||||
.experience-einstein-einsteinCarousel .carousel-md-6 .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarousel .carousel-md-6 .carousel-control-next,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel-md-6 .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel-md-6 .carousel-control-next,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel-md-6 .carousel-control-prev,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel-md-6 .carousel-control-next,
|
||||
.experience-commerce_layouts-carousel .carousel-md-6 .carousel-control-prev,
|
||||
.experience-commerce_layouts-carousel .carousel-md-6 .carousel-control-next {
|
||||
top: 29.5%;
|
||||
}
|
||||
|
||||
.carousel-md-6.indicators-md {
|
||||
.carousel-control-prev,
|
||||
.carousel-control-next {
|
||||
top: 22.5%;
|
||||
}
|
||||
}
|
||||
|
||||
.carousel-md-6 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left),
|
||||
.carousel-md-6 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left) + .carousel-item,
|
||||
.carousel-md-6 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left) + .carousel-item + .carousel-item,
|
||||
.carousel-md-6 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left) + .carousel-item + .carousel-item + .carousel-item,
|
||||
.carousel-md-6 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left) + .carousel-item + .carousel-item + .carousel-item + .carousel-item,
|
||||
.carousel-md-6 .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left) + .carousel-item + .carousel-item + .carousel-item + .carousel-item + .carousel-item {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.carousel-md-6 .carousel-item-next,
|
||||
.carousel-md-6 .carousel-item-prev {
|
||||
position: relative;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
.carousel-md-6 .active.carousel-item + .carousel-item + .carousel-item + .carousel-item + .carousel-item + .carousel-item + .carousel-item {
|
||||
@include carousel-right-most-element(-16.66667%);
|
||||
}
|
||||
|
||||
.carousel-md-6 .carousel-item-prev.carousel-item-right {
|
||||
@include carousel-left-most-element(-16.66667%);
|
||||
@include carousel-transform(100%);
|
||||
}
|
||||
|
||||
.carousel-md-6 .active.carousel-item-left + .carousel-item-next.carousel-item-left,
|
||||
.carousel-md-6 .carousel-item-next.carousel-item-left + .carousel-item,
|
||||
.carousel-md-6 .carousel-item-next.carousel-item-left + .carousel-item + .carousel-item,
|
||||
.carousel-md-6 .carousel-item-next.carousel-item-left + .carousel-item + .carousel-item + .carousel-item,
|
||||
.carousel-md-6 .carousel-item-next.carousel-item-left + .carousel-item + .carousel-item + .carousel-item + .carousel-item,
|
||||
.carousel-md-6 .carousel-item-next.carousel-item-left + .carousel-item + .carousel-item + .carousel-item + .carousel-item + .carousel-item,
|
||||
.carousel-md-6 .carousel-item-next.carousel-item-left + .carousel-item + .carousel-item + .carousel-item + .carousel-item + .carousel-item + .carousel-item {
|
||||
position: relative;
|
||||
visibility: visible;
|
||||
|
||||
@include carousel-transform(-100%);
|
||||
}
|
||||
|
||||
.carousel-md-6 .active.carousel-item-right + .carousel-item-prev.carousel-item-right,
|
||||
.carousel-md-6 .carousel-item-prev.carousel-item-right + .carousel-item,
|
||||
.carousel-md-6 .carousel-item-prev.carousel-item-right + .carousel-item + .carousel-item,
|
||||
.carousel-md-6 .carousel-item-prev.carousel-item-right + .carousel-item + .carousel-item + .carousel-item,
|
||||
.carousel-md-6 .carousel-item-prev.carousel-item-right + .carousel-item + .carousel-item + .carousel-item + .carousel-item,
|
||||
.carousel-md-6 .carousel-item-prev.carousel-item-right + .carousel-item + .carousel-item + .carousel-item + .carousel-item + .carousel-item,
|
||||
.carousel-md-6 .carousel-item-prev.carousel-item-right + .carousel-item + .carousel-item + .carousel-item + .carousel-item + .carousel-item + .carousel-item {
|
||||
position: relative;
|
||||
visibility: visible;
|
||||
display: block;
|
||||
|
||||
@include carousel-transform(100%);
|
||||
}
|
||||
|
||||
.carousel-md-6 .active,
|
||||
.carousel-md-6 .active + .carousel-item,
|
||||
.carousel-md-6 .active + .carousel-item + .carousel-item,
|
||||
.carousel-md-6 .active + .carousel-item + .carousel-item + .carousel-item,
|
||||
.carousel-md-6 .active + .carousel-item + .carousel-item + .carousel-item + .carousel-item,
|
||||
.carousel-md-6 .active + .carousel-item + .carousel-item + .carousel-item + .carousel-item + .carousel-item {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.experience-einstein-einsteinCarousel .carousel.carousel-md-6.insufficient-md-slides .carousel-item,
|
||||
.experience-einstein-einsteinCarouselCategory .carousel.carousel-md-6.insufficient-md-slides .carousel-item,
|
||||
.experience-einstein-einsteinCarouselProduct .carousel.carousel-md-6.insufficient-md-slides .carousel-item,
|
||||
.experience-commerce_layouts-carousel .carousel.carousel-md-6.insufficient-md-slides .carousel-item {
|
||||
display: block !important;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user