mirror of
https://github.com/YunoHost-Apps/jappix_ynh.git
synced 2024-09-03 19:26:19 +02:00
1678 lines
No EOL
57 KiB
JavaScript
1678 lines
No EOL
57 KiB
JavaScript
/*
|
|
|
|
Jappix - An open social platform
|
|
These are the presence JS scripts for Jappix
|
|
|
|
-------------------------------------------------
|
|
|
|
License: AGPL
|
|
Author: Valérian Saliou
|
|
|
|
*/
|
|
|
|
// Bundle
|
|
var Presence = (function () {
|
|
|
|
/**
|
|
* Alias of this
|
|
* @private
|
|
*/
|
|
var self = {};
|
|
|
|
|
|
/* Variables */
|
|
self.first_sent = false;
|
|
self.auto_idle = false;
|
|
|
|
|
|
/**
|
|
* Sends the user first presence
|
|
* @public
|
|
* @param {string} checksum
|
|
* @return {undefined}
|
|
*/
|
|
self.sendFirst = function(checksum) {
|
|
|
|
try {
|
|
Console.info('First presence sent.');
|
|
|
|
// Jappix is now ready: change the title
|
|
Interface.title('talk');
|
|
|
|
// Anonymous check
|
|
var is_anonymous = Utils.isAnonymous();
|
|
|
|
// Update our marker
|
|
self.first_sent = true;
|
|
|
|
// Try to use the last status message
|
|
var status = DataStore.getDB(Connection.desktop_hash, 'options', 'presence-status');
|
|
|
|
if(!status)
|
|
status = '';
|
|
|
|
// We tell the world that we are online
|
|
if(!is_anonymous)
|
|
self.send('', '', '', status, checksum);
|
|
|
|
// Any status to apply?
|
|
if(status)
|
|
$('#presence-status').val(status);
|
|
|
|
// Enable the presence picker
|
|
$('#presence-status').removeAttr('disabled');
|
|
$('#my-infos .f-presence a.picker').removeClass('disabled');
|
|
|
|
// We set the last activity stamp
|
|
DateUtils.presence_last_activity = DateUtils.getTimeStamp();
|
|
|
|
// We store our presence
|
|
DataStore.setDB(Connection.desktop_hash, 'presence-show', 1, 'available');
|
|
|
|
// Not anonymous
|
|
if(!is_anonymous) {
|
|
// We get the stored bookmarks (because of the photo hash and some other stuffs, we must get it later)
|
|
Storage.get(NS_BOOKMARKS);
|
|
|
|
// We open a new chat if a XMPP link was submitted
|
|
if((parent.location.hash != '#OK') && XMPPLinks.links_var.x) {
|
|
// A link is submitted in the URL
|
|
XMPPLinks.go(XMPPLinks.links_var.x);
|
|
|
|
// Set a OK status
|
|
parent.location.hash = 'OK';
|
|
}
|
|
}
|
|
} catch(e) {
|
|
Console.error('Presence.sendFirst', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Handles incoming presence packets
|
|
* @public
|
|
* @param {object} presence
|
|
* @return {undefined}
|
|
*/
|
|
self.handle = function(presence) {
|
|
|
|
try {
|
|
// We define everything needed here
|
|
var from = Common.fullXID(Common.getStanzaFrom(presence));
|
|
var hash = hex_md5(from);
|
|
var node = presence.getNode();
|
|
var xid = Common.bareXID(from);
|
|
var xidHash = hex_md5(xid);
|
|
var resource = Common.thisResource(from);
|
|
var resources_obj, xml;
|
|
|
|
// We get the type content
|
|
var type = presence.getType();
|
|
if(!type)
|
|
type = '';
|
|
|
|
// We get the priority content
|
|
var priority = presence.getPriority() + '';
|
|
if(!priority || (type == 'error'))
|
|
priority = '0';
|
|
|
|
// We get the show content
|
|
var show = presence.getShow();
|
|
if(!show || (type == 'error'))
|
|
show = '';
|
|
|
|
// We get the status content
|
|
var status = presence.getStatus();
|
|
if(!status || (type == 'error'))
|
|
status = '';
|
|
|
|
// We get the photo content
|
|
var photo = $(node).find('x[xmlns="' + NS_VCARD_P + '"]:first photo');
|
|
var checksum = photo.text();
|
|
var hasPhoto = photo.size();
|
|
|
|
if(hasPhoto && (type != 'error'))
|
|
hasPhoto = 'true';
|
|
else
|
|
hasPhoto = 'false';
|
|
|
|
// We get the CAPS content
|
|
var caps = $(node).find('c[xmlns="' + NS_CAPS + '"]:first').attr('ver');
|
|
if(!caps || (type == 'error'))
|
|
caps = '';
|
|
|
|
// This presence comes from another resource of my account with a difference avatar checksum
|
|
if((xid == Common.getXID()) && (hasPhoto == 'true') && (checksum != DataStore.getDB(Connection.desktop_hash, 'checksum', 1)))
|
|
Avatar.get(Common.getXID(), 'force', 'true', 'forget');
|
|
|
|
// This presence comes from a groupchat
|
|
if(Utils.isPrivate(xid)) {
|
|
var x_muc = $(node).find('x[xmlns="' + NS_MUC_USER + '"]:first');
|
|
var item = x_muc.find('item');
|
|
var affiliation = item.attr('affiliation');
|
|
var role = item.attr('role');
|
|
var reason = item.find('reason').text();
|
|
var iXID = item.attr('jid');
|
|
var iNick = item.attr('nick');
|
|
var nick = resource;
|
|
var messageTime = DateUtils.getCompleteTime();
|
|
var notInitial = true;
|
|
|
|
// Read the status code
|
|
var status_code = [];
|
|
|
|
x_muc.find('status').each(function() {
|
|
status_code.push(parseInt($(this).attr('code')));
|
|
});
|
|
|
|
// If this is an initial presence (when user join the room)
|
|
if(Common.exists('#' + xidHash + '[data-initial="true"]')) {
|
|
notInitial = false;
|
|
}
|
|
|
|
// If one user is quitting
|
|
if(type && (type == 'unavailable')) {
|
|
self.displayMUC(from, xidHash, hash, type, show, status, affiliation, role, reason, status_code, iXID, iNick, messageTime, nick, notInitial);
|
|
|
|
DataStore.removeDB(Connection.desktop_hash, 'presence-stanza', from);
|
|
resources_obj = self.removeResource(xid, resource);
|
|
}
|
|
|
|
// If one user is joining
|
|
else {
|
|
// Fixes M-Link first presence bug (missing ID!)
|
|
if((nick == Name.getMUCNick(xidHash)) && (presence.getID() === null) && !Common.exists('#page-engine #' + xidHash + ' .list .' + hash)) {
|
|
Groupchat.handleMUC(presence);
|
|
|
|
Console.warn('Passed M-Link MUC first presence handling.');
|
|
}
|
|
|
|
else {
|
|
self.displayMUC(from, xidHash, hash, type, show, status, affiliation, role, reason, status_code, iXID, iNick, messageTime, nick, notInitial);
|
|
|
|
xml = '<presence from="' + Common.encodeQuotes(from) + '"><priority>' + priority.htmlEnc() + '</priority><show>' + show.htmlEnc() + '</show><type>' + type.htmlEnc() + '</type><status>' + status.htmlEnc() + '</status><avatar>' + hasPhoto.htmlEnc() + '</avatar><checksum>' + checksum.htmlEnc() + '</checksum><caps>' + caps.htmlEnc() + '</caps></presence>';
|
|
|
|
DataStore.setDB(Connection.desktop_hash, 'presence-stanza', from, xml);
|
|
resources_obj = self.addResource(xid, resource);
|
|
}
|
|
}
|
|
|
|
// Manage the presence
|
|
self.processPriority(from, resource, resources_obj);
|
|
self.funnel(from, hash);
|
|
}
|
|
|
|
// This presence comes from an user or a gateway
|
|
else {
|
|
// Subscribed/Unsubscribed stanzas
|
|
if((type == 'subscribed') || (type == 'unsubscribed'))
|
|
return;
|
|
// Subscribe stanza
|
|
else if(type == 'subscribe') {
|
|
// This is a buddy we can safely authorize, because we added him to our roster
|
|
if(Common.exists('#roster .buddy[data-xid="' + escape(xid) + '"]'))
|
|
self.acceptSubscribe(xid);
|
|
|
|
// We do not know this entity, we'd be better ask the user
|
|
else {
|
|
// Get the nickname
|
|
var nickname = $(node).find('nick[xmlns="' + NS_NICK + '"]:first').text();
|
|
|
|
// New notification
|
|
Notification.create('subscribe', xid, [xid, nickname], status);
|
|
}
|
|
}
|
|
|
|
// Unsubscribe stanza
|
|
else if(type == 'unsubscribe') {
|
|
Roster.send(xid, 'remove');
|
|
}
|
|
|
|
// Other stanzas
|
|
else {
|
|
// Unavailable/error presence
|
|
if(type == 'unavailable') {
|
|
DataStore.removeDB(Connection.desktop_hash, 'presence-stanza', from);
|
|
resources_obj = self.removeResource(xid, resource);
|
|
}
|
|
|
|
// Other presence (available, subscribe...)
|
|
else {
|
|
xml = '<presence from="' + Common.encodeQuotes(from) + '"><priority>' + priority.htmlEnc() + '</priority><show>' + show.htmlEnc() + '</show><type>' + type.htmlEnc() + '</type><status>' + status.htmlEnc() + '</status><avatar>' + hasPhoto.htmlEnc() + '</avatar><checksum>' + checksum.htmlEnc() + '</checksum><caps>' + caps.htmlEnc() + '</caps></presence>';
|
|
|
|
DataStore.setDB(Connection.desktop_hash, 'presence-stanza', from, xml);
|
|
resources_obj = self.addResource(xid, resource);
|
|
}
|
|
|
|
// We manage the presence
|
|
self.processPriority(xid, resource, resources_obj);
|
|
self.funnel(xid, xidHash);
|
|
|
|
// We display the presence in the current chat
|
|
if(Common.exists('#' + xidHash)) {
|
|
var dStatus = self.filterStatus(xid, status, false);
|
|
|
|
if(dStatus)
|
|
dStatus = ' (' + dStatus + ')';
|
|
|
|
// Generate the presence-in-chat code
|
|
var dName = Name.getBuddy(from).htmlEnc();
|
|
var dBody = dName + ' (' + from + ') ' + Common._e("is now") + ' ' + self.humanShow(show, type) + dStatus;
|
|
|
|
// Check whether it has been previously displayed
|
|
var can_display = true;
|
|
|
|
if($('#' + xidHash + ' .one-line.system-message:last').html() == dBody)
|
|
can_display = false;
|
|
|
|
if(can_display)
|
|
Message.display('chat', xid, xidHash, dName, dBody, DateUtils.getCompleteTime(), DateUtils.getTimeStamp(), 'system-message', false);
|
|
}
|
|
}
|
|
|
|
// Get disco#infos for this presence (related to Caps)
|
|
Caps.getDiscoInfos(from, caps);
|
|
}
|
|
|
|
// For logger
|
|
if(!show) {
|
|
if(!type)
|
|
show = 'available';
|
|
else
|
|
show = 'unavailable';
|
|
}
|
|
|
|
Console.log('Presence received: ' + show + ', from ' + from);
|
|
} catch(e) {
|
|
Console.error('Presence.handle', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Displays a MUC presence
|
|
* @public
|
|
* @param {string} from
|
|
* @param {string} roomHash
|
|
* @param {string} hash
|
|
* @param {string} type
|
|
* @param {string} show
|
|
* @param {string} status
|
|
* @param {string} affiliation
|
|
* @param {string} role
|
|
* @param {string} reason
|
|
* @param {string} status_code
|
|
* @param {string} iXID
|
|
* @param {string} iNick
|
|
* @param {string} messageTime
|
|
* @param {string} nick
|
|
* @param {boolean} initial
|
|
* @return {undefined}
|
|
*/
|
|
self.displayMUC = function(from, roomHash, hash, type, show, status, affiliation, role, reason, status_code, iXID, iNick, messageTime, nick, initial) {
|
|
|
|
try {
|
|
// Generate the values
|
|
var room_xid = Common.bareXID(from);
|
|
var thisUser = '#page-engine #' + roomHash + ' .list .' + hash;
|
|
var thisPrivate = $('#' + hash + ' .message-area');
|
|
var nick_html = nick.htmlEnc();
|
|
var real_xid = '';
|
|
var write = nick_html + ' ';
|
|
var notify = false;
|
|
|
|
// Reset data?
|
|
if(!role)
|
|
role = 'participant';
|
|
if(!affiliation)
|
|
affiliation = 'none';
|
|
|
|
// Must update the role?
|
|
if(Common.exists(thisUser) && (($(thisUser).attr('data-role') != role) || ($(thisUser).attr('data-affiliation') != affiliation)))
|
|
$(thisUser).remove();
|
|
|
|
// Any XID submitted?
|
|
if(iXID) {
|
|
real_xid = ' data-realxid="' + iXID + '"';
|
|
iXID = Common.bareXID(iXID);
|
|
write += ' (<a onclick="return Chat.checkCreate(\'' + Utils.encodeOnclick(iXID) + '\', \'chat\');" href="xmpp:' + Utils.encodeOnclick(iXID) + '">' + iXID + '</a>) ';
|
|
}
|
|
|
|
// User does not exists yet
|
|
if(!Common.exists(thisUser) && (!type || (type == 'available'))) {
|
|
var myself = '';
|
|
|
|
// Is it me?
|
|
if(nick == Name.getMUCNick(roomHash)) {
|
|
// Enable the room
|
|
$('#' + roomHash + ' .message-area').removeAttr('disabled');
|
|
|
|
// Marker
|
|
myself = ' myself';
|
|
}
|
|
|
|
// Set the user in the MUC list
|
|
$('#' + roomHash + ' .list .' + role + ' .title').after(
|
|
'<div class="user ' + hash + myself + '" data-xid="' + Common.encodeQuotes(from) + '" data-nick="' + escape(nick) + '"' + real_xid + ' data-role="' + Common.encodeQuotes(role) + '" data-affiliation="' + Common.encodeQuotes(affiliation) + '">' +
|
|
'<div class="user-details">' +
|
|
'<div class="name talk-images available">' + nick_html + '</div>' +
|
|
|
|
'<div class="avatar-container">' +
|
|
'<img class="avatar" src="' + './images/others/default-avatar.png' + '" alt="" />' +
|
|
'</div>' +
|
|
|
|
'<div class="clear"></div>' +
|
|
'</div>' +
|
|
|
|
'<div class="user-actions">' +
|
|
'<span class="action promote">' +
|
|
'<a href="#" class="talk-images" title="' + Common._e("Promote as moderator") + '"></a>' +
|
|
'</span>' +
|
|
|
|
'<span class="action demote">' +
|
|
'<a href="#" class="talk-images" title="' + Common._e("Remove moderator status") + '"></a>' +
|
|
'</span>' +
|
|
|
|
'<span class="action add">' +
|
|
'<a href="#" class="talk-images" title="' + Common._e("Add to my contacts") + '"></a>' +
|
|
'</span>' +
|
|
|
|
'<span class="action kick">' +
|
|
'<a href="#" class="talk-images" title="' + Common._e("Kick from room") + '"></a>' +
|
|
'</span>' +
|
|
|
|
'<div class="clear"></div>' +
|
|
'</div>' +
|
|
'</div>'
|
|
);
|
|
|
|
// Click event
|
|
if(nick != Name.getMUCNick(roomHash)) {
|
|
$(thisUser).hover(function() {
|
|
if(iXID && Groupchat.affiliationMe(room_xid).code >= 2) {
|
|
var user_actions_sel = $(this).find('.user-actions');
|
|
var user_actions_btn_sel = user_actions_sel.find('.action');
|
|
|
|
// Update buttons
|
|
var i;
|
|
var hide_btns = [];
|
|
|
|
var user_affiliation = Groupchat.affiliationUser(room_xid, nick);
|
|
|
|
if(user_affiliation.name == 'owner') {
|
|
hide_btns.push('promote');
|
|
hide_btns.push('demote');
|
|
hide_btns.push('kick');
|
|
} else if(user_affiliation.name === 'admin') {
|
|
hide_btns.push('promote');
|
|
hide_btns.push('kick');
|
|
} else {
|
|
hide_btns.push('demote');
|
|
}
|
|
|
|
if(Roster.isFriend(iXID)) {
|
|
hide_btns.push('add');
|
|
}
|
|
|
|
// Go Go Go!!
|
|
for(i in hide_btns) {
|
|
user_actions_btn_sel.filter('.' + hide_btns[i]).hide();
|
|
}
|
|
|
|
// Slide down?
|
|
if(hide_btns.length < user_actions_btn_sel.size()) {
|
|
user_actions_sel.stop(true).slideDown(250);
|
|
}
|
|
}
|
|
}, function() {
|
|
var user_actions_sel = $(this).find('.user-actions');
|
|
|
|
if(user_actions_sel.is(':visible')) {
|
|
user_actions_sel.stop(true).slideUp(200, function() {
|
|
user_actions_sel.find('.action').show();
|
|
});
|
|
}
|
|
});
|
|
|
|
$(thisUser).find('.user-details').on('click', function() {
|
|
Chat.checkCreate(from, 'private');
|
|
});
|
|
|
|
$(thisUser).find('.user-actions .action a').on('click', function() {
|
|
var this_parent_sel = $(this).parent();
|
|
|
|
if(this_parent_sel.is('.promote')) {
|
|
Groupchat.promoteModerator(room_xid, iXID);
|
|
} else if(this_parent_sel.is('.demote')) {
|
|
Groupchat.demoteModerator(room_xid, iXID);
|
|
} else if(this_parent_sel.is('.add')) {
|
|
this_parent_sel.hide();
|
|
Roster.addThisContact(iXID, nick);
|
|
} else if(this_parent_sel.is('.kick')) {
|
|
Groupchat.kickUser(room_xid, (iXID || from), nick);
|
|
}
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
// We tell the user that someone entered the room
|
|
if(!initial && DataStore.getDB(Connection.desktop_hash, 'options', 'groupchatpresence') !== '0') {
|
|
notify = true;
|
|
write += Common._e("joined the chat room");
|
|
|
|
// Any status?
|
|
if(status)
|
|
write += ' (' + Filter.message(status, nick_html, true) + ')';
|
|
else
|
|
write += ' (' + Common._e("no status") + ')';
|
|
}
|
|
|
|
// Enable the private chat input
|
|
thisPrivate.removeAttr('disabled');
|
|
}
|
|
|
|
else if((type == 'unavailable') || (type == 'error')) {
|
|
// Is it me?
|
|
if(nick == Name.getMUCNick(roomHash)) {
|
|
$(thisUser).remove();
|
|
|
|
// Disable the groupchat input
|
|
$('#' + roomHash + ' .message-area').attr('disabled', true);
|
|
|
|
// Remove all the groupchat users
|
|
$('#' + roomHash + ' .list .user').remove();
|
|
}
|
|
|
|
// Someone has been kicked or banned?
|
|
if(Utils.existArrayValue(status_code, 301) || Utils.existArrayValue(status_code, 307)) {
|
|
$(thisUser).remove();
|
|
notify = true;
|
|
|
|
// Kicked?
|
|
if(Utils.existArrayValue(status_code, 307))
|
|
write += Common._e("has been kicked");
|
|
|
|
// Banned?
|
|
if(Utils.existArrayValue(status_code, 301))
|
|
write += Common._e("has been banned");
|
|
|
|
// Any reason?
|
|
if(reason)
|
|
write += ' (' + Filter.message(reason, nick_html, true) + ')';
|
|
else
|
|
write += ' (' + Common._e("no reason") + ')';
|
|
}
|
|
|
|
// Nickname change?
|
|
else if(Utils.existArrayValue(status_code, 303) && iNick) {
|
|
notify = true;
|
|
write += Common.printf(Common._e("changed his/her nickname to %s"), iNick.htmlEnc());
|
|
|
|
// New values
|
|
var new_xid = Common.cutResource(from) + '/' + iNick;
|
|
var new_hash = hex_md5(new_xid);
|
|
var new_class = 'user ' + new_hash;
|
|
|
|
if($(thisUser).hasClass('myself'))
|
|
new_class += ' myself';
|
|
|
|
// Die the click event
|
|
$(thisUser).off('click');
|
|
|
|
// Change to the new nickname
|
|
$(thisUser).attr('data-nick', escape(iNick))
|
|
.attr('data-xid', new_xid)
|
|
.find('.name').text(iNick);
|
|
|
|
// Change the user class
|
|
$(thisUser).attr('class', new_class);
|
|
|
|
// New click event
|
|
$('#page-engine #' + roomHash + ' .list .' + new_hash).on('click', function() {
|
|
Chat.checkCreate(new_xid, 'private');
|
|
});
|
|
}
|
|
|
|
// We tell the user that someone left the room
|
|
else if(!initial && DataStore.getDB(Connection.desktop_hash, 'options', 'groupchatpresence') !== '0') {
|
|
$(thisUser).remove();
|
|
notify = true;
|
|
write += Common._e("left the chat room");
|
|
|
|
// Any status?
|
|
if(status)
|
|
write += ' (' + Filter.message(status, nick_html, true) + ')';
|
|
else
|
|
write += ' (' + Common._e("no status") + ')';
|
|
}
|
|
|
|
// Disable the private chat input
|
|
thisPrivate.attr('disabled', true);
|
|
}
|
|
|
|
// Must notify something
|
|
if(notify)
|
|
Message.display('groupchat', from, roomHash, nick_html, write, messageTime, DateUtils.getTimeStamp(), 'system-message', false);
|
|
|
|
// Set the good status show icon
|
|
switch(show) {
|
|
case 'chat':
|
|
case 'away':
|
|
case 'xa':
|
|
case 'dnd':
|
|
break;
|
|
|
|
default:
|
|
show = 'available';
|
|
break;
|
|
}
|
|
|
|
$(thisUser + ' .name').attr('class', 'name talk-images ' + show);
|
|
|
|
// Set the good status text
|
|
var uTitle = nick;
|
|
|
|
// Any XID to add?
|
|
if(iXID)
|
|
uTitle += ' (' + iXID + ')';
|
|
|
|
// Any status to add?
|
|
if(status)
|
|
uTitle += ' - ' + status;
|
|
|
|
$(thisUser).attr('title', uTitle);
|
|
|
|
// Show or hide the role category, depending of its content
|
|
$('#' + roomHash + ' .list .role').each(function() {
|
|
if($(this).find('.user').size())
|
|
$(this).show();
|
|
else
|
|
$(this).hide();
|
|
});
|
|
} catch(e) {
|
|
Console.error('Presence.displayMUC', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Filters a given status
|
|
* @public
|
|
* @param {string} xid
|
|
* @param {string} status
|
|
* @param {boolean} cut
|
|
* @return {string}
|
|
*/
|
|
self.filterStatus = function(xid, status, cut) {
|
|
|
|
try {
|
|
var dStatus = '';
|
|
|
|
if(!status) {
|
|
status = '';
|
|
}
|
|
|
|
else {
|
|
if(cut) {
|
|
dStatus = Utils.truncate(status, 50);
|
|
} else {
|
|
dStatus = status;
|
|
}
|
|
|
|
dStatus = Filter.message(dStatus, Name.getBuddy(xid).htmlEnc(), true);
|
|
}
|
|
|
|
return dStatus;
|
|
} catch(e) {
|
|
Console.error('Presence.filterStatus', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Displays a user's presence
|
|
* @public
|
|
* @param {string} value
|
|
* @param {string} type
|
|
* @param {string} show
|
|
* @param {string} status
|
|
* @param {string} hash
|
|
* @param {string} xid
|
|
* @param {string} avatar
|
|
* @param {string} checksum
|
|
* @param {string} caps
|
|
* @return {undefined}
|
|
*/
|
|
self.display = function(value, type, show, status, hash, xid, avatar, checksum, caps) {
|
|
|
|
try {
|
|
// Display the presence in the roster
|
|
var path = '#roster .' + hash;
|
|
var buddy = $('#roster .content .' + hash);
|
|
var dStatus = self.filterStatus(xid, status, false);
|
|
var tStatus = Common.encodeQuotes(status);
|
|
var biStatus;
|
|
|
|
// The buddy presence behind his name
|
|
$(path + ' .name .buddy-presence').replaceWith('<p class="buddy-presence talk-images ' + type + '">' + value + '</p>');
|
|
|
|
// The buddy presence in the buddy infos
|
|
if(dStatus)
|
|
biStatus = dStatus;
|
|
else
|
|
biStatus = value;
|
|
|
|
$(path + ' .bi-status').replaceWith('<p class="bi-status talk-images ' + type + '" title="' + tStatus + '">' + biStatus + '</p>');
|
|
|
|
// When the buddy disconnect himself, we hide him
|
|
if((type == 'unavailable') || (type == 'error')) {
|
|
// Set a special class to the buddy
|
|
buddy.addClass('hidden-buddy');
|
|
|
|
// No filtering is launched?
|
|
if(!Search.search_filtered)
|
|
buddy.hide();
|
|
|
|
// All the buddies are shown?
|
|
if(Roster.blist_all)
|
|
buddy.show();
|
|
|
|
// Chat stuffs
|
|
if(Common.exists('#' + hash)) {
|
|
// Remove the chatstate stuffs
|
|
ChatState.reset(hash);
|
|
$('#' + hash + ' .chatstate').remove();
|
|
$('#' + hash + ' .message-area').removeAttr('data-chatstates');
|
|
|
|
// Get the buddy avatar (only if a chat is opened)
|
|
Avatar.get(xid, 'cache', 'true', 'forget');
|
|
}
|
|
}
|
|
|
|
// If the buddy is online
|
|
else {
|
|
// When the buddy is online, we show it
|
|
buddy.removeClass('hidden-buddy');
|
|
|
|
// No filtering is launched?
|
|
if(!Search.search_filtered)
|
|
buddy.show();
|
|
|
|
// Get the online buddy avatar if not a gateway
|
|
Avatar.get(xid, 'cache', avatar, checksum);
|
|
}
|
|
|
|
// Display the presence in the chat
|
|
if(Common.exists('#' + hash)) {
|
|
// We generate a well formed status message
|
|
if(dStatus) {
|
|
// No need to write the same status two times
|
|
if(dStatus == value)
|
|
dStatus = '';
|
|
else
|
|
dStatus = ' (' + dStatus + ')';
|
|
}
|
|
|
|
// We show the presence value
|
|
$('#' + hash + ' .bc-infos').replaceWith('<p class="bc-infos" title="' + tStatus + '"><span class="' + type + ' show talk-images">' + value + '</span>' + dStatus + '</p>');
|
|
|
|
// Process the new status position
|
|
self.adaptChat(hash);
|
|
}
|
|
|
|
// Display the presence in the switcher
|
|
if(Common.exists('#page-switch .' + hash)) {
|
|
$('#page-switch .' + hash + ' .icon').removeClass('available unavailable error away busy').addClass(type);
|
|
}
|
|
|
|
// Update roster groups
|
|
if(!Search.search_filtered) {
|
|
Roster.updateGroups();
|
|
} else {
|
|
Search.funnelFilterBuddy();
|
|
}
|
|
|
|
// Get the disco#infos for this user
|
|
var highest = self.highestPriority(xid);
|
|
|
|
if(highest) {
|
|
Caps.getDiscoInfos(highest, caps);
|
|
} else {
|
|
Caps.displayDiscoInfos(xid, '');
|
|
}
|
|
} catch(e) {
|
|
Console.error('Presence.display', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Process the chat presence position
|
|
* @public
|
|
* @param {string} hash
|
|
* @return {undefined}
|
|
*/
|
|
self.adaptChat = function(hash) {
|
|
|
|
try {
|
|
// Get values
|
|
var pep_numb = $('#' + hash + ' .bc-pep').find('a').size();
|
|
|
|
// Process the left/right position
|
|
var presence_h = 12;
|
|
|
|
if(pep_numb)
|
|
presence_h = (pep_numb * 20) + 18;
|
|
|
|
// Apply the left/right position
|
|
var presence_h_tag = ($('html').attr('dir') == 'rtl') ? 'left' : 'right';
|
|
$('#' + hash + ' p.bc-infos').css(presence_h_tag, presence_h);
|
|
} catch(e) {
|
|
Console.error('Presence.adaptChat', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Convert the presence "show" element into a human-readable output
|
|
* @public
|
|
* @param {string} show
|
|
* @param {string} type
|
|
* @return {undefined}
|
|
*/
|
|
self.humanShow = function(show, type) {
|
|
|
|
try {
|
|
if(type == 'unavailable')
|
|
show = Common._e("Unavailable");
|
|
|
|
else if(type == 'error')
|
|
show = Common._e("Error");
|
|
|
|
else {
|
|
switch(show) {
|
|
case 'chat':
|
|
show = Common._e("Talkative");
|
|
break;
|
|
|
|
case 'away':
|
|
show = Common._e("Away");
|
|
break;
|
|
|
|
case 'xa':
|
|
show = Common._e("Not available");
|
|
break;
|
|
|
|
case 'dnd':
|
|
show = Common._e("Busy");
|
|
break;
|
|
|
|
default:
|
|
show = Common._e("Available");
|
|
break;
|
|
}
|
|
}
|
|
|
|
return show;
|
|
} catch(e) {
|
|
Console.error('Presence.humanShow', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Makes the presence data go in the right way
|
|
* @public
|
|
* @param {string} type
|
|
* @param {string} show
|
|
* @param {string} status
|
|
* @param {string} hash
|
|
* @param {string} xid
|
|
* @param {string} avatar
|
|
* @param {string} checksum
|
|
* @param {string} caps
|
|
* @return {undefined}
|
|
*/
|
|
self.IA = function(type, show, status, hash, xid, avatar, checksum, caps) {
|
|
|
|
try {
|
|
// Is there a status defined?
|
|
if(!status)
|
|
status = self.humanShow(show, type);
|
|
|
|
// Then we can handle the events
|
|
if(type == 'error')
|
|
self.display(Common._e("Error"), 'error', show, status, hash, xid, avatar, checksum, caps);
|
|
|
|
else if(type == 'unavailable')
|
|
self.display(Common._e("Unavailable"), 'unavailable', show, status, hash, xid, avatar, checksum, caps);
|
|
|
|
else {
|
|
switch(show) {
|
|
case 'chat':
|
|
self.display(Common._e("Talkative"), 'available', show, status, hash, xid, avatar, checksum, caps);
|
|
break;
|
|
|
|
case 'away':
|
|
self.display(Common._e("Away"), 'away', show, status, hash, xid, avatar, checksum, caps);
|
|
break;
|
|
|
|
case 'xa':
|
|
self.display(Common._e("Not available"), 'busy', show, status, hash, xid, avatar, checksum, caps);
|
|
break;
|
|
|
|
case 'dnd':
|
|
self.display(Common._e("Busy"), 'busy', show, status, hash, xid, avatar, checksum, caps);
|
|
break;
|
|
|
|
default:
|
|
self.display(Common._e("Available"), 'available', show, status, hash, xid, avatar, checksum, caps);
|
|
break;
|
|
}
|
|
}
|
|
} catch(e) {
|
|
Console.error('Presence.IA', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Flush the presence data for a given user
|
|
* @public
|
|
* @param {string} xid
|
|
* @return {boolean}
|
|
*/
|
|
self.flush = function(xid) {
|
|
|
|
try {
|
|
var flushed_marker = false;
|
|
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)) {
|
|
// Get the current XID
|
|
var now_full = RegExp.$1;
|
|
var now_bare = Common.bareXID(now_full);
|
|
|
|
// If the current XID equals the asked XID
|
|
if(now_bare == xid) {
|
|
if(DataStore.removeDB(Connection.desktop_hash, 'presence-stanza', now_full)) {
|
|
Console.info('Presence data flushed for: ' + now_full);
|
|
|
|
flushed_marker = true;
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return flushed_marker;
|
|
} catch(e) {
|
|
Console.error('Presence.flush', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Process the highest resource priority for an user
|
|
* @public
|
|
* @param {string} xid
|
|
* @param {string} resource
|
|
* @param {object} resources_obj
|
|
* @return {undefined}
|
|
*/
|
|
self.processPriority = function(xid, resource, resources_obj) {
|
|
|
|
try {
|
|
if(!xid) {
|
|
Console.warn('No XID value');
|
|
return;
|
|
}
|
|
|
|
// Initialize vars
|
|
var cur_resource, cur_from, cur_pr,
|
|
cur_xml, cur_priority,
|
|
from_highest;
|
|
|
|
from_highest = null;
|
|
max_priority = null;
|
|
|
|
// Groupchat presence? (no priority here)
|
|
if(xid.indexOf('/') !== -1) {
|
|
from_highest = xid;
|
|
|
|
Console.log('Processed presence for groupchat user: ' + xid);
|
|
} else {
|
|
if(!self.highestPriority(xid)) {
|
|
from_highest = xid + '/' + resource;
|
|
|
|
Console.log('Processed initial presence for regular user: ' + xid + ' (highest priority for: ' + (from_highest || 'none') + ')');
|
|
} else {
|
|
for(cur_resource in resources_obj) {
|
|
// Read presence data
|
|
cur_from = xid + '/' + cur_resource;
|
|
cur_pr = DataStore.getDB(Connection.desktop_hash, 'presence-stanza', cur_from);
|
|
|
|
if(cur_pr) {
|
|
// Parse presence data
|
|
cur_xml = Common.XMLFromString(cur_pr);
|
|
cur_priority = $(cur_xml).find('priority').text();
|
|
cur_priority = !isNaN(cur_priority) ? parseInt(cur_priority) : 0;
|
|
|
|
// Higher priority?
|
|
if((cur_priority >= max_priority) || (max_priority === null)) {
|
|
max_priority = cur_priority;
|
|
from_highest = cur_from;
|
|
}
|
|
}
|
|
}
|
|
|
|
Console.log('Processed presence for regular user: ' + xid + ' (highest priority for: ' + (from_highest || 'none') + ')');
|
|
}
|
|
}
|
|
|
|
if(from_highest)
|
|
DataStore.setDB(Connection.desktop_hash, 'presence-priority', xid, from_highest);
|
|
else
|
|
DataStore.removeDB(Connection.desktop_hash, 'presence-priority', xid);
|
|
} catch(e) {
|
|
Console.error('Presence.processPriority', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Returns the highest presence priority XID for an user
|
|
* @public
|
|
* @param {string} xid
|
|
* @return {string}
|
|
*/
|
|
self.highestPriority = function(xid) {
|
|
|
|
try {
|
|
return DataStore.getDB(Connection.desktop_hash, 'presence-priority', xid) || '';
|
|
} catch(e) {
|
|
Console.error('Presence.highestPriority', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Gets the presence stanza for given full XID
|
|
* @public
|
|
* @param {string} xid_full
|
|
* @return {object}
|
|
*/
|
|
self.readStanza = function(xid_full) {
|
|
|
|
try {
|
|
var pr = DataStore.getDB(Connection.desktop_hash, 'presence-stanza', xid_full);
|
|
|
|
if(!pr) {
|
|
pr = '<presence><type>unavailable</type></presence>';
|
|
}
|
|
|
|
return Common.XMLFromString(pr);
|
|
} catch(e) {
|
|
Console.error('Presence.readStanza', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Gets the resource from a XID which has the highest priority
|
|
* @public
|
|
* @param {string} xid
|
|
* @return {object}
|
|
*/
|
|
self.highestPriorityStanza = function(xid) {
|
|
|
|
try {
|
|
return self.readStanza(
|
|
self.highestPriority(xid)
|
|
);
|
|
} catch(e) {
|
|
Console.error('Presence.highestPriorityStanza', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Lists presence resources for an user
|
|
* @public
|
|
* @param {string} xid
|
|
* @return {object}
|
|
*/
|
|
self.resources = function(xid) {
|
|
|
|
try {
|
|
var resources_obj = {};
|
|
var resources_db = DataStore.getDB(Connection.desktop_hash, 'presence-resources', xid);
|
|
|
|
if(resources_db) {
|
|
resources_obj = $.evalJSON(resources_db);
|
|
}
|
|
|
|
return resources_obj;
|
|
} catch(e) {
|
|
Console.error('Presence.resources', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Adds a given presence resource for an user
|
|
* @public
|
|
* @param {string} xid
|
|
* @param {string} resource
|
|
* @return {object}
|
|
*/
|
|
self.addResource = function(xid, resource) {
|
|
|
|
var resources_obj = null;
|
|
|
|
try {
|
|
resources_obj = self.resources(xid);
|
|
|
|
resources_obj[resource] = 1;
|
|
DataStore.setDB(Connection.desktop_hash, 'presence-resources', xid, $.toJSON(resources_obj));
|
|
} catch(e) {
|
|
Console.error('Presence.addResource', e);
|
|
} finally {
|
|
return resources_obj;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Removes a given presence resource for an user
|
|
* @public
|
|
* @param {string} xid
|
|
* @param {string} resource
|
|
* @return {object}
|
|
*/
|
|
self.removeResource = function(xid, resource) {
|
|
|
|
var resources_obj = null;
|
|
|
|
try {
|
|
resources_obj = self.resources(xid);
|
|
|
|
delete resources_obj[resource];
|
|
DataStore.setDB(Connection.desktop_hash, 'presence-resources', xid, $.toJSON(resources_obj));
|
|
} catch(e) {
|
|
Console.error('Presence.removeResource', e);
|
|
} finally {
|
|
return resources_obj;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Makes something easy to process for the presence IA
|
|
* @public
|
|
* @param {string} xid
|
|
* @param {string} hash
|
|
* @return {undefined}
|
|
*/
|
|
self.funnel = function(xid, hash) {
|
|
|
|
try {
|
|
// Get the highest priority presence value
|
|
var xml = $(self.highestPriorityStanza(xid));
|
|
var type = xml.find('type').text();
|
|
var show = xml.find('show').text();
|
|
var status = xml.find('status').text();
|
|
var avatar = xml.find('avatar').text();
|
|
var checksum = xml.find('checksum').text();
|
|
var caps = xml.find('caps').text();
|
|
|
|
// Display the presence with that stored value
|
|
if(!type && !show)
|
|
self.IA('', 'available', status, hash, xid, avatar, checksum, caps);
|
|
else
|
|
self.IA(type, show, status, hash, xid, avatar, checksum, caps);
|
|
} catch(e) {
|
|
Console.error('Presence.funnel', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Sends a defined presence packet
|
|
* @public
|
|
* @param {string} to
|
|
* @param {string} type
|
|
* @param {string} show
|
|
* @param {string} status
|
|
* @param {string} checksum
|
|
* @param {number} limit_history
|
|
* @param {string} password
|
|
* @param {function} handle
|
|
* @return {undefined}
|
|
*/
|
|
self.send = function(to, type, show, status, checksum, limit_history, password, handle) {
|
|
|
|
try {
|
|
// Get some stuffs
|
|
var priority = DataStore.getDB(Connection.desktop_hash, 'priority', 1);
|
|
|
|
if(!priority)
|
|
priority = '1';
|
|
if(!checksum)
|
|
checksum = DataStore.getDB(Connection.desktop_hash, 'checksum', 1);
|
|
if(show == 'available')
|
|
show = '';
|
|
if(type == 'available')
|
|
type = '';
|
|
|
|
// New presence
|
|
var presence = new JSJaCPresence();
|
|
|
|
// Avoid "null" or "none" if nothing stored
|
|
if(!checksum || (checksum == 'none'))
|
|
checksum = '';
|
|
|
|
// Presence headers
|
|
if(to)
|
|
presence.setTo(to);
|
|
if(type)
|
|
presence.setType(type);
|
|
if(show)
|
|
presence.setShow(show);
|
|
if(status)
|
|
presence.setStatus(status);
|
|
|
|
presence.setPriority(priority);
|
|
|
|
// CAPS (entity capabilities)
|
|
presence.appendNode('c', {'xmlns': NS_CAPS, 'hash': 'sha-1', 'node': 'http://jappix.org/', 'ver': Caps.mine()});
|
|
|
|
// Nickname
|
|
var nickname = Name.get();
|
|
|
|
if(nickname && !limit_history)
|
|
presence.appendNode('nick', {'xmlns': NS_NICK}, nickname);
|
|
|
|
// vcard-temp:x:update node
|
|
var x = presence.appendNode('x', {'xmlns': NS_VCARD_P});
|
|
x.appendChild(presence.buildNode('photo', {'xmlns': NS_VCARD_P}, checksum));
|
|
|
|
// MUC X data
|
|
if(limit_history || password) {
|
|
var xMUC = presence.appendNode('x', {'xmlns': NS_MUC});
|
|
|
|
// Max messages age (for MUC)
|
|
if(limit_history)
|
|
xMUC.appendChild(presence.buildNode('history', {'maxstanzas': 20, 'seconds': 86400, 'xmlns': NS_MUC}));
|
|
|
|
// Room password
|
|
if(password)
|
|
xMUC.appendChild(presence.buildNode('password', {'xmlns': NS_MUC}, password));
|
|
}
|
|
|
|
// If away, send a last activity time
|
|
if((show == 'away') || (show == 'xa')) {
|
|
/* REF: http://xmpp.org/extensions/xep-0256.html */
|
|
|
|
presence.appendNode(presence.buildNode('query', {
|
|
'xmlns': NS_LAST,
|
|
'seconds': DateUtils.getPresenceLast()
|
|
}));
|
|
}
|
|
|
|
// Else, set a new last activity stamp
|
|
else
|
|
DateUtils.presence_last_activity = DateUtils.getTimeStamp();
|
|
|
|
// Send the presence packet
|
|
if(handle)
|
|
con.send(presence, handle);
|
|
else
|
|
con.send(presence);
|
|
|
|
if(!type)
|
|
type = 'available';
|
|
|
|
Console.info('Presence sent: ' + type);
|
|
} catch(e) {
|
|
Console.error('Presence.send', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Performs all the actions to get the presence data
|
|
* @public
|
|
* @param {string} checksum
|
|
* @param {boolean} autoidle
|
|
* @return {undefined}
|
|
*/
|
|
self.sendActions = function(checksum, autoidle) {
|
|
|
|
try {
|
|
// We get the values of the inputs
|
|
var show = self.getUserShow();
|
|
var status = self.getUserStatus();
|
|
|
|
// Send the presence
|
|
if(!Utils.isAnonymous())
|
|
self.send('', '', show, status, checksum);
|
|
|
|
// We set the good icon
|
|
self.icon(show);
|
|
|
|
// We store our presence
|
|
if(!autoidle)
|
|
DataStore.setDB(Connection.desktop_hash, 'presence-show', 1, show);
|
|
|
|
// We send the presence to our active MUC
|
|
$('.page-engine-chan[data-type="groupchat"]').each(function() {
|
|
var tmp_nick = $(this).attr('data-nick');
|
|
|
|
if(!tmp_nick)
|
|
return;
|
|
|
|
var room = unescape($(this).attr('data-xid'));
|
|
var nick = unescape(tmp_nick);
|
|
|
|
// Must re-initialize?
|
|
if(RESUME)
|
|
Groupchat.getMUC(room, nick);
|
|
|
|
// Not disabled?
|
|
else if(!$(this).find('.message-area').attr('disabled'))
|
|
self.send(room + '/' + nick, '', show, status, '', true);
|
|
});
|
|
} catch(e) {
|
|
Console.error('Presence.quickSend', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Changes the presence icon
|
|
* @public
|
|
* @param {string} value
|
|
* @return {undefined}
|
|
*/
|
|
self.icon = function(value) {
|
|
|
|
try {
|
|
$('#my-infos .f-presence a.picker').attr('data-value', value);
|
|
} catch(e) {
|
|
Console.error('Presence.icon', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Sends a subscribe stanza
|
|
* @public
|
|
* @param {string} to
|
|
* @param {string} type
|
|
* @return {undefined}
|
|
*/
|
|
self.sendSubscribe = function(to, type) {
|
|
|
|
try {
|
|
var status = '';
|
|
|
|
// Subscribe request?
|
|
if(type == 'subscribe')
|
|
status = Common.printf(Common._e("Hi, I am %s, I would like to add you as my friend."), Name.get());
|
|
|
|
self.send(to, type, '', status);
|
|
} catch(e) {
|
|
Console.error('Presence.sendSubscribe', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Accepts the subscription from another entity
|
|
* @public
|
|
* @param {string} xid
|
|
* @param {string} name
|
|
* @return {undefined}
|
|
*/
|
|
self.acceptSubscribe = function(xid, name) {
|
|
|
|
try {
|
|
// We update our chat
|
|
$('#' + hex_md5(xid) + ' .tools-add').hide();
|
|
|
|
// We send a subsribed presence (to confirm)
|
|
self.sendSubscribe(xid, 'subscribed');
|
|
|
|
// We send a subscription request (subscribe both sides)
|
|
self.sendSubscribe(xid, 'subscribe');
|
|
|
|
// Specify the buddy name (if any)
|
|
if(name) {
|
|
Roster.send(xid, '', name);
|
|
}
|
|
} catch(e) {
|
|
Console.error('Presence.acceptSubscribe', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Sends automatic away presence
|
|
* @public
|
|
* @return {undefined}
|
|
*/
|
|
self.autoIdle = function() {
|
|
|
|
try {
|
|
// Not connected?
|
|
if(!Common.isConnected())
|
|
return;
|
|
|
|
// Stop if an xa presence was set manually
|
|
var last_presence = self.getUserShow();
|
|
|
|
if(!self.auto_idle && ((last_presence == 'away') || (last_presence == 'xa')))
|
|
return;
|
|
|
|
var idle_presence;
|
|
var activity_limit;
|
|
|
|
// Can we extend to auto extended away mode (20 minutes)?
|
|
if(self.auto_idle && (last_presence == 'away')) {
|
|
idle_presence = 'xa';
|
|
activity_limit = 1200;
|
|
}
|
|
|
|
// We must set the user to auto-away (10 minutes)
|
|
else {
|
|
idle_presence = 'away';
|
|
activity_limit = 600;
|
|
}
|
|
|
|
// The user is really inactive and has set another presence than extended away
|
|
if(((!self.auto_idle && (last_presence != 'away')) || (self.auto_idle && (last_presence == 'away'))) && (DateUtils.getLastActivity() >= activity_limit)) {
|
|
// Then tell we use an auto presence
|
|
self.auto_idle = true;
|
|
|
|
// Get the old status message
|
|
var status = DataStore.getDB(Connection.desktop_hash, 'options', 'presence-status');
|
|
|
|
if(!status)
|
|
status = '';
|
|
|
|
// Change the presence input
|
|
$('#my-infos .f-presence a.picker').attr('data-value', idle_presence);
|
|
$('#presence-status').val(status);
|
|
|
|
// Then send the xa presence
|
|
self.sendActions('', true);
|
|
|
|
Console.info('Auto-idle presence sent: ' + idle_presence);
|
|
}
|
|
} catch(e) {
|
|
Console.error('Presence.autoIdle', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Restores the old presence on a document bind
|
|
* @public
|
|
* @return {undefined}
|
|
*/
|
|
self.eventIdle = function() {
|
|
|
|
try {
|
|
// If we were idle, restore our old presence
|
|
if(self.auto_idle) {
|
|
// Get the values
|
|
var show = DataStore.getDB(Connection.desktop_hash, 'presence-show', 1);
|
|
var status = DataStore.getDB(Connection.desktop_hash, 'options', 'presence-status');
|
|
|
|
// Change the presence input
|
|
$('#my-infos .f-presence a.picker').attr('data-value', show);
|
|
$('#presence-status').val(status);
|
|
$('#presence-status').placeholder();
|
|
|
|
// Then restore the old presence
|
|
self.sendActions('', true);
|
|
|
|
if(!show)
|
|
show = 'available';
|
|
|
|
Console.info('Presence restored: ' + show);
|
|
}
|
|
|
|
// Apply some values
|
|
self.auto_idle = false;
|
|
DateUtils.last_activity = DateUtils.getTimeStamp();
|
|
} catch(e) {
|
|
Console.error('Presence.eventIdle', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Lives the auto idle functions
|
|
* @public
|
|
* @return {undefined}
|
|
*/
|
|
self.liveIdle = function() {
|
|
|
|
try {
|
|
// Apply the autoIdle function every minute
|
|
self.auto_idle = false;
|
|
$('#my-infos .f-presence').everyTime('30s', self.autoIdle);
|
|
|
|
// On body bind (click & key event)
|
|
$('body').on('mousedown', self.eventIdle)
|
|
.on('mousemove', self.eventIdle)
|
|
.on('keydown', self.eventIdle);
|
|
} catch(e) {
|
|
Console.error('Presence.liveIdle', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Kills the auto idle functions
|
|
* @public
|
|
* @return {undefined}
|
|
*/
|
|
self.dieIdle = function() {
|
|
|
|
try {
|
|
// Remove the event detector
|
|
$('body').off('mousedown', self.eventIdle)
|
|
.off('mousemove', self.eventIdle)
|
|
.off('keydown', self.eventIdle);
|
|
} catch(e) {
|
|
Console.error('Presence.dieIdle', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Gets the user presence show
|
|
* @public
|
|
* @return {string}
|
|
*/
|
|
self.getUserShow = function() {
|
|
|
|
try {
|
|
return $('#my-infos .f-presence a.picker').attr('data-value');
|
|
} catch(e) {
|
|
Console.error('Presence.getUserShow', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Gets the user presence status
|
|
* @public
|
|
* @return {string}
|
|
*/
|
|
self.getUserStatus = function() {
|
|
|
|
try {
|
|
return $('#presence-status').val();
|
|
} catch(e) {
|
|
Console.error('Presence.getUserStatus', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Plugin launcher
|
|
* @public
|
|
* @return {undefined}
|
|
*/
|
|
self.instance = function() {
|
|
|
|
try {
|
|
// Click event for user presence show
|
|
$('#my-infos .f-presence a.picker').click(function() {
|
|
// Disabled?
|
|
if($(this).hasClass('disabled'))
|
|
return false;
|
|
|
|
// Initialize some vars
|
|
var path = '#my-infos .f-presence div.bubble';
|
|
var show_id = ['xa', 'away', 'available'];
|
|
var show_lang = [Common._e("Not available"), Common._e("Away"), Common._e("Available")];
|
|
var show_val = self.getUserShow();
|
|
|
|
// Yet displayed?
|
|
var can_append = true;
|
|
|
|
if(Common.exists(path))
|
|
can_append = false;
|
|
|
|
// Add this bubble!
|
|
Bubble.show(path);
|
|
|
|
if(!can_append)
|
|
return false;
|
|
|
|
// Generate the HTML code
|
|
var html = '<div class="bubble removable">';
|
|
|
|
for(var i in show_id) {
|
|
// Yet in use: no need to display it!
|
|
if(show_id[i] == show_val)
|
|
continue;
|
|
|
|
html += '<a href="#" class="talk-images" data-value="' + show_id[i] + '" title="' + show_lang[i] + '"></a>';
|
|
}
|
|
|
|
html += '</div>';
|
|
|
|
// Append the HTML code
|
|
$('#my-infos .f-presence').append(html);
|
|
|
|
// Click event
|
|
$(path + ' a').click(function() {
|
|
// Update the presence show marker
|
|
$('#my-infos .f-presence a.picker').attr('data-value', $(this).attr('data-value'));
|
|
|
|
// Close the bubble
|
|
Bubble.close();
|
|
|
|
// Focus on the status input
|
|
$(document).oneTime(10, function() {
|
|
$('#presence-status').focus();
|
|
});
|
|
|
|
return false;
|
|
});
|
|
|
|
return false;
|
|
});
|
|
|
|
// Submit events for user presence status
|
|
$('#presence-status').placeholder()
|
|
|
|
.keyup(function(e) {
|
|
if(e.keyCode == 13) {
|
|
$(this).blur();
|
|
|
|
return false;
|
|
}
|
|
})
|
|
|
|
.blur(function() {
|
|
// Read the parameters
|
|
var show = self.getUserShow();
|
|
var status = self.getUserStatus();
|
|
|
|
// Read the old parameters
|
|
var old_show = DataStore.getDB(Connection.desktop_hash, 'presence-show', 1);
|
|
var old_status = DataStore.getDB(Connection.desktop_hash, 'options', 'presence-status');
|
|
|
|
// Must send the presence?
|
|
if((show != old_show) || (status != old_status)) {
|
|
// Update the local stored status
|
|
DataStore.setDB(Connection.desktop_hash, 'options', 'presence-status', status);
|
|
|
|
// Update the server stored status
|
|
if(status != old_status)
|
|
Options.store();
|
|
|
|
// Send the presence
|
|
self.sendActions();
|
|
}
|
|
})
|
|
|
|
// Input focus handler
|
|
.focus(function() {
|
|
Bubble.close();
|
|
});
|
|
} catch(e) {
|
|
Console.error('Presence.instance', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Return class scope
|
|
*/
|
|
return self;
|
|
|
|
})(); |