fix invalid recipient error on reply. small fix to message list css
[progetti-gl-como:friendica-messenger.git] / www / js / index.js
1
2
3 function url(endpoint){
4         return (app.settings.opts.secure?"https://":"http://") + app.settings.opts.user + ":" + app.settings.opts.pass + "@" + app.settings.opts.host + "/api/" + endpoint + "?callback=?";
5 }
6
7 /**
8  * Message List Object
9  */
10 function MessageList(sel_elm){
11         this.elm = $(sel_elm);
12 }
13
14
15 MessageList.prototype.update = function(clb){
16         $.getJSON(url("direct_messages"), {getText:"plain"}, function(data, status){
17                 //console.log(status);
18                 var senders = [];
19                 var out="";
20                 for (k in data) {
21                         var msg = data[k];
22                         if (senders.indexOf(msg.sender_screen_name)<0){
23                                 senders.push(msg.sender_screen_name);
24                                 out += "<li>";
25                                 out += "<aside class='pack'><img src='"+ msg.sender.profile_image_url + "'></aside>";
26                                 out += "<a href='#message/"+msg.sender_screen_name+"'>";
27                                 out += "<p>" + msg.text + "</p>";
28                                 out += "<p>" + msg.sender_screen_name + " - " + msg.created_at + "</p>";
29                                 out += "</a>";
30                                 out += "</li>";
31                         }
32                 }
33
34                 this.elm.html(out);
35                 if(clb) clb(data);
36         }.bind(this));
37 };
38
39
40 /**
41  * Conversation with a user
42  */
43 function Messages(sel_elm){
44         this.elm = $(sel_elm);
45         this.username = null;
46     this.reply_id = null;
47 }
48
49 Messages.prototype.update = function(username, clb) {
50         if (username) {
51                 this.username = username;
52         } else {
53                 username = this.username;
54         }
55         
56         if (!username) return;
57         
58         $("#contact_screen_name").html(username);
59         
60         $.getJSON(url("direct_messages/all"), {getText:"html", screen_name: username}, function(data, status){
61                 //console.log(data, status);
62                 data.reverse();
63                 var out="";
64                 var pack="";
65                 var reply_id; // id of the message to reply to. should be the last.
66                 for (k in data) {
67                         var msg = data[k];
68                         out += "<li>";
69                         pack = (msg.sender_screen_name==username ? "pack": "pack-end"); 
70                         out += "<aside class='"+pack+"'><img src='"+ msg.sender.profile_image_url + "'></aside>";
71                         //out += "<a href='#message/"+msg.sender_screen_name+"'>";
72                         out += "<p>" + msg.text + "</p>";
73                         out += "<p>" + msg.sender_screen_name + " - " + msg.created_at + "</p>";
74                         //out += "</a>";
75                         out += "</li>";
76                         reply_id = msg.id;
77                 }
78                 
79                 /* reply form */
80                 $(".message_text").val("");
81                 this.reply_id = reply_id;
82                 
83                 this.elm.html(out);
84                 if(clb) clb(data);
85         }.bind(this));
86         
87 };
88
89 Messages.prototype.reply = function(clb){
90     app.compose.send(clb, this.username, this.reply_id);
91 };
92
93 /**
94  * Send Message
95  */
96 function Compose(sel_elm){
97         this.elm = $(sel_elm);
98         this.dialog = this.elm.find("#select_contact");
99         
100         this.contact_photo = this.elm.find(".contact_photo");
101         this.contact_photo_empty = this.contact_photo.attr("src");
102         
103         
104         this.friends = {};
105         this.last_update = 0;
106
107         
108         /* contact list dialog */
109         this.dialog.hide();
110         
111         this.contact_photo.on("click",function(e){
112                 var out="";
113                 for (k in this.friends) {
114                         var f = this.friends[k];
115                         out += "<button type='button' value='"+k+"' class='contact_item'><img src='"+f.profile_image_url+"'>"+f.name+" ("+f.screen_name+")</button>";
116                 }
117                 out += '<button type="button" class="cancel">Cancel</button>';
118                 
119                 this.dialog.find("menu").html(out);
120                 this.dialog.show();
121
122                 this.dialog.find(".contact_item").on("click", function(e){
123                         $(".message_to").val( $(e.target).val() );
124                         $(".message_to").trigger("input");
125                         this.dialog.hide();
126                 }.bind(this));
127                 
128                 this.dialog.find(".cancel").on("click", function(){
129                         this.dialog.hide();
130                 }.bind(this));
131                 
132         }.bind(this));
133         /* /contact list dialog */
134         
135         this.elm.find(".message_to").on('input', function(e){
136                 var f=$(e.target).val().trim();
137                 if (this.friends[f] !== undefined) {
138                         this.contact_photo.attr("src",this.friends[f].profile_image_url);
139                 } else {
140                         this.contact_photo.attr("src", this.contact_photo_empty);
141                 }
142         }.bind(this));
143         
144         // get friend list
145         this.update();
146         
147 }
148
149 Compose.prototype.update = function(clb){
150         if (this.last_update > (new Date())-60000) {
151                 if (clb) clb(this.friends);
152                 return;
153         }
154         var dl = this.elm.find("#contacts");
155         
156         $.getJSON(url("statuses/friends"), {}, function(data, status) {
157                 var out="";
158                 this.friends = {};
159                 for (k in data){
160                         var friend = data[k];
161                         if (friend.network == "dfrn") {
162                                 this.friends[friend.screen_name] = friend;
163                                 out += "<option value='"+friend.screen_name+"'>"+friend.name+" ("+friend.screen_name+")</option>";
164                         }
165                 }
166                 this.last_update = (new Date()) - 0;
167                 dl.html(out);
168                 if (clb) clb(data);
169         }.bind(this));
170         
171 };
172
173 Compose.prototype.send = function(clb, send_to, reply_id){
174         
175         var screen_name;
176         var replyto = (reply_id?reply_id:$(".message_reply").val());
177         var text = $(".message_body").val();
178         if (text=="")
179                 text = $(".message_text").val();
180
181         if (text=="") {
182                 alert("Please enter the message body");
183                 return;
184         }
185
186     if (send_to!==undefined) {
187         screen_name = send_to;
188     } else {
189         screen_name  = $(".message_to").val().trim();
190         if (screen_name=="" || this.friends[screen_name]==undefined){
191                 alert("Please enter a valid recipient");
192                 return;
193         }
194         }
195         
196         /**
197                 WARNING: HACK AHEAD!
198
199                 Friendica doesn't set CORS headers (it should.. open a feature request!)
200                 We can't send post requests via ajax on different domains without it 
201                 (we can get with jsonp, wich is another hack, but standard...)
202                 We create an iframe, append it to body and create a form wich post data to
203                 remote server.
204                 We listen for 'load' event to know when the request returned data, so we
205                 can update the message list.
206                 We sould remove it when finished.
207                 We could read the content of the iframe before removeit as it would be json
208                 reply from API...
209         **/
210
211
212         var f = $("<iframe>").appendTo($("body")).hide();
213         
214         f.on('load', function() {
215                 if (clb){
216                         clb({
217                                 screen_name:screen_name,
218                                 replyto:replyto,
219                                 text:text
220                         });
221                 }
222         });
223         // we need a small timeout before we can write to iframe content
224         setTimeout( function() {
225                 var doc = f[0].contentWindow.document;
226                 // build the form
227                 var form = $("<form>").attr('action', url("direct_messages/new")).attr('method','POST').append(
228                                 $("<input>").attr('name','screen_name').val(screen_name)
229                         ).append(
230                                 $("<input>").attr('name','text').val(text)
231                         );
232                 if (replyto!=="") form.append(
233                         $("<input>").attr('name','replyto').val(replyto)
234                 );
235                 $('body',doc).append(form);
236                 // send the form!
237                 form.submit();
238         }, 1 );
239 };
240
241 /**
242  * App settings
243  */
244 function Settings(sel_elm) {
245         this.elm = $(sel_elm);
246         this.update();
247         
248         
249         this.elm.find(".autoupdate").on("blur", function(e,b){ 
250                 var val =  $(e.target).val();
251                 if (e.target.type=="checkbox") val = $(e.target).prop('checked');
252                 this.set(e.target.id, val);
253         }.bind(this));
254 }
255         
256 Settings.prototype.update = function(clb) {
257         this.opts = JSON.parse( window.localStorage.getItem("opts") );
258         if (this.opts === null) this.opts={};
259
260         var input_elm;
261         for (k in this.opts) {
262                 input_elm= this.elm.find("#"+k);
263                 if (input_elm.prop("type")=="checkbox") {
264                         input_elm.prop("checked", this.opts[k])
265                 } else {
266                         input_elm.val(this.opts[k]);
267                 }
268         }
269         if(clb) clb();
270 };
271         
272 Settings.prototype.is_valid = function() {
273         return this.opts !== null && 
274               this.opts.host !== undefined && this.opts.host !== "" && 
275               this.opts.user !== undefined && this.opts.user !== "" && 
276               this.opts.pass !== undefined && this.opts.pass !=="";
277 };
278         
279 Settings.prototype.set = function(name, value) {
280         this.opts[name] = value;
281         window.localStorage.setItem("opts", JSON.stringify(this.opts));
282 };
283
284
285
286 /**
287  * App Object
288  */
289 var app = {
290     // Application Constructor
291     initialize: function() {
292                 app.settings = new Settings("#settingsPage");
293                 app.messagelist = new MessageList("#messageList");
294                 app.messages    = new Messages("#messages");
295                 app.compose             = new Compose("#newMessagePage");
296                 
297                 routie({
298                         '': app.page_messageList,
299                         'settings' : app.page_settings,
300                         'compose'  : app.page_compose,
301                         'message/:user': app.page_messageUser
302                 });
303                 
304                 
305         this.bindEvents();
306     },
307         
308         page_messageList : function(){
309                 if (!app.settings.is_valid()) {
310                         /* alert("Please fill required settings"); */
311                         routie("settings");
312                         return;
313                 }
314                 app.messagelist.update(function(){
315                         if ($("body > .current").length>0) { 
316                                 $("body > .current").removeClass("current").addClass("right");
317                                 $("#inboxPage").addClass("current");
318                         }
319                 });
320         },
321         
322         page_messageUser : function(user) {
323
324                 app.messages.update(user, function(){
325                         
326                         var ofs = $("#messages li:last-of-type").offset();
327                         if (ofs !== null)
328                                 $("#messagePage .scrollable").scrollTop(ofs.top);
329                         
330                         $("#inboxPage").removeClass("current").addClass("left");
331                         $("#messagePage").removeClass("right").addClass("current");
332                 });
333         },
334         
335         page_settings : function() {
336                 app.settings.update(function(){
337                         $("#inboxPage").removeClass("current").addClass("left");
338                         $("#settingsPage").removeClass("right").addClass("current");
339                 });             
340         },
341         
342         page_compose : function() {
343                 $(".message_body").val("");
344                 $(".message_to").val("");
345                 $(".message_reply").val("");
346                 app.compose.contact_photo.attr("src", app.compose.contact_photo_empty);
347                 
348                 app.compose.update(function(){
349                         $("#inboxPage").removeClass("current").addClass("left");
350                         $("#newMessagePage").removeClass("right").addClass("current");
351                 });
352         },
353         
354     bindEvents: function() {
355         
356                 
357                 /* send reply */
358                 $("#reply_send").on("click", function(e){
359                         e.preventDefault();
360                         app.messages.reply(function(){
361                                 app.messages.update();
362                         });
363                 });
364                 
365                 /* send new message */
366                 $("#message_send").on("click", function(e){
367                         e.preventDefault();
368                         app.compose.send(function(data){
369                                 // dovrebbe andare a message/data.screen_name
370                                 // ma per come รจ fatto al momento non funziona...
371                                 // torniamo alla lista messaggi
372                                 routie("");
373                         });
374                 });
375                 
376                 
377     }
378 };
379
380 $("progress").hide();
381 $.ajaxSettings.beforeSend = function() { $("progress").show(); }
382 $.ajaxSettings.complete = function() { $("progress").hide(); }
383
384
385 app.initialize();