1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/jappix_ynh.git synced 2024-09-03 19:26:19 +02:00
jappix_ynh/source/app/javascripts/roster.js
2014-04-08 20:14:28 +02:00

1458 lines
No EOL
53 KiB
JavaScript

/*
Jappix - An open social platform
These are the roster JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Valérian Saliou
*/
// Bundle
var Roster = (function () {
/**
* Alias of this
* @private
*/
var self = {};
/* Variables */
self.blist_all = false;
/**
* Gets the roster items
* @public
* @return {undefined}
*/
self.get = function() {
try {
var iq = new JSJaCIQ();
iq.setType('get');
iq.setQuery(NS_ROSTER);
con.send(iq, self.handle);
} catch(e) {
Console.error('Roster.get', e);
}
};
/**
* Handles the roster items
* @public
* @param {object} iq
* @return {undefined}
*/
self.handle = function(iq) {
try {
// Parse the roster xml
$(iq.getQuery()).find('item').each(function() {
// Get user data
var _this = $(this);
var user_xid = _this.attr('jid');
var user_subscription = _this.attr('subscription');
// Parse roster data & display user
self.parse($(this), 'load');
// Request user microblog (populates channel)
if(user_xid && ((user_subscription == 'both') || (user_subscription == 'to'))) {
// Openfire has an issue, forget about it!
if(Features.getServerName() != 'openfire') {
Microblog.request(user_xid, 1, null, Microblog.handleRoster);
}
}
});
// Update our avatar (if changed), and send our presence
Avatar.get(Common.getXID(), 'force', 'true', 'forget');
Console.log('Roster received.');
} catch(e) {
Console.error('Roster.handle', e);
}
};
/**
* Parses the group XML and display the roster
* @public
* @param {string} current
* @param {string} mode
* @return {undefined}
*/
self.parse = function(current, mode) {
try {
// Get the values
xid = current.attr('jid');
dName = current.attr('name');
subscription = current.attr('subscription');
xidHash = hex_md5(xid);
// Create an array containing the groups
var groups = [];
current.find('group').each(function() {
var group_text = $(this).text();
if(group_text)
groups.push(group_text);
});
// No group?
if(!groups.length)
groups.push(Common._e("Unclassified"));
// If no name is defined, we get the default nick of the buddy
if(!dName)
dName = Common.getXIDNick(xid);
self.display(xid, xidHash, dName, subscription, groups, mode);
} catch(e) {
Console.error('Roster.parse', e);
}
};
/**
* Updates the roster groups
* @public
* @return {undefined}
*/
self.updateGroups = function() {
try {
$('#roster .one-group').each(function() {
// Current values
var check = $(this).find('.buddy').size();
var hidden = $(this).find('.buddy:not(.hidden-buddy:hidden)').size();
// Special case: the filtering tool
if(Search.search_filtered)
hidden = $(this).find('.buddy:visible').size();
// If the group is empty
if(!check)
$(this).remove();
// If the group contains no online buddy (and is not just hidden)
if(!hidden && $(this).find('a.group').hasClass('minus'))
$(this).hide();
else
$(this).show();
});
} catch(e) {
Console.error('Roster.updateGroups', e);
}
};
/**
* Displays a defined roster item
* @public
* @param {string} dXID
* @param {string} dXIDHash
* @param {string} dName
* @param {string} dSubscription
* @param {string} dGroup
* @param {string} dMode
* @return {undefined}
*/
self.display = function(dXID, dXIDHash, dName, dSubscription, dGroup, dMode) {
try {
// First remove the buddy
$('#roster .' + dXIDHash).remove();
// Define some things around the groups
var is_gateway = Common.isGateway(dXID);
var gateway = '';
if(is_gateway) {
gateway = ' gateway';
dGroup = new Array(Common._e("Gateways"));
}
// Remove request
if(dSubscription == 'remove') {
// Flush presence
Presence.flush(dXID);
Presence.funnel(dXID, dXIDHash);
// Empty social channel
$('#channel .mixed .one-update.update_' + dXIDHash).remove();
}
// Other request
else {
// Is this buddy blocked?
var privacy_class = '';
var privacy_state = Privacy.status('block', dXID);
if(privacy_state == 'deny')
privacy_class = ' blocked';
// For each group this buddy has
$.each(dGroup, function(i, cGroup) {
if(cGroup) {
// Process some vars
var groupHash = 'group' + hex_md5(cGroup);
var groupContent = '#roster .' + groupHash;
var groupBuddies = groupContent + ' .group-buddies';
// Is this group blocked?
if((Privacy.status('block', cGroup) == 'deny') && (privacy_state != 'allow'))
privacy_class = ' blocked';
// Group not yet displayed
if(!Common.exists(groupContent)) {
// Define some things
var groupCont = '#roster .content';
var groupToggle = groupCont + ' .' + groupHash + ' a.group';
// Create the HTML markup of the group
$(groupCont).prepend(
'<div class="' + groupHash + ' one-group" data-group="' + escape(cGroup) + '">' +
'<a href="#" class="group talk-images minus">' + cGroup.htmlEnc() + '</a>' +
'<div class="group-buddies"></div>' +
'</div>'
);
// Create the click event which will hide and show the content
$(groupToggle).click(function() {
var group = $(groupBuddies);
var group_toggle = $(groupContent + ' a.group');
// We must hide the buddies
if(group_toggle.hasClass('minus')) {
group.hide();
group_toggle.removeClass('minus').addClass('plus');
// Remove the group opened buddy-info
Bubble.close();
}
// We must show the buddies
else {
group_toggle.removeClass('plus').addClass('minus');
group.show();
}
return false;
});
}
// Initialize the HTML code
var name_code = '<p class="buddy-name">' + dName.htmlEnc() + '</p>';
var presence_code = '<p class="buddy-presence talk-images unavailable">' + Common._e("Unavailable") + '</p>';
var html = '<div class="hidden-buddy buddy ibubble ' + dXIDHash + gateway + privacy_class + '" data-xid="' + escape(dXID) + '">' +
'<div class="buddy-click">';
// Display avatar if not gateway
if(!is_gateway) {
html += '<div class="avatar-container">' +
'<img class="avatar" src="' + './images/others/default-avatar.png' + '" alt="" />' +
'</div>';
}
html += '<div class="name">';
// Special gateway code
if(is_gateway)
html += presence_code +
name_code;
else
html += name_code +
presence_code;
html += '</div></div></div>';
// Create the DOM element for this buddy
$(groupBuddies).append(html);
// Apply the hover event
self.applyBuddyHover(dXID, dXIDHash, dName, dSubscription, dGroup, groupHash);
}
});
// Click event on this buddy
$('#roster .' + dXIDHash + ' .buddy-click').click(function() {
return Chat.checkCreate(dXID, 'chat');
});
// We get the user presence if necessary
if(dMode == 'presence') {
Presence.funnel(dXID, dXIDHash);
}
// If the buddy must be shown
if(self.blist_all) {
$('#roster .' + dXIDHash).show();
}
}
// We update our groups
if(!Search.search_filtered) {
self.updateGroups();
} else {
Search.funnelFilterBuddy();
}
} catch(e) {
Console.error('Roster.display', e);
}
};
/**
* Applies the buddy editing input events
* @public
* @param {string} xid
* @return {undefined}
*/
self.applyBuddyInput = function(xid) {
try {
// Initialize
var path = '#roster .buddy[data-xid="' + escape(xid) + '"]';
var rename = path + ' .bm-rename input';
var group = path + ' .bm-group input';
var manage_infos = path + ' .manage-infos';
var bm_choose = manage_infos + ' div.bm-choose';
// Keyup events
$(rename).keyup(function(e) {
if(e.keyCode == 13) {
// Send the item
self.send(xid, '', $.trim($(rename).val()), self.thisBuddyGroups(xid));
// Remove the buddy editor
Bubble.close();
return false;
}
});
$(group).keyup(function(e) {
if(e.keyCode == 13) {
// Empty input?
if(!$.trim($(this).val())) {
// Send the item
self.send(xid, '', $.trim($(rename).val()), self.thisBuddyGroups(xid));
// Remove the buddy editor
Bubble.close();
return false;
}
// Get the values
var this_value = $.trim($(this).val());
var escaped_value = escape(this_value);
// Check if the group yet exists
var group_exists = false;
$(bm_choose + ' label span').each(function() {
if($(this).text() == this_value)
group_exists = true;
});
// Create a new checked checkbox
if(!group_exists)
$(bm_choose).prepend('<label><input type="checkbox" data-group="' + escaped_value + '" /><span>' + this_value.htmlEnc() + '</span></label>');
// Check the checkbox
$(bm_choose + ' input[data-group="' + escaped_value + '"]').attr('checked', true);
// Reset the value of this input
$(this).val('');
return false;
}
});
// Click events
$(manage_infos + ' p.bm-authorize a.to').click(function() {
Bubble.close();
Presence.sendSubscribe(xid, 'subscribed');
return false;
});
$(manage_infos + ' p.bm-authorize a.from').click(function() {
Bubble.close();
Presence.sendSubscribe(xid, 'subscribe');
return false;
});
$(manage_infos + ' p.bm-authorize a.unblock').click(function() {
Bubble.close();
// Update privacy settings
Privacy.push('block', ['jid'], [xid], ['allow'], [false], [true], [true], [true], '', 'roster');
$(path).removeClass('blocked');
// Enable the "block" list
Privacy.change('block', 'active');
Privacy.change('block', 'default');
// Send an available presence
Presence.send(xid, 'available', Presence.getUserShow(), getUserStatus());
return false;
});
$(manage_infos + ' p.bm-remove a.remove').click(function() {
Bubble.close();
// First unregister if gateway
if(Common.isGateway(xid))
self.unregisterGateway(xid);
// Then send roster removal query
self.send(xid, 'remove');
return false;
});
$(manage_infos + ' p.bm-remove a.prohibit').click(function() {
Bubble.close();
Presence.sendSubscribe(xid, 'unsubscribed');
return false;
});
$(manage_infos + ' p.bm-remove a.block').click(function() {
Bubble.close();
// Update privacy settings
Privacy.push('block', ['jid'], [xid], ['deny'], [false], [true], [true], [true], '', 'roster');
$(path).addClass('blocked');
// Enable the "block" list
Privacy.change('block', 'active');
Privacy.change('block', 'default');
// Send an unavailable presence
Presence.send(xid, 'unavailable');
// Remove the user presence
var db_regex = new RegExp(('^' + Connection.desktop_hash + '_') + 'presence' + ('_(.+)'));
for(var i = 0; i < DataStore.storageDB.length; i++) {
// Get the pointer values
var current = DataStore.storageDB.key(i);
// If the pointer is on a stored presence
if(current.match(db_regex)) {
if(Common.bareXID(RegExp.$1) == xid)
DataStore.storageDB.removeItem(current);
}
}
// Manage his new presence
Presence.funnel(xid, hex_md5(xid));
return false;
});
$(manage_infos + ' a.save').click(function() {
// Send the item
self.send(xid, '', $.trim($(rename).val()), self.thisBuddyGroups(xid));
// Remove the buddy editor
Bubble.close();
return false;
});
} catch(e) {
Console.error('Roster.applyBuddyInput', e);
}
};
/**
* Applies the buddy editing hover events
* @public
* @param {string} xid
* @param {string} hash
* @param {string} nick
* @param {string} subscription
* @param {object} groups
* @param {string} group_hash
* @return {undefined}
*/
self.applyBuddyHover = function(xid, hash, nick, subscription, groups, group_hash) {
try {
// Generate the values
var bPath = '#roster .' + group_hash + ' .buddy[data-xid="' + escape(xid) + '"]';
var iPath = bPath + ' .buddy-infos';
// Apply the hover event
$(bPath).hover(function() {
// Another bubble exist
if(Common.exists('#roster .buddy-infos'))
return false;
$(bPath).oneTime(200, function() {
// Another bubble exist
if(Common.exists('#roster .buddy-infos'))
return false;
// Add this bubble!
Bubble.show(iPath);
// Create the buddy infos DOM element
$(bPath).append(
'<div class="buddy-infos bubble removable">' +
'<div class="buddy-infos-subarrow talk-images"></div>' +
'<div class="buddy-infos-subitem">' +
'<div class="pep-infos">' +
'<p class="bi-status talk-images unavailable">' + Common._e("unknown") + '</p>' +
'<p class="bi-mood talk-images mood-four">' + Common._e("unknown") + '</p>' +
'<p class="bi-activity talk-images activity-exercising">' + Common._e("unknown") + '</p>' +
'<p class="bi-tune talk-images tune-note">' + Common._e("unknown") + '</p>' +
'<p class="bi-geoloc talk-images location-world">' + Common._e("unknown") + '</p>' +
'<p class="bi-jingle talk-images call-jingle"><a href="#" class="audio">' + Common._e("Audio Call") + '</a><span class="separator"> / </span><a href="#" class="video">' + Common._e("Video Call") + '</a>' +
'<p class="bi-view talk-images view-individual"><a href="#" class="profile">' + Common._e("Profile") + '</a> / <a href="#" class="channel">' + Common._e("Channel") + '</a> / <a href="#" class="commands">' + Common._e("Commands") + '</a></p>' +
'<p class="bi-edit talk-images edit-buddy"><a href="#">' + Common._e("Edit") + '</a></p>' +
'</div>' +
'</div>' +
'</div>'
);
// Sets the good position
self.buddyInfosPosition(xid, group_hash);
// Get the presence
Presence.funnel(xid, hash);
// Get the PEP infos
PEP.displayAll(xid);
// Click events
$(bPath + ' .bi-view a').click(function() {
// Renitialize the buddy infos
Bubble.close();
// Profile
if($(this).is('.profile'))
UserInfos.open(xid);
// Channel
else if($(this).is('.channel'))
Microblog.fromInfos(xid, hash);
// Command
else if($(this).is('.commands'))
AdHoc.retrieve(xid);
return false;
});
// Jingle events
$(bPath + ' .bi-jingle a').click(function() {
// Renitialize the buddy infos
Bubble.close();
// Audio call?
if($(this).is('.audio'))
Jingle.start(xid, 'audio');
// Video call?
else if($(this).is('.video'))
Jingle.start(xid, 'video');
return false;
});
$(bPath + ' .bi-edit a').click(function() {
self.buddyEdit(xid, nick, subscription, groups);
return false;
});
});
}, function() {
if(!Common.exists(iPath + ' .manage-infos'))
Bubble.close();
$(bPath).stopTime();
});
} catch(e) {
Console.error('Roster.applyBuddyHover', e);
}
};
/**
* Sets the good buddy-infos position
* @public
* @param {string} xid
* @param {string} group_hash
* @return {undefined}
*/
self.buddyInfosPosition = function(xid, group_hash) {
try {
// Paths
var group = '#roster .' + group_hash;
var buddy = group + ' .buddy[data-xid="' + escape(xid) + '"]';
var buddy_infos = buddy + ' .buddy-infos';
// Get the offset to define
var offset = 3;
if(Common.isGateway(xid))
offset = -8;
// Process the position
var v_position = $(buddy).position().top + offset;
var h_position = $(buddy).width() - 10;
// Apply the top position
$(buddy_infos).css('top', v_position);
// Apply the left/right position
if($('html').attr('dir') == 'rtl')
$(buddy_infos).css('right', h_position);
else
$(buddy_infos).css('left', h_position);
} catch(e) {
Console.error('Roster.buddyInfosPosition', e);
}
};
/**
* Generates an array of the current groups of a buddy
* @public
* @param {string} xid
* @return {undefined}
*/
self.thisBuddyGroups = function(xid) {
try {
var path = '#roster .buddy[data-xid="' + escape(xid) + '"] ';
var array = [];
// Each checked checkboxes
$(path + 'div.bm-choose input[type="checkbox"]').filter(':checked').each(function() {
array.push(unescape($(this).attr('data-group')));
});
// Entered input value (and not yet in the array)
var value = $.trim($(path + 'p.bm-group input').val());
if(value && !Utils.existArrayValue(array, value))
array.push(value);
return array;
} catch(e) {
Console.error('Roster.thisBuddyGroups', e);
}
};
/**
* Adds a given contact to our roster
* @public
* @param {string} xid
* @param {string} name
* @return {undefined}
*/
self.addThisContact = function(xid, name) {
try {
Console.info('Add this contact: ' + xid + ', as ' + name);
// Cut the resource of this XID
xid = Common.bareXID(xid);
// If the form is complete
if(xid) {
// We send the subscription
Presence.sendSubscribe(xid, 'subscribe');
self.send(xid, '', name);
// We hide the bubble
Bubble.close();
}
} catch(e) {
Console.error('Roster.addThisContact', e);
}
};
/**
* Gets an array of all the groups in the roster
* @public
* @param {type} name
* @return {undefined}
*/
self.getAllGroups = function() {
try {
var groups = [];
$('#roster .one-group').each(function() {
var current = unescape($(this).attr('data-group'));
if((current != Common._e("Unclassified")) && (current != Common._e("Gateways")))
groups.push(current);
});
return groups.sort();
} catch(e) {
Console.error('Roster.getAllGroups', e);
}
};
/**
* Edits buddy informations
* @public
* @param {string} xid
* @param {string} nick
* @param {string} subscription
* @param {object} groups
* @return {undefined}
*/
self.buddyEdit = function(xid, nick, subscription, groups) {
try {
Console.info('Buddy edit: ' + xid);
// Initialize
var path = '#roster .buddy[data-xid="' + escape(xid) + '"] .';
var html = '<div class="manage-infos">';
// Get the privacy state
var privacy_state = Privacy.status('block', xid);
var privacy_active = DataStore.getDB(Connection.desktop_hash, 'privacy-marker', 'available');
// Get the group privacy state
for(var g in groups) {
if((Privacy.status('block', groups[g]) == 'deny') && (privacy_state != 'allow'))
privacy_state = 'deny';
}
// The subscription with this buddy is not full
if((subscription != 'both') || ((privacy_state == 'deny') && privacy_active)) {
var authorize_links = '';
html += '<p class="bm-authorize talk-images">';
// Link to allow to see our status
if((subscription == 'to') || (subscription == 'none'))
authorize_links += '<a href="#" class="to">' + Common._e("Authorize") + '</a>';
// Link to ask to see his/her status
if((subscription == 'from') || (subscription == 'none')) {
if(authorize_links)
authorize_links += ' / ';
authorize_links += '<a href="#" class="from">' + Common._e("Ask for authorization") + '</a>';
}
// Link to unblock this buddy
if((privacy_state == 'deny') && privacy_active) {
if(authorize_links)
authorize_links += ' / ';
html += '<a href="#" class="unblock">' + Common._e("Unblock") + '</a>';
}
html += authorize_links + '</p>';
}
// Complete the HTML code
var remove_links = '';
html += '<p class="bm-remove talk-images">';
remove_links = '<a href="#" class="remove">' + Common._e("Remove") + '</a>';
// This buddy is allowed to see our presence, we can show a "prohibit" link
if((subscription == 'both') || (subscription == 'from'))
remove_links += ' / <a href="#" class="prohibit">' + Common._e("Prohibit") + '</a>';
// Complete the HTML code
if((privacy_state != 'deny') && privacy_active) {
if(remove_links)
remove_links += ' / ';
remove_links += '<a href="#" class="block">' + Common._e("Block") + '</a>';
}
// Complete the HTML code
html += remove_links +
'</p>' +
'<p class="bm-rename talk-images"><label>' + Common._e("Rename") + '</label> <input type="text" value="' + Common.encodeQuotes(nick) + '" /></p>';
// Only show group tool if not a gateway
if(!Common.isGateway(xid))
html += '<p class="bm-group talk-images"><label>' + Common._e("Groups") + '</label> <input type="text" /></p>' +
'<div class="bm-choose">' +
'<div></div>' +
'</div>';
// Close the DOM element
html += '<a href="#" class="save">' + Common._e("Save") + '</a>' +
'</div>';
// We update the DOM elements
$(path + 'pep-infos').replaceWith(html);
// Gets all the existing groups
var all_groups = self.getAllGroups();
var all_groups_dom = '';
for(var a in all_groups) {
// Current group
var all_groups_current = all_groups[a];
// Is the current group checked?
var checked = '';
if(Utils.existArrayValue(groups, all_groups_current))
checked = ' checked="true"';
// Add the current group HTML
all_groups_dom += '<label><input type="checkbox" data-group="' + escape(all_groups_current) + '"' + checked + ' /><span>' + all_groups_current.htmlEnc() + '</span></label>';
}
// Prepend this in the DOM
var bm_choose = path + 'manage-infos div.bm-choose';
$(bm_choose).prepend(all_groups_dom);
// Apply the editing input events
self.applyBuddyInput(xid);
} catch(e) {
Console.error('Roster.buddyEdit', e);
}
};
/**
* Unregisters from a given gateway
* @public
* @param {string} xid
* @return {undefined}
*/
self.unregisterGateway = function(xid) {
try {
var iq = new JSJaCIQ();
iq.setType('set');
iq.setTo(xid);
var query = iq.setQuery(NS_REGISTER);
query.appendChild(iq.buildNode('remove', {'xmlns': NS_REGISTER}));
con.send(iq);
} catch(e) {
Console.error('Roster.unregisterGateway', e);
}
};
/**
* Updates the roster items
* @public
* @param {string} xid
* @param {string} subscription
* @param {string} name
* @param {string} group
* @return {undefined}
*/
self.send = function(xid, subscription, name, group) {
try {
// We send the new buddy name
var iq = new JSJaCIQ();
iq.setType('set');
var iqQuery = iq.setQuery(NS_ROSTER);
var item = iqQuery.appendChild(iq.buildNode('item', {'xmlns': NS_ROSTER, 'jid': xid}));
// Any subscription?
if(subscription)
item.setAttribute('subscription', subscription);
// Any name?
if(name)
item.setAttribute('name', name);
// Any group?
if(group && group.length) {
for(var i in group)
item.appendChild(iq.buildNode('group', {'xmlns': NS_ROSTER}, group[i]));
}
con.send(iq);
Console.info('Roster item sent: ' + xid);
} catch(e) {
Console.error('Roster.send', e);
}
};
/**
* Adapts the roster height, depending of the window size
* @public
* @return {undefined}
*/
self.adapt = function() {
try {
// Process the new height
var new_height = $('#left-content').height() - $('#my-infos').height() - 97;
// New height too small
if(new_height < 211)
new_height = 211;
// Apply the new height
$('#roster .content').css('height', new_height);
} catch(e) {
Console.error('Roster.adapt', e);
}
};
/**
* Gets all the buddies in our roster
* @public
* @return {object}
*/
self.getAllBuddies = function() {
try {
var buddies = [];
$('#roster .buddy').each(function() {
var xid = unescape($(this).attr('data-xid'));
if(xid) {
buddies.push(xid);
}
});
return buddies;
} catch(e) {
Console.error('Roster.getAllBuddies', e);
}
};
/**
* Returns whether given XID is in buddy list or not
* @public
* @param {string} xid
* @return {boolean}
*/
self.isFriend = function(xid) {
try {
return Common.exists('#roster .buddy[data-xid="' + escape(xid) + '"]');
} catch(e) {
Console.error('Roster.isFriend', e);
}
};
/**
* Gets the user gateways
* @public
* @return {object}
*/
self.getGateways = function() {
try {
// New array
var gateways = [];
var buddies = self.getAllBuddies();
// Get the gateways
for(var c in buddies) {
if(Common.isGateway(buddies[c])) {
gateways.push(buddies[c]);
}
}
return gateways;
} catch(e) {
Console.error('Roster.getGateways', e);
}
};
/**
* Instanciate the roster
* @public
* @return {undefined}
*/
self.instance = function() {
try {
// Filtering tool
var iFilter = $('#roster .filter input');
var aFilter = $('#roster .filter a');
iFilter.placeholder()
.blur(function() {
// Nothing is entered, put the placeholder instead
if(!$.trim($(this).val()))
aFilter.hide();
else
aFilter.show();
})
.keyup(function(e) {
Search.funnelFilterBuddy(e.keyCode);
});
aFilter.click(function() {
// Reset the input
$(this).hide();
iFilter.val('');
iFilter.placeholder();
// Security: show all the groups, empty or not
$('#roster .one-group').show();
// Reset the filtering tool
Search.resetFilterBuddy();
return false;
});
// When the user click on the add button, show the contact adding tool
$('#roster .foot .add').click(function() {
// Yet displayed?
if(Common.exists('#buddy-conf-add'))
return Bubble.close();
// Add the bubble
Bubble.show('#buddy-conf-add');
// Append the content
$('#roster .roster-add').append(
'<div id="buddy-conf-add" class="buddy-conf-item bubble removable">' +
'<div class="buddy-conf-subarrow talk-images"></div>' +
'<div class="buddy-conf-subitem">' +
'<p class="buddy-conf-p">' + Common._e("Add a friend") + '</p>' +
'<label><span>' + Common._e("Address") + '</span><input type="text" class="buddy-conf-input add-contact-jid" required="" /></label>' +
'<label><span>' + Common._e("Name") + '</span><input type="text" class="buddy-conf-input add-contact-name" /></label>' +
'<label>' +
'<span>' + Common._e("Gateway") + '</span>' +
'<select class="buddy-conf-select add-contact-gateway">' +
'<option value="none" selected="">' + Common._e("None") + '</option>' +
'</select>' +
'</label>' +
'<span class="add-contact-name-get">' + Common._e("Getting the name...") + '</span>' +
'<p class="buddy-conf-text">' +
'<a href="#" class="buddy-conf-add-search">' + Common._e("Search a friend") + '</a>' +
'</p>' +
'</div>' +
'</div>'
);
// Add the gateways
var gateways = self.getGateways();
// Any gateway?
if(gateways.length) {
// Append the gateways
for(var i in gateways) {
$('.add-contact-gateway').append('<option value="' + escape(gateways[i]) + '">' + gateways[i].htmlEnc() + '</option>');
}
// Show the gateway selector
$('.add-contact-gateway').parent().show();
} else {
$('.add-contact-gateway').parent().hide();
}
// Blur event on the add contact input
$('.add-contact-jid').blur(function() {
// Read the value
var value = $.trim($(this).val());
// Try to catch the buddy name
if(value && !$.trim($('.add-contact-name').val()) && ($('.add-contact-gateway').val() == 'none')) {
// User XID
var xid = Common.generateXID(value, 'chat');
// Notice for the user
$('.add-contact-name-get').attr('data-for', escape(xid)).show();
// Request the user vCard
Name.getAddUser(xid);
}
});
// When a key is pressed...
$('#buddy-conf-add input, #buddy-conf-add select').keyup(function(e) {
// Enter : continue
if(e.keyCode == 13) {
// Get the values
var xid = $.trim($('.add-contact-jid').val());
var name = $.trim($('.add-contact-name').val());
var gateway = unescape($('.add-contact-gateway').val());
// Generate the XID to add
if((gateway != 'none') && xid)
xid = xid.replace(/@/g, '%') + '@' + gateway;
else
xid = Common.generateXID(xid, 'chat');
// Submit the form
if(xid && Common.getXIDNick(xid) && (xid != Common.getXID()))
self.addThisContact(xid, name);
else
$(document).oneTime(10, function() {
$('.add-contact-jid').addClass('please-complete').focus();
});
return false;
}
// Escape : quit
if(e.keyCode == 27)
Bubble.close();
});
// Click event on search link
$('.buddy-conf-add-search').click(function() {
Bubble.close();
return Directory.open();
});
// Focus on the input
$(document).oneTime(10, function() {
$('.add-contact-jid').focus();
});
return false;
});
// When the user click on the join button, show the chat joining tool
$('#roster .foot .join').click(function() {
// Yet displayed?
if(Common.exists('#buddy-conf-join'))
return Bubble.close();
// Add the bubble
Bubble.show('#buddy-conf-join');
// Append the content
$('#roster .roster-join').append(
'<div id="buddy-conf-join" class="buddy-conf-item bubble removable">' +
'<div class="buddy-conf-subarrow talk-images"></div>' +
'<div class="buddy-conf-subitem search">' +
'<p class="buddy-conf-p" style="margin-bottom: 0;">' + Common._e("Join a chat") + '</p>' +
'<input type="text" class="buddy-conf-input join-jid" required="" />' +
'<select class="buddy-conf-select buddy-conf-join-select join-type">' +
'<option value="chat" selected="">' + Common._e("Chat") + '</option>' +
'<option value="groupchat">' + Common._e("Groupchat") + '</option>' +
'</select>' +
'</div>' +
'</div>'
);
// Input vars
var destination = '#buddy-conf-join .search';
var dHovered = destination + ' ul li.hovered:first';
// When a key is pressed...
$('#buddy-conf-join input, #buddy-conf-join select').keyup(function(e) {
// Enter: continue
if(e.keyCode == 13) {
// Select something from the search
if(Common.exists(dHovered)) {
Search.addBuddy(destination, $(dHovered).attr('data-xid'));
}
// Join something
else {
var xid = $.trim($('.join-jid').val());
var type = $('.buddy-conf-join-select').val();
if(xid && type) {
// Generate a correct XID
xid = Common.generateXID(xid, type);
// Not me
if(xid != Common.getXID()) {
// Update some things
$('.join-jid').removeClass('please-complete');
Bubble.close();
// Create a new chat
Chat.checkCreate(xid, type);
}
else {
$('.join-jid').addClass('please-complete');
}
}
else {
$('.join-jid').addClass('please-complete');
}
}
return false;
}
// Escape: quit
else if(e.keyCode == 27)
Bubble.close();
// Buddy search?
else if($('.buddy-conf-join-select').val() == 'chat') {
// New buddy search
if((e.keyCode != 40) && (e.keyCode != 38))
Search.createBuddy(destination);
// Navigating with keyboard in the results
Search.arrowsBuddy(e, destination);
}
});
// Buddy search lost focus
$('#buddy-conf-join input').blur(function() {
if(!$(destination + ' ul').attr('mouse-hover'))
Search.resetBuddy(destination);
});
// Re-focus on the text input
$('#buddy-conf-join select').change(function() {
$(document).oneTime(10, function() {
$('#buddy-conf-join input').focus();
});
});
// We focus on the input
$(document).oneTime(10, function() {
$('#buddy-conf-join .join-jid').focus();
});
return false;
});
// When the user click on the groupchat button, show the groupchat menu
$('#roster .foot .groupchat').click(function() {
// Yet displayed?
if(Common.exists('#buddy-conf-groupchat'))
return Bubble.close();
// Add the bubble
Bubble.show('#buddy-conf-groupchat');
// Append the content
$('#roster .roster-groupchat').append(
'<div id="buddy-conf-groupchat" class="buddy-conf-item bubble removable">' +
'<div class="buddy-conf-subarrow talk-images"></div>' +
'<div class="buddy-conf-subitem">' +
'<p class="buddy-conf-p">' + Common._e("Your groupchats") + '</p>' +
'<select name="groupchat-join" class="buddy-conf-select buddy-conf-groupchat-select"></select>' +
'<p class="buddy-conf-text">' +
'- <a href="#" class="buddy-conf-groupchat-edit">' + Common._e("Manage your favorite groupchats") + '</a>' +
'</p>' +
'</div>' +
'</div>'
);
// When the user wants to edit his groupchat favorites
$('.buddy-conf-groupchat-edit').click(function() {
Favorites.open();
Bubble.close();
return false;
});
// Change event
$('.buddy-conf-groupchat-select').change(function() {
var groupchat = $.trim($(this).val());
if(groupchat != 'none') {
// We hide the bubble
Bubble.close();
// Create the chat
Chat.checkCreate(groupchat, 'groupchat');
// We reset the select value
$(this).val('none');
}
});
// Load the favorites
Favorites.load();
return false;
});
// When the user click on the more button, show the more menu
$('#roster .foot .more').click(function() {
// Yet displayed?
if(Common.exists('#buddy-conf-more'))
return Bubble.close();
// Add the bubble
Bubble.show('#buddy-conf-more');
// Append the content
$('#roster .roster-more').append(
'<div id="buddy-conf-more" class="buddy-conf-item bubble removable">' +
'<div class="buddy-conf-subarrow talk-images"></div>' +
'<div class="buddy-conf-subitem">' +
'<p class="buddy-conf-p">' + Common._e("More stuff") + '</p>' +
'<p class="buddy-conf-text">' +
'- <a href="#" class="buddy-conf-more-display-unavailable">' + Common._e("Show all friends") + '</a>' +
'<a href="#" class="buddy-conf-more-display-available">' + Common._e("Only show connected friends") + '</a>' +
'</p>' +
'<p class="buddy-conf-text privacy-hidable">' +
'- <a href="#" class="buddy-conf-more-privacy">' + Common._e("Privacy") + '</a>' +
'</p>' +
'<p class="buddy-conf-text">' +
'- <a href="#" class="buddy-conf-more-service-disco">' + Common._e("Service discovery") + '</a>' +
'</p>' +
'<p class="buddy-conf-text commands-hidable"">' +
'- <a href="#" class="buddy-conf-more-commands">' + Common._e("Commands") + '</a>' +
'</p>' +
'</div>' +
'</div>'
);
// Close bubble when link clicked
$('#buddy-conf-more a').click(function() {
Bubble.close();
});
// When the user wants to display all his buddies
$('.buddy-conf-more-display-unavailable').click(function() {
Interface.showAllBuddies('roster');
return false;
});
// When the user wants to display only online buddies
$('.buddy-conf-more-display-available').click(function() {
Interface.showOnlineBuddies('roster');
return false;
});
// When the user click on the privacy link
$('.buddy-conf-more-privacy').click(Privacy.open);
// When the user click on the service discovery link
$('.buddy-conf-more-service-disco').click(Discovery.open);
// When the user click on the command link
$('.buddy-conf-more-commands').click(function() {
AdHoc.server(con.domain);
return false;
});
// Manage the displayed links
if(self.blist_all) {
$('.buddy-conf-more-display-unavailable').hide();
$('.buddy-conf-more-display-available').show();
}
if(Features.enabledCommands())
$('.buddy-conf-more-commands').parent().show();
if(DataStore.getDB(Connection.desktop_hash, 'privacy-marker', 'available'))
$('.buddy-conf-more-privacy').parent().show();
return false;
});
// When the user scrolls the buddy list
$('#roster .content').scroll(function() {
// Close the opened buddy infos bubble
Bubble.close();
});
} catch(e) {
Console.error('Roster.instance', e);
}
};
/**
* Plugin launcher
* @public
* @return {undefined}
*/
self.launch = function() {
try {
// Window resize event handler
$(window).resize(self.adapt);
} catch(e) {
Console.error('Roster.launch', e);
}
};
/**
* Return class scope
*/
return self;
})();
Roster.launch();