/*
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 ' ';
}
// 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(
'' +
'' +
'0' +
'' +
''
);
// 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(
'
'
);
}
// 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 = '
');
// 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(
'
' +
'
' +
'' +
'
' +
'
'
);
// 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 = '
' +
'
' +
'
' +
'' + nick + '';
// 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 += '';
html += '