-
-
Save patrickbolle/3b623bdf80f9ff2d7ceeaaf49aa59faa to your computer and use it in GitHub Desktop.
| /*============================================================================ | |
| Ajax the add to cart experience by revealing it in a side drawer | |
| Plugin Documentation - http://shopify.github.io/Timber/#ajax-cart | |
| (c) Copyright 2015 Shopify Inc. Author: Carson Shold (@cshold). All Rights Reserved. | |
| This file includes: | |
| - Basic Shopify Ajax API calls | |
| - Ajax cart plugin | |
| This requires: | |
| - jQuery 1.8+ | |
| - handlebars.min.js (for cart template) | |
| - modernizer.min.js | |
| - snippet/ajax-cart-template.liquid | |
| Customized version of Shopify's jQuery API | |
| (c) Copyright 2009-2015 Shopify Inc. Author: Caroline Schnapp. All Rights Reserved. | |
| ==============================================================================*/ | |
| if ((typeof ShopifyAPI) === 'undefined') { ShopifyAPI = {}; } | |
| /*============================================================================ | |
| API Helper Functions | |
| ==============================================================================*/ | |
| function attributeToString(attribute) { | |
| if ((typeof attribute) !== 'string') { | |
| attribute += ''; | |
| if (attribute === 'undefined') { | |
| attribute = ''; | |
| } | |
| } | |
| return jQuery.trim(attribute); | |
| }; | |
| /*============================================================================ | |
| API Functions | |
| ==============================================================================*/ | |
| ShopifyAPI.onCartUpdate = function(cart) { | |
| // alert('There are now ' + cart.item_count + ' items in the cart.'); | |
| }; | |
| ShopifyAPI.updateCartNote = function(note, callback) { | |
| var params = { | |
| type: 'POST', | |
| url: '/cart/update.js', | |
| data: 'note=' + attributeToString(note), | |
| dataType: 'json', | |
| success: function(cart) { | |
| if ((typeof callback) === 'function') { | |
| callback(cart); | |
| } | |
| else { | |
| ShopifyAPI.onCartUpdate(cart); | |
| } | |
| }, | |
| error: function(XMLHttpRequest, textStatus) { | |
| ShopifyAPI.onError(XMLHttpRequest, textStatus); | |
| } | |
| }; | |
| jQuery.ajax(params); | |
| }; | |
| ShopifyAPI.onError = function(XMLHttpRequest, textStatus) { | |
| var data = eval('(' + XMLHttpRequest.responseText + ')'); | |
| if (!!data.message) { | |
| alert(data.message + '(' + data.status + '): ' + data.description); | |
| } | |
| }; | |
| /*============================================================================ | |
| POST to cart/add.js returns the JSON of the cart | |
| - Allow use of form element instead of just id | |
| - Allow custom error callback | |
| ==============================================================================*/ | |
| ShopifyAPI.addItemFromForm = function(form, callback, errorCallback) { | |
| var params = { | |
| type: 'POST', | |
| url: '/cart/add.js', | |
| data: jQuery(form).serialize(), | |
| dataType: 'json', | |
| success: function(line_item) { | |
| if (typeof(upsell_main) === "function") { | |
| upsell_main(); | |
| } | |
| if (typeof(upsell_offer) === "function") { | |
| upsell_offer(); | |
| jQuery('#giveacceptbtn,#giveclosebtn,.close_image,#facebox_overlay').on('click', function(){ | |
| if((typeof callback) === "function") { | |
| callback(line_item) | |
| } else { | |
| Shopify.api.onItemAdded(line_item) | |
| } | |
| }); | |
| } else { | |
| if((typeof callback) === "function") { | |
| callback(line_item) | |
| } else { | |
| Shopify.api.onItemAdded(line_item) | |
| } | |
| } | |
| }, | |
| error: function(XMLHttpRequest, textStatus) { | |
| if ((typeof errorCallback) === 'function') { | |
| errorCallback(XMLHttpRequest, textStatus); | |
| } | |
| else { | |
| ShopifyAPI.onError(XMLHttpRequest, textStatus); | |
| } | |
| } | |
| }; | |
| jQuery.ajax(params); | |
| }; | |
| // Get from cart.js returns the cart in JSON | |
| ShopifyAPI.getCart = function(callback) { | |
| jQuery.getJSON('/cart.js', function (cart, textStatus) { | |
| if ((typeof callback) === 'function') { | |
| callback(cart); | |
| } | |
| else { | |
| ShopifyAPI.onCartUpdate(cart); | |
| } | |
| }); | |
| }; | |
| // POST to cart/change.js returns the cart in JSON | |
| ShopifyAPI.changeItem = function(line, quantity, callback) { | |
| var params = { | |
| type: 'POST', | |
| url: '/cart/change.js', | |
| data: 'quantity=' + quantity + '&line=' + line, | |
| dataType: 'json', | |
| success: function(cart) { | |
| if ((typeof callback) === 'function') { | |
| callback(cart); | |
| } | |
| else { | |
| ShopifyAPI.onCartUpdate(cart); | |
| } | |
| }, | |
| error: function(XMLHttpRequest, textStatus) { | |
| ShopifyAPI.onError(XMLHttpRequest, textStatus); | |
| } | |
| }; | |
| jQuery.ajax(params); | |
| }; | |
| /*============================================================================ | |
| Ajax Shopify Add To Cart | |
| ==============================================================================*/ | |
| var ajaxCart = (function(module, $) { | |
| 'use strict'; | |
| // Public functions | |
| var init, loadCart; | |
| // Private general variables | |
| var settings, isUpdating, $body; | |
| // Private plugin variables | |
| var $formContainer, $addToCart, $cartCountSelector, $cartCostSelector, $cartContainer, $drawerContainer; | |
| // Private functions | |
| var updateCountPrice, formOverride, itemAddedCallback, itemErrorCallback, cartUpdateCallback, buildCart, cartCallback, adjustCart, adjustCartCallback, createQtySelectors, qtySelectors, validateQty; | |
| /*============================================================================ | |
| Initialise the plugin and define global options | |
| ==============================================================================*/ | |
| init = function (options) { | |
| // Default settings | |
| settings = { | |
| formSelector : 'form[action^="/cart/add"]', | |
| cartContainer : '#CartContainer', | |
| addToCartSelector : 'input[type="submit"]', | |
| cartCountSelector : null, | |
| cartCostSelector : null, | |
| moneyFormat : '${{amount}}', | |
| disableAjaxCart : false, | |
| enableQtySelectors : true | |
| }; | |
| // Override defaults with arguments | |
| $.extend(settings, options); | |
| // Select DOM elements | |
| $formContainer = $(settings.formSelector); | |
| $cartContainer = $(settings.cartContainer); | |
| $addToCart = $formContainer.find(settings.addToCartSelector); | |
| $cartCountSelector = $(settings.cartCountSelector); | |
| $cartCostSelector = $(settings.cartCostSelector); | |
| // General Selectors | |
| $body = $('body'); | |
| // Track cart activity status | |
| isUpdating = false; | |
| // Setup ajax quantity selectors on the any template if enableQtySelectors is true | |
| if (settings.enableQtySelectors) { | |
| qtySelectors(); | |
| } | |
| // Take over the add to cart form submit action if ajax enabled | |
| if (!settings.disableAjaxCart && $addToCart.length) { | |
| formOverride(); | |
| } | |
| // Run this function in case we're using the quantity selector outside of the cart | |
| adjustCart(); | |
| }; | |
| loadCart = function () { | |
| $body.addClass('drawer--is-loading'); | |
| ShopifyAPI.getCart(cartUpdateCallback); | |
| }; | |
| updateCountPrice = function (cart) { | |
| if ($cartCountSelector) { | |
| $cartCountSelector.html(cart.item_count).removeClass('hidden-count'); | |
| if (cart.item_count === 0) { | |
| $cartCountSelector.addClass('hidden-count'); | |
| } | |
| } | |
| if ($cartCostSelector) { | |
| $cartCostSelector.html(Shopify.formatMoney(cart.total_price, settings.moneyFormat)); | |
| } | |
| }; | |
| formOverride = function () { | |
| $formContainer.on('submit', function(evt) { | |
| evt.preventDefault(); | |
| // Add class to be styled if desired | |
| $addToCart.removeClass('is-added').addClass('is-adding'); | |
| // Remove any previous quantity errors | |
| $('.qty-error').remove(); | |
| ShopifyAPI.addItemFromForm(evt.target, itemAddedCallback, itemErrorCallback); | |
| }); | |
| }; | |
| itemAddedCallback = function (product) { | |
| $addToCart.removeClass('is-adding').addClass('is-added'); | |
| ShopifyAPI.getCart(cartUpdateCallback); | |
| }; | |
| itemErrorCallback = function (XMLHttpRequest, textStatus) { | |
| var data = eval('(' + XMLHttpRequest.responseText + ')'); | |
| $addToCart.removeClass('is-adding is-added'); | |
| if (!!data.message) { | |
| if (data.status == 422) { | |
| $formContainer.after('<div class="errors qty-error">'+ data.description +'</div>') | |
| } | |
| } | |
| }; | |
| cartUpdateCallback = function (cart) { | |
| // Update quantity and price | |
| updateCountPrice(cart); | |
| buildCart(cart); | |
| }; | |
| buildCart = function (cart) { | |
| // Start with a fresh cart div | |
| $cartContainer.empty(); | |
| // Show empty cart | |
| if (cart.item_count === 0) { | |
| $cartContainer | |
| .append('<p>' + {{ 'cart.general.empty' | t | json }} + '</p>'); | |
| cartCallback(cart); | |
| return; | |
| } | |
| // Handlebars.js cart layout | |
| var items = [], | |
| item = {}, | |
| data = {}, | |
| source = $("#CartTemplate").html(), | |
| template = Handlebars.compile(source); | |
| // Add each item to our handlebars.js data | |
| $.each(cart.items, function(index, cartItem) { | |
| /* Hack to get product image thumbnail | |
| * - If image is not null | |
| * - Remove file extension, add _small, and re-add extension | |
| * - Create server relative link | |
| * - A hard-coded url of no-image | |
| */ | |
| if (cartItem.image != null){ | |
| var prodImg = cartItem.image.replace(/(\.[^.]*)$/, "_small$1").replace('http:', ''); | |
| } else { | |
| var prodImg = "//cdn.shopify.com/s/assets/admin/no-image-medium-cc9732cb976dd349a0df1d39816fbcc7.gif"; | |
| } | |
| // Create item's data object and add to 'items' array | |
| item = { | |
| id: cartItem.variant_id, | |
| line: index + 1, // Shopify uses a 1+ index in the API | |
| url: cartItem.url, | |
| img: prodImg, | |
| name: cartItem.product_title, | |
| variation: cartItem.variant_title, | |
| properties: cartItem.properties, | |
| itemAdd: cartItem.quantity + 1, | |
| itemMinus: cartItem.quantity - 1, | |
| itemQty: cartItem.quantity, | |
| price: Shopify.formatMoney(cartItem.price, settings.moneyFormat), | |
| vendor: cartItem.vendor | |
| }; | |
| items.push(item); | |
| }); | |
| // Gather all cart data and add to DOM | |
| data = { | |
| items: items, | |
| note: cart.note, | |
| totalPrice: Shopify.formatMoney(cart.total_price, settings.moneyFormat) | |
| } | |
| $cartContainer.append(template(data)); | |
| cartCallback(cart); | |
| }; | |
| cartCallback = function(cart) { | |
| $body.removeClass('drawer--is-loading'); | |
| $body.trigger('ajaxCart.afterCartLoad', cart); | |
| if (window.Shopify && Shopify.StorefrontExpressButtons) { | |
| Shopify.StorefrontExpressButtons.initialize(); | |
| } | |
| }; | |
| adjustCart = function () { | |
| // Delegate all events because elements reload with the cart | |
| // Add or remove from the quantity | |
| $body.on('click', '.ajaxcart__qty-adjust', function() { | |
| var $el = $(this), | |
| line = $el.data('line'), | |
| $qtySelector = $el.siblings('.ajaxcart__qty-num'), | |
| qty = parseInt($qtySelector.val().replace(/\D/g, '')); | |
| var qty = validateQty(qty); | |
| // Add or subtract from the current quantity | |
| if ($el.hasClass('ajaxcart__qty--plus')) { | |
| qty += 1; | |
| } else { | |
| qty -= 1; | |
| if (qty <= 0) qty = 0; | |
| } | |
| // If it has a data-line, update the cart. | |
| // Otherwise, just update the input's number | |
| if (line) { | |
| updateQuantity(line, qty); | |
| } else { | |
| $qtySelector.val(qty); | |
| } | |
| }); | |
| // Update quantity based on input on change | |
| $body.on('change', '.ajaxcart__qty-num', function() { | |
| var $el = $(this), | |
| line = $el.data('line'), | |
| qty = parseInt($el.val().replace(/\D/g, '')); | |
| var qty = validateQty(qty); | |
| // If it has a data-line, update the cart | |
| if (line) { | |
| updateQuantity(line, qty); | |
| } | |
| }); | |
| // Prevent cart from being submitted while quantities are changing | |
| $body.on('submit', 'form.ajaxcart', function(evt) { | |
| if (isUpdating) { | |
| evt.preventDefault(); | |
| } | |
| }); | |
| // Highlight the text when focused | |
| $body.on('focus', '.ajaxcart__qty-adjust', function() { | |
| var $el = $(this); | |
| setTimeout(function() { | |
| $el.select(); | |
| }, 50); | |
| }); | |
| function updateQuantity(line, qty) { | |
| isUpdating = true; | |
| // Add activity classes when changing cart quantities | |
| var $row = $('.ajaxcart__row[data-line="' + line + '"]').addClass('is-loading'); | |
| if (qty === 0) { | |
| $row.parent().addClass('is-removed'); | |
| } | |
| // Slight delay to make sure removed animation is done | |
| setTimeout(function() { | |
| ShopifyAPI.changeItem(line, qty, adjustCartCallback); | |
| }, 250); | |
| } | |
| // Save note anytime it's changed | |
| $body.on('change', 'textarea[name="note"]', function() { | |
| var newNote = $(this).val(); | |
| // Update the cart note in case they don't click update/checkout | |
| ShopifyAPI.updateCartNote(newNote, function(cart) {}); | |
| }); | |
| }; | |
| adjustCartCallback = function (cart) { | |
| isUpdating = false; | |
| // Update quantity and price | |
| updateCountPrice(cart); | |
| // Reprint cart on short timeout so you don't see the content being removed | |
| setTimeout(function() { | |
| ShopifyAPI.getCart(buildCart); | |
| }, 150) | |
| }; | |
| createQtySelectors = function() { | |
| // If there is a normal quantity number field in the ajax cart, replace it with our version | |
| if ($('input[type="number"]', $cartContainer).length) { | |
| $('input[type="number"]', $cartContainer).each(function() { | |
| var $el = $(this), | |
| currentQty = $el.val(); | |
| var itemAdd = currentQty + 1, | |
| itemMinus = currentQty - 1, | |
| itemQty = currentQty; | |
| var source = $("#AjaxQty").html(), | |
| template = Handlebars.compile(source), | |
| data = { | |
| id: $el.data('id'), | |
| itemQty: itemQty, | |
| itemAdd: itemAdd, | |
| itemMinus: itemMinus | |
| }; | |
| // Append new quantity selector then remove original | |
| $el.after(template(data)).remove(); | |
| }); | |
| } | |
| }; | |
| qtySelectors = function() { | |
| // Change number inputs to JS ones, similar to ajax cart but without API integration. | |
| // Make sure to add the existing name and id to the new input element | |
| var numInputs = $('input[type="number"]'); | |
| if (numInputs.length) { | |
| numInputs.each(function() { | |
| var $el = $(this), | |
| currentQty = $el.val(), | |
| inputName = $el.attr('name'), | |
| inputId = $el.attr('id'); | |
| var itemAdd = currentQty + 1, | |
| itemMinus = currentQty - 1, | |
| itemQty = currentQty; | |
| var source = $("#JsQty").html(), | |
| template = Handlebars.compile(source), | |
| data = { | |
| id: $el.data('id'), | |
| itemQty: itemQty, | |
| itemAdd: itemAdd, | |
| itemMinus: itemMinus, | |
| inputName: inputName, | |
| inputId: inputId | |
| }; | |
| // Append new quantity selector then remove original | |
| $el.after(template(data)).remove(); | |
| }); | |
| // Setup listeners to add/subtract from the input | |
| $('.js-qty__adjust').on('click', function() { | |
| var $el = $(this), | |
| id = $el.data('id'), | |
| $qtySelector = $el.siblings('.js-qty__num'), | |
| qty = parseInt($qtySelector.val().replace(/\D/g, '')); | |
| var qty = validateQty(qty); | |
| // Add or subtract from the current quantity | |
| if ($el.hasClass('js-qty__adjust--plus')) { | |
| qty += 1; | |
| } else { | |
| qty -= 1; | |
| if (qty <= 1) qty = 1; | |
| } | |
| // Update the input's number | |
| $qtySelector.val(qty); | |
| }); | |
| } | |
| }; | |
| validateQty = function (qty) { | |
| if((parseFloat(qty) == parseInt(qty)) && !isNaN(qty)) { | |
| // We have a valid number! | |
| } else { | |
| // Not a number. Default to 1. | |
| qty = 1; | |
| } | |
| return qty; | |
| }; | |
| module = { | |
| init: init, | |
| load: loadCart | |
| }; | |
| return module; | |
| }(ajaxCart || {}, jQuery)); |
Hi, how do you edit this file inside assets folder, when I do a view source of the page I see it is referencing ajax-cart.js instead of ajax-cart.js.liquid but when I go to my assets folder I don't see the file, but when I download the theme I see the file :(
Can't even find documentation to point to how this can be edited?
Any pointers would be great
Thanks.
Hi @cinghaman !
Hmm, really depends on the theme - it could be in the snippets folder rather than the Assets folder!
Hi, how do you edit this file inside assets folder, when I do a view source of the page I see it is referencing ajax-cart.js instead of ajax-cart.js.liquid but when I go to my assets folder I don't see the file, but when I download the theme I see the file :(
Can't even find documentation to point to how this can be edited?
Any pointers would be great
Thanks.Hi @cinghaman !
Hmm, really depends on the theme - it could be in the snippets folder rather than the Assets folder!
Thanks for quick reply, when i try to re-upload the file in assets folder it says file already exist but i cant see it and when I download the theme i do see this file in assets folder
is there a way to de-compile the liquid js file and update the code i want to update and re-compile?
Hmm, I'm not too sure man. The file must be there if it is giving you that error, so it could be a browser bug or Shopify bug perhaps? Sorry can't be of much help here but this is very theme/store specific.
…
On Mon, Sep 21, 2020, at 11:58, Amanpreet Singh wrote: @.**** commented on this gist. >> Hi, how do you edit this file inside assets folder, when I do a view source of the page I see it is referencing ajax-cart.js instead of ajax-cart.js.liquid but when I go to my assets folder I don't see the file, but when I download the theme I see the file :( >> Can't even find documentation to point to how this can be edited? >> Any pointers would be great >> Thanks. > Hi @cinghaman https://github.com/cinghaman ! > Hmm, really depends on the theme - it could be in the snippets folder rather than the Assets folder! Thanks for quick reply, when i try to re-upload the file in assets folder it says file already exist but i cant see it and when I download the theme i do see this file in assets folder is there a way to de-compile the liquid js file and update the code i want to update and re-compile? — You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://gist.github.com/3b623bdf80f9ff2d7ceeaaf49aa59faa#gistcomment-3461847, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACUARXKH2T4HWHOOJPBLXDDSG5Z3FANCNFSM4RUWN33Q.
Thank you for quick reply :)
Hi, how do you edit this file inside assets folder, when I do a view source of the page I see it is referencing ajax-cart.js instead of ajax-cart.js.liquid but when I go to my assets folder I don't see the file, but when I download the theme I see the file :(
Can't even find documentation to point to how this can be edited?
Any pointers would be great
Thanks.