mirror of
https://git.friendi.ca/friendica/friendica-addons.git
synced 2024-11-29 23:53:20 +00:00
1624 lines
40 KiB
JavaScript
1624 lines
40 KiB
JavaScript
|
/*
|
||
|
|
||
|
Jappix - An open social platform
|
||
|
These are the Jappix Mini JS scripts for Jappix
|
||
|
|
||
|
-------------------------------------------------
|
||
|
|
||
|
License: AGPL
|
||
|
Author: Vanaryon
|
||
|
Last revision: 04/08/11
|
||
|
|
||
|
*/
|
||
|
|
||
|
// Jappix Mini vars
|
||
|
var MINI_DISCONNECT = false;
|
||
|
var MINI_AUTOCONNECT = false;
|
||
|
var MINI_SHOWPANE = false;
|
||
|
var MINI_INITIALIZED = false;
|
||
|
var MINI_ANONYMOUS = false;
|
||
|
var MINI_ANIMATE = false;
|
||
|
var MINI_NICKNAME = null;
|
||
|
var MINI_TITLE = null;
|
||
|
var MINI_DOMAIN = null;
|
||
|
var MINI_USER = null;
|
||
|
var MINI_PASSWORD = null;
|
||
|
var MINI_RECONNECT = 0;
|
||
|
var MINI_GROUPCHATS = [];
|
||
|
var MINI_PASSWORDS = [];
|
||
|
var MINI_RESOURCE = JAPPIX_RESOURCE + ' Mini';
|
||
|
|
||
|
// Setups connection handlers
|
||
|
function setupConMini(con) {
|
||
|
con.registerHandler('message', handleMessageMini);
|
||
|
con.registerHandler('presence', handlePresenceMini);
|
||
|
con.registerHandler('iq', handleIQMini);
|
||
|
con.registerHandler('onerror', handleErrorMini);
|
||
|
con.registerHandler('onconnect', connectedMini);
|
||
|
}
|
||
|
|
||
|
// Connects the user with the given logins
|
||
|
function connectMini(domain, user, password) {
|
||
|
try {
|
||
|
// We define the http binding parameters
|
||
|
oArgs = new Object();
|
||
|
|
||
|
if(HOST_BOSH_MINI)
|
||
|
oArgs.httpbase = HOST_BOSH_MINI;
|
||
|
else
|
||
|
oArgs.httpbase = HOST_BOSH;
|
||
|
|
||
|
// We create the new http-binding connection
|
||
|
con = new JSJaCHttpBindingConnection(oArgs);
|
||
|
|
||
|
// And we handle everything that happen
|
||
|
setupConMini(con);
|
||
|
|
||
|
// Generate a resource
|
||
|
var random_resource = getDB('jappix-mini', 'resource');
|
||
|
|
||
|
if(!random_resource)
|
||
|
random_resource = MINI_RESOURCE + ' (' + (new Date()).getTime() + ')';
|
||
|
|
||
|
// We retrieve what the user typed in the login inputs
|
||
|
oArgs = new Object();
|
||
|
oArgs.secure = true;
|
||
|
oArgs.xmllang = XML_LANG;
|
||
|
oArgs.resource = random_resource;
|
||
|
oArgs.domain = domain;
|
||
|
|
||
|
// Store the resource (for reconnection)
|
||
|
setDB('jappix-mini', 'resource', random_resource);
|
||
|
|
||
|
// Anonymous login?
|
||
|
if(MINI_ANONYMOUS) {
|
||
|
// Anonymous mode disabled?
|
||
|
if(!allowedAnonymous()) {
|
||
|
logThis('Not allowed to use anonymous mode.', 2);
|
||
|
|
||
|
// Notify this error
|
||
|
notifyErrorMini();
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Bad domain?
|
||
|
else if(lockHost() && (domain != HOST_ANONYMOUS)) {
|
||
|
logThis('Not allowed to connect to this anonymous domain: ' + domain, 2);
|
||
|
|
||
|
// Notify this error
|
||
|
notifyErrorMini();
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
oArgs.authtype = 'saslanon';
|
||
|
}
|
||
|
|
||
|
// Normal login
|
||
|
else {
|
||
|
// Bad domain?
|
||
|
if(lockHost() && (domain != HOST_MAIN)) {
|
||
|
logThis('Not allowed to connect to this main domain: ' + domain, 2);
|
||
|
|
||
|
// Notify this error
|
||
|
notifyErrorMini();
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// No nickname?
|
||
|
if(!MINI_NICKNAME)
|
||
|
MINI_NICKNAME = user;
|
||
|
|
||
|
oArgs.username = user;
|
||
|
oArgs.pass = password;
|
||
|
}
|
||
|
|
||
|
// We connect !
|
||
|
con.connect(oArgs);
|
||
|
|
||
|
logThis('Jappix Mini is connecting...', 3);
|
||
|
}
|
||
|
|
||
|
catch(e) {
|
||
|
// Logs errors
|
||
|
logThis('Error while logging in: ' + e, 1);
|
||
|
|
||
|
// Reset Jappix Mini
|
||
|
disconnectedMini();
|
||
|
}
|
||
|
|
||
|
finally {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// When the user is connected
|
||
|
function connectedMini() {
|
||
|
// Update the roster
|
||
|
jQuery('#jappix_mini a.jm_pane.jm_button span.jm_counter').text('0');
|
||
|
|
||
|
// Do not get the roster if anonymous
|
||
|
if(MINI_ANONYMOUS)
|
||
|
initializeMini();
|
||
|
else
|
||
|
getRosterMini();
|
||
|
|
||
|
// For logger
|
||
|
if(MINI_RECONNECT)
|
||
|
logThis('Jappix Mini is now reconnected.', 3);
|
||
|
else
|
||
|
logThis('Jappix Mini is now connected.', 3);
|
||
|
|
||
|
// Reset reconnect var
|
||
|
MINI_RECONNECT = 0;
|
||
|
}
|
||
|
|
||
|
// When the user disconnects
|
||
|
function saveSessionMini() {
|
||
|
// Not connected?
|
||
|
if(!isConnected())
|
||
|
return;
|
||
|
|
||
|
// Save the actual Jappix Mini DOM
|
||
|
setDB('jappix-mini', 'dom', jQuery('#jappix_mini').html());
|
||
|
setDB('jappix-mini', 'nickname', MINI_NICKNAME);
|
||
|
|
||
|
// Save the scrollbar position
|
||
|
var scroll_position = '';
|
||
|
var scroll_hash = jQuery('#jappix_mini div.jm_conversation:has(a.jm_pane.jm_clicked)').attr('data-hash');
|
||
|
|
||
|
if(scroll_hash)
|
||
|
scroll_position = document.getElementById('received-' + scroll_hash).scrollTop + '';
|
||
|
|
||
|
setDB('jappix-mini', 'scroll', scroll_position);
|
||
|
|
||
|
// Save the session stamp
|
||
|
setDB('jappix-mini', 'stamp', getTimeStamp());
|
||
|
|
||
|
// Suspend connection
|
||
|
con.suspend(false);
|
||
|
|
||
|
logThis('Jappix Mini session save tool launched.', 3);
|
||
|
}
|
||
|
|
||
|
// Disconnects the connected user
|
||
|
function disconnectMini() {
|
||
|
// No connection?
|
||
|
if(!isConnected())
|
||
|
return false;
|
||
|
|
||
|
// Change markers
|
||
|
MINI_DISCONNECT = true;
|
||
|
MINI_INITIALIZED = false;
|
||
|
|
||
|
// Add disconnection handler
|
||
|
con.registerHandler('ondisconnect', disconnectedMini);
|
||
|
|
||
|
// Disconnect the user
|
||
|
con.disconnect();
|
||
|
|
||
|
logThis('Jappix Mini is disconnecting...', 3);
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// When the user is disconnected
|
||
|
function disconnectedMini() {
|
||
|
// Remove the stored items
|
||
|
removeDB('jappix-mini', 'dom');
|
||
|
removeDB('jappix-mini', 'nickname');
|
||
|
removeDB('jappix-mini', 'scroll');
|
||
|
removeDB('jappix-mini', 'stamp');
|
||
|
|
||
|
// Connection error?
|
||
|
if(!MINI_DISCONNECT || MINI_INITIALIZED) {
|
||
|
// Browser error?
|
||
|
notifyErrorMini();
|
||
|
|
||
|
// Reset reconnect timer
|
||
|
jQuery('#jappix_mini').stopTime();
|
||
|
|
||
|
// Try to reconnect after a while
|
||
|
if(MINI_INITIALIZED && (MINI_RECONNECT < 5)) {
|
||
|
// Reconnect interval
|
||
|
var reconnect_interval = 10;
|
||
|
|
||
|
if(MINI_RECONNECT)
|
||
|
reconnect_interval = (5 + (5 * MINI_RECONNECT)) * 1000;
|
||
|
|
||
|
MINI_RECONNECT++;
|
||
|
|
||
|
// Set timer
|
||
|
jQuery('#jappix_mini').oneTime(reconnect_interval, function() {
|
||
|
launchMini(true, MINI_SHOWPANE, MINI_DOMAIN, MINI_USER, MINI_PASSWORD);
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Normal disconnection?
|
||
|
else
|
||
|
launchMini(false, MINI_SHOWPANE, MINI_DOMAIN, MINI_USER, MINI_PASSWORD);
|
||
|
|
||
|
// Reset markers
|
||
|
MINI_DISCONNECT = false;
|
||
|
MINI_INITIALIZED = false;
|
||
|
|
||
|
logThis('Jappix Mini is now disconnected.', 3);
|
||
|
}
|
||
|
|
||
|
// Handles the incoming messages
|
||
|
function handleMessageMini(msg) {
|
||
|
var type = msg.getType();
|
||
|
|
||
|
// This is a message Jappix can handle
|
||
|
if((type == 'chat') || (type == 'normal') || (type == 'groupchat') || !type) {
|
||
|
// Get the body
|
||
|
var body = trim(msg.getBody());
|
||
|
|
||
|
// Any subject?
|
||
|
var subject = trim(msg.getSubject());
|
||
|
|
||
|
if(subject)
|
||
|
body = subject;
|
||
|
|
||
|
if(body) {
|
||
|
// Get the values
|
||
|
var from = fullXID(getStanzaFrom(msg));
|
||
|
var xid = bareXID(from);
|
||
|
var use_xid = xid;
|
||
|
var hash = hex_md5(xid);
|
||
|
var nick = thisResource(from);
|
||
|
|
||
|
// Read the delay
|
||
|
var delay = readMessageDelay(msg.getNode());
|
||
|
var d_stamp;
|
||
|
|
||
|
// Manage this delay
|
||
|
if(delay) {
|
||
|
time = relativeDate(delay);
|
||
|
d_stamp = Date.jab2date(delay);
|
||
|
}
|
||
|
|
||
|
else {
|
||
|
time = getCompleteTime();
|
||
|
d_stamp = new Date();
|
||
|
}
|
||
|
|
||
|
// Get the stamp
|
||
|
var stamp = extractStamp(d_stamp);
|
||
|
|
||
|
// Is this a groupchat private message?
|
||
|
if(exists('#jappix_mini #chat-' + hash + '[data-type=groupchat]')) {
|
||
|
// Regenerate some stuffs
|
||
|
if((type == 'chat') || !type) {
|
||
|
xid = from;
|
||
|
hash = hex_md5(xid);
|
||
|
}
|
||
|
|
||
|
// XID to use for a groupchat
|
||
|
else
|
||
|
use_xid = from;
|
||
|
}
|
||
|
|
||
|
// Message type
|
||
|
var message_type = 'user-message';
|
||
|
|
||
|
// Grouphat values
|
||
|
if(type == 'groupchat') {
|
||
|
// Old message
|
||
|
if(msg.getChild('delay', NS_URN_DELAY) || msg.getChild('x', NS_DELAY))
|
||
|
message_type = 'old-message';
|
||
|
|
||
|
// System message?
|
||
|
if(!nick || subject) {
|
||
|
nick = '';
|
||
|
message_type = 'system-message';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Chat values
|
||
|
else {
|
||
|
nick = jQuery('#jappix_mini a#friend-' + hash).text().revertHtmlEnc();
|
||
|
|
||
|
// No nickname?
|
||
|
if(!nick)
|
||
|
nick = getXIDNick(xid);
|
||
|
}
|
||
|
|
||
|
// Define the target div
|
||
|
var target = '#jappix_mini #chat-' + hash;
|
||
|
|
||
|
// Create the chat if it does not exist
|
||
|
if(!exists(target) && (type != 'groupchat'))
|
||
|
chatMini(type, xid, nick, hash);
|
||
|
|
||
|
// Display the message
|
||
|
displayMessageMini(type, body, use_xid, nick, hash, time, stamp, message_type);
|
||
|
|
||
|
// Notify the user if not focused & the message is not a groupchat old one
|
||
|
if((!jQuery(target + ' a.jm_chat-tab').hasClass('jm_clicked') || !isFocused()) && (message_type == 'user-message'))
|
||
|
notifyMessageMini(hash);
|
||
|
|
||
|
logThis('Message received from: ' + from);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Handles the incoming IQs
|
||
|
function handleIQMini(iq) {
|
||
|
// Define some variables
|
||
|
var iqFrom = fullXID(getStanzaFrom(iq));
|
||
|
var iqID = iq.getID();
|
||
|
var iqQueryXMLNS = iq.getQueryXMLNS();
|
||
|
var iqType = iq.getType();
|
||
|
var iqNode = iq.getNode();
|
||
|
|
||
|
// Build the response
|
||
|
var iqResponse = new JSJaCIQ();
|
||
|
|
||
|
iqResponse.setID(iqID);
|
||
|
iqResponse.setTo(iqFrom);
|
||
|
iqResponse.setType('result');
|
||
|
|
||
|
// Software version query
|
||
|
if((iqQueryXMLNS == NS_VERSION) && (iqType == 'get')) {
|
||
|
/* REF: http://xmpp.org/extensions/xep-0092.html */
|
||
|
|
||
|
var iqQuery = iqResponse.setQuery(NS_VERSION);
|
||
|
|
||
|
iqQuery.appendChild(iq.buildNode('name', {'xmlns': NS_VERSION}, 'Jappix Mini'));
|
||
|
iqQuery.appendChild(iq.buildNode('version', {'xmlns': NS_VERSION}, JAPPIX_VERSION));
|
||
|
iqQuery.appendChild(iq.buildNode('os', {'xmlns': NS_VERSION}, BrowserDetect.OS));
|
||
|
|
||
|
con.send(iqResponse);
|
||
|
|
||
|
logThis('Received software version query: ' + iqFrom);
|
||
|
}
|
||
|
|
||
|
// Roster push
|
||
|
else if((iqQueryXMLNS == NS_ROSTER) && (iqType == 'set')) {
|
||
|
// Display the friend
|
||
|
handleRosterMini(iq);
|
||
|
|
||
|
con.send(iqResponse);
|
||
|
|
||
|
logThis('Received a roster push.');
|
||
|
}
|
||
|
|
||
|
// Disco info query
|
||
|
else if((iqQueryXMLNS == NS_DISCO_INFO) && (iqType == 'get')) {
|
||
|
/* REF: http://xmpp.org/extensions/xep-0030.html */
|
||
|
|
||
|
var iqQuery = iqResponse.setQuery(NS_DISCO_INFO);
|
||
|
|
||
|
// We set the name of the client
|
||
|
iqQuery.appendChild(iq.appendNode('identity', {
|
||
|
'category': 'client',
|
||
|
'type': 'web',
|
||
|
'name': 'Jappix Mini',
|
||
|
'xmlns': NS_DISCO_INFO
|
||
|
}));
|
||
|
|
||
|
// We set all the supported features
|
||
|
var fArray = new Array(
|
||
|
NS_DISCO_INFO,
|
||
|
NS_VERSION,
|
||
|
NS_ROSTER,
|
||
|
NS_MUC,
|
||
|
NS_VERSION,
|
||
|
NS_URN_TIME
|
||
|
);
|
||
|
|
||
|
for(i in fArray)
|
||
|
iqQuery.appendChild(iq.buildNode('feature', {'var': fArray[i], 'xmlns': NS_DISCO_INFO}));
|
||
|
|
||
|
con.send(iqResponse);
|
||
|
|
||
|
logThis('Received a disco#infos query.');
|
||
|
}
|
||
|
|
||
|
// User time query
|
||
|
else if(jQuery(iqNode).find('time').size() && (iqType == 'get')) {
|
||
|
/* REF: http://xmpp.org/extensions/xep-0202.html */
|
||
|
|
||
|
var iqTime = iqResponse.appendNode('time', {'xmlns': NS_URN_TIME});
|
||
|
iqTime.appendChild(iq.buildNode('tzo', {'xmlns': NS_URN_TIME}, getDateTZO()));
|
||
|
iqTime.appendChild(iq.buildNode('utc', {'xmlns': NS_URN_TIME}, getXMPPTime('utc')));
|
||
|
|
||
|
con.send(iqResponse);
|
||
|
|
||
|
logThis('Received local time query: ' + iqFrom);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Handles the incoming errors
|
||
|
function handleErrorMini(err) {
|
||
|
// First level error (connection error)
|
||
|
if(jQuery(err).is('error')) {
|
||
|
// Notify this error
|
||
|
disconnectedMini();
|
||
|
|
||
|
logThis('First level error received.', 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Handles the incoming presences
|
||
|
function handlePresenceMini(pr) {
|
||
|
// Get the values
|
||
|
var from = fullXID(getStanzaFrom(pr));
|
||
|
var xid = bareXID(from);
|
||
|
var resource = thisResource(from);
|
||
|
var hash = hex_md5(xid);
|
||
|
var type = pr.getType();
|
||
|
var show = pr.getShow();
|
||
|
|
||
|
// Manage the received presence values
|
||
|
if((type == 'error') || (type == 'unavailable'))
|
||
|
show = 'unavailable';
|
||
|
|
||
|
else {
|
||
|
switch(show) {
|
||
|
case 'chat':
|
||
|
case 'away':
|
||
|
case 'xa':
|
||
|
case 'dnd':
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
show = 'available';
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Is this a groupchat presence?
|
||
|
var groupchat_path = '#jappix_mini #chat-' + hash + '[data-type=groupchat]';
|
||
|
|
||
|
if(exists(groupchat_path)) {
|
||
|
// Groupchat buddy presence (not me)
|
||
|
if(resource != unescape(jQuery(groupchat_path).attr('data-nick'))) {
|
||
|
// Regenerate some stuffs
|
||
|
var groupchat = xid;
|
||
|
xid = from;
|
||
|
hash = hex_md5(xid);
|
||
|
|
||
|
// Remove this from the roster
|
||
|
if(show == 'unavailable')
|
||
|
removeBuddyMini(hash, groupchat);
|
||
|
|
||
|
// Add this to the roster
|
||
|
else
|
||
|
addBuddyMini(xid, hash, resource, groupchat);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Friend path
|
||
|
var chat = '#jappix_mini #chat-' + hash;
|
||
|
var friend = '#jappix_mini a#friend-' + hash;
|
||
|
var send_input = chat + ' input.jm_send-messages';
|
||
|
|
||
|
// Is this friend online?
|
||
|
if(show == 'unavailable') {
|
||
|
// Offline marker
|
||
|
jQuery(friend).addClass('jm_offline').removeClass('jm_online');
|
||
|
|
||
|
// Disable the chat tools
|
||
|
jQuery(chat).addClass('jm_disabled');
|
||
|
jQuery(send_input).attr('disabled', true).attr('data-value', _e("Unavailable")).val(_e("Unavailable"));
|
||
|
}
|
||
|
|
||
|
else {
|
||
|
// Online marker
|
||
|
jQuery(friend).removeClass('jm_offline').addClass('jm_online');
|
||
|
|
||
|
// Enable the chat input
|
||
|
jQuery(chat).removeClass('jm_disabled');
|
||
|
jQuery(send_input).removeAttr('disabled').val('');
|
||
|
}
|
||
|
|
||
|
// Change the show presence of this buddy
|
||
|
jQuery(friend + ' span.jm_presence, ' + chat + ' span.jm_presence').attr('class', 'jm_presence jm_images jm_' + show);
|
||
|
|
||
|
// Update the presence counter
|
||
|
updateRosterMini();
|
||
|
|
||
|
logThis('Presence received from: ' + from);
|
||
|
}
|
||
|
|
||
|
// Handles the MUC main elements
|
||
|
function handleMUCMini(pr) {
|
||
|
// We get the xml content
|
||
|
var xml = pr.getNode();
|
||
|
var from = fullXID(getStanzaFrom(pr));
|
||
|
var room = bareXID(from);
|
||
|
var hash = hex_md5(room);
|
||
|
var resource = thisResource(from);
|
||
|
|
||
|
// Is it a valid server presence?
|
||
|
var valid = false;
|
||
|
|
||
|
if(!resource || (resource == unescape(jQuery('#jappix_mini #chat-' + hash + '[data-type=groupchat]').attr('data-nick'))))
|
||
|
valid = true;
|
||
|
|
||
|
// Password required?
|
||
|
if(valid && jQuery(xml).find('error[type=auth] not-authorized').size()) {
|
||
|
// Create a new prompt
|
||
|
openPromptMini(printf(_e("This room (%s) is protected with a password."), room));
|
||
|
|
||
|
// When prompt submitted
|
||
|
jQuery('#jappix_popup div.jm_prompt form').submit(function() {
|
||
|
try {
|
||
|
// Read the value
|
||
|
var password = closePromptMini();
|
||
|
|
||
|
// Any submitted chat to join?
|
||
|
if(password) {
|
||
|
// Send the password
|
||
|
presenceMini('', '', '', '', from, password, true, handleMUCMini);
|
||
|
|
||
|
// Focus on the pane again
|
||
|
switchPaneMini('chat-' + hash, hash);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
catch(e) {}
|
||
|
|
||
|
finally {
|
||
|
return false;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Nickname conflict?
|
||
|
else if(valid && jQuery(xml).find('error[type=cancel] conflict').size()) {
|
||
|
// New nickname
|
||
|
var nickname = resource + '_';
|
||
|
|
||
|
// Send the new presence
|
||
|
presenceMini('', '', '', '', room + '/' + nickname, '', true, handleMUCMini);
|
||
|
|
||
|
// Update the nickname marker
|
||
|
jQuery('#jappix_mini #chat-' + hash).attr('data-nick', escape(nickname));
|
||
|
}
|
||
|
|
||
|
// Handle normal presence
|
||
|
else
|
||
|
handlePresenceMini(pr);
|
||
|
}
|
||
|
|
||
|
// Updates the user presence
|
||
|
function presenceMini(type, show, priority, status, to, password, limit_history, handler) {
|
||
|
var pr = new JSJaCPresence();
|
||
|
|
||
|
// Add the attributes
|
||
|
if(to)
|
||
|
pr.setTo(to);
|
||
|
if(type)
|
||
|
pr.setType(type);
|
||
|
if(show)
|
||
|
pr.setShow(show);
|
||
|
if(priority)
|
||
|
pr.setPriority(priority);
|
||
|
if(status)
|
||
|
pr.setStatus(status);
|
||
|
|
||
|
// Special presence elements
|
||
|
if(password || limit_history) {
|
||
|
var x = pr.appendNode('x', {'xmlns': NS_MUC});
|
||
|
|
||
|
// Any password?
|
||
|
if(password)
|
||
|
x.appendChild(pr.buildNode('password', {'xmlns': NS_MUC}, password));
|
||
|
|
||
|
// Any history limit?
|
||
|
if(limit_history)
|
||
|
x.appendChild(pr.buildNode('history', {'maxstanzas': 10, 'seconds': 86400, 'xmlns': NS_MUC}));
|
||
|
}
|
||
|
|
||
|
// Send the packet
|
||
|
if(handler)
|
||
|
con.send(pr, handler);
|
||
|
else
|
||
|
con.send(pr);
|
||
|
|
||
|
// No type?
|
||
|
if(!type)
|
||
|
type = 'available';
|
||
|
|
||
|
logThis('Presence sent: ' + type, 3);
|
||
|
}
|
||
|
|
||
|
// Sends a given message
|
||
|
function sendMessageMini(aForm) {
|
||
|
try {
|
||
|
var body = trim(aForm.body.value);
|
||
|
var xid = aForm.xid.value;
|
||
|
var type = aForm.type.value;
|
||
|
var hash = hex_md5(xid);
|
||
|
|
||
|
if(body && xid) {
|
||
|
// Send the message
|
||
|
var aMsg = new JSJaCMessage();
|
||
|
|
||
|
aMsg.setTo(xid);
|
||
|
aMsg.setType(type);
|
||
|
aMsg.setBody(body);
|
||
|
|
||
|
con.send(aMsg);
|
||
|
|
||
|
// Clear the input
|
||
|
aForm.body.value = '';
|
||
|
|
||
|
// Display the message we sent
|
||
|
if(type != 'groupchat')
|
||
|
displayMessageMini(type, body, getXID(), 'me', hash, getCompleteTime(), getTimeStamp(), 'user-message');
|
||
|
|
||
|
logThis('Message (' + type + ') sent to: ' + xid);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
catch(e) {}
|
||
|
|
||
|
finally {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Generates the asked smiley image
|
||
|
function smileyMini(image, text) {
|
||
|
return ' <img class="jm_smiley jm_smiley-' + image + ' jm_images" alt="' + encodeQuotes(text) + '" src="' + JAPPIX_STATIC + 'php/get.php?t=img&f=others/blank.gif" /> ';
|
||
|
}
|
||
|
|
||
|
// Notifies incoming chat messages
|
||
|
function notifyMessageMini(hash) {
|
||
|
// Define the paths
|
||
|
var tab = '#jappix_mini #chat-' + hash + ' a.jm_chat-tab';
|
||
|
var notify = tab + ' span.jm_notify';
|
||
|
var notify_middle = notify + ' span.jm_notify_middle';
|
||
|
|
||
|
// Notification box not yet added
|
||
|
if(!exists(notify))
|
||
|
jQuery(tab).append(
|
||
|
'<span class="jm_notify">' +
|
||
|
'<span class="jm_notify_left jm_images"></span>' +
|
||
|
'<span class="jm_notify_middle">0</span>' +
|
||
|
'<span class="jm_notify_right jm_images"></span>' +
|
||
|
'</span>'
|
||
|
);
|
||
|
|
||
|
// Increment the notification number
|
||
|
var number = parseInt(jQuery(notify_middle).text());
|
||
|
jQuery(notify_middle).text(number + 1);
|
||
|
|
||
|
// Change the page title
|
||
|
notifyTitleMini();
|
||
|
}
|
||
|
|
||
|
// Notifies the user from a session error
|
||
|
function notifyErrorMini() {
|
||
|
// Replace the Jappix Mini DOM content
|
||
|
jQuery('#jappix_mini').html(
|
||
|
'<div class="jm_starter">' +
|
||
|
'<a class="jm_pane jm_button jm_images" href="https://mini.jappix.com/issues" target="_blank" title="' + _e("Click here to solve the error") + '">' +
|
||
|
'<span class="jm_counter jm_error jm_images">' + _e("Error") + '</span>' +
|
||
|
'</a>' +
|
||
|
'</div>'
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// Updates the page title with the new notifications
|
||
|
function notifyTitleMini() {
|
||
|
// No saved title? Abort!
|
||
|
if(MINI_TITLE == null)
|
||
|
return false;
|
||
|
|
||
|
// Page title code
|
||
|
var title = MINI_TITLE;
|
||
|
|
||
|
// Count the number of notifications
|
||
|
var number = 0;
|
||
|
|
||
|
jQuery('#jappix_mini span.jm_notify span.jm_notify_middle').each(function() {
|
||
|
number = number + parseInt(jQuery(this).text());
|
||
|
});
|
||
|
|
||
|
// No new stuffs? Reset the title!
|
||
|
if(number)
|
||
|
title = '[' + number + '] ' + title;
|
||
|
|
||
|
// Apply the title
|
||
|
document.title = title;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Clears the notifications
|
||
|
function clearNotificationsMini(hash) {
|
||
|
// Not focused?
|
||
|
if(!isFocused())
|
||
|
return false;
|
||
|
|
||
|
// Remove the notifications counter
|
||
|
jQuery('#jappix_mini #chat-' + hash + ' span.jm_notify').remove();
|
||
|
|
||
|
// Update the page title
|
||
|
notifyTitleMini();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Updates the roster counter
|
||
|
function updateRosterMini() {
|
||
|
jQuery('#jappix_mini a.jm_button span.jm_counter').text(jQuery('#jappix_mini a.jm_online').size());
|
||
|
}
|
||
|
|
||
|
// Creates the Jappix Mini DOM content
|
||
|
function createMini(domain, user, password) {
|
||
|
// Try to restore the DOM
|
||
|
var dom = getDB('jappix-mini', 'dom');
|
||
|
var stamp = parseInt(getDB('jappix-mini', 'stamp'));
|
||
|
var suspended = false;
|
||
|
|
||
|
// Invalid stored DOM?
|
||
|
if(dom && isNaN(jQuery(dom).find('a.jm_pane.jm_button span.jm_counter').text()))
|
||
|
dom = null;
|
||
|
|
||
|
// Can resume a session?
|
||
|
con = new JSJaCHttpBindingConnection();
|
||
|
setupConMini(con);
|
||
|
|
||
|
// Old DOM?
|
||
|
if(dom && ((getTimeStamp() - stamp) < JSJACHBC_MAX_WAIT) && con.resume()) {
|
||
|
// Read the old nickname
|
||
|
MINI_NICKNAME = getDB('jappix-mini', 'nickname');
|
||
|
|
||
|
// Marker
|
||
|
suspended = true;
|
||
|
}
|
||
|
|
||
|
// New DOM?
|
||
|
else {
|
||
|
dom = '<div class="jm_position">' +
|
||
|
'<div class="jm_conversations"></div>' +
|
||
|
|
||
|
'<div class="jm_starter">' +
|
||
|
'<div class="jm_roster">' +
|
||
|
'<div class="jm_actions">' +
|
||
|
'<a class="jm_logo jm_images" href="https://mini.jappix.com/" target="_blank"></a>' +
|
||
|
'<a class="jm_one-action jm_join jm_images" title="' + _e("Join a chat") + '" href="#"></a>' +
|
||
|
'</div>' +
|
||
|
|
||
|
'<div class="jm_buddies"></div>' +
|
||
|
'</div>' +
|
||
|
|
||
|
'<a class="jm_pane jm_button jm_images" href="#">' +
|
||
|
'<span class="jm_counter jm_images">' + _e("Please wait...") + '</span>' +
|
||
|
'</a>' +
|
||
|
'</div>' +
|
||
|
'</div>';
|
||
|
}
|
||
|
|
||
|
// Create the DOM
|
||
|
jQuery('body').append('<div id="jappix_mini">' + dom + '</div>');
|
||
|
|
||
|
// Adapt roster height
|
||
|
adaptRosterMini();
|
||
|
|
||
|
// The click events
|
||
|
jQuery('#jappix_mini a.jm_button').click(function() {
|
||
|
// Using a try/catch override IE issues
|
||
|
try {
|
||
|
// Presence counter
|
||
|
var counter = '#jappix_mini a.jm_pane.jm_button span.jm_counter';
|
||
|
|
||
|
// Cannot open the roster?
|
||
|
if(jQuery(counter).text() == _e("Please wait..."))
|
||
|
return false;
|
||
|
|
||
|
// Not yet connected?
|
||
|
if(jQuery(counter).text() == _e("Chat")) {
|
||
|
// Remove the animated bubble
|
||
|
jQuery('#jappix_mini div.jm_starter span.jm_animate').stopTime().remove();
|
||
|
|
||
|
// Add a waiting marker
|
||
|
jQuery(counter).text(_e("Please wait..."));
|
||
|
|
||
|
// Launch the connection!
|
||
|
connectMini(domain, user, password);
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Normal actions
|
||
|
if(!jQuery(this).hasClass('jm_clicked'))
|
||
|
showRosterMini();
|
||
|
else
|
||
|
hideRosterMini();
|
||
|
}
|
||
|
|
||
|
catch(e) {}
|
||
|
|
||
|
finally {
|
||
|
return false;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
jQuery('#jappix_mini div.jm_actions a.jm_join').click(function() {
|
||
|
// Using a try/catch override IE issues
|
||
|
try {
|
||
|
// Create a new prompt
|
||
|
openPromptMini(_e("Please enter the group chat address to join."));
|
||
|
|
||
|
// When prompt submitted
|
||
|
jQuery('#jappix_popup div.jm_prompt form').submit(function() {
|
||
|
try {
|
||
|
// Read the value
|
||
|
var join_this = closePromptMini();
|
||
|
|
||
|
// Any submitted chat to join?
|
||
|
if(join_this) {
|
||
|
// Get the chat room to join
|
||
|
chat_room = bareXID(generateXID(join_this, 'groupchat'));
|
||
|
|
||
|
// Create a new groupchat
|
||
|
chatMini('groupchat', chat_room, getXIDNick(chat_room), hex_md5(chat_room));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
catch(e) {}
|
||
|
|
||
|
finally {
|
||
|
return false;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
catch(e) {}
|
||
|
|
||
|
finally {
|
||
|
return false;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Hides the roster when clicking away of Jappix Mini
|
||
|
jQuery(document).click(function(evt) {
|
||
|
if(!jQuery(evt.target).parents('#jappix_mini').size() && !exists('#jappix_popup'))
|
||
|
hideRosterMini();
|
||
|
});
|
||
|
|
||
|
// Hides all panes double clicking away of Jappix Mini
|
||
|
jQuery(document).dblclick(function(evt) {
|
||
|
if(!jQuery(evt.target).parents('#jappix_mini').size() && !exists('#jappix_popup'))
|
||
|
switchPaneMini();
|
||
|
});
|
||
|
|
||
|
// Suspended session resumed?
|
||
|
if(suspended) {
|
||
|
// Initialized marker
|
||
|
MINI_INITIALIZED = true;
|
||
|
|
||
|
// Restore chat input values
|
||
|
jQuery('#jappix_mini div.jm_conversation input.jm_send-messages').each(function() {
|
||
|
var chat_value = jQuery(this).attr('data-value');
|
||
|
|
||
|
if(chat_value)
|
||
|
jQuery(this).val(chat_value);
|
||
|
});
|
||
|
|
||
|
// Restore buddy click events
|
||
|
jQuery('#jappix_mini a.jm_friend').click(function() {
|
||
|
// Using a try/catch override IE issues
|
||
|
try {
|
||
|
chatMini('chat', unescape(jQuery(this).attr('data-xid')), unescape(jQuery(this).attr('data-nick')), jQuery(this).attr('data-hash'));
|
||
|
}
|
||
|
|
||
|
catch(e) {}
|
||
|
|
||
|
finally {
|
||
|
return false;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Restore chat click events
|
||
|
jQuery('#jappix_mini div.jm_conversation').each(function() {
|
||
|
chatEventsMini(jQuery(this).attr('data-type'), unescape(jQuery(this).attr('data-xid')), jQuery(this).attr('data-hash'));
|
||
|
});
|
||
|
|
||
|
// Scroll down to the last message
|
||
|
var scroll_hash = jQuery('#jappix_mini div.jm_conversation:has(a.jm_pane.jm_clicked)').attr('data-hash');
|
||
|
var scroll_position = getDB('jappix-mini', 'scroll');
|
||
|
|
||
|
// Any scroll position?
|
||
|
if(scroll_position)
|
||
|
scroll_position = parseInt(scroll_position);
|
||
|
|
||
|
if(scroll_hash) {
|
||
|
// Use a timer to override the DOM lag issue
|
||
|
jQuery(document).oneTime(200, function() {
|
||
|
messageScrollMini(scroll_hash, scroll_position);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// Update title notifications
|
||
|
notifyTitleMini();
|
||
|
}
|
||
|
|
||
|
// Can auto-connect?
|
||
|
else if(MINI_AUTOCONNECT)
|
||
|
connectMini(domain, user, password);
|
||
|
|
||
|
// Cannot auto-connect?
|
||
|
else {
|
||
|
// Chat text
|
||
|
jQuery('#jappix_mini a.jm_pane.jm_button span.jm_counter').text(_e("Chat"));
|
||
|
|
||
|
// Must animate?
|
||
|
if(MINI_ANIMATE) {
|
||
|
// Add content
|
||
|
jQuery('#jappix_mini div.jm_starter').prepend(
|
||
|
'<span class="jm_animate jm_images_animate"></span>'
|
||
|
);
|
||
|
|
||
|
// IE6 makes the image blink when animated...
|
||
|
if((BrowserDetect.browser == 'Explorer') && (BrowserDetect.version < 7))
|
||
|
return;
|
||
|
|
||
|
// Add timers
|
||
|
var anim_i = 0;
|
||
|
|
||
|
jQuery('#jappix_mini div.jm_starter span.jm_animate').everyTime(10, function() {
|
||
|
// Next
|
||
|
anim_i++;
|
||
|
|
||
|
// Margins
|
||
|
var m_top = Math.cos(anim_i * 0.02) * 3;
|
||
|
var m_left = Math.sin(anim_i * 0.02) * 3;
|
||
|
|
||
|
// Apply new position!
|
||
|
jQuery(this).css('margin-top', m_top + 'px')
|
||
|
.css('margin-left', m_left + 'px');
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Displays a given message
|
||
|
function displayMessageMini(type, body, xid, nick, hash, time, stamp, message_type) {
|
||
|
// Generate path
|
||
|
var path = '#chat-' + hash;
|
||
|
|
||
|
// Can scroll?
|
||
|
var cont_scroll = document.getElementById('received-' + hash);
|
||
|
var can_scroll = false;
|
||
|
|
||
|
if(!cont_scroll.scrollTop || ((cont_scroll.clientHeight + cont_scroll.scrollTop) == cont_scroll.scrollHeight))
|
||
|
can_scroll = true;
|
||
|
|
||
|
// Remove the previous message border if needed
|
||
|
var last = jQuery(path + ' div.jm_group:last');
|
||
|
var last_stamp = parseInt(last.attr('data-stamp'));
|
||
|
var last_b = jQuery(path + ' b:last');
|
||
|
var last_xid = last_b.attr('data-xid');
|
||
|
var last_type = last.attr('data-type');
|
||
|
var grouped = false;
|
||
|
var header = '';
|
||
|
|
||
|
if((last_xid == xid) && (message_type == last_type) && ((stamp - last_stamp) <= 1800))
|
||
|
grouped = true;
|
||
|
|
||
|
else {
|
||
|
// Write the message date
|
||
|
if(nick)
|
||
|
header += '<span class="jm_date">' + time + '</span>';
|
||
|
|
||
|
// Write the buddy name at the top of the message group
|
||
|
if(type == 'groupchat')
|
||
|
header += '<b style="color: ' + generateColor(nick) + ';" data-xid="' + encodeQuotes(xid) + '">' + nick.htmlEnc() + '</b>';
|
||
|
else if(nick == 'me')
|
||
|
header += '<b class="jm_me" data-xid="' + encodeQuotes(xid) + '">' + _e("You") + '</b>';
|
||
|
else
|
||
|
header += '<b class="jm_him" data-xid="' + encodeQuotes(xid) + '">' + nick.htmlEnc() + '</b>';
|
||
|
}
|
||
|
|
||
|
// Apply the /me command
|
||
|
var me_command = false;
|
||
|
|
||
|
if(body.match(/^\/me /i)) {
|
||
|
body = body.replace(/^\/me /i, nick + ' ');
|
||
|
|
||
|
// Marker
|
||
|
me_command = true;
|
||
|
}
|
||
|
|
||
|
// HTML-encode the message
|
||
|
body = body.htmlEnc();
|
||
|
|
||
|
// Apply the smileys
|
||
|
body = body.replace(/(;-?\))(\s|$)/gi, smileyMini('wink', '$1'))
|
||
|
.replace(/(:-?3)(\s|$)/gi, smileyMini('waii', '$1'))
|
||
|
.replace(/(:-?\()(\s|$)/gi, smileyMini('unhappy', '$1'))
|
||
|
.replace(/(:-?P)(\s|$)/gi, smileyMini('tongue', '$1'))
|
||
|
.replace(/(:-?O)(\s|$)/gi, smileyMini('surprised', '$1'))
|
||
|
.replace(/(:-?\))(\s|$)/gi, smileyMini('smile', '$1'))
|
||
|
.replace(/(\^_?\^)(\s|$)/gi, smileyMini('happy', '$1'))
|
||
|
.replace(/(:-?D)(\s|$)/gi, smileyMini('grin', '$1'));
|
||
|
|
||
|
// Filter the links
|
||
|
body = applyLinks(body, 'mini');
|
||
|
|
||
|
// Generate the message code
|
||
|
if(me_command)
|
||
|
body = '<em>' + body + '</em>';
|
||
|
|
||
|
body = '<p>' + body + '</p>';
|
||
|
|
||
|
// Create the message
|
||
|
if(grouped)
|
||
|
jQuery('#jappix_mini #chat-' + hash + ' div.jm_received-messages div.jm_group:last').append(body);
|
||
|
else
|
||
|
jQuery('#jappix_mini #chat-' + hash + ' div.jm_received-messages').append('<div class="jm_group jm_' + message_type + '" data-type="' + message_type + '" data-stamp="' + stamp + '">' + header + body + '</div>');
|
||
|
|
||
|
// Scroll to this message
|
||
|
if(can_scroll)
|
||
|
messageScrollMini(hash);
|
||
|
}
|
||
|
|
||
|
// Switches to a given point
|
||
|
function switchPaneMini(element, hash) {
|
||
|
// Hide every item
|
||
|
jQuery('#jappix_mini a.jm_pane').removeClass('jm_clicked');
|
||
|
jQuery('#jappix_mini div.jm_roster, #jappix_mini div.jm_chat-content').hide();
|
||
|
|
||
|
// Show the asked element
|
||
|
if(element && (element != 'roster')) {
|
||
|
var current = '#jappix_mini #' + element;
|
||
|
|
||
|
jQuery(current + ' a.jm_pane').addClass('jm_clicked');
|
||
|
jQuery(current + ' div.jm_chat-content').show();
|
||
|
|
||
|
// Use a timer to override the DOM lag issue
|
||
|
jQuery(document).oneTime(10, function() {
|
||
|
jQuery(current + ' input.jm_send-messages').focus();
|
||
|
});
|
||
|
|
||
|
// Scroll to the last message
|
||
|
if(hash)
|
||
|
messageScrollMini(hash);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Scrolls to the last chat message
|
||
|
function messageScrollMini(hash, position) {
|
||
|
var id = document.getElementById('received-' + hash);
|
||
|
|
||
|
// No defined position?
|
||
|
if(!position)
|
||
|
position = id.scrollHeight;
|
||
|
|
||
|
id.scrollTop = position;
|
||
|
}
|
||
|
|
||
|
// Prompts the user with a given text
|
||
|
function openPromptMini(text, value) {
|
||
|
// Initialize
|
||
|
var prompt = '#jappix_popup div.jm_prompt';
|
||
|
var input = prompt + ' form input';
|
||
|
var value_input = input + '[type=text]';
|
||
|
|
||
|
// Remove the existing prompt
|
||
|
closePromptMini();
|
||
|
|
||
|
// Add the prompt
|
||
|
jQuery('body').append(
|
||
|
'<div id="jappix_popup">' +
|
||
|
'<div class="jm_prompt">' +
|
||
|
'<form>' +
|
||
|
text +
|
||
|
'<input class="jm_text" type="text" value="" />' +
|
||
|
'<input class="jm_submit" type="submit" value="' + _e("Submit") + '" />' +
|
||
|
'<input class="jm_submit" type="reset" value="' + _e("Cancel") + '" />' +
|
||
|
'<div class="jm_clear"></div>' +
|
||
|
'</form>' +
|
||
|
'</div>' +
|
||
|
'</div>'
|
||
|
);
|
||
|
|
||
|
// Vertical center
|
||
|
var vert_pos = '-' + ((jQuery(prompt).height() / 2) + 10) + 'px';
|
||
|
jQuery(prompt).css('margin-top', vert_pos);
|
||
|
|
||
|
// Apply the value?
|
||
|
if(value)
|
||
|
jQuery(value_input).val(value);
|
||
|
|
||
|
// Focus on the input
|
||
|
jQuery(document).oneTime(10, function() {
|
||
|
jQuery(value_input).focus();
|
||
|
});
|
||
|
|
||
|
// Cancel event
|
||
|
jQuery(input + '[type=reset]').click(function() {
|
||
|
try {
|
||
|
closePromptMini();
|
||
|
}
|
||
|
|
||
|
catch(e) {}
|
||
|
|
||
|
finally {
|
||
|
return false;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// Returns the prompt value
|
||
|
function closePromptMini() {
|
||
|
// Read the value
|
||
|
var value = jQuery('#jappix_popup div.jm_prompt form input').val();
|
||
|
|
||
|
// Remove the popup
|
||
|
jQuery('#jappix_popup').remove();
|
||
|
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
// Manages and creates a chat
|
||
|
function chatMini(type, xid, nick, hash, pwd, show_pane) {
|
||
|
var current = '#jappix_mini #chat-' + hash;
|
||
|
|
||
|
// Not yet added?
|
||
|
if(!exists(current)) {
|
||
|
// Groupchat nickname
|
||
|
if(type == 'groupchat') {
|
||
|
var nickname = MINI_NICKNAME;
|
||
|
|
||
|
// No nickname?
|
||
|
if(!nickname) {
|
||
|
// Create a new prompt
|
||
|
openPromptMini(printf(_e("Please enter your nickname to join %s."), xid));
|
||
|
|
||
|
// When prompt submitted
|
||
|
jQuery('#jappix_popup div.jm_prompt form').submit(function() {
|
||
|
try {
|
||
|
// Read the value
|
||
|
var nickname = closePromptMini();
|
||
|
|
||
|
// Update the stored one
|
||
|
if(nickname)
|
||
|
MINI_NICKNAME = nickname;
|
||
|
|
||
|
// Launch it again!
|
||
|
chatMini(type, xid, nick, hash, pwd);
|
||
|
}
|
||
|
|
||
|
catch(e) {}
|
||
|
|
||
|
finally {
|
||
|
return false;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Create the HTML markup
|
||
|
var html = '<div class="jm_conversation jm_type_' + type + '" id="chat-' + hash + '" data-xid="' + escape(xid) + '" data-type="' + type + '" data-nick="' + escape(nick) + '" data-hash="' + hash + '" data-origin="' + escape(cutResource(xid)) + '">' +
|
||
|
'<div class="jm_chat-content">' +
|
||
|
'<div class="jm_actions">' +
|
||
|
'<span class="jm_nick">' + nick + '</span>';
|
||
|
|
||
|
// Check if the groupchat exists
|
||
|
var groupchat_exists = false;
|
||
|
|
||
|
if(MINI_GROUPCHATS && MINI_GROUPCHATS.length) {
|
||
|
for(g in MINI_GROUPCHATS) {
|
||
|
if(xid == bareXID(generateXID(MINI_GROUPCHATS[g], 'groupchat'))) {
|
||
|
groupchat_exists = true;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Any close button to display?
|
||
|
if(((type == 'groupchat') && !groupchat_exists) || (type != 'groupchat'))
|
||
|
html += '<a class="jm_one-action jm_close jm_images" title="' + _e("Close") + '" href="#"></a>';
|
||
|
|
||
|
html += '</div>' +
|
||
|
|
||
|
'<div class="jm_received-messages" id="received-' + hash + '"></div>' +
|
||
|
'<form action="#" method="post">' +
|
||
|
'<input type="text" class="jm_send-messages" name="body" autocomplete="off" />' +
|
||
|
'<input type="hidden" name="xid" value="' + xid + '" />' +
|
||
|
'<input type="hidden" name="type" value="' + type + '" />' +
|
||
|
'</form>' +
|
||
|
'</div>' +
|
||
|
|
||
|
'<a class="jm_pane jm_chat-tab jm_images" href="#">' +
|
||
|
'<span class="jm_name">' + nick.htmlEnc() + '</span>' +
|
||
|
'</a>' +
|
||
|
'</div>';
|
||
|
|
||
|
jQuery('#jappix_mini div.jm_conversations').prepend(html);
|
||
|
|
||
|
// Get the presence of this friend
|
||
|
if(type != 'groupchat') {
|
||
|
var selector = jQuery('#jappix_mini a#friend-' + hash + ' span.jm_presence');
|
||
|
|
||
|
// Default presence
|
||
|
var show = 'available';
|
||
|
|
||
|
// Read the presence
|
||
|
if(selector.hasClass('jm_unavailable'))
|
||
|
show = 'unavailable';
|
||
|
else if(selector.hasClass('jm_chat'))
|
||
|
show = 'chat';
|
||
|
else if(selector.hasClass('jm_away'))
|
||
|
show = 'away';
|
||
|
else if(selector.hasClass('jm_xa'))
|
||
|
show = 'xa';
|
||
|
else if(selector.hasClass('jm_dnd'))
|
||
|
show = 'dnd';
|
||
|
|
||
|
// Create the presence marker
|
||
|
jQuery(current + ' a.jm_chat-tab').prepend('<span class="jm_presence jm_images jm_' + show + '"></span>');
|
||
|
}
|
||
|
|
||
|
// The click events
|
||
|
chatEventsMini(type, xid, hash);
|
||
|
|
||
|
// Join the groupchat
|
||
|
if(type == 'groupchat') {
|
||
|
// Add the nickname value
|
||
|
jQuery(current).attr('data-nick', escape(nickname));
|
||
|
|
||
|
// Send the first groupchat presence
|
||
|
presenceMini('', '', '', '', xid + '/' + nickname, pwd, true, handleMUCMini);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Focus on our pane
|
||
|
if(show_pane != false)
|
||
|
jQuery(document).oneTime(10, function() {
|
||
|
switchPaneMini('chat-' + hash, hash);
|
||
|
});
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Events on the chat tool
|
||
|
function chatEventsMini(type, xid, hash) {
|
||
|
var current = '#jappix_mini #chat-' + hash;
|
||
|
|
||
|
// Submit the form
|
||
|
jQuery(current + ' form').submit(function() {
|
||
|
return sendMessageMini(this);
|
||
|
});
|
||
|
|
||
|
// Click on the tab
|
||
|
jQuery(current + ' a.jm_chat-tab').click(function() {
|
||
|
// Using a try/catch override IE issues
|
||
|
try {
|
||
|
// Not yet opened: open it!
|
||
|
if(!jQuery(this).hasClass('jm_clicked')) {
|
||
|
// Show it!
|
||
|
switchPaneMini('chat-' + hash, hash);
|
||
|
|
||
|
// Clear the eventual notifications
|
||
|
clearNotificationsMini(hash);
|
||
|
}
|
||
|
|
||
|
// Yet opened: close it!
|
||
|
else
|
||
|
switchPaneMini();
|
||
|
}
|
||
|
|
||
|
catch(e) {}
|
||
|
|
||
|
finally {
|
||
|
return false;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Click on the close button
|
||
|
jQuery(current + ' a.jm_close').click(function() {
|
||
|
// Using a try/catch override IE issues
|
||
|
try {
|
||
|
jQuery(current).remove();
|
||
|
|
||
|
// Quit the groupchat?
|
||
|
if(type == 'groupchat') {
|
||
|
// Send an unavailable presence
|
||
|
presenceMini('unavailable', '', '', '', xid + '/' + unescape(jQuery(current).attr('data-nick')));
|
||
|
|
||
|
// Remove this groupchat!
|
||
|
removeGroupchatMini(xid);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
catch(e) {}
|
||
|
|
||
|
finally {
|
||
|
return false;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Click on the chat content
|
||
|
jQuery(current + ' div.jm_received-messages').click(function() {
|
||
|
try {
|
||
|
jQuery(document).oneTime(10, function() {
|
||
|
jQuery(current + ' input.jm_send-messages').focus();
|
||
|
});
|
||
|
}
|
||
|
|
||
|
catch(e) {}
|
||
|
});
|
||
|
|
||
|
// Focus on the chat input
|
||
|
jQuery(current + ' input.jm_send-messages').focus(function() {
|
||
|
clearNotificationsMini(hash);
|
||
|
})
|
||
|
|
||
|
// Change on the chat input
|
||
|
.keyup(function() {
|
||
|
jQuery(this).attr('data-value', jQuery(this).val());
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// Shows the roster
|
||
|
function showRosterMini() {
|
||
|
switchPaneMini('roster');
|
||
|
jQuery('#jappix_mini div.jm_roster').show();
|
||
|
jQuery('#jappix_mini a.jm_button').addClass('jm_clicked');
|
||
|
}
|
||
|
|
||
|
// Hides the roster
|
||
|
function hideRosterMini() {
|
||
|
jQuery('#jappix_mini div.jm_roster').hide();
|
||
|
jQuery('#jappix_mini a.jm_button').removeClass('jm_clicked');
|
||
|
}
|
||
|
|
||
|
// Removes a groupchat from DOM
|
||
|
function removeGroupchatMini(xid) {
|
||
|
// Remove the groupchat private chats & the groupchat buddies from the roster
|
||
|
jQuery('#jappix_mini div.jm_conversation[data-origin=' + escape(cutResource(xid)) + '], #jappix_mini div.jm_roster div.jm_grouped[data-xid=' + escape(xid) + ']').remove();
|
||
|
|
||
|
// Update the presence counter
|
||
|
updateRosterMini();
|
||
|
}
|
||
|
|
||
|
// Initializes Jappix Mini
|
||
|
function initializeMini() {
|
||
|
// Update the marker
|
||
|
MINI_INITIALIZED = true;
|
||
|
|
||
|
// Send the initial presence
|
||
|
if(!MINI_ANONYMOUS)
|
||
|
presenceMini();
|
||
|
|
||
|
// Join the groupchats
|
||
|
for(var i = 0; i < MINI_GROUPCHATS.length; i++) {
|
||
|
// Empty value?
|
||
|
if(!MINI_GROUPCHATS[i])
|
||
|
continue;
|
||
|
|
||
|
// Using a try/catch override IE issues
|
||
|
try {
|
||
|
// Current chat room
|
||
|
var chat_room = bareXID(generateXID(MINI_GROUPCHATS[i], 'groupchat'));
|
||
|
|
||
|
// Open the current chat
|
||
|
chatMini('groupchat', chat_room, getXIDNick(chat_room), hex_md5(chat_room), MINI_PASSWORDS[i], MINI_SHOWPANE);
|
||
|
}
|
||
|
|
||
|
catch(e) {}
|
||
|
}
|
||
|
|
||
|
// Must show the roster?
|
||
|
if(!MINI_AUTOCONNECT && !MINI_GROUPCHATS.length)
|
||
|
jQuery(document).oneTime(10, function() {
|
||
|
showRosterMini();
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// Displays a roster buddy
|
||
|
function addBuddyMini(xid, hash, nick, groupchat) {
|
||
|
// Element
|
||
|
var element = '#jappix_mini a.jm_friend#friend-' + hash;
|
||
|
|
||
|
// Yet added?
|
||
|
if(exists(element))
|
||
|
return false;
|
||
|
|
||
|
// Generate the path
|
||
|
var path = '#jappix_mini div.jm_roster div.jm_buddies';
|
||
|
|
||
|
// Groupchat buddy
|
||
|
if(groupchat) {
|
||
|
// Generate the groupchat group path
|
||
|
path = '#jappix_mini div.jm_roster div.jm_grouped[data-xid=' + escape(groupchat) + ']';
|
||
|
|
||
|
// Must add a groupchat group?
|
||
|
if(!exists(path)) {
|
||
|
jQuery('#jappix_mini div.jm_roster div.jm_buddies').append(
|
||
|
'<div class="jm_grouped" data-xid="' + escape(groupchat) + '">' +
|
||
|
'<div class="jm_name">' + getXIDNick(groupchat).htmlEnc() + '</div>' +
|
||
|
'</div>'
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Append this buddy content
|
||
|
var code = '<a class="jm_friend jm_offline" id="friend-' + hash + '" data-xid="' + escape(xid) + '" data-nick="' + escape(nick) + '" data-hash="' + hash + '" href="#"><span class="jm_presence jm_images jm_unavailable"></span>' + nick.htmlEnc() + '</a>';
|
||
|
|
||
|
if(groupchat)
|
||
|
jQuery(path).append(code);
|
||
|
else
|
||
|
jQuery(path).prepend(code);
|
||
|
|
||
|
// Click event on this buddy
|
||
|
jQuery(element).click(function() {
|
||
|
// Using a try/catch override IE issues
|
||
|
try {
|
||
|
chatMini('chat', xid, nick, hash);
|
||
|
}
|
||
|
|
||
|
catch(e) {}
|
||
|
|
||
|
finally {
|
||
|
return false;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Removes a roster buddy
|
||
|
function removeBuddyMini(hash, groupchat) {
|
||
|
// Remove the buddy from the roster
|
||
|
jQuery('#jappix_mini a.jm_friend#friend-' + hash).remove();
|
||
|
|
||
|
// Empty group?
|
||
|
var group = '#jappix_mini div.jm_roster div.jm_grouped[data-xid=' + escape(groupchat) + ']';
|
||
|
|
||
|
if(groupchat && !jQuery(group + ' a.jm_friend').size())
|
||
|
jQuery(group).remove();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Gets the user's roster
|
||
|
function getRosterMini() {
|
||
|
var iq = new JSJaCIQ();
|
||
|
iq.setType('get');
|
||
|
iq.setQuery(NS_ROSTER);
|
||
|
con.send(iq, handleRosterMini);
|
||
|
|
||
|
logThis('Getting roster...', 3);
|
||
|
}
|
||
|
|
||
|
// Handles the user's roster
|
||
|
function handleRosterMini(iq) {
|
||
|
// Parse the roster
|
||
|
jQuery(iq.getQuery()).find('item').each(function() {
|
||
|
// Get the values
|
||
|
var current = jQuery(this);
|
||
|
var xid = current.attr('jid');
|
||
|
var subscription = current.attr('subscription');
|
||
|
|
||
|
// Not a gateway
|
||
|
if(!isGateway(xid)) {
|
||
|
var nick = current.attr('name');
|
||
|
var hash = hex_md5(xid);
|
||
|
|
||
|
// No name is defined?
|
||
|
if(!nick)
|
||
|
nick = getXIDNick(xid);
|
||
|
|
||
|
// Action on the current buddy
|
||
|
if(subscription == 'remove')
|
||
|
removeBuddyMini(hash);
|
||
|
else
|
||
|
addBuddyMini(xid, hash, nick);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Not yet initialized
|
||
|
if(!MINI_INITIALIZED)
|
||
|
initializeMini();
|
||
|
|
||
|
logThis('Roster got.', 3);
|
||
|
}
|
||
|
|
||
|
// Adapts the roster height to the window
|
||
|
function adaptRosterMini() {
|
||
|
// Process the new height
|
||
|
var height = jQuery(window).height() - 70;
|
||
|
|
||
|
// Apply the new height
|
||
|
jQuery('#jappix_mini div.jm_roster div.jm_buddies').css('max-height', height);
|
||
|
}
|
||
|
|
||
|
// Plugin launcher
|
||
|
function launchMini(autoconnect, show_pane, domain, user, password) {
|
||
|
// Save infos to reconnect
|
||
|
MINI_DOMAIN = domain;
|
||
|
MINI_USER = user;
|
||
|
MINI_PASSWORD = password;
|
||
|
|
||
|
// Anonymous mode?
|
||
|
if(!user || !password)
|
||
|
MINI_ANONYMOUS = true;
|
||
|
else
|
||
|
MINI_ANONYMOUS = false;
|
||
|
|
||
|
// Autoconnect (only if storage available to avoid floods)?
|
||
|
if(autoconnect && hasDB())
|
||
|
MINI_AUTOCONNECT = true;
|
||
|
else
|
||
|
MINI_AUTOCONNECT = false;
|
||
|
|
||
|
// Show pane?
|
||
|
if(show_pane)
|
||
|
MINI_SHOWPANE = true;
|
||
|
else
|
||
|
MINI_SHOWPANE = false;
|
||
|
|
||
|
// Remove Jappix Mini
|
||
|
jQuery('#jappix_mini').remove();
|
||
|
|
||
|
// Reconnect?
|
||
|
if(MINI_RECONNECT) {
|
||
|
logThis('Trying to reconnect (try: ' + MINI_RECONNECT + ')!');
|
||
|
|
||
|
return createMini(domain, user, password);
|
||
|
}
|
||
|
|
||
|
// Append the Mini stylesheet
|
||
|
jQuery('head').append('<link rel="stylesheet" href="' + JAPPIX_STATIC + 'php/get.php?t=css&g=mini.xml" type="text/css" media="all" />');
|
||
|
|
||
|
// Legacy IE stylesheet
|
||
|
if((BrowserDetect.browser == 'Explorer') && (BrowserDetect.version < 7))
|
||
|
jQuery('head').append('<link rel="stylesheet" href="' + JAPPIX_STATIC + 'php/get.php?t=css&f=mini-ie.css" type="text/css" media="all" />');
|
||
|
|
||
|
// Disables the browser HTTP-requests stopper
|
||
|
jQuery(document).keydown(function(e) {
|
||
|
if((e.keyCode == 27) && !isDeveloper())
|
||
|
return false;
|
||
|
});
|
||
|
|
||
|
// Save the page title
|
||
|
MINI_TITLE = document.title;
|
||
|
|
||
|
// Sets the good roster max-height
|
||
|
jQuery(window).resize(adaptRosterMini);
|
||
|
|
||
|
// Logouts when Jappix is closed
|
||
|
if(BrowserDetect.browser == 'Opera') {
|
||
|
// Emulates onbeforeunload on Opera (link clicked)
|
||
|
jQuery('a[href]:not([onclick])').click(function() {
|
||
|
// Link attributes
|
||
|
var href = jQuery(this).attr('href') || '';
|
||
|
var target = jQuery(this).attr('target') || '';
|
||
|
|
||
|
// Not new window or JS link
|
||
|
if(href && !href.match(/^#/i) && !target.match(/_blank|_new/i))
|
||
|
saveSessionMini();
|
||
|
});
|
||
|
|
||
|
// Emulates onbeforeunload on Opera (form submitted)
|
||
|
jQuery('form:not([onsubmit])').submit(saveSessionMini);
|
||
|
}
|
||
|
|
||
|
jQuery(window).bind('beforeunload', saveSessionMini);
|
||
|
|
||
|
// Create the Jappix Mini DOM content
|
||
|
createMini(domain, user, password);
|
||
|
|
||
|
logThis('Welcome to Jappix Mini! Happy coding in developer mode!');
|
||
|
}
|