Skip to content

Instantly share code, notes, and snippets.

@clooth
Created November 15, 2012 16:06
Show Gist options
  • Save clooth/4079406 to your computer and use it in GitHub Desktop.
Save clooth/4079406 to your computer and use it in GitHub Desktop.
/*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... &raquo;</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