/** Kelkoo Related Products Blog Widget * Ben Ward * EU Hack Day V * 2008-02-08 */ /** In your HTML, you need to put the scriptless fallback HTML, which * be enhanced by this script: * e.g. */ /** You must then call the init() functionon page load, customise the * ID parameter to correspond to the mark-up you create above. * e.g. YAHOO.EU.BenWard.HListingProductWidget.init( "related-results", "http://shopping.kelkoo.co.uk/ctl/do/search?siteSearchQuery=", {} ); */ (function() { // Load YUI prerequisites into the page try { if(YAHOO) {}; } catch (e) { throw "Need YAHOO core"; } try { if(YAHOO.util.Dom) {}; } catch (e) { throw "Need YAHOO Dom"; } // Declare namespace YAHOO.namespace("YAHOO.EU.BenWard"); // Widget object: // Pass an empty DIV element ID into the constructor YAHOO.EU.BenWard.HListingProductWidget = { // Some settings parser : "http://hack.ben-ward.co.uk/parse/proxy.php?profile=hlisting&output=json&callback=YAHOO.EU.BenWard.HListingProductWidget.callbackListings&url=", widget : undefined, provider : undefined, sourceurl: undefined, listings : undefined, // Initialisation takes an element ID name, provider URL and // optional preferences structure. init : function(el, provider, options) { self = YAHOO.EU.BenWard.HListingProductWidget; // Get the widget container and confirm its existence self.widget = document.getElementById(el); if(!self.widget) { return false; // Here the specified container doesn't exist, so fail } // Similarly, if no search provider URL is provided, the script fails self.provider = provider; if(self.provider == undefined || self.provider == '') { return false; } // The widget is somewhat configurable, for the number of results to // display, for example. Using an object for all options makes this // extensible in a tidy manner. if(self.options === undefined) { self.options = {}; } self.options.resultsLength = self.options.resultsLength || "5"; // With the widget configured and primed, run the first steps to load the // search result data var tags = self.getTags(); self.queryListings(tags); }, getTags : function() { // Get tags (as strings), from each rel-tag microformat on the page var tags = []; YAHOO.util.Dom.getElementsBy( function(anchor) { var rel = anchor.getAttribute('rel'); if(rel !== undefined && rel !== null) { return (rel.indexOf("tag") > -1); } else { return false; } }, "a", document.body, function(a) { // The rel-tag specification states that the tag itself is not // the inner text on the anchor, but is instead the last fragment // of the URL. // See http://microformats.org/wiki/rel-tag var segments = a.href.split('/'); var tag = segments[segments.length-1]; tags.push(tag); } ); return tags; }, queryListings : function(tags) { self = YAHOO.EU.BenWard.HListingProductWidget; // If there are tags, search for products var products; if(tags.length > 0) { // The query is cross-site, so insert a new script element with // the webservice URL, and then pass it a callback function var query = tags.join("%20"); var qscript = document.createElement("script"); qscript.type = "text/javascript"; self.datasource = self.provider + query; // self.parser is a string, pre-set as: // "http://hack.ben-ward.co.uk/parse/proxy.php? // profile=hlisting // &output=json // &callback=YAHOO.EU.BenWard.HListingProductWidget.callbackListings // &url=", qscript.src = self.parser + self.datasource; var body = document.getElementsByTagName('body')[0]; body.appendChild(qscript); } }, callbackListings : function(listings) { var self = YAHOO.EU.BenWard.HListingProductWidget; self.listings = listings; self.renderWidget(); }, renderWidget : function() { var self = YAHOO.EU.BenWard.HListingProductWidget; if(self.listings !== undefined && self.listings.length > 0) { // With it verified that there are results to display, // replace the entire static content of the ‘widget’ element self.widget.innerHTML = ""; // Results are going to be displayed in a list, ordered by // popularity (the same order as Kelkoo sends back by default) var list = document.createElement("ol"); for( var i=0; (listing = self.listings[i]) && (i < self.options.resultsLength); i++ ) { // For each result (up to the {resultsLength} limit set in the // widget options), create an LI, fill it with content and then // append it to the list. var li = document.createElement("li"); var item = document.createElement("a"); item.className = "fn"; if(listing.item.url !== undefined) { item.href = listing.item.url; } else { // Microformats are flexible to publishers, so handle // situations where a product might not have a URL of its // own, and instead link back to the datasource that the // results were parsed from. item.href = self.datasource; } var lister = document.createElement("span"); lister.className = "lister"; var price = document.createElement("span"); price.className = "price"; item.appendChild(document.createTextNode(listing.item.fn)); lister.appendChild(document.createTextNode(listing.lister.fn)); price.appendChild(document.createTextNode(listing.price)); li.appendChild(item); li.appendChild(lister); li.appendChild(price); list.appendChild(li); } // Finally, append the list to the now empty widget container element. self.widget.appendChild(list); } } }; })();