/*
This program is distributed under the terms of the MIT license.
Please see the LICENSE file for details.
Copyright 2008 Michael Garvin
*/
/*TODO dump / very loose roadmap
--0.4
add chats to json store
Mouseover status messages in roster
HTML in messages (xslt?)
Select presence status/message
Optional user-specified resource
Loglevel select on login instead of check box
vcard support http://xmpp.org/extensions/xep-0153.html
Notifications of closed chats
Notifications of typing
--0.5
roster management
figure out how we want to handle presence from our own jid (and transports)
roster sorting by presence / offline roster capablility
auto-subscribe vs prompted subscribe based on config option
make sure makeChat() et al. can handle empty resources
(offline chat capabilities)
--1.0 (or whenever someone submits better .css)
layout overhaul
code cleanup (like checking for excessive function lengths)
roster versioning http://xmpp.org/extensions/attic/xep-0237-0.1.html
make sure onload bootstrapping actually preserves existing onloads
*/
var TROPHYIM_BOSH_SERVICE = "/proxy/xmpp-httpbind"; //Change to suit
var TROPHYIM_LOG_LINES = 200;
var TROPHYIM_LOGLEVEL = 0; //0=debug, 1=info, 2=warn, 3=error, 4=fatal
var TROPHYIM_VERSION = "0.3";
var TROPHYIM_RESOURCE = "/JABBERITWEB";
//Uncomment to make session reattachment work
//var TROPHYIM_JSON_STORE = "json_store.php";
/** File: trophyimclient.js
* A JavaScript front-end for strophe.js
*
* This is a JavaScript library that runs on top of strophe.js. All that
* is required is that your page have a
element with an id of
* 'trophyimclient', and that your page does not explicitly set an onload
* event in its tag. In that case you need to append TrophyIM.load()
* to it.
*
* The style of the client can be conrolled via trophyim.css, which is
* auto-included by the client.
*/
/** Object: DOMObjects
* This class contains builders for all the DOM objects needed by TrophyIM
*/
DOMObjects = {
/** Function: xmlParse
* Cross-browser alternative to using innerHTML
* Parses given string, returns valid DOM HTML object
*
* Parameters:
* (String) xml - the xml string to parse
*/
xmlParse : function(xmlString) {
var xmlObj = this.xmlRender(xmlString);
if(xmlObj) {
try { //Firefox, Gecko, etc
if (this.processor == undefined) {
this.processor = new XSLTProcessor();
this.processor.importStylesheet(this.xmlRender(
'
\
\
'));
}
var htmlObj =
this.processor.transformToDocument(xmlObj).documentElement;
//Safari has a quirk where it wraps dom elements in
if (htmlObj.tagName.toLowerCase() == 'html') {
htmlObj = htmlObj.firstChild.firstChild;
}
return document.importNode(htmlObj, true);
} catch(e) {
try { //IE is so very very special
var htmlObj = document.importNode(xmlObj.documentElement, true);
if (htmlObj.tagName.toLowerCase() == "div") {
var div_wrapper = document.createElement('div');
div_wrapper.appendChild(htmlObj);
if(div_wrapper.innerHTML) {
div_wrapper.innerHTML = div_wrapper.innerHTML;
}
htmlObj = div_wrapper.firstChild;
}
return htmlObj;
} catch(e) {
alert(
"TrophyIM Error: Cannot add html to page" + e.message);
}
}
}
},
/** Function: xmlRender
* Uses browser-specific methods to turn given string into xml object
*
* Parameters:
* (String) xml - the xml string to parse
*/
xmlRender : function(xmlString) {
try {//IE
var renderObj = new ActiveXObject("Microsoft.XMLDOM");
renderObj.async="false";
if(xmlString) {
renderObj.loadXML(xmlString);
}
} catch (e) {
try { //Firefox, Gecko, etc
if (this.parser == undefined) {
this.parser = new DOMParser();
}
var renderObj = this.parser.parseFromString(xmlString,
"application/xml");
} catch(e) {
alert("TrophyIM Error: Cannot create new html for page");
}
}
return renderObj;
},
/** Function: getHTML
* Returns named HTML snippet as DOM object
*
* Parameters:
* (String) name - name of HTML snippet to retrieve (see HTMLSnippets
* object)
*/
getHTML : function(page)
{
return this.xmlParse(HTMLSnippets[page]);
},
/** Function: getScript
* Returns script object with src to given script
*
* Parameters:
* (String) script - name of script to put in src attribute of script
* element
*/
getScript : function(script) {
var newscript = document.createElement('script');
newscript.setAttribute('src', script);
newscript.setAttribute('type', 'text/javascript');
return newscript;
}
};
/** Object: TrophyIM
*
* This is the actual TrophyIM application. It searches for the
* 'trophyimclient' element and inserts itself into that.
*/
TrophyIM = {
/** Constants:
*
* (Boolean) stale_roster - roster is stale and needs to be rewritten.
*/
constants : {stale_roster: false},
/** Object: chatHistory
*
* Stores chat history (last 10 message) and current presence of active
* chat tabs. Indexed by jid.
*/
chatHistory : {},
/** Object: activeChats
*
* This object stores the currently active chats.
*/
activeChats : {current: null, divs: {}},
/** Function: setCookie
*
* Sets cookie name/value pair. Date and path are auto-selected.
*
* Parameters:
* (String) name - the name of the cookie variable
* (String) value - the value of the cookie variable
*/
setCookie : function(name, value) {
var expire = new Date();
expire.setDate(expire.getDate() + 365);
document.cookie = name + "=" + value + "; expires=" + expire.toGMTString();
},
/** Function: delCookie
*
* Deletes cookie
*
* Parameters:
* (String) name) - the name of the cookie to delete
*/
delCookie : function(name) {
var expire = new Date();
expire.setDate(expire.getDate() - 365);
document.cookie = name + "= ; expires=" + expire.toGMTString();
delete TrophyIM.cookies[name];
},
/** Function: getCookies
*
* Retrieves all trophyim cookies into an indexed object. Inteneded to be
* called once, at which time the app refers to the returned object instead
* of re-parsing the cookie string every time.
*
* Each cookie is also re-applied so as to refresh the expiry date.
*/
getCookies : function() {
var cObj = {};
var cookies = document.cookie.split(';');
for (var c in cookies) {
while (cookies[c].charAt(0)==' ') {
cookies[c] = cookies[c].substring(1,cookies[c].length);
}
if (cookies[c].substr(0, 8) == "trophyim") {
var nvpair = cookies[c].split("=", 2);
cObj[nvpair[0]] = nvpair[1];
TrophyIM.setCookie(nvpair[0], nvpair[1]);
}
}
return cObj;
},
/** Function: load
*
* This function searches for the trophyimclient div and loads the client
* into it.
*/
load : function()
{
TrophyIM.cookies = TrophyIM.getCookies();
//TrophyIM.client_div = document.getElementById('trophyimclient');
//Load other .js scripts needed
document.getElementsByTagName('head')[0].appendChild(DOMObjects.getScript('strophejs/strophe.js'));
document.getElementsByTagName('head')[0].appendChild(DOMObjects.getScript('strophejs/md5.js'));
document.getElementsByTagName('head')[0].appendChild(DOMObjects.getScript('strophejs/sha1.js'));
document.getElementsByTagName('head')[0].appendChild(DOMObjects.getScript('strophejs/b64.js'));
document.getElementsByTagName('head')[0].appendChild(DOMObjects.getScript('js/json2.js')); //Keep this script last
//Wait a second to give scripts time to load
setTimeout("TrophyIM.showLogin()", 500);
},
/** Function: storeData
*
* Store all our data in the JSONStore, if it is active
*/
storeData : function()
{
if ( TrophyIM.connection && TrophyIM.connection.connected )
{
TrophyIM.setCookie('trophyim_bosh_xid', TrophyIM.connection.jid + "|" +
TrophyIM.connection.sid + "|" + TrophyIM.connection.rid);
TrophyIM.rosterObj.save();
}
},
/** Function: showlogin
*
* This function clears out the IM box and either redisplays the login
* page, or re-attaches to Strophe, preserving the logging div if it
* exists, or creating a new one of we are re-attaching.
*/
showLogin : function()
{
//JSON is the last script to load, so we wait on it
//Added Strophe check too because of bug where it's sometimes missing
if (typeof(JSON) != undefined && typeof(Strophe) != undefined)
{
TrophyIM.JSONStore = new TrophyIMJSONStore();
if ( TrophyIM.JSONStore.store_working && TrophyIM.cookies['trophyim_bosh_xid'] )
{
var xids = TrophyIM.cookies['trophyim_bosh_xid'].split("|");
TrophyIM.delCookie('trophyim_bosh_xid');
TrophyIM.constants.stale_roster = true;
TrophyIM.connection = new Strophe.Connection(TROPHYIM_BOSH_SERVICE);
TrophyIM.connection.rawInput = TrophyIM.rawInput;
TrophyIM.connection.rawOutput = TrophyIM.rawOutput;
Strophe.log = TrophyIM.log;
Strophe.info('Attempting Strophe attach.');
TrophyIM.connection.attach(xids[0], xids[1], xids[2], TrophyIM.onConnect);
TrophyIM.onConnect(Strophe.Status.CONNECTED);
}
else
{
// List Contact
loadIM.HTMLSnippets.rosterDiv();
if ( loadIM.getUserCurrent() != null )
{
TrophyIM.login( loadIM.getUserCurrent().jid, loadIM.getUserCurrent().password );
}
else
{
loadIM.HTMLSnippets.loginPage();
}
}
}
else
{
setTimeout("TrophyIM.showLogin()", 500);
}
},
/** Function: log
*
* This function logs the given message in the trophyimlog div
*
* Parameter: (String) msg - the message to log
*/
log : function(level, msg)
{
if (TrophyIM.logging_div && level >= TROPHYIM_LOGLEVEL) {
while(TrophyIM.logging_div.childNodes.length > TROPHYIM_LOG_LINES) {
TrophyIM.logging_div.removeChild(
TrophyIM.logging_div.firstChild);
}
var msg_div = document.createElement('div');
msg_div.className = 'trophyimlogitem';
msg_div.appendChild(document.createTextNode(msg));
TrophyIM.logging_div.appendChild(msg_div);
TrophyIM.logging_div.scrollTop = TrophyIM.logging_div.scrollHeight;
}
},
/** Function: rawInput
*
* This logs the packets actually recieved by strophe at the debug level
*/
rawInput : function (data)
{
Strophe.debug("RECV: " + data);
},
/** Function: rawInput
*
* This logs the packets actually recieved by strophe at the debug level
*/
rawOutput : function (data)
{
Strophe.debug("SEND: " + data);
},
/** Function: login
*
* This function logs into server using information given on login page.
* Since the login page is where the logging checkbox is, it makes or
* removes the logging div and cookie accordingly.
*
*/
login : function()
{
if (TrophyIM.JSONStore.store_working)
{
//In case they never logged out
TrophyIM.JSONStore.delData(['groups','roster', 'active_chat', 'chat_history']);
}
TrophyIM.connection = new Strophe.Connection(TROPHYIM_BOSH_SERVICE);
TrophyIM.connection.rawInput = TrophyIM.rawInput;
TrophyIM.connection.rawOutput = TrophyIM.rawOutput;
Strophe.log = TrophyIM.log;
if ( arguments.length > 0 )
{
var barejid = arguments[0];
var password = arguments[1];
TrophyIM.connection.connect(barejid + TROPHYIM_RESOURCE, password, TrophyIM.onConnect);
}
else
{
var barejid = document.getElementById('trophyimjid').value
var fulljid = barejid + TROPHYIM_RESOURCE;
var password = document.getElementById('trophyimpass').value;
var button = document.getElementById('trophyimconnect');
loadIM.setUserCurrent( barejid, password);
if ( button.value == 'connect' )
{
button.value = 'disconnect';
TrophyIM.connection.connect(fulljid, password, TrophyIM.onConnect);
}
else
{
button.value = 'connect';
TrophyIM.connection.disconnect();
}
}
TrophyIM.setCookie('trophyimjid', barejid);
},
/** Function: logout
*
* Logs into fresh session through Strophe, purging any old data.
*/
logout : function()
{
TrophyIM.delCookie('trophyim_bosh_xid');
delete TrophyIM['cookies']['trophyim_bosh_xid'];
if (TrophyIM.JSONStore.store_working)
{
TrophyIM.JSONStore.delData(['groups','roster', 'active_chat', 'chat_history']);
}
for (var chat in TrophyIM.activeChats['divs'])
{
delete TrophyIM.activeChats['divs'][chat];
}
TrophyIM.activeChats = {current: null, divs: {}},
TrophyIM.connection.disconnect();
TrophyIM.showLogin();
},
/** Function onConnect
*
* Callback given to Strophe upon connection to BOSH proxy.
*/
onConnect : function(status)
{
if (status == Strophe.Status.CONNECTING) {
Strophe.info('Strophe is connecting.');
} else if (status == Strophe.Status.CONNFAIL) {
Strophe.info('Strophe failed to connect.');
TrophyIM.delCookie('trophyim_bosh_xid');
TrophyIM.showLogin();
} else if (status == Strophe.Status.DISCONNECTING) {
Strophe.info('Strophe is disconnecting.');
} else if (status == Strophe.Status.DISCONNECTED) {
Strophe.info('Strophe is disconnected.');
TrophyIM.delCookie('trophyim_bosh_xid');
TrophyIM.showLogin();
} else if (status == Strophe.Status.CONNECTED) {
Strophe.info('Strophe is connected.');
TrophyIM.showClient();
}
},
/** Function: showClient
*
* This clears out the main div and puts in the main client. It also
* registers all the handlers for Strophe to call in the client.
*/
showClient : function()
{
TrophyIM.setCookie('trophyim_bosh_xid', TrophyIM.connection.jid + "|" +
TrophyIM.connection.sid + "|" + TrophyIM.connection.rid);
//var logging_div = TrophyIM.clearClient();
/*if( logging_div )
{
TrophyIM.client_div.appendChild(logging_div);
TrophyIM.logging_div = document.getElementById('trophyimlog');
}*/
TrophyIM.rosterObj = new TrophyIMRoster();
TrophyIM.connection.addHandler(TrophyIM.onVersion, Strophe.NS.VERSION, 'iq', null, null, null);
TrophyIM.connection.addHandler(TrophyIM.onRoster, Strophe.NS.ROSTER, 'iq', null, null, null);
TrophyIM.connection.addHandler(TrophyIM.onPresence, null, 'presence', null, null, null);
TrophyIM.connection.addHandler(TrophyIM.onMessage, null, 'message', null, null, null);
//Get roster then announce presence.
TrophyIM.connection.send($iq({type: 'get', xmlns: Strophe.NS.CLIENT}).c('query', {xmlns: Strophe.NS.ROSTER}).tree());
TrophyIM.connection.send($pres().tree());
setTimeout("TrophyIM.renderRoster()", 1000);
},
/** Function: clearClient
*
* Clears out client div, preserving and returning existing logging_div if
* one exists
*/
clearClient : function() {
if(TrophyIM.logging_div) {
var logging_div = TrophyIM.client_div.removeChild(
document.getElementById('trophyimlog'));
} else {
var logging_div = null;
}
while(TrophyIM.client_div.childNodes.length > 0) {
TrophyIM.client_div.removeChild(TrophyIM.client_div.firstChild);
}
return logging_div;
},
/** Function: onVersion
*
* jabber:iq:version query handler
*/
onVersion : function(msg) {
Strophe.debug("Version handler");
if (msg.getAttribute('type') == 'get') {
var from = msg.getAttribute('from');
var to = msg.getAttribute('to');
var id = msg.getAttribute('id');
var reply = $iq({type: 'result', to: from, from: to, id: id}).c('query',
{name: "TrophyIM", version: TROPHYIM_VERSION, os:
"Javascript-capable browser"});
TrophyIM.connection.send(reply.tree());
}
return true;
},
/** Function: onRoster
*
* Roster iq handler
*/
onRoster : function(msg)
{
//Strophe.debug("Roster handler");
var roster_items = msg.firstChild.getElementsByTagName('item');
for (var i = 0; i < roster_items.length; i++)
{
var groups = roster_items[i].getElementsByTagName('group');
var group_array = new Array();
for (var g = 0; g < groups.length; g++)
{
group_array[group_array.length] = groups[g].firstChild.nodeValue;
}
with ( roster_items[i] )
{
TrophyIM.rosterObj.addContact(getAttribute('jid'), getAttribute('subscription'), getAttribute('name'), group_array);
}
}
if ( msg.getAttribute('type') == 'set' )
{
TrophyIM.connection.send($iq({type: 'reply', id:
msg.getAttribute('id'), to: msg.getAttribute('from')}).tree());
}
return true;
},
/** Function: onPresence
*
* Presence handler
*/
onPresence : function(msg)
{
Strophe.debug("Presence handler");
var type = msg.getAttribute('type') ? msg.getAttribute('type') : 'available';
var show = msg.getElementsByTagName('show').length ? Strophe.getText(msg.getElementsByTagName('show')[0]) : type;
var status = msg.getElementsByTagName('status').length ? Strophe.getText(msg.getElementsByTagName('status')[0]) : '';
var priority = msg.getElementsByTagName('priority').length ? parseInt(Strophe.getText(msg.getElementsByTagName('priority')[0])) : 0;
TrophyIM.rosterObj.setPresence(msg.getAttribute('from'), priority, show, status);
return true;
},
/** Function: onMessage
*
* Message handler
*/
onMessage : function(msg)
{
Strophe.debug("Message handler");
var from = msg.getAttribute('from');
var type = msg.getAttribute('type');
var elems = msg.getElementsByTagName('body');
if ( (type == 'chat' || type == 'normal') && elems.length > 0 )
{
var barejid = Strophe.getBareJidFromJid(from);
var jid_lower = barejid.toLowerCase();
var contact = "";
if( TrophyIM.rosterObj.roster[barejid.toLowerCase()]['contact']['name'] )
{
contact = TrophyIM.rosterObj.roster[barejid.toLowerCase()]['contact']['name'];
}
else
{
contact = barejid.toLowerCase();
contact = contact.substring(0, contact.indexOf('@'));
}
var message =
{
contact : "
" + contact + "",
msg : Strophe.getText(elems[0])
};
TrophyIM.makeChat(from); //Make sure we have a chat window
TrophyIM.addMessage(message, jid_lower);
}
return true;
},
/** Function: makeChat
*
* Make sure chat window to given fulljid exists, switching chat context to
* given resource
*/
makeChat : function(fulljid)
{
var barjid = Strophe.getBareJidFromJid(fulljid);
var paramsChatBox =
{
'idChatBox' : barjid + "__chatBox",
'jidTo' : barjid,
};
var winChatBox =
{
id_window : "window_chat_area_" + barjid,
width : 387,
height : 365,
top : 100,
left : 400,
draggable : true,
visible : "display",
resizable : true,
zindex : loadIM.getZIndex(),
title : barjid.substring(0, barjid.indexOf('@')),
closeAction : "hidden",
content : loadIM.parse("chat_box","chatBox.xsl", paramsChatBox)
}
_winBuild(winChatBox)
loadIM.configEvents(
document.getElementById( barjid + '__sendBox'),
'onkeyup', function(e)
{
if( e.keyCode == 13 )
{
TrophyIM.sendMessage( barjid );
document.getElementById( barjid + '__sendBox').value = '';
return false;
}
}
);
},
/** Function addContacts
*
* Parameters:
* (string) jid
* (string) name
* (string) group
*/
addContacts : function( jidFrom, jidTo, name, group )
{
var newPresence = $pres({from: jidFrom, to: jidTo, type: 'subscribe'}).tree();
TrophyIM.connection.send(newPresence);
var newContact = $iq({type: 'set', id: 'set1'});
newContact = newContact.c('query').attrs({xmlns : 'jabber:iq:roster'});
newContact = newContact.c('item').attrs({jid: jid, name: name, ask:'subscribe', subscription :'none'});
newContact = newContact.c('group').t(group).tree();
TrophyIM.connection.send(newContact);
},
/** Function: addMessage
*
* Parameters:
* (string) msg - the message to add
* (string) jid - the jid of chat box to add the message to.
*/
addMessage : function(msg, jid)
{
var chatBox = document.getElementById(jid + "__chatBox");
var messageDiv = document.createElement("div");
messageDiv.style.margin = "3px 0px 3px 3px";
messageDiv.innerHTML = msg.contact + " : " + msg.msg ;
chatBox.appendChild(messageDiv);
chatBox.scrollTop = chatBox.scrollHeight;
},
/** Function: renderRoster
*
* Renders roster, looking only for jids flagged by setPresence as having
* changed.
*/
renderRoster : function()
{
if( TrophyIM.rosterObj.changes.length > 0 )
{
var roster_div = document.getElementById('JabberIMRoster');
if( roster_div )
{
var users = new Array();
for( var user in TrophyIM.rosterObj.roster )
{
users[users.length] = TrophyIM.rosterObj.roster[user].contact.jid;
}
users.sort();
var groups = new Array();
for (var group in TrophyIM.rosterObj.groups)
{
if( group )
groups[groups.length] = group;
}
groups.sort();
for ( var i = 0; i < groups.length; i++ )
{
TrophyIM.renderGroups( groups[i] , roster_div.lastChild );
}
TrophyIM.renderItensGroup(users, roster_div);
}
}
//setTimeout("TrophyIM.renderRoster()", 1000 );
setTimeout("TrophyIM.renderRoster()", 2000 );
},
/** Function: renderGroups
*
*
*/
renderGroups: function( nameGroup, element )
{
var _addGroup = function()
{
var paramsGroup =
{
'nameGroup' : arguments[0],
}
element.innerHTML += loadIM.parse("group","groups.xsl", paramsGroup);
}
if( !element.hasChildNodes() )
{
_addGroup(nameGroup);
}
else
{
var elementChild = element;
var flag = false;
while ( elementChild )
{
if ( elementChild.childNodes[0].childNodes[0].firstChild.nodeValue === nameGroup )
{
flag = true;
}
elementChild = elementChild.nextSibling;
}
if( !flag )
_addGroup( nameGroup );
}
},
/** Function: renderItensGroup
*
*
*/
renderItensGroup : function( users, element )
{
var addItemGroup = function()
{
if( arguments.length > 0 )
{
var objContact = arguments[0];
var element = arguments[1];
var itensJid = document.getElementById( 'itenContact_' + objContact.contact.jid );
if( itensJid == null )
{
// Name
var nameContact = "";
if ( objContact.contact.name )
nameContact = objContact.contact.name;
else
{
nameContact = objContact.contact.jid;
nameContact = nameContact.substring(0, nameContact.indexOf('@'));
}
// Presence e Status
var presence = "unavailable";
var status = "";
var statusDisplay = "none";
if (objContact.presence)
{
for (var resource in objContact.presence)
{
presence = objContact.presence[resource].show;
if( objContact.presence[resource].status )
{
status = " ( " + objContact.presence[resource].status + " ) ";
statusDisplay = "block";
}
}
}
var paramsContact =
{
'nameContact' : nameContact,
'jid' : objContact.contact.jid,
'id' : 'itenContact_' + objContact.contact.jid,
'presence' : presence,
'status' : status,
'statusDisplay' : statusDisplay
}
if( element.id == "rosterIM_with_groups" )
{
var elementChild = element;
while ( elementChild )
{
if( elementChild.childNodes[0].childNodes[0].firstChild.nodeValue == objContact.contact.groups[0] )
elementChild.childNodes[0].innerHTML += loadIM.parse("itens_group", "itensGroup.xsl", paramsContact);
elementChild = elementChild.nextSibling;
}
}
else
{
element.innerHTML += loadIM.parse("itens_group", "itensGroup.xsl", paramsContact);
}
}
else
{
// Presence e Status
var presence = "unavailable";
var status = "";
var statusDisplay = "none";
if (objContact.presence)
{
for (var resource in objContact.presence)
{
presence = objContact.presence[resource].show;
if( objContact.presence[resource].status )
{
status = objContact.presence[resource].status;
statusDisplay = "block";
}
}
}
itensJid.style.background = "url('images/" + presence + ".gif')no-repeat center left";
itensJid.lastChild.style.display = statusDisplay;
itensJid.lastChild.innerHTML = " ( " + status + " ) ";
}
}
}
for( var i = 0 ; i < users.length; i++ )
{
if( TrophyIM.rosterObj.roster[users[i]].contact.groups )
if( TrophyIM.rosterObj.roster[users[i]].contact.groups[0] )
addItemGroup(TrophyIM.rosterObj.roster[users[i]], element.lastChild );
else
addItemGroup(TrophyIM.rosterObj.roster[users[i]], element.firstChild );
else
addItemGroup(TrophyIM.rosterObj.roster[users[i]], element.firstChild );
}
},
/** Function: rosterClick
*
* Handles actions when a roster item is clicked
*/
rosterClick : function(fulljid)
{
TrophyIM.makeChat(fulljid);
},
/** Function SetAutorization
*
*/
setAutorization : function( jid )
{
//
//var _autorization = $pres( ).attrs( {to: jid, from: loadIM.getUserCurrent(), type:'subscribed'}).tree();
TrophyIM.connection.send($pres( ).attrs( {to: jid, from: loadIM.getUserCurrent().jid, type:'subscribed'}).tree());
},
/** Function: setPresence
*
*/
setPresence : function( show )
{
TrophyIM.connection.send($pres( ).c('show').t(show).tree());
},
/** Function: sendMessage
*
* Send message from chat input to user
*/
sendMessage : function()
{
if( arguments.length > 0 )
{
var jidTo = arguments[0];
var message_input = document.getElementById(jidTo + "__sendBox").value;
if( ( message_input = message_input.replace(/^\s+|\s+$|^\n|\n$/g,"") ) != "" )
{
// Send Message
TrophyIM.connection.send($msg({to: jidTo, from: TrophyIM.connection.jid, type: 'chat'}).c('body').t(message_input).tree());
var message =
{
contact : "
" + "Eu" + "",
msg : message_input
}
// Add Message in chatBox;
TrophyIM.addMessage( message, jidTo);
document.getElementById(jidTo + "__sendBox").value = "";
document.getElementById(jidTo + "__sendBox").focus();
}
}
}
};
/** Class: TrophyIMRoster
*
*
* This object stores the roster and presence info for the TrophyIMClient
*
* roster[jid_lower]['contact']
* roster[jid_lower]['presence'][resource]
*/
function TrophyIMRoster()
{
/** Constants: internal arrays
* (Object) roster - the actual roster/presence information
* (Object) groups - list of current groups in the roster
* (Array) changes - array of jids with presence changes
*/
if (TrophyIM.JSONStore.store_working)
{
var data = TrophyIM.JSONStore.getData(['roster', 'groups']);
this.roster = (data['roster'] != null) ? data['roster'] : {};
this.groups = (data['groups'] != null) ? data['groups'] : {};
}
else
{
this.roster = {};
this.groups = {};
}
this.changes = new Array();
if (TrophyIM.constants.stale_roster)
{
for (var jid in this.roster)
{
this.changes[this.changes.length] = jid;
}
}
/** Function: addContact
*
* Adds given contact to roster
*
* Parameters:
* (String) jid - bare jid
* (String) subscription - subscription attribute for contact
* (String) name - name attribute for contact
* (Array) groups - array of groups contact is member of
*/
this.addContact = function(jid, subscription, name, groups)
{
var contact = { jid:jid, subscription:subscription, name:name, groups:groups }
var jid_lower = jid.toLowerCase();
if ( this.roster[jid_lower] )
{
this.roster[jid_lower]['contact'] = contact;
}
else
{
this.roster[jid_lower] = {contact:contact};
}
groups = groups ? groups : [''];
for ( var g = 0; g < groups.length; g++ )
{
if ( !this.groups[groups[g]] )
{
this.groups[groups[g]] = {};
}
this.groups[groups[g]][jid_lower] = jid_lower;
}
}
/** Function: getContact
*
* Returns contact entry for given jid
*
* Parameter: (String) jid - jid to return
*/
this.getContact = function(jid)
{
if (this.roster[jid.toLowerCase()])
{
return this.roster[jid.toLowerCase()]['contact'];
}
}
/** Function: setPresence
*
* Sets presence
*
* Parameters:
* (String) fulljid: full jid with presence
* (Integer) priority: priority attribute from presence
* (String) show: show attribute from presence
* (String) status: status attribute from presence
*/
this.setPresence = function(fulljid, priority, show, status)
{
var barejid = Strophe.getBareJidFromJid(fulljid);
var resource = Strophe.getResourceFromJid(fulljid);
var jid_lower = barejid.toLowerCase();
if( show != 'unavailable')
{
if (!this.roster[jid_lower])
{
this.addContact(barejid, 'not-in-roster');
}
var presence =
{
resource:resource, priority:priority, show:show, status:status
}
if (!this.roster[jid_lower]['presence'])
{
this.roster[jid_lower]['presence'] = {}
}
this.roster[jid_lower]['presence'][resource] = presence
}
else if (this.roster[jid_lower] && this.roster[jid_lower]['presence'] && this.roster[jid_lower]['presence'][resource])
{
delete this.roster[jid_lower]['presence'][resource];
}
this.addChange(jid_lower);
if (TrophyIM.activeChats['divs'][jid_lower])
{
TrophyIM.setTabPresence(jid_lower, TrophyIM.activeChats['divs'][jid_lower]['tab']);
}
}
/** Function: addChange
*
* Adds given jid to this.changes, keeping this.changes sorted and
* preventing duplicates.
*
* Parameters
* (String) jid : jid to add to this.changes
*/
this.addChange = function(jid) {
for (var c = 0; c < this.changes.length; c++) {
if (this.changes[c] == jid) {
return;
}
}
this.changes[this.changes.length] = jid;
this.changes.sort();
}
/** Function: getPresence
*
* Returns best presence for given jid as Array(resource, priority, show,
* status)
*
* Parameter: (String) fulljid - jid to return best presence for
*/
this.getPresence = function(fulljid) {
var jid = Strophe.getBareJidFromJid(fulljid);
var current = null;
if (this.roster[jid.toLowerCase()] &&
this.roster[jid.toLowerCase()]['presence']) {
for (var resource in this.roster[jid.toLowerCase()]['presence']) {
var presence = this.roster[jid.toLowerCase()]['presence'][resource];
if (current == null) {
current = presence
} else {
if(presence['priority'] > current['priority'] && ((presence['show'] == "chat"
|| presence['show'] == "available") || (current['show'] != "chat" ||
current['show'] != "available"))) {
current = presence
}
}
}
}
return current;
}
/** Function: groupHasChanges
*
* Returns true if current group has members in this.changes
*
* Parameters:
* (String) group - name of group to check
*/
this.groupHasChanges = function(group) {
for (var c = 0; c < this.changes.length; c++) {
if (this.groups[group][this.changes[c]]) {
return true;
}
}
return false;
}
/** Fuction: save
*
* Saves roster data to JSON store
*/
this.save = function() {
if (TrophyIM.JSONStore.store_working) {
TrophyIM.JSONStore.setData({roster:this.roster,
groups:this.groups, active_chat:TrophyIM.activeChats['current'],
chat_history:TrophyIM.chatHistory});
}
}
}
/** Class: TrophyIMJSONStore
*
*
* This object is the mechanism by which TrophyIM stores and retrieves its
* variables from the url provided by TROPHYIM_JSON_STORE
*
*/
function TrophyIMJSONStore() {
this.store_working = false;
/** Function _newXHR
*
* Set up new cross-browser xmlhttprequest object
*
* Parameters:
* (function) handler = what to set onreadystatechange to
*/
this._newXHR = function (handler) {
var xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
if (xhr.overrideMimeType) {
xhr.overrideMimeType("text/xml");
}
} else if (window.ActiveXObject) {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
return xhr;
}
/** Function getData
* Gets data from JSONStore
*
* Parameters:
* (Array) vars = Variables to get from JSON store
*
* Returns:
* Object with variables indexed by names given in parameter 'vars'
*/
this.getData = function(vars) {
if (typeof(TROPHYIM_JSON_STORE) != undefined) {
Strophe.debug("Retrieving JSONStore data");
var xhr = this._newXHR();
var getdata = "get=" + vars.join(",");
try {
xhr.open("POST", TROPHYIM_JSON_STORE, false);
} catch (e) {
Strophe.error("JSONStore open failed.");
return false;
}
xhr.setRequestHeader('Content-type',
'application/x-www-form-urlencoded');
xhr.setRequestHeader('Content-length', getdata.length);
xhr.send(getdata);
if (xhr.readyState == 4 && xhr.status == 200) {
try {
var dataObj = JSON.parse(xhr.responseText);
return this.emptyFix(dataObj);
} catch(e) {
Strophe.error("Could not parse JSONStore response" +
xhr.responseText);
return false;
}
} else {
Strophe.error("JSONStore open failed. Status: " + xhr.status);
return false;
}
}
}
/** Function emptyFix
* Fix for bugs in external JSON implementations such as
* http://bugs.php.net/bug.php?id=41504.
* A.K.A. Don't use PHP, people.
*/
this.emptyFix = function(obj) {
if (typeof(obj) == "object") {
for (var i in obj) {
if (i == '_empty_') {
obj[""] = this.emptyFix(obj['_empty_']);
delete obj['_empty_'];
} else {
obj[i] = this.emptyFix(obj[i]);
}
}
}
return obj
}
/** Function delData
* Deletes data from JSONStore
*
* Parameters:
* (Array) vars = Variables to delete from JSON store
*
* Returns:
* Status of delete attempt.
*/
this.delData = function(vars) {
if (typeof(TROPHYIM_JSON_STORE) != undefined) {
Strophe.debug("Retrieving JSONStore data");
var xhr = this._newXHR();
var deldata = "del=" + vars.join(",");
try {
xhr.open("POST", TROPHYIM_JSON_STORE, false);
} catch (e) {
Strophe.error("JSONStore open failed.");
return false;
}
xhr.setRequestHeader('Content-type',
'application/x-www-form-urlencoded');
xhr.setRequestHeader('Content-length', deldata.length);
xhr.send(deldata);
if (xhr.readyState == 4 && xhr.status == 200) {
try {
var dataObj = JSON.parse(xhr.responseText);
return dataObj;
} catch(e) {
Strophe.error("Could not parse JSONStore response");
return false;
}
} else {
Strophe.error("JSONStore open failed. Status: " + xhr.status);
return false;
}
}
}
/** Function setData
* Stores data in JSONStore, overwriting values if they exist
*
* Parameters:
* (Object) vars : Object containing named vars to store ({name: value,
* othername: othervalue})
*
* Returns:
* Status of storage attempt
*/
this.setData = function(vars) {
if (typeof(TROPHYIM_JSON_STORE) != undefined) {
Strophe.debug("Storing JSONStore data");
var senddata = "set=" + JSON.stringify(vars);
var xhr = this._newXHR();
try {
xhr.open("POST", TROPHYIM_JSON_STORE, false);
} catch (e) {
Strophe.error("JSONStore open failed.");
return false;
}
xhr.setRequestHeader('Content-type',
'application/x-www-form-urlencoded');
xhr.setRequestHeader('Content-length', senddata.length);
xhr.send(senddata);
if (xhr.readyState == 4 && xhr.status == 200 && xhr.responseText ==
"OK") {
return true;
} else {
Strophe.error("JSONStore open failed. Status: " + xhr.status);
return false;
}
}
}
var testData = true;
if (this.setData({testData:testData})) {
var testResult = this.getData(['testData']);
if (testResult && testResult['testData'] == true) {
this.store_working = true;
}
}
}
/** Constants: Node types
*
* Implementations of constants that IE doesn't have, but we need.
*/
if (document.ELEMENT_NODE == null) {
document.ELEMENT_NODE = 1;
document.ATTRIBUTE_NODE = 2;
document.TEXT_NODE = 3;
document.CDATA_SECTION_NODE = 4;
document.ENTITY_REFERENCE_NODE = 5;
document.ENTITY_NODE = 6;
document.PROCESSING_INSTRUCTION_NODE = 7;
document.COMMENT_NODE = 8;
document.DOCUMENT_NODE = 9;
document.DOCUMENT_TYPE_NODE = 10;
document.DOCUMENT_FRAGMENT_NODE = 11;
document.NOTATION_NODE = 12;
}
/** Function: importNode
*
* document.importNode implementation for IE, which doesn't have importNode
*
* Parameters:
* (Object) node - dom object
* (Boolean) allChildren - import node's children too
*/
if (!document.importNode) {
document.importNode = function(node, allChildren) {
switch (node.nodeType) {
case document.ELEMENT_NODE:
var newNode = document.createElement(node.nodeName);
if (node.attributes && node.attributes.length > 0) {
for(var i = 0; i < node.attributes.length; i++) {
newNode.setAttribute(node.attributes[i].nodeName,
node.getAttribute(node.attributes[i].nodeName));
}
}
if (allChildren && node.childNodes &&
node.childNodes.length > 0) {
for (var i = 0; i < node.childNodes.length; i++) {
newNode.appendChild(document.importNode(
node.childNodes[i], allChildren));
}
}
return newNode;
break;
case document.TEXT_NODE:
case document.CDATA_SECTION_NODE:
case document.COMMENT_NODE:
return document.createTextNode(node.nodeValue);
break;
}
};
}
/**
*
* Bootstrap self into window.onload and window.onunload
*/
/*
var oldonload = window.onload;
window.onload = function()
{
if(oldonload)
{
oldonload();
}
TrophyIM.load();
};
*/
var oldonunload = window.onunload;
window.onunload = function()
{
if(oldonunload)
{
oldonunload();
}
TrophyIM.storeData();
}