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