//= require lscache //= require moment var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; Heroku.BlogFetcher = (function() { function BlogFetcher(container) { this.handleError = bind(this.handleError, this); this.appendData = bind(this.appendData, this); this.$container = $(container); this.init(); } BlogFetcher.prototype.init = function() { this.$container .on('dataLoaded', this.appendData) .on('dataError', this.handleError); return this.getPosts(); }; BlogFetcher.prototype.getPosts = function() { $.support.cors = true; if (lscache.get('blogEntry')) { return this.$container.trigger('dataLoaded'); } else { var self = this; return $.ajax({ url: 'https://blog.heroku.com/rss_feedburner', type: 'GET', dataType: 'xml', crossDomain: true }) .done(function(result) { var obj = self.xmlToJson($(result).find('item')[0]); var textBlock = obj.description['#text']; var content = typeof textBlock === 'object' ? textBlock[0] : textBlock; // FF treats the textBlock as an object for some reason var blog = { 'title': obj.title['#text'], 'contentSnippet': self.trimToLength(content, 200), 'link': obj.link['#text'], 'publishedDate': obj.pubDate['#text'], 'author': obj.author['#text'] }; lscache.set('blogEntry', blog, 60); return self.$container.trigger('dataLoaded'); }) .fail(function(e) { return self.$container.trigger('dataError'); }); } }; BlogFetcher.prototype.appendData = function() { var blogContent = this.$container.find('.js-blog-content'); this.storedEntry = lscache.get('blogEntry'); this.$container.find('.js-blog-link').text(this.storedEntry.title); this.$container.find('.js-blog-link').attr('href', this.storedEntry.link); this.$container.find('.js-blog-date').html(this.buildDateAndAuthor()); blogContent.html(this.storedEntry.contentSnippet); blogContent.find('p').append(' Read More'); }; BlogFetcher.prototype.handleError = function() { if (this.storedEntry) { return this.$container.trigger('dataloaded'); } else { this.$container.find('.js-blog-link').text('Visit the Heroku Blog'); this.$container.find('.js-blog-date').empty(); this.$container.find('.js-blog-content').text('Find news and updates from Heroku in the blog.'); } }; BlogFetcher.prototype.buildDateAndAuthor = function() { var ago = moment.utc(this.storedEntry.publishedDate, 'ddd, D MMM YYYY hh:mm:ss ZZ').fromNow(); return ago + " by " + this.storedEntry.author; }; //http://davidwalsh.name/convert-xml-json BlogFetcher.prototype.xmlToJson = function(xml) { // Create the return object var obj = {}; if (xml.nodeType == 1) { // element // do attributes if (xml.attributes.length > 0) { obj["@attributes"] = {}; for (var j = 0; j < xml.attributes.length; j++) { var attribute = xml.attributes.item(j); obj["@attributes"][attribute.nodeName] = attribute.nodeValue; } } } else if (xml.nodeType == 3) { // text obj = xml.nodeValue; } // do children if (xml.hasChildNodes()) { for(var i = 0; i < xml.childNodes.length; i++) { var item = xml.childNodes.item(i); var nodeName = item.nodeName; if (typeof(obj[nodeName]) == "undefined") { obj[nodeName] = this.xmlToJson(item); } else { if (typeof(obj[nodeName].push) == "undefined") { var old = obj[nodeName]; obj[nodeName] = []; obj[nodeName].push(old); } obj[nodeName].push(this.xmlToJson(item)); } } } return obj; }; BlogFetcher.prototype.trimToLength = function(str, max) { if (str.length > max) { return jQuery.trim(str).substring(0, max).split(' ').slice(0, -1).join(' ') + '...'; } else { return str; } }; return BlogFetcher; })(); $(function() { return window.Heroku.latestBlog = new Heroku.BlogFetcher('#more-blog'); });