Skip to content
This repository has been archived by the owner on Aug 30, 2018. It is now read-only.

Moved product JS to external file (mostly) #220

Merged
merged 7 commits into from
Sep 3, 2014
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions assets/ajaxify.js.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,6 @@ var ajaxifyShopify = (function(module, $) {
qty = parseInt( qtySelector.val().replace(/\D/g, '') );

var qty = validateQty(qty);
console.log('1: ' + qty);

// Add or subtract from the current quantity
if (el.hasClass('ajaxifyCart--add')) {
Expand Down Expand Up @@ -927,7 +926,6 @@ var ajaxifyShopify = (function(module, $) {
qty = parseInt( el.val().replace(/\D/g, '') );

var qty = validateQty(qty);
console.log('2: ' + qty);

// Only update the cart via ajax if we have a variant ID to work with
if (id) {
Expand Down Expand Up @@ -1083,7 +1081,6 @@ var ajaxifyShopify = (function(module, $) {
qty = parseInt( qtySelector.val().replace(/\D/g, '') );

var qty = validateQty(qty);
console.log('3: ' + qty);

// Add or subtract from the current quantity
if (el.hasClass('js--add')) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😧

Expand Down
57 changes: 56 additions & 1 deletion assets/shop.js.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ timber.cacheSelectors = function () {

// Product Page
$productImage: $('#productPhotoImg'),
$thumbImages: $('#productThumbs').find('a.product-photo-thumb')
$thumbImages: $('#productThumbs').find('a.product-photo-thumb'),
$addToCart: $('#addToCart'),
$productPrice: $('#productPrice'),
$comparePrice: $('#comparePrice'),
$quantityElements: $('.quantity-selector, label + .js-qty'),
$addToCartText: $('#addToCartText')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should these be saved to timber.cache? Otherwise, since all are product related, they can also be saved to a single productCache obj or use a product_ naming convention? Not sure any of these are needed, just wondering if they might help distinguish these are being product-specific

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I like the idea of productCache or something. That way I could move the initializing JS back to the product template instead of theme.liquid. On it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do these need to be saved outside the productJs function? why not just declare them there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, they could be inside. Thought that went against our styleguide though. It would actually be my preference in this case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which part of the guide are you referring to? Vars should be declared at the top of a function, but it doesn't have to happen anywhere in particular other than that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must be thinking of something else I read, not the guide. Apologies for the confusion.

}
};

Expand Down Expand Up @@ -101,6 +106,56 @@ timber.accessibleNav = function () {
}
};

timber.productJs = function (options) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

knit-pick, but seems redundant to call something "js" inside a .js file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hah that's already irked me too. Thinking of a better name now.

var money_format = options.money_format,
variant = options.variant,
selector = options.selector;

if (variant) {

// Update variant image, if one is set
if (variant.featured_image) {
var newImg = variant.featured_image,
el = timber.cache.$productImage[0];
Shopify.Image.switchImage(newImg, el, timber.switchImage);
}

// Select a valid variant if available
if (variant.available) {
// Available, enable the submit button, change text, show quantity elements
timber.cache.$addToCart.removeClass('disabled').prop('disabled', false);
timber.cache.$addToCartText.text('{{ "products.product.add_to_cart" | t }}');
timber.cache.$quantityElements.show();
} else {
// Sold out, disable the submit button, change text, hide quantity elements
timber.cache.$addToCart.addClass('disabled').prop('disabled', true);
timber.cache.$addToCartText.text('{{ "products.product.sold_out" | t }}');
timber.cache.$quantityElements.hide();
}

// Regardless of stock, update the product price
timber.cache.$productPrice.html( Shopify.formatMoney(variant.price, money_format) );

// Also update and show the product's compare price if necessary
if ( variant.compare_at_price > variant.price ) {
timber.cache.$comparePrice
.html('{{ "products.product.compare_at" | t }}: ' + Shopify.formatMoney(variant.compare_at_price, money_format))
.show();
} else {
timber.cache.$comparePrice.hide();
}

} else {
// The variant doesn't exist, disable submit button.
// This may be an error or notice that a specific variant is not available.
// To only show available variants, implement linked product options:
// - http://docs.shopify.com/manual/configuration/store-customization/advanced-navigation/linked-product-options
timber.cache.$addToCart.addClass('disabled').prop('disabled', true);
timber.cache.$addToCartText.text('{{ "products.product.unavailable" | t }}');
timber.cache.$quantityElements.hide();
}
};

timber.productImageSwitch = function () {
if ( timber.cache.$thumbImages.length ) {
// Switch the main image with one of the thumbnails
Expand Down
48 changes: 48 additions & 0 deletions layout/theme.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,54 @@
{% endcomment %}
{{ 'shop.js' | asset_url | script_tag }}

{% comment %}
Product page specific JS
{% endcomment %}
{% if template contains 'product' %}
{% comment %}
To take advantage of a callback on the select dropdown, add option_selection.js
and customize the JS below as you need.

Currently, the code below does:
- Hides your <select> tag from above
- Breaks out the product variants into separate product options, if more than one exists
- Generates a <select> tag for each product option

Callback notes:
- Keep the callback available to the global scope (window.selectCallback) so that advanced
addons can override it.
* E.g. multiple currencies http://docs.shopify.com/manual/configuration/store-customization/currencies-and-translations/currencies/how-to-toggle-between-two-currencies
{% endcomment %}
{{ 'option_selection.js' | shopify_asset_url | script_tag }}
<script>
var selectCallback = function(variant, selector) {
timber.productJs({
money_format: "{{ shop.money_format }}",
variant: variant,
selector: selector
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice :)

});
};

jQuery(function($) {
new Shopify.OptionSelectors('productSelect', {
product: {{ product | json }},
onVariantSelected: selectCallback,
enableHistoryState: true
});

// Add label if only one product option and it isn't 'Title'. Could be 'Size'.
{% if product.options.size == 1 and product.options.first != 'Title' %}
$('.selector-wrapper:eq(0)').prepend('<label>{{ product.options.first | escape }}</label>');
{% endif %}

// Hide selectors if we only have 1 variant and its title contains 'Default'.
{% if product.variants.size == 1 and product.variants.first.title contains 'Default' %}
$('.selector-wrapper').hide();
{% endif %}
});
</script>
{% endif %}

{% comment %}
Ajaxify your cart with this plugin. Adding a product will reveal a drawer, modal, or confirmation button. Enabled by default in theme settings.

Expand Down
96 changes: 1 addition & 95 deletions templates/product.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,12 @@
- To separate these into multiple steps, which we suggest, use option_selection.js (see below)

You can leverage jQuery to add a callback on page load and each time the select element changes:
- Include option_selection.js (as seen at the bottom of this file)
- Include option_selection.js (as seen at the bottom of theme.liquid)
- This allows you to use JavaScript anytime the variant dropdown changes
- This also separates out your variant options (ie. size, color, etc.) to separate select elements

For more information on products with multiple options, visit:
- http://docs.shopify.com/support/your-website/themes/can-i-make-my-theme-use-products-with-multiple-options#update-product-liquid

{% endcomment %}
<select name="id" id="productSelect" class="product-variants">
{% for variant in product.variants %}
Expand Down Expand Up @@ -148,96 +147,3 @@
</div>

</div>


{% comment %}
To take advantage of a callback on the select dropdown, add option_selection.js
and customize the JS below as you need. This is only needed on pages where
product variants are accessible, so doesn't need to live in theme.liquid.

Currently, the code below does:
- Hides your <select> tag from above
- Breaks out the product variants into separate product options, if more than one exists
- Generates a <select> tag for each product option

Callback notes:
- Keep the callback available to the global scope (window.selectCallback) so that advanced
addons can override it.
* E.g. multiple currencies http://docs.shopify.com/manual/configuration/store-customization/currencies-and-translations/currencies/how-to-toggle-between-two-currencies
{% endcomment %}

{{ 'option_selection.js' | shopify_asset_url | script_tag }}
<script>
var selectCallback = function(variant, selector) {

var $addToCart = $('#addToCart'),
$productPrice = $('#productPrice'),
$comparePrice = $('#comparePrice'),
$quantityElements = $('.quantity-selector, label + .js-qty'),
$addToCartText = $('#addToCartText'),
$featuredImage = $('#productPhotoImg');

if (variant) {

// Update variant image, if one is set
// Call timber.switchImage function in shop.js
if (variant.featured_image) {
var newImg = variant.featured_image,
el = $featuredImage[0];
Shopify.Image.switchImage(newImg, el, timber.switchImage);
}

// Select a valid variant if available
if (variant.available) {
// We have a valid product variant, so enable the submit button
$addToCart.removeClass('disabled').prop('disabled', false);
$addToCartText.text('{{ "products.product.add_to_cart" | t }}');
$quantityElements.show();
} else {
// Variant is sold out, disable the submit button
$addToCart.addClass('disabled').prop('disabled', true);
$addToCartText.text('{{ "products.product.sold_out" | t }}');
$quantityElements.hide();
}

// Regardless of stock, update the product price
$productPrice.html( Shopify.formatMoney(variant.price, "{{ shop.money_format }}") );

// Also update and show the product's compare price if necessary
if ( variant.compare_at_price > variant.price ) {
$comparePrice
.html('{{ "products.product.compare_at" | t }}: ' + Shopify.formatMoney(variant.compare_at_price, "{{ shop.money_format }}"))
.show();
} else {
$comparePrice.hide();
}

} else {
// The variant doesn't exist, disable submit button.
// This may be an error or notice that a specific variant is not available.
// To only show available variants, implement linked product options:
// - http://docs.shopify.com/manual/configuration/store-customization/advanced-navigation/linked-product-options
$addToCart.addClass('disabled').prop('disabled', true);
$addToCartText.text('{{ "products.product.unavailable" | t }}');
$quantityElements.hide();
}
};

jQuery(function($) {
new Shopify.OptionSelectors('productSelect', {
product: {{ product | json }},
onVariantSelected: selectCallback,
enableHistoryState: true
});

// Add label if only one product option and it isn't 'Title'. Could be 'Size'.
{% if product.options.size == 1 and product.options.first != 'Title' %}
$('.selector-wrapper:eq(0)').prepend('<label>{{ product.options.first | escape }}</label>');
{% endif %}

// Hide selectors if we only have 1 variant and its title contains 'Default'.
{% if product.variants.size == 1 and product.variants.first.title contains 'Default' %}
$('.selector-wrapper').hide();
{% endif %}
});
</script>