Definitions for shopify buy. (#11760)

* Definitions for shopify buy.

        * Definitions for shopify buy.

* fix header format and remove core-js reference
This commit is contained in:
openminder
2016-10-06 16:38:32 +02:00
committed by Masahiro Wakame
parent f63e50aa81
commit 927c3555e0
2 changed files with 781 additions and 0 deletions

View File

@@ -0,0 +1,406 @@
/// <reference path="shopify-buy.d.ts" />
/// <reference path="../jquery/jquery.d.ts" />
/* Build new ShopifyBuy client
============================================================ */
let client = ShopifyBuy.buildClient({
apiKey: 'bf081e860bc9dc1ce0654fdfbc20892d',
myShopifyDomain: 'embeds',
appId: '6'
});
var product : ShopifyBuy.Shopify.ProductModel;
var cart : ShopifyBuy.Shopify.CartModel;
var cartLineItemCount : number;
if(localStorage.getItem('lastCartId')) {
client.fetchCart(localStorage.getItem('lastCartId')).then(function(remoteCart : ShopifyBuy.Shopify.CartModel) {
cart = remoteCart;
cartLineItemCount = cart.lineItems.length;
renderCartItems();
});
} else {
client.createCart().then(function (newCart : ShopifyBuy.Shopify.CartModel) {
cart = newCart;
localStorage.setItem('lastCartId', ""+cart.id);
cartLineItemCount = 0;
});
}
var previousFocusItem : any;
/* Fetch product and init
============================================================ */
client.fetchProduct('3614436099').then(function (fetchedProduct : ShopifyBuy.Shopify.ProductModel) {
product = fetchedProduct;
var selectedVariant : ShopifyBuy.Shopify.ProductVariantModel = product.selectedVariant;
var selectedVariantImage : any = product.selectedVariantImage;
var currentOptions : ShopifyBuy.Shopify.Option[] = product.options;
var variantSelectors = generateSelectors(product);
$('.variant-selectors').html(""+variantSelectors);
updateProductTitle(product.title);
updateVariantImage(selectedVariantImage);
updateVariantTitle(selectedVariant);
updateVariantPrice(selectedVariant);
attachOnVariantSelectListeners(product);
updateCartTabButton();
bindEventListeners();
});
/* Generate DOM elements for variant selectors
============================================================ */
function generateSelectors(product : ShopifyBuy.Shopify.ProductModel) {
var elements = product.options.map(function(option : ShopifyBuy.Shopify.Option) {
var optionsHtml = option.values.map(function(value : any) {
return '<option value="' + value + '">' + value + '</option>';
});
return '<div class="shopify-select">\
<select class="select" name="' + option.name + '">' + optionsHtml + '</select>\
<svg class="shopify-select-icon" viewBox="0 0 24 24"><path d="M21 5.176l-9.086 9.353L3 5.176.686 7.647 12 19.382 23.314 7.647 21 5.176z"></path></svg>\
</div>'
});
return elements;
}
/* Bind Event Listeners
============================================================ */
function bindEventListeners() {
/* cart close button listener */
$('.cart .btn--close').on('click', closeCart);
/* click away listener to close cart */
$(document).on('click', function(evt) {
if((!$(evt.target).closest('.cart').length) && (!$(evt.target).closest('.js-prevent-cart-listener').length)) {
closeCart();
}
});
/* escape key handler */
var ESCAPE_KEYCODE = 27;
$(document).on('keydown', function (evt) {
if (evt.which === ESCAPE_KEYCODE) {
if (previousFocusItem) {
$(previousFocusItem).focus();
previousFocusItem = ''
}
closeCart();
}
});
/* checkout button click listener */
$('.btn--cart-checkout').on('click', function () {
window.open(cart.checkoutUrl, '_self');
});
/* buy button click listener */
$('.buy-button').on('click', buyButtonClickHandler);
/* increment quantity click listener */
$('.cart').on('click', '.quantity-increment', function () {
var variantId = $(this).data('variant-id');
incrementQuantity(variantId);
});
/* decrement quantity click listener */
$('.cart').on('click', '.quantity-decrement', function() {
var variantId = $(this).data('variant-id');
decrementQuantity(variantId);
});
/* update quantity field listener */
$('.cart').on('keyup', '.cart-item__quantity', debounce(fieldQuantityHandler, 250));
/* cart tab click listener */
$('.btn--cart-tab').click(function() {
setPreviousFocusItem(this);
openCart();
});
}
/* Variant option change handler
============================================================ */
function attachOnVariantSelectListeners(product : ShopifyBuy.Shopify.ProductModel) {
$('.variant-selectors').on('change', 'select', function(event) {
var $element : any = $(event.target);
var name : string = $element.attr('name');
var value : string = $element.val();
product.options.filter(function(option : ShopifyBuy.Shopify.Option) {
return option.name === name;
})[0].selected = value;
var selectedVariant : ShopifyBuy.Shopify.ProductVariantModel = product.selectedVariant;
var selectedVariantImage : any = product.selectedVariantImage;
updateProductTitle(product.title);
updateVariantImage(selectedVariantImage);
updateVariantTitle(selectedVariant);
updateVariantPrice(selectedVariant);
});
}
/* Update product title
============================================================ */
function updateProductTitle(title : string) {
$('#buy-button-1 .product-title').text(title);
}
/* Update product image based on selected variant
============================================================ */
function updateVariantImage(image : any) {
var src = (image) ? image.src : ShopifyBuy.NO_IMAGE_URI;
$('#buy-button-1 .variant-image').attr('src', src);
}
/* Update product variant title based on selected variant
============================================================ */
function updateVariantTitle(variant : ShopifyBuy.Shopify.ProductVariantModel) {
$('#buy-button-1 .variant-title').text(variant.title);
}
/* Update product variant price based on selected variant
============================================================ */
function updateVariantPrice(variant : ShopifyBuy.Shopify.ProductVariantModel) {
$('#buy-button-1 .variant-price').text('$' + variant.price);
}
/* Attach and control listeners onto buy button
============================================================ */
function buyButtonClickHandler(evt : any) {
evt.preventDefault();
var id : string | number = product.selectedVariant.id;
var quantity : number;
var cartLineItem : ShopifyBuy.Shopify.CartLineItem = findCartItemByVariantId(id);
quantity = cartLineItem ? cartLineItem.quantity + 1 : 1;
addOrUpdateVariant(product.selectedVariant, quantity);
setPreviousFocusItem(evt.target);
$('#checkout').focus();
}
/* Update product variant quantity in cart
============================================================ */
function updateQuantity(fn : Function, variantId : string | number) {
var variant : ShopifyBuy.Shopify.ProductVariantModel = product.variants.filter(function (variant : ShopifyBuy.Shopify.ProductVariantModel) {
return (variant.id === variantId);
})[0];
var quantity : number;
var cartLineItem : ShopifyBuy.Shopify.CartLineItem = findCartItemByVariantId(variant.id);
if (cartLineItem) {
quantity = fn(cartLineItem.quantity);
updateVariantInCart(cartLineItem, quantity);
}
}
/* Decrease quantity amount by 1
============================================================ */
function decrementQuantity(variantId : string | number) {
updateQuantity(function(quantity : number) {
return quantity - 1;
}, variantId);
}
/* Increase quantity amount by 1
============================================================ */
function incrementQuantity(variantId : string | number) {
updateQuantity(function(quantity : number) {
return quantity + 1;
}, variantId);
}
/* Update product variant quantity in cart through input field
============================================================ */
function fieldQuantityHandler(evt : any) {
var variantId : string | number = parseInt($(this).closest('.cart-item').attr('data-variant-id'), 10);
var variant : ShopifyBuy.Shopify.ProductVariantModel = product.variants.filter(function (variant : ShopifyBuy.Shopify.ProductVariantModel) {
return (variant.id === variantId);
})[0];
var cartLineItem : ShopifyBuy.Shopify.CartLineItem = findCartItemByVariantId(variant.id);
var quantity : number = evt.target.value;
if (cartLineItem) {
updateVariantInCart(cartLineItem, quantity);
}
}
/* Debounce taken from _.js
============================================================ */
function debounce(func : any, wait : number, immediate? : number) {
var timeout : number;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
}
}
/* Open Cart
============================================================ */
function openCart() {
$('.cart').addClass('js-active');
}
/* Close Cart
============================================================ */
function closeCart() {
$('.cart').removeClass('js-active');
$('.overlay').removeClass('js-active');
}
/* Find Cart Line Item By Variant Id
============================================================ */
function findCartItemByVariantId(variantId : string | number) {
return cart.lineItems.filter(function (item) {
return (item.variant_id === variantId);
})[0];
}
/* Determine action for variant adding/updating/removing
============================================================ */
function addOrUpdateVariant(variant : ShopifyBuy.Shopify.ProductVariantModel, quantity : number) {
openCart();
var cartLineItem : ShopifyBuy.Shopify.CartLineItem = findCartItemByVariantId(variant.id);
if (cartLineItem) {
updateVariantInCart(cartLineItem, quantity);
} else {
addVariantToCart(variant, quantity);
}
updateCartTabButton();
}
/* Update details for item already in cart. Remove if necessary
============================================================ */
function updateVariantInCart(cartLineItem : ShopifyBuy.Shopify.CartLineItem, quantity : number) {
var variantId : string | number = cartLineItem.variant_id;
var cartLength : number = cart.lineItems.length;
cart.updateLineItem(cartLineItem.id, quantity).then(function(updatedCart : ShopifyBuy.Shopify.CartModel) {
var $cartItem = $('.cart').find('.cart-item[data-variant-id="' + variantId + '"]');
if (updatedCart.lineItems.length >= cartLength) {
$cartItem.find('.cart-item__quantity').val(cartLineItem.quantity);
$cartItem.find('.cart-item__price').text(formatAsMoney(cartLineItem.line_price));
} else {
$cartItem.addClass('js-hidden').bind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function() {
$cartItem.remove();
});
}
updateCartTabButton();
updateTotalCartPricing();
if (updatedCart.lineItems.length < 1) {
closeCart();
}
}).catch(function (errors : string) {
console.log('Fail');
console.error(errors);
});
}
/* Add 'quantity' amount of product 'variant' to cart
============================================================ */
function addVariantToCart(variant : ShopifyBuy.Shopify.ProductVariantModel, quantity : number) {
openCart();
cart.addVariants({ variant: variant, quantity: quantity }).then(function() {
var cartItem : ShopifyBuy.Shopify.CartLineItem = cart.lineItems.filter(function (item : ShopifyBuy.Shopify.CartLineItem ) {
return (item.variant_id === variant.id);
})[0];
var $cartItem = renderCartItem(cartItem);
var $cartItemContainer = $('.cart-item-container');
$cartItemContainer.append($cartItem);
setTimeout(function () {
$cartItemContainer.find('.js-hidden').removeClass('js-hidden');
}, 0)
}).catch(function (errors : string) {
console.log('Fail');
console.error(errors);
});
updateTotalCartPricing();
updateCartTabButton();
}
/* Return required markup for single item rendering
============================================================ */
function renderCartItem(lineItem : ShopifyBuy.Shopify.CartLineItem) {
var lineItemEmptyTemplate = $('#CartItemTemplate').html();
var $lineItemTemplate = $(lineItemEmptyTemplate);
var itemImage = lineItem.image.src;
$lineItemTemplate.attr('data-variant-id', lineItem.variant_id);
$lineItemTemplate.addClass('js-hidden');
$lineItemTemplate.find('.cart-item__img').css('background-image', 'url(' + itemImage + ')');
$lineItemTemplate.find('.cart-item__title').text(lineItem.title);
$lineItemTemplate.find('.cart-item__variant-title').text(lineItem.variant_title);
$lineItemTemplate.find('.cart-item__price').text(formatAsMoney(lineItem.line_price));
$lineItemTemplate.find('.cart-item__quantity').attr('value', lineItem.quantity);
$lineItemTemplate.find('.quantity-decrement').attr('data-variant-id', lineItem.variant_id);
$lineItemTemplate.find('.quantity-increment').attr('data-variant-id', lineItem.variant_id);
return $lineItemTemplate;
}
/* Render the line items currently in the cart
============================================================ */
function renderCartItems() {
var $cartItemContainer = $('.cart-item-container');
$cartItemContainer.empty();
var lineItemEmptyTemplate = $('#CartItemTemplate').html();
var $cartLineItems = cart.lineItems.map(function (lineItem, index) {
return renderCartItem(lineItem);
});
$cartItemContainer.append($cartLineItems);
setTimeout(function () {
$cartItemContainer.find('.js-hidden').removeClass('js-hidden');
}, 0)
updateTotalCartPricing();
}
/* Update Total Cart Pricing
============================================================ */
function updateTotalCartPricing() {
$('.cart .pricing').text(formatAsMoney(cart.subtotal));
}
/* Format amount as currency
============================================================ */
function formatAsMoney(amount : string, currency? : string, thousandSeparator? : string, decimalSeparator? : string , localeDecimalSeparator? : string) {
currency = currency || '$';
thousandSeparator = thousandSeparator || ',';
decimalSeparator = decimalSeparator || '.';
localeDecimalSeparator = localeDecimalSeparator || '.';
var regex = new RegExp('(\\d)(?=(\\d{3})+\\.)', 'g');
return currency + parseFloat(amount).toFixed(2)
.replace(localeDecimalSeparator, decimalSeparator)
.replace(regex, '$1' + thousandSeparator)
.toString();
}
/* Update cart tab button
============================================================ */
function updateCartTabButton() {
if (cart.lineItems.length > 0) {
$('.btn--cart-tab .btn__counter').html(""+cart.lineItemCount);
$('.btn--cart-tab').addClass('js-active');
} else {
$('.btn--cart-tab').removeClass('js-active');
$('.cart').removeClass('js-active');
}
}
/* Set previously focused item for escape handler
============================================================ */
function setPreviousFocusItem(item : ShopifyBuy.Shopify.CartLineItem) {
previousFocusItem = item;
}

