home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Freelog 117
/
FreelogNo117-OctobreNovembre2013.iso
/
Theme
/
8GadgetPack
/
8GadgetPackSetup.msi
/
Gadgets.7z
/
Gadgets
/
tweetz.gadget
/
app.js
next >
Wrap
Text File
|
2013-04-09
|
70KB
|
1,860 lines
/// <reference path="jquery.js" />
/*jslint browser: true, windows: true, onevar: true, undef: true, nomen: true, eqeqeq: true, bitwise: true, newcap: true */
/*global $: false, jQuery: false, OAuth: false, window: false, BigInteger: false */
var APP = {};
jQuery.support.cors = true; // force cross-site scripting (as of jQuery 1.5)
//jQuery.support.appendChecked = true; // as of jQuery 1.6 this is required
if (typeof Array.unique !== "function") {
Array.prototype.unique = function () {
var i, len = this.length, out = [], obj = {};
for (i = 0; i < len; i++) { obj[this[i]] = 0; }
for (i in obj) { if (obj.hasOwnProperty(i)) { out.push(i); } }
return out;
};
}
if (typeof Object.create !== "function") {
Object.create = function (o) {
var F = function () { };
F.prototype = o;
return new F();
};
}
String.regexUrl = /(^|[^\/!=])((?:https?:\/\/|www\.)(?:[a-z0-9\/\u272a][a-z0-9\-\/\u272a]*)\.(?:[a-z0-9]+)(?:\w|\([!*';:=+$\/%#\[\]\-_,~.@?&"\w]+\)|\/(?=($|\s))|[!*';:=+$\/%#\[\]\-_,~.@?&"](?=\S))+)/gi;
String.regexHashTag = /(^|[^0-9a-z&\/]+)(#|\uff03)([0-9]*[a-z_][a-z0-9_\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u00ff]*)/gi;
String.regexScreenName = /([^a-z0-9_]|^)(@|\uff20)([a-z0-9_]{1,20})(\/[a-z][a-z0-9_\-\x80-\xFF]{0,24})?/gi;
String.prototype.format = function () {
var pattern = /\{\d+\}/g,
placeHolder = /\d+/,
args = arguments;
return this.replace(pattern, function (capture) { return args[capture.match(placeHolder)]; });
};
String.prototype.contains = function (text) {
return this.indexOf(text) !== -1;
};
String.prototype.htmlEntities = function () {
return this.replace(/</g, '<').replace(/>/g, '>');
};
String.prototype.isBlank = function () {
return (/^\s*$/).test(this);
};
String.prototype.urlsToLinks = function (showLinks) {
return this.replace(String.regexUrl, function (text, c1, c2) {
var amp, que, at, c3 = "";
amp = text.indexOf("&");
que = text.indexOf("?");
if (/^.+@["'][a-zA-Z_\- ]+=/.test(text)) { // don't allow XSS after @
at = text.indexOf("@") - 1;
c3 = c2.slice(at);
c2 = c2.slice(0, at);
}
else if (amp > 0 && que < 0) { // don't allow & without ?
c3 = c2.slice(amp - 1);
c2 = c2.slice(0, amp - 1);
}
return '{0}<a href="{1}" class="link">{2}</a>{3}'.format(c1, c2, (showLinks ? c2 : (APP.locale.link || "[link]")), c3);
})
.replace("<a href=\"www.", "<a href=\"http://www.")
.replace("<a href=\"WWW.", "<a href=\"http://WWW.");
};
String.prototype.atScreenNames = function () {
return this.replace(String.regexScreenName, '$1<span class="screenname" sc="$2$3">$2$3</span>');
};
String.prototype.hashTags = function () {
return this.replace(String.regexHashTag, '$1<span class="hashtag">$2$3</span>');
};
String.prototype.htmlDecode = function () {
return $('<div/>').html(this.toString()).text();
};
String.prototype.findUrls = (function () {
var href = /\bhref="([\S]+\b|$)"/g;
return function () {
var matches = this.match(href);
if (matches) {
$.each(matches, function (idx) {
matches[idx] = this.replace(href, "$1");
});
}
return matches;
};
})();
$.fn.setCaretPos = function (pos) {
return this.each(function () {
var range = this.createTextRange();
range.move('character', pos);
range.select();
});
};
$.fn.pulse = function (options) {
return this.each(function () {
var settings = $.extend({}, $.fn.pulse.defaults, options),
n = settings.count,
$this = $(this);
function pulse() {
$this.fadeOut(settings.speed, function () {
$this.fadeIn(settings.speed, function () {
if (--n) { pulse(); return; }
settings.callback();
});
});
}
pulse();
});
};
$.fn.pulse.defaults = {
count: 3,
speed: 400,
callback: function () { }
};
$.fn.classAddOrRemove = function (className, add) {
return this.each(function () {
if (add) { $(this).addClass(className); }
else { $(this).removeClass(className); }
});
};
$.fn.loadStyleSheet = function (styleSheet) {
$(this).attr("href", styleSheet);
};
jQuery.extend(jQuery.expr[':'], {
focus: function (element) {
return element === document.activeElement;
}
});
APP.UTILITY = (function () {
var that = this;
that.setting = function (name, defaultValue) {
var setting;
return function (value) {
if (value !== undefined) {
System.Gadget.Settings.write(name, value);
}
else {
setting = System.Gadget.Settings.read(name);
return (setting !== "") ? setting : defaultValue;
}
};
};
that.modifyStyleSheet = function (selector, properties) {
selector = selector.toLowerCase();
$.each(document.styleSheets[0].rules, function () {
if (this.selectorText.toLowerCase() === selector) {
for (var property in properties) {
if (properties.hasOwnProperty(property)) {
this.style[property] = properties[property];
}
}
}
});
};
that.reverseLookup = function (links, link) {
if (link.substr(0, 7) === "http://" && !links[link]) {
$.getJSON("http://api.longurl.org/v2/expand",
{ url: link, format: "json" },
function (r) { links[link] = r["long-url"]; });
}
};
that.author = function (name, screen_name) {
return (name) ? '<span class="screenname author" sc="' + screen_name + '">' + name + "</span>" : "";
};
that.popup = function (id, text, element, yesAction) {
var d, dlg, o, t, x, y, h, yes, no;
$("#" + id).remove();
d = System.Gadget.docked;
dlg = $("<div>", { id: id, css: { top: 5000, width: d ? "100px" : "170px"} });
dlg.append($("<div>", { text: text || "undefined" }));
if (yesAction) {
yes = $("<button>", { text: "Yes" }).click(function () { yesAction(); dlg.remove(); });
no = $("<button>", { text: "No" }).click(function () { dlg.remove(); });
dlg.append(yes, no);
}
$("#content").append(dlg);
o = element ? element.offset() : { top: 10, left: 10 };
t = dlg.height();
x = Math.min(d ? 10 : 80, Math.max(10, o.left));
y = o.top + (element ? element.height() : 0) + 10;
h = d ? APP.settings.dockedHeight() : APP.settings.undockedHeight();
if ((y + t + 10) > h) { y = o.top - t - 10; }
dlg.hide().css({ "left": x, "top": y }).slideDown("fast");
};
that.shellRun = function (cmd) {
var shell = new ActiveXObject("WScript.Shell");
shell.Run(cmd);
};
that.showStatus = function (status) {
$("#content").trigger("showStatus", [status]);
};
that.versionChecker = (function () {
var self = {}, result, check, timer;
result = function (xml) {
var versionNumber = $(xml).find("tweetz31Result").text();
if (System.Gadget.version !== versionNumber) {
APP.UTILITY.popup("ask",
APP.locale.new_version_available || "Hey, there's a newer version available! Go get it?", null,
function () { APP.UTILITY.shellRun("http://blueonionsoftware.com/tweetz.aspx"); });
}
};
check = function () {
var soapMessage = '<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
'xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' +
'<soap:Body><tweetz31 xmlns="http://blueonionsoftware.com/"></tweetz31></soap:Body></soap:Envelope>';
$.ajax({
url: "http://blueonionsoftware.com/version.asmx",
type: "POST",
dataType: "xml",
data: soapMessage,
success: function (data, status, xhr) { result(xhr.responseXML); },
contentType: "text/xml; charset=\"utf-8\""
});
};
timer = null;
self.run = function () {
if (APP.settings.checkForUpdates()) {
if (timer === null) {
timer = setInterval(function () { check(); }, 1000 * 3600 * 24);
check();
}
}
else if (timer) {
clearInterval(timer);
timer = null;
}
};
return self;
})();
that.command = function (cmd, can) {
var self = {};
self.execute = function () {
var args = Array.prototype.slice.call(arguments);
return self.canExecute() ? cmd.apply(self, args) : undefined;
};
self.canExecute = function () {
return (can) ? can() : true;
};
return self;
};
that.maxId = (function () {
var notDigits = /\D/g,
removeLeadingZeros = /^0+/,
isBigger = function (a, b) {
if (notDigits.test(a) || notDigits.test(b)) { throw "not numbers"; }
a = a.replace(removeLeadingZeros, '');
b = b.replace(removeLeadingZeros, '');
if (a.length !== b.length) { return (a.length > b.length); }
return a.localeCompare(b) > 0;
};
return function (id1, id2) {
return isBigger(id1, id2) ? id1 : id2;
};
})();
return that;
})();
APP.settings = {
userId: APP.UTILITY.setting("userId", ""),
username: APP.UTILITY.setting("username", ""),
tokenAccess: APP.UTILITY.setting("tokenAccess", ""),
tokenSecret: APP.UTILITY.setting("tokenSecret", ""),
dockedHeight: APP.UTILITY.setting("dockedHeight", 400),
undockedHeight: APP.UTILITY.setting("undockedHeight", 400),
chirpOnStatus: APP.UTILITY.setting("chirpOnStatus", false),
chirpOnMention: APP.UTILITY.setting("chirpOnMention", false),
chirpOnMessage: APP.UTILITY.setting("chirpOnMessage", false),
intervalHome: APP.UTILITY.setting("intervalHome", 2),
intervalMentions: APP.UTILITY.setting("intervalMentions", 4),
intervalMessages: APP.UTILITY.setting("intervalMessages", 6),
showLinks: APP.UTILITY.setting("showLinks", false),
fontSize: APP.UTILITY.setting("fontSize", "medium"),
checkForUpdates: APP.UTILITY.setting("checkForUpdates", false),
styleSheet: APP.UTILITY.setting("styleSheet", "css/original.css")
};
APP.comm = function () {
var that = {}, accessor;
accessor =
{
consumerKey: "n4Ce1XD9SEXKBpJlkrGpA",
consumerSecret: "OKcBnIRHubrbKDbkXVEAVFLJ7yUC9glJ6Mhj6enXesU",
tokenAccess: APP.settings.tokenAccess(),
tokenSecret: APP.settings.tokenSecret(),
userId: APP.settings.userId(),
username: APP.settings.username()
};
function ajax(type, url, data, success, complete, error) {
var message = { action: url, method: type };
if (data) { OAuth.setParameters(message, data); }
if (accessor.tokenAccess.length > 0) { OAuth.setParameter(message, "oauth_token", accessor.tokenAccess); }
OAuth.completeRequest(message, accessor);
$("#content").trigger("commAccessing");
if (data) {
var sdata = "";
var first = true;
$.each(data, function(key, value) {
if (!first) sdata += "&";
first = false;
sdata += key + "=" + OAuth.percentEncode(value);
});
}
$.ajax({ type: message.method, url: message.action, data: sdata,
headers: {Authorization: OAuth.getAuthorizationHeader(message.parameters)},
success: function (d, s, x) { if (success) { success(d, s, x); } },
error: function (d, s, x) {
$("#content").trigger("commError");
if (error) { error(d, s, x); }
},
statusCode: {
200: function () { $("#content").trigger("commSuccess"); },
429: function () { $("#content").trigger("commTooManyRequests"); }
},
complete: complete,
processData: false,
crossDomain: true // required as of 1.5
});
}
that.get = function (url, data, success, complete, error) { ajax("get", url, data, success, complete, error); };
that.post = function (url, data, success, complete, error) { ajax("post", url, data, success, complete, error); };
that.tokenAccess = function (t) {
if (t === undefined) { return accessor.tokenAccess; }
accessor.tokenAccess = t;
};
that.tokenSecret = function (t) {
if (t === undefined) { return accessor.tokenSecret; }
accessor.tokenSecret = t;
};
that.userId = function (id) {
if (id === undefined) { return accessor.userId; }
accessor.userId = id;
};
that.username = function (name) {
if (name === undefined) { return accessor.username; }
accessor.username = name;
};
return that;
};
APP.twitter = {
getPin: function (comm, successCallback, errorCallback) {
comm.tokenAccess("");
comm.tokenSecret("");
comm.get("https://twitter.com/oauth/request_token", null, function (data) {
if (successCallback) { successCallback(); }
var d = data.split("&");
comm.tokenAccess(d[0].split("=")[1]);
comm.tokenSecret(d[1].split("=")[1]);
APP.UTILITY.shellRun("https://twitter.com/oauth/authorize?" + data + "&oauth_callback=oob");
}, null, errorCallback);
},
getAccessToken: function (comm, pin, errorCallback) {
var verifier = { oauth_verifier: $.trim(pin) };
comm.post("https://twitter.com/oauth/access_token", verifier, function (data) {
var d = data.split("&");
comm.tokenAccess(d[0].split("=")[1]);
comm.tokenSecret(d[1].split("=")[1]);
comm.userId(d[2].split("=")[1]);
comm.username(d[3].split("=")[1]);
APP.settings.tokenAccess(comm.tokenAccess());
APP.settings.tokenSecret(comm.tokenSecret());
APP.settings.userId(comm.userId());
APP.settings.username(comm.username());
$("#container").trigger("accessTokenReceived");
}, null, errorCallback);
},
getHome: function (model, more) {
var params = { count: 25 }, max_id;
if (more) { max_id = model.getOldestId("home"); if (max_id) { params.max_id = max_id; } }
else { params.since_id = model.sinceIdHome || 1; }
model.comm.get("https://api.twitter.com/1.1/statuses/home_timeline.json", params, function (data) { model.updateHome(data, more); });
},
getMentions: function (model, more) {
var params = { count: 15 }, max_id;
if (more) { max_id = model.getOldestId("mentions"); if (max_id) { params.max_id = max_id; } }
else { params.since_id = model.sinceIdMentions || 1; }
model.comm.get("https://api.twitter.com/1.1/statuses/mentions_timeline.json", params, function (data) { model.updateMentions(data, more); });
},
getMessages: function (model, more) {
var params = { count: 15 }, max_id;
if (more) { max_id = model.getOldestId("messages"); if (max_id) { params.max_id = max_id; } }
else { params.since_id = model.sinceIdMessages || 1; }
model.comm.get("https://api.twitter.com/1.1/direct_messages.json", params, function (data) { model.updateMessages(data, more); });
},
getMessagesSent: function (model, more) {
var params = { count: 15 };
model.comm.get("https://api.twitter.com/1.1/direct_messages/sent.json", params, function (data) { model.updateMessages(data, more); });
},
getFavorites: function (model, more) {
var params = { count: 100 }, max_id;
if (more) { max_id = model.getOldestId("favorites"); if (max_id) { params.max_id = max_id; } }
model.comm.get("https://api.twitter.com/1.1/favorites/list.json", params, function (data) { model.updateFavorites(data, more); });
},
updateStatus: function (model, message, inReplyToId, callback) {
try {
var params = { status: message };
if (inReplyToId) { params.in_reply_to_status_id = inReplyToId; }
model.comm.post("https://api.twitter.com/1.1/statuses/update.json", params, function () {
if (callback) { callback(); }
APP.UTILITY.showStatus(APP.locale.status_updated || "Status Updated");
});
}
catch (e) {
System.Diagnostics.EventLog.writeEntry(e.toString());
$("#content").trigger("internalError");
}
},
search: function (model, params, completeCallback) {
model.comm.get("https://api.twitter.com/1.1/search/tweets.json", params, model.updateSearch, completeCallback);
},
retweetedBy: function (model, tweet) {
model.comm.get("https://api.twitter.com/1.1/statuses/retweets/{0}.json".format(tweet.retweeted_status_id),
{ count: 100 }, function (data) {
var count = Math.max(0, data.length - 1);
model.retweets[tweet.id] =
(APP.locale.retweeted_by_format || " {5} {0} {1}{2}{3}{4}").format(
APP.UTILITY.author(tweet.retweeted_by, ""),
count ? (APP.locale.retweeted_by_arg_1 || "+") : "",
count ? count : "",
count === 1 ? (APP.locale.retweeted_by_arg_3 || "") : "",
count > 1 ? (APP.locale.retweeted_by_arg_4 || "") : "",
APP.locale.retweeted_by || "RT by");
});
},
createFavorite: function (model, id) {
model.comm.post("https://api.twitter.com/1.1/favorites/create/json", {"id": id}, function () {
APP.UTILITY.showStatus(APP.locale.favorites_updated || "Favorites Updated");
APP.twitter.getFavorites(model);
});
},
deleteFavorite: function (model, id) {
model.comm.post("https://api.twitter.com/1.1/favorites/destroy.json", {"id": id}, function () {
setTimeout(function () { model.removeFavorite(id); }, 500);
});
},
deleteTweet: function (model, id) {
model.comm.post("https://api.twitter.com/1.1/statuses/destroy/" + id + ".json", null, function () {
model.removeStatus(id);
});
},
sendMessage: function (model, screen_name, message, success, error) {
try {
var params = { screen_name: screen_name, text: message };
model.comm.post("https://api.twitter.com/1/direct_messages/new.json", params, function () {
if (success) { success(); }
APP.UTILITY.showStatus(APP.locale.message_sent || "Message Sent");
setTimeout(function () { APP.twitter.getMessagesSent(model); }, 500);
}, undefined, error);
}
catch (e) {
System.Diagnostics.EventLog.writeEntry(e.toString());
$("#content").trigger("internalError");
}
},
retweet: function (model, id) {
model.comm.post("https://api.twitter.com/1.1/statuses/retweet/" + id + ".json", null, function () {
APP.UTILITY.showStatus(APP.locale.retweet_sent || "Retweet Sent");
});
},
getStatus: function (model, id, callback) {
model.comm.get("https://api.twitter.com/1.1/statuses/show.json", {"id": id}, callback);
},
getUserInfo: function (model, screenName, successCallback, errorCallback) {
model.comm.get("https://api.twitter.com/1.1/users/show.json", {"screen_name": screenName}, successCallback, null, errorCallback);
},
deleteFriendship: function (model, screenName, callback) {
model.comm.post("https://api.twitter.com/1.1/friendships/destroy.json", { "screen_name": screenName }, callback);
},
createFriendship: function (model, screenName, callback) {
model.comm.post("https://api.twitter.com/1.1/friendships/create.json", { "screen_name": screenName }, callback);
}
};
APP.title = function () {
var t =
'<div id="title" title="{0}"><span id="comm_indicator">•</span>' +
'<span id="lock_indicator" style="display:none"/></div>';
return t.format(APP.locale.compose_tweet || "Compose tweet (ctrl+S)");
};
APP.tabs = function () {
var locale = APP.locale;
function tab(id, title) {
return '<div id="' + id + '" title="' + title + '"/>';
}
return '<div id="tabs">' +
tab("tab_all", locale.tab_all_tooltip || "Unified:Home/Mentions/Messages") +
tab("tab_home", locale.tab_home_tooltip || "Home") +
tab("tab_mentions", locale.tab_mentions_tooltip || "Mentions") +
tab("tab_messages", locale.tab_messages_tooltip || "Messages") +
tab("tab_search", locale.tab_search_tooltip || "Search") +
tab("tab_favorites", locale.tab_favorites_tooltip || "Favorites") +
'</div>';
};
APP.edit = function (model) {
var that = {}, action, tweet, inReplyToId, toScreenName, dlg, title, textarea, counter;
function countChars() {
var count = textarea.val().length;
counter.text(count);
counter.removeClass("counter_ok counter_near counter_over");
counter.addClass((count > 135) ? ((count > 140) ? "counter_over" : "counter_near") : "counter_ok");
}
function sendNow() {
var text = textarea.val(),
length = text.length,
successCallback,
errorCallback;
if (length <= 0 || length > 140) { textarea.focus(); return; }
successCallback = function () { that.hide(); textarea.empty(); model.locked(false); };
errorCallback = function (xhr) { title.text($.parseJSON(xhr.responseText).error); };
switch (action) {
case "tweet": APP.twitter.updateStatus(model, text, undefined, successCallback, errorCallback); break;
case "reply_command": APP.twitter.updateStatus(model, text, inReplyToId, successCallback, errorCallback); break;
case "reply_all_command": APP.twitter.updateStatus(model, text, inReplyToId, successCallback, errorCallback); break;
case "message_command": APP.twitter.sendMessage(model, toScreenName, text, successCallback, errorCallback); break;
case "retweet_command": APP.twitter.updateStatus(model, text, undefined, successCallback, errorCallback); break;
}
title.text(APP.locale.send_now_sending || "Sending...").pulse();
}
function shortenUrl(url) {
if (url.contains('http://is.gd') === false) {
url = $.trim(url);
$.get("http://is.gd/api.php", { longurl: url }, function (shortUrl) {
textarea.val(textarea.val().replace(url, shortUrl));
countChars();
});
}
}
function shortenUrls() {
var length,
text = textarea.val(),
matches = text.match(String.regexUrl);
if (matches) {
length = matches.length;
while (length--) { shortenUrl(matches[length]); }
}
}
function buildDialog() {
var shorten, cancel, send, actions, button;
title = $("<div>", { text: APP.locale.edit_whats_happening || "What's happening?" }).bind("mousedown", that.hide);
textarea = $("<textarea>").bind("keyup", function (e) {
var sKey = 83, kKey = 75;
if (!e.shiftKey && !e.altKey && e.ctrlKey && e.keyCode === sKey) { sendNow(); }
else if (!e.shiftKey && !e.altKey && e.ctrlKey && e.keyCode === kKey) { shortenUrls(); }
else { countChars(); }
return false;
});
counter = $("<span>", { id: "counter", text: 0 });
button = function (id, txt, tip, cmd) {
return $("<span>", { id: id, text: txt, title: tip, "class": "hover" }).bind("mousedown", cmd);
};
shorten = button("shorten", APP.locale.edit_shorten || "Shorten", APP.locale.edit_shorten_tooltip || "Shorten urls (ctrl+K)", shortenUrls);
cancel = button("cancel", APP.locale.edit_cancel || "Cancel", "Esc", that.hide);
send = button("send", APP.locale.edit_send || "Send", "ctrl+S", sendNow);
actions = $("<div>", { css: { "text-align": "right"} }).append(counter, shorten, cancel, send);
return $("<div>", { id: "edit" }).append(title, textarea, actions).bind("keydown", function (e) {
var escapeKey = 27;
if (e.keyCode === escapeKey) {
that.hide();
return false;
}
});
}
that.dialog = function () {
return (dlg = dlg || buildDialog());
};
that.show = function (actionArg, tweetArg) {
action = actionArg || "tweet";
tweet = tweetArg || { screen_name: "" };
switch (action) {
case "reply_command":
title.text("@" + tweet.screen_name);
textarea.val("@" + tweet.screen_name + " ");
inReplyToId = tweet.id;
break;
case "reply_all_command":
title.text("@" + tweet.screen_name);
textarea.val("@{0} {1} ".format(tweet.screen_name, function () {
var names = tweet.text.match(String.regexScreenName);
return names ? names.unique().join(" ") : "";
} ()));
inReplyToId = tweet.id;
break;
case "message_command":
title.text((APP.locale.edit_message_to || "Message to:") + " " + tweet.screen_name);
toScreenName = tweet.screen_name;
break;
case "retweet_command":
title.text((APP.locale.edit_retweet || "Retweet") + " " + tweet.screen_name);
textarea.val("RT @{0} {1}".format(tweet.screen_name, tweet.text));
break;
default:
title.text(APP.locale.edit_whats_happening || "What's happening?");
break;
}
countChars();
dlg.show();
setTimeout(function () { textarea.focus().setCaretPos(1000); }, 100);
};
that.hide = function () {
dlg.hide();
textarea.empty();
$("#content").focus();
};
that.toggle = function (actionArg, tweetArg) {
if (dlg.is(":hidden")) { that.show(actionArg, tweetArg); }
else { that.hide(); }
};
return that;
};
APP.FORM = {
login: function () {
var that = {};
that.render = function (model) {
var content =
'<div id="login_container" style="height:400px;">' +
'<div id="login_spacer" style="margin-top:2pc; margin-left:13;">' +
'<div id="login_pin_button"><button id="get_pin" style="width:100;">{0}</button></div><br/>' +
'<div id="login_pin_text"><input id="pin_text" value="{1}" class="blur" type="text" style="width:90; margin-left:2;"/></div><br/>' +
'<div id="login_login_button"><button id="login" style="width:100;" disabled="disabled">{2}</button><br/></div><br/>' +
'<p id="login_help_link"><a href="http://blueonionsoftware.com/tweetz-help.aspx">{3}</a></p>' +
'<p id="pin_error"></p>' +
'</div></div>';
return content.format(
APP.locale.login_get_pin || "Get PIN",
APP.locale.login_enter_pin || "Enter PIN here",
APP.locale.login_login || "Login",
APP.locale.settings_help || "Help");
};
that.onSize = function () {
var docked = System.Gadget.docked,
height = docked ? APP.settings.dockedHeight() : APP.settings.undockedHeight();
$(document.body, "#container").css({ "width": docked ? "130px" : "300px", "height": height });
};
that.selectTab = function () { };
return that;
},
formBase: (function () {
var that = {}, locale, author, tabs, title;
function contentHeight(height) {
return height -
$("#header").outerHeight() -
$("#search").outerHeight() - 2;
}
function setFontSizes() {
var fontClass;
switch (APP.settings.fontSize()) {
case "small": fontClass = "small_font"; break;
case "large": fontClass = "large_font"; break;
default: fontClass = "medium_font"; break;
}
$("#content, #status, #tip, #ask, #edit, #more, #panel")
.removeClass("small_font medium_font large_font")
.addClass(fontClass);
}
that.onSize = function () {
var docked = System.Gadget.docked,
height = docked ? APP.settings.dockedHeight() : APP.settings.undockedHeight();
$("#base_style_sheet").loadStyleSheet("css/base.css");
$("#style_sheet").loadStyleSheet(APP.settings.styleSheet());
$(document.body).css({ width: (docked ? 130 : 300), "height": height });
$("#container").css({ "height": height - 2 });
$("#container, #edit").classAddOrRemove("docked", docked);
$("#content").css({ "height": contentHeight(height) });
setFontSizes();
};
function timeNumUnit(format, num, unit) {
var f = format.replace('{0}', '<span class="time_num">{0}</span>').replace(
'{1}', '<span class="time_unit">{1}</span>');
return f.format(num, unit);
}
function relativeTime(date) {
var diff = ((new Date()).getTime() - date.getTime()) / 1000;
return true && (
diff < 20 && (locale.time_seconds_ago || "seconds ago") ||
diff < 120 && timeNumUnit(locale.time_minute_ago || "{0}{1}", 1, locale.time_minute_unit || "m") ||
diff < 3600 && timeNumUnit(locale.time_minutes_ago || "{0}{1}", Math.floor(diff / 60), locale.time_minutes_unit || "m") ||
diff < 7200 && timeNumUnit(locale.time_hour_ago || "h", 1, locale.time_hour_unit || "h") ||
diff < 86400 && timeNumUnit(locale.time_hours_ago || "{0}{1}", Math.floor(diff / 3600), locale.time_hours_unit || "h") ||
Math.floor(diff / 86400) === 1 && (locale.time_yesterday || "yesterday") || "");
}
function timeStamp(time) {
var minutes = time.getMinutes();
if (minutes < 10) { minutes = "0" + minutes; }
return relativeTime(time) ||
"{0} {1}, {2} {3}:{4} {5}".format(
(locale.months || ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"])[time.getMonth()],
time.getDate(),
time.getYear(),
(time.getHours() % 12) || "12", minutes,
(time.getHours() < 12) ? (locale.time_am || "am") : (locale.time_pm || "pm"));
}
that.updateTimeStamps = function (model) {
$(".tweet_time").each(function () {
var ts,
stamp = $(this),
id = stamp.closest(".tweet").attr("id"),
tweet = model.getTweet(id);
if (tweet) {
ts = timeStamp(tweet.created_at);
if (stamp.html() !== ts) { stamp.html(ts); }
}
});
};
function inReplyTo(tweet) {
if (tweet.in_reply_to_screen_name) {
return '<span class="inreplyto_label">{2}</span> <span name="{0}" class="inreplyto">{1}</span>'.format(
tweet.in_reply_to_status_id, tweet.in_reply_to_screen_name, locale.foot_in_reply_to || "in reply to");
}
return "";
}
that.assembleForm = function (model, content) {
return '<div id="header">{0}{1}</div>'.format(title, tabs) + content;
};
that.selected = (function () {
var selectedId = "";
return function (id) {
if (id !== undefined) { selectedId = id; }
return selectedId;
};
})();
that.renderTweet = function (model, tweet) {
var classNames, htmlFormat;
classNames = "tweet" +
((tweet.id.toString() === that.selected().toString()) ? " selected_tweet" : "") +
((tweet.timelines.contains("mentions")) ? " mention" : "") +
((tweet.timelines.contains("messages")) ? " message" : "") +
((tweet.retweeted_status_id) ? " retweet" : "");
htmlFormat =
'<div id="{0}" class="{1}">' +
'<div class="tweet_inner">' +
'<img id="p{0}" src="{2}" class="pic"/>' +
'<div class="tweet_content">{3}{4}{5}' +
'<div class="tweet_text">{6}</div>' +
'</div>' +
'<div class="tweet_info">' +
'<span class="tweet_time">{7}</span>' +
'<span class="tweet_source">' +
'<span class="source_label">{8}</span>' +
'<span class="source">{9}</span> ' +
'</span>' +
'<span class="{10}">{11}</span>' +
'<span class="{12}">•</span>' +
'</div>' +
'</div>' +
'</div>';
if (!tweet.html) {
tweet.html = tweet.text.htmlEntities().atScreenNames().urlsToLinks(APP.settings.showLinks()).hashTags();
}
return htmlFormat.format(
tweet.id,
classNames,
tweet.profile_image_url,
(tweet.timelines.contains("messages")) ? '<img src="images/invisible.gif" class="msg"/>' : "",
(tweet.retweeted_status_id) ? '<img src="images/invisible.gif" class="retweet"/>' : "",
author(tweet.name, tweet.screen_name),
tweet.html,
timeStamp(tweet.created_at),
tweet.source ? (locale.foot_via || "via") : "",
tweet.source || "",
(model.retweets[tweet.id] && "tweet_retweet") || (inReplyTo(tweet) && "tweet_inreplyto"),
model.retweets[tweet.id] || inReplyTo(tweet),
model.unread[tweet.id] ? " unread" : "read");
};
that.render = function (model) {
var tweets = this.getTweets(model), length = tweets.length, content = "", i, t = that;
if (!locale) { locale = APP.locale; }
if (!author) { author = APP.UTILITY.author; }
if (!tabs) { tabs = APP.tabs(); }
if (!title) { title = APP.title(); }
model.locked(false);
for (i = 0; i < length; ++i) { content += t.renderTweet(model, tweets[i]); }
if (content.length) { content += this.more(); }
return this.assembleForm(model, '<div id="content">' + content + '</div>');
};
that.more = function () {
return '<div id="more">' + (locale.foot_more || "more") + '</div>';
};
return that;
} ()),
all: function () {
var that = Object.create(APP.FORM.formBase);
that.tabId = "tab_all";
that.getTweets = function (model) { return model.getAllTweets(); };
that.more = function () { return ""; };
return that;
},
home: function () {
var that = Object.create(APP.FORM.formBase);
that.tabId = "tab_home";
that.getTweets = function (model) { return model.getHomeTweets(); };
return that;
},
search: function () {
var that = Object.create(APP.FORM.formBase);
that.tabId = "tab_search";
that.getTweets = function (model) { return model.getSearchTweets(); };
that.assembleForm = function (model, content) {
var div = '<div id="search"><input id="search_query" value="{0}"/><img id="search_button" src="/images/tab/accept.png"/></div>',
textarea = div.format(model.lastSearch);
return '<div id="header">{0}{1}</div>'.format(APP.title(), APP.tabs()) + textarea + content;
};
return that;
},
favorites: function () {
var that = Object.create(APP.FORM.formBase);
that.tabId = "tab_favorites";
that.getTweets = function (model) { return model.getFavorites(); };
that.more = function () { return ""; };
return that;
},
mentions: function () {
var that = Object.create(APP.FORM.formBase);
that.tabId = "tab_mentions";
that.getTweets = function (model) { return model.getMentions(); };
return that;
},
messages: function () {
var that = Object.create(APP.FORM.formBase);
that.tabId = "tab_messages";
that.getTweets = function (model) { return model.getMessages(); };
return that;
}
};
APP.model = function (comm) {
var that = {},
statuses = {},
searches = {},
pendingUpdateEvents = {};
that.comm = comm;
that.links = {};
that.unread = {};
that.retweets = {};
that.sinceIdHome = "1";
that.sinceIdMentions = "1";
that.sinceIdMessages = "1";
that.lastSearch = "";
that.readTweet = function (data, timeline) {
try {
var tweet = {},
user = data.user || (data.sender_id_str === comm.userId() ? data.recipient : data.sender);
tweet.id = data.id_str;
tweet.screen_name = (user) ? user.screen_name : data.from_user;
tweet.name = (user) ? user.name : data.from_user;
tweet.profile_image_url = (user) ? user.profile_image_url : data.profile_image_url;
tweet.text = data.text.htmlDecode();
tweet.created_at = new Date((data.created_at || "").replace("+0000", "GMT"));
tweet.favorited = data.favorited;
tweet.source = (data.from_user) ? data.source.htmlDecode() : data.source;
tweet.in_reply_to_screen_name = data.in_reply_to_screen_name;
tweet.in_reply_to_status_id = data.in_reply_to_status_id_str;
tweet.retweeted_status_id = data.retweeted_status && data.retweeted_status.id_str;
if (tweet.retweeted_status_id) {
tweet.text = data.retweeted_status.text;
tweet.retweeted_by = tweet.screen_name;
tweet.screen_name = data.retweeted_status.user.screen_name;
tweet.name = data.retweeted_status.user.name;
tweet.profile_image_url = data.retweeted_status.user.profile_image_url;
that.retweets[tweet.id] = (
'<span class="tweet_retweet">' +
'<span class="retweet_label">RT by</span> ' +
'<span class="retweet_person">{0}</span>' +
'</span>').format(APP.UTILITY.author(tweet.retweeted_by, ""));
}
tweet.timelines = timeline || "";
return tweet;
}
catch (e) {
return null;
}
};
function asArraySortedByTime(obj) {
var items = [];
$.each(obj, function () { items.push(this); });
items.sort(function (a, b) { return b.created_at.getTime() - a.created_at.getTime(); });
return items;
}
function filterBy(timeline) {
var items = {};
$.each(statuses, function () {
if (this.timelines.contains(timeline)) {
items[this.id] = this;
}
});
return items;
}
function purgeOldTweetsFromTimeline(timeline) {
var i,
item,
items = asArraySortedByTime(filterBy(timeline)),
length = items.length;
for (i = 26; i < length; i += 1) {
item = items[i];
item.timelines = item.timelines.replace(timeline, "");
if (item.timelines.isBlank()) {
delete statuses[item.id];
$(item.id).remove();
}
}
}
function purgeOldTweetsFromAllTimelines() {
purgeOldTweetsFromTimeline("home");
purgeOldTweetsFromTimeline("mentions");
purgeOldTweetsFromTimeline("messages");
}
that.fireUpdateEvent = function (updateEvent, params) {
if (pendingUpdateEvents[updateEvent]) { clearTimeout(pendingUpdateEvents[updateEvent]); }
pendingUpdateEvents[updateEvent] = setTimeout(function () {
pendingUpdateEvents[updateEvent] = null;
$("#container").trigger(updateEvent, params);
}, 2000);
};
that.locked = (function () {
var locked = false;
return function (lock) {
if (lock === undefined) { return locked; }
locked = lock;
$("#content").trigger("lockIndicator", [locked]);
};
})();
that.isMention = (function () {
var nameExp;
return function (tweet) {
if (!nameExp) { nameExp = new RegExp("([^a-z0-9_]|^)(@|\\uff20)" + comm.username(), "i"); }
return nameExp.test(tweet.text.htmlEntities());
};
} ());
function update(store, data, timeline, updateEvent, more) {
var updated = false, sinceId = "0", forceChirp = false, maxId = APP.UTILITY.maxId;
$.each(data.results || data, function () {
var tweet = that.readTweet(this, timeline), matches;
if (tweet) {
if (store[tweet.id] === undefined) {
store[tweet.id] = tweet;
tweet.html = tweet.text.htmlEntities().atScreenNames().urlsToLinks(APP.settings.showLinks()).hashTags();
matches = tweet.html.findUrls();
if (matches) { $.each(matches, function (idx, val) { APP.UTILITY.reverseLookup(that.links, val); }); }
if (tweet.retweeted_status_id) { APP.twitter.retweetedBy(that, tweet); }
if (!more) { that.unread[tweet.id] = true; }
sinceId = maxId(tweet.id, sinceId);
updated = true;
}
tweet = store[tweet.id];
if (tweet.timelines.contains(timeline) === false) {
tweet.timelines += timeline + " ";
updated = true;
}
if (tweet.timelines.contains("mentions") === false && that.isMention(tweet)) {
tweet.timelines += "mentions ";
if (APP.settings.chirpOnMention()) { forceChirp = true; }
}
}
});
if (updated) {
switch (timeline) {
case "home":
that.sinceIdHome = maxId(sinceId, that.sinceIdHome);
if (APP.settings.chirpOnStatus() || forceChirp) { that.fireUpdateEvent("chirp"); }
break;
case "mentions":
that.sinceIdMentions = maxId(sinceId, that.sinceIdMentions);
if (APP.settings.chirpOnMention() || forceChirp) { that.fireUpdateEvent("chirp"); }
break;
case "messages":
that.sinceIdMessages = maxId(sinceId, that.sinceIdMessages);
if (APP.settings.chirpOnMessage() || forceChirp) { that.fireUpdateEvent("chirp"); }
break;
case "search":
break;
}
if (!that.locked() || timeline === "search" || more) { setTimeout(function () { that.fireUpdateEvent(updateEvent, [more], 2000); }); }
if (!that.locked()) { purgeOldTweetsFromAllTimelines(); }
}
}
that.updateHome = function (data, more) { update(statuses, data, "home", "homeUpdated", more); };
that.updateMentions = function (data, more) { update(statuses, data, "mentions", "mentionsUpdated", more); };
that.updateMessages = function (data, more) { update(statuses, data, "messages", "messagesUpdated", more); };
that.updateFavorites = function (data, more) { update(statuses, data, "favorites", "favoritesUpdated", more); };
that.updateSearch = function (data, more) { update(searches, data.statuses, "search", "searchUpdated", more); };
that.clearTweetHtml = function () {
$.each(statuses, function () { delete this.html; });
$.each(searches, function () { delete this.html; });
};
that.getOldestId = function (timeline) {
var t = asArraySortedByTime(filterBy(timeline)),
l = t.length;
return l ? t[l - 1].id : undefined;
};
that.getAllTweets = function () { return asArraySortedByTime(statuses); };
that.getHomeTweets = function () { return asArraySortedByTime(filterBy("home")); };
that.getSearchTweets = function () { return asArraySortedByTime(searches); };
that.getFavorites = function () { return asArraySortedByTime(filterBy("favorites")); };
that.getMentions = function () { return asArraySortedByTime(filterBy("mentions")); };
that.getMessages = function () { return asArraySortedByTime(filterBy("messages")); };
that.getTweet = function (id) { return statuses[id] || searches[id]; };
that.clearSearches = function () { searches = {}; that.oldestIdSearch = 1; };
function whereRetweetStatusId(items, id) {
var tweet;
$.each(items, function () {
if (this.retweeted_status_id === id) { tweet = this; return false; }
});
return tweet;
}
that.findRetweetedTweet = function (id) {
return whereRetweetStatusId(statuses, id) || that.getTweet(id);
};
that.removeStatus = function (id) {
if (statuses[id]) {
delete statuses[id];
that.fireUpdateEvent("homeUpdated", [true]);
}
};
that.removeFavorite = function (id) {
if (statuses[id]) {
statuses[id].favorited = false;
statuses[id].timelines = statuses[id].timelines.replace("favorites", "");
that.fireUpdateEvent("favoriteDeleted", [id]);
}
};
return that;
};
APP.view = function (model) {
var that = {},
currentFormName = "home",
controller = APP.controller(model, that),
forms,
showFormMap;
forms = {
login: APP.FORM.login(),
all: APP.FORM.all(),
home: APP.FORM.home(),
search: APP.FORM.search(),
favorites: APP.FORM.favorites(),
mentions: APP.FORM.mentions(),
messages: APP.FORM.messages()
};
$(document.body).append('<div id="status"/>');
function panel() {
var item = function (text, shortcut, commandId) {
return $("<tr>", { id: commandId })
.bind("mousedown", function () { $("#panel").trigger(commandId); })
.append($("<td>", { text: text }), $("<td>", { text: shortcut }));
},
separator = function () {
return $("<tr>", { "class": "panelseparator" }).append($("<td>", { "colspan": "2" }));
};
return $("<table>", { id: "panel" }).append(
item(APP.locale.panel_reply || "Reply", APP.locale.panel_reply_shortcut || "R", "reply_command"),
item(APP.locale.panel_reply_all || "Reply All", APP.locale.panel_reply_all_shortcut || "Shift+R", "reply_all_command"),
item(APP.locale.panel_message || "Message", APP.locale.panel_message_shortcut || "M", "message_command"),
item(APP.locale.panel_retweet || "RT (>)...", APP.locale.panel_retweet_shortcut || "T", "retweet_command"),
item(APP.locale.panel_retweet_api || "Retweet", APP.locale.panel_retweet_api_shortcut || "Shift+T", "native_retweet_command"),
separator(),
item(APP.locale.panel_favorite || "Favorite", APP.locale.panel_favorite_shortcut || "F", "favorite_command"),
item(APP.locale.panel_delete || "Delete", "", "delete_command"),
separator(),
item(APP.locale.panel_browser || "Browser", "", "open_in_browser_command"),
item(APP.locale.panel_copy || "Copy", APP.locale.panel_copy_shortcut || "Ctrl+C", "copy_command")
);
}
$("#container").after(panel());
that.showStatus = function (status) {
var sb, offset;
sb = $("#status");
offset = $("#content").offset();
sb.text(status);
sb.css({ "top": offset.top + 2, right: System.Gadget.docked ? "5px" : "21px" });
sb.fadeIn("normal", function () { $(this).fadeOut(); }).delay(800);
};
that.selected = function (id) {
var form = forms[currentFormName];
if (form && form.selected) {
if (id === undefined) { return form.selected(); }
form.selected(id);
}
};
that.edit = APP.edit(model);
$(document.body).append(that.edit.dialog());
showFormMap = {
"all": function (more) { that.updateForm("all", more); },
"home": function (more) { that.updateForm("home", more); },
"mentions": function (more) { that.updateForm("mentions", more); },
"messages": function (more) { that.updateForm("messages", more); },
"favorites": function (more) { that.updateForm("favorites", more); },
"search": function (more) { that.showForm("search", more); }
};
$("#container").live("homeUpdated mentionsUpdated messagesUpdated favoritesUpdated searchUpdated", function (e, more) {
showFormMap[currentFormName](more);
});
$("#container").live("favoriteDeleted", function (e, id) {
if (currentFormName === "favorites") {
$("#" + id).remove();
}
});
function setActiveTab(tabId) {
$("#tabs > img").removeClass("active");
$("#" + tabId).addClass("active");
}
that.previousForm = function () {
var formName;
switch (currentFormName) {
case "home": formName = "all"; break;
case "mentions": formName = "home"; break;
case "messages": formName = "mentions"; break;
case "search": formName = "messages"; break;
case "favorites": formName = "search"; break;
}
if (formName) { that.showForm(formName); }
};
that.nextForm = function () {
var formName;
switch (currentFormName) {
case "all": formName = "home"; break;
case "home": formName = "mentions"; break;
case "mentions": formName = "messages"; break;
case "messages": formName = "search"; break;
case "search": formName = "favorites"; break;
}
if (formName) { that.showForm(formName); }
};
that.onSize = function () { };
that.showForm = function (formName, keepScrollTop, callback) {
var form, formContent, scrollTop;
form = forms[formName];
formContent = form.render(model);
scrollTop = (keepScrollTop) ? $("#content").scrollTop() : 0;
$("#container").empty().html(formContent);
setActiveTab(form.tabId);
if (keepScrollTop) { $("#content").scrollTop(scrollTop); }
currentFormName = formName;
System.Gadget.onDock = form.onSize;
System.Gadget.onUndock = form.onSize;
that.onSize = form.onSize;
form.onSize();
that.updateCommIndicator();
if (callback) { callback(); }
$("#content").focus();
};
that.updateForm = function (formName, more) {
var form, content, tweet, updates, formContent;
if (more) { that.showForm(formName, more); }
updates = [];
form = forms[formName];
formContent = form.render(model);
content = $("<div>").html(formContent);
content.find(".tweet").each(function (idx) {
var t, id = "#" + this.id;
if (idx > 4) {
updates.length = 0;
that.showForm(formName, more);
return false;
}
if ($(id).length) { return false; }
t = $(this).hide();
updates.push(t.clone());
});
content.remove();
tweet = updates.pop();
while (tweet) {
$("#content").prepend(tweet);
$(tweet).slideDown("slow");
tweet = updates.pop();
}
};
that.updateTimeStamps = function () {
if (forms[currentFormName].updateTimeStamps) {
forms[currentFormName].updateTimeStamps(model);
}
};
that.getCurrentFormName = function () {
return currentFormName;
};
that.cursor = function (cursor) {
$("#container").css("cursor", cursor);
};
function settingsClosed(e) {
if (e.closeAction === e.Action.commit) {
model.clearTweetHtml();
setTimeout(function () {
that.showForm(currentFormName);
APP.UTILITY.versionChecker.run();
}, 500);
}
}
System.Gadget.settingsUI = "settings.html";
System.Gadget.onSettingsClosed = settingsClosed;
that.updateCommIndicator = (function () {
var timer,
lastColor = "#f00",
setIndicator = function (color) { $("#comm_indicator").css("color", color); };
return function (state) {
if (timer) { clearTimeout(timer); timer = null; }
if (state === undefined) { setIndicator(lastColor); return; }
if (state === "accessing") { lastColor = "#ff0"; setIndicator("#ff0"); return; }
if (state === "tooManyRequests") { lastColor = "#00f"; setIndicator("#00f"); return; }
lastColor = (state === "success") ? "#0d0" : "#f00";
timer = setTimeout(function () { setIndicator(lastColor); }, 1500);
};
})();
that.lockIndicator = function (locked) {
var l = $("#lock_indicator");
if (locked) { l.show(); }
else { l.hide(); }
};
that.showStatusFlyout = function (tweet) {
var form = APP.FORM.home(), renderedTweet = form.renderTweet(model, tweet);
APP.statusParams = { tweet: renderedTweet };
System.Gadget.Flyout.file = "inreplyto.html";
System.Gadget.Flyout.show = true;
};
that.start = function () {
if (APP.settings.username()) { controller.startTimelines(); }
else { that.showForm("login"); }
};
return that;
};
APP.controller = function (model, view) {
var that = {}, homeTimer, mentionsTimer, messagesTimer, timeStampTimer, switchStyleSheet;
function stopTimer(timerId) {
if (timerId !== undefined) { clearInterval(timerId); }
}
that.startTimelines = function () {
var start = function (getTimeline, interval, id) {
stopTimer(id);
getTimeline(model, true);
return setInterval(function () { getTimeline(model, false); }, interval * 1000 * 60);
};
$("#base_style_sheet").loadStyleSheet("css/base.css");
$("#style_sheet").loadStyleSheet(APP.settings.styleSheet());
view.showForm("all");
homeTimer = start(APP.twitter.getHome, APP.settings.intervalHome(), homeTimer);
mentionsTimer = start(APP.twitter.getMentions, APP.settings.intervalMentions(), mentionsTimer);
messagesTimer = start(APP.twitter.getMessages, APP.settings.intervalMessages(), messagesTimer);
APP.twitter.getMessagesSent(model);
if (timeStampTimer === undefined) { timeStampTimer = setInterval(view.updateTimeStamps, 60000); }
setTimeout(function () { APP.UTILITY.versionChecker.run(); }, 20000);
};
$("#container").live("accessTokenReceived", function () {
that.startTimelines();
});
$("#title").live("mousedown", function () {
view.edit.toggle("tweet");
});
$("#container").live("keydown", function (e) {
var sKey = 83, dKey = 68, source, w;
if (e.ctrlKey && e.keyCode === sKey) {
view.edit.show("tweet");
return false;
}
if (e.ctrlKey && e.keyCode === dKey) {
w = window.open('', 'DOM', '');
w.document.write('<html><head><title>Document Dump</title></head><body><pre>');
w.document.write('</head><body><pre>');
source = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\x0d<html>';
source += document.getElementsByTagName("html")[0].innerHTML;
source += "\x0d</html>";
w.document.write(source.htmlEntities());
w.document.write('</pre></body></html>');
w.document.close();
return false;
}
});
that.commands = {
reply: APP.UTILITY.command("reply", function () { }, true),
replyAll: APP.UTILITY.command("reply_all", function () { }, true)
};
function canDelete(id) {
var tweet = model.getTweet(id);
return (tweet && tweet.screen_name === model.comm.username());
}
function isFavorite(id) {
var tweet = model.getTweet(id);
return (tweet && tweet.favorited);
}
(function () {
var timerId;
$(".pic").live("mouseenter mouseleave", function (e) {
var pic;
if (e.type === "mouseenter") {
pic = $(this);
timerId = setTimeout(function () {
var offset, id, panel, diff, top;
if ($("#edit").is(":visible")) { return false; }
offset = pic.offset();
id = pic.attr("id").slice(1);
panel = $("#panel");
panel.data("id", id);
$("#delete_command").classAddOrRemove("menu_off", !canDelete(id));
$("#favorite_command > td:first").html((isFavorite(id) ? "<b>!</b> " : "") + APP.locale.panel_favorite || "Favorite");
diff = $("#container").outerHeight() - (offset.top + panel.outerHeight());
top = (diff < 0) ? offset.top + diff - 4 : offset.top;
panel.css({ "top": top, "left": offset.left - 4, display: "block" });
return false;
}, 300);
}
else if (e.type === "mouseleave") {
clearTimeout(timerId);
}
});
})();
$("#panel").live("mousemove", function () {
return false;
});
$("body").live("mousemove mouseleave", function () {
$("#panel").css("display", "none");
});
$("#usr_button").live("mousedown", function () {
var tweet = model.getTweet($("#panel").data("id"));
APP.showUserParams = { model: model, view: view, showUserName: "@" + tweet.screen_name };
System.Gadget.Flyout.file = "showuser.html";
System.Gadget.Flyout.show = true;
});
$("#panel").live("reply_command", function (evt) {
var panel = $(this);
panel.hide();
view.edit.show(evt.type, model.getTweet(panel.data("id")));
});
$("#panel").live("reply_all_command", function (evt) {
var panel = $(this);
panel.hide();
view.edit.show(evt.type, model.getTweet(panel.data("id")));
});
$("#panel").live("message_command", function (evt) {
var panel = $(this);
panel.hide();
view.edit.show(evt.type, model.getTweet(panel.data("id")));
});
$("#panel").live("retweet_command", function (evt) {
var panel = $(this);
panel.hide();
view.edit.show(evt.type, model.getTweet(panel.data("id")));
});
$("#panel").live("native_retweet_command", function () {
var panel = $(this);
panel.hide();
APP.UTILITY.popup("ask", APP.locale.retweet_confirmation || "Retweet to your followers?", $(this), function () {
APP.twitter.retweet(model, panel.data("id"));
});
});
$("#panel").live("delete_command", function () {
var panel;
panel = $(this);
panel.hide();
APP.twitter.deleteTweet(model, panel.data("id"));
});
$("#panel").live("favorite_command", function () {
var panel = $(this), id = panel.data("id"), func;
panel.hide();
func = isFavorite(id) ? APP.twitter.deleteFavorite : APP.twitter.createFavorite;
func(model, id);
});
$("#panel").live("open_in_browser_command", function () {
var panel = $(this),
tweet = model.getTweet(panel.data("id")),
url = "https://twitter.com/{0}/statuses/{1}".format(tweet.screen_name, tweet.id);
panel.hide();
APP.UTILITY.shellRun(url);
});
$("#panel").live("copy_command", function () {
var panel = $(this),
tweet = model.getTweet(panel.data("id"));
panel.hide();
if (tweet) { window.clipboardData.setData("text", tweet.text); }
});
$("#container").live("keydown", function (e) {
var cKey = 67, fKey = 70, mKey = 77, rKey = 82, tKey = 84, command, tweetId = view.selected(), panel;
if (!tweetId || $("input").is(":focus")) { return; }
switch (e.keyCode) {
case cKey: if (e.ctrlKey) { command = "copy_command"; } else { return; } break;
case fKey: command = "favorite_command"; break;
case mKey: command = "message_command"; break;
case rKey: command = (e.shiftKey ? "reply_all_command" : "reply_command"); break;
case tKey: command = (e.shiftKey ? "native_retweet_command" : "retweet_command"); break;
default: return true;
}
panel = $("#panel");
if (panel) {
panel.data("id", tweetId);
panel.trigger(command);
}
return false;
});
function scroll(delta) {
var i,
content = $("#content"),
s = content.scrollTop(),
o = content.offset().top - s,
t = 0, p1 = 0, p2, gap = 7,
tweets = content.find(".tweet"),
length = tweets.length;
for (i = 0; i < length; i += gap) {
if (($(tweets[i]).offset().top - o) > s) { i -= (gap + 1); break; }
}
if (i > tweets.length) { i -= (gap + 1); }
for (i = Math.max(0, i); i < length; i += 1) {
p2 = p1;
p1 = t;
t = $(tweets[i]).offset().top - o;
if (t > s) {
if (delta > 0) { t = p2; }
break;
}
}
content.scrollTop(t);
model.locked(t !== 0);
}
$("#content").live("mousewheel", function () {
scroll(window.event.wheelDelta);
return false;
});
$("#content").live("keydown", function (e) {
var up = 38, down = 40, left = 37, right = 39, pgUp = 33, pgDn = 34, home = 36, end = 35, direction = 0;
if (e.keyCode === up) { direction = 1; }
if (e.keyCode === down) { direction = -1; }
if (e.keyCode === pgUp) { direction = 3; }
if (e.keyCode === pgDn) { direction = -3; }
if (e.keyCode === home) { model.locked(false); }
if (e.keyCode === end) { model.locked(true); }
if (e.keyCode === left) { view.previousForm(); }
if (e.keyCode === right) { view.nextForm(); }
if (direction) { scroll(direction); return false; }
});
$("#tab_all").live("mousedown", function () {
var refresh = view.getCurrentFormName() === "all";
$("#content").empty();
view.showForm("all");
if (refresh) {
APP.twitter.getHome(model);
APP.twitter.getMentions(model);
APP.twitter.getMessages(model);
}
});
$("#tab_home").live("mousedown", function () {
var refresh = view.getCurrentFormName() === "home";
view.showForm("home", false, function () {
if (refresh) { APP.twitter.getHome(model); }
});
});
$("#tab_mentions").live("mousedown", function () {
var refresh = view.getCurrentFormName() === "mentions";
view.showForm("mentions", false, function () {
if (refresh) { APP.twitter.getMentions(model); }
});
});
$("#tab_messages").live("mousedown", function () {
var refresh;
refresh = view.getCurrentFormName() === "messages";
view.showForm("messages", false, function () {
if (refresh) { APP.twitter.getMessages(model); }
});
});
$("#tab_search").live("mousedown", function () {
view.showForm("search");
});
$("#tab_favorites").live("mousedown", function () {
view.showForm("favorites");
APP.twitter.getFavorites(model);
});
function tooltip(tipText, element) {
APP.UTILITY.popup("tip", tipText, element);
}
(function () {
var timerId;
$(".link").live("mouseenter mouseleave", function (e) {
var link = $(this), href;
if (e.type === "mouseenter" && $("#tip").length === 0) {
timerId = setTimeout(function () {
timerId = 0;
href = link.attr("href");
tooltip(model.links[href] || href, link);
}, 300);
}
else if (e.type === "mouseleave") {
if (timerId) { clearTimeout(timerId); }
else { $("#tip").slideUp("fast", function () { $(this).remove(); }); }
}
});
})();
function submitSearch(params) {
if (params === undefined) { params = {}; }
params.q = $("#search_query").val();
if (params.q.length === 0) { return; }
if (model.lastSearch !== params.q) {
model.clearSearches();
model.fireUpdateEvent("searchUpdated");
}
model.lastSearch = params.q;
$("#search_button").attr("src", "/images/waiting.gif");
APP.twitter.search(model, params, function () {
$("#search_button").attr("src", "/images/tab/accept.png");
});
}
$("#search_button").live("mousedown", function () { submitSearch(); });
$("#search_query").live("keydown", function (e) {
if (e.keyCode === 13) { submitSearch(); }
});
$(".hashtag").live("mousedown", function () {
var query = $(this).text().replace("\uff03", "#");
view.showForm("search", false, function () {
$("#search_query").val(query);
submitSearch();
});
});
$(".screenname").live("mousedown", function () {
var screen_name = $(this).attr("sc").replace("\uff20", "@");
APP.showUserParams = { model: model, view: view, showUserName: screen_name };
System.Gadget.Flyout.file = "showuser.html";
System.Gadget.Flyout.show = true;
});
$(".tweet").live("mousedown", function () {
var oldId = view.selected(),
newId = $(this).attr("id");
$(".tweet").removeClass("selected_tweet");
view.selected(0);
if (oldId !== newId) {
$(this).addClass("selected_tweet");
view.selected($(this).attr("id"));
}
});
$("#container").live("chirp", function () {
System.Sound.playSound("notify.wav");
});
$("#content:not(:text, textarea)").live("keydown", function (e) {
var cKey = 67, tweet;
if (e.ctrlKey && e.keyCode === cKey) {
tweet = model.getTweet(view.selected());
if (tweet) { window.clipboardData.setData("text", tweet.text); }
return false;
}
});
$("#content").live("selectstart", function () {
// Kill selection of text in gadget
return false;
});
$("#content").live("showStatus", function (e, status) {
view.showStatus(status);
});
$("#content").live("commAccessing", function () {
view.updateCommIndicator("accessing");
});
$("#content").live("commSuccess", function () {
view.updateCommIndicator("success");
});
$("#content").live("commError", function () {
view.updateCommIndicator("error");
});
$("#content").live("commTooManyRequests", function() {
view.updateCommIndicator("tooManyRequests");
});
$("#content").live("internalError", function () {
view.updateCommIndicator("internal error");
});
$("#content").live("lockIndicator", function (e, locked) {
view.lockIndicator(locked);
});
$(".inreplyto").live("mousedown", function () {
var id = $(this).attr("name"),
tweet = model.getTweet(id);
if (tweet) { view.showStatusFlyout(tweet); }
else {
APP.twitter.getStatus(model, id, function (data) {
var replyTweet = model.readTweet(data, "");
view.showStatusFlyout(replyTweet);
});
}
});
$("#more").live("mousedown", function () {
switch (view.getCurrentFormName()) {
case "home": APP.twitter.getHome(model, true); break;
case "mentions": APP.twitter.getMentions(model, true); break;
case "messages": APP.twitter.getMessages(model, true); break;
case "search": submitSearch({ max_id: model.oldestIdSearch }); break;
default: return false;
}
$(this).empty().append($("<img>", { src: "images/waiting.gif" }));
});
switchStyleSheet = (function () {
var index, styleSheet,
styleSheets = ["css/original.css", "css/aqua.css", "css/white.css"];
return function () {
index = $.inArray(APP.settings.styleSheet(), styleSheets);
styleSheet = styleSheets[(index + 1) % styleSheets.length];
APP.settings.styleSheet(styleSheet);
$("#style_sheet").loadStyleSheet(styleSheet);
view.onSize();
};
})();
$("#container").live("keydown", function (e) {
var qKey = 81;
if (e.ctrlKey && e.keyCode === qKey) {
switchStyleSheet();
return false;
}
});
$(".tweet").live("mouseenter", function () {
$(this).find(".unread").removeClass("unread").addClass("read");
delete model.unread[this.id];
});
// $("#container").live("keydown", function (e) {
// var pKey = 80;
// if (e.keyCode === pKey) {
// $("#content div.tweet:first").remove();
// $("#content div.tweet:first").remove();
// $("#content div.tweet:first").remove();
// model.fireUpdateEvent("homeUpdated");
// return false;
// }
// });
$("#get_pin").live("click", function () {
$("#pin_error").hide();
APP.twitter.getPin(model.comm,
function () { },
function (x, t, e) { $("#pin_error").text(t).show(); });
return false;
});
$("#pin_text").live("focus", function (e) {
$(this).val("").removeClass("blur");
$("#login").removeAttr("disabled");
});
$("#login").live("click", function () {
APP.twitter.getAccessToken(model.comm, $("#pin_text").val(), function (x, t, e) {
$("#pin_error").text(t).show();
return false;
});
});
return that;
};
APP.run = function () {
var view = APP.view(APP.model(APP.comm()));
view.start();
};
// x-auth
// consider new tweet notification like chrome bird
// different action panels for different states (delete for your own tweets)
// popup send to list
// spell checker
// geolocation
// switch panels using left/right arrows
// more keyboard shortcuts
// twittpic
// search near you
// tooltips on panel
// twittlonger
// choose sounds
// Translate tweet (ctrl+T)
// Auto translate?
// indicate private account
// hide user icons option
// accessibility
// publish future tweets
// multiple replies
// tall tweets
// twitter symbols
// add unfavorites
// fix keyboard accelerators