Processed all outstanding update submissions
[webos-internals:modifications.git] / messaging / messaging-poor-mans-twitter-client.patch
1 diff --git a/usr/palm/applications/com.palm.app.messaging/app/controllers/chatview-assistant.js b/usr/palm/applications/com.palm.app.messaging/app/controllers/chatview-assistant.js
2 index 484cd45..b62863a 100644
3 --- a/usr/palm/applications/com.palm.app.messaging/app/controllers/chatview-assistant.js
4 +++ b/usr/palm/applications/com.palm.app.messaging/app/controllers/chatview-assistant.js
5 @@ -1807,9 +1807,255 @@ var ChatviewAssistant = Class.create({
6                         this.addTextToClipboard(text);
7                 } else if (value === 'delete-cmd') {
8                         this.handleMessageDeleteFromContextMenu(messageId, index);
9 +               } else if (value === "twitter-retweet-cmd") {
10 +                       Mojo.Log.info("twitter-retweet-cmd");
11 +                       this.twitterRetweet(text);
12 +               } else if (value === "twitter-reply-cmd") {
13 +                       Mojo.Log.info("twitter-reply-cmd");
14 +                       this.twitterReply(text);
15 +               } else if (value === "twitter-direct-reply-cmd") {
16 +                       Mojo.Log.info("twitter-direct-reply-cmd");
17 +                       this.twitterDirectReply(text);
18 +               } else if (value === "twitter-leave-user-cmd") {
19 +                       Mojo.Log.info("twitter-leave-user-cmd");
20 +                       this.twitterLeaveUser(text);
21 +               } else if (/^twitter-user:/.test(value)) {
22 +                       var username = RegExp.rightContext;
23 +                       var url = "http://twitter.com/" + username;
24 +                       var params = {
25 +                               scene: "page",
26 +                               target: url
27 +                       };
28 +                       var request = new Mojo.Service.Request("palm://com.palm.applicationManager", {
29 +                               method: 'launch',
30 +                               parameters: {'id': "com.palm.app.browser", 'params': params}
31 +                       });
32 +               }
33 +       },
34 +
35 +       twitterSkipChain: function (body) {
36 +               var originally_from, chainlink, result;
37 +               var modified = false;
38 +               Mojo.Log.info("twitterSkipChain(%j)", body);
39 +               while (true) {
40 +                       // skip past any RT/via chains.
41 +                       if (/^\s*rt(?:\s*@\s*|\s+)([_A-Za-z0-9]+)(?:\s*:\s*|\s+)/i.test(body)) {
42 +                               // RT@user:... (space optional before or after @ and :)
43 +                               // RT user ...
44 +                               chainlink       = RegExp.match;
45 +                               originally_from = RegExp.$1;
46 +                               body            = RegExp.rightContext;
47 +                               Mojo.Log.info("twitterSkipChain: skipping 'RT' chain link: %j", chainlink);
48 +                               modified = true;
49 +                       }
50 +                       else if (/^\s*(?:[\(\[\{]\s*)?via(?:\s*@\s*|\s+)[_A-Za-z0-9]+(?:\s*[\)\]\}])?(?:\s*:\s*|\s+)/i.test(body)) {
51 +                               // (via@user):...
52 +                               //  via user  ...
53 +                               chainlink = RegExp.match;
54 +                               body      = RegExp.rightContext;
55 +                               Mojo.Log.info("twitterSkipChain: skipping 'via' chain link: %j", chainlink);
56 +                               modified = true;
57 +                       }
58 +                       else {
59 +                               break;
60 +                       }
61 +               }
62 +               if (modified) {
63 +                       result = {
64 +                               body: body,
65 +                               originally_from: originally_from
66 +                       };
67                 }
68 +               Mojo.Log.info("twitterSkipChain: returning %j", result);
69 +               return result;
70 +       },
71 +
72 +       twitterParseMessage: function (text) {
73 +               var from, originally_from, body, chain, result, match;
74 +               var mentioned = {};
75 +               var theMentioned = [];
76 +               var addMention = function (username) {
77 +                       Mojo.Log.info("ADDMENTION: %s", username);
78 +                       var usernameLower = username.toLowerCase();
79 +                       Mojo.Log.info("ADDMENTION: %s", usernameLower);
80 +                       if (!(usernameLower in mentioned)) {
81 +                               Mojo.Log.info(":)");
82 +                               mentioned[usernameLower] = true;
83 +                               theMentioned.push(username);
84 +                       }
85 +               };
86 +               Mojo.Log.info("twitterParseMessage(%j)", text);
87 +               if (/^Direct from (\S+):\s*(.*)/i.test(text)) {
88 +                       from = RegExp.$1;
89 +                       body = RegExp.$2;
90 +                       result = {
91 +                               direct: true,
92 +                               from: from,
93 +                               body: body,
94 +                               mentioned: theMentioned
95 +                       };
96 +                       addMention(from);
97 +               }
98 +               else if (/^(\S+):\s*(.*)/.test(text)) {
99 +                       from = RegExp.$1;
100 +                       originally_from = from;
101 +                       body = RegExp.$2;
102 +                       chain = this.twitterSkipChain(body);
103 +                       if (chain) {
104 +                               if ("originally_from" in chain) {
105 +                                       originally_from = chain.originally_from;
106 +                               }
107 +                               body = chain.body;
108 +                       }
109 +                       result = {
110 +                               direct: false, 
111 +                               from: from,
112 +                               originally_from: originally_from,
113 +                               body: body,
114 +                               mentioned: theMentioned
115 +                       };
116 +                       addMention(from);
117 +                       addMention(originally_from);
118 +               }
119 +
120 +               var match;
121 +               var rx_user = /\@([_A-Za-z0-9]+)/g;
122 +               while ((match = rx_user.exec(text)) !== null) {
123 +                       addMention(match[1]);
124 +               }
125 +
126 +               Mojo.Log.info("twitterParseMessage: returning %j", result);
127 +               return result;
128 +       },
129 +
130 +       twitterRetweet: function (text) {
131 +               Mojo.Log.info("twitterRetweet(%j)", text);
132 +               var tweet = this.twitterParseMessage(text);
133 +               if (tweet) {
134 +                       Mojo.Log.info("twitterRetweet: is an actionable tweet.");
135 +                       if (tweet.direct) {
136 +                               this.twitterErrorDialog("You cannot retweet a direct message.");
137 +                       }
138 +                       else {
139 +                               if (tweet.originally_from === tweet.from) {
140 +                                       this.twitterSetTextFieldValue(
141 +                                               "RT @" + tweet.originally_from + ": " + tweet.body
142 +                                       );
143 +                               }
144 +                               else {
145 +                                       this.twitterSetTextFieldValue(
146 +                                               "RT @" + tweet.originally_from +
147 +                                                       " via @" + tweet.from + ": " + tweet.body
148 +                                       );
149 +                               }
150 +                       }
151 +               }
152 +               else {
153 +                       Mojo.Log.info("twitterRetweet: is not an actionable tweet.");
154 +               }
155 +       },
156 +
157 +       twitterErrorDialog: function (error) {
158 +               this.controller.showAlertDialog({
159 +                       onChoose: function () { },
160 +                       title: $L("Error"),
161 +                       message: $L(error),
162 +                       preventCancel: false,
163 +                       choices: [{ label: $L('Dismiss'), value: 'Dismiss' }]
164 +               });
165         },
166         
167 +       twitterWarningDialog: function (warning) {
168 +               this.controller.showAlertDialog({
169 +                       onChoose: function () { },
170 +                       title: $L("Warning"),
171 +                       message: $L(warning),
172 +                       preventCancel: false,
173 +                       choices: [{ label: $L('OK'), value: 'OK' }]
174 +               });
175 +       },
176 +
177 +       twitterSetTextFieldValue: function (text) {
178 +               var self = this;
179 +               var value = this.messageTextElement.value;
180 +               if (/\S/.test(value)) {
181 +                       this.controller.showAlertDialog({
182 +                               onChoose: function (choice) {
183 +                                       if (choice) {
184 +                                               self.twitterSetTextFieldValueRaw(text);
185 +                                       }
186 +                               },
187 +                               title: "Erase existing message?",
188 +                               message: "Your current message:\n" + value,
189 +                               preventCancel: false,
190 +                               choices: [{ label: $L('Yes'), value: true },
191 +                                         { label: $L('No'),  value: false }]
192 +                       });
193 +               }
194 +               else {
195 +                       this.twitterSetTextFieldValueRaw(text);
196 +               }
197 +       },
198 +
199 +       twitterSetTextFieldValueRaw: function (text) {
200 +               this.setTextFieldValue(text);
201 +               this.moveCursorToEndOfTextField();
202 +               if (text.length > 140) {
203 +                       this.twitterWarningDialog("Your submission is longer than 140 characters. " + 
204 +                                                 "Please shorten before sending.");
205 +               }
206 +       },
207 +
208 +       twitterReply: function (text) {
209 +               Mojo.Log.info("twitterReply(%j)", text);
210 +               var tweet = this.twitterParseMessage(text);
211 +               if (tweet) {
212 +                       Mojo.Log.info("twitterReply: is an actionable tweet.");
213 +                       this.twitterSetTextFieldValue("@" + tweet.from + " ");
214 +               }
215 +               else {
216 +                       Mojo.Log.info("twitterReply: is not an actionable tweet.");
217 +               }
218 +       },
219 +       
220 +       twitterDirectReply: function (text) {
221 +               Mojo.Log.info("twitterDirectReply(%j)", text);
222 +               var tweet = this.twitterParseMessage(text);
223 +               if (tweet) {
224 +                       Mojo.Log.info("twitterReply: is an actionable tweet.");
225 +                       this.twitterSetTextFieldValue("D " + tweet.from + " ");
226 +               }
227 +               else {
228 +                       Mojo.Log.info("twitterReply: is not an actionable tweet.");
229 +               }
230 +       },
231 +       
232 +       twitterLeaveUser: function (text) {
233 +               Mojo.Log.info("twitterLeaveUser(%j)", text);
234 +               var tweet = this.twitterParseMessage(text);
235 +               if (tweet) {
236 +                       Mojo.Log.info("twitterLeaveUser: is an actionable tweet.");
237 +                       if (tweet.direct) {
238 +                               this.twitterSetTextFieldValue("leave " + tweet.from);
239 +                       }
240 +                       else {
241 +                               this.twitterSetTextFieldValue("leave " + tweet.from);
242 +                       }
243 +               }
244 +               else {
245 +                       Mojo.Log.info("twitterLeaveUser: is not an actionable tweet.");
246 +               }
247 +       },
248 +
249 +       moveCursorToEndOfTextField: function () {
250 +               var widget = this.controller.get('messageTextWidget');
251 +               if (widget) {
252 +                       widget = widget.mojo;
253 +               }
254 +               var len = widget.getValue().length;
255 +               widget.setCursorPosition(len, len);
256 +       },
257 +
258         /**
259          * context menu handler for tap on MMS in chat list
260          * 
261 @@ -1946,15 +2192,45 @@ var ChatviewAssistant = Class.create({
262                         
263                         var composeParams;
264                         if ((messageType === "SMS") || (messageType === "IM")) {
265 +                               var menuItems = [
266 +                                       {label: $L('Forward'), command: 'forward-cmd'},
267 +                                       {label: $L('Forward Via Email'), command: 'forward-as-email-cmd'},
268 +                                       {label: $L('Copy Text'), command: 'copy-cmd'},
269 +                                       {label: $L('Delete'), command: 'delete-cmd'}
270 +                               ];
271 +                               var lcDisplayName = this.chatDisplayName.toLowerCase();
272 +                               if (lcDisplayName === "twitter" ||
273 +                                   lcDisplayName === "40404") {
274 +                                       var text = event.item.textForCopying;
275 +                                       Mojo.Log.info("MOO");
276 +                                       var tweet = this.twitterParseMessage(text);
277 +                                       if (tweet) {
278 +                                               if (tweet.direct) {
279 +                                                       menuItems.push({ label: $L('DM Reply'),
280 +                                                                        command: 'twitter-direct-reply-cmd' });
281 +                                               }
282 +                                               else {
283 +                                                       menuItems.push({ label: $L('Retweet'),
284 +                                                                        command: 'twitter-retweet-cmd' });
285 +                                                       menuItems.push({ label: $L('Tweet Reply'),
286 +                                                                        command: 'twitter-reply-cmd' });
287 +                                                       menuItems.push({ label: $L('DM Reply'),
288 +                                                                        command: 'twitter-direct-reply-cmd' });
289 +                                               }
290 +                                               menuItems.push({ label: $L('Leave User'),
291 +                                                                command: 'twitter-leave-user-cmd' });
292 +                                               tweet.mentioned.forEach(function (username) {
293 +                                                       menuItems.push({
294 +                                                               label: "@" + username,
295 +                                                               command: 'twitter-user:' + username
296 +                                                       });
297 +                                               });
298 +                                       }
299 +                               }
300                                 this.controller.popupSubmenu({
301                                         onChoose: this.handleContextMenuSelectSmsIm.bind(this, event.item.textForCopying, messageId, event.index),
302                                         placeNear: eventTarget.target,
303 -                                       items: [
304 -                                               {label: $L('Forward'), command: 'forward-cmd'},
305 -                                               {label: $L('Forward Via Email'), command: 'forward-as-email-cmd'},
306 -                                               {label: $L('Copy Text'), command: 'copy-cmd'},
307 -                                               {label: $L('Delete'), command: 'delete-cmd'}
308 -                                       ]
309 +                                       items: menuItems
310                                 });
311  
312                         } else if (messageType === "MMS") {