375
shopify-buy/shopify-buy.d.ts vendored Normal file
View File

@@ -0,0 +1,375 @@
// Type definitions for shopify-buy
// Project: http://shopify.github.io/js-buy-sdk/api/
// Definitions by: Martin Köhn <https://github.com/openminder>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
/**
* The JS Buy SDK is a lightweight library that allows you to build ecommerce into any website.
* It is based on Shopifys API and provides the ability to retrieve products and collections from your shop,
* add products to a cart, and checkout.
*/
declare namespace ShopifyBuy {
/**
* Create a ShopClient. This is the main entry point to the SDK.
*/
export function buildClient(configAttrs : Shopify.Config) : Shopify.ShopClient
/**
* Internal Image description
*/
interface Image {
id : string|number
src : string
position : number
product_id : string
variant_ids : Array<string>
created_at : string
updated_at : string
}
/**
* Internal BaseModel class
*/
class BaseModel {
constructor( attrs: any, metaAttrs: any )
attrs : any
serializer: any
adapter: any
shopClient: any
}
var NO_IMAGE_URI : string;
/**
* This namespace contains all globally accessible classes
*/
export namespace Shopify {
/**
* Base Shopify Client config object
*/
interface Config
{
/**
* Your api client's public token.
*/
apiKey: string
/** The app whose listings the client will be using.
* If you are just modifying a buy button, the buy-button's app id is.
* Otherwise, obtain the app id of the app you're modifying or extending.
*/
appId: string
/** You shop's myshopify.com domain. */
myShopifyDomain: string
}
/**
* Cart item, that should be added to the card
*/
interface CartModelItem {
variant : Shopify.ProductVariantModel
quantity : number
}
class CartLineItem extends BaseModel {
constructor()
/**
* Line item unique ID
*/
id : string|number
/**
* Images associated with product.
*/
image : Image
/**
* Product title
*/
title: string
/**
* ID of selected variant
*/
variant_id: string|number
/**
* Title of selected variant
*/
variant_title: string
/**
* Number of selected items
*/
quantity : number
/**
* Variant weight in grams
*/
grams: number
/**
* ID of selected product
*/
product_id: string|number
/**
* Price of variant, formatted as currency
*/
price: string
/**
* Compare at price for variant formatted as currency.
*/
compare_at_price: string
/**
* Calculated price for the number of variant in card
*/
line_price: string
}
/**
* Shopify-Buy-SDK Client to handle products and cart
*/
class ShopClient {
/**
* Config data to be used throughout all API interaction
*/
constructor( config? : Config )
/**
* Creates a CartModel instance, optionally including attrs.
*/
createCart(attrs? : any) : Promise<CartModel>
/**
* Updates an existing CartModel instance and persists it to localStorage.
*/
updateCart(attrs? : any) : Promise<CartModel>
/**
* Retrieve a previously created cart by its key.
*/
fetchCart(id : string) : Promise<CartModel>
/**
* Fetch one collection by its ID.
*/
fetchCollection(id : string|number) : Promise<any> //TODO: Find declaration for Collection
/**
* Fetch one product by its ID.
*/
fetchProduct(id: string|number) : Promise<ProductModel>
/**
* Fetches a list of collections matching a specified query.
*/
fetchQueryCollections(query? : any) : Promise<Array<any>>
/**
* Fetches a list of products matching a specified query.
*/
fetchQueryProducts(query? : any) : Promise<Array<ProductModel>>
}
/**
* Class for cart model
*/
class CartModel extends BaseModel {
constructor()
/**
* Get checkout URL for current cart
*/
checkoutUrl : string
/**
* get ID for current cart
*/
id : string|number
/**
* Get current line items for cart
*/
lineItems : Array<CartLineItem>
/**
* Get current subtotal price for all line items
*/
subtotal: string
/**
* Gets the sum quantity of each line item
*/
lineItemCount : number
/**
* Add items to cart. Updates cart's lineItems
*/
addVariants(item : CartModelItem, nextItem? : Array<CartModelItem>) : Promise<CartModel>
/**
* Remove all line items from cart
*/
clearLineItems() : Promise<CartModel>
/**
* Remove line item from cart
*/
removeLineItem(id : string|number) : Promise<CartModel>
/**
* Update line item quantity
*/
updateLineItem(id : string|number, quantitiy : number ) : Promise<CartModel>
}
/**
* Class for products returned by fetch('product')
*/
class ProductModel extends BaseModel {
constructor()
/**
* Product unique ID
*/
id : string|number
/**
* All images associated with product.
*/
images : Array<Image>
/**
* Product title
*/
title: string
/**
* All variants of a product.
*/
variants: Array<ProductVariantModel>
/**
* Get array of options with nested values. Useful for creating UI for selecting options.
*/
options : Array<Option>
/**
* Retrieve variant for currently selected options
*/
selectedVariant : ProductVariantModel
/**
* Retrieve image for currently selected variantImage
*/
selectedVariantImage : Image
/**
* Retrieve currently selected option values.
*/
selections : Option
}
/**
* Model for product variant
*/
class ProductVariantModel extends BaseModel {
constructor()
/*
* Checkout URL for purchasing variant with quantity.
*/
checkoutUrl( quantitiy : number ) : string
/**
* Compare at price for variant formatted as currency.
*/
compareAtPrice : string
/**
* Variant weight in grams
*/
grams : number
/**
* Variant unique ID
*/
id : string|number
/**
* Image for variant
*/
image : Image
/**
* Option values associated with this variant, ex {name: "color", value: "Blue"}
*/
optionValues : Array<Option>
/**
* Price of variant, formatted as currency
*/
price : string
/**
* ID of product variant belongs to
*/
productId : string|number
/**
* Title of product variant belongs to
*/
productTitle : string
/**
* Title of variant
*/
title: string
}
/**
* Class for product option
*/
class Option extends BaseModel {
constructor()
/**
* name of option (ex. "Size", "Color")
*/
name: string
/**
* get/set selected option value (ex. "Large").
* Setting this will update the selected value on the model.
* Throws {Error} if setting selected to value that does not exist for option
*/
selected : string
/**
* possible values for selection
*/
values : Array<any>
}
}
}
declare module "ShopifyBuy" {
export = ShopifyBuy
}