Created
November 15, 2012 16:06
-
-
Save clooth/4079406 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*global Hogan:true*/ | |
$(function() { | |
"use strict"; | |
/* | |
* Global configuration options | |
*/ | |
var Config = { | |
// Product fields | |
productSchema: { | |
id: 'product_id', | |
title: 'title', | |
photo_url: 'field_image', | |
category: 'field_product_tags', | |
price: 'commerce_price', | |
bestPrice: 'field_minimum_price' | |
}, | |
// Catalog configuration | |
catalog: { | |
dataSource: 'lib/products.json', | |
container: '#products', | |
nextPageLink: '#catalog-next-page', | |
panelSelector: '.panel', | |
showPerPage: 16 | |
}, | |
// Configuration for scrolling to an element | |
scrolling: { | |
duration: 800 | |
} | |
}; | |
/* | |
* Utility functions to make certain things easier | |
*/ | |
var Util = { | |
// Scroll the window to a specific element after a | |
// given delay for a given duration. | |
scrollToElement: function(selector, duration, delay) { | |
var win = $('html, body'), | |
element = $(selector); | |
if (typeof duration === 'undefined') { | |
duration = Config.scrolling.duration; | |
} | |
// Use a timeout if given | |
if (typeof delay !== 'undefined') { | |
setTimeout(function() { | |
win.stop(true, false).animate({ | |
scrollTop: element.offset().top - 20 | |
}, duration); | |
}, delay); | |
} else { | |
win.stop(true, false).animate({ | |
scrollTop: element.offset().top - 20 | |
}, duration); | |
} | |
} | |
}; | |
/* | |
* A container for all the hogan templates used | |
*/ | |
var Templates = { | |
// A single product element in the browser | |
productPanel: Hogan.compile('<li class="panel item {{ css_class }}" id="catalog-product-{{ id }}"><div class="photo"><img src="{{ photo_url }}"><div class="best-price-caption">{{ best_price }}</div></div><div class="details"><div class="left"><span class="product-category">{{ tags }}</span><span class="title">{{ title }}</span></div><div class="right"><span class="best-price-title">Best Group price</span>{{{best_price}}}<span class="learn-more">Learn more... »</span></div></div></li>') | |
}; | |
/* | |
* A single product object containing the required attributes | |
*/ | |
var Product = function(info) { | |
this.id = info[Config.productSchema.id]; | |
this.title = info[Config.productSchema.title]; | |
this.category = info[Config.productSchema.category]; | |
this.price = info[Config.productSchema.price]; | |
this.bestPrice = info[Config.productSchema.bestPrice]; | |
}; | |
/* | |
* Class for managing products easily | |
*/ | |
var ProductManager = function(productsData) { | |
var self = this; | |
// Collection of Product objects | |
this.productsList = []; | |
// Loop through each of the objects inside the result | |
// JSON object and add them to the products list | |
// collection. | |
$.each(productsData.products, function(productData) { | |
var product = new Product(productData); | |
self.addProduct(product); | |
}); | |
this.sortMode = 'id'; | |
}; | |
// Add a new item to the collection of products | |
ProductManager.prototype.addProduct = function(product) { | |
if (this.productsList.indexOf(product) < 0) { | |
this.productsList.push(product); | |
return true; | |
} else { | |
return false; | |
} | |
}; | |
// Remove an item from the collection of products | |
ProductManager.prototype.removeProduct = function(product) { | |
// Check if the product exists in our collection | |
// and then remove and return the removed product. | |
var productIndex = this.productsList.indexOf(product); | |
if (productIndex >= 0) { | |
return this.productsList.splice(productIndex, 1); | |
} | |
return null; | |
}; | |
/* | |
* Main catalog browser | |
* Takes care of HTML rendering of all the product items | |
* And sorting and whatnot inside of it. | |
*/ | |
var Catalog = function(productsData) { | |
// Set up the product manager | |
this.products = new ProductManager(productsData.products); | |
// Pagination | |
this.currentPage = 0; | |
this.showPerPage = Config.catalog.showPerPage; | |
// Set up the catalog container element | |
this.container = $(Config.catalog.container); | |
// Set up isotope for the container | |
this.container.isotope({ | |
itemSelector: Config.catalog.panelSelector, | |
layoutMode: Config.catalog.layoutMode, | |
getSortData: Config.catalog.sortData | |
}); | |
}; | |
// Browse to the next page of products within the catalog | |
Catalog.prototype.renderNextPage = function() { | |
// Starting index for products | |
var startingIndex = this.currentPage * this.showPerPage; | |
// Loop through all the products from our collection | |
// from the starting index to the right end index. | |
var productsPage = this.products.products.slice( | |
startingIndex, | |
startingIndex+this.showPerPage | |
); | |
var currentColumn = 0; | |
$.each(productsPage, function(product) { | |
// Reset column index at the end of the row | |
currentColumn = currentColumn === 4 ? 0 : currentColumn; | |
// Product panel css classes | |
product.css_class = ""; | |
if (currentColumn === 3) { | |
product.css_class += ' last'; | |
} | |
if (currentColumn === 0) { | |
product.css_class += ' first'; | |
} | |
// Render the template for this product panel | |
// into a jQuery object. | |
var rendered = $( | |
Templates.productPanel.render(product) | |
); | |
// Set some data attributes for the DOM element | |
// These are used in sorting | |
rendered.data({ | |
id: product.id, | |
category: product.category, | |
price: product.price, | |
title: product.title | |
}); | |
// Append the product panels to the container | |
// Scrolling is triggered after the last item is appended | |
// NOTE: Scrolling currently disabled. | |
var appendedCounter = 0; | |
this.container.append(rendered).isotope( | |
'appended', rendered, | |
function() { | |
var panelSelector = '#catalog-product-'+ product.id; | |
Util.scrollToElement(panelSelector); | |
appendedCounter++; | |
} | |
); | |
currentColumn++; | |
}); | |
// Increment page index | |
this.currentPage++; | |
}; | |
// Elements used with the catalog | |
var productsList = $(Config.catalog.container), | |
nextPageLink = $(Config.catalog.nextPageLink); | |
// Check if the container exists, so we know whether | |
// to initialize the catalog or not. | |
if (productsList.length > 0) { | |
// Load products JSON | |
$.getJSON(Config.catalog.dataSource, function(result) { | |
// Initialize catalog instance with the data | |
// we get from the JSON. | |
var catalog = new Catalog(result); | |
// Render the first page of products | |
catalog.renderNextPage(); | |
// Bind the next page link event | |
nextPageLink.bind('click', function(e) { | |
e.preventDefault(); | |
catalog.renderNextPage(); | |
}); | |
}); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment