Skip to content

Instantly share code, notes, and snippets.

@williambsb
Created June 25, 2020 20:29
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save williambsb/72915e277e3b10125ff536b7ee92edff to your computer and use it in GitHub Desktop.
Save williambsb/72915e277e3b10125ff536b7ee92edff to your computer and use it in GitHub Desktop.
Cart Drawer - HC Shopify
<script>
/**
* Module to ajaxify all add to cart forms on the page.
*
* Copyright (c) 2015 Caroline Schnapp (11heavens.com)
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/
Shopify.AjaxifyCart = (function($) {
// Some configuration options.
// I have separated what you will never need to change from what
// you might change.
var _config = {
// What you might want to change
addToCartBtnLabel: 'Add to cart',
addedToCartBtnLabel: 'Thank you!',
addingToCartBtnLabel: 'Adding...',
soldOutBtnLabel: 'Sold Out',
howLongTillBtnReturnsToNormal: 1000, // in milliseconds.
cartCountSelector: '.cart-count, #cart-count a:first, #gocart p a, #cart .checkout em, .item-count, #CartCount',
cartTotalSelector: '#cart-price',
// 'aboveForm' for top of add to cart form,
// 'belowForm' for below the add to cart form, and
// 'nextButton' for next to add to cart button.
feedbackPosition: 'belowForm',
// What you will never need to change
addToCartBtnSelector: '[type="submit"]',
addToCartFormSelector: 'form[action="/cart/add"]',
shopifyAjaxAddURL: '/cart/add.js',
shopifyAjaxCartURL: '/cart.js'
};
// We need some feedback when adding an item to the cart.
// Here it is.
var _showFeedback = function(success, html, $addToCartForm) {
$('.ajaxified-cart-feedback').remove();
var feedback = '<p class="ajaxified-cart-feedback ' + success + '">' + html + '</p>';
switch (_config.feedbackPosition) {
case 'aboveForm':
$addToCartForm.before(feedback);
jQuery('.ajaxify_success_message_container').before(feedback);
break;
case 'belowForm':
$addToCartForm.after(feedback);
jQuery('.ajaxify_success_message_container').after(feedback);
break;
case 'nextButton':
default:
$addToCartForm.find(_config.addToCartBtnSelector).after(feedback);
jQuery('.ajaxify_success_message_container').after(feedback);
break;
}
// If you use animate.css
// $('.ajaxified-cart-feedback').addClass('animated bounceInDown');
$('.ajaxified-cart-feedback').slideDown();
};
var _setText = function($button, label) {
if ($button.children().length) {
$button.children().each(function() {
if ($.trim($(this).text()) !== '') {
$(this).text(label);
}
});
}
else {
$button.val(label).text(label);
}
};
var _init = function() {
$(document).ready(function() {
$(_config.addToCartFormSelector).submit(function(e) {
e.preventDefault();
var $addToCartForm = $(this);
var $addToCartBtn = $addToCartForm.find(_config.addToCartBtnSelector);
_setText($addToCartBtn, _config.addingToCartBtnLabel);
$addToCartBtn.addClass('disabled').prop('disabled', true);
// Add to cart.
$.ajax({
url: _config.shopifyAjaxAddURL,
dataType: 'json',
type: 'post',
data: $addToCartForm.serialize(),
success: function(itemData) {
// Re-enable add to cart button.
$addToCartBtn.addClass('inverted');
_setText($addToCartBtn, _config.addedToCartBtnLabel);
_showFeedback('success','<i class="fa fa-check"></i> Added to cart! <a href="/cart">View cart</a> or <a href="/collections/all">continue shopping</a>.',$addToCartForm);
window.setTimeout(function(){
$addToCartBtn.prop('disabled', false).removeClass('disabled').removeClass('inverted');
_setText($addToCartBtn,_config.addToCartBtnLabel);
}, _config.howLongTillBtnReturnsToNormal);
// Update cart count and show cart link.
$.getJSON(_config.shopifyAjaxCartURL, function(cart) {
var size = cart.item_count;
$('.hc-items-count').text(cart.item_count);
$('.hc-mini-table').remove();
$('.amount').text(Shopify.formatMoney(cart.total_price, Shopify.moneyFormat));
$('.hc-append').append('<table class="hc-mini-table">');
$(cart.items).each(function(index, item) {
$('.hc-mini-table').append('<tr class="item-details" data-id="'+item.id+'"><td class="td-image"><img src="' + item.image + '" /></td><td><div class="mini_cart_title_price"><div>' + item.product_title + '</div> ' + item.variant_title + '<span class="item-price">' + Shopify.formatMoney(item.price, theme.moneyFormat) + '</span></div><a href class="minus-quantity">&minus;</a><input type="text" class="quantity-input" value="' + item.quantity + '"><a href class="plus-quantity">&plus;</a><a class="hc-remove" href="">Remove</a></td></tr>');
});
$('.hc-append').append('</table>');
$('#CartCount > span').text(size);
$(".custom-overlay").toggle();
jQuery('body').addClass('active_slide_cart');
$('div#mini-cart').fadeIn('slow', function(){
setTimeout(function() {
jQuery('body').removeClass('active_slide_cart');
$(".custom-overlay").fadeOut('fast');
}, 5000);
});
if (_config.cartCountSelector && $(_config.cartCountSelector).size()) {
var value = $(_config.cartCountSelector).html() || '0';
$(_config.cartCountSelector).html(value.replace(/[0-9]+/,cart.item_count)).removeClass('hidden-count');
}
if (_config.cartTotalSelector && $(_config.cartTotalSelector).size()) {
if (typeof Currency !== 'undefined' && typeof Currency.moneyFormats !== 'undefined') {
var newCurrency = '';
if ($('[name="currencies"]').size()) {
newCurrency = $('[name="currencies"]').val();
}
else if ($('#currencies span.selected').size()) {
newCurrency = $('#currencies span.selected').attr('data-currency');
}
if (newCurrency) {
$(_config.cartTotalSelector).html('<span class=money>' + Shopify.formatMoney(Currency.convert(cart.total_price, "{{ shop.currency }}", newCurrency), Currency.moneyFormats[newCurrency].money_with_currency_format) + '</span>');
}
else {
$(_config.cartTotalSelector).html(Shopify.formatMoney(cart.total_price, "{{ shop.money_format | remove: "'" | remove: '"' }}"));
}
}
else {
$(_config.cartTotalSelector).html(Shopify.formatMoney(cart.total_price, "{{ shop.money_format | remove: "'" | remove: '"' }}"));
}
};
});
},
error: function(XMLHttpRequest) {
var response = eval('(' + XMLHttpRequest.responseText + ')');
response = response.description;
if (response.slice(0,4) === 'All ') {
_showFeedback('error', response.replace('All 1 ', 'All '), $addToCartForm);
$addToCartBtn.prop('disabled', false);
_setText($addToCartBtn, _config.soldOutBtnLabel);
$addToCartBtn.prop('disabled',true);
}
else {
_showFeedback('error', '<i class="fa fa-warning"></i> ' + response, $addToCartForm);
$addToCartBtn.prop('disabled', false).removeClass('disabled');
_setText($addToCartBtn, _config.addToCartBtnLabel);
}
}
});
return false;
});
});
};
return {
init: function(params) {
// Configuration
params = params || {};
// Merging with defaults.
$.extend(_config, params);
// Action
$(function() {
_init();
});
},
getConfig: function() {
return _config;
}
}
})(jQuery);
Shopify.AjaxifyCart.init();
var Shopify = Shopify || {};
// ---------------------------------------------------------------------------
// Money format handler
// ---------------------------------------------------------------------------
Shopify.money_format = "${{amount}}";
Shopify.formatMoney = function(cents, format) {
if (typeof cents == 'string') { cents = cents.replace('.',''); }
var value = '';
var placeholderRegex = /\{\{\s*(\w+)\s*\}\}/;
var formatString = (format || this.money_format);
function defaultOption(opt, def) {
return (typeof opt == 'undefined' ? def : opt);
}
function formatWithDelimiters(number, precision, thousands, decimal) {
precision = defaultOption(precision, 2);
thousands = defaultOption(thousands, ',');
decimal = defaultOption(decimal, '.');
if (isNaN(number) || number == null) { return 0; }
number = (number/100.0).toFixed(precision);
var parts = number.split('.'),
dollars = parts[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1' + thousands),
cents = parts[1] ? (decimal + parts[1]) : '';
return dollars + cents;
}
switch(formatString.match(placeholderRegex)[1]) {
case 'amount':
value = formatWithDelimiters(cents, 2);
break;
case 'amount_no_decimals':
value = formatWithDelimiters(cents, 0);
break;
case 'amount_with_comma_separator':
value = formatWithDelimiters(cents, 2, '.', ',');
break;
case 'amount_no_decimals_with_comma_separator':
value = formatWithDelimiters(cents, 0, '.', ',');
break;
}
return formatString.replace(placeholderRegex, value);
};
</script>
{% comment %}
If you want to animate your feedback message.
{% endcomment %}
{% comment %}
{{ '//cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.0/animate.min.css' | stylesheet_tag }}
{% endcomment %}
{{ '//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.0.3/css/font-awesome.css' | stylesheet_tag }}
<style>
.ajaxified-cart-feedback {
display: block;
line-height: 36px;
font-size: 90%;
vertical-align: middle;
}
.ajaxified-cart-feedback.success {
color: #3D9970;
}
.ajaxified-cart-feedback.error {
color: #FF4136;
}
.ajaxified-cart-feedback a {
border-bottom: 1px solid;
}
</style>
<div id="mini-cart" class="hc-cartDrawer">
<h4>Cart</h4>
<span class="hc-close" aria-hidden="true">&times;</span>
<div class="count">
<span class="hc-items-count">{{cart.item_count }}</span> item(s) in your cart
</div>
<form action="/cart" method="post" novalidate class="cart">
<div class="hc-append"></div>
<table class="hc-mini-table">
{% for item in cart.items %}
<tr class="item-details" data-id="{{ item.id }}">
<td class="td-image">
<img src="{{ item | img_url: 'x100' }}" />
</td>
<td>
<div class="mini_cart_title_price">
<div>{{ item.title }}</div>
<span class="item-price">{{item.price | money }}</span>
</div>
<a href class="minus-quantity">&minus;</a>
<input type="text" class="quantity-input" value="{{item.quantity}}">
<a href class="plus-quantity">&plus;</a>
<a class="hc-remove" href="">Remove</a>
</td>
</tr>
{% endfor %}
</table>
<div class="hc-buttons action buttons">
<div class="subtotal">
<strong class="float-left">Subtotal </strong>
<strong class="amount">{{ cart.total_price | money }}</strong>
</div>
<a href="/cart" rel="nofollow" class="cart-grey-btn">View Cart</a>
<a class="checkout" href="/checkout" rel="nofollow">Checkout</a>
<div class="additional-checkout-buttons">{{ content_for_additional_checkout_buttons }}</div>
</div>
</form>
</div>
<div class="custom-overlay"></div>
<style>
.additional-checkout-button+.additional-checkout-button, .additional-checkout-button--google-pay {
width: 100% !important;
margin-left: 0;
}
form.cart {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 90vh;
}
body {
-webkit-transition: transform 0.5s ease;
-moz-transition: transform 0.5s ease;
-o-transition: transform 0.5s ease;
transition: transform 0.5s ease;
}
body.active_slide_cart {
position: static;
overflow: hidden !important;
}
@media screen and (max-width: 480px) {
body.active_slide_cart {
position: fixed;
overflow: auto !important;
}
}
#mini-cart {
width: 500px;
position: fixed;
top: 0;
z-index: 999;
background: #f7f7f7;
color: #000;
display: block;
padding: 15px;
height: 100vh;
right: -500px;
bottom: 0;
}
body.active_slide_cart {
-ms-transform: translate(-500px, 0px); /* IE 9 */
-webkit-transform: translate(-500px, 0px); /* Safari */
transform: translate(-500px, 0px);
-webkit-transition: transform 0.5s ease;
-moz-transition: transform 0.5s ease;
-o-transition: transform 0.5s ease;
transition: transform 0.5s ease;
}
#mini-cart .count, #mini-cart .subtotal, #mini-cart .buttons {
padding: 10px;
}
#mini-cart .subtotal {
text-align: right;
padding-right: 5px;
}
#mini-cart .subtotal .amount {
display: inline-block;
padding: 0 10px;
}
#mini-cart table tr, #mini-cart .count {
border-bottom: 1px solid #ccc;
}
#mini-cart table td {
border: none;
padding: 5px;
vertical-align: top;
}
#mini-cart a {
padding: 5px;
}
.hc-mini-table {
overflow-y: auto;
max-height: 500px;
display: block;
}
@media screen and (max-width: 480px) {
.hc-mini-table {
max-height: 300px;
}
}
#mini-cart .action.buttons a {
padding: 16px;
width: 100%;
text-align: center;
display: block;
font-size: 14px;
margin-bottom: 10px;
background: #666;
}
#mini-cart .action.buttons a.checkout {
background: #000;
}
.cart-grey-btn {
background: #666;
color: #fff;
}
#mini-cart a.checkout {
float: right;
background: #000;
color: #fff;
}
#mini-cart .item-price {
float: right;
margin-right: 24px;
margin-top: 18px;
margin-left: 10px;
}
.custom-overlay {
display: none;
position: fixed;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 99;
}
.action.buttons {
overflow: hidden;
position: absolute;
width: 95%;
bottom: 0;
text-transform: uppercase;
}
#mini-cart .action.buttons a:hover {
opacity: .9;
color: #fff;
}
.float-left {
float: left;
}
.hc-close {
float: right;
font-size: 20px;
font-weight: bold;
cursor: pointer;
border-radius: 50%;
width: 21px;
text-align: center;
}
.td-image{
width: 100px;
}
#mini-cart a {
padding: 10px 15px;
background-color: #ffffff;
border: 1px solid #e8e9eb;
}
input.quantity-input {
width: 41px;
display: inline-block;
text-align: center;
padding: 10px 0px;
}
#mini-cart a.hc-remove {
float: right;
vertical-align: top;
display: inline-block;
padding: 0px 5px;
margin-top: 7.5px;
}
.mini_cart_title_price {
display: block;
width: 100%;
clear: both;
position: relative;
margin-bottom: 10px;
}
.mini_cart_title_price div {
display: inline-block;
}
td.td-image img {
max-height: 100px;
height: 100%;
width: initial;
}
#mini-cart .hc-buttons.action.buttons {
z-index: 999999;
position: relative;
}
@media screen and (max-width: 767px) {
#mini-cart {
width: 100%;
}
#mini-cart .item-price,
#mini-cart a.hc-remove {
float: none;
}
#mini-cart .action.buttons a {
padding: 10px;
}
form.cart {
height: 87vh;
}
}
div#mini-cart.mini-cart-popup {
display: none;
}
.mini_cart_trigger {
padding: 11px;
}
div#mini-cart.mini-cart-popup {
right: 0;
height: initial;
top: 40px;
width: 360px;
bottom: initial;
left: initial;
position: absolute;
}
div#mini-cart.mini-cart-popup .hc-append {
max-height: initial;
overflow-x: hidden;
}
div#mini-cart.mini-cart-popup td.td-image img {
max-height: initial;
height: initial;
width: 100%;
vertical-align: middle;
display: inline-block;
}
div#mini-cart.mini-cart-popup .mini_cart_title_price {
font-size: 14px;
}
.mini_cart_trigger:hover + div#mini-cart.mini-cart-popup,
div#mini-cart.mini-cart-popup:hover {
display: block !important; /* Overwriting js script */
}
div#mini-cart.mini-cart-popup table td {
vertical-align: middle;
}
@media screen and (max-width: 767px) {
div#mini-cart.mini-cart-popup {
width: 300px;
}
div#mini-cart.mini-cart-popup .item-price,
div#mini-cart.mini-cart-popup a.hc-remove {
float: right;
clear: both;
display: block;
}
}
</style>
<script>
$(function() {
$('.slide_out_cart_trigger, .custom-overlay').click(function(event) {
event.preventDefault();
$(".custom-overlay").toggle();
jQuery('body').toggleClass('active_slide_cart');
});
$('.hc-close').click(function() {
$(".custom-overlay").hide();
jQuery('body').removeClass('active_slide_cart');
});
$(document).on('click', '.plus-quantity',function(e){
e.preventDefault();
var $input = $(this).siblings('.quantity-input');
var newValue = parseInt($input.val()) + 1;
$input.val(newValue).trigger('change');
return false;
});
$(document).on('click', '.minus-quantity',function(e){
e.preventDefault();
var $input = $(this).siblings('.quantity-input');
var newValue = parseInt($input.val()) - 1;
$input.val(newValue).trigger('change');
return false;
});
$(document).on('click', '.hc-remove',function(e){
e.preventDefault();
var $input = $(this).siblings('.quantity-input');
$input.val('0').trigger('change');
return false;
});
$(document).on('change', '.quantity-input', function() {
var $update = {};
$update[$(this).closest('.item-details').data('id')] = parseInt($(this).val());
$.ajax({
method: 'POST',
datatype: 'json',
data: { updates: $update },
url: '/cart/update.js',
success: function(){
// console.log('success');
},
error: function(message){
if (message['status'] == 200) {
$.getJSON('/cart.js', function(cart) {
var size = cart.item_count;
$('.hc-items-count').text(size);
$('.hc-mini-table').remove();
$('.amount').text(Shopify.formatMoney(cart.total_price, Shopify.moneyFormat));
$('.hc-append').append('<table class="hc-mini-table">');
$(cart.items).each(function(index, item) {
$('.hc-mini-table').append('<tr class="item-details" data-id="'+item.id+'"><td class="td-image"><img src="' + item.image + '" /></td><td><div class="mini_cart_title_price"><div>' + item.product_title + ' ' + item.variant_title + '</div><span class="item-price">' + Shopify.formatMoney(item.price, theme.moneyFormat) + '</span></div><a href class="minus-quantity">&minus;</a><input type="text" class="quantity-input" value="' + item.quantity + '"><a href class="plus-quantity">&plus;</a><a class="hc-remove" href="">Remove</a></td></tr>');
});
$('.hc-append').append('</table>');
$('#CartCount > span').text(size);
});
}
}
});
return false;
});
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment