// "use strict";
var Cart = {
settings: {
_init: false,
form: '#cart',
headerCartCount: 'header .cart .quantity, .cart-count',
itemWrapper: '.cart-item',
itemQuantity: '.quantity input',
itemRemove: '.remove a',
itemPrice: '.price',
itemTotal: '.totalcolumn',
itemUnitPrice: '.unit',
summaryWrapper: '.totals',
summarySubtotal: '.subtotal .amount',
summaryShipping: '.shipping .amount',
summaryDiscount: '.discount .amount',
summaryTax: '.tax .amount',
summaryVat: '.vat .amount',
summaryTotal: '.total .amount',
updateUnitPrice: false,
wishlist: 'body.wishlist',
onchange: $.noop,
afterchange: $.noop,
beforechange: $.noop,
},
init: function(settings) {
var settings = settings || {};
this.settings = _.extend(this.settings, settings);
this.bindUI();
},
bindUI: function() {
var self = this;
$('body').on('keyup', self.settings.itemQuantity, function(e){
self.quantityChange($(this), e);
});
$(self.settings.form).on('keypress', function(e){
var target = $(event.target);
if (target.is(self.settings.itemQuantity)) {
return e.which != 13;
}
});
$(self.settings.itemRemove).on('click', function(e){
return self.removeItem($(this), e);
});
this.settings._init = true;
},
quantityChange: function(field, e) {
var self = this,
quantityField = $(field),
newQuantity = quantityField.val();
if (!isNaN(newQuantity) && parseInt(newQuantity) === 0) {
quantityField.closest(self.settings.itemWrapper).find(self.settings.itemRemove)[0].click();
quantityField.val(1);
}
if (!newQuantity || isNaN(newQuantity) || newQuantity <= 0) {
return false;
}
// Update cart through AJAX
var quantityData = { format: 'json' };
quantityData[quantityField.attr('name')] = newQuantity;
$.getJSON($(self.settings.form).attr('action') + 'update/', quantityData, function(results) {
if(self.settings.beforechange(self, field, results) === false) {
return false;
}
if (newQuantity != quantityField.val()) {
return false;
}
// Cart reload
if (results.reload === true) {
location.reload(true);
}
// Modify quantities if necessary
if (results.updated_quantity) {
//quantityField.val(results.updated_quantity);
}
self.settings.onchange(self, field, results);
if(self.settings.updateUnitPrice && results.item && results.item.price) {
quantityField.closest(self.settings.itemWrapper).find(self.settings.itemPrice).text(results.item.price);
}
if (results.discount_amount) {
$(self.settings.summaryDiscount).currency(-results.discount_amount * 100);
}
if (results.tax_amount) {
$(self.settings.summaryTax).currency(results.tax_amount * 100);
}
self.updateCartDisplay();
// Display error messages if present
if (results.errors) {
for (var i = 0; i < results.errors.length; i++) {
alert(results.errors[i]);
}
}
self.settings.afterchange(self, field, results);
});
self.updateCartDisplay(field);
},
updateCartDisplay: function(field) {
var self = this,
subtotalPrice = 0,
totalPrice = 0,
totalQuantity = 0,
itemQuantity = 0,
totalFields = [
self.settings.summarySubtotal,
self.settings.summaryDiscount,
self.settings.summaryShipping,
self.settings.summaryTax
],
ignoreFields = [
self.settings.summaryVat,
self.settings.summaryTotal
];
// Check quantities on each item
$(self.settings.form).find(self.settings.itemWrapper).each(function() {
var itemPrice = $(this).find(self.settings.itemPrice).text().toCents();
if ($(this).find(self.settings.itemQuantity).length) {
itemQuantity = parseInt($(this).find(self.settings.itemQuantity).val());
} else {
itemQuantity = 1;
}
var itemTotal = itemPrice * itemQuantity;
subtotalPrice += itemTotal;
totalQuantity += itemQuantity;
// Write item total to page
$(this).find(self.settings.itemTotal).currency(itemTotal);
});
// Write subtotal price to page
$(self.settings.summarySubtotal).currency(subtotalPrice);
// Calculate new total
$(self.settings.summaryWrapper).find(totalFields.join(',')).not(ignoreFields.join(',')).each(function() {
totalPrice += $(this).text().toCents();
});
// Zero minium Order total, can be negative when resolving discounts
totalPrice = Math.max(0, totalPrice)
$(self.settings.summaryTotal).currency(totalPrice);
// Write new quantity to page (if its a cart update)
if ($(field).closest('form[action="/cart/"]').length > 0) {
$(self.settings.headerCartCount).text(totalQuantity);
}
},
removeItem: function(item, e) {
var self = this;
var container = $(self.settings.wishlist).length ? 'wishlist' : 'cart';
return confirm('This item will be removed from your ' + container + '.');
}
}
var Crementor = {
settings: {
_init: false,
selector: '[data-widget=crementor]',
decreaseClass: 'decrease',
decreaseText: 'decrease',
decreaseTitle: 'Remove one!',
increaseClass: 'increase',
increaseText: 'increase',
increaseTitle: 'Add another!',
wrapperClass: 'crementor',
},
init: function(settings) {
var settings = settings || {};
this.settings = _.extend(this.settings, settings);
this.bindUI();
this.settings._init = true;
},
bindUI: function() {
var self = this;
$(self.settings.selector).each(function(){
self.markup($(this));
});
},
markup: function(el) {
var self = this,
wrapper = $('
'),
increase = $(''),
decrease = $('');
// Add crementor class to wrapper along with modifier class with form id, like this: 'crementor crementor--cart'
wrapper.addClass('' + self.settings.wrapperClass + ' ' + self.settings.wrapperClass + '--' + el.closest('form').attr('id') + '');
decrease.addClass(self.settings.decreaseClass)
.attr('title', self.settings.decreaseTitle)
.text(self.settings.decreaseText)
.on('click', function(e){
self.change($(this), -1, e);
});
increase.addClass(self.settings.increaseClass)
.attr('title', self.settings.increaseTitle)
.text(self.settings.increaseText)
.on('click', function(e){
self.change($(this), 1, e);
});
el.wrap(wrapper).before(decrease).after(increase);
},
change: function(el, change, e) {
var self = this,
el = $(el),
input = el.parent().find('input'),
max = input.is('[max]') ? parseInt(input.attr('max'), 10) : Infinity,
min = input.is('[min]') ? parseInt(input.attr('min'), 10) : -Infinity,
step = input.is('[step]') ? change * parseInt(input.attr('step'), 10) : change,
val = parseInt(input.val(), 10),
newval = val + step;
if(newval > max || newval < min) {
return false;
}
if(newval != val) {
input.val(newval).trigger('change');
}
}
}
var Minicart = {
/**
* Settings Explained
* form: add to cart form on product detail page
* cartWrapper: selector wrapper around the entire mini cart area
* cartTotal: selector for the subtotal text
* enabled: function that returns a bool for if we should hijack from submission
* empty: markup that will appear when there are no items in your cart
* itemWrapper: wrapper element for a specific cart item in the mini cart
* miniCart: selector for the minicart content that will be replaced with the real cart contents
* messageTime: number of seconds to show messages to the user before they dissappear
* messageWrapper: selector for the wrapper of the messages element
* remove: selector for the remove button
* beforeadd: function that is called before an item is added to the cart
* onadd: function that is called after an item was added to the cart
* failadd: function that is called when the add to cart fails
* beforeremove: function that is called before an item is removed from the cart
* onremove: function that is called after an item was removed from the cart
* failremove: function that is called when the remove from cart fails
*/
settings: {
form: 'form.add',
formItems: '.product-sizes li',
activeClass: 'js-active',
cartWrapper: 'li.cart',
cartTotal: '.amount',
cartQty: '.quantity',
cartAmount: '.amount',
enabled: function(){ return $(parent).width() > 1024 },
empty: 'Nothing in your cart yet.
',
itemWrapper: 'li.cart-item',
hoverTime: 10,
miniCart: '.drop',
messageTime: 5,
messageWrapper: 'ul.messages',
remove: '.remove',
wishlistButton: '[name=wishlist]',
sizeWarning: function(){ return alert('Please select a size!') },
beforeadd: $.noop,
onadd: $.noop,
afteronadd: $.noop,
beforeaddwishlist: function(){},
failadd: $.noop,
beforeremove: $.noop,
onremove: $.noop,
failremove: $.noop
},
hoverTimeout: null,
init: function(settings) {
var settings = settings || {};
this.settings = _.extend(this.settings, settings);
this.bindUI();
},
bindUI: function(){
var self = this;
$('body').on('click', self.settings.wishlistButton, function(e){
if($(this).is('.disabled')) {
var params = [
'product_id=' + $(this).closest('form').find('[name=product_id]').val(),
'item_id=' + $(this).closest('form').find('[name=item_id]').val()
];
if ($(this).closest('form').find('[name=item_id]').val() != '') {
console.log($(this).closest('form').data('wishlist-url') + '?' + params.join('&'));
parent.location.href = $(this).closest('form').data('wishlist-url') + '?' + params.join('&');
return false;
}
}
$(this).closest('form').data('wishlist', true);
setTimeout(function() {
$(this).closest('form').data('wishlist', false);
}, 100);
});
// Sizes as lis instead of a select menu
if ($(self.settings.formItems).length) {
$('body').on('click', self.settings.formItems, function(e){
if ($(this).is('[disabled="disabled"]')) return false;
$(this).addClass("active").siblings().removeClass("active");
$(this).closest(self.settings.form).find('[name="item_id"]').val($(this).data('value'));
});
}
$('body').on('submit', self.settings.form, function(e){
var submitButton = $(this).find('button').not('[name=wishlist]');
submitButton.addClass('loading').prop('disabled', true);
setTimeout(function() {
submitButton.removeClass('loading').prop('disabled', false)
}, 500);
return self.addItem($(this), e);
});
$('body').on('click', self.settings.cartWrapper + ' ' + self.settings.remove, function(e){
return self.removeItem($(this), e);
});
// Hide the minicart if it is a popup based one
$(self.settings.cartWrapper).on('mouseenter mousemove', function(e){
$(this).removeClass(self.settings.activeClass);
clearTimeout(self.hoverTimeout);
});
},
addItem: function(el, e) {
var self = this,
form = el,
params;
// Build the ajax request to add to the form
params = {
'product_id': form.find('[name=product_id]').val(),
'item_id': form.find('[name=item_id]').val()
}
// Check if item is selected
if (!params['item_id']) {
self.settings.sizeWarning();
return false;
}
if (form.data('wishlist') === true) {
if (self.settings.beforeaddwishlist(self) === false) {
return false
}
}
// Don't add to cart for wishlist, or if the entire thing is not enabled (typically a sign of mobile)
if (form.data('wishlist') === true || !self.settings.enabled()) {
return true;
}
$.each(form.serializeArray(), function(index, obj){
params[obj.name] = obj.value;
});
self.params = params;
self.form = form;
if (self.beforeadd(e) !== false) {
self.addToCart(form.attr('action'), self.params);
}
return false;
},
addToCart: function(url, params) {
var self = this,
minicart = parent.$(self.settings.cartWrapper);
params['ajax'] = true;
$.post(url, params, function(data){
minicart.find(self.settings.miniCart).html(data);
minicart.find(self.settings.cartQty).text(minicart.find(self.settings.miniCart).find('[data-quantity]:first').data('quantity'));
minicart.find(self.settings.cartAmount).text(minicart.find(self.settings.miniCart).find('.amount:first').text());
self.onadd();
}).fail(function(data){
self.settings.failadd(self);
console.error('Could not add item to cart', data);
alert('Oops. We had a problem and could not add that to your cart');
});
},
removeItem: function(el, e) {
var self = this,
minicart = parent.$(self.settings.cartWrapper);
// If they are clicking remove we will force the mini cart to show for a while so they can interact with the confirm menu
self.setHover();
// Make sure they confirm removing the item first
if(!confirm('This item will be removed from your cart')) {
return false;
}
self.removeMessages();
self.settings.beforeremove(self, e);
e.preventDefault();
$.getJSON(el.attr('href') + '?format=json', function(data){
// Update the quantity and subtotal
minicart.find(self.settings.cartQty).text(data.quantity);
minicart.find(self.settings.cartTotal).text(data.subtotal_amount.currency());
// Remove this item
el.closest(self.settings.itemWrapper).slideUp(400, function(){
var empty;
$(this).remove();
// If there are no items left in the cart show a message
if(minicart.find(self.settings.itemWrapper).length === 0) {
empty = $(self.settings.empty).hide();
minicart.find(self.settings.miniCart).prepend(empty);
empty.slideDown();
}
});
self.settings.onremove(self);
}).fail(function(data){
self.settings.failremove(self);
console.error('Error removing item from cart', data);
alert('Oops! We had a problem and could not remove that from your cart.');
});
},
beforeadd: function(e) {
var self = this,
minicart = parent.$(self.settings.cartWrapper),
success = true;
if (self.settings.beforeadd(self, e) === false) {
success = false;
}
minicart.addClass('js-loading');
return success;
},
onadd: function() {
var self = this,
minicart = parent.$(self.settings.cartWrapper);
self.settings.onadd(self);
$(self.settings.cartWrapper).removeClass('js-loading');
// Show the hover cart for hoverTime seconds
self.setHover();
// Show Messages
minicart.find(self.settings.messageWrapper).slideDown();
// Hide the message alerts after messageTime seconds
clearTimeout(self.messageTimeout);
self.messageTimeout = setTimeout(function(){
self.removeMessages();
}, self.settings.messageTime * 1000);
self.settings.afteronadd(self);
},
removeMessages: function() {
var self = this,
minicart = parent.$(self.settings.cartWrapper);
clearTimeout(self.messageTimeout);
minicart.find(self.settings.messageWrapper).slideUp(function(){
$(this).remove();
});
},
setHover: function() {
var self = this,
minicart = parent.$(self.settings.cartWrapper);
minicart.addClass(self.settings.activeClass);
clearTimeout(self.hoverTimeout);
self.hoverTimeout = setTimeout(function(){
minicart.removeClass(self.settings.activeClass);
}, self.settings.hoverTime * 1000);
}
}