From 422dbd34ff6ce260d73adeee46eec636fd2c9b71 Mon Sep 17 00:00:00 2001 From: Jeena Paradies Date: Wed, 22 May 2013 02:40:52 +0200 Subject: [PATCH 01/18] first auth test working --- WebKit/scripts/controller/Oauth.js | 124 +++++++++++++++-------------- WebKit/scripts/helper/Hmac.js | 54 +++++++++++++ WebKit/scripts/helper/HostApp.js | 8 ++ WebKit/scripts/helper/Paths.js | 25 +++--- 4 files changed, 140 insertions(+), 71 deletions(-) diff --git a/WebKit/scripts/controller/Oauth.js b/WebKit/scripts/controller/Oauth.js index 0cebc2e..bbdb296 100644 --- a/WebKit/scripts/controller/Oauth.js +++ b/WebKit/scripts/controller/Oauth.js @@ -8,31 +8,38 @@ function(HostApp, Paths, Hmac) { function Oauth() { this.app_info = { - "id": null, - "name": "Bungloo on " + HostApp.osType(), - "description": "A small TentStatus client.", - "url": "http://jabs.nu/bungloo/", - "icon": "http://jabs.nu/bungloo/icon.png", - "redirect_uris": [ - "bungloo://oauthtoken" - ], - "scopes": { - "read_posts": "Uses posts to show them in a list", - "write_posts": "Posts on users behalf", - "read_profile": "Displays your own profile", - "write_profile": "Updating profile and mentions pointer", - "read_followers": "Display a list of people who follow you", - "write_followers": "Be able to block people who follow you", - "read_followings": "Display following list and their older posts in conversations", - "write_followings": "Follow ne entities" + "type": "https://tent.io/types/app/v0#", + "content": { + "name": "Bungloo on " + HostApp.osType(), + "url": "http://jabs.nu/bungloo/", + "description": "A desktop Tent client.", + "redirect_uri": "bungloo://oauthtoken", + "post_types": { + "read": [ + "https://tent.io/types/meta/v0", + "https://tent.io/types/relationship/v0", + "https://tent.io/types/subscription/v0", + "https://tent.io/types/delete/v0", + "https://tent.io/types/status/v0", + "https://tent.io/types/repost/v0", + "https://tent.io/types/photo/v0", + "https://tent.io/types/cursor/v0", + "https://tent.io/types/basic-profile/v0" + ], + "write": [ + "https://tent.io/types/relationship/v0", + "https://tent.io/types/subscription/v0", + "https://tent.io/types/delete/v0", + "https://tent.io/types/status/v0", + "https://tent.io/types/repost/v0", + "https://tent.io/types/photo/v0", + "https://tent.io/types/cursor/v0" + ] + } }, - "tent_profile_info_types": [ "all" ], - "tent_post_types": [ - "https://tent.io/types/post/status/v0.1.0", - "https://tent.io/types/post/photo/v0.1.0", - "https://tent.io/types/post/repost/v0.1.0", - "https://tent.io/types/post/delete/v0.1.0" - ] + "permissions": { + "public": false + } }; this.register_data = null; this.profile = null; @@ -61,10 +68,6 @@ function(HostApp, Paths, Hmac) { } } - 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, @@ -76,6 +79,7 @@ function(HostApp, Paths, Hmac) { } }, function(errorMessage) { // error callback + HostApp.authentificationDidNotSucceed(errorMessage); HostApp.authentificationDidNotSucceed("Could not find profile for: " + entity); } ); @@ -83,57 +87,53 @@ function(HostApp, Paths, Hmac) { Oauth.prototype.register = function (url) { var those = this; - Paths.getURL(url, "GET", function(resp) { those.profile = JSON.parse(resp.responseText); - those.entity = those.profile["https://tent.io/types/info/core/v0.1.0"].entity; + those.entity = those.profile.content.entity; HostApp.setStringForKey(those.entity, "entity") - HostApp.setStringForKey(those.apiRoot(), "api_root"); + HostApp.setServerUrls(those.profile.content.servers[0].urls); var callback = function(resp) { - var data = JSON.parse(resp.responseText); - those.authRequest(data); + var app_id = JSON.parse(resp.responseText).id; + var header_string = resp.getAllResponseHeaders(); + var regexp = /https:\/\/tent.io\/rels\/credentials/i + var url = Paths.parseHeaderForLink(header_string, regexp); + Paths.getURL(url, "GET", function(resp) { + var data = JSON.parse(resp.responseText); + those.authRequest(data, app_id); + }, null, false) } - Paths.getURL(Paths.mkApiRootPath("/apps"), "POST", callback, JSON.stringify(those.app_info), false); + + Paths.getURL(HostApp.serverUrl("new_post"), "POST", callback, JSON.stringify(those.app_info), false); + }, null, false); } - 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"); + Oauth.prototype.authRequest = function(credentials, app_id) { + HostApp.setStringForKey(app_id, "app_id"); + HostApp.setStringForKey(credentials.id, "app_hawk_id"); + HostApp.setStringForKey(credentials.content.hawk_key, "app_hawk_key"); + HostApp.setStringForKey(credentials.content.hawk_algorithm, "app_hawk_algorithm"); + this.state = Hmac.makeid(19); - var auth = "/oauth/authorize?client_id=" + register_data["id"] - + "&redirect_uri=" + this.app_info["redirect_uris"][0] - + "&scope=" + Object.keys(this.app_info["scopes"]).join(",") - + "&state=" + this.state - + "&tent_post_types=" + this.app_info["tent_post_types"].join(",") - + "&tent_profile_info_types=" + this.app_info["tent_profile_info_types"].join(","); - - HostApp.openAuthorizationURL(this.apiRoot() + auth); + var url = HostApp.serverUrl("oauth_auth") + "?client_id=" + app_id + "&state=" + this.state; + HostApp.openAuthorizationURL(url); } Oauth.prototype.requestAccessToken = function(responseBody) { // /oauthtoken?code=51d0115b04d1ed94001dde751c5b360f&state=aQfH1VEohYsQr86qqyv + // https://app.example.com/oauth?code=K4m2J2bGI9rcICBqmUCYuQ&state=d173d2bb868a 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 url = HostApp.serverUrl("oauth_token"); var requestBody = JSON.stringify({ 'code' : urlVars["code"], - 'token_type' : "mac" + 'token_type' : "https://tent.io/oauth/hawk-token" }); var those = this; @@ -142,11 +142,12 @@ function(HostApp, Paths, Hmac) { those.requestAccessTokenTicketFinished(resp.responseText); }; - var auth_header = Hmac.makeAuthHeader( + var auth_header = Hmac.makeHawkAuthHeader( url, http_method, - HostApp.stringForKey("app_mac_key"), - HostApp.stringForKey("app_mac_key_id") + HostApp.stringForKey("app_hawk_id"), + HostApp.stringForKey("app_hawk_key"), + requestBody ); Paths.getURL(url, http_method, callback, requestBody, auth_header); @@ -163,11 +164,12 @@ function(HostApp, Paths, Hmac) { var access = JSON.parse(responseBody); HostApp.setStringForKey(access["access_token"], "user_access_token"); - HostApp.setSecret(access["mac_key"]); - HostApp.setStringForKey(access["mac_algorithm"], "user_mac_algorithm"); + HostApp.setSecret(access["hawk_key"]); + HostApp.setStringForKey(access["hawk_algorithm"], "user_hawk_algorithm"); HostApp.setStringForKey(access["token_type"], "user_token_type"); HostApp.loggedIn(); + debug("loggedIn") } Oauth.prototype.logout = function() { diff --git a/WebKit/scripts/helper/Hmac.js b/WebKit/scripts/helper/Hmac.js index b22a2f3..0e2b1fc 100644 --- a/WebKit/scripts/helper/Hmac.js +++ b/WebKit/scripts/helper/Hmac.js @@ -9,6 +9,8 @@ function(URI, CryptoJS) { Hmac.makeAuthHeader = function(url, http_method, mac_key, mac_key_id) { + debug("makeAuthHeader should not be used anymore, bug!") + url = URI(url); var nonce = Hmac.makeid(8); var time_stamp = parseInt((new Date).getTime() / 1000, 10); @@ -38,6 +40,58 @@ function(URI, CryptoJS) { '", mac="' + mac + '"'; } + Hmac.makeHawkAuthHeader = function(url, http_method, hawk_id, key, payload, app_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 = "hawk.1.header\n" // header + + time_stamp + '\n' // ts + + nonce + '\n' // nonce + + http_method.toUpperCase() + '\n' // method + + url.path() + url.search() + url.hash() + '\n' // request uri + + url.hostname().toLowerCase() + '\n' // host + + port + '\n' // port + + Hmac.calculatePayloadHash(payload) + '\n' // hash + + '\n' // ext (we don't use it) + + var app = ""; + if(app_id) { + app = ', app="' + app_id + "'"; + normalizedRequestString += app_id + "\n" + // app + '\n'; // dlg should be empty + } + + + var hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key); + hmac.update(normalizedRequestString); + var hash = hmac.finalize(); + var mac = hash.toString(CryptoJS.enc.Base64); + + + + return 'Hawk id="' + hawk_id + + '", mac="' + mac + + '", ts="' + time_stamp + + '", nonce="' + nonce + '"' + + app + } + + Hmac.calculatePayloadHash = function (payload) { + var hash = CryptoJS.algo.SHA256.create(); + hash.update('hawk.1.payload\n'); + hash.update('application/vnd.tent.post.v0+json\n'); + hash.update(payload || ''); + hash.update('\n'); + return hash.finalize().toString(CryptoJS.enc.Base64); + }, + Hmac.makeid = function(len) { var text = ""; var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; diff --git a/WebKit/scripts/helper/HostApp.js b/WebKit/scripts/helper/HostApp.js index 60cf9e5..ced766a 100644 --- a/WebKit/scripts/helper/HostApp.js +++ b/WebKit/scripts/helper/HostApp.js @@ -37,6 +37,14 @@ define(function() { } } + HostApp.setServerUrls = function(server_urls) { + HostApp.setStringForKey(JSON.stringify(server_urls), "server_urls"); + } + + HostApp.serverUrl = function(key) { + return JSON.parse(HostApp.stringForKey("server_urls"))[key]; + } + HostApp.openURL = function(url) { if (OS_TYPE == "mac") { diff --git a/WebKit/scripts/helper/Paths.js b/WebKit/scripts/helper/Paths.js index 5f477a7..f6a703f 100644 --- a/WebKit/scripts/helper/Paths.js +++ b/WebKit/scripts/helper/Paths.js @@ -25,7 +25,7 @@ function(jQuery, HostApp, Hmac, Cache) { Paths.getURL = function(url, http_method, callback, data, auth_header, accepts) { - if(accepts !== false) accepts = accepts || "application/vnd.tent.v0+json; charset=utf-8"; + if(accepts !== false) accepts = accepts || "application/vnd.tent.post.v0+json"; var options = { @@ -56,7 +56,7 @@ function(jQuery, HostApp, Hmac, Cache) { } }, url: url, - contentType: "application/vnd.tent.v0+json", + contentType: 'application/vnd.tent.post.v0+json; type="https://tent.io/types/app/v0#"', type: http_method, complete: callback, data: data, @@ -65,7 +65,7 @@ function(jQuery, HostApp, Hmac, Cache) { console.error("getURL (" + xhr.status + ")" + xhr.statusText + " " + http_method + " (" + url + "): '" + xhr.responseText + "'"); } } - + debug(url) jQuery.ajax(options); } @@ -127,7 +127,7 @@ function(jQuery, HostApp, Hmac, Cache) { if(profile_urls.length > 0) { var profile_url = profile_urls[0]; if (!profile_url.startsWith("http")) { - profile_url = entity + "/profile"; + profile_url = entity + profile_url; } } @@ -140,13 +140,13 @@ function(jQuery, HostApp, Hmac, Cache) { if (resp.status >= 200 && resp.status < 300) { var doc = document.implementation.createHTMLDocument(""); doc.documentElement.innerHTML = resp.responseText; - var links = $(doc).find("link[rel='https://tent.io/rels/profile']"); + var links = $(doc).find("link[rel='https://tent.io/rels/meta-post']"); if (links.length > 0) { var href = links.get(0).href; Paths.cache.profile_urls.setItem(entity, href); if (!href.startsWith("http")) { - href = entity + "/profile"; + href = entity + href; } callback(href); @@ -184,6 +184,11 @@ function(jQuery, HostApp, Hmac, Cache) { } Paths.parseHeaderForProfiles = function(header_string) { + var regexp = /https:\/\/tent.io\/rels\/meta-post/i; + return Paths.parseHeaderForLink(header_string, regexp); + } + + Paths.parseHeaderForLink = function(header_string, match) { var headers = header_string.split(/\n/); var links = []; for (var i = 0; i < headers.length; i++) { @@ -197,18 +202,18 @@ function(jQuery, HostApp, Hmac, Cache) { for (var i = 0; i < links.length; i++) { items = items.concat(links[i].split(",")); } - var profiles = []; + var things = []; for (var i = 0; i < items.length; i++) { var item = items[i]; - if (item.match(/https:\/\/tent.io\/rels\/profile/i)) { + if (item.match(match)) { var n = item.match(/<([^>]*)>/); if (n) { - profiles.push(n[1]); + things.push(n[1]); } } } - return profiles; + return things; } return Paths; From f73ce7d196eaab9287df2e84a668c3714ca83128 Mon Sep 17 00:00:00 2001 From: Jeena Paradies Date: Sun, 26 May 2013 09:51:01 +0200 Subject: [PATCH 02/18] api calls --- WebKit/scripts/controller/Conversation.js | 18 +- WebKit/scripts/controller/Mentions.js | 16 +- WebKit/scripts/controller/Oauth.js | 24 +- WebKit/scripts/controller/Profile.js | 40 +-- WebKit/scripts/controller/Search.js | 6 +- WebKit/scripts/controller/Sidebar.js | 8 +- WebKit/scripts/controller/Timeline.js | 8 +- WebKit/scripts/helper/APICalls.js | 285 ++++++++++++++++++++++ WebKit/scripts/helper/Cache.js | 4 +- WebKit/scripts/helper/Core.js | 48 ++-- 10 files changed, 371 insertions(+), 86 deletions(-) create mode 100644 WebKit/scripts/helper/APICalls.js diff --git a/WebKit/scripts/controller/Conversation.js b/WebKit/scripts/controller/Conversation.js index cb49aeb..817cf01 100644 --- a/WebKit/scripts/controller/Conversation.js +++ b/WebKit/scripts/controller/Conversation.js @@ -1,11 +1,11 @@ define([ "helper/HostApp", "helper/Core", - "helper/Paths", + "helper/APICalls", "lib/URI" ], -function(HostApp, Core, Paths, URI) { +function(HostApp, Core, APICalls, URI) { function Conversation(standalone) { @@ -86,15 +86,15 @@ function(HostApp, Core, Paths, URI) { function getRemoteStatus(profile) { var server = profile["https://tent.io/types/info/core/v0.1.0"].servers[0]; - Paths.getURL(URI(server + "/posts/" + id).toString(), "GET", callback, null, false); + APICalls.http_call(URI(server + "/posts/" + id).toString(), "GET", callback, null, false); } var profile = this.cache.profiles.getItem(entity); if (entity == HostApp.stringForKey("entity")) { - var url = URI(Paths.mkApiRootPath("/posts/" + id)); - Paths.getURL(url.toString(), "GET", callback, null); + var url = URI(APICalls.mkApiRootPath("/posts/" + id)); + APICalls.http_call(url.toString(), "GET", callback, null); } else if(profile) { @@ -102,7 +102,7 @@ function(HostApp, Core, Paths, URI) { } else { - Paths.findProfileURL(entity, function(profile_url) { + APICalls.findProfileURL(entity, function(profile_url) { if (profile_url) { @@ -113,7 +113,7 @@ function(HostApp, Core, Paths, URI) { } else { - Paths.getURL(profile_url, "GET", function(resp) { + APICalls.http_call(profile_url, "GET", function(resp) { var profile = JSON.parse(resp.responseText) this.cache.profiles.setItem(entity, profile); @@ -128,7 +128,7 @@ function(HostApp, Core, Paths, URI) { Conversation.prototype.appendMentioned = function(id, entity, node) { - var url = URI(Paths.mkApiRootPath("/posts")); + var url = URI(APICalls.mkApiRootPath("/posts")); url.addSearch("mentioned_post", id); url.addSearch("post_types", "https%3A%2F%2Ftent.io%2Ftypes%2Fpost%2Fstatus%2Fv0.1.0"); @@ -147,7 +147,7 @@ function(HostApp, Core, Paths, URI) { } } - Paths.getURL(url.toString(), "GET", callback); + APICalls.http_call(url.toString(), "GET", callback); } diff --git a/WebKit/scripts/controller/Mentions.js b/WebKit/scripts/controller/Mentions.js index a0cc51c..7d20d5b 100644 --- a/WebKit/scripts/controller/Mentions.js +++ b/WebKit/scripts/controller/Mentions.js @@ -2,11 +2,11 @@ define([ "helper/HostApp", "controller/Timeline", "lib/URI", - "helper/Paths", + "helper/APICalls", "helper/Core" ], -function(HostApp, Timeline, URI, Paths, Core) { +function(HostApp, Timeline, URI, APICalls, Core) { function Mentions() { @@ -90,7 +90,7 @@ function(HostApp, Timeline, URI, Paths, Core) { if (!status.__repost) { if (status && status.type == "https://tent.io/types/post/status/v0.1.0") { - var url = URI(Paths.mkApiRootPath("/profile/" + encodeURIComponent("https://tent.io/types/info/cursor/v0.1.0"))); + var url = URI(APICalls.mkApiRootPath("/profile/" + encodeURIComponent("https://tent.io/types/info/cursor/v0.1.0"))); var body = { "mentions": { "https://tent.io/types/post/status/v0.1.0": { @@ -104,7 +104,7 @@ function(HostApp, Timeline, URI, Paths, Core) { } - Paths.getURL(url.toString(), "PUT", callback, JSON.stringify(body)); + APICalls.http_call(url.toString(), "PUT", callback, JSON.stringify(body)); } break; @@ -115,11 +115,11 @@ function(HostApp, Timeline, URI, Paths, Core) { Mentions.prototype.getLatestMentionRead = function() { - var cursor_url = URI(Paths.mkApiRootPath("/profile/" + encodeURIComponent("https://tent.io/types/info/cursor/v0.1.0"))); + var cursor_url = URI(APICalls.mkApiRootPath("/profile/" + encodeURIComponent("https://tent.io/types/info/cursor/v0.1.0"))); - Paths.getURL(cursor_url.toString(), "GET", function(resp) { + APICalls.http_call(cursor_url.toString(), "GET", function(resp) { - var url = URI(Paths.mkApiRootPath("/posts/count")); + var url = URI(APICalls.mkApiRootPath("/posts/count")); var post_types = [ "https://tent.io/types/post/status/v0.1.0", ]; @@ -139,7 +139,7 @@ function(HostApp, Timeline, URI, Paths, Core) { HostApp.unreadMentions(this.unread_mentions); } - Paths.getURL(url.toString(), "GET", callback); // FIXME: error callback + APICalls.http_call(url.toString(), "GET", callback); // FIXME: error callback }); } diff --git a/WebKit/scripts/controller/Oauth.js b/WebKit/scripts/controller/Oauth.js index bbdb296..a60a286 100644 --- a/WebKit/scripts/controller/Oauth.js +++ b/WebKit/scripts/controller/Oauth.js @@ -1,10 +1,10 @@ define([ "helper/HostApp", - "helper/Paths", + "helper/APICalls", "helper/Hmac" ], -function(HostApp, Paths, Hmac) { +function(HostApp, APICalls, Hmac) { function Oauth() { this.app_info = { @@ -70,7 +70,7 @@ function(HostApp, Paths, Hmac) { Oauth.prototype.requestProfileURL = function (entity) { var those = this; - Paths.findProfileURL(entity, + APICalls.findProfileURL(entity, function(profile_url) { if (profile_url && (profile_url.startsWith("http://") || profile_url.startsWith("https://"))) { those.register(profile_url); @@ -87,7 +87,7 @@ function(HostApp, Paths, Hmac) { Oauth.prototype.register = function (url) { var those = this; - Paths.getURL(url, "GET", function(resp) { + APICalls.get(url, { callback: function(resp) { those.profile = JSON.parse(resp.responseText); those.entity = those.profile.content.entity; @@ -98,16 +98,16 @@ function(HostApp, Paths, Hmac) { var app_id = JSON.parse(resp.responseText).id; var header_string = resp.getAllResponseHeaders(); var regexp = /https:\/\/tent.io\/rels\/credentials/i - var url = Paths.parseHeaderForLink(header_string, regexp); - Paths.getURL(url, "GET", function(resp) { + var url = APICalls.parseHeaderForLink(header_string, regexp); + APICalls.http_call(url, "GET", function(resp) { var data = JSON.parse(resp.responseText); those.authRequest(data, app_id); }, null, false) } - Paths.getURL(HostApp.serverUrl("new_post"), "POST", callback, JSON.stringify(those.app_info), false); + APICalls.post(HostApp.serverUrl("new_post"), JSON.stringify(those.app_info), {callback: callback}); - }, null, false); + }}); } Oauth.prototype.authRequest = function(credentials, app_id) { @@ -126,7 +126,7 @@ function(HostApp, Paths, Hmac) { // /oauthtoken?code=51d0115b04d1ed94001dde751c5b360f&state=aQfH1VEohYsQr86qqyv // https://app.example.com/oauth?code=K4m2J2bGI9rcICBqmUCYuQ&state=d173d2bb868a - var urlVars = Paths.getUrlVars(responseBody); + var urlVars = APICalls.getUrlVars(responseBody); if(this.state && this.state != "" && urlVars["state"] == this.state) { var url = HostApp.serverUrl("oauth_token"); @@ -150,7 +150,7 @@ function(HostApp, Paths, Hmac) { requestBody ); - Paths.getURL(url, http_method, callback, requestBody, auth_header); + APICalls.http_call(url, http_method, callback, requestBody, auth_header); } else { console.error("State is not the same: {" + this.state + "} vs {" + urlVars["state"] + "}") @@ -174,7 +174,7 @@ function(HostApp, Paths, Hmac) { Oauth.prototype.logout = function() { - var url = Paths.mkApiRootPath("/apps/" + HostApp.stringForKey("app_id")); + var url = APICalls.mkApiRootPath("/apps/" + HostApp.stringForKey("app_id")); var http_method = "DELETE"; var auth_header = Hmac.makeAuthHeader( url, @@ -183,7 +183,7 @@ function(HostApp, Paths, Hmac) { HostApp.stringForKey("app_mac_key_id") ); - Paths.getURL(url, http_method, function(resp) { + APICalls.http_call(url, http_method, function(resp) { HostApp.setStringForKey(null, "app_mac_key"); HostApp.setStringForKey(null, "app_mac_key_id"); HostApp.setStringForKey(null, "app_id"); diff --git a/WebKit/scripts/controller/Profile.js b/WebKit/scripts/controller/Profile.js index 584a046..6058784 100644 --- a/WebKit/scripts/controller/Profile.js +++ b/WebKit/scripts/controller/Profile.js @@ -1,11 +1,11 @@ define([ "helper/HostApp", "helper/Core", - "helper/Paths", + "helper/APICalls", "lib/URI" ], -function(HostApp, Core, Paths, URI) { +function(HostApp, Core, APICalls, URI) { function Profile() { @@ -239,11 +239,11 @@ function(HostApp, Core, Paths, URI) { this.profile = profile; } else { - Paths.findProfileURL(this.entity, function(profile_url) { + APICalls.findProfileURL(this.entity, function(profile_url) { if (profile_url) { - Paths.getURL(profile_url, "GET", function(resp) { + APICalls.http_call(profile_url, "GET", function(resp) { profile = JSON.parse(resp.responseText); _this.showProfile(profile); @@ -258,9 +258,9 @@ function(HostApp, Core, Paths, URI) { Profile.prototype.getFollowing = function() { if(this.entity != HostApp.stringForKey("entity")) { - var url = Paths.mkApiRootPath("/followings") + "/" + encodeURIComponent(this.entity); + var url = APICalls.mkApiRootPath("/followings") + "/" + encodeURIComponent(this.entity); var _this = this; - Paths.getURL(url, "GET", function(resp) { + APICalls.http_call(url, "GET", function(resp) { if (resp.status >= 200 && resp.status < 400) { var following = JSON.parse(resp.responseText); _this.following_id = following.id @@ -325,18 +325,18 @@ function(HostApp, Core, Paths, URI) { Profile.prototype.getMeta = function(root_url) { var _this = this; - Paths.getURL(URI(root_url + "/followings/count").toString(), "GET", function(resp) { + APICalls.http_call(URI(root_url + "/followings/count").toString(), "GET", function(resp) { _this.populate(_this.profile_template.following, resp.responseText); }, null, false); - Paths.getURL(URI(root_url + "/followers/count").toString(), "GET", function(resp) { + APICalls.http_call(URI(root_url + "/followers/count").toString(), "GET", function(resp) { _this.populate(_this.profile_template.followed, resp.responseText); }, null, false); if (this.entity != HostApp.stringForKey("entity")) { - Paths.getURL(URI(root_url + "/followers/" + encodeURIComponent(HostApp.stringForKey("entity"))).toString(), "GET", function(resp) { + APICalls.http_call(URI(root_url + "/followers/" + encodeURIComponent(HostApp.stringForKey("entity"))).toString(), "GET", function(resp) { if (resp.status == 200) { _this.relationships.following_you = true; } @@ -344,7 +344,7 @@ function(HostApp, Core, Paths, URI) { }, null, false); - Paths.getURL(URI(Paths.mkApiRootPath("/followings/" + encodeURIComponent(this.entity))), "GET", function(resp) { + APICalls.http_call(URI(APICalls.mkApiRootPath("/followings/" + encodeURIComponent(this.entity))), "GET", function(resp) { if (resp.status == 200) { _this.relationships.followed_by_you = true; } @@ -363,7 +363,7 @@ function(HostApp, Core, Paths, URI) { ]; url.addSearch("post_types", post_types.join(",")); - Paths.getURL(url.toString(), "GET", function(resp) { + APICalls.http_call(url.toString(), "GET", function(resp) { _this.populate(_this.profile_template.posts, resp.responseText); }, null, false); @@ -405,7 +405,7 @@ function(HostApp, Core, Paths, URI) { url.addSearch(key, add_search[key]); } - Paths.getURL(url.toString(), "GET", function(resp) { + APICalls.http_call(url.toString(), "GET", function(resp) { var statuses = JSON.parse(resp.responseText); @@ -495,8 +495,8 @@ function(HostApp, Core, Paths, URI) { if (this.following_id) { this.setFollowingButton(false); - var url = Paths.mkApiRootPath("/followings/") + this.following_id; - Paths.getURL(url, "DELETE", function(resp) { + var url = APICalls.mkApiRootPath("/followings/") + this.following_id; + APICalls.http_call(url, "DELETE", function(resp) { if (resp.status >= 200 && resp.status < 300) { _this.setFollowingButton(false); _this.following_id = null; @@ -508,10 +508,10 @@ function(HostApp, Core, Paths, URI) { } else { this.setFollowingButton(true); - var url = URI(Paths.mkApiRootPath("/followings")); + var url = URI(APICalls.mkApiRootPath("/followings")); var data = JSON.stringify({"entity": this.entity }); - Paths.getURL(url.toString(), "POST", function(resp) { + APICalls.http_call(url.toString(), "POST", function(resp) { if (resp.status >= 200 && resp.status < 300) { _this.following_id = JSON.parse(resp.responseText).id _this.setFollowingButton(true); @@ -542,7 +542,7 @@ function(HostApp, Core, Paths, URI) { var url = URI(this.server + "/followings"); url.addSearch("limit", 200); - Paths.getURL(url.toString(), "GET", callback, null, false); + APICalls.http_call(url.toString(), "GET", callback, null, false); } Profile.prototype.showFollowers = function() { @@ -561,7 +561,7 @@ function(HostApp, Core, Paths, URI) { var url = URI(this.server + "/followers"); url.addSearch("limit", 200); - Paths.getURL(url.toString(), "GET", callback, null, false); + APICalls.http_call(url.toString(), "GET", callback, null, false); } Profile.prototype.getDOMSmallProfile = function(profile) { @@ -643,10 +643,10 @@ function(HostApp, Core, Paths, URI) { } else { var _this = this; - Paths.findProfileURL(profile.entity, function(profile_url) { + APICalls.findProfileURL(profile.entity, function(profile_url) { if (profile_url) { - Paths.getURL(profile_url, "GET", function(resp) { + APICalls.http_call(profile_url, "GET", function(resp) { var p = JSON.parse(resp.responseText); if (p && p != "null") { _this.cache.profiles.setItem(profile.entity, p); diff --git a/WebKit/scripts/controller/Search.js b/WebKit/scripts/controller/Search.js index 51ce153..b083362 100644 --- a/WebKit/scripts/controller/Search.js +++ b/WebKit/scripts/controller/Search.js @@ -1,11 +1,11 @@ define([ "helper/HostApp", "helper/Core", - "helper/Paths", + "helper/APICalls", "lib/URI" ], -function(HostApp, Core, Paths, URI) { +function(HostApp, Core, APICalls, URI) { function Search() { @@ -79,7 +79,7 @@ function(HostApp, Core, Paths, URI) { var _this = this; - Paths.getURL(url.toString(), "GET", function(resp) { + APICalls.http_call(url.toString(), "GET", function(resp) { var results = JSON.parse(resp.responseText).results; if (results && results.length > 0) { diff --git a/WebKit/scripts/controller/Sidebar.js b/WebKit/scripts/controller/Sidebar.js index 5b453b8..69b8831 100644 --- a/WebKit/scripts/controller/Sidebar.js +++ b/WebKit/scripts/controller/Sidebar.js @@ -1,10 +1,10 @@ define([ "helper/HostApp", - "helper/Paths", + "helper/APICalls", "helper/Cache" ], -function(HostApp, Paths, Cache) { +function(HostApp, APICalls, Cache) { function Sidebar() { @@ -121,10 +121,10 @@ function(HostApp, Paths, Cache) { } else { - Paths.findProfileURL(entity, function(profile_url) { + APICalls.findProfileURL(entity, function(profile_url) { if (profile_url) { - Paths.getURL(profile_url, "GET", function(resp) { + APICalls.http_call(profile_url, "GET", function(resp) { var p = JSON.parse(resp.responseText); if (p && p != "null") { _this.cache.profiles.setItem(entity, p); diff --git a/WebKit/scripts/controller/Timeline.js b/WebKit/scripts/controller/Timeline.js index fbd1383..307a651 100644 --- a/WebKit/scripts/controller/Timeline.js +++ b/WebKit/scripts/controller/Timeline.js @@ -1,11 +1,11 @@ define([ "helper/Core", - "helper/Paths", + "helper/APICalls", "helper/HostApp", "lib/URI" ], -function(Core, Paths, HostApp, URI) { +function(Core, APICalls, HostApp, URI) { function Timeline() { @@ -100,7 +100,7 @@ function(Core, Paths, HostApp, URI) { add_to_search = add_to_search || {}; var those = this; - var url = URI(Paths.mkApiRootPath("/posts")); + var url = URI(APICalls.mkApiRootPath("/posts")); var post_types = [ "https://tent.io/types/post/repost/v0.1.0", @@ -143,7 +143,7 @@ function(Core, Paths, HostApp, URI) { if (!this.reload_blocked) { this.reload_blocked = true; - Paths.getURL(url.toString(), http_method, callback, data); // FIXME: error callback + APICalls.http_call(url.toString(), http_method, callback, data); // FIXME: error callback } } } diff --git a/WebKit/scripts/helper/APICalls.js b/WebKit/scripts/helper/APICalls.js new file mode 100644 index 0000000..3176a13 --- /dev/null +++ b/WebKit/scripts/helper/APICalls.js @@ -0,0 +1,285 @@ +define([ + "jquery", + "helper/HostApp", + "helper/Hmac", + "helper/Cache" +], + +function(jQuery, HostApp, Hmac, Cache) { + var APICalls = {}; + + APICalls.cache = new Cache(); + + APICalls.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; + } +/* + APICalls.http_call = function(url, http_method, callback, data, auth_header, accepts) { + + if(accepts !== false) accepts = accepts || "application/vnd.tent.post.v0+json"; + + var options = { + + beforeSend: function(xhr) { + + if(accepts !== false) xhr.setRequestHeader("Accept", accepts); + + 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 && typeof user_access_token != "undefined") { + + auth_header = Hmac.makeAuthHeader( + url, + http_method, + HostApp.secret(), + user_access_token + ); + xhr.setRequestHeader("Authorization", auth_header); + } + } + }, + url: url, + contentType: 'application/vnd.tent.post.v0+json; type="https://tent.io/types/app/v0#"', + type: http_method, + complete: callback, + data: data, + processData: false, + error: function(xhr, ajaxOptions, thrownError) { + console.error("getURL (" + xhr.status + ")" + xhr.statusText + " " + http_method + " (" + url + "): '" + xhr.responseText + "'"); + } + } + debug(url) + jQuery.ajax(options); + } +*/ + APICalls.http_call = function(options) { + + if(!options.content_type) { + console.error("No content type for " + options.url); + return; + } + + var settings = { + beforeSend: function(xhr) { + if (options.data) xhr.setRequestHeader("Content-Length", data.length); + if (options.accept) xhr.setRequestHeader("Accept", "application/vnd.tent.post.v0+json"); + var user_access_token = HostApp.stringForKey("user_access_token"); + if (!no_auth && user_access_token) { + var auth_header = Hmac.makeHawkAuthHeader( + options.url, + options.http_method, + HostApp.secret(), + user_access_token + ); + xhr.setRequestHeader("Authorization", auth_header); + } else { + console.error("No user_access_token yet - " + options.url); + } + } + url: options.url, + contentType: options.content_type, + type: url.http_method, + complete: options.callback, + data: options.data, + processData: false, + error: function(xhr, ajaxOptions, thrownError) { + console.error("HTTP CALL (" + xhr.status + ")" + xhr.statusText + " " + options.http_method + " (" + options.url + "): '" + xhr.responseText + "'"); + } + }; + + jQuery.ajax(settings); + } + + APICalls.get = function(url, options) { + var settings = { + url: url, + http_method: "GET", + accept: null, + data: null, + no_auth: false + content_type: null + }; + + jQuery.extend(settings, options); + + APICalls.http_call(settings); + } + + APICalls.post = function(url, data, options) { + var settings = { + url: url, + http_method: "POST", + data: data + }; + + jQuery.extend(settings, options); + + APICalls.http_call(settings); + } + + APICalls.postMultipart = function(url, callback, data, boundary, accepts) { + + accepts = accepts || "application/vnd.tent.v0+json"; + + jQuery.ajax({ + + beforeSend: function(xhr) { + xhr.setRequestHeader("Accept", accepts); + + if (data) xhr.setRequestHeader("Content-Length", data.length); + + var user_access_token = HostApp.stringForKey("user_access_token"); + + if (user_access_token) { + + auth_header = Hmac.makeAuthHeader( + url, + "POST", + HostApp.secret(), + user_access_token + ); + + xhr.setRequestHeader("Authorization", auth_header); + } + }, + url: url, + contentType: "multipart/form-data;boundary=" + boundary, + type: "POST", + complete: callback, + data: data, + processData: false, + error: function(xhr, ajaxOptions, thrownError) { + console.error("postMultipart (" + xhr.status + ")" + xhr.statusText + " (" + url + "): '" + xhr.responseText + "'"); + } + }); + } + + APICalls.findProfileURL = function(entity, callback, errorCallback) { + var profile_url = APICalls.cache.profile_urls.getItem(entity); + + if (profile_url && profile_url != "null") { + + callback(profile_url); + + } else { + + jQuery.ajax({ + url: entity, + type: "HEAD", + complete: function(resp) { + if(resp) { + var headers = resp.getAllResponseHeaders(); + + var profile_urls = APICalls.parseHeaderForProfiles(headers); + var profile_url = null; + if(profile_urls.length > 0) { + var profile_url = profile_urls[0]; + if (!profile_url.startsWith("http")) { + profile_url = entity + profile_url; + } + } + + if (profile_url) { + APICalls.cache.profile_urls.setItem(entity, profile_url); + callback(profile_url); + } else { + APICalls.http_call(entity, "GET", function(resp) { + + if (resp.status >= 200 && resp.status < 300) { + var doc = document.implementation.createHTMLDocument(""); + doc.documentElement.innerHTML = resp.responseText; + var links = $(doc).find("link[rel='https://tent.io/rels/meta-post']"); + + if (links.length > 0) { + var href = links.get(0).href; + APICalls.cache.profile_urls.setItem(entity, href); + if (!href.startsWith("http")) { + href = entity + href; + } + callback(href); + + } else { + if(errorCallback) errorCallback(entity + " has no profile URL"); + } + } else { + if(errorCallback) errorCallback(entity + " has no profile URL"); + } + + }, null, false, false); + + //if(errorCallback) errorCallback(entity + " has no profile URL"); + } + } + }, + error: function(xhr, ajaxOptions, thrownError) { + console.error("findProfileURL " + xhr.statusText + " (" + entity + "): " + xhr.responseText); + if (errorCallback) errorCallback(xhr.statusText + " - " + xhr.responseText) + } + }); + } + } + + APICalls.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; + } + + APICalls.parseHeaderForProfiles = function(header_string) { + var regexp = /https:\/\/tent.io\/rels\/meta-post/i; + return APICalls.parseHeaderForLink(header_string, regexp); + } + + APICalls.parseHeaderForLink = function(header_string, match) { + var headers = header_string.split(/\n/); + var links = []; + for (var i = 0; i < headers.length; i++) { + var header = headers[i]; + if (header.match(/^Link:(.*)/i)) { + links.push(header.replace(/\r/, "").substr(5).trim()); + } + } + + var items = []; + for (var i = 0; i < links.length; i++) { + items = items.concat(links[i].split(",")); + } + var things = []; + for (var i = 0; i < items.length; i++) { + var item = items[i]; + if (item.match(match)) { + var n = item.match(/<([^>]*)>/); + if (n) { + things.push(n[1]); + } + } + } + + return things; + } + + return APICalls; +}); \ No newline at end of file diff --git a/WebKit/scripts/helper/Cache.js b/WebKit/scripts/helper/Cache.js index eb79fe7..2b35364 100644 --- a/WebKit/scripts/helper/Cache.js +++ b/WebKit/scripts/helper/Cache.js @@ -40,12 +40,12 @@ function(URI, CacheStorage, require) { } } - var url = URI(require("helper/Paths").mkApiRootPath("/followings")); + var url = URI(require("helper/APICalls").mkApiRootPath("/followings")); if (this.followings_before_id) { url.addSearch("before_id", this.followings_before_id); } - require("helper/Paths").getURL(url, "GET", callback); + require("helper/APICalls").getURL(url, "GET", callback); } Cache.prototype.periodicallyGetFollowings = function() { diff --git a/WebKit/scripts/helper/Core.js b/WebKit/scripts/helper/Core.js index 7f3b350..68e1e41 100644 --- a/WebKit/scripts/helper/Core.js +++ b/WebKit/scripts/helper/Core.js @@ -1,6 +1,6 @@ define([ "jquery", - "helper/Paths", + "helper/APICalls", "lib/URI", "helper/HostApp", "helper/Cache", @@ -8,7 +8,7 @@ define([ "lib/SingleDoubleClick" ], -function(jQuery, Paths, URI, HostApp, Cache) { +function(jQuery, APICalls, URI, HostApp, Cache) { function Core() { this.cache = new Cache(); @@ -247,10 +247,10 @@ function(jQuery, Paths, URI, HostApp, Cache) { } else { - Paths.findProfileURL(status.entity, function(profile_url) { + APICalls.findProfileURL(status.entity, function(profile_url) { if (profile_url) { - Paths.getURL(profile_url, "GET", function(resp) { + APICalls.http_call(profile_url, "GET", function(resp) { var p = JSON.parse(resp.responseText); if (p && p != "null") { _this.cache.profiles.setItem(status.entity, p); @@ -308,11 +308,11 @@ function(jQuery, Paths, URI, HostApp, Cache) { } if (status.entity == HostApp.stringForKey("entity")) { - var url = Paths.mkApiRootPath("/posts/" + status.id + "/attachments/" + attachment.name); - Paths.getURL(url, "GET", callback, null, null, attachment.type); + var url = APICalls.mkApiRootPath("/posts/" + status.id + "/attachments/" + attachment.name); + APICalls.http_call(url, "GET", callback, null, null, attachment.type); } else { - var url = Paths.mkApiRootPath("/posts/" + encodeURIComponent(status.entity) + "/" + status.id + "/attachments/" + attachment.name); - Paths.getURL(url, "GET", callback, null, null, attachment.type); + var url = APICalls.mkApiRootPath("/posts/" + encodeURIComponent(status.entity) + "/" + status.id + "/attachments/" + attachment.name); + APICalls.http_call(url, "GET", callback, null, null, attachment.type); } })(); } @@ -431,9 +431,9 @@ function(jQuery, Paths, URI, HostApp, Cache) { }); var _this = this; - Paths.findProfileURL(repost.entity, function(profile_url) { + APICalls.findProfileURL(repost.entity, function(profile_url) { if (profile_url) { - Paths.getURL(profile_url, "GET", function(resp) { + APICalls.http_call(profile_url, "GET", function(resp) { if (resp.status >= 200 && resp.status < 400) { var _p = JSON.parse(resp.responseText); _this.cache.profiles.setItem(repost.entity, _p); @@ -460,14 +460,14 @@ function(jQuery, Paths, URI, HostApp, Cache) { } } - Paths.findProfileURL(repost.content.entity, function(profile_url) { + APICalls.findProfileURL(repost.content.entity, function(profile_url) { if (profile_url) { - Paths.getURL(profile_url, "GET", function(resp) { + APICalls.http_call(profile_url, "GET", function(resp) { var profile = JSON.parse(resp.responseText); var server = profile["https://tent.io/types/info/core/v0.1.0"].servers[0]; - Paths.getURL(URI(server + "/posts/" + repost.content.id).toString(), "GET", callback, null, false); + APICalls.http_call(URI(server + "/posts/" + repost.content.id).toString(), "GET", callback, null, false); }, null, false); // do not send auth-headers } @@ -483,7 +483,7 @@ function(jQuery, Paths, URI, HostApp, Cache) { } else { - var url = URI(Paths.mkApiRootPath("/posts")); + var url = URI(APICalls.mkApiRootPath("/posts")); var http_method = "POST"; @@ -517,13 +517,13 @@ function(jQuery, Paths, URI, HostApp, Cache) { } } - Paths.getURL(url.toString(), http_method, callback, JSON.stringify(data)); + APICalls.http_call(url.toString(), http_method, callback, JSON.stringify(data)); } } Core.prototype.repost = function(id, entity, callback) { - var url = URI(Paths.mkApiRootPath("/posts")); + var url = URI(APICalls.mkApiRootPath("/posts")); var data = { "type": "https://tent.io/types/post/repost/v0.1.0", @@ -549,12 +549,12 @@ function(jQuery, Paths, URI, HostApp, Cache) { _this.highlight(id); } - Paths.getURL(url.toString(), "POST", new_callback, JSON.stringify(data)); + APICalls.http_call(url.toString(), "POST", new_callback, JSON.stringify(data)); } Core.prototype.sendNewMessageWithImage = function(content, in_reply_to_status_id, in_reply_to_entity, location, image_data_uri, is_private, callback) { - var url = URI(Paths.mkApiRootPath("/posts")); + var url = URI(APICalls.mkApiRootPath("/posts")); var data = { "type": "https://tent.io/types/post/photo/v0.1.0", @@ -623,14 +623,14 @@ function(jQuery, Paths, URI, HostApp, Cache) { callback(resp); } - Paths.postMultipart(url.toString(), newCallback, post, boundary); + APICalls.postMultipart(url.toString(), newCallback, post, boundary); } Core.prototype.remove = function(id, callback, type) { type = type || "post"; if (confirm("Really delete this " + type + "?")) { - var url = URI(Paths.mkApiRootPath("/posts/" + id)); - Paths.getURL(url.toString(), "DELETE", callback); + var url = URI(APICalls.mkApiRootPath("/posts/" + id)); + APICalls.http_call(url.toString(), "DELETE", callback); } } @@ -738,9 +738,9 @@ function(jQuery, Paths, URI, HostApp, Cache) { } else { - Paths.findProfileURL(mention.entity, function(profile_url) { + APICalls.findProfileURL(mention.entity, function(profile_url) { if (profile_url) { - Paths.getURL(profile_url, "GET", function(resp) { + APICalls.http_call(profile_url, "GET", function(resp) { if (resp.status >= 200 && resp.status < 400) { var p = JSON.parse(resp.responseText); _this.cache.profiles.setItem(mention.entity, p); @@ -838,7 +838,7 @@ function(jQuery, Paths, URI, HostApp, Cache) { } else if(word.startsWith("http://youtube.com/") || word.startsWith("http://www.youtube.com/") || word.startsWith("https://youtube.com/") || word.startsWith("https://www.youtube.com/")) { - var v = Paths.getUrlVars(word)["v"]; + var v = APICalls.getUrlVars(word)["v"]; this.addYouTube(v, images); } else if (word.startsWith("http://youtu.be/") || word.startsWith("https://youtu.be/")) { From 650f107d21a40bdbfdb99d5f519635bb33fa871f Mon Sep 17 00:00:00 2001 From: jeena Date: Mon, 27 May 2013 09:44:43 +0200 Subject: [PATCH 03/18] more work on posting and showing status posts --- WebKit/scripts/controller/Mentions.js | 1 + WebKit/scripts/controller/Oauth.js | 42 ++++++++----- WebKit/scripts/controller/Sidebar.js | 2 +- WebKit/scripts/controller/Timeline.js | 22 ++++--- WebKit/scripts/helper/APICalls.js | 91 +++++++++------------------ WebKit/scripts/helper/Core.js | 42 ++++++++++--- WebKit/scripts/helper/Hmac.js | 43 ++----------- 7 files changed, 108 insertions(+), 135 deletions(-) diff --git a/WebKit/scripts/controller/Mentions.js b/WebKit/scripts/controller/Mentions.js index 7d20d5b..68fc7ec 100644 --- a/WebKit/scripts/controller/Mentions.js +++ b/WebKit/scripts/controller/Mentions.js @@ -10,6 +10,7 @@ function(HostApp, Timeline, URI, APICalls, Core) { function Mentions() { + return // FIXME this.is_not_init = false; this.unread_mentions = 0; diff --git a/WebKit/scripts/controller/Oauth.js b/WebKit/scripts/controller/Oauth.js index a60a286..f020b5e 100644 --- a/WebKit/scripts/controller/Oauth.js +++ b/WebKit/scripts/controller/Oauth.js @@ -87,31 +87,40 @@ function(HostApp, APICalls, Hmac) { Oauth.prototype.register = function (url) { var those = this; - APICalls.get(url, { callback: function(resp) { + debug(url) + APICalls.get(url, { + no_auth: true, + callback: function(resp) { those.profile = JSON.parse(resp.responseText); those.entity = those.profile.content.entity; HostApp.setStringForKey(those.entity, "entity") HostApp.setServerUrls(those.profile.content.servers[0].urls); - var callback = function(resp) { + APICalls.post(HostApp.serverUrl("new_post"), JSON.stringify(those.app_info), { + content_type: "https://tent.io/types/app/v0#", + no_auth: true, + callback: function(resp) { + var app_id = JSON.parse(resp.responseText).id; var header_string = resp.getAllResponseHeaders(); var regexp = /https:\/\/tent.io\/rels\/credentials/i var url = APICalls.parseHeaderForLink(header_string, regexp); - APICalls.http_call(url, "GET", function(resp) { - var data = JSON.parse(resp.responseText); - those.authRequest(data, app_id); - }, null, false) - } - APICalls.post(HostApp.serverUrl("new_post"), JSON.stringify(those.app_info), {callback: callback}); + APICalls.get(url, { + content_type: "https://tent.io/types/app/v0#", + no_auth: true, + callback: function(resp) { + var data = JSON.parse(resp.responseText); + those.authRequest(data, app_id); + }}); + }}); }}); } Oauth.prototype.authRequest = function(credentials, app_id) { - + HostApp.setStringForKey(app_id, "app_id"); HostApp.setStringForKey(credentials.id, "app_hawk_id"); HostApp.setStringForKey(credentials.content.hawk_key, "app_hawk_key"); @@ -137,20 +146,20 @@ function(HostApp, APICalls, Hmac) { }); var those = this; - var http_method = "POST"; - var callback = function(resp) { - those.requestAccessTokenTicketFinished(resp.responseText); - }; - var auth_header = Hmac.makeHawkAuthHeader( url, - http_method, + "POST", HostApp.stringForKey("app_hawk_id"), HostApp.stringForKey("app_hawk_key"), requestBody ); - APICalls.http_call(url, http_method, callback, requestBody, auth_header); + APICalls.post(url, requestBody, { + content_type: "https://tent.io/types/app/v0#", + auth_header: auth_header, + callback: function(resp) { + those.requestAccessTokenTicketFinished(resp.responseText); + }}); } else { console.error("State is not the same: {" + this.state + "} vs {" + urlVars["state"] + "}") @@ -162,6 +171,7 @@ function(HostApp, APICalls, Hmac) { Oauth.prototype.requestAccessTokenTicketFinished = function(responseBody) { var access = JSON.parse(responseBody); + debug(access) HostApp.setStringForKey(access["access_token"], "user_access_token"); HostApp.setSecret(access["hawk_key"]); diff --git a/WebKit/scripts/controller/Sidebar.js b/WebKit/scripts/controller/Sidebar.js index 69b8831..e715f94 100644 --- a/WebKit/scripts/controller/Sidebar.js +++ b/WebKit/scripts/controller/Sidebar.js @@ -51,7 +51,7 @@ function(HostApp, APICalls, Cache) { document.body.className = "body-timeline"; document.body.id = "with-sidebar"; - this.setEntityAvatar(); + //this.setEntityAvatar(); FIXME this.setOnScroll(); } diff --git a/WebKit/scripts/controller/Timeline.js b/WebKit/scripts/controller/Timeline.js index 307a651..19030eb 100644 --- a/WebKit/scripts/controller/Timeline.js +++ b/WebKit/scripts/controller/Timeline.js @@ -30,7 +30,7 @@ function(Core, APICalls, HostApp, URI) { document.getElementById("content").appendChild(this.container); var _this = this; - this.reloadIntervall = setInterval(function() { _this.getNewData() }, this.timeout); + //this.reloadIntervall = setInterval(function() { _this.getNewData() }, this.timeout); //FIXME back this.getNewData(); } @@ -48,6 +48,7 @@ function(Core, APICalls, HostApp, URI) { Timeline.prototype.newStatus = function(statuses, append) { + statuses = statuses.data; if(statuses != null && statuses.length > 0) { this.before.loading = false; @@ -62,7 +63,7 @@ function(Core, APICalls, HostApp, URI) { this.since_id_entity = status.entity; } - if (status.type == "https://tent.io/types/post/status/v0.1.0" || status.type == "https://tent.io/types/post/photo/v0.1.0") { + if (status.type == "https://tent.io/types/status/v0#" || status.type == "https://tent.io/types/post/photo/v0.1.0") { var new_node = this.getStatusDOMElement(status); @@ -100,15 +101,16 @@ function(Core, APICalls, HostApp, URI) { add_to_search = add_to_search || {}; var those = this; - var url = URI(APICalls.mkApiRootPath("/posts")); + var url = URI(HostApp.serverUrl("posts_feed")); var post_types = [ - "https://tent.io/types/post/repost/v0.1.0", - "https://tent.io/types/post/status/v0.1.0", - "https://tent.io/types/post/delete/v0.1.0", - "https://tent.io/types/post/photo/v0.1.0" + "https://tent.io/types/status/v0#", + "https://tent.io/types/status/v0#reply", + "https://tent.io/types/repost/v0#", + "https://tent.io/types/delete/v0#", + //"https://tent.io/types/post/photo/v0.1.0" ]; - url.addSearch("post_types", post_types.join(",")); + //url.addSearch("types", post_types.join(",")); //url.addSearch("sort_by", "published_at"); url.addSearch("limit", this.posts_limit); @@ -127,7 +129,6 @@ function(Core, APICalls, HostApp, URI) { those.reload_blocked = false; try { - var json = JSON.parse(resp.responseText); those.newStatus(json, append); @@ -143,7 +144,8 @@ function(Core, APICalls, HostApp, URI) { if (!this.reload_blocked) { this.reload_blocked = true; - APICalls.http_call(url.toString(), http_method, callback, data); // FIXME: error callback + // APICalls.http_call(url.toString(), http_method, callback, data); // FIXME: error callback + APICalls.get(url.toString(), { callback: callback }); } } } diff --git a/WebKit/scripts/helper/APICalls.js b/WebKit/scripts/helper/APICalls.js index 3176a13..dd942de 100644 --- a/WebKit/scripts/helper/APICalls.js +++ b/WebKit/scripts/helper/APICalls.js @@ -22,80 +22,47 @@ function(jQuery, HostApp, Hmac, Cache) { } return vars; } -/* - APICalls.http_call = function(url, http_method, callback, data, auth_header, accepts) { - if(accepts !== false) accepts = accepts || "application/vnd.tent.post.v0+json"; - - var options = { - - beforeSend: function(xhr) { - - if(accepts !== false) xhr.setRequestHeader("Accept", accepts); - - 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 && typeof user_access_token != "undefined") { - - auth_header = Hmac.makeAuthHeader( - url, - http_method, - HostApp.secret(), - user_access_token - ); - xhr.setRequestHeader("Authorization", auth_header); - } - } - }, - url: url, - contentType: 'application/vnd.tent.post.v0+json; type="https://tent.io/types/app/v0#"', - type: http_method, - complete: callback, - data: data, - processData: false, - error: function(xhr, ajaxOptions, thrownError) { - console.error("getURL (" + xhr.status + ")" + xhr.statusText + " " + http_method + " (" + url + "): '" + xhr.responseText + "'"); - } - } - debug(url) - jQuery.ajax(options); - } -*/ APICalls.http_call = function(options) { - if(!options.content_type) { + if (typeof options === "string") { + console.error(options + " not implemented yet") + return; + } + + var content_type = null; + + if(options.http_method == "POST" && !options.content_type) { console.error("No content type for " + options.url); return; + } else { + content_type = "application/vnd.tent.post.v0+json; type=\"" + options.content_type + "\""; } var settings = { beforeSend: function(xhr) { - if (options.data) xhr.setRequestHeader("Content-Length", data.length); - if (options.accept) xhr.setRequestHeader("Accept", "application/vnd.tent.post.v0+json"); + if (options.data) xhr.setRequestHeader("Content-Length", options.data.length); + if (options.accept) xhr.setRequestHeader("Accept", options.accept); + else xhr.setRequestHeader("Accept", "application/vnd.tent.post.v0+json"); var user_access_token = HostApp.stringForKey("user_access_token"); - if (!no_auth && user_access_token) { + if (!options.auth_header && !options.no_auth && user_access_token) { var auth_header = Hmac.makeHawkAuthHeader( options.url, options.http_method, - HostApp.secret(), - user_access_token + user_access_token, + HostApp.secret()//, + //HostApp.stringForKey("app_id") ); xhr.setRequestHeader("Authorization", auth_header); - } else { + } else if(options.auth_header) { + xhr.setRequestHeader("Authorization", options.auth_header); + } else if(!options.no_auth) { console.error("No user_access_token yet - " + options.url); } - } + }, url: options.url, - contentType: options.content_type, - type: url.http_method, + contentType: content_type, + type: options.http_method, complete: options.callback, data: options.data, processData: false, @@ -111,13 +78,11 @@ function(jQuery, HostApp, Hmac, Cache) { var settings = { url: url, http_method: "GET", - accept: null, - data: null, - no_auth: false - content_type: null }; - jQuery.extend(settings, options); + for (var key in options) { + settings[key] = options[key]; + } APICalls.http_call(settings); } @@ -129,7 +94,9 @@ function(jQuery, HostApp, Hmac, Cache) { data: data }; - jQuery.extend(settings, options); + for (var key in options) { + settings[key] = options[key]; + } APICalls.http_call(settings); } diff --git a/WebKit/scripts/helper/Core.js b/WebKit/scripts/helper/Core.js index 68e1e41..802ca7a 100644 --- a/WebKit/scripts/helper/Core.js +++ b/WebKit/scripts/helper/Core.js @@ -162,7 +162,28 @@ function(jQuery, APICalls, URI, HostApp, Cache) { } Core.prototype.getStatusDOMElement = function(status) { - + /* +{ + "app": { + "id": "P8FJjaiRv0AKXfjUMd_4YQ", + "name": "Bungloo on Linux", + "url": "http:\/\/jabs.nu\/bungloo\/" + }, + "content": { + "text": "jeena test" + }, + "entity": "http:\/\/155969d81672.alpha.attic.is", + "id": "HlSXe8MREzU4h2fGLGSnCA", + "published_at": 1369566009, + "received_at": 1369566008799, + "type": "https:\/\/tent.io\/types\/status\/v0#", + "version": { + "id": "a2f702b4615c7d7dd0f98c73d7b55749880bf6e437a77349454ff10745d134c6", + "published_at": 1369566009, + "received_at": 1369566008799 + } +} + */ var _this = this; var template = this.getTemplate(); @@ -320,6 +341,7 @@ function(jQuery, APICalls, URI, HostApp, Cache) { this.findMentions(template.message, status.mentions); +/* for (var i = 0; i < status.mentions.length; i++) { var mention = status.mentions[i]; if (mention.entity == HostApp.stringForKey("entity")) { @@ -327,10 +349,10 @@ function(jQuery, APICalls, URI, HostApp, Cache) { break; } } - - var published_at = typeof status.__repost == "undefined" ? status.published_at : status.__repost.published_at; +*/ + var published_at = typeof status.__repost == "undefined" ? status.version.published_at : status.__repost.published_at; var time = document.createElement("abbr"); - time.innerText = this.ISODateString(new Date(published_at * 1000)); + time.innerText = this.ISODateString(new Date(published_at)); time.title = time.innerText; time.className = "timeago"; jQuery(time).timeago(); @@ -483,13 +505,13 @@ function(jQuery, APICalls, URI, HostApp, Cache) { } else { - var url = URI(APICalls.mkApiRootPath("/posts")); + var url = URI(HostApp.serverUrl("new_post")); var http_method = "POST"; var data = { - "type": "https://tent.io/types/post/status/v0.1.0", - "published_at": parseInt(new Date().getTime() / 1000, 10), + "type": in_reply_to_status_id ? "https://tent.io/types/status/v0#" : "https://tent.io/types/status/v0#reply", + "published_at": parseInt(new Date().getTime(), 10), "permissions": { "public": !is_private }, @@ -517,7 +539,11 @@ function(jQuery, APICalls, URI, HostApp, Cache) { } } - APICalls.http_call(url.toString(), http_method, callback, JSON.stringify(data)); + // APICalls.http_call(url.toString(), http_method, callback, JSON.stringify(data)); + APICalls.post(url.toString(), JSON.stringify(data), { + content_type: data.type, + callback: callback + }); } } diff --git a/WebKit/scripts/helper/Hmac.js b/WebKit/scripts/helper/Hmac.js index 0e2b1fc..be4db38 100644 --- a/WebKit/scripts/helper/Hmac.js +++ b/WebKit/scripts/helper/Hmac.js @@ -7,40 +7,7 @@ function(URI, CryptoJS) { var Hmac = {}; - Hmac.makeAuthHeader = function(url, http_method, mac_key, mac_key_id) { - - debug("makeAuthHeader should not be used anymore, bug!") - - 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.makeHawkAuthHeader = function(url, http_method, hawk_id, key, payload, app_id) { + Hmac.makeHawkAuthHeader = function(url, http_method, hawk_id, key, app_id) { url = URI(url); var nonce = Hmac.makeid(8); @@ -58,24 +25,22 @@ function(URI, CryptoJS) { + url.path() + url.search() + url.hash() + '\n' // request uri + url.hostname().toLowerCase() + '\n' // host + port + '\n' // port - + Hmac.calculatePayloadHash(payload) + '\n' // hash + + '\n' // Hmac.calculatePayloadHash(payload) + '\n' // hash // FIXME implement payload validation + '\n' // ext (we don't use it) var app = ""; + if(app_id) { app = ', app="' + app_id + "'"; normalizedRequestString += app_id + "\n" + // app '\n'; // dlg should be empty } - var hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key); hmac.update(normalizedRequestString); var hash = hmac.finalize(); var mac = hash.toString(CryptoJS.enc.Base64); - - return 'Hawk id="' + hawk_id + '", mac="' + mac + '", ts="' + time_stamp + @@ -84,6 +49,8 @@ function(URI, CryptoJS) { } Hmac.calculatePayloadHash = function (payload) { + if (!payload) return ""; + var hash = CryptoJS.algo.SHA256.create(); hash.update('hawk.1.payload\n'); hash.update('application/vnd.tent.post.v0+json\n'); From 36e45d04abf6012eee0b07a69120cd87daf4e4ac Mon Sep 17 00:00:00 2001 From: jeena Date: Mon, 8 Jul 2013 17:03:53 +0200 Subject: [PATCH 04/18] more textarea fixes --- Qt/Bungloo.py | 23 ++-- Qt/Windows.py | 100 +++++--------- WebKit/css/default.css | 16 ++- WebKit/scripts/controller/NewPost.js | 197 +++++++++++++++++++++++++++ WebKit/scripts/controller/Oauth.js | 33 +++-- WebKit/scripts/controller/Profile.js | 27 ++-- WebKit/scripts/helper/Core.js | 13 +- WebKit/scripts/main.js | 25 +++- 8 files changed, 317 insertions(+), 117 deletions(-) create mode 100644 WebKit/scripts/controller/NewPost.js diff --git a/Qt/Bungloo.py b/Qt/Bungloo.py index 6a065e7..e5eaf3e 100755 --- a/Qt/Bungloo.py +++ b/Qt/Bungloo.py @@ -107,15 +107,12 @@ class Controller(QtCore.QObject): QtCore.QObject.__init__(self) self.app = app - oldpath = os.path.expanduser('~/.bungloo/') - if os.path.isdir(oldpath): - shutil.copytree(oldpath, os.path.expanduser('~/.config/bungloo/')) - shutil.rmtree(os.path.expanduser('~/.bungloo/')) + name = "bungloo2" - if not os.path.exists(os.path.expanduser("~/.config/bungloo/")): - os.makedirs(os.path.expanduser("~/.config/bungloo/")) + if not os.path.exists(os.path.expanduser("~/.config/" + name + "/")): + os.makedirs(os.path.expanduser("~/.config/" + name + "/")) - self.config_path = os.path.expanduser('~/.config/bungloo/bungloo.cfg') + self.config_path = os.path.expanduser('~/.config/' + name + '/bungloo.cfg') if os.access(self.config_path, os.R_OK): with open(self.config_path, 'r') as f: @@ -180,15 +177,12 @@ class Controller(QtCore.QObject): @QtCore.pyqtSlot(str, str, str, bool) def openNewMessageWindowInReplyTostatusIdwithStringIsPrivate(self, entity, status_id, string, is_private): - new_message_window = Windows.NewPost(self.app) - new_message_window.inReplyToStatusIdWithString(entity, status_id, string) - new_message_window.setIsPrivate(is_private) + new_message_window = Windows.NewPost(self.app, string, "[]", is_private) new_message_window.show() new_message_window.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.app.new_message_windows.append(new_message_window) new_message_window.activateWindow() new_message_window.setFocus() - new_message_window.textInput.setFocus() new_message_window.show() new_message_window.raise_() @@ -268,6 +262,11 @@ class Controller(QtCore.QObject): msgBox.setInformativeText(message) msgBox.exec_() + @QtCore.pyqtSlot(result=str) + def getCachedEntities(self): + entities = self.app.timeline.evaluateJavaScript("JSON.stringify(bungloo.cache.entities);") + return entities.toString() + def logout(self, sender): print "logout is not implemented yet" @@ -297,7 +296,7 @@ class Console(QtCore.QObject): if __name__ == "__main__": - key = 'BUNGLOO' + key = 'BUNGLOO2' if len(sys.argv) > 1 and sys.argv[1] == "--help": print """ diff --git a/Qt/Windows.py b/Qt/Windows.py index b47d8ae..7317f56 100644 --- a/Qt/Windows.py +++ b/Qt/Windows.py @@ -242,7 +242,7 @@ class Oauth: new_manager.sslErrors.connect(lambda reply, errors: self.handleSslErrors(reply, errors)) self.auth_view.page().setNetworkAccessManager(new_manager) self.auth_view.show() - + print url self.auth_view.load_url(url) return False @@ -329,25 +329,29 @@ class FindEntity(QtGui.QDialog): class NewPost(Helper.RestorableWindow): - def __init__(self, app): + def __init__(self, app, string, mentions, is_private): self.app = app + self.string = string + self.mentions = mentions + self.is_private = is_private + Helper.RestorableWindow.__init__(self, "newpost", self.app) + self.activateWindow() + self.raise_() self.setWindowIcon(QtGui.QIcon(self.app.resources_path() + "/images/Icon.png")) - self.textInput = QtGui.QPlainTextEdit(self) - self.setCentralWidget(self.textInput) - self.textInput.textChanged.connect(self.onChanged) + self.webView = Helper.WebViewCreator(self.app, True, self) + self.webView.load_local(self.load_finished) + self.setCentralWidget(self.webView) + + self.initUI() + + self.webView.triggerPageAction(QtWebKit.QWebPage.InspectElement) self.setWindowTitle("New Post") self.resize(300, 150) self.setMinimumSize(100, 100) - self.initUI() - - self.setIsPrivate(False) - self.status_id = None - self.reply_to_entity = None - self.imageFilePath = None def initUI(self): newPostAction = QtGui.QAction("&New Post", self) @@ -396,69 +400,29 @@ class NewPost(Helper.RestorableWindow): aboutAction.setStatusTip("Open about page in Webbrowser") aboutAction.triggered.connect(self.app.open_about) + developerExtrasAction = QtGui.QAction("&Developer Extras", self) + developerExtrasAction.setStatusTip("Activate webkit inspector") + developerExtrasAction.triggered.connect(self.developer_extras) + helpMenu = menubar.addMenu("&Help") helpMenu.addAction(aboutAction) + helpMenu.addAction(developerExtrasAction) - self.statusBar().showMessage('256') + def load_finished(self, widget): + is_private = "false" + if self.is_private: + is_private = "true" - self.addButton = QtGui.QToolButton() - self.addButton.setToolTip("Add photo") - self.addButton.clicked.connect(self.openFileDialog) - self.addButton.setAutoRaise(True) - #addIcon = QtGui.QIcon.fromTheme("insert-image", QtGui.QIcon(self.app.resources_path() + "/images/Actions-insert-image-icon.png")) - addIcon = QtGui.QIcon(self.app.resources_path() + "/images/glyphicons_138_picture.png") - self.addButton.setIcon(addIcon) - self.statusBar().addPermanentWidget(self.addButton) + callback = "function() { bungloo.newpost.setString('%s'); bungloo.newpost.setIsPrivate(%s); bungloo.newpost.setMentions(%s);}" % (self.string, is_private, self.mentions) - self.isPrivateButton = QtGui.QToolButton() - self.isPrivateButton.setToolTip("Make private") - self.isPrivateButton.clicked.connect(self.toggleIsPrivate) - self.isPrivateButton.setAutoRaise(True) - #self.isPrivateIcon = QtGui.QIcon(self.app.resources_path() + "/images/Lock-Lock-icon.png") - self.isPrivateIcon = QtGui.QIcon(self.app.resources_path() + "/images/glyphicons_203_lock.png") - #self.isNotPrivateIcon = QtGui.QIcon(self.app.resources_path() + "/images/Lock-Unlock-icon.png") - self.isNotPrivateIcon = QtGui.QIcon(self.app.resources_path() + "/images/glyphicons_204_unlock.png") - self.isPrivateButton.setIcon(self.isNotPrivateIcon) - self.statusBar().addPermanentWidget(self.isPrivateButton) - - self.sendButton = QtGui.QToolButton() - self.sendButton.setToolTip("Send") - self.sendButton.clicked.connect(self.sendMessage) - self.sendButton.setAutoRaise(True) - #sendIcon = QtGui.QIcon.fromTheme("mail-send", QtGui.QIcon(self.app.resources_path() + "/images/send-icon.png")) - sendIcon = QtGui.QIcon(self.app.resources_path() + "/images/glyphicons_123_message_out.png") - self.sendButton.setIcon(sendIcon) - self.statusBar().addPermanentWidget(self.sendButton) - - def setIsPrivate(self, is_private): - self.isPrivate = is_private - icon = self.isNotPrivateIcon - if self.isPrivate: - icon = self.isPrivateIcon - - self.isPrivateButton.setIcon(icon) + script = "function HostAppGo() { start('newpost', " + callback + "); }" + self.webView.page().mainFrame().evaluateJavaScript(script) + self.webView.setFocus() def toggleIsPrivate(self): - self.setIsPrivate(not self.isPrivate) - - def setString(self, string): - self.inReplyToStatusIdWithString(None, None, string) - - def inReplyToStatusIdWithString(self, reply_to, status_id, string): - self.reply_to_entity = reply_to - self.status_id = status_id - self.textInput.setPlainText(string) - - cursor = self.textInput.textCursor() - cursor.movePosition(QtGui.QTextCursor.End, QtGui.QTextCursor.MoveAnchor) - cursor.movePosition(QtGui.QTextCursor.Start, QtGui.QTextCursor.KeepAnchor) - cursor.movePosition(QtGui.QTextCursor.EndOfLine, QtGui.QTextCursor.KeepAnchor) - self.textInput.setTextCursor(cursor) - - def onChanged(self): - count = 256 - len(self.textInput.toPlainText()) - self.statusBar().showMessage(str(count)) + script = "bungloo.newpost.toggleIsPrivate();" + self.webView.page().mainFrame().evaluateJavaScript(script) def sendMessage(self): count = len(self.textInput.toPlainText()) @@ -482,3 +446,7 @@ class NewPost(Helper.RestorableWindow): else: self.imageFilePath = None + def developer_extras(self, widget): + QtWebKit.QWebSettings.globalSettings().setAttribute(QtWebKit.QWebSettings.DeveloperExtrasEnabled, True) + + diff --git a/WebKit/css/default.css b/WebKit/css/default.css index ff8bbfd..63bd2e8 100644 --- a/WebKit/css/default.css +++ b/WebKit/css/default.css @@ -446,4 +446,18 @@ form.search input { p.noresult { padding : 10px; text-align : center; -} \ No newline at end of file +} + +.new_post #sidebar, .new_post #content { display: none; } +.new_post { height: 100%; } +#new_post_container { position: absolute; border-collapse: collapse; height: 100%; width: 100%; } +#new_post_container td { position: relative; height: 90%; } +#new_post_container .text td { background: white; } +#new_post_container textarea { resize: none; box-sizing: border-box; position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0; background: transparent; outline: none; } +#new_post_container div { box-sizing: border-box; position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0; background: white; color: white; padding: 2px; } + +#new_post_container div span { background: #D8DFEA; } +#suggestions { position: absolute; left: 0; bottom: 0; } +#suggestions .active { color: red; } +#status_bar { height: 1em; } +#status_bar p { float: right; } \ No newline at end of file diff --git a/WebKit/scripts/controller/NewPost.js b/WebKit/scripts/controller/NewPost.js new file mode 100644 index 0000000..113c58c --- /dev/null +++ b/WebKit/scripts/controller/NewPost.js @@ -0,0 +1,197 @@ +define([ +], + +function() { + + function NewPost() { + + this.entities = JSON.parse(controller.getCachedEntities()); + this.mentions = []; + this.is_private = false; + document.body.className = "new_post"; + + // Textarea + + this.container = $("
"); + this.textarea = this.container.find("textarea"); + this.highlighter = this.container.find("div"); + + $(document.body).append(this.container); + + this.textarea.keyup(this.keyup.bind(this)); + this.textarea.keydown(this.keydown.bind(this)); + + this.suggestions = $("
    "); + + $(document.body).append(this.suggestions); + + // Status bar + this.counter = $("256"); + var buttons = $( + "

    " + + "" + + "" + + "" + + "

    "); + + this.buttons = { + images: buttons.find("#images"), + is_private: buttons.find("#private"), + send: buttons.find("#send") + } + + //this.buttons.images.bind("click", this.addImage.bind(this)); + //this.buttons.is_private.bind("click", this.togglePrivate.bind(this)); + this.buttons.send.bind("click", this.send.bind(this)); + + this.container.find("#status_bar").append(this.counter); + this.container.find("#status_bar").append(buttons); + + this.textarea.focus() + } + + NewPost.prototype.setString = function(string) { + this.textarea.val(string); + } + + NewPost.prototype.setMentions = function(mentions) { + + if(mentions && mentions.length > 0) { + var mentions_string = " "; + for (var i = 0; i < mentions.length; i++) { + mentions_string += mentions[i].name + " "; + } + + this.textarea.val(this.textarea.val() + " " + mentions_string); + this.mentions = mentions; + } + this.keyup(); + } + + NewPost.prototype.setIsPrivate = function(is_private) { + this.is_private = is_private; + } + + NewPost.prototype.toggleIsPrivate = function() { + this.is_private = !this.is_private; + }; + + NewPost.prototype.keyup = function(e) { + if(!e) return; + + var key = e.which; + if(key != 38 && key != 40 && key != 13) { + + this.applyText($(this.textarea).val()); + + } else { + + var lis = this.suggestions.find("li"); + + if (lis.length > 0) { + e.preventDefault(); + var active = this.suggestions.find(".active"); + if(key == 38) { // up + var prev = active.prev(); + if(active.lentgh == 0) { + lis.last().addClass("active"); + } else if(prev) { + active.removeClass("active"); + prev.addClass("active"); + } + } else if(key == 40) { // down + var next = active.next(); + if(active.length == 0) { + lis.first().addClass("active"); + } else if(next) { + active.removeClass("active"); + next.addClass("active"); + } + } else if(key == 13) { // enter + if(active.length > 0) { + this.replaceWithName(this.textarea.val(), this.suggestions.find("li.active").get(0).item); + } + } + } + } + } + + NewPost.prototype.keydown = function(e) { + var key = e.which; + var lis = this.suggestions.find("li"); + if(lis.length > 0 && (key == 38 || key == 40 || key == 13)) { + e.preventDefault(); + } + } + + NewPost.prototype.replaceAll = function(txt, replace, with_this) { + return txt.replace(new RegExp(replace, 'g'),with_this); + } + + NewPost.prototype.replaceWithName = function(txt, with_item) { + var words = txt.match(/(^|\s)\^([^\s]+)/); + var replace = words[2]; + + var original = txt.replace("^" + replace, with_item.name); + this.textarea.val(original); + + this.mentions.push(with_item); + + this.applyText(original); + } + + NewPost.prototype.applyText = function (text) { + var words = text.match(/(^|\s)\^([^\s]+)/); + this.suggestions.html(""); + + if(words) { + var name = words[2]; + for (var key in this.entities.length) { + var item = this.entities[key]; + if(item.name.toLowerCase().indexOf(name.toLowerCase()) != -1 || item.entity.toLowerCase().indexOf(name.toLowerCase()) != -1) { + var li = $("
  • " + item.name + " " + item.entity + "
  • ") + li.get(0).item = item; + this.suggestions.append(li) + } + } + } + + // parse the text: + // replace all the line braks by
    , and all the double spaces by the html version   + text = this.replaceAll(text,'\n','
    '); + text = this.replaceAll(text,' ','  '); + + // replace the words by a highlighted version of the words + + var remove = []; + + for (var i=0;i' + name + ''); + } else { + remove.push(this.mentions[i]); + } + } + + for (var i = 0; i < remove.length; i++) { + this.mentions.splice(this.mentions.indexOf(remove[i]), 1); + } + + // re-inject the processed text into the div + this.highlighter.html(text); + + var count = 256 - this.textarea.val().length + (this.mentions.length * 6); + this.counter.html(count) + + return true; + } + + NewPost.prototype.send = function() { + debug("Send not implemented yet"); + $("textarea").focus(); + } + + + return NewPost; +}) \ No newline at end of file diff --git a/WebKit/scripts/controller/Oauth.js b/WebKit/scripts/controller/Oauth.js index f020b5e..1adf8a9 100644 --- a/WebKit/scripts/controller/Oauth.js +++ b/WebKit/scripts/controller/Oauth.js @@ -14,7 +14,7 @@ function(HostApp, APICalls, Hmac) { "url": "http://jabs.nu/bungloo/", "description": "A desktop Tent client.", "redirect_uri": "bungloo://oauthtoken", - "post_types": { + "types": { "read": [ "https://tent.io/types/meta/v0", "https://tent.io/types/relationship/v0", @@ -87,12 +87,12 @@ function(HostApp, APICalls, Hmac) { Oauth.prototype.register = function (url) { var those = this; - debug(url) + APICalls.get(url, { no_auth: true, callback: function(resp) { - those.profile = JSON.parse(resp.responseText); + those.profile = JSON.parse(resp.responseText).post; those.entity = those.profile.content.entity; HostApp.setStringForKey(those.entity, "entity") HostApp.setServerUrls(those.profile.content.servers[0].urls); @@ -101,19 +101,19 @@ function(HostApp, APICalls, Hmac) { content_type: "https://tent.io/types/app/v0#", no_auth: true, callback: function(resp) { + var app_id = JSON.parse(resp.responseText).post.id; + var header_string = resp.getAllResponseHeaders(); + var regexp = /https:\/\/tent.io\/rels\/credentials/i + var url = APICalls.parseHeaderForLink(header_string, regexp); - var app_id = JSON.parse(resp.responseText).id; - var header_string = resp.getAllResponseHeaders(); - var regexp = /https:\/\/tent.io\/rels\/credentials/i - var url = APICalls.parseHeaderForLink(header_string, regexp); - - APICalls.get(url, { - content_type: "https://tent.io/types/app/v0#", - no_auth: true, - callback: function(resp) { - var data = JSON.parse(resp.responseText); - those.authRequest(data, app_id); - }}); + APICalls.get(url, { + content_type: "https://tent.io/types/app/v0#", + no_auth: true, + callback: function(resp) { + var data = JSON.parse(resp.responseText); + those.authRequest(data.post, app_id); + } + }); }}); }}); @@ -150,8 +150,7 @@ function(HostApp, APICalls, Hmac) { url, "POST", HostApp.stringForKey("app_hawk_id"), - HostApp.stringForKey("app_hawk_key"), - requestBody + HostApp.stringForKey("app_hawk_key") ); APICalls.post(url, requestBody, { diff --git a/WebKit/scripts/controller/Profile.js b/WebKit/scripts/controller/Profile.js index 6058784..94dcb7a 100644 --- a/WebKit/scripts/controller/Profile.js +++ b/WebKit/scripts/controller/Profile.js @@ -24,7 +24,7 @@ function(HostApp, Core, APICalls, URI) { this.hide(); var _this = this; - setTimeout(function() { _this.showProfileForEntity() }, 5000); // Load users profile on start + setTimeout(function() { _this.showProfileForEntity() }, 500); // Load users profile on start } Profile.prototype = Object.create(Core.prototype); @@ -239,20 +239,14 @@ function(HostApp, Core, APICalls, URI) { this.profile = profile; } else { - APICalls.findProfileURL(this.entity, function(profile_url) { - - if (profile_url) { - - APICalls.http_call(profile_url, "GET", function(resp) { - - profile = JSON.parse(resp.responseText); - _this.showProfile(profile); - _this.profile = profile; - - }, null, false); // do not send auth-headers - } - }); - + var url = HostApp.serverUrl("posts_feed") + "?types=" + encodeURIComponent("https://tent.io/types/meta/v0") + "&entities=" + encodeURIComponent(this.entity) + debug(url) + APICalls.get(url, { + callback: function(resp) { + profile = JSON.parse(resp.responseText); + _this.showProfile(profile); + _this.profile = profile; + }}); } } @@ -278,6 +272,9 @@ function(HostApp, Core, APICalls, URI) { Profile.prototype.showProfile = function(profile) { + debug(profile) + return + var basic = profile["https://tent.io/types/info/basic/v0.1.0"]; if (profile && basic) { diff --git a/WebKit/scripts/helper/Core.js b/WebKit/scripts/helper/Core.js index 802ca7a..77ea169 100644 --- a/WebKit/scripts/helper/Core.js +++ b/WebKit/scripts/helper/Core.js @@ -212,7 +212,8 @@ function(jQuery, APICalls, URI, HostApp, Cache) { template.reply_to.onclick = function() { var mentions = []; - var status_mentions = status.mentions.slice(0); + var status_mentions = []; + if(status.mentions) status_mentions = status.mentions.slice(0); if (typeof status.__repost != "undefined") { status_mentions.push({entity:status.__repost.entity}); @@ -507,10 +508,13 @@ function(jQuery, APICalls, URI, HostApp, Cache) { var url = URI(HostApp.serverUrl("new_post")); - var http_method = "POST"; + var type = in_reply_to_status_id.length == 0 ? "https://tent.io/types/status/v0#" : "https://tent.io/types/status/v0#reply"; + debug(typeof in_reply_to_status_id) + debug(in_reply_to_status_id.length) + debug(type) var data = { - "type": in_reply_to_status_id ? "https://tent.io/types/status/v0#" : "https://tent.io/types/status/v0#reply", + "type": type, "published_at": parseInt(new Date().getTime(), 10), "permissions": { "public": !is_private @@ -521,7 +525,7 @@ function(jQuery, APICalls, URI, HostApp, Cache) { }; if (location) { - data["content"]["location"] = { "type": "Point", "coordinates": location } + //data["content"]["location"] = { "type": "Point", "coordinates": location } } var mentions = this.parseMentions(content, in_reply_to_status_id, in_reply_to_entity); @@ -1041,7 +1045,6 @@ function(jQuery, APICalls, URI, HostApp, Cache) { } - return Core; }); \ No newline at end of file diff --git a/WebKit/scripts/main.js b/WebKit/scripts/main.js index 7e30518..f823148 100644 --- a/WebKit/scripts/main.js +++ b/WebKit/scripts/main.js @@ -7,7 +7,8 @@ var bungloo = { entityProfile: null, conversation: null, search: null, - cache: {} + cache: {}, + newpost: null }; requirejs.config({ @@ -33,6 +34,15 @@ function start(view, callback) { }); + } else if (view == "newpost") { + + require(["controller/NewPost"], function(NewPost) { + + bungloo.newpost = new NewPost(); + if(callback) callback(); + + }); + } else { @@ -55,6 +65,19 @@ function start(view, callback) { bungloo.sidebar.showContentForTimeline(); + bungloo.cache.entities = { + "https://jeena.net" : { + name: "Jeena", + entity: "https://jeena.net", + avatar: "https://jeena.net/avatar.png" + }, + "https://ck.kennt-wayne.de": { + name: "Christian", + entity: "http://ck.kennt-wayne.de", + avatar: "http://ck.kennt-wayne.de/pavatar.png" + } + }; + }); } From 3fff224924e8e5c834d843a328d0f056f00b618c Mon Sep 17 00:00:00 2001 From: jeena Date: Tue, 9 Jul 2013 19:41:44 +0200 Subject: [PATCH 05/18] fixed content-type for oauth --- WebKit/scripts/controller/Oauth.js | 6 ++---- WebKit/scripts/controller/Profile.js | 4 ++-- WebKit/scripts/helper/APICalls.js | 7 ++++++- WebKit/scripts/helper/Paths.js | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/WebKit/scripts/controller/Oauth.js b/WebKit/scripts/controller/Oauth.js index 1adf8a9..f556117 100644 --- a/WebKit/scripts/controller/Oauth.js +++ b/WebKit/scripts/controller/Oauth.js @@ -142,7 +142,7 @@ function(HostApp, APICalls, Hmac) { var requestBody = JSON.stringify({ 'code' : urlVars["code"], - 'token_type' : "https://tent.io/oauth/hawk-token" + 'token_type': "https://tent.io/oauth/hawk-token" }); var those = this; @@ -154,7 +154,7 @@ function(HostApp, APICalls, Hmac) { ); APICalls.post(url, requestBody, { - content_type: "https://tent.io/types/app/v0#", + content_type: "application/json", auth_header: auth_header, callback: function(resp) { those.requestAccessTokenTicketFinished(resp.responseText); @@ -170,7 +170,6 @@ function(HostApp, APICalls, Hmac) { Oauth.prototype.requestAccessTokenTicketFinished = function(responseBody) { var access = JSON.parse(responseBody); - debug(access) HostApp.setStringForKey(access["access_token"], "user_access_token"); HostApp.setSecret(access["hawk_key"]); @@ -178,7 +177,6 @@ function(HostApp, APICalls, Hmac) { HostApp.setStringForKey(access["token_type"], "user_token_type"); HostApp.loggedIn(); - debug("loggedIn") } Oauth.prototype.logout = function() { diff --git a/WebKit/scripts/controller/Profile.js b/WebKit/scripts/controller/Profile.js index 94dcb7a..d57b605 100644 --- a/WebKit/scripts/controller/Profile.js +++ b/WebKit/scripts/controller/Profile.js @@ -240,7 +240,7 @@ function(HostApp, Core, APICalls, URI) { } else { var url = HostApp.serverUrl("posts_feed") + "?types=" + encodeURIComponent("https://tent.io/types/meta/v0") + "&entities=" + encodeURIComponent(this.entity) - debug(url) + APICalls.get(url, { callback: function(resp) { profile = JSON.parse(resp.responseText); @@ -272,7 +272,7 @@ function(HostApp, Core, APICalls, URI) { Profile.prototype.showProfile = function(profile) { - debug(profile) + //debug(profile) return var basic = profile["https://tent.io/types/info/basic/v0.1.0"]; diff --git a/WebKit/scripts/helper/APICalls.js b/WebKit/scripts/helper/APICalls.js index dd942de..64341b1 100644 --- a/WebKit/scripts/helper/APICalls.js +++ b/WebKit/scripts/helper/APICalls.js @@ -36,7 +36,12 @@ function(jQuery, HostApp, Hmac, Cache) { console.error("No content type for " + options.url); return; } else { - content_type = "application/vnd.tent.post.v0+json; type=\"" + options.content_type + "\""; + if(options.content_type != "application/json") { + content_type = "application/vnd.tent.post.v0+json; type=\"" + options.content_type + "\""; + } else { + content_type = options.content_type; + } + } var settings = { diff --git a/WebKit/scripts/helper/Paths.js b/WebKit/scripts/helper/Paths.js index f6a703f..af1fb75 100644 --- a/WebKit/scripts/helper/Paths.js +++ b/WebKit/scripts/helper/Paths.js @@ -65,7 +65,7 @@ function(jQuery, HostApp, Hmac, Cache) { console.error("getURL (" + xhr.status + ")" + xhr.statusText + " " + http_method + " (" + url + "): '" + xhr.responseText + "'"); } } - debug(url) + jQuery.ajax(options); } From 16d7016e29a77562316d0f484e13a49f475680d0 Mon Sep 17 00:00:00 2001 From: jeena Date: Wed, 17 Jul 2013 00:44:47 +0200 Subject: [PATCH 06/18] fixing problems with new post --- Qt/Bungloo.py | 9 +- Qt/Windows.py | 15 +- WebKit/scripts/controller/NewPost.js | 133 ++- WebKit/scripts/controller/Oauth.js | 3 +- WebKit/scripts/controller/Profile.js | 1235 +++++++++++++------------ WebKit/scripts/controller/Timeline.js | 16 +- WebKit/scripts/helper/APICalls.js | 39 +- WebKit/scripts/helper/Core.js | 199 +--- WebKit/scripts/helper/HostApp.js | 7 +- WebKit/scripts/main.js | 2 +- 10 files changed, 851 insertions(+), 807 deletions(-) diff --git a/Qt/Bungloo.py b/Qt/Bungloo.py index e5eaf3e..a8ca0be 100755 --- a/Qt/Bungloo.py +++ b/Qt/Bungloo.py @@ -171,13 +171,12 @@ class Controller(QtCore.QObject): pass @QtCore.pyqtSlot(str) - def openNewMessageWidow(self, is_private=False, string=""): - string = str(string) - self.openNewMessageWindowInReplyTostatusIdwithStringIsPrivate(None, None, string, is_private) + def openNewMessageWidow(self): + self.openNewMessageWindowInReplyTostatus(None) @QtCore.pyqtSlot(str, str, str, bool) - def openNewMessageWindowInReplyTostatusIdwithStringIsPrivate(self, entity, status_id, string, is_private): - new_message_window = Windows.NewPost(self.app, string, "[]", is_private) + def openNewMessageWindowInReplyTostatus(self, status_string): + new_message_window = Windows.NewPost(self.app) new_message_window.show() new_message_window.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.app.new_message_windows.append(new_message_window) diff --git a/Qt/Windows.py b/Qt/Windows.py index 7317f56..fb7d332 100644 --- a/Qt/Windows.py +++ b/Qt/Windows.py @@ -329,11 +329,12 @@ class FindEntity(QtGui.QDialog): class NewPost(Helper.RestorableWindow): - def __init__(self, app, string, mentions, is_private): + def __init__(self, app, string=None, mentions="[]", is_private=False, post_id=None): self.app = app self.string = string self.mentions = mentions self.is_private = is_private + self.post_id = post_id Helper.RestorableWindow.__init__(self, "newpost", self.app) self.activateWindow() @@ -414,7 +415,11 @@ class NewPost(Helper.RestorableWindow): if self.is_private: is_private = "true" - callback = "function() { bungloo.newpost.setString('%s'); bungloo.newpost.setIsPrivate(%s); bungloo.newpost.setMentions(%s);}" % (self.string, is_private, self.mentions) + post_id = "" + if self.post_id: + post_id = self.post_id + + callback = "function() { bungloo.newpost.setString('%s'); bungloo.newpost.setIsPrivate(%s); bungloo.newpost.setMentions(%s); bungloo.newPostAction.setPostId(%s); }" % (self.string, is_private, self.mentions, post_id) script = "function HostAppGo() { start('newpost', " + callback + "); }" self.webView.page().mainFrame().evaluateJavaScript(script) @@ -425,6 +430,11 @@ class NewPost(Helper.RestorableWindow): self.webView.page().mainFrame().evaluateJavaScript(script) def sendMessage(self): + script = "bungloo.newpost.send()" + self.webView.page().mainFrame().evaluateJavaScript(script) + self.close() + + """ count = len(self.textInput.toPlainText()) if count > 0 and count <= 256: message = Helper.PostModel() @@ -438,6 +448,7 @@ class NewPost(Helper.RestorableWindow): self.close() else: QtGui.qApp.beep() + """ def openFileDialog(self): fileNamePath = QtGui.QFileDialog.getOpenFileName(self, "Choose a image", "", "Images (*.png *.gif *.jpg *.jpeg)") diff --git a/WebKit/scripts/controller/NewPost.js b/WebKit/scripts/controller/NewPost.js index 113c58c..e37fcce 100644 --- a/WebKit/scripts/controller/NewPost.js +++ b/WebKit/scripts/controller/NewPost.js @@ -29,7 +29,7 @@ function() { this.counter = $("256"); var buttons = $( "

    " + - "" + + //"" + "" + "" + "

    "); @@ -50,6 +50,12 @@ function() { this.textarea.focus() } + NewPost.prototype.setStatus = function(status_string) { + this.status = JSON.parse(status_string); + debug(this.status) + // FIXME set string, private, mentions, etc. + }; + NewPost.prototype.setString = function(string) { this.textarea.val(string); } @@ -190,8 +196,133 @@ function() { NewPost.prototype.send = function() { debug("Send not implemented yet"); $("textarea").focus(); + var count = 256 - this.textarea.val().length + (this.mentions.length * 6); + if(count >= 0) { + this.sentNewMessage(); + } else { + debug("BEEP"); + } } + NewPost.prototype.sendNewMessage = function() { + + var content = this.textarea.val(); + + var url = URI(HostApp.serverUrl("new_post")); + + var type = in_reply_to_status_id.length == 0 ? "https://tent.io/types/status/v0#" : "https://tent.io/types/status/v0#reply"; + + var data = { + "type": type, + "published_at": parseInt(new Date().getTime(), 10), + "permissions": { + "public": !is_private + }, + "content": { + "text": content, + }, + }; + + if (location) { + //data["content"]["location"] = { "type": "Point", "coordinates": location } + } + + var mentions = this.parseMentions(content, in_reply_to_status_id, in_reply_to_entity); + + if (mentions.length > 0) { + data["mentions"] = mentions; + if (is_private) { + var entities = {}; + for (var i = 0; i < mentions.length; i++) { + var entity = mentions[i]["entity"] + entities[entity] = true; + }; + + data["permissions"]["entities"] = entities; + } + } + + // APICalls.http_call(url.toString(), http_method, callback, JSON.stringify(data)); + APICalls.post(url.toString(), JSON.stringify(data), { + content_type: data.type, + callback: callback + }); + } +/* + NewPost.prototype.sendNewMessageWithImage = function(content, in_reply_to_status_id, in_reply_to_entity, location, image_data_uri, is_private, callback) { + + var url = URI(APICalls.mkApiRootPath("/posts")); + + var data = { + "type": "https://tent.io/types/post/photo/v0.1.0", + "published_at": parseInt(new Date().getTime() / 1000, 10), + "permissions": { + "public": !is_private + }, + "content": { + "caption": content, + }, + }; + + if (location) { + data["content"]["location"] = { "type": "Point", "coordinates": location } + } + + var mentions = this.parseMentions(content, in_reply_to_status_id, in_reply_to_entity); + if (mentions.length > 0) { + data["mentions"] = mentions; + if (is_private) { + var entities = {}; + for (var i = 0; i < mentions.length; i++) { + var entity = mentions[i]["entity"] + entities[entity] = true; + }; + + data["permissions"]["entities"] = entities; + } + } + + var data_string = JSON.stringify(data); + + var boundary = "TentAttachment----------TentAttachment"; + var post = "--" + boundary + "\r\n"; + + post += 'Content-Disposition: form-data; name="post"; filename="post.json"\r\n'; + post += 'Content-Length: ' + data_string.length + '\r\n'; + post += 'Content-Type: application/vnd.tent.v0+json\r\n'; + post += 'Content-Transfer-Encoding: binary\r\n\r\n'; + post += data_string; + + post += "\r\n--" + boundary + "\r\n"; + + var blob_string = image_data_uri.split(',')[1]; + var mime_type = image_data_uri.split(',')[0].split(':')[1].split(';')[0]; + var ext = "png"; + if (mime_type == "image/jpeg") { + ext = "jpeg"; + } else if (mime_type == "image/gif") { + ext = "gif"; + } + + + post += 'Content-Disposition: form-data; name="photos[0]"; filename="photo.' + ext + '"\r\n'; + post += 'Content-Length: ' + blob_string.length + "\r\n"; + post += 'Content-Type: ' + mime_type + "\r\n"; + post += 'Content-Transfer-Encoding: base64\r\n\r\n'; + post += blob_string; + post += "\r\n--" + boundary + "--\r\n"; + + var newCallback = function(resp) { + if (resp.status == 403) { + var err = JSON.parse(resp.responseText); + HostApp.alertTitleWithMessage(resp.statusText, err.error); + } + callback(resp); + } + + APICalls.postMultipart(url.toString(), newCallback, post, boundary); + } +*/ return NewPost; }) \ No newline at end of file diff --git a/WebKit/scripts/controller/Oauth.js b/WebKit/scripts/controller/Oauth.js index f556117..69e1b41 100644 --- a/WebKit/scripts/controller/Oauth.js +++ b/WebKit/scripts/controller/Oauth.js @@ -96,7 +96,6 @@ function(HostApp, APICalls, Hmac) { those.entity = those.profile.content.entity; HostApp.setStringForKey(those.entity, "entity") HostApp.setServerUrls(those.profile.content.servers[0].urls); - APICalls.post(HostApp.serverUrl("new_post"), JSON.stringify(those.app_info), { content_type: "https://tent.io/types/app/v0#", no_auth: true, @@ -112,7 +111,7 @@ function(HostApp, APICalls, Hmac) { callback: function(resp) { var data = JSON.parse(resp.responseText); those.authRequest(data.post, app_id); - } + } }); }}); diff --git a/WebKit/scripts/controller/Profile.js b/WebKit/scripts/controller/Profile.js index d57b605..febc78c 100644 --- a/WebKit/scripts/controller/Profile.js +++ b/WebKit/scripts/controller/Profile.js @@ -1,664 +1,703 @@ define([ - "helper/HostApp", - "helper/Core", - "helper/APICalls", - "lib/URI" + "helper/HostApp", + "helper/Core", + "helper/APICalls", + "lib/URI" ], function(HostApp, Core, APICalls, URI) { - function Profile() { - - Core.call(this); - - this.action = "profile"; - - this.posts_limit = 25; - - this.container = document.createElement("div"); - this.container.className = this.action; - document.getElementById("content").appendChild(this.container); - - this.initProfileTemplate(); - this.hide(); + function Profile() { + + Core.call(this); + + this.action = "profile"; + + this.posts_limit = 25; + + this.container = document.createElement("div"); + this.container.className = this.action; + document.getElementById("content").appendChild(this.container); + + this.initProfileTemplate(); + this.hide(); - var _this = this; - setTimeout(function() { _this.showProfileForEntity() }, 500); // Load users profile on start - } + var _this = this; + setTimeout(function() { _this.showProfileForEntity() }, 500); // Load users profile on start + } - Profile.prototype = Object.create(Core.prototype); - - - Profile.prototype.show = function() { - Core.prototype.show.call(this, this.container); - } - - Profile.prototype.hide = function() { - Core.prototype.hide.call(this, this.container); - } - - Profile.prototype.logout = function() { - this.container = ""; - } - - Profile.prototype.showList = function(list) { - $(this.body).hide(); - $(this.followingsBody).hide(); - $(this.followersBody).hide(); - $(list).show(); - }; - - Profile.prototype.showProfileForEntity = function(entity) { - - if (!entity) { - entity = HostApp.stringForKey("entity"); - }; - - this.clear(); - this.entity = entity; - this.following = null; - this.following_id = null; - this.profile_template.entity.innerHTML = this.entity; - this.profile_template.entity.href = this.entity; - - this.getProfile(); - this.getFollowing(); - } - - Profile.prototype.initProfileTemplate = function() { - - var _this = this; - - var header = document.createElement("header"); - header.className = "profile"; - - this.container.appendChild(header); - - this.profile_template = { - avatar: document.createElement("img"), - name: document.createElement("h1"), - entity: document.createElement("a"), - bio: document.createElement("p"), - relationships: document.createElement("td"), - posts: document.createElement("a"), - following: document.createElement("a"), - followed: document.createElement("a"), - birthdate: document.createElement("td"), - location: document.createElement("td"), - gender: document.createElement("td"), - url: document.createElement("a"), - following_button: document.createElement("button"), - mention_button: document.createElement("button") - }; + Profile.prototype = Object.create(Core.prototype); + + + Profile.prototype.show = function() { + Core.prototype.show.call(this, this.container); + } + + Profile.prototype.hide = function() { + Core.prototype.hide.call(this, this.container); + } + + Profile.prototype.logout = function() { + this.container = ""; + } + + Profile.prototype.showList = function(list) { + $(this.body).hide(); + $(this.followingsBody).hide(); + $(this.followersBody).hide(); + $(list).show(); + }; + + Profile.prototype.showProfileForEntity = function(entity) { + + if (!entity) { + entity = HostApp.stringForKey("entity"); + }; + + this.clear(); + this.entity = entity; + this.following = null; + this.following_id = null; + this.profile_template.entity.innerHTML = this.entity; + this.profile_template.entity.href = this.entity; + + this.getProfile(); + this.getFollowing(); + } + + Profile.prototype.initProfileTemplate = function() { + + var _this = this; + + var header = document.createElement("header"); + header.className = "profile"; + + this.container.appendChild(header); + + this.profile_template = { + avatar: document.createElement("img"), + name: document.createElement("h1"), + entity: document.createElement("a"), + bio: document.createElement("p"), + relationships: document.createElement("td"), + posts: document.createElement("a"), + following: document.createElement("a"), + followed: document.createElement("a"), + birthdate: document.createElement("td"), + location: document.createElement("td"), + gender: document.createElement("td"), + url: document.createElement("a"), + following_button: document.createElement("button"), + mention_button: document.createElement("button") + }; - header.appendChild(this.profile_template.avatar); - this.profile_template.avatar.src = "img/default-avatar.png"; + header.appendChild(this.profile_template.avatar); + this.profile_template.avatar.src = "img/default-avatar.png"; - var div = document.createElement("div"); - header.appendChild(div); - - this.profile_template.following_button.onclick = function(e) { - _this.toggleFollow() - } - div.appendChild(this.profile_template.following_button); - - this.profile_template.mention_button.onclick = function() { - var e = _this.entity; - if (e.startsWith("https://")) { - e = e.substr(8, e.length); - } - HostApp.openNewMessageWidow(null, null, "^" + e + " ", false); - } - div.appendChild(this.profile_template.mention_button); - this.profile_template.mention_button.innerHTML = "Mention"; - - div.appendChild(this.profile_template.name); - - var p = document.createElement("p"); - p.appendChild(this.profile_template.entity); - div.appendChild(p); - - div.appendChild(this.profile_template.bio); - - var table = document.createElement("table"); - div.appendChild(table); - - function mkLi(name, template) { - var tr = document.createElement("tr"); - var th = document.createElement("th"); - tr.style.display = "none"; - th.innerText = name + ": "; - tr.appendChild(th); - tr.appendChild(template); - table.appendChild(tr); - } - - mkLi("Birth date", this.profile_template.birthdate); - mkLi("Location", this.profile_template.location); - mkLi("Gender", this.profile_template.gender); - - var td = document.createElement("td"); - td.appendChild(this.profile_template.url); - mkLi("Homepage", td); - - mkLi("Relationships", this.profile_template.relationships); - - td = document.createElement("td"); - td.appendChild(this.profile_template.posts); - this.profile_template.posts.href = "#"; - this.profile_template.posts.onclick = function() { _this.showPosts(); return false; }; - mkLi("Posts", td); - - td = document.createElement("td"); - td.appendChild(this.profile_template.following); - this.profile_template.following.href = "#"; - this.profile_template.following.onclick = function() { _this.showFollowings(); return false; }; - mkLi("Following", td); - - td = document.createElement("td"); - td.appendChild(this.profile_template.followed); - this.profile_template.followed.href = "#"; - this.profile_template.followed.onclick = function() { _this.showFollowers(); return false; }; - mkLi("Followed by", td); - - - this.body = document.createElement("ol"); - this.body.className = this.action; - this.container.appendChild(this.body); - - this.followingsBody = document.createElement("ol"); - this.followingsBody.className = this.action + " followings"; - this.container.appendChild(this.followingsBody); - - this.followersBody = document.createElement("ol"); - this.followersBody.className = this.action + " folloewds"; - this.container.appendChild(this.followersBody); - - } - - Profile.prototype.clear = function() { - - this.server = null; - this.before = {id: null, entity: null, loading: false}; - - - this.profile_template.avatar.src = "img/default-avatar.png"; - - this.relationships = { - following_you: false, - followed_by_you: false, - it_is_you: false - } - - this.profile_template.name.innerText = ""; - this.profile_template.entity.innerText = ""; - this.profile_template.bio.innerText = ""; - this.profile_template.relationships.innerText = ""; - this.profile_template.posts.innerText = ""; - this.profile_template.following.innerText = ""; - this.profile_template.followed.innerText = ""; - this.profile_template.birthdate.innerText = ""; - this.profile_template.location.innerText = ""; - this.profile_template.gender.innerText = ""; - this.profile_template.url.innerText = ""; - this.profile_template.url.href = ""; - - this.profile_template.posts.parentNode.parentNode.style.display = "none"; - this.profile_template.following.parentNode.parentNode.style.display = "none"; - this.profile_template.followed.parentNode.parentNode.style.display = "none"; - this.profile_template.birthdate.parentNode.style.display = "none"; - this.profile_template.location.parentNode.style.display = "none"; - this.profile_template.gender.parentNode.style.display = "none"; - this.profile_template.url.parentNode.parentNode.style.display = "none"; - - this.profile_template.following_button.style.display = ""; - this.setFollowingButton(false); - - this.body.innerHTML = ""; - this.followingsBody.innerHTML = ""; - this.followersBody.innerHTML = ""; - - this.showList(this.body); - }; - - Profile.prototype.getProfile = function() { - - var _this = this; - - if (HostApp.stringForKey("entity") == this.entity) { - this.relationships.it_is_you = true; - this.profile_template.following_button.style.display = "none"; - } - - var profile = this.cache.profiles.getItem(this.entity); - - if (profile && profile != "null") { - - this.showProfile(profile); - this.profile = profile; - - } else { - var url = HostApp.serverUrl("posts_feed") + "?types=" + encodeURIComponent("https://tent.io/types/meta/v0") + "&entities=" + encodeURIComponent(this.entity) - - APICalls.get(url, { - callback: function(resp) { - profile = JSON.parse(resp.responseText); - _this.showProfile(profile); - _this.profile = profile; - }}); - } - } - - Profile.prototype.getFollowing = function() { - if(this.entity != HostApp.stringForKey("entity")) { - var url = APICalls.mkApiRootPath("/followings") + "/" + encodeURIComponent(this.entity); - var _this = this; - APICalls.http_call(url, "GET", function(resp) { - if (resp.status >= 200 && resp.status < 400) { - var following = JSON.parse(resp.responseText); - _this.following_id = following.id - _this.setFollowingButton(true); - } else { - _this.setFollowingButton(false); - _this.following_id = null; - } - }) - } else { - this.setFollowingButton(false); - this.following_id = null; - } - } - - Profile.prototype.showProfile = function(profile) { - - //debug(profile) - return - - var basic = profile["https://tent.io/types/info/basic/v0.1.0"]; - - if (profile && basic) { - - if(basic.avatar_url) { - this.profile_template.avatar.onerror = function() { this.profile_template.avatar.src = 'img/default-avatar.png' }; - this.profile_template.avatar.src = basic.avatar_url; - } - - this.populate(this.profile_template.name, basic.name); - this.populate(this.profile_template.birthdate, basic.birthdate); - this.populate(this.profile_template.location, basic.location); - this.populate(this.profile_template.gender, basic.gender); - this.populate(this.profile_template.bio, basic.bio); - - if(basic.website_url) { - - var url = basic.website_url; - this.profile_template.url.innerText = url; - this.profile_template.url.parentNode.parentNode.style.display = ""; - - if (!url.startsWith("http")) { - url = "http://" + url; - } - - this.profile_template.url.href = url; - } - } - - if (profile) { - this.server = profile["https://tent.io/types/info/core/v0.1.0"]["servers"][0]; - this.getMeta(this.server); - this.getStatuses(this.server); - } - } - - Profile.prototype.populate = function(t, v) { - if (v) { - t.innerText = v; - t.parentNode.style.display = ""; - t.parentNode.parentNode.style.display = ""; - } - } + var div = document.createElement("div"); + header.appendChild(div); + + this.profile_template.following_button.onclick = function(e) { + _this.toggleFollow() + } + div.appendChild(this.profile_template.following_button); + + this.profile_template.mention_button.onclick = function() { + var e = _this.entity; + if (e.startsWith("https://")) { + e = e.substr(8, e.length); + } + HostApp.openNewMessageWidow(null, null, "^" + e + " ", false); + } + div.appendChild(this.profile_template.mention_button); + this.profile_template.mention_button.innerHTML = "Mention"; + + div.appendChild(this.profile_template.name); + + var p = document.createElement("p"); + p.appendChild(this.profile_template.entity); + div.appendChild(p); + + div.appendChild(this.profile_template.bio); + + var table = document.createElement("table"); + div.appendChild(table); + + function mkLi(name, template) { + var tr = document.createElement("tr"); + var th = document.createElement("th"); + tr.style.display = "none"; + th.innerText = name + ": "; + tr.appendChild(th); + tr.appendChild(template); + table.appendChild(tr); + } + + mkLi("Birth date", this.profile_template.birthdate); + mkLi("Location", this.profile_template.location); + mkLi("Gender", this.profile_template.gender); + + var td = document.createElement("td"); + td.appendChild(this.profile_template.url); + mkLi("Homepage", td); + + mkLi("Relationships", this.profile_template.relationships); + + td = document.createElement("td"); + td.appendChild(this.profile_template.posts); + this.profile_template.posts.href = "#"; + this.profile_template.posts.onclick = function() { _this.showPosts(); return false; }; + mkLi("Posts", td); + + td = document.createElement("td"); + td.appendChild(this.profile_template.following); + this.profile_template.following.href = "#"; + this.profile_template.following.onclick = function() { _this.showFollowings(); return false; }; + mkLi("Following", td); + + td = document.createElement("td"); + td.appendChild(this.profile_template.followed); + this.profile_template.followed.href = "#"; + this.profile_template.followed.onclick = function() { _this.showFollowers(); return false; }; + mkLi("Followed by", td); + + + this.body = document.createElement("ol"); + this.body.className = this.action; + this.container.appendChild(this.body); + + this.followingsBody = document.createElement("ol"); + this.followingsBody.className = this.action + " followings"; + this.container.appendChild(this.followingsBody); + + this.followersBody = document.createElement("ol"); + this.followersBody.className = this.action + " folloewds"; + this.container.appendChild(this.followersBody); + + } + + Profile.prototype.clear = function() { + + this.server = null; + this.before = {id: null, entity: null, loading: false}; + + + this.profile_template.avatar.src = "img/default-avatar.png"; + + this.relationships = { + following_you: false, + followed_by_you: false, + it_is_you: false + } + + this.profile_template.name.innerText = ""; + this.profile_template.entity.innerText = ""; + this.profile_template.bio.innerText = ""; + this.profile_template.relationships.innerText = ""; + this.profile_template.posts.innerText = ""; + this.profile_template.following.innerText = ""; + this.profile_template.followed.innerText = ""; + this.profile_template.birthdate.innerText = ""; + this.profile_template.location.innerText = ""; + this.profile_template.gender.innerText = ""; + this.profile_template.url.innerText = ""; + this.profile_template.url.href = ""; + + this.profile_template.posts.parentNode.parentNode.style.display = "none"; + this.profile_template.following.parentNode.parentNode.style.display = "none"; + this.profile_template.followed.parentNode.parentNode.style.display = "none"; + this.profile_template.birthdate.parentNode.style.display = "none"; + this.profile_template.location.parentNode.style.display = "none"; + this.profile_template.gender.parentNode.style.display = "none"; + this.profile_template.url.parentNode.parentNode.style.display = "none"; + + this.profile_template.following_button.style.display = ""; + this.setFollowingButton(false); + + this.body.innerHTML = ""; + this.followingsBody.innerHTML = ""; + this.followersBody.innerHTML = ""; + + this.showList(this.body); + }; + + Profile.prototype.getProfile = function() { + + var _this = this; + + if (HostApp.stringForKey("entity") == this.entity) { + this.relationships.it_is_you = true; + this.profile_template.following_button.style.display = "none"; + } + + var url = HostApp.serverUrl("posts_feed") + "?types=" + encodeURIComponent("https://tent.io/types/meta/v0") + "&entities=" + encodeURIComponent(this.entity) + //var url = HostApp.serverUrl("discover").replace(/{entity}/, encodeURIComponent(this.entity)); + APICalls.get(url, { + callback: function(resp) { + var profile = JSON.parse(resp.responseText); + _this.showProfile(profile); + _this.profile = profile; + }}); + } + + Profile.prototype.getFollowing = function() { + if(this.entity != HostApp.stringForKey("entity")) { + + var url = HostApp.serverUrl("posts_feed") + "?mentions=" + encodeURIComponent(this.entity) + "&types=" + encodeURIComponent("https://tent.io/types/subscription/v0#https://tent.io/types/status/v0"); + var _this = this; + + APICalls.head(url, {callback: function(resp) { + + var count = APICalls.getCount(resp); + + if (count > 0) { + _this.setFollowingButton(true); + } else { + _this.setFollowingButton(false); + } - Profile.prototype.getMeta = function(root_url) { + }}); - var _this = this; - APICalls.http_call(URI(root_url + "/followings/count").toString(), "GET", function(resp) { + } else { - _this.populate(_this.profile_template.following, resp.responseText); - }, null, false); + this.setFollowingButton(false); + this.following_id = null; + } + } - APICalls.http_call(URI(root_url + "/followers/count").toString(), "GET", function(resp) { + Profile.prototype.showProfile = function(profiles) { - _this.populate(_this.profile_template.followed, resp.responseText); - }, null, false); + if(profiles.posts.length < 1) return; + var profile = profiles.posts[0]; + var basic = profile.content.profile; - if (this.entity != HostApp.stringForKey("entity")) { - APICalls.http_call(URI(root_url + "/followers/" + encodeURIComponent(HostApp.stringForKey("entity"))).toString(), "GET", function(resp) { - if (resp.status == 200) { - _this.relationships.following_you = true; - } - _this.setRelationships(); + if (profile && basic) { - }, null, false); + // Find and apply avatar + if(profile.attachments.length > 0) { - APICalls.http_call(URI(APICalls.mkApiRootPath("/followings/" + encodeURIComponent(this.entity))), "GET", function(resp) { - if (resp.status == 200) { - _this.relationships.followed_by_you = true; - } - _this.setRelationships(); - }); + var digest = null; + for (var i = 0; i < profile.attachments.length; i++) { + var attachment = profile.attachments[i]; + if(attachment.category == "avatar") { + digest = attachment.digest; + break; + } + } + + if(digest) { + var _this = this; + this.profile_template.avatar.onerror = function() { _this.profile_template.avatar.src = 'img/default-avatar.png' }; + var avatar_url = profile.content.servers[0].urls.attachment.replace(/\{entity\}/, encodeURIComponent(profile.entity)); + this.profile_template.avatar.src = avatar_url.replace(/\{digest\}/, digest); + } + } + + this.populate(this.profile_template.name, basic.name); + this.populate(this.profile_template.birthdate, basic.birthdate); + this.populate(this.profile_template.location, basic.location); + this.populate(this.profile_template.gender, basic.gender); + this.populate(this.profile_template.bio, basic.bio); + + if(basic.website) { + + var url = basic.website; + this.profile_template.url.innerText = url; + this.profile_template.url.parentNode.parentNode.style.display = ""; + + if (!url.startsWith("http")) { + url = "http://" + url; + } + + this.profile_template.url.href = url; + } + } - } else { - this.setRelationships(); - } + if (profile) { + this.profile = profile; + this.getMeta(this.profile); + //this.getStatuses(this.server); + } + } + + Profile.prototype.populate = function(t, v) { + if (v) { + t.innerText = v; + t.parentNode.style.display = ""; + t.parentNode.parentNode.style.display = ""; + } + } + + Profile.prototype.getMeta = function(profile) { - var url = URI(root_url + "/posts/count"); - var post_types = [ - "https://tent.io/types/post/repost/v0.1.0", - "https://tent.io/types/post/status/v0.1.0", - "https://tent.io/types/post/photo/v0.1.0" - ]; - url.addSearch("post_types", post_types.join(",")); + var _this = this; - APICalls.http_call(url.toString(), "GET", function(resp) { + var url = HostApp.serverUrl("posts_feed") + "?entities=" + encodeURIComponent(this.entity) + "&types=" + encodeURIComponent("https://tent.io/types/relationship/v0#follower"); + APICalls.head(url, { + callback: function(resp) { + debug(APICalls.getCount(resp)) - _this.populate(_this.profile_template.posts, resp.responseText); - }, null, false); - } + _this.populate(_this.profile_template.followed, APICalls.getCount(resp)+" "); + } + }); - Profile.prototype.setRelationships = function() { - var relation = "none"; - if (this.relationships.it_is_you) { - relation = "it's you"; - } else { - if (this.relationships.following_you && !this.relationships.followed_by_you) { - relation = "is following you"; - } else if (this.relationships.following_you && this.relationships.followed_by_you) { - relation = "you both follow each other"; - } else if (!this.relationships.following_you && this.relationships.followed_by_you) { - relation = "being followed by you"; - } - } - this.populate(this.profile_template.relationships, relation); - } + var url = HostApp.serverUrl("posts_feed") + "?entities=" + encodeURIComponent(this.entity) + "&types=" + encodeURIComponent("https://tent.io/types/relationship/v0#following"); + APICalls.head(url, { + callback: function(resp) { + _this.populate(_this.profile_template.following, APICalls.getCount(resp) + " "); + } + }); + return; - Profile.prototype.getStatuses = function(root_url, add_search, append) { - var _this = this; - add_search = add_search || {}; - var url = URI(root_url + "/posts"); - url.addSearch("limit", this.posts_limit); - var post_types = [ - "https://tent.io/types/post/repost/v0.1.0", - "https://tent.io/types/post/status/v0.1.0", - "https://tent.io/types/post/photo/v0.1.0" - ]; - url.addSearch("post_types", post_types.join(",")); - for(var key in add_search) { - url.addSearch(key, add_search[key]); - } - APICalls.http_call(url.toString(), "GET", function(resp) { + if (this.entity != HostApp.stringForKey("entity")) { + APICalls.http_call(URI(root_url + "/followers/" + encodeURIComponent(HostApp.stringForKey("entity"))).toString(), "GET", function(resp) { + if (resp.status == 200) { + _this.relationships.following_you = true; + } + _this.setRelationships(); - var statuses = JSON.parse(resp.responseText); + }, null, false); - _this.newStatus(statuses, append); + APICalls.http_call(URI(APICalls.mkApiRootPath("/followings/" + encodeURIComponent(this.entity))), "GET", function(resp) { + if (resp.status == 200) { + _this.relationships.followed_by_you = true; + } + _this.setRelationships(); + }); - }, null, false); - } + } else { + this.setRelationships(); + } - Profile.prototype.newStatus = function(statuses, append) { + var url = URI(root_url + "/posts/count"); + var post_types = [ + "https://tent.io/types/post/repost/v0.1.0", + "https://tent.io/types/post/status/v0.1.0", + "https://tent.io/types/post/photo/v0.1.0" + ]; + url.addSearch("post_types", post_types.join(",")); - if(statuses != null && statuses.length > 0) { + APICalls.http_call(url.toString(), "GET", function(resp) { - this.before.loading = false; + _this.populate(_this.profile_template.posts, resp.responseText); + }, null, false); + } - if (append) statuses = statuses.reverse(); + Profile.prototype.setRelationships = function() { + var relation = "none"; + if (HostApp.stringForKey("entity") == this.entity) { + relation = "it's you"; + } else { + if (this.relationships.following_you && !this.relationships.followed_by_you) { + relation = "is following you"; + } else if (this.relationships.following_you && this.relationships.followed_by_you) { + relation = "you both follow each other"; + } else if (!this.relationships.following_you && this.relationships.followed_by_you) { + relation = "being followed by you"; + } + } + this.populate(this.profile_template.relationships, relation); + } - for(var i = statuses.length-1, c=0; i>=c; --i) { - var status = statuses[i]; + Profile.prototype.getStatuses = function(root_url, add_search, append) { + var _this = this; - if (status.type == "https://tent.io/types/post/status/v0.1.0" || status.type == "https://tent.io/types/post/photo/v0.1.0") { + add_search = add_search || {}; - var new_node = this.getStatusDOMElement(status); + var url = URI(root_url + "/posts"); + url.addSearch("limit", this.posts_limit); - if(!append && this.body.childNodes.length > 0) { + var post_types = [ + "https://tent.io/types/post/repost/v0.1.0", + "https://tent.io/types/post/status/v0.1.0", + "https://tent.io/types/post/photo/v0.1.0" + ]; + url.addSearch("post_types", post_types.join(",")); - if(this.body.childNodes.length > this.max_length) { + for(var key in add_search) { + url.addSearch(key, add_search[key]); + } - this.body.removeChild(this.body.lastChild); - } + APICalls.http_call(url.toString(), "GET", function(resp) { - this.body.insertBefore(new_node, this.body.firstChild); + var statuses = JSON.parse(resp.responseText); - } else { + _this.newStatus(statuses, append); - this.body.appendChild(new_node); - } + }, null, false); + } - } else if (status.type == "https://tent.io/types/post/delete/v0.1.0") { - var li = document.getElementById("post-" + status.content.id + "-" + this.action); - if (li) { - this.body.removeChild(li); - } - } else if (status.type == "https://tent.io/types/post/repost/v0.1.0") { + Profile.prototype.newStatus = function(statuses, append) { - this.getRepost(status, this.body.firstChild); - } + if(statuses != null && statuses.length > 0) { - } - } - } + this.before.loading = false; - Profile.prototype.getMoreStatusPosts = function() { - if (!this.before.loading) { - this.before.loading = true; - var add_search = { - "before_id": this.body.lastChild.status.id, - "before_id_entity": this.body.lastChild.status.entity - } - this.getStatuses(this.server, add_search, true); - } - } + if (append) statuses = statuses.reverse(); - Profile.prototype.mention = function() { + for(var i = statuses.length-1, c=0; i>=c; --i) { - } + var status = statuses[i]; - Profile.prototype.setFollowingButton = function(following) { + if (status.type == "https://tent.io/types/post/status/v0.1.0" || status.type == "https://tent.io/types/post/photo/v0.1.0") { - this.following = following; + var new_node = this.getStatusDOMElement(status); - if (following) { - this.profile_template.following_button.className = "following"; - this.profile_template.following_button.innerText = "Unfollow"; - } else { - this.profile_template.following_button.className = ""; - this.profile_template.following_button.innerText = "Follow"; - } - } + if(!append && this.body.childNodes.length > 0) { - Profile.prototype.toggleFollow = function() { + if(this.body.childNodes.length > this.max_length) { - var _this = this; + this.body.removeChild(this.body.lastChild); + } - if (this.following_id) { + this.body.insertBefore(new_node, this.body.firstChild); - this.setFollowingButton(false); - var url = APICalls.mkApiRootPath("/followings/") + this.following_id; - APICalls.http_call(url, "DELETE", function(resp) { - if (resp.status >= 200 && resp.status < 300) { - _this.setFollowingButton(false); - _this.following_id = null; - } else { - _this.setFollowingButton(true); - } - }); + } else { - } else { + this.body.appendChild(new_node); + } - this.setFollowingButton(true); - var url = URI(APICalls.mkApiRootPath("/followings")); - var data = JSON.stringify({"entity": this.entity }); - - APICalls.http_call(url.toString(), "POST", function(resp) { - if (resp.status >= 200 && resp.status < 300) { - _this.following_id = JSON.parse(resp.responseText).id - _this.setFollowingButton(true); - } else { - _this.setFollowingButton(false); - } - }, data); - } - } - - Profile.prototype.showPosts = function() { - this.showList(this.body); - } - - Profile.prototype.showFollowings = function() { - - this.showList(this.followingsBody); - this.followingsBody.innerHTML = ""; - - var _this = this; - var callback = function(resp) { - var followings = JSON.parse(resp.responseText); - for (var i = 0; i < followings.length; i++) { - var li = _this.getDOMSmallProfile(followings[i]); - _this.followingsBody.appendChild(li); - } - } - - var url = URI(this.server + "/followings"); - url.addSearch("limit", 200); - APICalls.http_call(url.toString(), "GET", callback, null, false); - } - - Profile.prototype.showFollowers = function() { - - this.showList(this.followersBody); - this.followersBody.innerHTML = ""; - - var _this = this; - var callback = function(resp) { - var followers = JSON.parse(resp.responseText); - for (var i = 0; i < followers.length; i++) { - var li = _this.getDOMSmallProfile(followers[i]); - _this.followersBody.appendChild(li); - } - } - - var url = URI(this.server + "/followers"); - url.addSearch("limit", 200); - APICalls.http_call(url.toString(), "GET", callback, null, false); - } - - Profile.prototype.getDOMSmallProfile = function(profile) { - - var li = document.createElement("li"); - - var image = document.createElement("img"); - image.title = profile.entity; - image.className = "image"; - image.src = 'img/default-avatar.png'; - li.appendChild(image); - image.onclick = function(e) { - HostApp.showProfileForEntity(e.target.title); - return false; - } - - var div = document.createElement("div"); - div.className = "data" - - var h1 = document.createElement("h1"); - var username = document.createElement("a"); - username.title = profile.entity; - username.className = "name"; - username.href = profile.entity; - username.onclick = function(e) { - HostApp.showProfileForEntity(profile.entity); - return false; - } - - h1.appendChild(username) - div.appendChild(h1); - li.appendChild(div); - - var p = document.createElement("p"); - p.className = "message"; - - var entity_tag = document.createElement("a"); - entity_tag.innerText = profile.entity; - entity_tag.href = profile.entity; - entity_tag.title = profile.entity; - - var new_line = document.createElement("br"); - var follows_since = document.createTextNode("follows since "); - var follows_since_time = document.createElement("span"); - follows_since_time.innerText = this.ISODateString(new Date(profile.created_at * 1000)); - follows_since_time.title = follows_since_time.innerText; - follows_since_time.className = "timeago"; - jQuery(follows_since_time).timeago(); - - p.appendChild(entity_tag); - p.appendChild(new_line); - p.appendChild(follows_since); - p.appendChild(follows_since_time); - div.appendChild(p); - - var profile_callback = function(p) { - - var basic = p["https://tent.io/types/info/basic/v0.1.0"]; - - if (p && basic) { - if(basic.name) { - username.title = username.innerText; - username.innerText = basic.name; - } - if(basic.avatar_url) { - image.onerror = function() { image.src = 'img/default-avatar.png'; }; - image.src = basic.avatar_url; - } - } - - } - - var p = this.cache.profiles.getItem(profile.entity); - - if (p && p != "null") { - - profile_callback(p); - - } else { - - var _this = this; - APICalls.findProfileURL(profile.entity, function(profile_url) { - - if (profile_url) { - APICalls.http_call(profile_url, "GET", function(resp) { - var p = JSON.parse(resp.responseText); - if (p && p != "null") { - _this.cache.profiles.setItem(profile.entity, p); - profile_callback(p); - } - - }, null, false); // do not send auth-headers - } - }); - } - - return li; - } - - - return Profile; + } else if (status.type == "https://tent.io/types/post/delete/v0.1.0") { + + var li = document.getElementById("post-" + status.content.id + "-" + this.action); + if (li) { + this.body.removeChild(li); + } + } else if (status.type == "https://tent.io/types/post/repost/v0.1.0") { + + this.getRepost(status, this.body.firstChild); + } + + } + } + } + + Profile.prototype.getMoreStatusPosts = function() { + if (!this.before.loading) { + this.before.loading = true; + var add_search = { + "before_id": this.body.lastChild.status.id, + "before_id_entity": this.body.lastChild.status.entity + } + this.getStatuses(this.server, add_search, true); + } + } + + Profile.prototype.mention = function() { + + } + + Profile.prototype.setFollowingButton = function(following) { + + this.following = following; + + if (following) { + this.profile_template.following_button.className = "following"; + this.profile_template.following_button.innerText = "Unfollow"; + } else { + this.profile_template.following_button.className = ""; + this.profile_template.following_button.innerText = "Follow"; + } + } + + Profile.prototype.toggleFollow = function() { + + var _this = this; + + if (this.following_id) { + + this.setFollowingButton(false); + + /* + var url = APICalls.mkApiRootPath("/followings/") + this.following_id; + APICalls.http_call(url, "DELETE", function(resp) { + if (resp.status >= 200 && resp.status < 300) { + _this.setFollowingButton(false); + _this.following_id = null; + } else { + _this.setFollowingButton(true); + } + });*/ + + } else { + + this.setFollowingButton(true); + + var url = HostApp.serverUrl("new_post"); + + var data = JSON.stringify({ + type: "https://tent.io/types/subscription/v0#https://tent.io/types/status/v0", + mentions: [{ + entity: this.entity + }] + }); + + APICalls.post(url, data, { + content_type: "https://tent.io/types/subscription/v0", + callback: function(resp) { + debug(resp.status) + if (resp.status >= 200 && resp.status < 300) { + _this.setFollowingButton(true); + } else { + _this.setFollowingButton(false); + } + } + }); + } + } + + Profile.prototype.showPosts = function() { + this.showList(this.body); + } + + Profile.prototype.showFollowings = function() { + + this.showList(this.followingsBody); + this.followingsBody.innerHTML = ""; + + var _this = this; + var callback = function(resp) { + var followings = JSON.parse(resp.responseText); + for (var i = 0; i < followings.length; i++) { + var li = _this.getDOMSmallProfile(followings[i]); + _this.followingsBody.appendChild(li); + } + } + + var url = URI(this.server + "/followings"); + url.addSearch("limit", 200); + APICalls.http_call(url.toString(), "GET", callback, null, false); + } + + Profile.prototype.showFollowers = function() { + + this.showList(this.followersBody); + this.followersBody.innerHTML = ""; + + var _this = this; + var callback = function(resp) { + var followers = JSON.parse(resp.responseText); + for (var i = 0; i < followers.length; i++) { + var li = _this.getDOMSmallProfile(followers[i]); + _this.followersBody.appendChild(li); + } + } + + var url = URI(this.server + "/followers"); + url.addSearch("limit", 200); + APICalls.http_call(url.toString(), "GET", callback, null, false); + } + + Profile.prototype.getDOMSmallProfile = function(profile) { + + var li = document.createElement("li"); + + var image = document.createElement("img"); + image.title = profile.entity; + image.className = "image"; + image.src = 'img/default-avatar.png'; + li.appendChild(image); + image.onclick = function(e) { + HostApp.showProfileForEntity(e.target.title); + return false; + } + + var div = document.createElement("div"); + div.className = "data" + + var h1 = document.createElement("h1"); + var username = document.createElement("a"); + username.title = profile.entity; + username.className = "name"; + username.href = profile.entity; + username.onclick = function(e) { + HostApp.showProfileForEntity(profile.entity); + return false; + } + + h1.appendChild(username) + div.appendChild(h1); + li.appendChild(div); + + var p = document.createElement("p"); + p.className = "message"; + + var entity_tag = document.createElement("a"); + entity_tag.innerText = profile.entity; + entity_tag.href = profile.entity; + entity_tag.title = profile.entity; + + var new_line = document.createElement("br"); + var follows_since = document.createTextNode("follows since "); + var follows_since_time = document.createElement("span"); + follows_since_time.innerText = this.ISODateString(new Date(profile.created_at * 1000)); + follows_since_time.title = follows_since_time.innerText; + follows_since_time.className = "timeago"; + jQuery(follows_since_time).timeago(); + + p.appendChild(entity_tag); + p.appendChild(new_line); + p.appendChild(follows_since); + p.appendChild(follows_since_time); + div.appendChild(p); + + var profile_callback = function(p) { + + var basic = p["https://tent.io/types/info/basic/v0.1.0"]; + + if (p && basic) { + if(basic.name) { + username.title = username.innerText; + username.innerText = basic.name; + } + if(basic.avatar_url) { + image.onerror = function() { image.src = 'img/default-avatar.png'; }; + image.src = basic.avatar_url; + } + } + + } + + var p = this.cache.profiles.getItem(profile.entity); + + if (p && p != "null") { + + profile_callback(p); + + } else { + + var _this = this; + APICalls.findProfileURL(profile.entity, function(profile_url) { + + if (profile_url) { + APICalls.http_call(profile_url, "GET", function(resp) { + var p = JSON.parse(resp.responseText); + if (p && p != "null") { + _this.cache.profiles.setItem(profile.entity, p); + profile_callback(p); + } + + }, null, false); // do not send auth-headers + } + }); + } + + return li; + } + + + + + return Profile; }); diff --git a/WebKit/scripts/controller/Timeline.js b/WebKit/scripts/controller/Timeline.js index 19030eb..c01f418 100644 --- a/WebKit/scripts/controller/Timeline.js +++ b/WebKit/scripts/controller/Timeline.js @@ -46,9 +46,13 @@ function(Core, APICalls, HostApp, URI) { } - Timeline.prototype.newStatus = function(statuses, append) { + Timeline.prototype.newStatus = function(_statuses, append) { - statuses = statuses.data; + for (var entity in _statuses.profiles) { + bungloo.cache.profiles[entity] = _statuses.profiles[entity]; + } + + statuses = _statuses.posts; if(statuses != null && statuses.length > 0) { this.before.loading = false; @@ -63,7 +67,7 @@ function(Core, APICalls, HostApp, URI) { this.since_id_entity = status.entity; } - if (status.type == "https://tent.io/types/status/v0#" || status.type == "https://tent.io/types/post/photo/v0.1.0") { + if (status.type == "https://tent.io/types/status/v0#") { var new_node = this.getStatusDOMElement(status); @@ -110,9 +114,11 @@ function(Core, APICalls, HostApp, URI) { "https://tent.io/types/delete/v0#", //"https://tent.io/types/post/photo/v0.1.0" ]; - //url.addSearch("types", post_types.join(",")); + url.addSearch("types", post_types.join(",")); //url.addSearch("sort_by", "published_at"); url.addSearch("limit", this.posts_limit); + url.addSearch("max_refs", 20); + url.addSearch("profiles", "entity"); if(this.since_id && !append) { url.addSearch("since_id", this.since_id); @@ -144,7 +150,7 @@ function(Core, APICalls, HostApp, URI) { if (!this.reload_blocked) { this.reload_blocked = true; - // APICalls.http_call(url.toString(), http_method, callback, data); // FIXME: error callback + APICalls.get(url.toString(), { callback: callback }); } } diff --git a/WebKit/scripts/helper/APICalls.js b/WebKit/scripts/helper/APICalls.js index 64341b1..60a971b 100644 --- a/WebKit/scripts/helper/APICalls.js +++ b/WebKit/scripts/helper/APICalls.js @@ -36,10 +36,10 @@ function(jQuery, HostApp, Hmac, Cache) { console.error("No content type for " + options.url); return; } else { - if(options.content_type != "application/json") { - content_type = "application/vnd.tent.post.v0+json; type=\"" + options.content_type + "\""; + if(options.content_type == "application/json") { + content_type = "application/json"; } else { - content_type = options.content_type; + content_type = "application/vnd.tent.post.v0+json; type=\"" + options.content_type + "\""; } } @@ -64,6 +64,7 @@ function(jQuery, HostApp, Hmac, Cache) { } else if(!options.no_auth) { console.error("No user_access_token yet - " + options.url); } + xhr.setRequestHeader("Cache-Control", "no-cache"); }, url: options.url, contentType: content_type, @@ -72,13 +73,26 @@ function(jQuery, HostApp, Hmac, Cache) { data: options.data, processData: false, error: function(xhr, ajaxOptions, thrownError) { - console.error("HTTP CALL (" + xhr.status + ")" + xhr.statusText + " " + options.http_method + " (" + options.url + "): '" + xhr.responseText + "'"); + console.error("HTTP CALL (" + xhr.status + ") " + xhr.statusText + " " + options.http_method + " URL(" + options.url + "): '" + xhr.responseText + "'"); } }; jQuery.ajax(settings); } + APICalls.head = function(url, options) { + var settings = { + url: url, + http_method: "HEAD", + }; + + for (var key in options) { + settings[key] = options[key]; + } + + APICalls.http_call(settings); + } + APICalls.get = function(url, options) { var settings = { url: url, @@ -225,6 +239,23 @@ function(jQuery, HostApp, Hmac, Cache) { return APICalls.parseHeaderForLink(header_string, regexp); } + APICalls.parseHeader = function(header_string) { + var header_strings = header_string.split(/\n/); + var headers = {}; + for (var i = 0; i < header_strings.length; i++) { + var hs = header_strings[i].split(/:(.+)?/); + headers[hs[0]] = hs[1]; + } + return headers; + } + + APICalls.getCount = function(resp) { + var count = 0; + var headers = APICalls.parseHeader(resp.getAllResponseHeaders()); + if(headers["Count"]) count = parseInt(headers["Count"], 10); + return count; + } + APICalls.parseHeaderForLink = function(header_string, match) { var headers = header_string.split(/\n/); var links = []; diff --git a/WebKit/scripts/helper/Core.js b/WebKit/scripts/helper/Core.js index 77ea169..b4bc318 100644 --- a/WebKit/scripts/helper/Core.js +++ b/WebKit/scripts/helper/Core.js @@ -69,6 +69,7 @@ function(jQuery, APICalls, URI, HostApp, Cache) { image.className = "image"; image.src = "img/default-avatar.png"; image.onmousedown = function(e) { e.preventDefault(); }; + image.onerror = function() { this.src = 'img/default-avatar.png' }; item.appendChild(image); var image_username = a.cloneNode(); @@ -224,7 +225,7 @@ function(jQuery, APICalls, URI, HostApp, Cache) { mentions.push(mention); } - _this.replyTo(status.entity, status.id, mentions, (status && status.permissions && !status.permissions.public)); + _this.replyTo(status); return false; } @@ -234,7 +235,7 @@ function(jQuery, APICalls, URI, HostApp, Cache) { return false; } - template.username.innerText = status.entity; + if(bungloo.cache.profiles[status.entity].name) template.username.innerText = bungloo.cache.profiles[status.entity].name; template.username.href = status.entity; template.username.title = status.entity; template.username.onclick = function() { @@ -242,47 +243,12 @@ function(jQuery, APICalls, URI, HostApp, Cache) { return false; } + if(bungloo.cache.profiles[status.entity].avatar_digest) { + template.image.src = HostApp.serverUrl("attachment").replace(/\{entity\}/, encodeURIComponent(status.entity)).replace(/\{digest\}/, bungloo.cache.profiles[status.entity].avatar_digest); + } + template.image.onclick = template.username.onclick; - var profile_callback = function(p) { - - var basic = p["https://tent.io/types/info/basic/v0.1.0"]; - - if (p && 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; - } - } - - } - - var p = this.cache.profiles.getItem(status.entity); - - if (p && p != "null") { - - profile_callback(p); - - } else { - - APICalls.findProfileURL(status.entity, function(profile_url) { - - if (profile_url) { - APICalls.http_call(profile_url, "GET", function(resp) { - var p = JSON.parse(resp.responseText); - if (p && p != "null") { - _this.cache.profiles.setItem(status.entity, p); - profile_callback(p); - } - - }, null, false); // do not send auth-headers - } - }); - } if (status && status.permissions && !status.permissions.public) { template.is_private.style.display = ''; @@ -389,9 +355,11 @@ function(jQuery, APICalls, URI, HostApp, Cache) { template.source.innerHTML = status.__repost.app.name; template.source.title = status.__repost.app.url; } else { - template.source.href = status.app.url; - template.source.innerHTML = status.app.name; - template.source.title = status.app.url; + if(status.app) { + template.source.href = status.app.url; + template.source.innerHTML = status.app.name; + template.source.title = status.app.url; + } } return template.item; @@ -498,60 +466,6 @@ function(jQuery, APICalls, URI, HostApp, Cache) { } } - Core.prototype.sendNewMessage = function(content, in_reply_to_status_id, in_reply_to_entity, location, image_data_uri, is_private, callback) { - - if (image_data_uri) { - - this.sendNewMessageWithImage(content, in_reply_to_status_id, in_reply_to_entity, location, image_data_uri, is_private, callback); - - } else { - - var url = URI(HostApp.serverUrl("new_post")); - - var type = in_reply_to_status_id.length == 0 ? "https://tent.io/types/status/v0#" : "https://tent.io/types/status/v0#reply"; - debug(typeof in_reply_to_status_id) - debug(in_reply_to_status_id.length) - debug(type) - - var data = { - "type": type, - "published_at": parseInt(new Date().getTime(), 10), - "permissions": { - "public": !is_private - }, - "content": { - "text": content, - }, - }; - - if (location) { - //data["content"]["location"] = { "type": "Point", "coordinates": location } - } - - var mentions = this.parseMentions(content, in_reply_to_status_id, in_reply_to_entity); - - if (mentions.length > 0) { - data["mentions"] = mentions; - if (is_private) { - var entities = {}; - for (var i = 0; i < mentions.length; i++) { - var entity = mentions[i]["entity"] - entities[entity] = true; - }; - - data["permissions"]["entities"] = entities; - } - } - - // APICalls.http_call(url.toString(), http_method, callback, JSON.stringify(data)); - APICalls.post(url.toString(), JSON.stringify(data), { - content_type: data.type, - callback: callback - }); - } - } - - Core.prototype.repost = function(id, entity, callback) { var url = URI(APICalls.mkApiRootPath("/posts")); @@ -582,80 +496,6 @@ function(jQuery, APICalls, URI, HostApp, Cache) { APICalls.http_call(url.toString(), "POST", new_callback, JSON.stringify(data)); } - Core.prototype.sendNewMessageWithImage = function(content, in_reply_to_status_id, in_reply_to_entity, location, image_data_uri, is_private, callback) { - - var url = URI(APICalls.mkApiRootPath("/posts")); - - var data = { - "type": "https://tent.io/types/post/photo/v0.1.0", - "published_at": parseInt(new Date().getTime() / 1000, 10), - "permissions": { - "public": !is_private - }, - "content": { - "caption": content, - }, - }; - - if (location) { - data["content"]["location"] = { "type": "Point", "coordinates": location } - } - - var mentions = this.parseMentions(content, in_reply_to_status_id, in_reply_to_entity); - if (mentions.length > 0) { - data["mentions"] = mentions; - if (is_private) { - var entities = {}; - for (var i = 0; i < mentions.length; i++) { - var entity = mentions[i]["entity"] - entities[entity] = true; - }; - - data["permissions"]["entities"] = entities; - } - } - - var data_string = JSON.stringify(data); - - var boundary = "TentAttachment----------TentAttachment"; - var post = "--" + boundary + "\r\n"; - - post += 'Content-Disposition: form-data; name="post"; filename="post.json"\r\n'; - post += 'Content-Length: ' + data_string.length + '\r\n'; - post += 'Content-Type: application/vnd.tent.v0+json\r\n'; - post += 'Content-Transfer-Encoding: binary\r\n\r\n'; - post += data_string; - - post += "\r\n--" + boundary + "\r\n"; - - var blob_string = image_data_uri.split(',')[1]; - var mime_type = image_data_uri.split(',')[0].split(':')[1].split(';')[0]; - var ext = "png"; - if (mime_type == "image/jpeg") { - ext = "jpeg"; - } else if (mime_type == "image/gif") { - ext = "gif"; - } - - - post += 'Content-Disposition: form-data; name="photos[0]"; filename="photo.' + ext + '"\r\n'; - post += 'Content-Length: ' + blob_string.length + "\r\n"; - post += 'Content-Type: ' + mime_type + "\r\n"; - post += 'Content-Transfer-Encoding: base64\r\n\r\n'; - post += blob_string; - post += "\r\n--" + boundary + "--\r\n"; - - var newCallback = function(resp) { - if (resp.status == 403) { - var err = JSON.parse(resp.responseText); - HostApp.alertTitleWithMessage(resp.statusText, err.error); - } - callback(resp); - } - - APICalls.postMultipart(url.toString(), newCallback, post, boundary); - } - Core.prototype.remove = function(id, callback, type) { type = type || "post"; if (confirm("Really delete this " + type + "?")) { @@ -920,19 +760,8 @@ function(jQuery, APICalls, URI, HostApp, Cache) { } } - Core.prototype.replyTo = function(entity, status_id, mentions, is_private) { - - var string = "^" + entity.replace("https://", "") + " "; - - var ms = ""; - for (var i = 0; i < mentions.length; i++) { - var e = mentions[i].entity.replace("https://", ""); - if(string.indexOf(e) == -1) ms += " ^" + e; - } - - if(ms.length > 0) string += "\n\n/cc" + ms; - - HostApp.openNewMessageWidow(entity, status_id, string, is_private); + Core.prototype.replyTo = function(status) { + HostApp.openNewMessageWidow(status); } Core.prototype.postDeleted = function(post_id, entity) { diff --git a/WebKit/scripts/helper/HostApp.js b/WebKit/scripts/helper/HostApp.js index ced766a..13992ad 100644 --- a/WebKit/scripts/helper/HostApp.js +++ b/WebKit/scripts/helper/HostApp.js @@ -85,13 +85,12 @@ define(function() { } } - HostApp.openNewMessageWidow = function(entity, status_id, string, is_private) { + HostApp.openNewMessageWidow = function(status) { if (OS_TYPE == "mac") { - controller.openNewMessageWindowInReplyTo_statusId_withString_isPrivate_(entity, status_id, string, is_private); + controller.openNewMessageWindowInReplyToStatus(JSON.stringify(status)); } else { - is_private = is_private == true - controller.openNewMessageWindowInReplyTostatusIdwithStringIsPrivate(entity, status_id, string, is_private); + controller.openNewMessageWindowInReplyTostatus(JSON.stringify(status)); } } diff --git a/WebKit/scripts/main.js b/WebKit/scripts/main.js index f823148..69511ef 100644 --- a/WebKit/scripts/main.js +++ b/WebKit/scripts/main.js @@ -7,7 +7,7 @@ var bungloo = { entityProfile: null, conversation: null, search: null, - cache: {}, + cache: { profiles: {}}, newpost: null }; From 771243a75f11c806d0358b3bfb72c275972ee67e Mon Sep 17 00:00:00 2001 From: jeena Date: Wed, 17 Jul 2013 03:01:43 +0200 Subject: [PATCH 07/18] fixed following/unfollowing --- WebKit/scripts/controller/Profile.js | 39 ++++++++++++++++----------- WebKit/scripts/controller/Timeline.js | 6 ++++- WebKit/scripts/helper/APICalls.js | 17 ++++++++++-- WebKit/scripts/helper/Core.js | 1 + 4 files changed, 44 insertions(+), 19 deletions(-) diff --git a/WebKit/scripts/controller/Profile.js b/WebKit/scripts/controller/Profile.js index febc78c..bd42d8d 100644 --- a/WebKit/scripts/controller/Profile.js +++ b/WebKit/scripts/controller/Profile.js @@ -247,14 +247,17 @@ function(HostApp, Core, APICalls, URI) { var url = HostApp.serverUrl("posts_feed") + "?mentions=" + encodeURIComponent(this.entity) + "&types=" + encodeURIComponent("https://tent.io/types/subscription/v0#https://tent.io/types/status/v0"); var _this = this; - APICalls.head(url, {callback: function(resp) { + APICalls.get(url, {callback: function(resp) { - var count = APICalls.getCount(resp); + var json = JSON.parse(resp.responseText); + var count = json.posts.length; if (count > 0) { _this.setFollowingButton(true); + _this.following_id = json.posts[0].id; } else { _this.setFollowingButton(false); + delete _this.following_id; } }}); @@ -331,13 +334,14 @@ function(HostApp, Core, APICalls, URI) { Profile.prototype.getMeta = function(profile) { + // FIXME! + return; + var _this = this; var url = HostApp.serverUrl("posts_feed") + "?entities=" + encodeURIComponent(this.entity) + "&types=" + encodeURIComponent("https://tent.io/types/relationship/v0#follower"); APICalls.head(url, { callback: function(resp) { - debug(APICalls.getCount(resp)) - _this.populate(_this.profile_template.followed, APICalls.getCount(resp)+" "); } }); @@ -518,16 +522,15 @@ function(HostApp, Core, APICalls, URI) { this.setFollowingButton(false); - /* - var url = APICalls.mkApiRootPath("/followings/") + this.following_id; - APICalls.http_call(url, "DELETE", function(resp) { + var url = HostApp.serverUrl("post").replace(/\{entity\}/, encodeURIComponent(HostApp.stringForKey("entity"))).replace(/\{post\}/, this.following_id); + APICalls.delete(url, { callback: function(resp) { if (resp.status >= 200 && resp.status < 300) { _this.setFollowingButton(false); - _this.following_id = null; + delete _this.following_id; } else { _this.setFollowingButton(true); } - });*/ + }}); } else { @@ -535,19 +538,23 @@ function(HostApp, Core, APICalls, URI) { var url = HostApp.serverUrl("new_post"); - var data = JSON.stringify({ - type: "https://tent.io/types/subscription/v0#https://tent.io/types/status/v0", + var data = { + content: { + type: "https://tent.io/types/status/v0" + }, mentions: [{ entity: this.entity - }] - }); + }], + type: "https://tent.io/types/subscription/v0#https://tent.io/types/status/v0" + }; - APICalls.post(url, data, { - content_type: "https://tent.io/types/subscription/v0", + APICalls.post(url, JSON.stringify(data), { + content_type: data.type, callback: function(resp) { - debug(resp.status) if (resp.status >= 200 && resp.status < 300) { _this.setFollowingButton(true); + var json = JSON.parse(resp.responseText); + _this.following_id = json.post.id; } else { _this.setFollowingButton(false); } diff --git a/WebKit/scripts/controller/Timeline.js b/WebKit/scripts/controller/Timeline.js index c01f418..c4716d7 100644 --- a/WebKit/scripts/controller/Timeline.js +++ b/WebKit/scripts/controller/Timeline.js @@ -49,7 +49,11 @@ function(Core, APICalls, HostApp, URI) { Timeline.prototype.newStatus = function(_statuses, append) { for (var entity in _statuses.profiles) { - bungloo.cache.profiles[entity] = _statuses.profiles[entity]; + if (_statuses.profiles[entity] != null) { + bungloo.cache.profiles[entity] = _statuses.profiles[entity]; + } else { + bungloo.cache.profiles[entity] = {}; + } } statuses = _statuses.posts; diff --git a/WebKit/scripts/helper/APICalls.js b/WebKit/scripts/helper/APICalls.js index 60a971b..1bdc52d 100644 --- a/WebKit/scripts/helper/APICalls.js +++ b/WebKit/scripts/helper/APICalls.js @@ -38,10 +38,9 @@ function(jQuery, HostApp, Hmac, Cache) { } else { if(options.content_type == "application/json") { content_type = "application/json"; - } else { + } else if(options.content_type) { content_type = "application/vnd.tent.post.v0+json; type=\"" + options.content_type + "\""; } - } var settings = { @@ -120,6 +119,20 @@ function(jQuery, HostApp, Hmac, Cache) { APICalls.http_call(settings); } + APICalls.delete = function(url, options) { + var settings = { + url: url, + http_method: "DELETE" + }; + + for (var key in options) { + settings[key] = options[key]; + } + + APICalls.http_call(settings); + } + + APICalls.postMultipart = function(url, callback, data, boundary, accepts) { accepts = accepts || "application/vnd.tent.v0+json"; diff --git a/WebKit/scripts/helper/Core.js b/WebKit/scripts/helper/Core.js index b4bc318..1f17530 100644 --- a/WebKit/scripts/helper/Core.js +++ b/WebKit/scripts/helper/Core.js @@ -236,6 +236,7 @@ function(jQuery, APICalls, URI, HostApp, Cache) { } if(bungloo.cache.profiles[status.entity].name) template.username.innerText = bungloo.cache.profiles[status.entity].name; + else template.username.innerText = status.entity; template.username.href = status.entity; template.username.title = status.entity; template.username.onclick = function() { From 3aa9a730451d75d236ba09c3f387cb1d444fc2d1 Mon Sep 17 00:00:00 2001 From: jeena Date: Wed, 17 Jul 2013 04:40:04 +0200 Subject: [PATCH 08/18] moved image files --- .../img/images.png | Bin .../img/private.png | Bin .../img/public.png | Bin .../img/send.png | Bin images/Actions-insert-image-icon.png | Bin 719 -> 0 bytes images/Lock-Lock-icon.png | Bin 617 -> 0 bytes images/Lock-Unlock-icon.png | Bin 516 -> 0 bytes 7 files changed, 0 insertions(+), 0 deletions(-) rename images/glyphicons_138_picture.png => WebKit/img/images.png (100%) rename images/glyphicons_203_lock.png => WebKit/img/private.png (100%) rename images/glyphicons_204_unlock.png => WebKit/img/public.png (100%) rename images/glyphicons_123_message_out.png => WebKit/img/send.png (100%) delete mode 100644 images/Actions-insert-image-icon.png delete mode 100644 images/Lock-Lock-icon.png delete mode 100644 images/Lock-Unlock-icon.png diff --git a/images/glyphicons_138_picture.png b/WebKit/img/images.png similarity index 100% rename from images/glyphicons_138_picture.png rename to WebKit/img/images.png diff --git a/images/glyphicons_203_lock.png b/WebKit/img/private.png similarity index 100% rename from images/glyphicons_203_lock.png rename to WebKit/img/private.png diff --git a/images/glyphicons_204_unlock.png b/WebKit/img/public.png similarity index 100% rename from images/glyphicons_204_unlock.png rename to WebKit/img/public.png diff --git a/images/glyphicons_123_message_out.png b/WebKit/img/send.png similarity index 100% rename from images/glyphicons_123_message_out.png rename to WebKit/img/send.png diff --git a/images/Actions-insert-image-icon.png b/images/Actions-insert-image-icon.png deleted file mode 100644 index 05adf9a3a8d6086c45f829db6e8773dfffc4ea92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 719 zcmV;=0xMg_SxC-9mL_ z7CbL@<^XARS2Ew6LO|dMT>@|-kW2$<Jf#;%Wr5NG16&cHs|hJJSqURk3eTA))Hk07ll%fm9{@d*n?f_G z(IhPhWU)Z~WBmY-RAj05d?Q2;gKRd7K!8V}oC9xU@Iz&>tFzDvz_V^Ta0Q=VO~5M% zd4Md-Qs_hje4+={0UH&520O9?Rp;P146Lk8U>i2WQnQs)bK~2NLw_L;P!vUKZEZ!s zFW}Q(whe)lhV144wRK}Xm8dC zU}1IL!KY0JmLtIH^&%RLB6zC`0?(mlt0~^q)pf%#jODxr1PF)2wCSL|MMF)6jrZ#u zHomhEODfRa-Hk{jf~nLvN_{-8nte-}rcI^Q^n?qDkSGi8n6B$whvnQ?bRosVmqXax zTSsGE9ZkbwFTICg;5Z(&KY8Gu2$C30e=~b57Q40*Tpm{TchPXn4^d?Cb!Qtbbtf@- zWp;?c5ivM8D2$Gd-sd>(dfU@rXJxGq3%wr~9UCvEXQrPY2`ENFPQ;=!m&P+>_16Q7 z!}O`oiVpv$7#kZC`tSDNBMUHd^K%n@clr#s{u>y;1lNxcc3}Vj002ovPDHLkV1ipg BIuQT> diff --git a/images/Lock-Lock-icon.png b/images/Lock-Lock-icon.png deleted file mode 100644 index 45079c95fa9bfdc8567df3cc7a3799237ea774f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 617 zcmV-v0+#)WP)jA)vL1%-rnRM#|^1P2E)aB*>g z6@2~njbZKD^$cw-4QJlHd+PxddW+Qn4i3&u(`PUA)z;BsShajP!Wwt6*$xsQa~d_qG(E*b1mzgtMF1oa*`}w!W^; z|64Y$)(47RMmHd%tfpnUhNc!na!km)|Ns9bqxhAPY3_^#E0P{PxW~|1Uy%tEnt^UW zaamn^kBpQgLtaKg1CZZ{7C!a0ZT$_rT$~JL1sNqkelM~CwyH`D3z9P8lyo)K7@8Yu z-T=kkpcx<%7Mm)fAS1z0QPzC#_C1CKpx9xs0ir?-JDwe7aA#p+APW5X$G{+E&9L+J zI|dK10rHXz`yZ@haA5dPoB<$rD+Dndc=(*b5n_M@(17JY1JJ;CW(dvs7t;)dNT2~P zU#L4)5Lh0d5JOL)#tyT&p!H{1qxpPE4RQAh7k8F00000NkvXXu0mjf DAxspF diff --git a/images/Lock-Unlock-icon.png b/images/Lock-Unlock-icon.png deleted file mode 100644 index 627d59fb3bd8f0a6408885708c7f6c9262b7d8e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 516 zcmV+f0{i`mP)5o7R{9 z|NnmqAp@ccORAQJhJ`Y$S+$bk*|Vn%a`Flc!6Bgx^XJa}KV#a&0K5js$jV=sy>PjH zO?lDlv!_o40EI3Av5AeH)B39VW`X#~;3IeqFt@h5y&loi8HgX%vri- zTXJV}?K_YGHb5MNEj$cOtqY1v%Nb(A{7wV8?LfR99B_<`lNYYqoHMbj^#h}eHN)dA za~Ncpn6N|PP|(EiXWCK*5uor#AZ}Gs)l7Q%{OL!=crS+c3#x(9^B;d` zb}VCHsGP)rV&d`if+ zVFL|ozx`Z(>IWzmzMvQY#9Bb?!9X})90%fK7*WkYApig+HkNwzjQ>CY0000 Date: Mon, 22 Jul 2013 02:02:59 +0200 Subject: [PATCH 09/18] fixed some mentions stuff --- Qt/Bungloo.py | 19 ++- Qt/Windows.py | 56 +++----- WebKit/css/default.css | 12 +- WebKit/scripts/controller/NewPost.js | 184 ++++++++++++++++++--------- WebKit/scripts/controller/Oauth.js | 2 +- WebKit/scripts/controller/Profile.js | 5 +- WebKit/scripts/controller/Sidebar.js | 55 +------- WebKit/scripts/helper/APICalls.js | 10 +- WebKit/scripts/helper/HostApp.js | 4 +- WebKit/scripts/main.js | 74 ++++++----- 10 files changed, 222 insertions(+), 199 deletions(-) diff --git a/Qt/Bungloo.py b/Qt/Bungloo.py index a8ca0be..6ccfe15 100755 --- a/Qt/Bungloo.py +++ b/Qt/Bungloo.py @@ -170,13 +170,13 @@ class Controller(QtCore.QObject): except OSError: pass - @QtCore.pyqtSlot(str) + @QtCore.pyqtSlot() def openNewMessageWidow(self): - self.openNewMessageWindowInReplyTostatus(None) + self.openNewMessageWindowInReplyToStatus("") - @QtCore.pyqtSlot(str, str, str, bool) - def openNewMessageWindowInReplyTostatus(self, status_string): - new_message_window = Windows.NewPost(self.app) + @QtCore.pyqtSlot(str) + def openNewMessageWindowInReplyToStatus(self, status_string): + new_message_window = Windows.NewPost(self.app, status_string) new_message_window.show() new_message_window.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.app.new_message_windows.append(new_message_window) @@ -262,10 +262,15 @@ class Controller(QtCore.QObject): msgBox.exec_() @QtCore.pyqtSlot(result=str) - def getCachedEntities(self): - entities = self.app.timeline.evaluateJavaScript("JSON.stringify(bungloo.cache.entities);") + def getCachedProfiles(self): + entities = self.app.timeline.evaluateJavaScript("JSON.stringify(bungloo.cache.profiles);") return entities.toString() + @QtCore.pyqtSlot() + def getNewData(self): + func = "bungloo.timeline.getNewData()" + self.app.timeline.evaluateJavaScript(func) + def logout(self, sender): print "logout is not implemented yet" diff --git a/Qt/Windows.py b/Qt/Windows.py index fb7d332..762a02a 100644 --- a/Qt/Windows.py +++ b/Qt/Windows.py @@ -9,7 +9,7 @@ class Preferences: # window self.window = QtGui.QMainWindow() - self.window.setWindowTitle("Preferences") + self.window.setWindowTitle("Login") self.window.resize(480, 186) self.window.setMinimumSize(480, 186) self.window.setMaximumSize(480, 186) @@ -329,12 +329,9 @@ class FindEntity(QtGui.QDialog): class NewPost(Helper.RestorableWindow): - def __init__(self, app, string=None, mentions="[]", is_private=False, post_id=None): + def __init__(self, app, status_string): self.app = app - self.string = string - self.mentions = mentions - self.is_private = is_private - self.post_id = post_id + self.status_string = status_string Helper.RestorableWindow.__init__(self, "newpost", self.app) self.activateWindow() @@ -349,6 +346,8 @@ class NewPost(Helper.RestorableWindow): self.initUI() self.webView.triggerPageAction(QtWebKit.QWebPage.InspectElement) + frame = self.webView.page().mainFrame() + frame.addToJavaScriptWindowObject("new_post_window", self) self.setWindowTitle("New Post") self.resize(300, 150) @@ -409,18 +408,8 @@ class NewPost(Helper.RestorableWindow): helpMenu.addAction(aboutAction) helpMenu.addAction(developerExtrasAction) - def load_finished(self, widget): - is_private = "false" - if self.is_private: - is_private = "true" - - post_id = "" - if self.post_id: - post_id = self.post_id - - callback = "function() { bungloo.newpost.setString('%s'); bungloo.newpost.setIsPrivate(%s); bungloo.newpost.setMentions(%s); bungloo.newPostAction.setPostId(%s); }" % (self.string, is_private, self.mentions, post_id) - + callback = "function() { bungloo.newpost.setStatus('%s'); }" % (self.status_string) script = "function HostAppGo() { start('newpost', " + callback + "); }" self.webView.page().mainFrame().evaluateJavaScript(script) self.webView.setFocus() @@ -432,32 +421,17 @@ class NewPost(Helper.RestorableWindow): def sendMessage(self): script = "bungloo.newpost.send()" self.webView.page().mainFrame().evaluateJavaScript(script) - self.close() - - """ - count = len(self.textInput.toPlainText()) - if count > 0 and count <= 256: - message = Helper.PostModel() - message.text = unicode(self.textInput.toPlainText().toUtf8(), "utf-8") - message.inReplyTostatusId = self.status_id - message.inReplyToEntity = self.reply_to_entity - message.location = None - message.imageFilePath = self.imageFilePath - message.isPrivate = self.isPrivate - self.app.controller.sendMessage(message) - self.close() - else: - QtGui.qApp.beep() - """ - - def openFileDialog(self): - fileNamePath = QtGui.QFileDialog.getOpenFileName(self, "Choose a image", "", "Images (*.png *.gif *.jpg *.jpeg)") - if len(fileNamePath) > 0: - self.imageFilePath = str(fileNamePath) - else: - self.imageFilePath = None def developer_extras(self, widget): QtWebKit.QWebSettings.globalSettings().setAttribute(QtWebKit.QWebSettings.DeveloperExtrasEnabled, True) + def openFileDialog(self): + print "openFileDialog Not implemented yet" + @QtCore.pyqtSlot() + def closeWindow(self): + self.close() + + @QtCore.pyqtSlot() + def beep(self): + QtGui.qApp.beep() \ No newline at end of file diff --git a/WebKit/css/default.css b/WebKit/css/default.css index 63bd2e8..eec1a75 100644 --- a/WebKit/css/default.css +++ b/WebKit/css/default.css @@ -18,6 +18,15 @@ a { text-decoration: none; color: #00317a; outline: 0; + outline : none; +} + +button { + background: transparent; + border: 0; + margin: 0; + padding: 4px 5px 0 5px; + outline : none; } #sidebar { @@ -460,4 +469,5 @@ p.noresult { #suggestions { position: absolute; left: 0; bottom: 0; } #suggestions .active { color: red; } #status_bar { height: 1em; } -#status_bar p { float: right; } \ No newline at end of file +#status_bar p { float: right; margin: 0; padding: 0; } +#status_bar span { display: inline-block; margin: 4px 5px 0 5px; } \ No newline at end of file diff --git a/WebKit/scripts/controller/NewPost.js b/WebKit/scripts/controller/NewPost.js index e37fcce..63ec2bd 100644 --- a/WebKit/scripts/controller/NewPost.js +++ b/WebKit/scripts/controller/NewPost.js @@ -1,13 +1,20 @@ define([ + "helper/APICalls", + "helper/HostApp" ], -function() { +function(APICalls, HostApp) { function NewPost() { - this.entities = JSON.parse(controller.getCachedEntities()); + this.profiles = JSON.parse(controller.getCachedProfiles()); + for (var key in this.profiles) { + var item = this.profiles[key]; + if(!item.entity) item.entity = key; + if(!item.name) item.name = key; + } + this.mentions = []; - this.is_private = false; document.body.className = "new_post"; // Textarea @@ -30,8 +37,8 @@ function() { var buttons = $( "

    " + //"" + - "" + - "" + + "" + + "" + "

    "); this.buttons = { @@ -41,18 +48,26 @@ function() { } //this.buttons.images.bind("click", this.addImage.bind(this)); - //this.buttons.is_private.bind("click", this.togglePrivate.bind(this)); + this.buttons.is_private.bind("click", this.toggleIsPrivate.bind(this)); this.buttons.send.bind("click", this.send.bind(this)); this.container.find("#status_bar").append(this.counter); this.container.find("#status_bar").append(buttons); - this.textarea.focus() + this.textarea.focus(); + this.setIsPrivate(false); } NewPost.prototype.setStatus = function(status_string) { - this.status = JSON.parse(status_string); - debug(this.status) + if (status_string && status_string.length > 0) { + debug(status_string) + this.status = JSON.parse(status_string); + this.setIsPrivate(this.status.permissions && !this.status.permissions.public); + this.setMentions(this.status); + } else { + this.status = null; + } + // FIXME set string, private, mentions, etc. }; @@ -60,27 +75,67 @@ function() { this.textarea.val(string); } - NewPost.prototype.setMentions = function(mentions) { + NewPost.prototype.setMentions = function(status) { - if(mentions && mentions.length > 0) { - var mentions_string = " "; - for (var i = 0; i < mentions.length; i++) { - mentions_string += mentions[i].name + " "; + var mentions = [this.profiles[status.entity]]; + var text = this.profiles[status.entity].name + " "; + var start = text.length; + + if(status.mentions && status.mentions.length > 0) { + + var mentions_text = "" + for (var i = 0; i < status.mentions.length; i++) { + + var entity = status.mentions[i].entity; + + // Sometimes there are mentions without entity, don't know why + if(entity) { + // fix broken profiles + var profile = this.profiles[entity]; + if(!profile) { + profile = {}; + this.profiles[entity] = profile; + } + if(!profile.entity) profile.entity = entity; + if(!profile.name) profile.name = entity; + + // add profile to mentions and textarea + mentions.push(profile); + mentions_text += profile.name; + + // add space after mention + if(i < status.mentions.length) { + mentions_text += " "; + } + } } + if (mentions_text.length > 0) { + text += "\n\n/cc " + mentions_text; + }; - this.textarea.val(this.textarea.val() + " " + mentions_string); - this.mentions = mentions; } - this.keyup(); + + this.mentions = mentions; + this.textarea.val(text); + this.parseText(text); + + // Select other mentions so user can start writing and removing them + var end = text.length; + this.textarea.get(0).setSelectionRange(start, end); } NewPost.prototype.setIsPrivate = function(is_private) { this.is_private = is_private; + if (this.is_private) { + this.buttons.is_private.find("img").attr("src", "img/private.png"); + } else { + this.buttons.is_private.find("img").attr("src", "img/public.png"); + } } NewPost.prototype.toggleIsPrivate = function() { - this.is_private = !this.is_private; - }; + this.setIsPrivate(!this.is_private); + } NewPost.prototype.keyup = function(e) { if(!e) return; @@ -152,16 +207,20 @@ function() { if(words) { var name = words[2]; - for (var key in this.entities.length) { - var item = this.entities[key]; - if(item.name.toLowerCase().indexOf(name.toLowerCase()) != -1 || item.entity.toLowerCase().indexOf(name.toLowerCase()) != -1) { + for (var key in this.profiles) { + var item = this.profiles[key]; + if((item.name.toLowerCase().indexOf(name.toLowerCase()) != -1) || item.entity.toLowerCase().indexOf(name.toLowerCase()) != -1) { var li = $("
  • " + item.name + " " + item.entity + "
  • ") li.get(0).item = item; - this.suggestions.append(li) + this.suggestions.append(li); } } } + this.parseText(text); + } + + NewPost.prototype.parseText = function(text) { // parse the text: // replace all the line braks by
    , and all the double spaces by the html version   text = this.replaceAll(text,'\n','
    '); @@ -188,19 +247,18 @@ function() { this.highlighter.html(text); var count = 256 - this.textarea.val().length + (this.mentions.length * 6); - this.counter.html(count) - - return true; + this.counter.html(count); } NewPost.prototype.send = function() { - debug("Send not implemented yet"); - $("textarea").focus(); + var count = 256 - this.textarea.val().length + (this.mentions.length * 6); - if(count >= 0) { - this.sentNewMessage(); + if(count >= 0 && count <= 256) { + this.sendNewMessage(); + return true; } else { debug("BEEP"); + return false; } } @@ -208,44 +266,52 @@ function() { var content = this.textarea.val(); - var url = URI(HostApp.serverUrl("new_post")); - - var type = in_reply_to_status_id.length == 0 ? "https://tent.io/types/status/v0#" : "https://tent.io/types/status/v0#reply"; - + var type = "https://tent.io/types/status/v0#"; var data = { - "type": type, - "published_at": parseInt(new Date().getTime(), 10), - "permissions": { - "public": !is_private - }, - "content": { - "text": content, + type: type, + content: { + text: content }, + permissions: { + public: !this.is_private + } }; - if (location) { - //data["content"]["location"] = { "type": "Point", "coordinates": location } + var mentions = []; + if (this.status) { + mentions.push({ + entity: this.status.entity, + post: this.status.id, + type: this.status.type + }); } - var mentions = this.parseMentions(content, in_reply_to_status_id, in_reply_to_entity); - - if (mentions.length > 0) { - data["mentions"] = mentions; - if (is_private) { - var entities = {}; - for (var i = 0; i < mentions.length; i++) { - var entity = mentions[i]["entity"] - entities[entity] = true; - }; - - data["permissions"]["entities"] = entities; - } + for (var i = 0; i < this.mentions.length; i++) { + var mention = this.mentions[i]; + mentions.push({ + entity: mention.entity + }); } - // APICalls.http_call(url.toString(), http_method, callback, JSON.stringify(data)); - APICalls.post(url.toString(), JSON.stringify(data), { + data.mentions = mentions; + + // Make tent flavored markdown mentions + for (var i = 0; i < this.mentions.length; i++) { + var mention = this.mentions[i]; + data.content.text = this.replaceAll(data.content.text, mention.name, "^[" + mention.name + "](" + i + ")") + } + + APICalls.post(HostApp.serverUrl("new_post"), JSON.stringify(data), { content_type: data.type, - callback: callback + accept: 'application/vnd.tent.post.v0+json; type="https://tent.io/types/status/v0#"', + callback: function(resp) { + if (resp.status >= 200 < 300) { + new_post_window.closeWindow(); + controller.getNewData(); + } else { + new_post_window.beep(); + } + } }); } /* diff --git a/WebKit/scripts/controller/Oauth.js b/WebKit/scripts/controller/Oauth.js index 69e1b41..9999826 100644 --- a/WebKit/scripts/controller/Oauth.js +++ b/WebKit/scripts/controller/Oauth.js @@ -178,7 +178,7 @@ function(HostApp, APICalls, Hmac) { HostApp.loggedIn(); } - Oauth.prototype.logout = function() { + Oauth.prototype.logout = function() { // FIXME var url = APICalls.mkApiRootPath("/apps/" + HostApp.stringForKey("app_id")); var http_method = "DELETE"; diff --git a/WebKit/scripts/controller/Profile.js b/WebKit/scripts/controller/Profile.js index bd42d8d..fb8125b 100644 --- a/WebKit/scripts/controller/Profile.js +++ b/WebKit/scripts/controller/Profile.js @@ -250,6 +250,7 @@ function(HostApp, Core, APICalls, URI) { APICalls.get(url, {callback: function(resp) { var json = JSON.parse(resp.responseText); + debug(json) var count = json.posts.length; if (count > 0) { @@ -273,12 +274,14 @@ function(HostApp, Core, APICalls, URI) { if(profiles.posts.length < 1) return; var profile = profiles.posts[0]; + bungloo.cache.profiles[profile.entity] = profile; + var basic = profile.content.profile; if (profile && basic) { // Find and apply avatar - if(profile.attachments.length > 0) { + if(profile.attachments) { var digest = null; for (var i = 0; i < profile.attachments.length; i++) { diff --git a/WebKit/scripts/controller/Sidebar.js b/WebKit/scripts/controller/Sidebar.js index e715f94..61d05d4 100644 --- a/WebKit/scripts/controller/Sidebar.js +++ b/WebKit/scripts/controller/Sidebar.js @@ -1,16 +1,13 @@ define([ "helper/HostApp", "helper/APICalls", - "helper/Cache" ], -function(HostApp, APICalls, Cache) { +function(HostApp, APICalls) { function Sidebar() { - this.cache = new Cache(); - this.body = document.createElement("ul"); this.body.class = "sidebar"; @@ -51,7 +48,7 @@ function(HostApp, APICalls, Cache) { document.body.className = "body-timeline"; document.body.id = "with-sidebar"; - //this.setEntityAvatar(); FIXME + this.setEntityAvatar(); this.setOnScroll(); } @@ -88,53 +85,13 @@ function(HostApp, APICalls, Cache) { var _this = this; - var profile_callback = function(p) { + var url = HostApp.serverUrl("discover"); + debug(url) - var basic = p["https://tent.io/types/info/basic/v0.1.0"]; + APICalls.get(url, { callback: function(resp) { - if (p && basic) { - if(basic.name) { - _this.menu.user.title = basic.name; - } - if(basic.avatar_url) { + }}); - img.onerror = function() { - img.src = "img/sidebar/user.png"; - img.src_inactive = img.src; - img.src_active = img.src; - } - - img.src = basic.avatar_url; - img.src_inactive = basic.avatar_url; - img.src_active = basic.avatar_url; - - } - } - - } - - var p = this.cache.profiles.getItem(entity); - - if (p && p != "null") { - - profile_callback(p); - - } else { - - APICalls.findProfileURL(entity, function(profile_url) { - - if (profile_url) { - APICalls.http_call(profile_url, "GET", function(resp) { - var p = JSON.parse(resp.responseText); - if (p && p != "null") { - _this.cache.profiles.setItem(entity, p); - profile_callback(p); - } - - }, null, false); // do not send auth-headers - } - }); - } } Sidebar.prototype.removeEntityAvatar = function() { diff --git a/WebKit/scripts/helper/APICalls.js b/WebKit/scripts/helper/APICalls.js index 1bdc52d..9ab43c2 100644 --- a/WebKit/scripts/helper/APICalls.js +++ b/WebKit/scripts/helper/APICalls.js @@ -35,19 +35,23 @@ function(jQuery, HostApp, Hmac, Cache) { if(options.http_method == "POST" && !options.content_type) { console.error("No content type for " + options.url); return; - } else { + } else if(options.content_type != "AAA") { if(options.content_type == "application/json") { content_type = "application/json"; } else if(options.content_type) { - content_type = "application/vnd.tent.post.v0+json; type=\"" + options.content_type + "\""; + content_type = "application/vnd.tent.post.v0+json; charset=UTF-8; type=\"" + options.content_type + "\""; } + } else { + content_type = 'application/vnd.tent.post.v0+json; charset=UTF-8; type="https://tent.io/types/status/v0#"'; } var settings = { beforeSend: function(xhr) { if (options.data) xhr.setRequestHeader("Content-Length", options.data.length); + if (options.accept) xhr.setRequestHeader("Accept", options.accept); else xhr.setRequestHeader("Accept", "application/vnd.tent.post.v0+json"); + var user_access_token = HostApp.stringForKey("user_access_token"); if (!options.auth_header && !options.no_auth && user_access_token) { var auth_header = Hmac.makeHawkAuthHeader( @@ -63,7 +67,7 @@ function(jQuery, HostApp, Hmac, Cache) { } else if(!options.no_auth) { console.error("No user_access_token yet - " + options.url); } - xhr.setRequestHeader("Cache-Control", "no-cache"); + xhr.setRequestHeader("Cache-Control", "no-proxy"); }, url: options.url, contentType: content_type, diff --git a/WebKit/scripts/helper/HostApp.js b/WebKit/scripts/helper/HostApp.js index 13992ad..9811fda 100644 --- a/WebKit/scripts/helper/HostApp.js +++ b/WebKit/scripts/helper/HostApp.js @@ -88,9 +88,9 @@ define(function() { HostApp.openNewMessageWidow = function(status) { if (OS_TYPE == "mac") { - controller.openNewMessageWindowInReplyToStatus(JSON.stringify(status)); + controller.openNewMessageWindowInReplyToStatus_(JSON.stringify(status)); } else { - controller.openNewMessageWindowInReplyTostatus(JSON.stringify(status)); + controller.openNewMessageWindowInReplyToStatus(JSON.stringify(status).escapeSpecialChars()); } } diff --git a/WebKit/scripts/main.js b/WebKit/scripts/main.js index 69511ef..3b48c90 100644 --- a/WebKit/scripts/main.js +++ b/WebKit/scripts/main.js @@ -64,46 +64,12 @@ function start(view, callback) { bungloo.search = new Search(); bungloo.sidebar.showContentForTimeline(); - - bungloo.cache.entities = { - "https://jeena.net" : { - name: "Jeena", - entity: "https://jeena.net", - avatar: "https://jeena.net/avatar.png" - }, - "https://ck.kennt-wayne.de": { - name: "Christian", - entity: "http://ck.kennt-wayne.de", - avatar: "http://ck.kennt-wayne.de/pavatar.png" - } - }; - }); } } -String.prototype.startsWith = function(prefix) { - return this.indexOf(prefix) === 0; -} - -String.prototype.endsWith = function(suffix) { - return this.match(suffix+"$") == suffix; -}; - -var __entityMap = { - "&": "&", - "<": "<", - ">": ">" -}; - -String.prototype.escapeHTML = function() { - return String(this).replace(/[&<>]/g, function (s) { - return __entityMap[s]; - }); -} - var console = { log: function(s) { if (OS_TYPE == "mac") { @@ -195,4 +161,42 @@ function go() { // wait untill everything is loaded }, 500); } -go(); \ No newline at end of file +go(); + + +// String stuff +String.prototype.startsWith = function(prefix) { + return this.indexOf(prefix) === 0; +} + +String.prototype.endsWith = function(suffix) { + return this.match(suffix+"$") == suffix; +}; + +var __entityMap = { + "&": "&", + "<": "<", + ">": ">" +}; + +String.prototype.escapeHTML = function() { + return String(this).replace(/[&<>]/g, function (s) { + return __entityMap[s]; + }); +} + +String.prototype.hasArabicCharacter = function() { + var arregex = /[\u0600-\u06FF]/; + return arregex.test(this); +} + +String.prototype.escapeSpecialChars = function() { + return this.replace(/[\\]/g, '\\\\') + .replace(/[\"]/g, '\\\"') + .replace(/[\/]/g, '\\/') + .replace(/[\b]/g, '\\b') + .replace(/[\f]/g, '\\f') + .replace(/[\n]/g, '\\n') + .replace(/[\r]/g, '\\r') + .replace(/[\t]/g, '\\t'); +} \ No newline at end of file From 0eeffcf7f61e1273d60a74f74ee86dc990c17f55 Mon Sep 17 00:00:00 2001 From: jeena Date: Mon, 22 Jul 2013 03:33:54 +0200 Subject: [PATCH 10/18] fixed avatar in sidebar --- WebKit/scripts/controller/NewPost.js | 1 - WebKit/scripts/controller/Profile.js | 5 ++-- WebKit/scripts/controller/Sidebar.js | 33 +++++++++++++++++++++++---- WebKit/scripts/controller/Timeline.js | 2 +- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/WebKit/scripts/controller/NewPost.js b/WebKit/scripts/controller/NewPost.js index 63ec2bd..63144ff 100644 --- a/WebKit/scripts/controller/NewPost.js +++ b/WebKit/scripts/controller/NewPost.js @@ -60,7 +60,6 @@ function(APICalls, HostApp) { NewPost.prototype.setStatus = function(status_string) { if (status_string && status_string.length > 0) { - debug(status_string) this.status = JSON.parse(status_string); this.setIsPrivate(this.status.permissions && !this.status.permissions.public); this.setMentions(this.status); diff --git a/WebKit/scripts/controller/Profile.js b/WebKit/scripts/controller/Profile.js index fb8125b..f36e915 100644 --- a/WebKit/scripts/controller/Profile.js +++ b/WebKit/scripts/controller/Profile.js @@ -231,8 +231,7 @@ function(HostApp, Core, APICalls, URI) { this.profile_template.following_button.style.display = "none"; } - var url = HostApp.serverUrl("posts_feed") + "?types=" + encodeURIComponent("https://tent.io/types/meta/v0") + "&entities=" + encodeURIComponent(this.entity) - //var url = HostApp.serverUrl("discover").replace(/{entity}/, encodeURIComponent(this.entity)); + var url = HostApp.serverUrl("posts_feed") + "?types=" + encodeURIComponent("https://tent.io/types/meta/v0") + "&entities=" + encodeURIComponent(this.entity); APICalls.get(url, { callback: function(resp) { var profile = JSON.parse(resp.responseText); @@ -274,7 +273,7 @@ function(HostApp, Core, APICalls, URI) { if(profiles.posts.length < 1) return; var profile = profiles.posts[0]; - bungloo.cache.profiles[profile.entity] = profile; + bungloo.cache.profiles[profile.entity] = profile.content.profile; var basic = profile.content.profile; diff --git a/WebKit/scripts/controller/Sidebar.js b/WebKit/scripts/controller/Sidebar.js index 61d05d4..d32c1e4 100644 --- a/WebKit/scripts/controller/Sidebar.js +++ b/WebKit/scripts/controller/Sidebar.js @@ -81,15 +81,38 @@ function(HostApp, APICalls) { var entity = HostApp.stringForKey("entity"); this.menu.user.title = entity; - var img = this.menu.user.getElementsByTagName("img")[0]; - + var avatar = this.menu.user.getElementsByTagName("img")[0]; var _this = this; - var url = HostApp.serverUrl("discover"); - debug(url) - + var url = HostApp.serverUrl("posts_feed") + "?types=" + encodeURIComponent("https://tent.io/types/meta/v0") + "&entities=" + encodeURIComponent(entity); APICalls.get(url, { callback: function(resp) { + var profiles = JSON.parse(resp.responseText); + if(profiles.posts.length < 1) return; + var profile = profiles.posts[0]; + bungloo.cache.profiles[entity] = profile; + + // Find and apply avatar + if(profile.attachments) { + + var digest = null; + for (var i = 0; i < profile.attachments.length; i++) { + var attachment = profile.attachments[i]; + if(attachment.category == "avatar") { + digest = attachment.digest; + break; + } + } + + if(digest) { + var _this = this; + avatar.onerror = function() { avatar.src = 'img/default-avatar.png' }; + var avatar_url = profile.content.servers[0].urls.attachment.replace(/\{entity\}/, encodeURIComponent(profile.entity)); + avatar.src = avatar_url.replace(/\{digest\}/, digest); + avatar.src_inactive = avatar.src; + avatar.src_active = avatar.src; + } + } }}); } diff --git a/WebKit/scripts/controller/Timeline.js b/WebKit/scripts/controller/Timeline.js index c4716d7..576246b 100644 --- a/WebKit/scripts/controller/Timeline.js +++ b/WebKit/scripts/controller/Timeline.js @@ -30,7 +30,7 @@ function(Core, APICalls, HostApp, URI) { document.getElementById("content").appendChild(this.container); var _this = this; - //this.reloadIntervall = setInterval(function() { _this.getNewData() }, this.timeout); //FIXME back + this.reloadIntervall = setInterval(function() { _this.getNewData() }, this.timeout); this.getNewData(); } From ec43a38b8672b201c350c6dfce967af9d55fa309 Mon Sep 17 00:00:00 2001 From: jeena Date: Mon, 22 Jul 2013 07:02:26 +0200 Subject: [PATCH 11/18] fixed initial mentions --- WebKit/scripts/controller/Mentions.js | 11 ++++---- WebKit/scripts/controller/Sidebar.js | 1 - WebKit/scripts/helper/APICalls.js | 16 ++++++++++- WebKit/scripts/helper/Core.js | 38 +++++++++------------------ 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/WebKit/scripts/controller/Mentions.js b/WebKit/scripts/controller/Mentions.js index 68fc7ec..dc64952 100644 --- a/WebKit/scripts/controller/Mentions.js +++ b/WebKit/scripts/controller/Mentions.js @@ -10,7 +10,6 @@ function(HostApp, Timeline, URI, APICalls, Core) { function Mentions() { - return // FIXME this.is_not_init = false; this.unread_mentions = 0; @@ -37,7 +36,7 @@ function(HostApp, Timeline, URI, APICalls, Core) { Mentions.prototype.newStatus = function(statuses, append) { Timeline.prototype.newStatus.call(this, statuses, append); - +/* if(this.is_not_init) { for (var i = 0; i < statuses.length; i++) { @@ -52,7 +51,7 @@ function(HostApp, Timeline, URI, APICalls, Core) { if(!append) HostApp.notificateUserAboutMention(status.content.text, name || status.entity, status.id, status.entity); } } - +*/ this.is_not_init = true; } @@ -60,13 +59,13 @@ function(HostApp, Timeline, URI, APICalls, Core) { add_to_search = add_to_search || {}; - if (!add_to_search["mentioned_entity"]) { - add_to_search["mentioned_entity"] = HostApp.stringForKey("entity"); + if (!add_to_search["mentions"]) { + add_to_search["mentions"] = HostApp.stringForKey("entity"); } Timeline.prototype.getNewData.call(this, add_to_search, append); - this.getLatestMentionRead(); + //this.getLatestMentionRead(); } Mentions.prototype.mentionRead = function(id, entity) { diff --git a/WebKit/scripts/controller/Sidebar.js b/WebKit/scripts/controller/Sidebar.js index d32c1e4..845946c 100644 --- a/WebKit/scripts/controller/Sidebar.js +++ b/WebKit/scripts/controller/Sidebar.js @@ -114,7 +114,6 @@ function(HostApp, APICalls) { } } }}); - } Sidebar.prototype.removeEntityAvatar = function() { diff --git a/WebKit/scripts/helper/APICalls.js b/WebKit/scripts/helper/APICalls.js index 9ab43c2..7d97790 100644 --- a/WebKit/scripts/helper/APICalls.js +++ b/WebKit/scripts/helper/APICalls.js @@ -32,7 +32,7 @@ function(jQuery, HostApp, Hmac, Cache) { var content_type = null; - if(options.http_method == "POST" && !options.content_type) { + if((options.http_method == "POST" || options.http_method == "PUT") && !options.content_type) { console.error("No content type for " + options.url); return; } else if(options.content_type != "AAA") { @@ -136,6 +136,20 @@ function(jQuery, HostApp, Hmac, Cache) { APICalls.http_call(settings); } + APICalls.put = function(url, data, options) { + var settings = { + url: url, + http_method: "PUT", + data: data + }; + + for (var key in options) { + settings[key] = options[key]; + } + + APICalls.http_call(settings); + } + APICalls.postMultipart = function(url, callback, data, boundary, accepts) { diff --git a/WebKit/scripts/helper/Core.js b/WebKit/scripts/helper/Core.js index 1f17530..58f54df 100644 --- a/WebKit/scripts/helper/Core.js +++ b/WebKit/scripts/helper/Core.js @@ -3,16 +3,16 @@ define([ "helper/APICalls", "lib/URI", "helper/HostApp", - "helper/Cache", + "lib/Showdown", "lib/Timeago", "lib/SingleDoubleClick" ], -function(jQuery, APICalls, URI, HostApp, Cache) { +function(jQuery, APICalls, URI, HostApp, Showdown) { function Core() { - this.cache = new Cache(); this.saveScrollTop = 0; + this.markdown = new Showdown.converter(); } @@ -279,6 +279,7 @@ function(jQuery, APICalls, URI, HostApp, Cache) { template.message.innerHTML = this.replaceURLWithHTMLLinks(text, entities, template.message); this.afterChangingTextinMessageHTML(template.message) + /* if (status.type == "https://tent.io/types/post/photo/v0.1.0") { for (var i = 0; i < status.attachments.length; i++) { @@ -306,7 +307,7 @@ function(jQuery, APICalls, URI, HostApp, Cache) { })(); } } - + */ this.findMentions(template.message, status.mentions); /* @@ -667,27 +668,14 @@ function(jQuery, APICalls, URI, HostApp, Cache) { } Core.prototype.replaceURLWithHTMLLinks = function(text, entities, message_node) { - - var callback = function(url) { - - var result; - - if (entities && entities.some(function(x) { return x == url })) { - result = url; - } else { - - result = url; - if (url.startsWith("http://") || url.startsWith("https://")) { - result = '' + url + ''; - } - } - - return result; - } - - var hash = /(^|\s)(#)(\w+)/ig; - - return URI.withinString(text, callback).replace(hash, "$1$2$3"); + // FIXME: this has to be done better so one can nest that stuff and escape with \ + return text.replace(/_([^_]+)_/g, "$1 ") + .replace(/\*([^\*]+)\*/g, "$1 ") + .replace(/`([^`]+)`/g, "$1 ") + .replace(/~([^~]+)~/g, "$1 ") + .replace(/\#[^\s]+/, "#$1") + .replace(/[^\^]\[([^\]]+)\]\(([^\)]+)\)/g, "$1 ") + .replace(/\^\[([^\]]+)\]\(([^\)]+)\)/g, "$1 "); } Core.prototype.parseForMedia = function(text, images) { From 0bf0324702f174f5a945b9a46accb4d040627e81 Mon Sep 17 00:00:00 2001 From: jeena Date: Mon, 22 Jul 2013 14:00:43 +0200 Subject: [PATCH 12/18] fixed paging --- WebKit/scripts/controller/Mentions.js | 4 +- WebKit/scripts/controller/Timeline.js | 90 +++++++++++++++------------ 2 files changed, 51 insertions(+), 43 deletions(-) diff --git a/WebKit/scripts/controller/Mentions.js b/WebKit/scripts/controller/Mentions.js index dc64952..80f1ab8 100644 --- a/WebKit/scripts/controller/Mentions.js +++ b/WebKit/scripts/controller/Mentions.js @@ -55,7 +55,7 @@ function(HostApp, Timeline, URI, APICalls, Core) { this.is_not_init = true; } - Mentions.prototype.getNewData = function(add_to_search, append) { + Mentions.prototype.getNewData = function(add_to_search, append, query) { add_to_search = add_to_search || {}; @@ -63,7 +63,7 @@ function(HostApp, Timeline, URI, APICalls, Core) { add_to_search["mentions"] = HostApp.stringForKey("entity"); } - Timeline.prototype.getNewData.call(this, add_to_search, append); + Timeline.prototype.getNewData.call(this, add_to_search, append, query); //this.getLatestMentionRead(); } diff --git a/WebKit/scripts/controller/Timeline.js b/WebKit/scripts/controller/Timeline.js index 576246b..78998b4 100644 --- a/WebKit/scripts/controller/Timeline.js +++ b/WebKit/scripts/controller/Timeline.js @@ -14,13 +14,15 @@ function(Core, APICalls, HostApp, URI) { this.action = "timeline"; this.reload_blocked = false; - this.posts_limit = 25; + this.posts_limit = 4; this.max_length = 200; this.timeout = 10 * 1000; // every 10 seconds this.since_id = null; this.since_id_entity = null; this.since_time = 0; + this.pages = {}; + this.before = {id: null, entity: null, loading: false}; this.container = document.createElement("div"); @@ -56,6 +58,8 @@ function(Core, APICalls, HostApp, URI) { } } + this.pages = _statuses.pages; + statuses = _statuses.posts; if(statuses != null && statuses.length > 0) { @@ -104,48 +108,43 @@ function(Core, APICalls, HostApp, URI) { } } - Timeline.prototype.getNewData = function(add_to_search, append) { + Timeline.prototype.getNewData = function(add_to_search, append, query) { add_to_search = add_to_search || {}; var those = this; - var url = URI(HostApp.serverUrl("posts_feed")); + var url = HostApp.serverUrl("posts_feed"); - var post_types = [ - "https://tent.io/types/status/v0#", - "https://tent.io/types/status/v0#reply", - "https://tent.io/types/repost/v0#", - "https://tent.io/types/delete/v0#", - //"https://tent.io/types/post/photo/v0.1.0" - ]; - url.addSearch("types", post_types.join(",")); - //url.addSearch("sort_by", "published_at"); - url.addSearch("limit", this.posts_limit); - url.addSearch("max_refs", 20); - url.addSearch("profiles", "entity"); + if(!query) { - if(this.since_id && !append) { - url.addSearch("since_id", this.since_id); - url.addSearch("since_id_entity", this.since_id_entity); - } + var uri = URI(url); - for (key in add_to_search) { - url.addSearch(key, add_to_search[key]); - } + var post_types = [ + "https://tent.io/types/status/v0#", + "https://tent.io/types/status/v0#reply", + "https://tent.io/types/repost/v0#", + "https://tent.io/types/delete/v0#", + //"https://tent.io/types/post/photo/v0.1.0" + ]; + uri.addSearch("types", post_types.join(",")); + //uri.addSearch("sort_by", "published_at"); + uri.addSearch("limit", this.posts_limit); + uri.addSearch("max_refs", 20); + uri.addSearch("profiles", "entity"); - var http_method = "GET"; - var callback = function(resp) { - - those.reload_blocked = false; - - try { - var json = JSON.parse(resp.responseText); - those.newStatus(json, append); - - } catch (e) { - console.error(url + " JSON parse error"); - throw e; + if(this.since_id && !append) { + uri.addSearch("since_id", this.since_id); + uri.addSearch("since_id_entity", this.since_id_entity); } + + for (key in add_to_search) { + uri.addSearch(key, add_to_search[key]); + } + + url = uri.toString(); + + } else { + url += query; } var data = null; @@ -155,20 +154,29 @@ function(Core, APICalls, HostApp, URI) { if (!this.reload_blocked) { this.reload_blocked = true; - APICalls.get(url.toString(), { callback: callback }); + APICalls.get(url, { callback: function(resp) { + + those.reload_blocked = false; + + try { + var json = JSON.parse(resp.responseText); + those.newStatus(json, append); + + } catch (e) { + console.error(url + " JSON parse error"); + throw e; + } + } }); } } } Timeline.prototype.getMoreStatusPosts = function() { if (!this.before.loading) { - this.before.loading = true; - var add_search = { - "before_id": this.body.lastChild.status.id, - "before_id_entity": this.body.lastChild.status.entity + if (this.pages.next) { + this.before.loading = true; + this.getNewData({}, true, this.pages.next); } - - this.getNewData(add_search, true); } } From 1c12e5b3756b44497537c6bd83b053711d79c866 Mon Sep 17 00:00:00 2001 From: jeena Date: Thu, 25 Jul 2013 16:27:55 +0200 Subject: [PATCH 13/18] fixed problems with mentions --- WebKit/scripts/controller/NewPost.js | 25 ++++++++++++++----------- WebKit/scripts/controller/Profile.js | 13 +++++++++---- WebKit/scripts/controller/Timeline.js | 2 +- WebKit/scripts/helper/Core.js | 24 ++++++++++++------------ 4 files changed, 36 insertions(+), 28 deletions(-) diff --git a/WebKit/scripts/controller/NewPost.js b/WebKit/scripts/controller/NewPost.js index 63144ff..61b2f3a 100644 --- a/WebKit/scripts/controller/NewPost.js +++ b/WebKit/scripts/controller/NewPost.js @@ -277,28 +277,31 @@ function(APICalls, HostApp) { }; var mentions = []; - if (this.status) { - mentions.push({ - entity: this.status.entity, - post: this.status.id, - type: this.status.type - }); - } - for (var i = 0; i < this.mentions.length; i++) { var mention = this.mentions[i]; - mentions.push({ - entity: mention.entity - }); + if(this.status && this.status.entity == mention.entity) { + mentions.push({ + entity: this.status.entity, + post: this.status.id, + type: this.status.type + }); + } else { + mentions.push({ + entity: mention.entity + }); + } } data.mentions = mentions; + debug(data.mentions) + // Make tent flavored markdown mentions for (var i = 0; i < this.mentions.length; i++) { var mention = this.mentions[i]; data.content.text = this.replaceAll(data.content.text, mention.name, "^[" + mention.name + "](" + i + ")") } + debug(data.content.text) APICalls.post(HostApp.serverUrl("new_post"), JSON.stringify(data), { content_type: data.type, diff --git a/WebKit/scripts/controller/Profile.js b/WebKit/scripts/controller/Profile.js index f36e915..98b21bd 100644 --- a/WebKit/scripts/controller/Profile.js +++ b/WebKit/scripts/controller/Profile.js @@ -23,8 +23,8 @@ function(HostApp, Core, APICalls, URI) { this.initProfileTemplate(); this.hide(); - var _this = this; - setTimeout(function() { _this.showProfileForEntity() }, 500); // Load users profile on start + //var _this = this; + //setTimeout(function() { _this.showProfileForEntity() }, 500); // Load users profile on start } Profile.prototype = Object.create(Core.prototype); @@ -47,13 +47,19 @@ function(HostApp, Core, APICalls, URI) { $(this.followingsBody).hide(); $(this.followersBody).hide(); $(list).show(); + } + + Profile.prototype.showEntity = function(a, i) { + var entity = $(a).closest("li").get(0).status.mentions[i].entity; + this.showProfileForEntity(entity); + bungloo.sidebar.onEntityProfile(); }; Profile.prototype.showProfileForEntity = function(entity) { if (!entity) { entity = HostApp.stringForKey("entity"); - }; + } this.clear(); this.entity = entity; @@ -249,7 +255,6 @@ function(HostApp, Core, APICalls, URI) { APICalls.get(url, {callback: function(resp) { var json = JSON.parse(resp.responseText); - debug(json) var count = json.posts.length; if (count > 0) { diff --git a/WebKit/scripts/controller/Timeline.js b/WebKit/scripts/controller/Timeline.js index 78998b4..3f0bf11 100644 --- a/WebKit/scripts/controller/Timeline.js +++ b/WebKit/scripts/controller/Timeline.js @@ -14,7 +14,7 @@ function(Core, APICalls, HostApp, URI) { this.action = "timeline"; this.reload_blocked = false; - this.posts_limit = 4; + this.posts_limit = 25; this.max_length = 200; this.timeout = 10 * 1000; // every 10 seconds this.since_id = null; diff --git a/WebKit/scripts/helper/Core.js b/WebKit/scripts/helper/Core.js index 58f54df..a003ae1 100644 --- a/WebKit/scripts/helper/Core.js +++ b/WebKit/scripts/helper/Core.js @@ -3,16 +3,14 @@ define([ "helper/APICalls", "lib/URI", "helper/HostApp", - "lib/Showdown", "lib/Timeago", "lib/SingleDoubleClick" ], -function(jQuery, APICalls, URI, HostApp, Showdown) { +function(jQuery, APICalls, URI, HostApp) { function Core() { this.saveScrollTop = 0; - this.markdown = new Showdown.converter(); } @@ -669,13 +667,13 @@ function(jQuery, APICalls, URI, HostApp, Showdown) { Core.prototype.replaceURLWithHTMLLinks = function(text, entities, message_node) { // FIXME: this has to be done better so one can nest that stuff and escape with \ - return text.replace(/_([^_]+)_/g, "$1 ") - .replace(/\*([^\*]+)\*/g, "$1 ") - .replace(/`([^`]+)`/g, "$1 ") - .replace(/~([^~]+)~/g, "$1 ") - .replace(/\#[^\s]+/, "#$1") - .replace(/[^\^]\[([^\]]+)\]\(([^\)]+)\)/g, "$1 ") - .replace(/\^\[([^\]]+)\]\(([^\)]+)\)/g, "$1 "); + return text.replace(/_([^_]+)_/g, "$1") + .replace(/\*([^\*]+)\*/g, "$1") + .replace(/`([^`]+)`/g, "$1") + .replace(/~([^~]+)~/g, "$1") + .replace(/\#([^\s]+)/g, "#$1") + .replace(/(^|[^\^])\[([^\]]+)\]\(([^\)]+)\)/g, "$2") + .replace(/\^\[([^\]]+)\]\(([^\)]+)\)/g, "$1"); } Core.prototype.parseForMedia = function(text, images) { @@ -849,17 +847,19 @@ function(jQuery, APICalls, URI, HostApp, Showdown) { Core.prototype.afterChangingTextinMessageHTML = function(message_node) { // adding show search on click hash + /* $(message_node).find("a.hash").click(function(e) { if(bungloo.search) bungloo.search.searchFor(e.target.innerHTML); return false; }); - + */ // adding show profile on click + /* $(message_node).find("a.name").click(function(e) { HostApp.showProfileForEntity(e.target.title); return false; - }); + });*/ } From 096916395b0b21cdd2237c857c4ed54c0b1b4f49 Mon Sep 17 00:00:00 2001 From: jeena Date: Thu, 25 Jul 2013 17:27:32 +0200 Subject: [PATCH 14/18] facelift new post mentions --- WebKit/css/default.css | 12 ++++++++---- WebKit/scripts/controller/NewPost.js | 5 +++-- WebKit/scripts/controller/Profile.js | 6 +----- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/WebKit/css/default.css b/WebKit/css/default.css index eec1a75..76013fd 100644 --- a/WebKit/css/default.css +++ b/WebKit/css/default.css @@ -466,8 +466,12 @@ p.noresult { #new_post_container div { box-sizing: border-box; position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0; background: white; color: white; padding: 2px; } #new_post_container div span { background: #D8DFEA; } -#suggestions { position: absolute; left: 0; bottom: 0; } -#suggestions .active { color: red; } -#status_bar { height: 1em; } +#suggestions { width: 100%; position: absolute; left: 0; bottom: 0; background: #efefef; list-style-type: none; padding: 0; margin: 0; border-top: 1px solid #ccc; } +#suggestions li { border-top: 1px solid #fefefe; border-bottom: #c9c9c9; padding: 0 0.5em; } +#suggestions strong { font-weight: normal; color: #555; } +#suggestions .active { background: #dedede; } +#suggestions .active strong { color: black; } +#status_bar { height: 1em; border-top: 1px solid #ccc; } #status_bar p { float: right; margin: 0; padding: 0; } -#status_bar span { display: inline-block; margin: 4px 5px 0 5px; } \ No newline at end of file +#status_bar span { display: inline-block; margin: 4px 5px 0 5px; } + diff --git a/WebKit/scripts/controller/NewPost.js b/WebKit/scripts/controller/NewPost.js index 61b2f3a..6638b45 100644 --- a/WebKit/scripts/controller/NewPost.js +++ b/WebKit/scripts/controller/NewPost.js @@ -192,7 +192,7 @@ function(APICalls, HostApp) { var words = txt.match(/(^|\s)\^([^\s]+)/); var replace = words[2]; - var original = txt.replace("^" + replace, with_item.name); + var original = txt.replace("^" + replace, with_item.name + " "); this.textarea.val(original); this.mentions.push(with_item); @@ -209,11 +209,12 @@ function(APICalls, HostApp) { for (var key in this.profiles) { var item = this.profiles[key]; if((item.name.toLowerCase().indexOf(name.toLowerCase()) != -1) || item.entity.toLowerCase().indexOf(name.toLowerCase()) != -1) { - var li = $("
  • " + item.name + " " + item.entity + "
  • ") + var li = $("
  • " + item.name + "
  • ") li.get(0).item = item; this.suggestions.append(li); } } + this.suggestions.find("li:first-child").addClass("active"); } this.parseText(text); diff --git a/WebKit/scripts/controller/Profile.js b/WebKit/scripts/controller/Profile.js index 98b21bd..1315c3d 100644 --- a/WebKit/scripts/controller/Profile.js +++ b/WebKit/scripts/controller/Profile.js @@ -110,11 +110,7 @@ function(HostApp, Core, APICalls, URI) { div.appendChild(this.profile_template.following_button); this.profile_template.mention_button.onclick = function() { - var e = _this.entity; - if (e.startsWith("https://")) { - e = e.substr(8, e.length); - } - HostApp.openNewMessageWidow(null, null, "^" + e + " ", false); + HostApp.openNewMessageWidow({entity:_this.entity}); } div.appendChild(this.profile_template.mention_button); this.profile_template.mention_button.innerHTML = "Mention"; From 213c83f3e90359580251904c61a60e6e18a75eaf Mon Sep 17 00:00:00 2001 From: jeena Date: Thu, 25 Jul 2013 18:53:14 +0200 Subject: [PATCH 15/18] only digits in mentions --- WebKit/scripts/helper/Core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebKit/scripts/helper/Core.js b/WebKit/scripts/helper/Core.js index a003ae1..4b8983e 100644 --- a/WebKit/scripts/helper/Core.js +++ b/WebKit/scripts/helper/Core.js @@ -673,7 +673,7 @@ function(jQuery, APICalls, URI, HostApp) { .replace(/~([^~]+)~/g, "$1") .replace(/\#([^\s]+)/g, "#$1") .replace(/(^|[^\^])\[([^\]]+)\]\(([^\)]+)\)/g, "$2") - .replace(/\^\[([^\]]+)\]\(([^\)]+)\)/g, "$1"); + .replace(/\^\[([^\]]+)\]\((\d+)\)/g, "$1"); } Core.prototype.parseForMedia = function(text, images) { From 07b043c159f99d5d2ee06aee33811b526766d43d Mon Sep 17 00:00:00 2001 From: jeena Date: Fri, 26 Jul 2013 13:48:18 +0200 Subject: [PATCH 16/18] work on profile --- WebKit/scripts/controller/Profile.js | 164 +++++++++----------------- WebKit/scripts/controller/Timeline.js | 9 +- 2 files changed, 61 insertions(+), 112 deletions(-) diff --git a/WebKit/scripts/controller/Profile.js b/WebKit/scripts/controller/Profile.js index 1315c3d..4912ed7 100644 --- a/WebKit/scripts/controller/Profile.js +++ b/WebKit/scripts/controller/Profile.js @@ -2,32 +2,28 @@ define([ "helper/HostApp", "helper/Core", "helper/APICalls", - "lib/URI" + "lib/URI", + "controller/Timeline" ], -function(HostApp, Core, APICalls, URI) { +function(HostApp, Core, APICalls, URI, Timeline) { function Profile() { - Core.call(this); + Timeline.call(this); this.action = "profile"; - this.posts_limit = 25; - this.container = document.createElement("div"); this.container.className = this.action; document.getElementById("content").appendChild(this.container); this.initProfileTemplate(); this.hide(); - - //var _this = this; - //setTimeout(function() { _this.showProfileForEntity() }, 500); // Load users profile on start } - Profile.prototype = Object.create(Core.prototype); + Profile.prototype = Object.create(Timeline.prototype); Profile.prototype.show = function() { @@ -61,6 +57,8 @@ function(HostApp, Core, APICalls, URI) { entity = HostApp.stringForKey("entity"); } + debug(entity) + this.clear(); this.entity = entity; this.following = null; @@ -70,6 +68,7 @@ function(HostApp, Core, APICalls, URI) { this.getProfile(); this.getFollowing(); + this.getStatuses(); } Profile.prototype.initProfileTemplate = function() { @@ -322,8 +321,10 @@ function(HostApp, Core, APICalls, URI) { if (profile) { this.profile = profile; + + // FIXME this.getMeta(this.profile); - //this.getStatuses(this.server); + this.getStatuses(); } } @@ -338,14 +339,13 @@ function(HostApp, Core, APICalls, URI) { Profile.prototype.getMeta = function(profile) { // FIXME! - return; var _this = this; - - var url = HostApp.serverUrl("posts_feed") + "?entities=" + encodeURIComponent(this.entity) + "&types=" + encodeURIComponent("https://tent.io/types/relationship/v0#follower"); +/* + var url = HostApp.serverUrl("posts_feed") + "?entities=" + encodeURIComponent(this.entity) + "&types=" + encodeURIComponent("https://tent.io/types/subscription/v0#"); APICalls.head(url, { callback: function(resp) { - _this.populate(_this.profile_template.followed, APICalls.getCount(resp)+" "); + _this.populate(_this.profile_template.followed, APICalls.getCount(resp) + " "); } }); @@ -356,11 +356,47 @@ function(HostApp, Core, APICalls, URI) { } }); + var url = HostApp.serverUrl("posts_feed") + "?entities=" + encodeURIComponent(this.entity) + "&types=" + encodeURIComponent("https://tent.io/types/status/v0#"); + APICalls.head(url, { + callback: function(resp) { + _this.populate(_this.profile_template.posts, APICalls.getCount(resp) + " "); + } + }); +*/ + + // is following you + // FIXME: should use HEAD + var url = HostApp.serverUrl("posts_feed") + "?entities=" + encodeURIComponent(this.entity) + "&types=" + encodeURIComponent("https://tent.io/types/subscription/v0#https://tent.io/types/status/v0") + "&mentions=" + encodeURIComponent(HostApp.stringForKey("entity")); + APICalls.get(url, { + callback: function(resp) { + var json = JSON.parse(resp.responseText); + if (json.posts.length > 0) { + _this.relationships.following_you = true; + } else { + _this.relationships.following_you = false; + } + _this.setRelationships(); + } + }); + + // is followed by you + // FIXME: should use HEAD + var url = HostApp.serverUrl("posts_feed") + "?mentions=" + encodeURIComponent(this.entity) + "&types=" + encodeURIComponent("https://tent.io/types/subscription/v0#https://tent.io/types/status/v0"); + APICalls.get(url, { + callback: function(resp) { + var json = JSON.parse(resp.responseText); + debug(json) + if (json.posts.length > 0) { + _this.relationships.followed_by_you = true; + } else { + _this.relationships.followed_by_you = false; + } + _this.setRelationships(); + } + }); + return; - - - - +/* if (this.entity != HostApp.stringForKey("entity")) { @@ -395,7 +431,7 @@ function(HostApp, Core, APICalls, URI) { APICalls.http_call(url.toString(), "GET", function(resp) { _this.populate(_this.profile_template.posts, resp.responseText); - }, null, false); + }, null, false);*/ } Profile.prototype.setRelationships = function() { @@ -415,93 +451,9 @@ function(HostApp, Core, APICalls, URI) { } - Profile.prototype.getStatuses = function(root_url, add_search, append) { - var _this = this; - - add_search = add_search || {}; - - var url = URI(root_url + "/posts"); - url.addSearch("limit", this.posts_limit); - - var post_types = [ - "https://tent.io/types/post/repost/v0.1.0", - "https://tent.io/types/post/status/v0.1.0", - "https://tent.io/types/post/photo/v0.1.0" - ]; - url.addSearch("post_types", post_types.join(",")); - - for(var key in add_search) { - url.addSearch(key, add_search[key]); - } - - APICalls.http_call(url.toString(), "GET", function(resp) { - - var statuses = JSON.parse(resp.responseText); - - _this.newStatus(statuses, append); - - }, null, false); - } - - - Profile.prototype.newStatus = function(statuses, append) { - - if(statuses != null && statuses.length > 0) { - - this.before.loading = false; - - if (append) statuses = statuses.reverse(); - - for(var i = statuses.length-1, c=0; i>=c; --i) { - - var status = statuses[i]; - - if (status.type == "https://tent.io/types/post/status/v0.1.0" || status.type == "https://tent.io/types/post/photo/v0.1.0") { - - var new_node = this.getStatusDOMElement(status); - - if(!append && this.body.childNodes.length > 0) { - - if(this.body.childNodes.length > this.max_length) { - - this.body.removeChild(this.body.lastChild); - } - - this.body.insertBefore(new_node, this.body.firstChild); - - } else { - - this.body.appendChild(new_node); - } - - } else if (status.type == "https://tent.io/types/post/delete/v0.1.0") { - - var li = document.getElementById("post-" + status.content.id + "-" + this.action); - if (li) { - this.body.removeChild(li); - } - } else if (status.type == "https://tent.io/types/post/repost/v0.1.0") { - - this.getRepost(status, this.body.firstChild); - } - - } - } - } - - Profile.prototype.getMoreStatusPosts = function() { - if (!this.before.loading) { - this.before.loading = true; - var add_search = { - "before_id": this.body.lastChild.status.id, - "before_id_entity": this.body.lastChild.status.entity - } - this.getStatuses(this.server, add_search, true); - } - } - - Profile.prototype.mention = function() { + Profile.prototype.getStatuses = function() { + Timeline.prototype.getNewData.call(this, {entities: this.entity}); } Profile.prototype.setFollowingButton = function(following) { @@ -533,6 +485,7 @@ function(HostApp, Core, APICalls, URI) { } else { _this.setFollowingButton(true); } + _this.getMeta(); }}); } else { @@ -561,6 +514,7 @@ function(HostApp, Core, APICalls, URI) { } else { _this.setFollowingButton(false); } + _this.getMeta(); } }); } diff --git a/WebKit/scripts/controller/Timeline.js b/WebKit/scripts/controller/Timeline.js index 3f0bf11..4c0cf8a 100644 --- a/WebKit/scripts/controller/Timeline.js +++ b/WebKit/scripts/controller/Timeline.js @@ -132,11 +132,6 @@ function(Core, APICalls, HostApp, URI) { uri.addSearch("max_refs", 20); uri.addSearch("profiles", "entity"); - if(this.since_id && !append) { - uri.addSearch("since_id", this.since_id); - uri.addSearch("since_id_entity", this.since_id_entity); - } - for (key in add_to_search) { uri.addSearch(key, add_to_search[key]); } @@ -147,12 +142,12 @@ function(Core, APICalls, HostApp, URI) { url += query; } - var data = null; - if (HostApp.stringForKey("user_access_token")) { if (!this.reload_blocked) { this.reload_blocked = true; + + debug(url) APICalls.get(url, { callback: function(resp) { From 5f55bb9b0d5f8530e87b892b9c409ba0d20bb9ea Mon Sep 17 00:00:00 2001 From: jeena Date: Sun, 1 Sep 2013 15:07:01 +0200 Subject: [PATCH 17/18] removed debug stuff --- WebKit/scripts/controller/NewPost.js | 3 --- WebKit/scripts/controller/Profile.js | 6 +++--- WebKit/scripts/controller/Timeline.js | 3 +-- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/WebKit/scripts/controller/NewPost.js b/WebKit/scripts/controller/NewPost.js index 6638b45..078848b 100644 --- a/WebKit/scripts/controller/NewPost.js +++ b/WebKit/scripts/controller/NewPost.js @@ -295,14 +295,11 @@ function(APICalls, HostApp) { data.mentions = mentions; - debug(data.mentions) - // Make tent flavored markdown mentions for (var i = 0; i < this.mentions.length; i++) { var mention = this.mentions[i]; data.content.text = this.replaceAll(data.content.text, mention.name, "^[" + mention.name + "](" + i + ")") } - debug(data.content.text) APICalls.post(HostApp.serverUrl("new_post"), JSON.stringify(data), { content_type: data.type, diff --git a/WebKit/scripts/controller/Profile.js b/WebKit/scripts/controller/Profile.js index 4912ed7..840eed9 100644 --- a/WebKit/scripts/controller/Profile.js +++ b/WebKit/scripts/controller/Profile.js @@ -57,8 +57,6 @@ function(HostApp, Core, APICalls, URI, Timeline) { entity = HostApp.stringForKey("entity"); } - debug(entity) - this.clear(); this.entity = entity; this.following = null; @@ -385,7 +383,6 @@ function(HostApp, Core, APICalls, URI, Timeline) { APICalls.get(url, { callback: function(resp) { var json = JSON.parse(resp.responseText); - debug(json) if (json.posts.length > 0) { _this.relationships.followed_by_you = true; } else { @@ -504,6 +501,9 @@ function(HostApp, Core, APICalls, URI, Timeline) { type: "https://tent.io/types/subscription/v0#https://tent.io/types/status/v0" }; + debug(data) + debug(url) + APICalls.post(url, JSON.stringify(data), { content_type: data.type, callback: function(resp) { diff --git a/WebKit/scripts/controller/Timeline.js b/WebKit/scripts/controller/Timeline.js index 4c0cf8a..43db2d3 100644 --- a/WebKit/scripts/controller/Timeline.js +++ b/WebKit/scripts/controller/Timeline.js @@ -146,10 +146,9 @@ function(Core, APICalls, HostApp, URI) { if (!this.reload_blocked) { this.reload_blocked = true; - debug(url) - APICalls.get(url, { callback: function(resp) { + debug(resp.responseText) those.reload_blocked = false; From a8b58216de40b3c63cab512f53a7133a90acb750 Mon Sep 17 00:00:00 2001 From: jeena Date: Tue, 3 Sep 2013 13:06:35 +0200 Subject: [PATCH 18/18] added permissions scope --- WebKit/scripts/controller/NewPost.js | 1 + WebKit/scripts/controller/Oauth.js | 3 ++- WebKit/scripts/controller/Timeline.js | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/WebKit/scripts/controller/NewPost.js b/WebKit/scripts/controller/NewPost.js index 078848b..cd33d35 100644 --- a/WebKit/scripts/controller/NewPost.js +++ b/WebKit/scripts/controller/NewPost.js @@ -16,6 +16,7 @@ function(APICalls, HostApp) { this.mentions = []; document.body.className = "new_post"; + this.is_private = false; // Textarea diff --git a/WebKit/scripts/controller/Oauth.js b/WebKit/scripts/controller/Oauth.js index 9999826..7967c12 100644 --- a/WebKit/scripts/controller/Oauth.js +++ b/WebKit/scripts/controller/Oauth.js @@ -35,7 +35,8 @@ function(HostApp, APICalls, Hmac) { "https://tent.io/types/photo/v0", "https://tent.io/types/cursor/v0" ] - } + }, + "scopes": ["permissions"] }, "permissions": { "public": false diff --git a/WebKit/scripts/controller/Timeline.js b/WebKit/scripts/controller/Timeline.js index 43db2d3..c7d9331 100644 --- a/WebKit/scripts/controller/Timeline.js +++ b/WebKit/scripts/controller/Timeline.js @@ -146,9 +146,9 @@ function(Core, APICalls, HostApp, URI) { if (!this.reload_blocked) { this.reload_blocked = true; - debug(url) + APICalls.get(url, { callback: function(resp) { - debug(resp.responseText) + // FIXME this is getting data when it shouldn't debug(resp.responseText) those.reload_blocked = false;