]> git.mxchange.org Git - friendica-addons.git/blob - jappixmini/jappix/js/roster.js
Merge branch '3.6-rc'
[friendica-addons.git] / jappixmini / jappix / js / roster.js
1 /*
2
3 Jappix - An open social platform
4 These are the roster JS scripts for Jappix
5
6 -------------------------------------------------
7
8 License: AGPL
9 Author: Vanaryon
10 Last revision: 19/05/11
11
12 */
13
14 // Gets the roster items
15 function getRoster() {
16         var iq = new JSJaCIQ();
17         
18         iq.setType('get');
19         iq.setQuery(NS_ROSTER);
20         
21         con.send(iq, handleRoster);
22 }
23
24 // Handles the roster items
25 function handleRoster(iq) {
26         // Define some variables
27         var handleXML = iq.getQuery();
28         var current, xid, dName, subscription, group, xidHash, getNick, nick;
29         
30         // Parse the vcard xml
31         $(handleXML).find('item').each(function() {
32                 parseRoster($(this), 'load');
33         });
34         
35         // Update our avatar (if changed), and send our presence
36         getAvatar(getXID(), 'force', 'true', 'forget');
37         
38         logThis('Roster received.');
39 }
40
41 // Parses the group XML and display the roster
42 function parseRoster(current, mode) {
43         // Get the values
44         xid = current.attr('jid');
45         dName = current.attr('name');
46         subscription = current.attr('subscription');
47         xidHash = hex_md5(xid);
48         
49         // Create an array containing the groups
50         var groups = new Array();
51         
52         current.find('group').each(function() {
53                 var group_text = $(this).text();
54                 
55                 if(group_text)
56                         groups.push(group_text);
57         });
58         
59         // No group?
60         if(!groups.length)
61                 groups.push(_e("Unclassified"));
62         
63         // If no name is defined, we get the default nick of the buddy
64         if(!dName)
65                 dName = getXIDNick(xid);
66         
67         displayRoster(xid, xidHash, dName, subscription, groups, mode);
68 }
69
70 // Updates the roster groups
71 function updateGroups() {
72         $('#buddy-list .one-group').each(function() {
73                 // Current values
74                 var check = $(this).find('.buddy').size();
75                 var hidden = $(this).find('.buddy:not(.hidden-buddy:hidden)').size();
76                 
77                 // Special case: the filtering tool
78                 if(SEARCH_FILTERED)
79                         hidden = $(this).find('.buddy:visible').size();
80                 
81                 // If the group is empty
82                 if(!check)
83                         $(this).remove();
84                 
85                 // If the group contains no online buddy (and is not just hidden)
86                 if(!hidden && $(this).find('a.group').hasClass('minus'))
87                         $(this).hide();
88                 else
89                         $(this).show();
90         });
91 }
92
93 // Displays a defined roster item
94 function displayRoster(dXID, dXIDHash, dName, dSubscription, dGroup, dMode) {
95         // First remove the buddy
96         $('#buddy-list .' + dXIDHash).remove();
97         
98         // Define some things around the groups
99         var is_gateway = isGateway(dXID);
100         var gateway = '';
101         
102         if(is_gateway) {
103                 gateway = ' gateway';
104                 dGroup = new Array(_e("Gateways"));
105         }
106         
107         // Remove request (empty his social channel)
108         if(dSubscription == 'remove')
109                 $('#channel .mixed .one-update.update_' + dXIDHash).remove();
110         
111         // Other request
112         else {
113                 // Is this buddy blocked?
114                 var privacy_class = '';
115                 var privacy_state = statusPrivacy('block', dXID);
116                 
117                 if(privacy_state == 'deny')
118                         privacy_class = ' blocked';
119                 
120                 // For each group this buddy has
121                 for(i in dGroup) {
122                         var cGroup = dGroup[i];
123                         
124                         if(cGroup) {
125                                 // Process some vars
126                                 var groupHash = 'group' + hex_md5(cGroup);
127                                 var groupContent = '#buddy-list .' + groupHash;
128                                 var groupBuddies = groupContent + ' .group-buddies';
129                                 
130                                 // Is this group blocked?
131                                 if((statusPrivacy('block', cGroup) == 'deny') && (privacy_state != 'allow'))
132                                         privacy_class = ' blocked';
133                                 
134                                 // Group not yet displayed
135                                 if(!exists(groupContent)) {
136                                         // Define some things
137                                         var groupCont = '#buddy-list .content';
138                                         var groupToggle = groupCont + ' .' + groupHash + ' a.group';
139                                         
140                                         // Create the HTML markup of the group
141                                         $(groupCont).prepend(
142                                                 '<div class="' + groupHash + ' one-group" data-group="' + escape(cGroup) + '">' + 
143                                                         '<a href="#" class="group talk-images minus">' + cGroup.htmlEnc() + '</a>' + 
144                                                         '<div class="group-buddies"></div>' + 
145                                                 '</div>'
146                                         );
147                                         
148                                         // Create the click event which will hide and show the content
149                                         $(groupToggle).click(function() {
150                                                 var group = $(groupBuddies);
151                                                 var group_toggle = $(groupContent + ' a.group');
152                                                 
153                                                 // We must hide the buddies
154                                                 if(group_toggle.hasClass('minus')) {
155                                                         group.hide();
156                                                         group_toggle.removeClass('minus').addClass('plus');
157                                                         
158                                                         // Remove the group opened buddy-info
159                                                         closeBubbles();
160                                                 }
161                                                 
162                                                 // We must show the buddies
163                                                 else {
164                                                         group_toggle.removeClass('plus').addClass('minus');
165                                                         group.show();
166                                                 }
167                                                 
168                                                 return false;
169                                         });
170                                 }
171                                 
172                                 // Initialize the HTML code
173                                 var name_code = '<p class="buddy-name">' + dName.htmlEnc() + '</p>';
174                                 var presence_code = '<p class="buddy-presence talk-images unavailable">' + _e("Unavailable") + '</p>';
175                                 
176                                 var html = '<div class="hidden-buddy buddy ibubble ' + dXIDHash + gateway + privacy_class + '" data-xid="' + escape(dXID) + '">' + 
177                                                 '<div class="buddy-click">';
178                                 
179                                 // Display avatar if not gateway
180                                 if(!is_gateway)
181                                         html += '<div class="avatar-container">' + 
182                                                         '<img class="avatar" src="' + './img/others/default-avatar.png' + '" alt="" />' + 
183                                                 '</div>';
184                                 
185                                 html += '<div class="name">';
186                                 
187                                 // Special gateway code
188                                 if(is_gateway)
189                                         html += presence_code +
190                                                 name_code;
191                                 
192                                 else
193                                         html += name_code + 
194                                                 presence_code;
195                                 
196                                 html += '</div></div></div>';
197                                 
198                                 // Create the DOM element for this buddy
199                                 $(groupBuddies).append(html);
200                                 
201                                 // Apply the hover event
202                                 applyBuddyHover(dXID, dXIDHash, dName, dSubscription, dGroup, groupHash);
203                         }
204                 }
205                 
206                 // Click event on this buddy
207                 $('#buddy-list .' + dXIDHash + ' .buddy-click').click(function() {
208                         return checkChatCreate(dXID, 'chat');
209                 });
210                 
211                 // We get the user presence if necessary
212                 if(dMode == 'presence')
213                         presenceFunnel(dXID, dXIDHash);
214                 
215                 // If the buddy must be shown
216                 if(BLIST_ALL)
217                         $('#buddy-list .' + dXIDHash).show();
218         }
219         
220         // We update our groups
221         if(!SEARCH_FILTERED)
222                 updateGroups();
223         else
224                 funnelFilterBuddySearch();
225 }
226
227 // Applies the buddy editing input events
228 function applyBuddyInput(xid) {
229         // Initialize
230         var path = '#buddy-list .buddy[data-xid=' + escape(xid) + ']';
231         var rename = path + ' .bm-rename input';
232         var group = path + ' .bm-group input';
233         var manage_infos = path + ' .manage-infos';
234         var bm_choose = manage_infos + ' div.bm-choose';
235         
236         // Keyup events
237         $(rename).keyup(function(e) {
238                 if(e.keyCode == 13) {
239                         // Send the item
240                         sendRoster(xid, '', trim($(rename).val()), thisBuddyGroups(xid));
241                         
242                         // Remove the buddy editor
243                         closeBubbles();
244                         
245                         return false;
246                 }
247         });
248         
249         $(group).keyup(function(e) {
250                 if(e.keyCode == 13) {
251                         // Empty input?
252                         if(!trim($(this).val())) {
253                                 // Send the item
254                                 sendRoster(xid, '', trim($(rename).val()), thisBuddyGroups(xid));
255                                 
256                                 // Remove the buddy editor
257                                 closeBubbles();
258                                 
259                                 return false;
260                         }
261                         
262                         // Get the values
263                         var this_value = trim($(this).val());
264                         var escaped_value = escape(this_value);
265                         
266                         // Check if the group yet exists
267                         var group_exists = false;
268                         
269                         $(bm_choose + ' label span').each(function() {
270                                 if($(this).text() == this_value)
271                                         group_exists = true;
272                         });
273                         
274                         // Create a new checked checkbox
275                         if(!group_exists)
276                                 $(bm_choose).prepend('<label><input type="checkbox" data-group="' + escaped_value + '" /><span>' + this_value.htmlEnc() + '</span></label>');
277                         
278                         // Check the checkbox
279                         $(bm_choose + ' input[data-group=' + escaped_value + ']').attr('checked', true);
280                         
281                         // Reset the value of this input
282                         $(this).val('');
283                         
284                         return false;
285                 }
286         });
287         
288         // Click events
289         $(manage_infos + ' p.bm-authorize a.to').click(function() {
290                 closeBubbles();
291                 sendSubscribe(xid, 'subscribed');
292                 
293                 return false;
294         });
295         
296         $(manage_infos + ' p.bm-authorize a.from').click(function() {
297                 closeBubbles();
298                 sendSubscribe(xid, 'subscribe');
299                 
300                 return false;
301         });
302         
303         $(manage_infos + ' p.bm-authorize a.unblock').click(function() {
304                 closeBubbles();
305                 
306                 // Update privacy settings
307                 pushPrivacy('block', ['jid'], [xid], ['allow'], ['1'], [false], [true], [true], [true], '', 'roster');
308                 $(path).removeClass('blocked');
309                 
310                 // Enable the "block" list
311                 changePrivacy('block', 'active');
312                 changePrivacy('block', 'default');
313                 
314                 // Send an available presence
315                 sendPresence(xid, 'available', getUserShow(), getUserStatus());
316                 
317                 return false;
318         });
319         
320         $(manage_infos + ' p.bm-remove a.remove').click(function() {
321                 closeBubbles();
322                 sendRoster(xid, 'remove');
323                 
324                 return false;
325         });
326         
327         $(manage_infos + ' p.bm-remove a.prohibit').click(function() {
328                 closeBubbles();
329                 sendSubscribe(xid, 'unsubscribed');
330                 
331                 return false;
332         });
333         
334         $(manage_infos + ' p.bm-remove a.block').click(function() {
335                 closeBubbles();
336                 
337                 // Update privacy settings
338                 pushPrivacy('block', ['jid'], [xid], ['deny'], ['1'], [false], [true], [true], [true], '', 'roster');
339                 $(path).addClass('blocked');
340                 
341                 // Enable the "block" list
342                 changePrivacy('block', 'active');
343                 changePrivacy('block', 'default');
344                 
345                 // Send an unavailable presence
346                 sendPresence(xid, 'unavailable');
347                 
348                 // Remove the user presence
349                 for(var i = 0; i < sessionStorage.length; i++) {
350                         // Get the pointer values
351                         var current = sessionStorage.key(i);
352                         
353                         // If the pointer is on a stored presence
354                         if((explodeThis('_', current, 0) == 'presence') && (bareXID(explodeThis('_', current, 1)) == xid))
355                                 sessionStorage.removeItem(current);
356                 }
357                 
358                 // Manage his new presence
359                 presenceFunnel(xid, hex_md5(xid));
360                 
361                 return false;
362         });
363         
364         $(manage_infos + ' a.save').click(function() {
365                 // Send the item
366                 sendRoster(xid, '', trim($(rename).val()), thisBuddyGroups(xid));
367                 
368                 // Remove the buddy editor
369                 closeBubbles();
370                 
371                 return false;
372         });
373 }
374
375 // Applies the buddy editing hover events
376 function applyBuddyHover(xid, hash, nick, subscription, groups, group_hash) {
377         // Generate the values
378         var bPath = '#buddy-list .' + group_hash + ' .buddy[data-xid=' + escape(xid) + ']';
379         var iPath = bPath + ' .buddy-infos';
380         
381         // Apply the hover event
382         $(bPath).hover(function() {
383                 // Another bubble exist
384                 if(exists('#buddy-list .buddy-infos'))
385                         return false;
386                 
387                 $(bPath).oneTime(200, function() {
388                         // Another bubble exist
389                         if(exists('#buddy-list .buddy-infos'))
390                                 return false;
391                         
392                         // Add this bubble!
393                         showBubble(iPath);
394                         
395                         // Create the buddy infos DOM element
396                         $(bPath).append(
397                                 '<div class="buddy-infos bubble removable">' + 
398                                         '<div class="buddy-infos-subarrow talk-images"></div>' + 
399                                         '<div class="buddy-infos-subitem">' + 
400                                                 '<div class="pep-infos">' + 
401                                                         '<p class="bi-status talk-images unavailable">' + _e("unknown") + '</p>' + 
402                                                         '<p class="bi-mood talk-images mood-four">' + _e("unknown") + '</p>' + 
403                                                         '<p class="bi-activity talk-images activity-exercising">' + _e("unknown") + '</p>' + 
404                                                         '<p class="bi-tune talk-images tune-note">' + _e("unknown") + '</p>' + 
405                                                         '<p class="bi-geoloc talk-images location-world">' + _e("unknown") + '</p>' + 
406                                                         '<p class="bi-view talk-images view-individual"><a href="#" class="profile">' + _e("Profile") + '</a> / <a href="#" class="channel">' + _e("Channel") + '</a> / <a href="#" class="commands">' + _e("Commands") + '</a></p>' + 
407                                                         '<p class="bi-edit talk-images edit-buddy"><a href="#">' + _e("Edit") + '</a></p>' + 
408                                                 '</div>' + 
409                                         '</div>' + 
410                                 '</div>'
411                         );
412                         
413                         // Sets the good position
414                         buddyInfosPosition(xid, group_hash);
415                         
416                         // Get the presence
417                         presenceFunnel(xid, hash);
418                         
419                         // Get the PEP infos
420                         displayAllPEP(xid);
421                         
422                         // Click events
423                         $(bPath + ' .bi-view a').click(function() {
424                                 // Renitialize the buddy infos
425                                 closeBubbles();
426                                 
427                                 // Profile
428                                 if($(this).is('.profile'))
429                                         openUserInfos(xid);
430                                 
431                                 // Channel
432                                 else if($(this).is('.channel'))
433                                         fromInfosMicroblog(xid, hash);
434                                 
435                                 // Command
436                                 else if($(this).is('.commands'))
437                                         retrieveAdHoc(xid);
438                                 
439                                 return false;
440                         });
441                         
442                         $(bPath + ' .bi-edit a').click(function() {
443                                 buddyEdit(xid, nick, subscription, groups);
444                                 
445                                 return false;
446                         });
447                 });
448         }, function() {
449                 if(!exists(iPath + ' .manage-infos'))
450                         closeBubbles();
451                 
452                 $(bPath).stopTime();
453         });
454 }
455
456 // Sets the good buddy-infos position
457 function buddyInfosPosition(xid, group_hash) {
458         // Paths
459         var group = '#buddy-list .' + group_hash;
460         var buddy = group + ' .buddy[data-xid=' + escape(xid) + ']';
461         var buddy_infos = buddy + ' .buddy-infos';
462         
463         // Get the offset to define
464         var offset = 3;
465         
466         if(isGateway(xid))
467                 offset = -8;
468         
469         // Process the position
470         var top = $(buddy).position().top + offset;
471         var left = $(buddy).width() - 10;
472         
473         // Apply the top position
474         $(buddy_infos).css('top', top)
475                       .css('left', left);
476 }
477
478 // Generates an array of the current groups of a buddy
479 function thisBuddyGroups(xid) {
480         var path = '#buddy-list .buddy[data-xid=' + escape(xid) + '] ';
481         var array = new Array();
482         
483         // Each checked checkboxes
484         $(path + 'div.bm-choose input[type=checkbox]').filter(':checked').each(function() {
485                 array.push(unescape($(this).attr('data-group')));
486         });
487         
488         // Entered input value (and not yet in the array)
489         var value = trim($(path + 'p.bm-group input').val());
490         
491         if(value && !existArrayValue(array, value))
492                 array.push(value);
493         
494         return array;
495 }
496
497 // Adds a given contact to our roster
498 function addThisContact(xid, name) {
499         logThis('Add this contact: ' + xid + ', as ' + name, 3);
500         
501         // Cut the resource of this XID
502         xid = bareXID(xid);
503         
504         // If the form is complete
505         if(xid) {
506                 // We send the subscription
507                 sendSubscribe(xid, 'subscribe');
508                 sendRoster(xid, '', name);
509                 
510                 // We hide the bubble
511                 closeBubbles();
512         }
513 }
514
515 // Gets an array of all the groups in the roster
516 function getAllGroups() {
517         var groups = new Array();
518         
519         $('#buddy-list .one-group').each(function() {
520                 var current = unescape($(this).attr('data-group'));
521                 
522                 if((current != _e("Unclassified")) && (current != _e("Gateways")))
523                         groups.push(current);
524         });
525         
526         return groups.sort();
527 }
528
529 // Edits buddy informations
530 function buddyEdit(xid, nick, subscription, groups) {
531         logThis('Buddy edit: ' + xid, 3);
532         
533         // Initialize
534         var path = '#buddy-list .buddy[data-xid=' + escape(xid) + '] .';
535         var html = '<div class="manage-infos">';
536         
537         // Get the privacy state
538         var privacy_state = statusPrivacy('block', xid);
539         var privacy_active = getDB('privacy-marker', 'available');
540         
541         // Get the group privacy state
542         for(g in groups) {
543                 if((statusPrivacy('block', groups[g]) == 'deny') && (privacy_state != 'allow'))
544                         privacy_state = 'deny';
545         }
546         
547         // The subscription with this buddy is not full
548         if((subscription != 'both') || ((privacy_state == 'deny') && privacy_active)) {
549                 var authorize_links = '';
550                 html += '<p class="bm-authorize talk-images">';
551                 
552                 // Link to allow to see our status
553                 if((subscription == 'to') || (subscription == 'none'))
554                         authorize_links += '<a href="#" class="to">' + _e("Authorize") + '</a>';
555                 
556                 // Link to ask to see his/her status
557                 if((subscription == 'from') || (subscription == 'none')) {
558                         if(authorize_links)
559                                 authorize_links += ' / ';
560                         
561                         authorize_links += '<a href="#" class="from">' + _e("Ask for authorization") + '</a>';
562                 }
563                 
564                 // Link to unblock this buddy
565                 if((privacy_state == 'deny') && privacy_active) {
566                         if(authorize_links)
567                                 authorize_links += ' / ';
568                         
569                         html += '<a href="#" class="unblock">' + _e("Unblock") + '</a>';
570                 }
571                 
572                 html += authorize_links + '</p>';
573         }
574         
575         // Complete the HTML code
576         var remove_links = '';
577         html += '<p class="bm-remove talk-images">';
578         remove_links = '<a href="#" class="remove">' + _e("Remove") + '</a>';
579         
580         // This buddy is allowed to see our presence, we can show a "prohibit" link
581         if((subscription == 'both') || (subscription == 'from'))
582                 remove_links += ' / <a href="#" class="prohibit">' + _e("Prohibit") + '</a>';
583         
584         // Complete the HTML code
585         if((privacy_state != 'deny') && privacy_active) {
586                 if(remove_links)
587                         remove_links += ' / ';
588                 
589                 remove_links += '<a href="#" class="block">' + _e("Block") + '</a>';
590         }
591         
592         // Complete the HTML code
593         html += remove_links + 
594                 '</p>' + 
595                 '<p class="bm-rename talk-images"><label>' + _e("Rename") + '</label> <input type="text" value="' + encodeQuotes(nick) + '" /></p>';
596         
597         // Only show group tool if not a gateway
598         if(!isGateway(xid))
599                 html += '<p class="bm-group talk-images"><label>' + _e("Groups") + '</label> <input type="text" /></p>' + 
600                         '<div class="bm-choose">' + 
601                                 '<div></div>' + 
602                         '</div>';
603         
604         // Close the DOM element
605         html += '<a href="#" class="save">' + _e("Save") + '</a>' + 
606                 '</div>';
607         
608         // We update the DOM elements
609         $(path + 'pep-infos').replaceWith(html);
610         
611         // Gets all the existing groups
612         var all_groups = getAllGroups();
613         var all_groups_dom = '';
614         
615         for(a in all_groups) {
616                 // Current group
617                 var all_groups_current = all_groups[a];
618                 
619                 // Is the current group checked?
620                 var checked = '';
621                 
622                 if(existArrayValue(groups, all_groups_current))
623                         checked = ' checked="true"';
624                 
625                 // Add the current group HTML
626                 all_groups_dom += '<label><input type="checkbox" data-group="' + escape(all_groups_current) + '"' + checked + ' /><span>' + all_groups_current.htmlEnc() + '</span></label>';
627         }
628         
629         // Prepend this in the DOM
630         var bm_choose = path + 'manage-infos div.bm-choose';
631         
632         $(bm_choose).prepend(all_groups_dom);
633         
634         // Apply the editing input events
635         applyBuddyInput(xid);
636 }
637
638 // Updates the roster items
639 function sendRoster(xid, subscription, name, group) {
640         // We send the new buddy name
641         var iq = new JSJaCIQ();
642         iq.setType('set');
643         
644         var iqQuery = iq.setQuery(NS_ROSTER);
645         var item = iqQuery.appendChild(iq.buildNode('item', {'xmlns': NS_ROSTER, 'jid': xid}));
646         
647         // Any subscription?
648         if(subscription)
649                 item.setAttribute('subscription', subscription);
650         
651         // Any name?
652         if(name)
653                 item.setAttribute('name', name);
654         
655         // Any group?
656         if(group && group.length) {
657                 for(i in group)
658                         item.appendChild(iq.buildNode('group', {'xmlns': NS_ROSTER}, group[i]));
659         }
660         
661         con.send(iq);
662         
663         logThis('Roster item sent: ' + xid, 3);
664 }
665
666 // Adapts the roster height, depending of the window size
667 function adaptRoster() {
668         // Process the new height
669         var new_height = $('#left-content').height() - $('#my-infos').height() - 97;
670         
671         // New height too small
672         if(new_height < 211)
673                 new_height = 211;
674         
675         // Apply the new height
676         $('#buddy-list .content').css('height', new_height);
677 }
678
679 // Gets all the buddies in our roster
680 function getAllBuddies() {
681         var buddies = new Array();
682         
683         $('#buddy-list .buddy').each(function() {
684                 var xid = unescape($(this).attr('data-xid'));
685                 
686                 if(xid)
687                         buddies.push(xid);
688         });
689         
690         return buddies;
691 }
692
693 // Gets the user gateways
694 function getGateways() {
695         // New array
696         var gateways = new Array();
697         var buddies = getAllBuddies();
698         
699         // Get the gateways
700         for(c in buddies) {
701                 if(isGateway(buddies[c]))
702                         gateways.push(buddies[c]);
703         }
704         
705         return gateways;
706 }
707
708 // Define a global var for buddy list all buddies displayed
709 var BLIST_ALL = false;
710
711 // Addon launcher
712 function launchRoster() {
713         // Filtering tool
714         var iFilter = $('#buddy-list .filter input');
715         var aFilter = $('#buddy-list .filter a');
716         
717         iFilter.placeholder()
718         
719         .blur(function() {
720                 // Nothing is entered, put the placeholder instead
721                 if(!trim($(this).val()))
722                         aFilter.hide();
723                 else
724                         aFilter.show();
725         })
726         
727         .keyup(function(e) {
728                 funnelFilterBuddySearch(e.keyCode);
729         });
730         
731         aFilter.click(function() {
732                 // Reset the input
733                 $(this).hide();
734                 iFilter.val('');
735                 iFilter.placeholder();
736                 
737                 // Security: show all the groups, empty or not
738                 $('#buddy-list .one-group').show();
739                 
740                 // Reset the filtering tool
741                 resetFilterBuddySearch();
742                 
743                 return false;
744         });
745         
746         // When the user click on the add button, show the contact adding tool
747         $('#buddy-list .foot .add').click(function() {
748                 // Yet displayed?
749                 if(exists('#buddy-conf-add'))
750                         return closeBubbles();
751                 
752                 // Add the bubble
753                 showBubble('#buddy-conf-add');
754                 
755                 // Append the content
756                 $('#buddy-list .buddy-list-add').append(
757                         '<div id="buddy-conf-add" class="buddy-conf-item bubble removable">' + 
758                                 '<div class="buddy-conf-subarrow talk-images"></div>' + 
759                                 
760                                 '<div class="buddy-conf-subitem">' + 
761                                         '<p class="buddy-conf-p">' + _e("Add a friend") +  '</p>' + 
762                                         
763                                         '<label><span>' + _e("Address") +  '</span><input type="text" class="buddy-conf-input add-contact-jid" required="" /></label>' + 
764                                         '<label><span>' + _e("Name") +  '</span><input type="text" class="buddy-conf-input add-contact-name" /></label>' +  
765                                         '<label>' + 
766                                                 '<span>' + _e("Gateway") +  '</span>' + 
767                                                 '<select class="buddy-conf-select add-contact-gateway">' + 
768                                                         '<option value="none" selected="">' + _e("None") +  '</option>' + 
769                                                 '</select>' + 
770                                         '</label>' +  
771                                         '<span class="add-contact-name-get">' + _e("Getting the name...") + '</span>' + 
772                                         
773                                         '<p class="buddy-conf-text">' + 
774                                                 '<a href="#" class="buddy-conf-add-search">' + _e("Search a friend") +  '</a>' + 
775                                         '</p>' + 
776                                 '</div>' + 
777                         '</div>'
778                 );
779                 
780                 // Add the gateways
781                 var gateways = getGateways();
782                 
783                 // Any gateway?
784                 if(gateways.length) {
785                         // Append the gateways
786                         for(i in gateways)
787                                 $('.add-contact-gateway').append('<option value="' + escape(gateways[i]) + '">' + gateways[i].htmlEnc() +  '</option>');
788                         
789                         // Show the gateway selector
790                         $('.add-contact-gateway').parent().show();
791                 }
792                 
793                 // No gateway?
794                 else
795                         $('.add-contact-gateway').parent().hide();
796                 
797                 // Blur event on the add contact input
798                 $('.add-contact-jid').blur(function() {
799                         // Read the value
800                         var value = trim($(this).val());
801                         
802                         // Try to catch the buddy name
803                         if(value && !trim($('.add-contact-name').val()) && ($('.add-contact-gateway').val() == 'none')) {
804                                 // User XID
805                                 var xid = generateXID(value, 'chat');
806                                 
807                                 // Notice for the user
808                                 $('.add-contact-name-get').attr('data-for', escape(xid)).show();
809                                 
810                                 // Request the user vCard
811                                 getAddUserName(xid);
812                         }
813                 });
814                 
815                 // When a key is pressed...
816                 $('#buddy-conf-add input, #buddy-conf-add select').keyup(function(e) {
817                         // Enter : continue
818                         if(e.keyCode == 13) {
819                                 // Get the values
820                                 var xid = trim($('.add-contact-jid').val());
821                                 var name = trim($('.add-contact-name').val());
822                                 var gateway = unescape($('.add-contact-gateway').val());
823                                 
824                                 // Generate the XID to add
825                                 if((gateway != 'none') && xid)
826                                         xid = xid.replace(/@/g, '%') + '@' + gateway;
827                                 else
828                                         xid = generateXID(xid, 'chat');
829                                 
830                                 // Submit the form
831                                 if(xid && (xid != getXID()))
832                                         addThisContact(xid, name);
833                                 else
834                                         $(document).oneTime(10, function() {
835                                                 $('.add-contact-jid').addClass('please-complete').focus();
836                                         });
837                                 
838                                 return false;
839                         }
840                         
841                         // Escape : quit
842                         if(e.keyCode == 27)
843                                 closeBubbles();
844                 });
845                 
846                 // Click event on search link
847                 $('.buddy-conf-add-search').click(function() {
848                         closeBubbles();
849                         return openDirectory();
850                 });
851                 
852                 // Focus on the input
853                 $(document).oneTime(10, function() {
854                         $('.add-contact-jid').focus();
855                 });
856                 
857                 return false;
858         });
859         
860         // When the user click on the join button, show the chat joining tool
861         $('#buddy-list .foot .join').click(function() {
862                 // Yet displayed?
863                 if(exists('#buddy-conf-join'))
864                         return closeBubbles();
865                 
866                 // Add the bubble
867                 showBubble('#buddy-conf-join');
868                 
869                 // Append the content
870                 $('#buddy-list .buddy-list-join').append(
871                         '<div id="buddy-conf-join" class="buddy-conf-item bubble removable">' + 
872                                 '<div class="buddy-conf-subarrow talk-images"></div>' + 
873                                 
874                                 '<div class="buddy-conf-subitem search">' + 
875                                         '<p class="buddy-conf-p" style="margin-bottom: 0;">' + _e("Join a chat") +  '</p>' + 
876                                         
877                                         '<input type="text" class="buddy-conf-input join-jid" required="" />' + 
878                                         '<select class="buddy-conf-select buddy-conf-join-select join-type">' + 
879                                                 '<option value="chat" selected="">' + _e("Chat") +  '</option>' + 
880                                                 '<option value="groupchat">' + _e("Groupchat") +  '</option>' + 
881                                         '</select>' + 
882                                 '</div>' + 
883                         '</div>'
884                 );
885                 
886                 // Input vars
887                 var destination = '#buddy-conf-join .search';
888                 var dHovered = destination + ' ul li.hovered:first';
889                 
890                 // When a key is pressed...
891                 $('#buddy-conf-join input, #buddy-conf-join select').keyup(function(e) {
892                         // Enter: continue
893                         if(e.keyCode == 13) {
894                                 // Select something from the search
895                                 if(exists(dHovered))
896                                         addBuddySearch(destination, $(dHovered).attr('data-xid'));
897                                 
898                                 // Join something
899                                 else {
900                                         var xid = trim($('.join-jid').val());
901                                         var type = $('.buddy-conf-join-select').val();
902                                         
903                                         if(xid && type) {
904                                                 // Generate a correct XID
905                                                 xid = generateXID(xid, type);
906                                                 
907                                                 // Not me
908                                                 if(xid != getXID()) {
909                                                         // Update some things
910                                                         $('.join-jid').removeClass('please-complete');
911                                                         closeBubbles();
912                                                         
913                                                         // Create a new chat
914                                                         checkChatCreate(xid, type);
915                                                 }
916                                                 
917                                                 else
918                                                         $('.join-jid').addClass('please-complete');
919                                         }
920                                         
921                                         else
922                                                 $('.join-jid').addClass('please-complete');
923                                 }
924                                 
925                                 return false;
926                         }
927                         
928                         // Escape: quit
929                         else if(e.keyCode == 27)
930                                 closeBubbles();
931                         
932                         // Buddy search?
933                         else if($('.buddy-conf-join-select').val() == 'chat') {
934                                 // New buddy search
935                                 if((e.keyCode != 40) && (e.keyCode != 38))
936                                         createBuddySearch(destination);
937                                 
938                                 // Navigating with keyboard in the results
939                                 arrowsBuddySearch(e, destination);
940                         }
941                 });
942                 
943                 // Buddy search lost focus
944                 $('#buddy-conf-join input').blur(function() {
945                         if(!$(destination + ' ul').attr('mouse-hover'))
946                                 resetBuddySearch(destination);
947                 });
948                 
949                 // Re-focus on the text input
950                 $('#buddy-conf-join select').change(function() {
951                         $(document).oneTime(10, function() {
952                                 $('#buddy-conf-join input').focus();
953                         });
954                 });
955                 
956                 // We focus on the input
957                 $(document).oneTime(10, function() {
958                         $('#buddy-conf-join .join-jid').focus();
959                 });
960                 
961                 return false;
962         });
963         
964         // When the user click on the groupchat button, show the groupchat menu
965         $('#buddy-list .foot .groupchat').click(function() {
966                 // Yet displayed?
967                 if(exists('#buddy-conf-groupchat'))
968                         return closeBubbles();
969                 
970                 // Add the bubble
971                 showBubble('#buddy-conf-groupchat');
972                 
973                 // Append the content
974                 $('#buddy-list .buddy-list-groupchat').append(
975                         '<div id="buddy-conf-groupchat" class="buddy-conf-item bubble removable">' + 
976                                 '<div class="buddy-conf-subarrow talk-images"></div>' + 
977                                 
978                                 '<div class="buddy-conf-subitem">' + 
979                                         '<p class="buddy-conf-p">' + _e("Your groupchats") +  '</p>' + 
980                                         
981                                         '<select name="groupchat-join" class="buddy-conf-select buddy-conf-groupchat-select"></select>' + 
982                                         
983                                         '<p class="buddy-conf-text">' + 
984                                                 '- <a href="#" class="buddy-conf-groupchat-edit">' + _e("Manage your favorite groupchats") +  '</a>' + 
985                                         '</p>' + 
986                                 '</div>' + 
987                         '</div>'
988                 );
989                 
990                 // When the user wants to edit his groupchat favorites
991                 $('.buddy-conf-groupchat-edit').click(function() {
992                         openFavorites();
993                         closeBubbles();
994                         
995                         return false;
996                 });
997                 
998                 // Change event
999                 $('.buddy-conf-groupchat-select').change(function() {
1000                         var groupchat = trim($(this).val());
1001                         
1002                         if(groupchat != 'none') {
1003                                 // We hide the bubble
1004                                 closeBubbles();
1005                                 
1006                                 // Create the chat
1007                                 checkChatCreate(groupchat, 'groupchat');
1008                                 
1009                                 // We reset the select value
1010                                 $(this).val('none');
1011                         }
1012                 });
1013                 
1014                 // Load the favorites
1015                 loadFavorites();
1016                 
1017                 return false;
1018         });
1019         
1020         // When the user click on the more button, show the more menu
1021         $('#buddy-list .foot .more').click(function() {
1022                 // Yet displayed?
1023                 if(exists('#buddy-conf-more'))
1024                         return closeBubbles();
1025                 
1026                 // Add the bubble
1027                 showBubble('#buddy-conf-more');
1028                 
1029                 // Append the content
1030                 $('#buddy-list .buddy-list-more').append(
1031                         '<div id="buddy-conf-more" class="buddy-conf-item bubble removable">' + 
1032                                 '<div class="buddy-conf-subarrow talk-images"></div>' + 
1033                                 
1034                                 '<div class="buddy-conf-subitem">' + 
1035                                         '<p class="buddy-conf-p">' + _e("More stuff") +  '</p>' + 
1036                                         
1037                                         '<p class="buddy-conf-text">' + 
1038                                                 '- <a href="#" class="buddy-conf-more-display-unavailable">' + _e("Show all friends") +  '</a>' + 
1039                                                 '<a href="#" class="buddy-conf-more-display-available">' + _e("Only show connected friends") +  '</a>' + 
1040                                         '</p>' + 
1041                                         
1042                                         '<p class="buddy-conf-text archives-hidable">' + 
1043                                                 '- <a href="#" class="buddy-conf-more-archives">' + _e("Message archives") +  '</a>' + 
1044                                         '</p>' + 
1045                                         
1046                                         '<p class="buddy-conf-text privacy-hidable">' + 
1047                                                 '- <a href="#" class="buddy-conf-more-privacy">' + _e("Privacy") +  '</a>' + 
1048                                         '</p>' + 
1049                                         
1050                                         '<p class="buddy-conf-text">' + 
1051                                                 '- <a href="#" class="buddy-conf-more-service-disco">' + _e("Service discovery") +  '</a>' + 
1052                                         '</p>' + 
1053                                         
1054                                         '<p class="buddy-conf-text commands-hidable"">' + 
1055                                                 '- <a href="#" class="buddy-conf-more-commands">' + _e("Commands") +  '</a>' + 
1056                                         '</p>' + 
1057                                 '</div>' + 
1058                         '</div>'
1059                 );
1060                 
1061                 // Close bubble when link clicked
1062                 $('#buddy-conf-more a').click(function() {
1063                         closeBubbles();
1064                 });
1065                 
1066                 // When the user wants to display all his buddies
1067                 $('.buddy-conf-more-display-unavailable').click(function() {
1068                         showAllBuddies('roster');
1069                         
1070                         return false;
1071                 });
1072                 
1073                 // When the user wants to display only online buddies
1074                 $('.buddy-conf-more-display-available').click(function() {
1075                         showOnlineBuddies('roster');
1076                         
1077                         return false;
1078                 });
1079                 
1080                 // When the user click on the archives link
1081                 $('.buddy-conf-more-archives').click(openArchives);
1082                 
1083                 // When the user click on the privacy link
1084                 $('.buddy-conf-more-privacy').click(openPrivacy);
1085                 
1086                 // When the user click on the service discovery link
1087                 $('.buddy-conf-more-service-disco').click(openDiscovery);
1088                 
1089                 // When the user click on the command link
1090                 $('.buddy-conf-more-commands').click(function() {
1091                         serverAdHoc(con.domain);
1092                         
1093                         return false;
1094                 });
1095                 
1096                 // Manage the displayed links
1097                 if(BLIST_ALL) {
1098                         $('.buddy-conf-more-display-unavailable').hide();
1099                         $('.buddy-conf-more-display-available').show();
1100                 }
1101                 
1102                 if(enabledArchives() || enabledArchives('auto') || enabledArchives('manual') || enabledArchives('manage'))
1103                         $('.buddy-conf-more-archives').parent().show();
1104                 
1105                 if(enabledCommands())
1106                         $('.buddy-conf-more-commands').parent().show();
1107                 
1108                 if(getDB('privacy-marker', 'available'))
1109                         $('.buddy-conf-more-privacy').parent().show();
1110                 
1111                 return false;
1112         });
1113         
1114         // When the user scrolls the buddy list
1115         $('#buddy-list .content').scroll(function() {
1116                 // Close the opened buddy infos bubble
1117                 closeBubbles();
1118         });
1119 }
1120
1121 // Window resize event handler
1122 $(window).resize(adaptRoster);