UNPKG

@eastsideco/escshopify

Version:

WIP JS library for Shopify, containing a variety of useful functionality.

579 lines (495 loc) 34.7 kB
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <base data-ice="baseUrl" href="../"> <title data-ice="title">Manual | @eastsideco/escshopify</title> <link type="text/css" rel="stylesheet" href="css/style.css"> <link type="text/css" rel="stylesheet" href="css/prettify-tomorrow.css"> <script src="script/prettify/prettify.js"></script> <script src="script/manual.js"></script> </head> <body class="layout-container manual-root manual-index" data-ice="rootContainer"> <header> <a href="./">Home</a> <a href="./manual/index.html" data-ice="manualHeaderLink">Manual</a> <a href="identifiers.html">Reference</a> <a href="source.html">Source</a> <div class="search-box"> <span> <img src="./image/search.png"> <span class="search-input-edge"></span><input class="search-input"><span class="search-input-edge"></span> </span> <ul class="search-result"></ul> </div> <a href="https://bitbucket.org/sigapps/escshopify.git">Repository</a></header> <nav class="navigation" data-ice="nav"><div class="manual-toc-root"> <div data-ice="manual"> <ul class="manual-toc"> <li data-ice="manualNav" class="indent-h1" data-link="manual/overview.html"><a href="manual/overview.html" data-ice="link">Overview</a></li> </ul> </div> <div data-ice="manual"> <ul class="manual-toc"> <li data-ice="manualNav" class="indent-h1" data-link="manual/entities.html"><a href="manual/entities.html" data-ice="link">Entities</a></li> </ul> </div> <div data-ice="manual"> <ul class="manual-toc"> <li data-ice="manualNav" class="indent-h1" data-link="manual/cart.html"><a href="manual/cart.html" data-ice="link">Entities/Cart</a></li> <li data-ice="manualNav" class="indent-h2" data-link="manual/cart.html"><a href="manual/cart.html#example" data-ice="link">Example</a></li> <li data-ice="manualNav" class="indent-h2" data-link="manual/cart.html"><a href="manual/cart.html#getting-started" data-ice="link">Getting Started</a></li> <li data-ice="manualNav" class="indent-h3" data-link="manual/cart.html"><a href="manual/cart.html#initializing-the-cart-state" data-ice="link">Initializing the cart state</a></li> <li data-ice="manualNav" class="indent-h3" data-link="manual/cart.html"><a href="manual/cart.html#reading-the-cart" data-ice="link">Reading the cart</a></li> <li data-ice="manualNav" class="indent-h3" data-link="manual/cart.html"><a href="manual/cart.html#setting-cart-items-and-attributes" data-ice="link">Setting cart items and attributes</a></li> <li data-ice="manualNav" class="indent-h4" data-link="manual/cart.html"><a href="manual/cart.html#important-warning-about-async" data-ice="link">Important warning about async</a></li> <li data-ice="manualNav" class="indent-h2" data-link="manual/cart.html"><a href="manual/cart.html#events" data-ice="link">Events</a></li> <li data-ice="manualNav" class="indent-h3" data-link="manual/cart.html"><a href="manual/cart.html#update" data-ice="link">update</a></li> <li data-ice="manualNav" class="indent-h3" data-link="manual/cart.html"><a href="manual/cart.html#add" data-ice="link">add</a></li> <li data-ice="manualNav" class="indent-h3" data-link="manual/cart.html"><a href="manual/cart.html#item-updated" data-ice="link">item-updated</a></li> <li data-ice="manualNav" class="indent-h3" data-link="manual/cart.html"><a href="manual/cart.html#remove" data-ice="link">remove</a></li> <li data-ice="manualNav" class="indent-h3" data-link="manual/cart.html"><a href="manual/cart.html#clear" data-ice="link">clear</a></li> </ul> </div> <div data-ice="manual"> <ul class="manual-toc"> <li data-ice="manualNav" class="indent-h1" data-link="manual/shop.html"><a href="manual/shop.html" data-ice="link">Entities/Shop</a></li> <li data-ice="manualNav" class="indent-h2" data-link="manual/shop.html"><a href="manual/shop.html#examples" data-ice="link">Examples</a></li> <li data-ice="manualNav" class="indent-h2" data-link="manual/shop.html"><a href="manual/shop.html#getting-started" data-ice="link">Getting Started</a></li> <li data-ice="manualNav" class="indent-h3" data-link="manual/shop.html"><a href="manual/shop.html#initializing-the-shop-state" data-ice="link">Initializing the shop state</a></li> <li data-ice="manualNav" class="indent-h2" data-link="manual/shop.html"><a href="manual/shop.html#events" data-ice="link">Events</a></li> <li data-ice="manualNav" class="indent-h3" data-link="manual/shop.html"><a href="manual/shop.html#init" data-ice="link">init</a></li> </ul> </div> <div data-ice="manual"> <ul class="manual-toc"> <li data-ice="manualNav" class="indent-h1" data-link="manual/plugins.html"><a href="manual/plugins.html" data-ice="link">Plugins</a></li> </ul> </div> <div data-ice="manual"> <ul class="manual-toc"> <li data-ice="manualNav" class="indent-h1" data-link="manual/easycurrency.html"><a href="manual/easycurrency.html" data-ice="link">Plugins/EasyCurrency</a></li> <li data-ice="manualNav" class="indent-h2" data-link="manual/easycurrency.html"><a href="manual/easycurrency.html#getting-started" data-ice="link">Getting started</a></li> <li data-ice="manualNav" class="indent-h3" data-link="manual/easycurrency.html"><a href="manual/easycurrency.html#simple-example" data-ice="link">Simple example</a></li> <li data-ice="manualNav" class="indent-h3" data-link="manual/easycurrency.html"><a href="manual/easycurrency.html#config-options" data-ice="link">Config options</a></li> <li data-ice="manualNav" class="indent-h2" data-link="manual/easycurrency.html"><a href="manual/easycurrency.html#events" data-ice="link">Events</a></li> <li data-ice="manualNav" class="indent-h2" data-link="manual/easycurrency.html"><a href="manual/easycurrency.html#extending-easycurrency" data-ice="link">Extending EasyCurrency</a></li> <li data-ice="manualNav" class="indent-h3" data-link="manual/easycurrency.html"><a href="manual/easycurrency.html#formatters" data-ice="link">Formatters</a></li> <li data-ice="manualNav" class="indent-h3" data-link="manual/easycurrency.html"><a href="manual/easycurrency.html#currency-resolvers" data-ice="link">Currency Resolvers</a></li> </ul> </div> <div data-ice="manual"> <ul class="manual-toc"> <li data-ice="manualNav" class="indent-h1" data-link="manual/geoservice.html"><a href="manual/geoservice.html" data-ice="link">Plugins/Geoservice</a></li> <li data-ice="manualNav" class="indent-h2" data-link="manual/geoservice.html"><a href="manual/geoservice.html#getting-started" data-ice="link">Getting started</a></li> <li data-ice="manualNav" class="indent-h3" data-link="manual/geoservice.html"><a href="manual/geoservice.html#get-visitor-geolocation-info" data-ice="link">Get visitor geolocation info</a></li> <li data-ice="manualNav" class="indent-h3" data-link="manual/geoservice.html"><a href="manual/geoservice.html#get-currency-exchange-rates" data-ice="link">Get currency exchange rates</a></li> </ul> </div> <div data-ice="manual"> <ul class="manual-toc"> <li data-ice="manualNav" class="indent-h1" data-link="manual/utils.html"><a href="manual/utils.html" data-ice="link">Utilities</a></li> </ul> </div> <div data-ice="manual"> <ul class="manual-toc"> </ul> </div> <div data-ice="manual"> <ul class="manual-toc"> <li data-ice="manualNav" class="indent-h1" data-link="manual/log.html"><a href="manual/log.html" data-ice="link">Utilities/Log</a></li> <li data-ice="manualNav" class="indent-h2" data-link="manual/log.html"><a href="manual/log.html#using-salvo" data-ice="link">Using SALVO</a></li> <li data-ice="manualNav" class="indent-h2" data-link="manual/log.html"><a href="manual/log.html#log-levels-and-tags" data-ice="link">Log levels and tags</a></li> <li data-ice="manualNav" class="indent-h2" data-link="manual/log.html"><a href="manual/log.html#getting-started" data-ice="link">Getting started</a></li> <li data-ice="manualNav" class="indent-h3" data-link="manual/log.html"><a href="manual/log.html#create-a-logging-module" data-ice="link">Create a logging module</a></li> <li data-ice="manualNav" class="indent-h3" data-link="manual/log.html"><a href="manual/log.html#setting-a-log-level" data-ice="link">Setting a log level</a></li> <li data-ice="manualNav" class="indent-h2" data-link="manual/log.html"><a href="manual/log.html#writing-new-loggers" data-ice="link">Writing new loggers</a></li> </ul> </div> </div> </nav> <div class="content" data-ice="content"><div class="github-markdown"> <div class="manual-user-index" data-ice="manualUserIndex"><h1 id="-eastsideco-escshopify">@eastsideco/escshopify</h1><p><em>A modular support library for building Shopify themes with ES6 and webpack.</em></p> <p>While the library can be used directly from any ES6 code (or traditional non-compiled scripts via a script tag), this library is ultimately intended to be used alongside two other tools:</p> <ul> <li>The SALVO theme development framework, which provides an environment for structuring themes and components. SALVO usually takes care of initializing many aspects of this library and providing a convinient interface for the theme developer.</li> <li>MATTv2, the second generation theme deployment framework.</li> </ul> <p>The library is still a WIP and may change radically in structure and/or function.</p> </div> <div class="manual-cards"> <div class="manual-card-wrap" data-ice="cards"> <div class="manual-card"> <div data-ice="card"><h1>Overview</h1></div> <a data-ice="link" href="manual/overview.html"></a> </div> </div> <div class="manual-card-wrap" data-ice="cards"> <div class="manual-card"> <div data-ice="card"><h1>Entities</h1><p>Entities represent common environment models that all Shopify themes need to work with. For example: the session cart; shop settings; product information.</p><p>These entities may be read-only (i.e. shop current format info), or provide an interface for modifying the entity (i.e. cart items).</p><p>Entities can be accessed from the object under EscShopifyJS.Entities.</p></div> <a data-ice="link" href="manual/entities.html"></a> </div> </div> <div class="manual-card-wrap" data-ice="cards"> <div class="manual-card"> <div data-ice="card"><h1>Entities/Cart</h1><p>The Cart module provides an interface to the state of the visitor&apos;s cart and the cart AJAX API.</p><p>For member and method documentation, see the API reference. For event documentation and examples, see below.</p><h2>Example</h2><p>The following example shows a simple JS component which keeps track of the number of items in the visitor&apos;s cart.</p><p><strong>ES6</strong>:</p><pre><code class="lang-js"><code class="source-code prettyprint">import {entities, utils} from &apos;@eastsideco/escshopify&apos;; const cart = new entities.Cart; export default class CartCounter { constructor(element) { this._element = element; cart.on(&apos;update&apos;, () =&gt; this.render()); utils.onLoad(() =&gt; this.render()); } async render() { await cart.ready(); var count = cart.items.reduce((total, i) =&gt; total + i.quantity, 0); this._element.innerText = count; } }</code> </code></pre><h2>Getting Started</h2><h3>Initializing the cart state</h3><p>Before using the cart module, you should initialize it with the current state of the cart, for example from a binding created in Liquid.</p><p><em>This is done for you automatically if you use SALVO.</em></p><p><strong>ES6</strong>:</p><pre><code class="lang-js"><code class="source-code prettyprint">import {entities, utils} from &apos;@eastsideco/escshopify&apos;; const cart = new entities.Cart; cartData = { token: &apos;...&apos;, items: [ ... ], ... }; cart.initialize(cartData);</code> </code></pre><h3>Reading the cart</h3><p>You can access the items in the cart using <code>.items</code>. It&apos;s highly recommended to check or wait for the cart entity to be &apos;ready&apos; before doing this. Async/await makes this quite trivial.</p><p><strong>ES6</strong>:</p><pre><code class="lang-js"><code class="source-code prettyprint">import {entities, utils} from &apos;@eastsideco/escshopify&apos;; const cart = new entities.Cart; // Using async/await async function printCartItemNames() { await cart.ready(); for (let cart.items as item) { console.log(item.title + &apos; x&apos; + item.quantity); } } // Using promises function printCartItemNames() { cart.ready().then(() =&gt; { for (let cart.items as item) { console.log(item.title + &apos; x&apos; + item.quantity); } }); } // Checking cart state syncronously function printCartItemNames() { if (cart.isReady) { for (let cart.items as item) { console.log(item.title + &apos; x&apos; + item.quantity); } } }</code> </code></pre><h3>Setting cart items and attributes</h3><p>You can modify the cart items using <code>#addItem</code>, <code>#updateItem</code>, etc. You can modify cart attributes using <code>#setAttribute</code> or <code>#setAttributes</code>.</p><p><strong>ES6</strong>:</p><pre><code class="lang-js"><code class="source-code prettyprint">cart.addItem(variantId, 1);</code> </code></pre><pre><code class="lang-js"><code class="source-code prettyprint">await cart.addItem(variantId, 1); cart.updateItemById(variantId, 3);</code> </code></pre><pre><code class="lang-js"><code class="source-code prettyprint">// Setting a line item attribute on each item in the cart: for (let item, lineNumber of cart.items) { cart.updateItem(lineNumber, item.quantity, { promotion: &apos;Added by promotion&apos; }); }</code> </code></pre><h4>Important warning about async</h4><p><strong>Warning:</strong> Most setter methods are asynchronous. Await the promise fulfillment, or be aware that the cart state may not reflect your changes.</p><p>Examples:</p><p><strong>ES6</strong>:</p><pre><code class="lang-js"><code class="source-code prettyprint">// starting cart attributes: { test: 1 } cart.setAttribute(&apos;test&apos;, 2); console.log(cart.getAttribute(&apos;test&apos;)); // may still 1?</code> </code></pre><pre><code class="lang-js"><code class="source-code prettyprint">// starting cart attributes: { test: 1 } await cart.setAttribute(&apos;test&apos;, 2); console.log(cart.getAttribute(&apos;test&apos;)); // definitely 2</code> </code></pre><pre><code class="lang-js"><code class="source-code prettyprint">// starting cart attributes: { test: 1 } cart.setAttribute(&apos;test&apos;, 2).then(() =&gt; { console.log(cart.getAttribute(&apos;test&apos;); // definitely 2 });</code> </code></pre><p>You can use <code>Promise#all</code> to wait for multiple changes to complete:</p><pre><code class="lang-js"><code class="source-code prettyprint">// Set attributes on all line items and wait until complete var promises = []; for (let item, lineNumber of cart.items) { promises.push(cart.updateItem(lineNumber, item.quantity, { attribute: &apos;test&apos; })); } console.log(cart.items); // Attributes may or may not be updated? await Promise.all(promises); console.log(cart.items); // Attributes are definitely updated</code> </code></pre><h2>Events</h2><p>Listen to the following events to track the lifecycle of this entity.</p><h3>update</h3><p>The cart was modified.</p><pre><code class="lang-txt"><code class="source-code prettyprint">Object[] items - The new state of items in the cart. String operation - &apos;add&apos;, &apos;item-updated&apos;, &apos;remove&apos;, &apos;init&apos;, or &apos;attribute-updated&apos; Object|Null item - Item that was added/updated/removed.</code> </code></pre><p>Updating an item to 0 qty is considered a <code>remove</code>.</p><pre><code class="lang-js"><code class="source-code prettyprint">cart.on(&apos;update&apos;, (e) =&gt; { this.cartTotalMinusGiftcards = _.reduce(e.items, (total, item) =&gt; { return item.gift_card ? total : total + item.line_price; }, 0); });</code> </code></pre><h3>add</h3><p>An item has been added.</p><pre><code><code class="source-code prettyprint">Object[] items - The new state of items in the cart. Object item - Item that was added.</code> </code></pre><p>Updating an existing item with higher qty <em>does not</em> fire this event (see <code>item-updated</code>).</p><pre><code class="lang-js"><code class="source-code prettyprint">cart.on(&apos;add&apos;, (e) =&gt; { // &quot;Thanks for adding Example Product!&quot; window.alert(&apos;Thanks for adding &apos; + e.item.product_title + &apos;!&apos;); });</code> </code></pre><h3>item-updated</h3><p>An item has been modified.</p><pre><code><code class="source-code prettyprint">Object[] items - The new state of items in the cart. Object item - Item that was updated (after update).</code> </code></pre><p>Adding a new line item <em>does not</em> fire this event (see <code>add</code>).</p><h3>remove</h3><p>An item has been removed.</p><pre><code><code class="source-code prettyprint">Object[] items - The new state of items in the cart. Object item - Item that was removed.</code> </code></pre><h3>clear</h3><p>The cart is now empty.</p><pre><code><code class="source-code prettyprint">Object[] oldItems - Items that were previously in the cart.</code> </code></pre><p>This will typically fire when the last item is removed from the cart.</p></div> <a data-ice="link" href="manual/cart.html"></a> </div> </div> <div class="manual-card-wrap" data-ice="cards"> <div class="manual-card"> <div data-ice="card"><h1>Entities/Shop</h1><p>The Shop entity represents global shop settings and details (i.e. contact email address, policies, URL, etc.)</p><p>This entity is read-only, and it properties match that of the Shopify <code>shop</code> liquid object. There are some extra methods and properties added for convinience.</p><h2>Examples</h2><p><strong>ES6</strong>:</p><pre><code class="lang-js"><code class="source-code prettyprint">import {entities, utils} from &apos;@eastsideco/escshopify&apos;; const shop = new entities.Shop; // Accessing shop properties: var primaryDomain = shop.domain; var myshopifyDomain = shop.permanent_domain; var storeName = shop.name; var defaultCurrency = shop.currency; var averageCollectionSize = shop.products_count / shop.collections_count; // Generating absolute shop URLs: var absoluteUrl = shop.makeAbsoluteUrl(&apos;/collections/all&apos;); // https://shop.com/collections/all var permanentUrl = shop.makePermanentUrl(&apos;/collections/all&apos;); // https://shop.myshopify.com/collections/all</code> </code></pre><h2>Getting Started</h2><h3>Initializing the shop state</h3><p>Before using the shop module, you should initialize it with the global shop state, for eaxmple from a binding created in Liquid.</p><p><em>This is done for you automatically if you use SALVO.</em></p><p><strong>ES6</strong>:</p><pre><code class="lang-js"><code class="source-code prettyprint">import {entities, utils} from &apos;@eastsideco/escshopify&apos;; const shop = new entities.Shop; shopData = { name: &apos;...&apos;, domain: &apos;...&apos;, ... }; shop.initialize(shopData);</code> </code></pre><h2>Events</h2><p>Listen to the following events to track the lifecycle of this entity.</p><h3>init</h3><p>The shop entity was initialized.</p><pre><code class="lang-txt"><code class="source-code prettyprint">Object shop - The current shop entity.</code> </code></pre></div> <a data-ice="link" href="manual/shop.html"></a> </div> </div> <div class="manual-card-wrap" data-ice="cards"> <div class="manual-card"> <div data-ice="card"><h1>Plugins</h1><p>Plugins are larger modules which encapsulate a more complex piece of functionality (i.e. currency conversion and formatting). Plugins are self-contained and entirely optional, but they provide an easy way to implement common complex funtionality.</p><p>Plugins can be accessed via the object under EscShopifyJs.Plugins.</p></div> <a data-ice="link" href="manual/plugins.html"></a> </div> </div> <div class="manual-card-wrap" data-ice="cards"> <div class="manual-card"> <div data-ice="card"><h1>Plugins/EasyCurrency</h1><p>The EasyCurrency module provides easy-to-use and highly customizable frontend currency conversion.</p><h2>Getting started</h2><h3>Simple example</h3><p>By default, EC will convert elements with <code>[data-money]</code>, optionally making use of the <code>[data-money-currency]</code> property.</p><p>For example, this element:<br><code>&lt;span data-money=&quot;1234&quot; data-money-currency=&quot;USD&quot;&gt;$12.34&lt;/span&gt;</code><br>May be converted to:<br><code>&lt;span&gt;&#xA3;10.00&lt;/span&gt;</code><br>Note that amounts are specified in integer units (i.e. cents).</p><p>Note that the default parser removes the initialization properties from the element after initialization, but this may not always be the case.<br><strong>Warning:</strong> Don&apos;t use the initialization properties to read/write conversion state after initialization (as you would have in the classic EC) - there are now other mechanisms for supporting this.</p><p><strong>ES6</strong>:</p><pre><code class="lang-js"><code class="source-code prettyprint">import {plugins, utils} from &apos;@eastsideco/escshopify&apos;; const easyCurrency = new plugins.EasyCurrency; // Initialize EC once the page has loaded. utils.onLoad(() =&gt; { easyCurrency.useGeoserviceResolver(); easyCurrency.initialize({ defaultCurrency: &apos;GBP&apos; }); });</code> </code></pre><p><strong>ES5</strong>:</p><pre><code class="lang-html"><code class="source-code prettyprint">&lt;script src=&quot;escshopify.web.js&quot;&gt;&lt;/script&gt; &lt;script&gt; (function() { // Initialize EC once the page has loaded. escshopify.utils.onLoad(function() { var easyCurrency = new escshopify.plugins.EasyCurrency(); easyCurrency.useGeoserviceResolver(); easyCurrency.initialize({ defaultCurrency: &apos;GBP&apos; }); }); })(); &lt;/script&gt;</code> </code></pre><h3>Config options</h3><p>Here is an example with all of the config options and default values:<br>See the reference for Config#constructor for more info.</p><p><strong>ES6</strong>:</p><pre><code class="lang-js"><code class="source-code prettyprint">import {plugins, utils} from &apos;@eastsideco/escshopify&apos;; const easyCurrency = new plugins.EasyCurrency; // Initialize EC once the page has loaded. utils.onLoad(() =&gt; { easyCurrency.useGeoserviceResolver(); easyCurrency.initialize({ // Currency to use before geolocation is first resolved. defaultCurrency: &apos;GBP&apos;, // List of currencies the user can use, or the string &apos;any&apos;. allowedCurrencies: &apos;any&apos;, // [&apos;USD&apos;, &apos;EUR&apos;], // Whether to set currency based on geolocation. useGeoForCurrency: true, // Selectors to parse as MoneySpans moneySpanSelectors: [ &apos;[data-money]&apos; ], // How to extract amount + currency from the selected elements moneySpanParser: function(el, easyCurrency) { var amount = el.dataset.money; var currency = el.dataset.moneyCurrency || easyCurrency.getState().currency; delete el.dataset.money; delete el.dataset.moneyCurrency; amount = Number(amount); return new Money(amount, currency); }, }); });</code> </code></pre><h2>Events</h2><p>EasyCurrency extends evee and provides a variety of events for to listening to changes. See the &apos;Emit&apos; sections of the class reference for a list of events. <strong>ES6</strong>:</p><pre><code class="lang-js"><code class="source-code prettyprint">import {plugins, utils} from &apos;@eastsideco/escshopify&apos;; const easyCurrency = new plugins.EasyCurrency; // Initialize EC once the page has loaded. utils.onLoad(() =&gt; { easyCurrency.useGeoserviceResolver(); easyCurrency.initialize({ defaultCurrency: &apos;GBP&apos;, }); easyCurrency.on(&apos;currencyChanged&apos;, (e) =&gt; { alert(&apos;Currency is now: &apos; + e.data); }); });</code> </code></pre><h2>Extending EasyCurrency</h2><h3>Formatters</h3><p>EasyCurrency uses a <a href="./manual/../class/src/plugins/easycurrency/formatters/Formatter.js~Formatter.html">Formatter</a> to format currencies.</p><p>To override currency formatting, make an object extending Formatter (or with #format), and then call EasyCurrency#setFormatter.</p><p><strong>ES6</strong>:</p><pre><code class="lang-js"><code class="source-code prettyprint">// CustomFormatter.js import {plugins} from &apos;@eastsideco/escshopify&apos;; export default class CustomFormatter extends plugins.EasyCurrency.formatters.Formatter { format(amount, currency) { return (amount / 100).toFixed(2) + &apos; &apos; + currency; // i.e. &quot;12.34 USD&quot; } } // main.js import {plugins, utils} from &apos;@eastsideco/escshopify&apos;; import CustomFormatter from &apos;./CustomFormatter&apos;; const easyCurrency = new plugins.EasyCurrency; // Initialize EC once the page has loaded. utils.onLoad(() =&gt; { easyCurrency.useGeoserviceResolver(); easyCurrency.setFormatter(new CustomFormatter); easyCurrency.initialize({ defaultCurrency: &apos;GBP&apos;, }); });</code> </code></pre><h3>Currency Resolvers</h3><p>EasyCurrency uses a <a href="./manual/../class/src/plugins/easycurrency/resolvers/CurrencyResolver.js~CurrencyResolver.html">CurrencyResolver</a> to determine which currencies are available and the conversion rate between them.</p><p>To override convertion rates or available currencies, make an object extending CurrencyResolver (or with #getConversionRate and #listCurrencyCodes), and call EasyCurrency#setCurrencyResolver.</p><p><strong>ES6</strong>:</p><pre><code class="lang-js"><code class="source-code prettyprint">// CustomResolver.js import {plugins} from &apos;@eastsideco/escshopify&apos;; export default class CustomResolver extends plugins.EasyCurrency.resolvers.CurrencyResolver { async listCurrencyCodes() { return [&apos;USD&apos;, &apos;GBP&apos;, &apos;EUR&apos;]; } async getConversionRate(from, to) { // Just an example, please don&apos;t write rates like this. var rates = { USD: { USD: 1, GBP: 0.8, EUR: 0.9 }, GBP: { USD: 1/0.8, GBP: 1, EUR: (1/0.8)*0.9 }, EUR: { USD: 1/0.9, GBP (1/0.9)*0.8, EUR: 1} }; return rates[from][to]; } } // main.js import {plugins, utils} from &apos;@eastsideco/escshopify&apos;; import CustomResolver from &apos;./CustomResolver&apos;; const easyCurrency = new plugins.EasyCurrency; // Initialize EC once the page has loaded. utils.onLoad(() =&gt; { easyCurrency.useGeoserviceResolver(); easyCurrency.setCurrencyResolver(new CustomResolver); easyCurrency.initialize({ defaultCurrency: &apos;GBP&apos;, }); });</code> </code></pre></div> <a data-ice="link" href="manual/easycurrency.html"></a> </div> </div> <div class="manual-card-wrap" data-ice="cards"> <div class="manual-card"> <div data-ice="card"><h1>Plugins/Geoservice</h1><p>The Geoservice module provides an easy-to-use interface for visitor geolocation and currency information.</p><h2>Getting started</h2><h3>Get visitor geolocation info</h3><p><strong>ES6</strong>:</p><pre><code class="lang-js"><code class="source-code prettyprint">import {plugins} from &apos;@eastsideco/escshopify&apos;; const geoService = new plugins.GeoService; async function alertVisitorCountry() { var geoInfo = await geoService.lookupGeo(); alert(geoInfo.country.iso_code); }</code> </code></pre><h3>Get currency exchange rates</h3><p><strong>Note</strong>: It&apos;s highly recommended to use the EasyCurrency plugin instead of re-implementing currency conversion yourself - it had more features and covers many easy-to-miss edge cases.</p><p><strong>ES6</strong>:</p><pre><code class="lang-js"><code class="source-code prettyprint">import {plugins} from &apos;@eastsideco/escshopify&apos;; const geoService = new plugins.GeoService; class VisitorCurrencyConverter { constructor(baseCurrency) { this._baseCurrency = basyCurrency; this._visitorCurrency = &apos;USD&apos;; this._rates = null this._getRates(); this._getVisitorCurrency(); } async _getVisitorCurrency() { var geoInfo = await geoService.lookupGeo(); this._visitorCurrency = geoInfo.currency; } async _getRates() { var res = await geoService.getCurrencyInfo(); this._rates = res.rates; } convert(amount) { var baseToUsd = this._baseCurrency == &apos;USD&apos; ? 1 : this._rates[this._baseCurrency]; var usdToVisitor = this._visitorCurency == &apos;USD&apos; ? 1 : this._rates[this._visitorCurrency; var rate = usdToVisitor / baseToUsd; return amount * rate; } }</code> </code></pre></div> <a data-ice="link" href="manual/geoservice.html"></a> </div> </div> <div class="manual-card-wrap" data-ice="cards"> <div class="manual-card"> <div data-ice="card"><h1>Utilities</h1><p>The library provides various utility functions to reduce boilerplate and make common tasks easier.</p><p>Most of these utilties can be found in the general utils module, but some groups of functionality have been put into their own standalone modules (i.e. logging).</p></div> <a data-ice="link" href="manual/utils.html"></a> </div> </div> <div class="manual-card-wrap" data-ice="cards"> <div class="manual-card"> <div data-ice="card"><h1>Utilities/Log</h1><p>The Log util module provides a very basic logging framework for level and module-based logging. The log utility support custom loggers (i.e. to send logs via AJAX or to the DOM), and level-based muting (i.e. ignoring debug-level messages).</p><h2>Using SALVO</h2><p>If you&apos;re using SALVO, a logger has already been configured for you - simple use salvo.log:</p><p><strong>ES6</strong>:</p><pre><code class="lang-js"><code class="source-code prettyprint">import salvo from &apos;salvo&apos;; salvo.log.send(salvo.log.WARN, &apos;Example&apos;, &apos;This is an example message.&apos;);</code> </code></pre><h2>Log levels and tags</h2><p>The log interface accepts three arguments: log level, tag, and message.</p><p>The log level is a description of the purpose and importance of the log message: DEBUG, INFO, WARN, ERROR, or FATAL. These constants are defined on the log instance, i.e. <code>log.DEBUG</code>, <code>log.WARN</code>, etc.</p><p>The log tag is a description of where the log message comes from. Typically, it should be the name of a component or class. Log tags help find track down log messages, or filter messages in the debugger. A common pattern is to have a TAG constant in your classes like so:</p><p><strong>ES6</strong>:</p><pre><code class="lang-js"><code class="source-code prettyprint">import log from &apos;log&apos;; const TAG = &apos;ExampleComponent&apos;; class ExampleComponent { constructor() { log.send(log.DEBUG, TAG, &apos;Created a new thing!&apos;); } }</code> </code></pre><h2>Getting started</h2><h3>Create a logging module</h3><p>Create a module in your application which bootstraps logging like so:</p><p><strong>ES6</strong>:</p><pre><code class="lang-js"><code class="source-code prettyprint">// log.js import {Log} from &apos;@eastsideco/esc-shopify&apos;; import ConsoleLogger from &apos;@eastsideco/esc-shopify/src/utils/loggers/ConsoleLogger.js&apos;; const log = new Log; const defaultLogger = new ConsoleLogger(); log.addLogger(logger); export default log;</code> </code></pre><p>You can then use the log like so:</p><pre><code class="lang-js"><code class="source-code prettyprint">import log from &apos;log&apos;; log.send(log.WARN, &apos;Example&apos;, &apos;This is an example message&apos;); log.sendObject(log.DEBUG, &apos;Example&apos;, &apos;This is an example object&apos;, { test: 123 });</code> </code></pre><h3>Setting a log level</h3><p>You can mute logging below a given level by calling <code>Log#setLogLevel</code>:</p><pre><code class="lang-js"><code class="source-code prettyprint">if (!config.debug) { log.setLogLevel(log.WARN); }</code> </code></pre><h2>Writing new loggers</h2><p>A single log instance can write to multiple loggers. By default, the library provides a ConsoleLogger, which simply passes the log arguments on to window.console, but you can extend this if you need to display logs elsewhere for some reason.</p><p><strong>ES6</strong>:</p><pre><code class="lang-js"><code class="source-code prettyprint">// DOMLogger.js import Logger from &apos;@eastsideco/escshopify/src/utils/loggers/Logger.js&apos;; export default class DOMLogger extends Logger { constructor(element) { this._element = element; } send(level, tag, text) { var child = document.createElement(&apos;p&apos;); child.classList.add(&apos;level-&apos;+level); child.innerText = tag + &apos;: &apos; + text; this._element.appendChild(child); } sendObject(level, tag, text, object) { this.send(level, tag, text + &apos; -- &apos; + JSON.stringify(object); } } // log.js import {Log} from &apos;@eastsideco/shopify&apos;; import ConsoleLogger from &apos;@eastsideco/shopify/src/utils/loggers/ConsoleLogger.js&apos;; import DOMLogger from &apos;./DomLogger&apos;; const log = new Log; const defaultLogger = new ConsoleLogger; const customLogger = new DOMLogger; log.addLogger(defaultLogger); log.addLogger(customLogger); export default log;</code> </code></pre></div> <a data-ice="link" href="manual/log.html"></a> </div> </div> </div> </div> </div> <footer class="footer"> Generated by <a href="https://esdoc.org">ESDoc<span data-ice="esdocVersion">(1.0.4)</span><img src="./image/esdoc-logo-mini-black.png"></a> </footer> <script src="script/search_index.js"></script> <script src="script/search.js"></script> <script src="script/pretty-print.js"></script> <script src="script/inherited-summary.js"></script> <script src="script/test-summary.js"></script> <script src="script/inner-link.js"></script> <script src="script/patch-for-local.js"></script> </body> </html>