restructuring of the whole code basis

This commit is contained in:
Jeena Paradies 2012-11-07 03:51:27 +01:00
parent 2efbbd1d0a
commit d99ff86520
60 changed files with 14404 additions and 2490 deletions

View file

@ -1,21 +0,0 @@
//
// Constants.js
// Tentia
//
// Created by Jeena on 19.09.11.
// Licence: BSD (see attached LICENCE.txt file).
//
OAUTH_CONSUMER_KEY = "JPmU8KJhiBKfpohCiWLg"
OAUTH_CONSUMER_SECRET = "jtfSrnDrRcUnL1nqTMcAW0055m63EMClmkxhiBjQ"
OAUTH_SIGNATURE_METHOD = "HMAC-SHA1"
OAUTH_REQUEST_TOKEN_URL = "http://twitter.com/oauth/request_token"
OAUTH_USER_AUTHORIZATION_URL = "http://twitter.com/oauth/authorize"
OAUTH_ACCESS_TOKEN_URL = "http://twitter.com/oauth/access_token"
OAUTH_SERVICE_NAME = "twitter.com"
APP_NAME = "Tentia";
API_PATH = "http://api.twitter.com/1/";
WEBSITE_PATH = "http://twitter.com/";

View file

@ -1,457 +0,0 @@
//
// Core.js
// Tentia
//
// Created by Jeena on 15.04.10.
// Licence: BSD (see attached LICENCE.txt file).
//
function Core(action) {
this.max_length = 200;
// this.timeout = 2 * 60 * 1000;
this.timeout = 10 * 1000; // every 10 seconds
this.action = action;
this.getNewData();
this.unread_mentions = 0;
this.since_id = null;
this.since_id_entity = null;
this.since_time = 0;
this.body = document.createElement("ol");
this.body.className = this.action;
this.cache = {};
this.is_not_init = false;
var _this = this;
setInterval(function() { _this.getNewData() }, this.timeout);
}
Core.prototype.newStatus = function(status) {
if(status != null && status.length > 0) {
for(var i = status.length-1, c=0; i>=c; --i) {
if(this.body.childNodes.length > 0) {
if(this.body.childNodes.length > this.max_length) {
this.body.removeChild(this.body.lastChild);
}
this.body.insertBefore(this.getItem(status[i]), this.body.firstChild);
} else {
this.body.appendChild(this.getItem(status[i]));
}
}
}
if(this.action == "mentions" && this.is_not_init) {
this.unread_mentions += status.length;
controller.unreadMentions_(this.unread_mentions);
}
this.is_not_init = true;
}
Core.prototype.logout = function() {
this.body.innerHTML = "";
}
Core.prototype.getItem = function(status) {
var _this = this;
this.since_id = status.id;
this.since_id_entity = status.entity;
var template = this.getTemplate();
template.reply_to.onclick = function() {
var mentions = [];
for (var i = 0; i < status.mentions.length; i++) {
var mention = status.mentions[i];
if(mention.entity != controller.stringForKey_("entity"))
mentions.push(mention);
};
replyTo(status.entity, status.id, mentions);
return false;
}
//template.retweet.onclick = function() { template.retweet.className = "hidden"; _this.retweet(status.id_str, template.item); return false; }
template.username.innerText = status.entity;
template.username.href = status.entity; // FIXME open profile
findProfileURL(status.entity, function(profile_url) {
if (profile_url) {
getURL(profile_url, "GET", function(resp) {
var profile = JSON.parse(resp.responseText);
var basic = profile["https://tent.io/types/info/basic/v0.1.0"];
if (profile && basic) {
if(basic.name) {
template.username.title = template.username.innerText;
template.username.innerText = basic.name;
}
if(basic.avatar_url) {
template.image.onerror = function() { template.image.src = 'default-avatar.png' };
template.image.src = basic.avatar_url;
}
}
}, null, false); // do not send auth-headers
}
});
template.in_reply.parentNode.className = "hidden";
template.message.innerHTML = replaceUsernamesWithLinks(replaceURLWithHTMLLinks(status.content.text, status.entities, template.message));
findMentions(template.message, status.mentions);
var time = document.createElement("abbr");
time.innerText = ISODateString(new Date(status.published_at * 1000));
time.title = time.innerText;
time.className = "timeago";
$(time).timeago();
template.ago.appendChild(time);
// {"type":"Point","coordinates":[57.10803113,12.25854746]}
if (status.content && status.content.location && status.content.location.type == "Point") {
template.geo.href = "http://maps.google.com/maps?q=" + status.content.location.coordinates[0] + "," + status.content.location.coordinates[1];
template.geo.style.display = "";
}
template.source.href = status.app.url;
template.source.innerHTML = status.app.name;
template.source.title = status.app.url;
return template.item;
}
Core.prototype.getTemplate = function() {
if(this.template == "undefined") {
return jQuery.extend(true, {}, this.template);
}
var a = document.createElement("a");
var item = document.createElement("li");
var reply_to = a.cloneNode();
reply_to.className = "reply_to"
reply_to.innerText = " ";
reply_to.href = "#";
item.appendChild(reply_to);
var retweet = a.cloneNode();
retweet.className = "retweet";
retweet.innerText = " ";
retweet.href = "#";
// item.appendChild(retweet); // FIXME
var image = document.createElement("img");
image.className = "image";
image.src = "default-avatar.png";
image.onmousedown = function(e) { e.preventDefault(); };
item.appendChild(image);
var image_username = a.cloneNode();
image.appendChild(image_username);
var data = document.createElement("div");
data.className = "data";
item.appendChild(data);
var head = document.createElement("h1");
data.appendChild(head);
var username = a.cloneNode();
head.appendChild(username);
var in_reply = document.createElement("span");
in_reply.className = "reply";
head.appendChild(in_reply);
var space = document.createTextNode(" ");
head.appendChild(space);
var geo = document.createElement("a");
geo.style.display = "none";
head.appendChild(geo);
var pin = document.createElement("img");
pin.src = "pin.png";
pin.alt = "Map link";
geo.appendChild(pin);
var in_reply_text = document.createTextNode(" in reply to ");
in_reply.appendChild(in_reply_text)
var in_reply_a = a.cloneNode();
in_reply.appendChild(in_reply_a);
var message = document.createElement("p");
message.className = "message";
data.appendChild(message);
var images = document.createElement("p")
images.className = "images";
data.appendChild(images);
var date = message.cloneNode();
date.className = "date";
data.appendChild(date);
var ago = a.cloneNode();
date.appendChild(ago);
var from = document.createTextNode(" from ");
date.appendChild(from)
var source = document.createElement("a");
source.className = "source";
date.appendChild(source)
this.template = {
item: item,
reply_to: reply_to,
retweet: retweet,
image: image,
username: username,
in_reply: in_reply_a,
message: message,
ago: ago,
source: source,
geo: geo,
images: images
}
return jQuery.extend(true, {}, this.template);
}
Core.prototype.getNewData = function() {
var those = this;
var url = URI(mkApiRootPath("/posts"));
url.addSearch("post_types", "https://tent.io/types/post/status/v0.1.0");
url.addSearch("limit", this.max_length);
if(this.since_id) {
url.addSearch("since_id", this.since_id);
url.addSearch("since_id_entity", this.since_id_entity);
}
if (this.action == "mentions") {
url.addSearch("mentioned_entity", controller.stringForKey_("entity"));
}
var http_method = "GET";
var callback = function(resp) {
try {
var json = JSON.parse(resp.responseText)
} catch (e) {
//alert(resp.responseText);
alert(url + " JSON parse error");
throw e;
}
those.newStatus(json);
}
var data = null;
if (controller.stringForKey_("user_access_token")) {
getURL(url.toString(), http_method, callback, data); // FIXME: error callback
}
}
Core.prototype.sendNewMessage = function(content, in_reply_to_status_id, in_reply_to_entity) {
var _this = this;
var url = URI(mkApiRootPath("/posts"));
var http_method = "POST";
var callback = function(data) { _this.getNewData(); }
var data = {
"type": "https://tent.io/types/post/status/v0.1.0",
"published_at": (new Date().getTime() / 1000),
"permissions": {
"public": true
},
"content": {
"text": content,
},
};
var mentions = parseMentions(content, in_reply_to_status_id, in_reply_to_entity);
if (mentions.length > 0) {
data["mentions"] = mentions;
}
getURL(url.toString(), http_method, callback, JSON.stringify(data)); // FIXME: error callback
}
/* Helper functions */
function replaceURLWithHTMLLinks(text, entities, message_node) {
var exp = /(([^\^]https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_()|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
return text.replace(exp, "<a href='$1'>$1</a>");
}
function replaceUsernamesWithLinks(text, mentions) {
return text; // FIXME!
var username = /(^|\s)(\^)(\w+)/ig;
var hash = /(^|\s)(#)(\w+)/ig;
text = text.replace(username, "$1$2<a href='tentia://profile/$3'>$3</a>");
return text.replace(hash, "$1$2<a href='http://search.twitter.com/search?q=%23$3'>$3</a>");
}
function replyTo(entity, status_id, mentions) {
var string = "^" + entity.replace("https://", "") + " ";
for (var i = 0; i < mentions.length; i++) {
var e = mentions[i].entity.replace("https://", "");
if(string.indexOf(e) == -1) string += "^" + e + " ";
}
controller.openNewMessageWindowInReplyTo_statusId_withString_(entity, status_id, string);
}
function loadPlugin(url) {
var plugin = document.createElement("script");
plugin.type = "text/javascript";
plugin.src = url;
document.getElementsByTagName("head")[0].appendChild(plugin);
}
String.prototype.startsWith = function(prefix) {
return this.indexOf(prefix) === 0;
}
String.prototype.endsWith = function(suffix) {
return this.match(suffix+"$") == suffix;
};
function getUrlVars(url)
{
var vars = [], hash;
if(url.indexOf("#") > -1) url = url.slice(0, url.indexOf("#"));
var hashes = url.slice(url.indexOf('?') + 1).split('&');
for(var i = 0; i < hashes.length; i++)
{
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
}
function replaceShortened(url, message_node) {
var api = "http://api.bitly.com";
if(url.startsWith("http://j.mp/")) {
api = "http://api.j.mp";
}
var api_url = api + "/v3/expand?format=json&apiKey=R_4fc2a1aa461d076556016390fa6400f6&login=twittia&shortUrl=" + url; // FIXME: new api key
$.ajax({
url: api_url,
success: function(data) {
var new_url = data.data.expand[0].long_url;
if (new_url) {
var regex = new RegExp(url, "g");
message_node.innerHTML = message_node.innerHTML.replace(regex, new_url);
}
},
error:function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
}
function findMentions(node, mentions) {
var text = node.innerHTML;
var mentions_in_text = [];
var res = text.match(/(\^\S+)/ig);
if (res) {
for (var i = 0; i < res.length; i++) {
var name = res[i];
var e = name.substring(1);
if (e.substring(0,7) != "http://" && e.substring(0,8) != "https://") {
e = "https://" + e;
}
for (var j = 0; j < mentions.length; j++) {
var m = mentions[j];
if(m.entity.startsWith(e)) {
mentions_in_text.push({
entity: m.entity,
text: name
});
}
}
}
}
for (var i = 0; i < mentions_in_text.length; i++) {
var mention = mentions_in_text[i];
(function(mention) { // need this closure
findProfileURL(mention.entity, function(profile_url) {
if (profile_url) {
getURL(profile_url, "GET", function(resp) {
var profile = JSON.parse(resp.responseText);
var basic = profile["https://tent.io/types/info/basic/v0.1.0"];
if (profile && basic) {
if(basic.name) {
var new_text = node.innerHTML.replace(
mention.text,
"<strong class='name' title='" + mention.entity + "'" + ">"
+ basic.name
+ "</strong>"
);
node.innerHTML = new_text;
}
}
}, null, false); // do not send auth-headers
}
});
})(mention);
}
}
function parseMentions(text, post_id, entity) {
var mentions = [];
if (post_id && entity) {
mentions.push({
post: post_id,
entity: entity
})
}
var res = text.match(/(\^\S+)/ig);
if (res) {
for (var i = 0; i < res.length; i++) {
var e = res[i].substring(1);
if (e.substring(0,7) != "http://" && e.substring(0,8) != "https://") {
e = "https://" + e;
}
if (e != entity) {
mentions.push({entity:e});
}
}
}
return mentions;
}
function ISODateString(d){
function pad(n){return n<10 ? '0'+n : n}
return d.getUTCFullYear()+'-'
+ pad(d.getUTCMonth()+1)+'-'
+ pad(d.getUTCDate())+'T'
+ pad(d.getUTCHours())+':'
+ pad(d.getUTCMinutes())+':'
+ pad(d.getUTCSeconds())+'Z'
}
var tentia_instance;

View file

@ -1,142 +0,0 @@
//
// OauthImplementation.js
// Tentia
//
// Created by Jeena on 19.09.11.
// Licence: BSD (see attached LICENCE.txt file).
//
function getUrlVars(url) {
var vars = [], hash;
if(url.indexOf("#") > -1) url = url.slice(0, url.indexOf("#"));
var hashes = url.slice(url.indexOf('?') + 1).split('&');
for(var i = 0; i < hashes.length; i++)
{
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
}
function OauthImplementation() {
this.app_info = {
"id": null,
"name": "Tentia",
"description": "A small TentStatus client.",
"url": "http://jabs.nu/Tentia/",
"icon": "http://jabs.nu/Tentia/icon.png",
"redirect_uris": [
"tentia://oauthtoken"
],
"scopes": {
"read_posts": "Uses posts to show them in a list",
"write_posts": "Posts on users behalf"
}
};
this.register_data = null;
this.profile = null;
this.state = null;
this.authenticate();
}
OauthImplementation.prototype.authenticate = function() {
this.entity = controller.stringForKey_("entity");
this.requestProfileURL(this.entity);
}
OauthImplementation.prototype.apiRoot = function() {
return this.profile["https://tent.io/types/info/core/v0.1.0"]["servers"][0];
}
OauthImplementation.prototype.requestProfileURL = function (entity) {
var those = this;
findProfileURL(entity, function(profile_url) {
those.register(profile_url);
});
}
OauthImplementation.prototype.register = function (url) {
var those = this;
getURL(url, "GET", function(resp) {
those.profile = JSON.parse(resp.responseText);
controller.setString_forKey_(those.apiRoot(), "api_root");
var callback = function(resp) {
var data = JSON.parse(resp.responseText);
those.authRequest(data);
}
getURL(mkApiRootPath("/apps"), "POST", callback, JSON.stringify(those.app_info));
});
}
OauthImplementation.prototype.authRequest = function(register_data) {
// id
// mac_key_id
// mac_key
// mac_algorithm
this.register_data = register_data;
// Needed for later App Registration Modification
controller.setString_forKey_(register_data["mac_key"], "app_mac_key");
controller.setString_forKey_(register_data["mac_key_id"], "app_mac_key_id");
controller.setString_forKey_(register_data["id"], "app_id");
controller.setString_forKey_(register_data["mac_algorithm"], "app_mac_algorithm");
this.state = makeid(19);
var auth = "/oauth/authorize?client_id=" + register_data["id"]
+ "&redirect_uri=" + escape(this.app_info["redirect_uris"][0])
+ "&scope=" + Object.keys(this.app_info["scopes"]).join(",")
+ "&state=" + this.state
+ "&tent_post_types=" + escape("https://tent.io/types/posts/status/v0.1.0");
controller.openURL_(this.apiRoot() + auth);
}
OauthImplementation.prototype.requestAccessToken = function(responseBody) {
// /oauthtoken?code=51d0115b04d1ed94001dde751c5b360f&state=aQfH1VEohYsQr86qqyv
var urlVars = getUrlVars(responseBody);
if(this.state && this.state != "" && urlVars["state"] == this.state) {
var url = mkApiRootPath("/apps/") + this.register_data["id"] + "/authorizations";
var requestBody = JSON.stringify({
'code' : urlVars["code"],
'token_type' : "mac"
});
var those = this;
var http_method = "POST";
var callback = function(resp) {
those.requestAccessTokenTicketFinished(resp.responseText);
};
var auth_header = makeAuthHeader(
url,
http_method,
controller.stringForKey_("app_mac_key"),
controller.stringForKey_("app_mac_key_id")
);
getURL(url, http_method, callback, requestBody, auth_header);
} else {
alert("State is not the same: {" + this.state + "} vs {" + urlVars["state"] + "}")
}
this.state = null; // reset the state
}
OauthImplementation.prototype.requestAccessTokenTicketFinished = function(responseBody) {
var access = JSON.parse(responseBody);
controller.setString_forKey_(access["access_token"], "user_access_token");
controller.setString_forKey_(access["mac_key"], "user_mac_key");
controller.setString_forKey_(access["mac_algorithm"], "user_mac_algorithm");
controller.setString_forKey_(access["token_type"], "user_token_type");
controller.loggedIn();
}
var tentia_oauth;

View file

View file

@ -6,7 +6,7 @@ html, body {
body {
font-family: "Lucida Grande", Tahoma, sans-serif;
font-size: 11px;
background: #dedede url(Icon.png) bottom center no-repeat;
background: #dedede url(../img/Icon.png) bottom center no-repeat;
}
a {
@ -42,11 +42,11 @@ li:first-child {
}
li:nth-child(odd), .error {
background: url(odd-bg.png) repeat-x bottom #fafafa;
background: url(../img/odd-bg.png) repeat-x bottom #fafafa;
}
li:nth-child(even) {
background: url(even-bg.png) repeat-x bottom #f2f2f2;
background: url(../img/even-bg.png) repeat-x bottom #f2f2f2;
}
li:hover {
@ -143,7 +143,7 @@ p {
.retweeted span {
height: 11px;
width: 15px;
background: url(sprite-icons.png) no-repeat -192px -1px;
background: url(../img/sprite-icons.png) no-repeat -192px -1px;
display: inline-block;
margin: 0 3px 0 4px;
}
@ -224,7 +224,7 @@ li:first-child:hover .date {
position: absolute;
top: 2px;
right: 2px;
background: url(sprite-icons.png) no-repeat -16px 0;
background: url(../img/sprite-icons.png) no-repeat -16px 0;
display: none;
}

View file

@ -1,122 +0,0 @@
// its different for app authentication and user authentication:
// for apps its id: mac_key_id and secret: mac_key,
// for users its id: access_token and secret:mac_key
function getURL(url, http_method, callback, data, auth_header) {
$.ajax({
beforeSend: function(xhr) {
if (data) xhr.setRequestHeader("Content-Length", data.length);
if (auth_header) { // if is_set? auth_header
xhr.setRequestHeader("Authorization", auth_header);
} else {
var user_access_token = controller.stringForKey_("user_access_token");
if (auth_header !== false && user_access_token) {
auth_header = makeAuthHeader(
url,
http_method,
controller.stringForKey_("user_mac_key"),
user_access_token
)
xhr.setRequestHeader("Authorization", auth_header);
}
}
},
url: url,
accepts: "application/vnd.tent.v0+json",
contentType: "application/vnd.tent.v0+json",
type: http_method,
complete: callback,
data: data,
processData: false,
error: function(xhr, ajaxOptions, thrownError) {
alert("getURL " + xhr.statusText + " " + http_method + " (" + url + "): '" + xhr.responseText + "'");
}
});
}
function makeAuthHeader(url, http_method, mac_key, mac_key_id) {
url = URI(url);
var nonce = makeid(8);
var time_stamp = parseInt((new Date).getTime() / 1000, 10);
var port = url.port();
if (!port) {
port = url.protocol() == "https" ? "443" : "80";
}
var normalizedRequestString = ""
+ time_stamp + '\n'
+ nonce + '\n'
+ http_method + '\n'
+ url.path() + url.search() + url.hash() + '\n'
+ url.hostname() + '\n'
+ port + '\n'
+ '\n' ;
var hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, mac_key);
hmac.update(normalizedRequestString);
var hash = hmac.finalize();
var mac = hash.toString(CryptoJS.enc.Base64);
return 'MAC id="' + mac_key_id +
'", ts="' + time_stamp +
'", nonce="' + nonce +
'", mac="' + mac + '"';
}
function makeid(len) {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < len; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
function findProfileURL(entity, callback) {
$.ajax({
url: entity,
type: "HEAD",
complete: function(resp) {
if(resp) {
var headers = resp.getAllResponseHeaders();
var regex = /Link: <([^>]*)>; rel="https:\/\/tent.io\/rels\/profile"/; // FIXME: parse it!
var ret = headers.match(regex);
var profile_url = null;
if(ret && ret.length > 1) {
var profile_url = ret[1];
if (profile_url == "/profile") {
profile_url = entity + "/profile";
}
}
if (profile_url) {
callback(profile_url);
}
}
},
error: function(xhr, ajaxOptions, thrownError) {
alert("findProfileURL " + xhr.statusText + " (" + entity + "): " + xhr.responseText);
}
});
}
function mkApiRootPath(path) {
var api_root = controller.stringForKey_("api_root");
if((api_root.substring(api_root.length - 1, api_root.length) != "/") && (path.substring(0, 1) != "/")) {
api_root += "/";
} else if((api_root.substring(api_root.length - 1, api_root.length) == "/") && (path.substring(0, 1) == "/")) {
api_root = api_root.substring(0, api_root.length -1);
}
return api_root + path;
}
function debug(string) {
if (typeof string == "Object") {
string = JSON.stirngify(string);
}
alert("DEBUG: " + string);
}

View file

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 199 B

After

Width:  |  Height:  |  Size: 199 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 171 B

After

Width:  |  Height:  |  Size: 171 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 166 B

After

Width:  |  Height:  |  Size: 166 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 630 B

After

Width:  |  Height:  |  Size: 630 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before After
Before After

View file

@ -3,15 +3,8 @@
<head>
<title>Tentia</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="default.css" type="text/css" />
<link rel="stylesheet" href="~/Library/Application%20Support/Style.css" type="text/css" />
<script type="text/javascript" src="jQuery.js"></script>
<script type="text/javascript" src="jQuery-Plugins.js"></script>
<script type="text/javascript" src="hmac-sha256.js"></script>
<script type="text/javascript" src="enc-base64-min.js"></script>
<script type="text/javascript" src="URI.min.js"></script>
<script type="text/javascript" src="hmac-helper.js"></script>
<script type="text/javascript" src="Core.js"></script>
<link rel="stylesheet" href="css/default.css" type="text/css" />
<script data-main="scripts/main" src="scripts/lib/vendor/require-jquery.js"></script>
</head>
<body>
</body>

View file

@ -1,16 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Tentia</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/javascript" src="jQuery.js"></script>
<script type="text/javascript" src="jQuery-Plugins.js"></script>
<script type="text/javascript" src="hmac-sha256.js"></script>
<script type="text/javascript" src="enc-base64-min.js"></script>
<script type="text/javascript" src="URI.min.js"></script>
<script type="text/javascript" src="hmac-helper.js"></script>
<script type="text/javascript" src="OauthImplementation.js"></script>
</head>
<body>
</body>
</html>

View file

@ -0,0 +1,45 @@
define([
"helper/HostApp",
"controller/Timeline"
],
function(HostApp, Timeline) {
function Mentions() {
this.is_not_init = false;
this.action = "mentions";
this.unread_mentions = 0;
Timeline.call(this);
}
Mentions.prototype = Object.create(Timeline.prototype);
Mentions.prototype.newStatus = function(status) {
Timeline.prototype.newStatus.call(this, status);
if(this.action == "mentions" && this.is_not_init) {
this.unread_mentions += status.length;
HostApp.unreadMentions(this.unread_mentions);
}
this.is_not_init = true;
}
Mentions.prototype.getNewData = function(add_to_search) {
add_to_search = add_to_search || {};
if (!add_to_search["mentioned_entity"]) {
add_to_search["mentioned_entity"] = HostApp.stringForKey("entity");
}
Timeline.prototype.getNewData.call(this, add_to_search);
}
return Mentions;
});

View file

@ -0,0 +1,134 @@
define([
"helper/HostApp",
"helper/Paths",
"helper/Hmac"
],
function(HostApp, Paths, Hmac) {
function Oauth() {
this.app_info = {
"id": null,
"name": "Tentia",
"description": "A small TentStatus client.",
"url": "http://jabs.nu/Tentia/",
"icon": "http://jabs.nu/Tentia/icon.png",
"redirect_uris": [
"tentia://oauthtoken"
],
"scopes": {
"read_posts": "Uses posts to show them in a list",
"write_posts": "Posts on users behalf"
}
};
this.register_data = null;
this.profile = null;
this.state = null;
}
Oauth.prototype.authenticate = function() {
this.entity = HostApp.stringForKey("entity");
this.requestProfileURL(this.entity);
}
Oauth.prototype.apiRoot = function() {
return this.profile["https://tent.io/types/info/core/v0.1.0"]["servers"][0];
}
Oauth.prototype.requestProfileURL = function (entity) {
var those = this;
Paths.findProfileURL(entity, function(profile_url) {
those.register(profile_url);
});
}
Oauth.prototype.register = function (url) {
var those = this;
Paths.getURL(url, "GET", function(resp) {
those.profile = JSON.parse(resp.responseText);
HostApp.setStringForKey(those.apiRoot(), "api_root");
var callback = function(resp) {
var data = JSON.parse(resp.responseText);
those.authRequest(data);
}
Paths.getURL(Paths.mkApiRootPath("/apps"), "POST", callback, JSON.stringify(those.app_info));
});
}
Oauth.prototype.authRequest = function(register_data) {
// id
// mac_key_id
// mac_key
// mac_algorithm
this.register_data = register_data;
// Needed for later App Registration Modification
HostApp.setStringForKey(register_data["mac_key"], "app_mac_key");
HostApp.setStringForKey(register_data["mac_key_id"], "app_mac_key_id");
HostApp.setStringForKey(register_data["id"], "app_id");
HostApp.setStringForKey(register_data["mac_algorithm"], "app_mac_algorithm");
this.state = Hmac.makeid(19);
var auth = "/oauth/authorize?client_id=" + register_data["id"]
+ "&redirect_uri=" + escape(this.app_info["redirect_uris"][0])
+ "&scope=" + Object.keys(this.app_info["scopes"]).join(",")
+ "&state=" + this.state
+ "&tent_post_types=" + escape("https://tent.io/types/posts/status/v0.1.0");
HostApp.openURL(this.apiRoot() + auth);
}
Oauth.prototype.requestAccessToken = function(responseBody) {
// /oauthtoken?code=51d0115b04d1ed94001dde751c5b360f&state=aQfH1VEohYsQr86qqyv
var urlVars = Paths.getUrlVars(responseBody);
if(this.state && this.state != "" && urlVars["state"] == this.state) {
var url = Paths.mkApiRootPath("/apps/") + this.register_data["id"] + "/authorizations";
var requestBody = JSON.stringify({
'code' : urlVars["code"],
'token_type' : "mac"
});
var those = this;
var http_method = "POST";
var callback = function(resp) {
those.requestAccessTokenTicketFinished(resp.responseText);
};
var auth_header = Hmac.makeAuthHeader(
url,
http_method,
HostApp.stringForKey("app_mac_key"),
HostApp.stringForKey("app_mac_key_id")
);
Paths.getURL(url, http_method, callback, requestBody, auth_header);
} else {
alert("State is not the same: {" + this.state + "} vs {" + urlVars["state"] + "}")
}
this.state = null; // reset the state
}
Oauth.prototype.requestAccessTokenTicketFinished = function(responseBody) {
var access = JSON.parse(responseBody);
HostApp.setStringForKey(access["access_token"], "user_access_token");
HostApp.setStringForKey(access["mac_key"], "user_mac_key");
HostApp.setStringForKey(access["mac_algorithm"], "user_mac_algorithm");
HostApp.setStringForKey(access["token_type"], "user_token_type");
HostApp.loggedIn();
}
Oauth.prototype.logout = function() {
}
return Oauth;
});

View file

@ -0,0 +1,106 @@
define([
"helper/Core",
"helper/Paths",
"helper/HostApp",
"lib/URI"
],
function(Core, Paths, HostApp, URI) {
function Timeline() {
Core.call(this);
this.action = "timeline";
this.max_length = 20;
this.timeout = 10 * 1000; // every 10 seconds
this.since_id = null;
this.since_id_entity = null;
this.since_time = 0;
this.body = document.createElement("ol");
this.body.className = this.action;
document.body.appendChild(this.body);
var _this = this;
this.reloadIntervall = setInterval(function() { _this.getNewData() }, this.timeout);
this.getNewData();
}
Timeline.prototype = Object.create(Core.prototype);
Timeline.prototype.newStatus = function(statuses) {
if(statuses != null && statuses.length > 0) {
for(var i = statuses.length-1, c=0; i>=c; --i) {
var status = statuses[i];
this.since_id = status.id;
this.since_id_entity = status.entity;
if(this.body.childNodes.length > 0) {
if(this.body.childNodes.length > this.max_length) {
this.body.removeChild(this.body.lastChild);
}
this.body.insertBefore(this.getStatusDOMElement(status), this.body.firstChild);
} else {
this.body.appendChild(this.getStatusDOMElement(status));
}
}
}
}
Timeline.prototype.getNewData = function(add_to_search) {
add_to_search = add_to_search || {};
var those = this;
var url = URI(Paths.mkApiRootPath("/posts"));
url.addSearch("post_types", "https://tent.io/types/post/status/v0.1.0");
url.addSearch("limit", this.max_length);
if(this.since_id) {
url.addSearch("since_id", this.since_id);
url.addSearch("since_id_entity", this.since_id_entity);
}
for (key in add_to_search) {
url.addSearch(key, add_to_search[key]);
}
var http_method = "GET";
var callback = function(resp) {
try {
var json = JSON.parse(resp.responseText)
} catch (e) {
//alert(resp.responseText);
alert(url + " JSON parse error");
throw e;
}
those.newStatus(json);
}
var data = null;
if (HostApp.stringForKey("user_access_token")) {
Paths.getURL(url.toString(), http_method, callback, data); // FIXME: error callback
}
}
Timeline.prototype.sendNewMessage = function(content, in_reply_to_status_id, in_reply_to_entity) {
var _this = this;
var callback = function(data) { _this.getNewData(); }
Core.prototype.sendNewMessage.call(this, content, in_reply_to_status_id, in_reply_to_entity, callback);
}
Timeline.prototype.foo = function(a) {
return a;
}
return Timeline;
});

View file

@ -0,0 +1,358 @@
define([
"jquery",
"helper/Paths",
"lib/URI",
"lib/vendor/jquery.plugins"
],
function(jQuery, Paths, URI) {
function Core() {
}
Core.prototype.getTemplate = function() {
if(this.template == "undefined") {
return jQuery.extend(true, {}, this.template);
}
var a = document.createElement("a");
var item = document.createElement("li");
var reply_to = a.cloneNode();
reply_to.className = "reply_to"
reply_to.innerText = " ";
reply_to.href = "#";
item.appendChild(reply_to);
var retweet = a.cloneNode();
retweet.className = "retweet";
retweet.innerText = " ";
retweet.href = "#";
// item.appendChild(retweet); // FIXME
var image = document.createElement("img");
image.className = "image";
image.src = "img/default-avatar.png";
image.onmousedown = function(e) { e.preventDefault(); };
item.appendChild(image);
var image_username = a.cloneNode();
image.appendChild(image_username);
var data = document.createElement("div");
data.className = "data";
item.appendChild(data);
var head = document.createElement("h1");
data.appendChild(head);
var username = a.cloneNode();
head.appendChild(username);
var in_reply = document.createElement("span");
in_reply.className = "reply";
head.appendChild(in_reply);
var space = document.createTextNode(" ");
head.appendChild(space);
var geo = document.createElement("a");
geo.style.display = "none";
head.appendChild(geo);
var pin = document.createElement("img");
pin.src = "img/pin.png";
pin.alt = "Map link";
geo.appendChild(pin);
var in_reply_text = document.createTextNode(" in reply to ");
in_reply.appendChild(in_reply_text)
var in_reply_a = a.cloneNode();
in_reply.appendChild(in_reply_a);
var message = document.createElement("p");
message.className = "message";
data.appendChild(message);
var images = document.createElement("p")
images.className = "images";
data.appendChild(images);
var date = message.cloneNode();
date.className = "date";
data.appendChild(date);
var ago = a.cloneNode();
date.appendChild(ago);
var from = document.createTextNode(" from ");
date.appendChild(from)
var source = document.createElement("a");
source.className = "source";
date.appendChild(source)
this.template = {
item: item,
reply_to: reply_to,
retweet: retweet,
image: image,
username: username,
in_reply: in_reply_a,
message: message,
ago: ago,
source: source,
geo: geo,
images: images
}
return jQuery.extend(true, {}, this.template);
}
Core.prototype.getStatusDOMElement = function(status) {
var _this = this;
var template = this.getTemplate();
template.reply_to.onclick = function() {
var mentions = [];
for (var i = 0; i < status.mentions.length; i++) {
var mention = status.mentions[i];
if(mention.entity != HostApp.stringForKey("entity"))
mentions.push(mention);
}
this.replyTo(status.entity, status.id, mentions);
return false;
}
//template.retweet.onclick = function() { template.retweet.className = "hidden"; _this.retweet(status.id_str, template.item); return false; }
template.username.innerText = status.entity;
template.username.href = status.entity; // FIXME open profile
Paths.findProfileURL(status.entity, function(profile_url) {
if (profile_url) {
Paths.getURL(profile_url, "GET", function(resp) {
var profile = JSON.parse(resp.responseText);
var basic = profile["https://tent.io/types/info/basic/v0.1.0"];
if (profile && basic) {
if(basic.name) {
template.username.title = template.username.innerText;
template.username.innerText = basic.name;
}
if(basic.avatar_url) {
template.image.onerror = function() { template.image.src = 'img/default-avatar.png' };
template.image.src = basic.avatar_url;
}
}
}, null, false); // do not send auth-headers
}
});
template.in_reply.parentNode.className = "hidden";
template.message.innerHTML = this.replaceUsernamesWithLinks(
this.replaceURLWithHTMLLinks(status.content.text, status.entities, template.message)
);
this.findMentions(template.message, status.mentions);
var time = document.createElement("abbr");
time.innerText = this.ISODateString(new Date(status.published_at * 1000));
time.title = time.innerText;
time.className = "timeago";
jQuery(time).timeago();
template.ago.appendChild(time);
// {"type":"Point","coordinates":[57.10803113,12.25854746]}
if (status.content && status.content.location && status.content.location.type == "Point") {
template.geo.href = "http://maps.google.com/maps?q=" + status.content.location.coordinates[0] + "," + status.content.location.coordinates[1];
template.geo.style.display = "";
}
template.source.href = status.app.url;
template.source.innerHTML = status.app.name;
template.source.title = status.app.url;
return template.item;
}
Core.prototype.sendNewMessage = function(content, in_reply_to_status_id, in_reply_to_entity, callback) {
var url = URI(Paths.mkApiRootPath("/posts"));
var http_method = "POST";
var data = {
"type": "https://tent.io/types/post/status/v0.1.0",
"published_at": (new Date().getTime() / 1000),
"permissions": {
"public": true
},
"content": {
"text": content,
},
};
var mentions = this.parseMentions(content, in_reply_to_status_id, in_reply_to_entity);
if (mentions.length > 0) {
data["mentions"] = mentions;
}
Paths.getURL(url.toString(), http_method, callback, JSON.stringify(data)); // FIXME: error callback
}
Core.prototype.logout = function() {
this.body.innerHTML = "";
}
// Helper functions
Core.prototype.replaceShortened = function(url, message_node) {
var api = "http://api.bitly.com";
if(url.startsWith("http://j.mp/")) {
api = "http://api.j.mp";
}
var api_url = api + "/v3/expand?format=json&apiKey=R_4fc2a1aa461d076556016390fa6400f6&login=twittia&shortUrl=" + url; // FIXME: new api key
jQuery.ajax({
url: api_url,
success: function(data) {
var new_url = data.data.expand[0].long_url;
if (new_url) {
var regex = new RegExp(url, "g");
message_node.innerHTML = message_node.innerHTML.replace(regex, new_url);
}
},
error:function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
}
Core.prototype.findMentions = function(node, mentions) {
var text = node.innerHTML;
var mentions_in_text = [];
var res = text.match(/(\^\S+)/ig);
if (res) {
for (var i = 0; i < res.length; i++) {
var name = res[i];
var e = name.substring(1);
if (e.substring(0,7) != "http://" && e.substring(0,8) != "https://") {
e = "https://" + e;
}
for (var j = 0; j < mentions.length; j++) {
var m = mentions[j];
if(m.entity.startsWith(e)) {
mentions_in_text.push({
entity: m.entity,
text: name
});
}
}
}
}
for (var i = 0; i < mentions_in_text.length; i++) {
var mention = mentions_in_text[i];
(function(mention) { // need this closure
Paths.findProfileURL(mention.entity, function(profile_url) {
if (profile_url) {
Paths.getURL(profile_url, "GET", function(resp) {
var profile = JSON.parse(resp.responseText);
var basic = profile["https://tent.io/types/info/basic/v0.1.0"];
if (profile && basic) {
if(basic.name) {
var new_text = node.innerHTML.replace(
mention.text,
"<strong class='name' title='" + mention.entity + "'" + ">"
+ basic.name
+ "</strong>"
);
node.innerHTML = new_text;
}
}
}, null, false); // do not send auth-headers
}
});
})(mention);
}
}
Core.prototype.parseMentions = function(text, post_id, entity) {
var mentions = [];
if (post_id && entity) {
mentions.push({
post: post_id,
entity: entity
})
}
var res = text.match(/(\^\S+)/ig);
if (res) {
for (var i = 0; i < res.length; i++) {
var e = res[i].substring(1);
if (e.substring(0,7) != "http://" && e.substring(0,8) != "https://") {
e = "https://" + e;
}
if (e != entity) {
mentions.push({entity:e});
}
}
}
return mentions;
}
Core.prototype.ISODateString = function(d){
function pad(n){return n<10 ? '0'+n : n}
return d.getUTCFullYear()+'-'
+ pad(d.getUTCMonth()+1)+'-'
+ pad(d.getUTCDate())+'T'
+ pad(d.getUTCHours())+':'
+ pad(d.getUTCMinutes())+':'
+ pad(d.getUTCSeconds())+'Z'
}
Core.prototype.replaceURLWithHTMLLinks = function(text, entities, message_node) {
var exp = /(([^\^]https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_()|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
return text.replace(exp, "<a href='$1'>$1</a>");
}
Core.prototype.replaceUsernamesWithLinks = function(text, mentions) {
return text; // FIXME!
var username = /(^|\s)(\^)(\w+)/ig;
var hash = /(^|\s)(#)(\w+)/ig;
text = text.replace(username, "$1$2<a href='tentia://profile/$3'>$3</a>");
return text.replace(hash, "$1$2<a href='http://search.twitter.com/search?q=%23$3'>$3</a>");
}
Core.prototype.replyTo = function(entity, status_id, mentions) {
var string = "^" + entity.replace("https://", "") + " ";
for (var i = 0; i < mentions.length; i++) {
var e = mentions[i].entity.replace("https://", "");
if(string.indexOf(e) == -1) string += "^" + e + " ";
}
controller.openNewMessageWindowInReplyTo_statusId_withString_(entity, status_id, string);
}
return Core;
});

View file

@ -0,0 +1,56 @@
define([
"lib/URI",
"lib/CryptoJS"
],
function(URI, CryptoJS) {
var Hmac = {};
Hmac.makeAuthHeader = function(url, http_method, mac_key, mac_key_id) {
url = URI(url);
var nonce = Hmac.makeid(8);
var time_stamp = parseInt((new Date).getTime() / 1000, 10);
var port = url.port();
if (!port) {
port = url.protocol() == "https" ? "443" : "80";
}
var normalizedRequestString = ""
+ time_stamp + '\n'
+ nonce + '\n'
+ http_method + '\n'
+ url.path() + url.search() + url.hash() + '\n'
+ url.hostname() + '\n'
+ port + '\n'
+ '\n' ;
var hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, mac_key);
hmac.update(normalizedRequestString);
var hash = hmac.finalize();
var mac = hash.toString(CryptoJS.enc.Base64);
return 'MAC id="' + mac_key_id +
'", ts="' + time_stamp +
'", nonce="' + nonce +
'", mac="' + mac + '"';
}
Hmac.makeid = function(len) {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < len; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
return Hmac;
});
// its different for app authentication and user authentication:
// for apps its id: mac_key_id and secret: mac_key,
// for users its id: access_token and secret:mac_key

View file

@ -0,0 +1,51 @@
define(function() {
var HostApp = {};
HostApp.setStringForKey = function(string, key) {
if (OS_TYPE == "mac") {
controller.setString_forKey_(string, key);
} else {
controller.setStringForKey(string, key);
}
}
HostApp.stringForKey = function(key) {
if (OS_TYPE == "mac") {
return controller.stringForKey_(key);
} else {
return controller.stringForKey(key);
}
}
HostApp.openURL = function(url) {
if (OS_TYPE == "mac") {
controller.openURL_(url);
} else {
controller.openURL(URL);
}
}
HostApp.loggedIn = function() {
controller.loggedIn();
}
HostApp.logout = function() {
if (OS_TYPE == "mac") {
controller.logout_(self);
} else {
controller.logout(self);
}
}
HostApp.unreadMentions = function(i) {
if (OS_TYPE == "mac") {
controller.unreadMentions_(i);
} else {
controller.unreadMentions(i);
}
}
return HostApp;
});

View file

@ -0,0 +1,95 @@
define([
"jquery",
"helper/HostApp",
"helper/Hmac"
],
function(jQuery, HostApp, Hmac) {
var Paths = {};
Paths.getUrlVars = function(url) {
var vars = [], hash;
if(url.indexOf("#") > -1) url = url.slice(0, url.indexOf("#"));
var hashes = url.slice(url.indexOf('?') + 1).split('&');
for(var i = 0; i < hashes.length; i++)
{
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
}
Paths.getURL = function(url, http_method, callback, data, auth_header) {
jQuery.ajax({
beforeSend: function(xhr) {
if (data) xhr.setRequestHeader("Content-Length", data.length);
if (auth_header) { // if is_set? auth_header
xhr.setRequestHeader("Authorization", auth_header);
} else {
var user_access_token = HostApp.stringForKey("user_access_token");
if (auth_header !== false && user_access_token) {
auth_header = Hmac.makeAuthHeader(
url,
http_method,
HostApp.stringForKey("user_mac_key"),
user_access_token
)
xhr.setRequestHeader("Authorization", auth_header);
}
}
},
url: url,
accepts: "application/vnd.tent.v0+json",
contentType: "application/vnd.tent.v0+json",
type: http_method,
complete: callback,
data: data,
processData: false,
error: function(xhr, ajaxOptions, thrownError) {
alert("getURL " + xhr.statusText + " " + http_method + " (" + url + "): '" + xhr.responseText + "'");
}
});
}
Paths.findProfileURL = function(entity, callback) {
jQuery.ajax({
url: entity,
type: "HEAD",
complete: function(resp) {
if(resp) {
var headers = resp.getAllResponseHeaders();
var regex = /Link: <([^>]*)>; rel="https:\/\/tent.io\/rels\/profile"/; // FIXME: parse it!
var ret = headers.match(regex);
var profile_url = null;
if(ret && ret.length > 1) {
var profile_url = ret[1];
if (profile_url == "/profile") {
profile_url = entity + "/profile";
}
}
if (profile_url) {
callback(profile_url);
}
}
},
error: function(xhr, ajaxOptions, thrownError) {
alert("findProfileURL " + xhr.statusText + " (" + entity + "): " + xhr.responseText);
}
});
}
Paths.mkApiRootPath = function(path) {
var api_root = HostApp.stringForKey("api_root");
if((api_root.substring(api_root.length - 1, api_root.length) != "/") && (path.substring(0, 1) != "/")) {
api_root += "/";
} else if((api_root.substring(api_root.length - 1, api_root.length) == "/") && (path.substring(0, 1) == "/")) {
api_root = api_root.substring(0, api_root.length -1);
}
return api_root + path;
}
return Paths;
});

BIN
WebKit/scripts/lib/.DS_Store vendored Normal file

Binary file not shown.

View file

@ -0,0 +1,7 @@
define([
"lib/vendor/hmac-sha256"
],
function() {
return CryptoJS;
});

View file

@ -0,0 +1,7 @@
define([
"lib/vendor/URI.min"
],
function() {
return URI;
})

BIN
WebKit/scripts/lib/vendor/.DS_Store vendored Normal file

Binary file not shown.

View file

@ -15,3 +15,15 @@ n;n++){if(16>n)m[n]=e[f+n]|0;else{var i=m[n-15],p=m[n-2];m[n]=((i<<25|i>>>7)^(i<
g=8*e.sigBytes;f[g>>>5]|=128<<24-g%32;f[(g+64>>>9<<4)+15]=b;e.sigBytes=4*f.length;this._process()}});i.SHA256=e._createHelper(l);i.HmacSHA256=e._createHmacHelper(l)})(Math);
(function(){var h=CryptoJS,i=h.enc.Utf8;h.algo.HMAC=h.lib.Base.extend({init:function(e,f){e=this._hasher=e.create();"string"==typeof f&&(f=i.parse(f));var h=e.blockSize,k=4*h;f.sigBytes>k&&(f=e.finalize(f));for(var o=this._oKey=f.clone(),m=this._iKey=f.clone(),q=o.words,r=m.words,b=0;b<h;b++)q[b]^=1549556828,r[b]^=909522486;o.sigBytes=m.sigBytes=k;this.reset()},reset:function(){var e=this._hasher;e.reset();e.update(this._iKey)},update:function(e){this._hasher.update(e);return this},finalize:function(e){var f=
this._hasher,e=f.finalize(e);f.reset();return f.finalize(this._oKey.clone().concat(e))}})})();
/*
CryptoJS v3.0.2
code.google.com/p/crypto-js
(c) 2009-2012 by Jeff Mott. All rights reserved.
code.google.com/p/crypto-js/wiki/License
*/
(function(){var h=CryptoJS,i=h.lib.WordArray;h.enc.Base64={stringify:function(b){var e=b.words,f=b.sigBytes,c=this._map;b.clamp();for(var b=[],a=0;a<f;a+=3)for(var d=(e[a>>>2]>>>24-8*(a%4)&255)<<16|(e[a+1>>>2]>>>24-8*((a+1)%4)&255)<<8|e[a+2>>>2]>>>24-8*((a+2)%4)&255,g=0;4>g&&a+0.75*g<f;g++)b.push(c.charAt(d>>>6*(3-g)&63));if(e=c.charAt(64))for(;b.length%4;)b.push(e);return b.join("")},parse:function(b){var b=b.replace(/\s/g,""),e=b.length,f=this._map,c=f.charAt(64);c&&(c=b.indexOf(c),-1!=c&&(e=c));
for(var c=[],a=0,d=0;d<e;d++)if(d%4){var g=f.indexOf(b.charAt(d-1))<<2*(d%4),h=f.indexOf(b.charAt(d))>>>6-2*(d%4);c[a>>>2]|=(g|h)<<24-8*(a%4);a++}return i.create(c,a)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})();

11421
WebKit/scripts/lib/vendor/require-jquery.js vendored Normal file

File diff suppressed because it is too large Load diff

1981
WebKit/scripts/lib/vendor/require.js vendored Normal file

File diff suppressed because it is too large Load diff

68
WebKit/scripts/main.js Normal file
View file

@ -0,0 +1,68 @@
var tentia_instance;
var tentia_cache = {};
var OS_TYPE = "mac";
requirejs.config({
baseUrl: 'scripts'
});
function start(view) {
if (view == "oauth") {
require(["controller/Oauth"], function(Oauth) {
tentia_instance = new Oauth();
tentia_instance.authenticate();
});
} else if (view == "timeline") {
require(["controller/Timeline"], function(Timeline) {
tentia_instance = new Timeline();
});
} else if (view == "mentions") {
require(["controller/Mentions"], function(Mentions) {
tentia_instance = new Mentions();
});
} else if (view == "profile") {
} else if (view == "follow") {
} else if (view == "conversation") {
}
}
String.prototype.startsWith = function(prefix) {
return this.indexOf(prefix) === 0;
}
String.prototype.endsWith = function(suffix) {
return this.match(suffix+"$") == suffix;
};
function loadPlugin(url) {
var plugin = document.createElement("script");
plugin.type = "text/javascript";
plugin.src = url;
document.getElementsByTagName("head")[0].appendChild(plugin);
}
function debug(string) {
if (typeof string != "string") {
string = JSON.stringify(string);
}
alert("DEBUG: " + string);
}
setTimeout(HostAppGo, 1000);