// "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); } }