(function($) { function start() { loadConfig(loadTwitter); } function loadConfig(callback) { $.ajax({ url: "/include/twitter/twitter-config.xml", dataType: "xml", success: configLoaded, complete: callback, global: false }); function configLoaded(xml) { var replaceRefs = (function() { var re = /%{([a-zA-Z_:][-a-zA-Z0-9_:.]*)}%/; function replace(text) { while (text.search(re) >= 0) { text = text.replace(re, $.trim(config$.find(text.match(re)[1]).text())); } return text; } return function(node) { $(node).contents().filter(function() { return this.nodeType === 3 || this.nodeType === 4; }).each(function() { this.nodeValue = replace($.trim(this.nodeValue)); }).end().filter(function() { return this.nodeType === 1; }).each(function() { if (this.attributes.length > 0) { $.each(this.attributes, function() { this.nodeValue = replace($.trim(this.nodeValue)); }); } replaceRefs(this); }); }; })(); config$ = $(xml).find("twitter-config"); // recursively descend through the config XML and replace {%...%} references replaceRefs(config$.get(0)); } } function loadTwitter() { var tweetHTML$; var errorTimeoutID = (function() { var timeout = parseInt(getConfigText("timeout")); if (!isNaN(timeout) && timeout >= 0) return setTimeout(error, timeout); else return null; })(); $.ajax({ url: getConfigText("twitter-json-request > url"), timeout: getConfigText("timeout"), dataType: "jsonp", data: (function() { var data = { }; config$.find("twitter-json-request > data > attr").each(function() { data[$.trim($(this).attr("name"))] = $.trim($(this).attr("value")); }) return data; })(), success: success, complete: complete }); function success(json) { clearTimeout(errorTimeoutID); if (Boolean(json.error)) { //alert(json.error); return error(); } var hashTags$ = config$.find("hash-tags > match"); var tweetIndex = 0; hashTagSearch: for (var i = 0; i < hashTags$.length; ++i) { var current$ = hashTags$.eq(i); var regex = (function() { var regex; try { regex = new RegExp($.trim(current$.text())); } catch(e) { regex = new RegExp(); } return regex; })(); var maxAge = (function() { var maxAge = parseInt(current$.attr("max-age")) * 1000; maxAge = (isNaN(maxAge) || maxAge < 0) ? 0 : maxAge; return maxAge; })(); var now = new Date().getTime(); for (var t = 0; t < json.length; ++t) { if (maxAge > 0 && now - new Date(json[t]["created_at"]).getTime() > maxAge) break; for (var h = 0, HTs = json[t]["entities"]["hashtags"]; h < HTs.length; ++h) { if (new String(HTs[h]["text"]).search(regex) >= 0) { tweetIndex = t; break hashTagSearch; } } } } var tweetJSON = json[tweetIndex]; tweetHTML$ = $.tmpl(getConfigText("tweet-template"), tweetJSON); if (Boolean(tweetJSON["entities"])) { var replacements = []; if (tweetJSON["entities"]["user_mentions"].length > 0) { $.template("user-mention-template", getConfigText("entity-templates > user-mention-template")); $.each(tweetJSON["entities"]["user_mentions"], function() { replacements.push({ beginning: this["indices"][0], end: this["indices"][1], html: $.tmpl("user-mention-template", this) }); }); } if (tweetJSON["entities"]["urls"].length > 0) { $.template("external-link-template", getConfigText("entity-templates > external-link-template")); $.each(tweetJSON["entities"]["urls"], function() { replacements.push({ beginning: this["indices"][0], end: this["indices"][1], html: $.tmpl("external-link-template", this) }); }); } if (tweetJSON["entities"]["hashtags"].length > 0) { $.template("hash-tag-template", getConfigText("entity-templates > hash-tag-template")); $.each(tweetJSON["entities"]["hashtags"], function() { replacements.push({ beginning: this["indices"][0], end: this["indices"][1], html: $.tmpl("hash-tag-template", this) }); }); } if (replacements.length > 0) { replacements.sort(function(a, b) { return a.beginning - b.beginning; }); var tweetContents$ = $(getConfigText("tweet-contents-selector"), tweetHTML$); var tweetText = tweetContents$.text(); tweetContents$.empty(); for (var i = 0; i < replacements.length; ++i) { tweetContents$.append(tweetText.substring((i === 0) ? 0 : replacements[i-1].end, replacements[i].beginning)); tweetContents$.append(replacements[i].html); } tweetContents$.append(tweetText.substring(replacements[replacements.length - 1].end)); } saveTweet(tweetHTML$); } } function error() { clearTimeout(errorTimeoutID); var savedTweet = getSavedTweet(); if (Boolean(savedTweet)) tweetHTML$ = $("
").html(savedTweet).children(); else tweetHTML$ = $("
").html(getConfigText("default-tweet")).children(); // This function is not defined as the error handler for the AJAX request, so we must directly invoke the complete handler function because it will not be called otherwise. complete(); } function complete() { $(getConfigText("tweet-selector")).empty().append(tweetHTML$); } } function getConfigText(name) { return $.trim(config$.find(name).text()); } function saveTweet(tweetHTML$) { var hasLocalStorage = (function() { try { var item = "localstorage"; localStorage.setItem(item, item); localStorage.removeItem(item); return true; } catch(e) { return false; } })(); var hasCookies = Boolean(document.cookie); var tweetHTMLString = tweetHTML$.clone().wrap("
").parent().html(); if (hasLocalStorage) { localStorage.setItem("last-tweet", tweetHTMLString); } else if (hasCookies) { document.cookie = "last-tweet=" + encodeURIComponent(tweetHTMLString) + "; max-age=" + (60*60*24*7); // 1 week } } function getSavedTweet() { var hasLocalStorage = (function() { try { var item = "localstorage"; localStorage.setItem(item, item); localStorage.removeItem(item); return true; } catch(e) { return false; } })(); var hasCookies = Boolean(document.cookie); if (hasLocalStorage) { return localStorage.getItem("last-tweet"); } else if (hasCookies) { var allCookies = document.cookie.split(";"); for (var i = 0; i < allCookies.length; ++i) { var cookie = $.trim(allCookies[i]); if (cookie.indexOf("last-tweet=") == 0) return decodeURIComponent(cookie.substring(name.length, cookie.length)); } } return null; } $(start); })(jQuery);