source: sandbox/jabberit_messenger/trophy/js/trophyim.js @ 2325

Revision 2325, 60.3 KB checked in by alexandrecorreia, 14 years ago (diff)

Ticket #986 - Adicionado function ao botao troca de status e criacao de div.

  • Property svn:executable set to *
Line 
1/*
2    This program is distributed under the terms of the MIT license.
3    Please see the LICENSE file for details.
4
5    Copyright 2008 Michael Garvin
6*/
7/*TODO dump / very loose roadmap
8--0.4
9add chats to json store
10Mouseover status messages in roster
11HTML in messages (xslt?)
12Select presence status/message
13Optional user-specified resource
14Loglevel select on login instead of check box
15vcard support http://xmpp.org/extensions/xep-0153.html
16Notifications of closed chats
17Notifications of typing
18--0.5
19roster management
20figure out how we want to handle presence from our own jid (and transports)
21roster sorting by presence / offline roster capablility
22auto-subscribe vs prompted subscribe based on config option
23make sure makeChat() et al. can handle empty resources
24    (offline chat capabilities)
25--1.0 (or whenever someone submits better .css)
26layout overhaul
27code cleanup (like checking for excessive function lengths)
28roster versioning http://xmpp.org/extensions/attic/xep-0237-0.1.html
29make sure onload bootstrapping actually preserves existing onloads
30*/
31var TROPHYIM_BOSH_SERVICE = '/proxy/xmpp-httpbind';  //Change to suit
32var TROPHYIM_LOG_LINES = 200;
33var TROPHYIM_LOGLEVEL = 0; //0=debug, 1=info, 2=warn, 3=error, 4=fatal
34var TROPHYIM_VERSION = "0.3";
35//Uncomment to make session reattachment work
36//var TROPHYIM_JSON_STORE = "json_store.php";
37
38/** File: trophyimclient.js
39 *  A JavaScript front-end for strophe.js
40 *
41 *  This is a JavaScript library that runs on top of strophe.js.  All that
42 *  is required is that your page have a <div> element with an id of
43 *  'trophyimclient', and that your page does not explicitly set an onload
44 *  event in its <body> tag.  In that case you need to append TrophyIM.load()
45 *  to it.
46 *
47 *  The style of the client can be conrolled via trophyim.css, which is
48 *  auto-included by the client.
49 */
50
51/** Object: HTMLSnippets
52 *
53 *  This is the repository for all the html snippets that TrophyIM uses
54 *
55 */
56HTMLSnippets = {
57
58                chatArea        : loadIM.HTMLSnippets.chatArea( ),
59               
60        chatBox         : loadIM.HTMLSnippets.chatBox( ),
61
62        chatTab         : loadIM.HTMLSnippets.chatTab( ),
63               
64                //loginPage     : loadIM.HTMLSnippets.loginPage( ),
65   
66        loggingDiv      : loadIM.HTMLSnippets.loggingDiv( ),
67   
68        rosterDiv       : loadIM.HTMLSnippets.rosterDiv( ),
69   
70        rosterGroup     : loadIM.HTMLSnippets.rosterGroup( ),
71       
72        rosterItem      : loadIM.HTMLSnippets.rosterItem( ),
73   
74        //statusDiv     : loadIM.HTMLSnippets.statusDiv( ),
75};
76
77/** Object: DOMObjects
78 *  This class contains builders for all the DOM objects needed by TrophyIM
79 */
80DOMObjects = {
81    /** Function: xmlParse
82     *  Cross-browser alternative to using innerHTML
83     *  Parses given string, returns valid DOM HTML object
84     *
85     *  Parameters:
86     *    (String) xml - the xml string to parse
87     */
88    xmlParse : function(xmlString) {
89        var xmlObj = this.xmlRender(xmlString);
90        if(xmlObj) {
91            try { //Firefox, Gecko, etc
92                if (this.processor == undefined) {
93                    this.processor = new XSLTProcessor();
94                    this.processor.importStylesheet(this.xmlRender(
95                    '<xsl:stylesheet version="1.0"\
96                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">\
97                    <xsl:output method="html" indent="yes"/><xsl:template\
98                    match="@*|node()"><xsl:copy><xsl:copy-of\
99                    select="@*|node()"/></xsl:copy></xsl:template>\
100                    </xsl:stylesheet>'));
101                }
102                var htmlObj =
103                this.processor.transformToDocument(xmlObj).documentElement;
104                //Safari has a quirk where it wraps dom elements in <html><body>
105                if (htmlObj.tagName.toLowerCase() == 'html') {
106                    htmlObj = htmlObj.firstChild.firstChild;
107                }
108                return document.importNode(htmlObj, true);
109            } catch(e) {
110                try { //IE is so very very special
111                    var htmlObj = document.importNode(xmlObj.documentElement, true);
112                    if (htmlObj.tagName.toLowerCase() == "div") {
113                        var div_wrapper = document.createElement('div');
114                        div_wrapper.appendChild(htmlObj);
115                        if(div_wrapper.innerHTML) {
116                            div_wrapper.innerHTML = div_wrapper.innerHTML;
117                        }
118                        htmlObj = div_wrapper.firstChild;
119                    }
120                    return htmlObj;
121                } catch(e) {
122                    alert(
123                    "TrophyIM Error: Cannot add html to page" + e.message);
124                }
125            }
126        }
127    },
128    /** Function: xmlRender
129     *  Uses browser-specific methods to turn given string into xml object
130     *
131     *  Parameters:
132     *    (String) xml - the xml string to parse
133     */
134    xmlRender : function(xmlString) {
135        try {//IE
136            var renderObj = new ActiveXObject("Microsoft.XMLDOM");
137            renderObj.async="false";
138            if(xmlString) {
139                renderObj.loadXML(xmlString);
140            }
141        } catch (e) {
142            try { //Firefox, Gecko, etc
143                if (this.parser == undefined) {
144                    this.parser = new DOMParser();
145                }
146                var renderObj = this.parser.parseFromString(xmlString,
147                "application/xml");
148            } catch(e) {
149                alert("TrophyIM Error: Cannot create new html for page");
150            }
151        }
152
153        return renderObj;
154    },
155    /** Function: getHTML
156     *  Returns named HTML snippet as DOM object
157     *
158     *  Parameters:
159     *    (String) name - name of HTML snippet to retrieve (see HTMLSnippets
160     *    object)
161     */
162    getHTML : function(page) {
163        //alert("Page : \n" + page);
164        return this.xmlParse(HTMLSnippets[page]);
165    },
166    /** Function: getScript
167     *  Returns script object with src to given script
168     *
169     *  Parameters:
170     *    (String) script - name of script to put in src attribute of script
171     *    element
172     */
173    getScript : function(script) {
174        var newscript = document.createElement('script');
175        newscript.setAttribute('src', script);
176        newscript.setAttribute('type', 'text/javascript');
177        return newscript;
178    }
179};
180
181/** Object: TrophyIM
182 *
183 *  This is the actual TrophyIM application.  It searches for the
184 *  'trophyimclient' element and inserts itself into that.
185 */
186TrophyIM = {
187    /** Constants:
188     *
189     *    (Boolean) stale_roster - roster is stale and needs to be rewritten.
190     */
191    constants : {stale_roster: false},
192    /** Object: chatHistory
193     *
194     *  Stores chat history (last 10 message) and current presence of active
195     *  chat tabs.  Indexed by jid.
196     */
197    chatHistory : {},
198   
199    /** Object: activeChats
200     *
201     *  This object stores the currently active chats.
202     */
203   
204     activeChats : {current: null, divs: {}},
205   
206     /** Function: setCookie
207     *
208     *  Sets cookie name/value pair.  Date and path are auto-selected.
209     *
210     *  Parameters:
211     *    (String) name - the name of the cookie variable
212     *    (String) value - the value of the cookie variable
213     */
214    setCookie : function(name, value) {
215        var expire = new Date();
216        expire.setDate(expire.getDate() + 365);
217        document.cookie = name + "=" + value + "; expires=" + expire.toGMTString();
218    },
219    /** Function: delCookie
220     *
221     *  Deletes cookie
222     *
223     *  Parameters:
224     *    (String) name) - the name of the cookie to delete
225     */
226    delCookie : function(name) {
227        var expire = new Date();
228        expire.setDate(expire.getDate() - 365);
229        document.cookie = name + "= ; expires=" + expire.toGMTString();
230        delete TrophyIM.cookies[name];
231    },
232    /** Function: getCookies
233     *
234     *  Retrieves all trophyim cookies into an indexed object.  Inteneded to be
235     *  called once, at which time the app refers to the returned object instead
236     *  of re-parsing the cookie string every time.
237     *
238     *  Each cookie is also re-applied so as to refresh the expiry date.
239     */
240    getCookies : function() {
241        var cObj = {};
242        var cookies = document.cookie.split(';');
243        for (var c in cookies) {
244            while (cookies[c].charAt(0)==' ') {
245                cookies[c] = cookies[c].substring(1,cookies[c].length);
246            }
247            if (cookies[c].substr(0, 8) == "trophyim") {
248                var nvpair = cookies[c].split("=", 2);
249                cObj[nvpair[0]] = nvpair[1];
250                TrophyIM.setCookie(nvpair[0], nvpair[1]);
251            }
252        }
253        return cObj;
254    },
255    /** Function: load
256     *
257     *  This function searches for the trophyimclient div and loads the client
258     *  into it.
259     */
260    load : function()
261        {
262                TrophyIM.cookies        = TrophyIM.getCookies();
263
264                TrophyIM.client_div = document.getElementById('trophyimclient');
265
266        //Load other .js scripts needed
267        document.getElementsByTagName('head')[0].appendChild(DOMObjects.getScript('strophejs/strophe.js'));
268        document.getElementsByTagName('head')[0].appendChild(DOMObjects.getScript('strophejs/md5.js'));
269        document.getElementsByTagName('head')[0].appendChild(DOMObjects.getScript('strophejs/sha1.js'));
270        document.getElementsByTagName('head')[0].appendChild(DOMObjects.getScript('strophejs/b64.js'));
271        document.getElementsByTagName('head')[0].appendChild(DOMObjects.getScript('js/json2.js')); //Keep this script last
272
273                //Wait a second to give scripts time to load
274                setTimeout("TrophyIM.showLogin()", 500);
275
276            /*TrophyIM.cookies = TrophyIM.getCookies();
277        var client_div = document.getElementById('trophyimclient');
278        if (client_div)
279        {
280            TrophyIM.client_div = client_div;
281
282            //load .css
283            //document.getElementsByTagName('head')[0].appendChild(DOMObjects.getHTML('cssLink'));
284            //DOMObjects.getHTML('cssLink');
285           
286            //Load other .js scripts needed
287            document.getElementsByTagName('head')[0].appendChild(DOMObjects.getScript('strophejs/strophe.js'));
288            document.getElementsByTagName('head')[0].appendChild(DOMObjects.getScript('strophejs/md5.js'));
289            document.getElementsByTagName('head')[0].appendChild(DOMObjects.getScript('strophejs/sha1.js'));
290            document.getElementsByTagName('head')[0].appendChild(DOMObjects.getScript('strophejs/b64.js'));
291            document.getElementsByTagName('head')[0].appendChild(DOMObjects.getScript('js/json2.js')); //Keep this script last
292           
293            //Wait a second to give scripts time to load
294            setTimeout("TrophyIM.showLogin()", 500);
295        } else {
296            alert("Cannot load TrophyIM client.\nClient div not found.");
297        }*/
298    },
299    /** Function: storeData
300     *
301     *  Store all our data in the JSONStore, if it is active
302     */
303    storeData : function() {
304        if (TrophyIM.connection && TrophyIM.connection.connected) {
305            TrophyIM.setCookie('trophyim_bosh_xid', TrophyIM.connection.jid + "|" +
306            TrophyIM.connection.sid + "|" +  TrophyIM.connection.rid);
307            TrophyIM.rosterObj.save();
308        }
309    },
310    /**  Function: showlogin
311     *
312     *   This function clears out the IM box and either redisplays the login
313     *   page, or re-attaches to Strophe, preserving the logging div if it
314     *   exists, or creating a new one of we are re-attaching.
315     */
316    showLogin : function() {
317        //JSON is the last script to load, so we wait on it
318        //Added Strophe check too because of bug where it's sometimes missing
319        if (typeof(JSON) != undefined && typeof(Strophe) != undefined)
320        {
321                TrophyIM.JSONStore = new TrophyIMJSONStore();
322               
323            if ( TrophyIM.JSONStore.store_working && TrophyIM.cookies['trophyim_bosh_xid'] )
324            {
325                var xids = TrophyIM.cookies['trophyim_bosh_xid'].split("|");
326                TrophyIM.delCookie('trophyim_bosh_xid');
327                TrophyIM.constants.stale_roster = true;
328                if (TrophyIM.cookies['trophyimloglevel'])
329                {
330                    TrophyIM.client_div.appendChild(DOMObjects.getHTML('loggingDiv'));
331                    TrophyIM.logging_div = document.getElementById('trophyimlog');
332                }
333                TrophyIM.connection = new Strophe.Connection(TROPHYIM_BOSH_SERVICE);
334                TrophyIM.connection.rawInput = TrophyIM.rawInput;
335                TrophyIM.connection.rawOutput = TrophyIM.rawOutput;
336                Strophe.log = TrophyIM.log;
337                Strophe.info('Attempting Strophe attach.');
338                TrophyIM.connection.attach(xids[0], xids[1], xids[2], TrophyIM.onConnect);
339                TrophyIM.onConnect(Strophe.Status.CONNECTED);
340            }
341            else
342            {
343                var logging_div = TrophyIM.clearClient();
344                loadIM.HTMLSnippets.loginPage();
345            }
346        }
347        else
348        {
349                setTimeout("TrophyIM.showLogin()", 500);
350        }
351    },
352    /** Function: log
353     *
354     *  This function logs the given message in the trophyimlog div
355     *
356     *  Parameter: (String) msg - the message to log
357     */
358   
359    log : function(level, msg)
360    {
361        if (TrophyIM.logging_div && level >= TROPHYIM_LOGLEVEL) {
362            while(TrophyIM.logging_div.childNodes.length > TROPHYIM_LOG_LINES) {
363                TrophyIM.logging_div.removeChild(
364                TrophyIM.logging_div.firstChild);
365            }
366            var msg_div = document.createElement('div');
367            msg_div.className = 'trophyimlogitem';
368            msg_div.appendChild(document.createTextNode(msg));
369            TrophyIM.logging_div.appendChild(msg_div);
370            TrophyIM.logging_div.scrollTop = TrophyIM.logging_div.scrollHeight;
371        }
372    },
373    /** Function: rawInput
374     *
375     *  This logs the packets actually recieved by strophe at the debug level
376     */
377    rawInput : function (data) {
378        Strophe.debug("RECV: " + data);
379    },
380    /** Function: rawInput
381     *
382     *  This logs the packets actually recieved by strophe at the debug level
383     */
384    rawOutput : function (data) {
385        Strophe.debug("SEND: " + data);
386    },
387    /** Function: login
388     *
389     *  This function logs into server using information given on login page.
390     *  Since the login page is where the logging checkbox is, it makes or
391     *  removes the logging div and cookie accordingly.
392     *
393     */
394    login : function() {
395        if (document.getElementById('trophyimloglevel').checked) {
396            TrophyIM.setCookie('trophyimloglevel', 1);
397            if (!document.getElementById('trophyimlog')) {
398                TrophyIM.client_div.appendChild(DOMObjects.getHTML('loggingDiv'));
399                TrophyIM.logging_div = document.getElementById('trophyimlog');
400            }
401        } else {
402            TrophyIM.delCookie('trophyimloglevel');
403            if (document.getElementById('trophyimlog')) {
404                TrophyIM.client_div.removeChild(document.getElementById(
405                'trophyimlog'));
406                TrophyIM.logging_div = null;
407            }
408        }
409        if (TrophyIM.JSONStore.store_working) { //In case they never logged out
410            TrophyIM.JSONStore.delData(['groups','roster', 'active_chat',
411            'chat_history']);
412        }
413        TrophyIM.connection = new Strophe.Connection(TROPHYIM_BOSH_SERVICE);
414        TrophyIM.connection.rawInput = TrophyIM.rawInput;
415        TrophyIM.connection.rawOutput = TrophyIM.rawOutput;
416        Strophe.log = TrophyIM.log;
417        var barejid  = document.getElementById('trophyimjid').value
418        var fulljid = barejid + '/TrophyIM';
419        TrophyIM.setCookie('trophyimjid', barejid);
420        var password = document.getElementById('trophyimpass').value;
421        var button = document.getElementById('trophyimconnect');
422        if (button.value == 'connect') {
423            button.value = 'disconnect';
424            TrophyIM.connection.connect(fulljid, password, TrophyIM.onConnect);
425        } else {
426            button.value = 'connect';
427            TrophyIM.connection.disconnect();
428        }
429
430    },
431    /** Function: login
432     *
433     *  Logs into fresh session through Strophe, purging any old data.
434     */
435    logout : function()
436        {
437        TrophyIM.delCookie('trophyim_bosh_xid');
438        delete TrophyIM['cookies']['trophyim_bosh_xid'];
439        if (TrophyIM.JSONStore.store_working)
440                {
441            TrophyIM.JSONStore.delData(['groups','roster', 'active_chat', 'chat_history']);
442        }
443       
444                for (var chat in TrophyIM.activeChats['divs'])
445                {
446            delete TrophyIM.activeChats['divs'][chat];
447        }
448               
449        TrophyIM.activeChats = {current: null, divs: {}},
450        TrophyIM.connection.disconnect();
451        TrophyIM.showLogin();
452               
453    },
454    /** Function onConnect
455     *
456     *  Callback given to Strophe upon connection to BOSH proxy.
457     */
458    onConnect : function(status) {
459        if (status == Strophe.Status.CONNECTING) {
460            Strophe.info('Strophe is connecting.');
461        } else if (status == Strophe.Status.CONNFAIL) {
462            Strophe.info('Strophe failed to connect.');
463            TrophyIM.delCookie('trophyim_bosh_xid');
464            TrophyIM.showLogin();
465        } else if (status == Strophe.Status.DISCONNECTING) {
466            Strophe.info('Strophe is disconnecting.');
467        } else if (status == Strophe.Status.DISCONNECTED) {
468            Strophe.info('Strophe is disconnected.');
469            TrophyIM.delCookie('trophyim_bosh_xid');
470            TrophyIM.showLogin();
471        } else if (status == Strophe.Status.CONNECTED) {
472            Strophe.info('Strophe is connected.');
473            TrophyIM.showClient();
474        }
475    },
476
477    /** Function: showClient
478     *
479     *  This clears out the main div and puts in the main client.  It also
480     *  registers all the handlers for Strophe to call in the client.
481     */
482    showClient : function()
483        {
484        TrophyIM.setCookie('trophyim_bosh_xid', TrophyIM.connection.jid + "|" +
485        TrophyIM.connection.sid + "|" +  TrophyIM.connection.rid);
486        var logging_div = TrophyIM.clearClient();
487       
488                loadIM.HTMLSnippets.rosterDiv();
489                loadIM.HTMLSnippets.chatArea();
490               
491                //TrophyIM.client_div.appendChild(DOMObjects.getHTML('rosterDiv'));
492        //TrophyIM.client_div.appendChild(DOMObjects.getHTML('chatArea'));
493        //TrophyIM.client_div.appendChild(DOMObjects.getHTML('statusDiv'));
494               
495        if(logging_div)
496                {
497            TrophyIM.client_div.appendChild(logging_div);
498            TrophyIM.logging_div = document.getElementById('trophyimlog');
499        }
500        TrophyIM.rosterObj = new TrophyIMRoster();
501        TrophyIM.connection.addHandler(TrophyIM.onVersion, Strophe.NS.VERSION, 'iq', null, null, null);
502        TrophyIM.connection.addHandler(TrophyIM.onRoster, Strophe.NS.ROSTER, 'iq', null, null, null);
503        TrophyIM.connection.addHandler(TrophyIM.onPresence, null, 'presence', null, null, null);
504        TrophyIM.connection.addHandler(TrophyIM.onMessage, null, 'message', null, null,  null);
505        //Get roster then announce presence.
506        TrophyIM.connection.send($iq({type: 'get', xmlns: Strophe.NS.CLIENT}).c('query', {xmlns: Strophe.NS.ROSTER}).tree());
507        TrophyIM.connection.send($pres().tree());
508        TrophyIM.renderChats();
509        setTimeout("TrophyIM.renderRoster()", 1000);
510    },
511       
512    /** Function: clearClient
513     *
514     *  Clears out client div, preserving and returning existing logging_div if
515     *  one exists
516     */
517    clearClient : function() {
518        if(TrophyIM.logging_div) {
519            var logging_div = TrophyIM.client_div.removeChild(
520            document.getElementById('trophyimlog'));
521        } else {
522            var logging_div = null;
523        }
524        while(TrophyIM.client_div.childNodes.length > 0) {
525            TrophyIM.client_div.removeChild(TrophyIM.client_div.firstChild);
526        }
527        return logging_div;
528    },
529    /** Function: onVersion
530     *
531     *  jabber:iq:version query handler
532     */
533    onVersion : function(msg) {
534        Strophe.debug("Version handler");
535        if (msg.getAttribute('type') == 'get') {
536            var from = msg.getAttribute('from');
537            var to = msg.getAttribute('to');
538            var id = msg.getAttribute('id');
539            var reply = $iq({type: 'result', to: from, from: to, id: id}).c('query',
540            {name: "TrophyIM", version: TROPHYIM_VERSION, os:
541            "Javascript-capable browser"});
542            TrophyIM.connection.send(reply.tree());
543        }
544        return true;
545    },
546    /** Function: onRoster
547     *
548     *  Roster iq handler
549     */
550    onRoster : function(msg) {
551        Strophe.debug("Roster handler");
552        var roster_items = msg.firstChild.getElementsByTagName('item');
553        for (var i = 0; i < roster_items.length; i++) {
554            var groups = roster_items[i].getElementsByTagName('group');
555            var group_array = new Array();
556            for (var g = 0; g < groups.length; g++) {
557                group_array[group_array.length] =
558                groups[g].firstChild.nodeValue;
559            }
560            TrophyIM.rosterObj.addContact(roster_items[i].getAttribute('jid'),
561            roster_items[i].getAttribute('subscription'),
562            roster_items[i].getAttribute('name'), group_array);
563        }
564        if (msg.getAttribute('type') == 'set') {
565            TrophyIM.connection.send($iq({type: 'reply', id:
566            msg.getAttribute('id'), to: msg.getAttribute('from')}).tree());
567        }
568        return true;
569    },
570    /** Function: onPresence
571     *
572     *  Presence handler
573     */
574    onPresence : function(msg)
575        {
576                //alert('Function onPresence');
577               
578                Strophe.debug("Presence handler");
579        var type = msg.getAttribute('type') ? msg.getAttribute('type') : 'available';
580        var show = msg.getElementsByTagName('show').length ? Strophe.getText(msg.getElementsByTagName('show')[0]) : type;
581        var status = msg.getElementsByTagName('status').length ? Strophe.getText(msg.getElementsByTagName('status')[0]) : '';
582        var priority = msg.getElementsByTagName('priority').length ? parseInt(Strophe.getText(msg.getElementsByTagName('priority')[0])) : 0;
583                TrophyIM.rosterObj.setPresence(msg.getAttribute('from'), priority, show, status);
584               
585        return true;
586    },
587    /** Function: onMessage
588     *
589     *  Message handler
590     */
591    onMessage : function(msg)
592    {
593        Strophe.debug("Message handler");
594   
595        var from = msg.getAttribute('from');
596        var type = msg.getAttribute('type');
597        var elems = msg.getElementsByTagName('body');
598
599        if ( (type == 'chat' || type == 'normal') && elems.length > 0 )
600        {
601            var barejid         = Strophe.getBareJidFromJid(from);
602            var jid_lower       = barejid.toLowerCase();
603            var contact = "";
604               
605            if( TrophyIM.rosterObj.roster[barejid.toLowerCase()] )
606            {
607                contact = TrophyIM.rosterObj.roster[barejid.toLowerCase()]['contact']['name'];
608            }
609            else
610            {
611                contact = barejid.toLowerCase();
612                contact = contact.substring(0, contact.indexOf('@'));
613            }   
614           
615            var message =
616            {
617                contact : "<font style='font-weight:bold; color:black;'>" + contact + "</font>",
618                msg             : Strophe.getText(elems[0])     
619            };
620
621            TrophyIM.makeChat(from); //Make sure we have a chat window
622            TrophyIM.addMessage(message, jid_lower);
623
624            /* 
625            if ( contact )
626            {
627
628                //Do we know you?
629                if ( contact['name'] != null )
630                {
631                    message  = contact['name'] + " (" + barejid + "): ";
632                }
633                else
634                {
635                    message = contact['jid'] + ": ";
636                }
637               
638                message += Strophe.getText(elems[0]);
639               
640                TrophyIM.makeChat(from); //Make sure we have a chat window
641                TrophyIM.addMessage(message, jid_lower);
642               
643               
644                //if (TrophyIM.activeChats['current'] != jid_lower) {
645                //    TrophyIM.activeChats['divs'][jid_lower][
646                //    'tab'].className = "trophyimchattab trophyimchattab_a";
647                //    TrophyIM.setTabPresence(from,
648                //    TrophyIM.activeChats['divs'][jid_lower]['tab']);
649                //}
650            }*/
651        }
652        return true;
653    },
654    /** Function: makeChat
655     *
656     *  Make sure chat window to given fulljid exists, switching chat context to
657     *  given resource
658     */
659    makeChat : function(fulljid)
660    {
661       
662        var barjid = Strophe.getBareJidFromJid(fulljid);
663       
664        var paramsChatBox =
665        {
666                        'idChatBox' : barjid + "__chatBox",
667                        'jidTo'         : barjid,
668        };
669       
670        var winChatBox =
671        {
672                         id_window              : "window_chat_area_" + barjid,
673                         width                  : 387,
674                         height                 : 365,
675                         top                    : 100,
676                         left                   : 400,
677                         draggable              : true,
678                         visible                : "display",
679                         resizable              : true,
680                         zindex                 : loadIM.getZIndex(),
681                         title                  : barjid.substring(0, barjid.indexOf('@')),
682                         closeAction    : "hidden",
683                         content                : loadIM.parse("chat_box","chatBox.xsl", paramsChatBox)
684        }
685       
686        _winBuild(winChatBox)
687               
688                loadIM.configEvents(
689                        document.getElementById( barjid + '__sendBox'),
690                        'onkeyup', function(e)
691                        {
692                                if( e.keyCode == 13 )
693                                {
694                                        TrophyIM.sendMessage( barjid );
695                                        document.getElementById( barjid + '__sendBox').value = '';
696                                        return false;
697                                }
698                        }
699                );
700               
701        /*
702         * Codigo Original
703         *
704        var barejid = Strophe.getBareJidFromJid(fulljid);
705        if (!TrophyIM.activeChats['divs'][barejid]) {
706            var chat_tabs = document.getElementById('trophyimchattabs');
707            var chat_tab = DOMObjects.getHTML('chatTab');
708            var chat_box = DOMObjects.getHTML('chatBox');
709            var contact = TrophyIM.rosterObj.getContact(barejid);
710            var tab_name = (contact['name'] != null) ? contact['name'] : barejid;
711            chat_tab.className = "trophyimchattab trophyimchattab_a";
712            getElementsByClassName('trophyimchattabjid', 'div', chat_tab)[0].appendChild(document.createTextNode(barejid));
713            getElementsByClassName('trophyimchattabname', 'div', chat_tab)[0].appendChild(document.createTextNode(tab_name));
714            chat_tab = chat_tabs.appendChild(chat_tab);
715            TrophyIM.activeChats['divs'][barejid] = {jid:fulljid, tab:chat_tab, box:chat_box};
716           
717            if (!TrophyIM.activeChats['current']) { //We're the first
718                TrophyIM.activeChats['current'] = barejid;
719                document.getElementById('trophyimchat').appendChild(chat_box);
720                TrophyIM.activeChats['divs'][barejid]['box'] = chat_box;
721                TrophyIM.activeChats['divs'][barejid]['tab'].className =
722                "trophyimchattab trophyimchattab_f";
723            }
724            if (!TrophyIM.chatHistory[barejid.toLowerCase()]) {
725                TrophyIM.chatHistory[barejid.toLowerCase()] = {resource: null,
726                history: new Array()};
727            }
728            TrophyIM.setTabPresence(fulljid, chat_tab);
729        }
730        TrophyIM.activeChats['divs'][barejid.toLowerCase()]['resource'] =
731        Strophe.getResourceFromJid(fulljid);
732        TrophyIM.chatHistory[barejid.toLowerCase()]['resource'] =
733        Strophe.getResourceFromJid(fulljid);*/
734       
735    },
736    /** Function showChat
737     *
738     *  Make chat box to given barejid active
739     */
740    showChat : function(barejid) {
741        if (TrophyIM.activeChats['current'] &&
742        TrophyIM.activeChats['current'] != barejid) {
743            var chat_area = document.getElementById('trophyimchat');
744            var active_divs =
745            TrophyIM.activeChats['divs'][TrophyIM.activeChats['current']];
746            active_divs['box'] =
747            chat_area.removeChild(getElementsByClassName('trophyimchatbox',
748            'div', chat_area)[0].parentNode);
749            active_divs['tab'].className = "trophyimchattab trophyimchattab_b";
750            TrophyIM.setTabPresence(TrophyIM.activeChats['current'],
751            active_divs['tab']);
752            TrophyIM.activeChats['divs'][barejid]['box'] =
753            chat_area.appendChild(TrophyIM.activeChats['divs'][barejid]['box']);
754            TrophyIM.activeChats['current'] = barejid;
755            TrophyIM.activeChats['divs'][barejid]['tab'].className =
756            "trophyimchattab trophyimchattab_f";
757            TrophyIM.setTabPresence(barejid,
758            TrophyIM.activeChats['divs'][barejid]['tab']);
759            getElementsByClassName('trophyimchatinput', null,
760            TrophyIM.activeChats['divs'][barejid]['box'])[0].focus();
761        }
762    },
763    /** Function: setTabPresence
764     *
765     *  Applies appropriate class to tab div based on presence
766     *
767     *  Parameters:
768     *    (String) jid - jid to check presence for
769     *    (String) tab_div - tab div element to alter class on
770     */
771    setTabPresence : function(jid, tab_div)
772        {
773        alert('function setTabPresence');
774               
775                var presence = TrophyIM.rosterObj.getPresence(jid);
776        tab_div.className = tab_div.className.replace(" trophyimchattab_av", "");
777        tab_div.className = tab_div.className.replace(" trophyimchattab_aw", "");
778        tab_div.className = tab_div.className.replace(" trophyimchattab_off", "");
779        if (presence) {
780            if (presence['show'] == "chat" || presence['show'] == "available") {
781                tab_div.className += " trophyimchattab_av";
782            } else {
783                tab_div.className += " trophyimchattab_aw";
784            }
785        } else {
786            tab_div.className += " trophyimchattab_off";
787        }
788    },
789    /** Function: addMessage
790     *
791     *  Adds message to chat box, and history
792     *
793     *  Parameters:
794     *    (string) msg - the message to add
795     *    (string) jid - the jid of chat box to add the message to.
796     */
797    addMessage : function(msg, jid)
798    {
799        var chatBox             = document.getElementById(jid + "__chatBox");
800        var messageDiv  = document.createElement("div");
801                messageDiv.style.margin = "3px 0px 3px 3px";
802                messageDiv.innerHTML    = msg.contact + " : " + msg.msg ;
803               
804        chatBox.appendChild(messageDiv);
805        chatBox.scrollTop = chatBox.scrollHeight;
806       
807        /*
808         * Codigo Original Comentado
809         *
810       
811        var chat_box = getElementsByClassName('trophyimchatbox', 'div',
812        TrophyIM.activeChats['divs'][jid]['box'])[0];
813        var msg_div = document.createElement('div');
814        msg_div.className = 'trophyimchatmessage';
815        msg_div.appendChild(document.createTextNode(msg));
816        chat_box.appendChild(msg_div);
817        chat_box.scrollTop = chat_box.scrollHeight;
818        if (TrophyIM.chatHistory[jid]['history'].length > 10) {
819            TrophyIM.chatHistory[jid]['history'].shift();
820        }
821        TrophyIM.chatHistory[jid]['history'][
822        TrophyIM.chatHistory[jid]['history'].length] = msg;
823        */
824    },
825    /** Function: renderRoster
826     *
827     *  Renders roster, looking only for jids flagged by setPresence as having
828     *  changed.
829     */
830    renderRoster : function() {
831        if (TrophyIM.rosterObj.changes.length > 0) {
832            var roster_div = document.getElementById('trophyimroster');
833            if(roster_div) {
834                var groups = new Array();
835                for (var group in TrophyIM.rosterObj.groups) {
836                    groups[groups.length] = group;
837                }
838                groups.sort();
839                var group_divs = getElementsByClassName('trophyimrostergroup',
840                null, roster_div);
841                for (var g = 0; g < group_divs.length; g++) {
842                    var group_name = getElementsByClassName('trophyimrosterlabel',
843                    null, group_divs[g])[0].firstChild.nodeValue;
844                    while (group_name > groups[0]) {
845                        var new_group = TrophyIM.renderGroup(groups[0], roster_div);
846                        new_group = roster_div.insertBefore(new_group,
847                        group_divs[g]);
848                        if (TrophyIM.rosterObj.groupHasChanges(groups[0])) {
849                            TrophyIM.renderGroupUsers(new_group, groups[0],
850                            TrophyIM.rosterObj.changes.slice());
851                        }
852                        groups.shift();
853                    }
854                    if (group_name == groups[0]) {
855                        groups.shift();
856                    }
857                    if (TrophyIM.rosterObj.groupHasChanges(group_name)) {
858                        TrophyIM.renderGroupUsers(group_divs[g], group_name,
859                        TrophyIM.rosterObj.changes.slice());
860                    }
861                }
862                while (groups.length) {
863                    var group_name = groups.shift();
864                    var new_group = TrophyIM.renderGroup(group_name,
865                    roster_div);
866                    new_group = roster_div.appendChild(new_group);
867                    if (TrophyIM.rosterObj.groupHasChanges(group_name)) {
868                        TrophyIM.renderGroupUsers(new_group, group_name,
869                        TrophyIM.rosterObj.changes.slice());
870                    }
871                }
872            }
873            TrophyIM.rosterObj.changes = new Array();
874            TrophyIM.constants.stale_roster = false;
875        }
876        setTimeout("TrophyIM.renderRoster()", 1000);
877    },
878    /** Function: renderChats
879    *
880    *  Renders chats found in TrophyIM.chatHistory.  Called upon page reload.
881    *  Waits for stale_roster flag to clear before trying to run, so that the
882    *  roster exists
883    */
884    renderChats : function() {
885        if (TrophyIM.constants.stale_roster == false) {
886            if(TrophyIM.JSONStore.store_working) {
887                var data = TrophyIM.JSONStore.getData(['chat_history',
888                'active_chat']);
889                if (data['active_chat']) {
890                    for (var jid in data['chat_history']) {
891                        fulljid = jid + "/" + data['chat_history'][jid]['resource'];
892                        Strophe.info("Makechat " + fulljid);
893                        TrophyIM.makeChat(fulljid);
894                        for (var h = 0; h <
895                        data['chat_history'][jid]['history'].length; h++) {
896                            TrophyIM.addMessage(data['chat_history'][jid]['history'][h],
897                            jid);
898                        }
899                    }
900                    TrophyIM.chat_history = data['chat_history'];
901                    TrophyIM.showChat(data['active_chat']);
902                }
903            }
904        } else {
905            setTimeout("TrophyIM.renderChats()", 1000);
906        }
907    },
908    /** Function: renderGroup
909     *
910     *  Renders actual group label in roster
911     *
912     *  Parameters:
913     *    (String) group - name of group to render
914     *    (DOM) roster_div - roster div
915     *
916     *  Returns:
917     *    DOM group div to append into roster
918     */
919    renderGroup : function(group, roster_div) {
920        var new_group = DOMObjects.getHTML('rosterGroup');
921        var label_div = getElementsByClassName( 'trophyimrosterlabel', null,
922        new_group)[0];
923        label_div.appendChild(document.createTextNode(group));
924        new_group.appendChild(label_div);
925        return new_group;
926    },
927    /** Function: renderGroupUsers
928     *
929     *  Re-renders user entries in given group div based on status of roster
930     *
931     *  Parameter: (Array) changes - jids with changes in the roster.  Note:
932     *  renderGroupUsers will clobber this.
933     */
934    renderGroupUsers : function(group_div, group_name, changes) {
935        var group_members = TrophyIM.rosterObj.groups[group_name];
936        var member_divs = getElementsByClassName('trophyimrosteritem', null,
937        group_div);
938        for (var m = 0; m < member_divs.length; m++) {
939            member_jid = getElementsByClassName('trophyimrosterjid', null,
940            member_divs[m])[0].firstChild.nodeValue;
941            if (member_jid > changes[0]) {
942                if (changes[0] in group_members) {
943                    var new_presence = TrophyIM.rosterObj.getPresence(
944                    changes[0]);
945                    if(new_presence) {
946                        var new_member = DOMObjects.getHTML('rosterItem');
947                        var new_contact =
948                        TrophyIM.rosterObj.getContact(changes[0]);
949                        getElementsByClassName('trophyimrosterjid', null,
950                        new_member)[0].appendChild(document.createTextNode(
951                        changes[0]));
952                        var new_name = (new_contact['name'] != null) ?
953                        new_contact['name'] : changes[0];
954                        getElementsByClassName('trophyimrostername', null,
955                        new_member)[0].appendChild(document.createTextNode(
956                        new_name));
957                        group_div.insertBefore(new_member, member_divs[m]);
958                        if (new_presence['show'] == "available" ||
959                        new_presence['show'] == "chat") {
960                            new_member.className =
961                            "trophyimrosteritem trophyimrosteritem_av";
962                        } else {
963                            new_member.className =
964                            "trophyimrosteritem trophyimrosteritem_aw";
965                        }
966                    } else {
967                        //show offline contacts
968                    }
969                }
970                changes.shift();
971            } else if (member_jid == changes[0]) {
972                member_presence = TrophyIM.rosterObj.getPresence(member_jid);
973                if(member_presence) {
974                    if (member_presence['show'] == "available" ||
975                    member_presence['show'] == "chat") {
976                        member_divs[m].className =
977                        "trophyimrosteritem trophyimrosteritem_av";
978                    } else {
979                        member_divs[m].className =
980                        "trophyimrosteritem trophyimrosteritem_aw";
981                    }
982                } else {
983                    //show offline status
984                    group_div.removeChild(member_divs[m]);
985                }
986                changes.shift();
987            }
988        }
989        while (changes.length > 0) {
990            if (changes[0] in group_members) {
991                var new_presence = TrophyIM.rosterObj.getPresence(changes[0]);
992                if(new_presence) {
993                    var new_member = DOMObjects.getHTML('rosterItem');
994                    var new_contact =
995                    TrophyIM.rosterObj.getContact(changes[0]);
996                    getElementsByClassName('trophyimrosterjid', null,
997                    new_member)[0].appendChild(document.createTextNode(
998                    changes[0]));
999                    var new_name = (new_contact['name'] != null) ?
1000                    new_contact['name'] : changes[0];
1001                    getElementsByClassName('trophyimrostername', null,
1002                    new_member)[0].appendChild(document.createTextNode(
1003                    new_name));
1004                    group_div.appendChild(new_member);
1005                    if (new_presence['show'] == "available" ||
1006                    new_presence['show'] == "chat") {
1007                        new_member.className =
1008                        "trophyimrosteritem trophyimrosteritem_av";
1009                    } else {
1010                        new_member.className =
1011                        "trophyimrosteritem trophyimrosteritem_aw";
1012                    }
1013                } else {
1014                    //show offline
1015                }
1016            }
1017            changes.shift();
1018        }
1019    },
1020    /** Function: rosterClick
1021     *
1022     *  Handles actions when a roster item is clicked
1023     */
1024    rosterClick : function(roster_item) {
1025        var barejid = getElementsByClassName('trophyimrosterjid', null,
1026        roster_item)[0].firstChild.nodeValue;
1027        var presence = TrophyIM.rosterObj.getPresence(barejid);
1028        if (presence && presence['resource']) {
1029            var fulljid = barejid + "/" + presence['resource'];
1030        } else {
1031            var fulljid = barejid;
1032        }
1033        TrophyIM.makeChat(fulljid);
1034        TrophyIM.showChat(barejid);
1035    },
1036    /** Function: tabClick
1037     *
1038     *  Handles actions when a chat tab is clicked
1039     */
1040    tabClick : function(tab_item) {
1041        var barejid = getElementsByClassName('trophyimchattabjid', null,
1042        tab_item)[0].firstChild.nodeValue;
1043        if (TrophyIM.activeChats['divs'][barejid]) {
1044            TrophyIM.showChat(barejid);
1045        }
1046    },
1047    /** Function: tabClose
1048     *
1049     *  Closes chat tab
1050     */
1051    tabClose : function(tab_item) {
1052        var barejid = getElementsByClassName('trophyimchattabjid', null,
1053        tab_item.parentNode)[0].firstChild.nodeValue;
1054        if (TrophyIM.activeChats['current'] == barejid) {
1055            if (tab_item.parentNode.nextSibling) {
1056                TrophyIM.showChat(getElementsByClassName('trophyimchattabjid',
1057                null, tab_item.parentNode.nextSibling)[0].firstChild.nodeValue);
1058            } else if (tab_item.parentNode.previousSibling) {
1059                TrophyIM.showChat(getElementsByClassName('trophyimchattabjid',
1060                null, tab_item.parentNode.previousSibling)[0].firstChild.nodeValue);
1061            } else { //no other active chat
1062                document.getElementById('trophyimchat').removeChild(
1063                getElementsByClassName('trophyimchatbox')[0].parentNode);
1064                delete TrophyIM.activeChats['current'];
1065            }
1066        }
1067        delete TrophyIM.activeChats['divs'][barejid];
1068        delete TrophyIM.chatHistory[barejid];
1069        //delete tab
1070        tab_item.parentNode.parentNode.removeChild(tab_item.parentNode);
1071    },
1072   
1073        setPresence : function()
1074        {
1075                if( arguments.length > 0 )
1076                {
1077                        TrophyIM.connection.send($pres( ).c('show').t(arguments[0]));
1078                }
1079        },
1080       
1081        /** Function: sendMessage
1082     *
1083     *  Send message from chat input to user
1084     */
1085     
1086    sendMessage : function()
1087    {
1088
1089        if( arguments.length > 0 )
1090        {
1091                var jidTo = arguments[0];
1092                var message_input = document.getElementById(jidTo + "__sendBox").value;
1093           
1094                if( ( message_input = message_input.replace(/^\s+|\s+$|^\n|\n$/g,"") ) != "" )
1095                {
1096                        // Send Message
1097                        TrophyIM.connection.send($msg({to: jidTo, from: TrophyIM.connection.jid, type: 'chat'}).c('body').t(message_input).tree());
1098                       
1099                        var message =
1100                        {
1101                                        contact : "<font style='font-weight:bold; color:red;'>" + "Eu" + "</font>",
1102                                        msg : message_input
1103                        }
1104                       
1105                        // Add Message in chatBox;
1106                        TrophyIM.addMessage( message, jidTo);
1107                                document.getElementById(jidTo + "__sendBox").value = "";
1108                                document.getElementById(jidTo + "__sendBox").focus();
1109                }
1110        }
1111       
1112       
1113        /*
1114         * Codigo original comentado
1115         *
1116        var message_input = getElementsByClassName('trophyimchatinput', null, chat_box.parentNode)[0];
1117        var active_jid = TrophyIM.activeChats['current'];
1118       
1119        if(TrophyIM.activeChats['current'])
1120        {
1121            var active_chat =
1122            TrophyIM.activeChats['divs'][TrophyIM.activeChats['current']];
1123            var to = TrophyIM.activeChats['current'];
1124            if (active_chat['resource'])
1125            {
1126                to += "/" + active_chat['resource'];
1127            }
1128            TrophyIM.connection.send($msg({to: to, from: TrophyIM.connection.jid, type: 'chat'}).c('body').t(message_input.value).tree());
1129           
1130            TrophyIM.addMessage("Me:\n" + message_input.value,
1131            TrophyIM.activeChats['current']);
1132        }
1133       
1134        message_input.value = '';
1135        message_input.focus();
1136        */
1137    }
1138};
1139
1140/** Class: TrophyIMRoster
1141 *
1142 *
1143 *  This object stores the roster and presence info for the TrophyIMClient
1144 *
1145 *  roster[jid_lower]['contact']
1146 *  roster[jid_lower]['presence'][resource]
1147 */
1148function TrophyIMRoster() {
1149    /** Constants: internal arrays
1150     *    (Object) roster - the actual roster/presence information
1151     *    (Object) groups - list of current groups in the roster
1152     *    (Array) changes - array of jids with presence changes
1153     */
1154    if (TrophyIM.JSONStore.store_working) {
1155        var data = TrophyIM.JSONStore.getData(['roster', 'groups']);
1156        this.roster = (data['roster'] != null) ? data['roster'] : {};
1157        this.groups = (data['groups'] != null) ? data['groups'] : {};
1158    } else {
1159        this.roster = {};
1160        this.groups = {};
1161    }
1162    this.changes = new Array();
1163    if (TrophyIM.constants.stale_roster) {
1164        for (var jid in this.roster) {
1165            this.changes[this.changes.length] = jid;
1166        }
1167    }
1168    /** Function: addContact
1169     *
1170     *  Adds given contact to roster
1171     *
1172     *  Parameters:
1173     *    (String) jid - bare jid
1174     *    (String) subscription - subscription attribute for contact
1175     *    (String) name - name attribute for contact
1176     *    (Array) groups - array of groups contact is member of
1177     */
1178    this.addContact = function(jid, subscription, name, groups) {
1179        var contact = {jid:jid, subscription:subscription, name:name, groups:groups}
1180        var jid_lower = jid.toLowerCase();
1181        if (this.roster[jid_lower]) {
1182            this.roster[jid_lower]['contact'] = contact;
1183        } else {
1184            this.roster[jid_lower] = {contact:contact};
1185        }
1186        groups = groups ? groups : [''];
1187        for (var g = 0; g < groups.length; g++) {
1188            if (!this.groups[groups[g]]) {
1189                this.groups[groups[g]] = {};
1190            }
1191            this.groups[groups[g]][jid_lower] = jid_lower;
1192        }
1193    }
1194    /** Function: getContact
1195     *
1196     *  Returns contact entry for given jid
1197     *
1198     *  Parameter: (String) jid - jid to return
1199     */
1200    this.getContact = function(jid) {
1201        if (this.roster[jid.toLowerCase()]) {
1202            return this.roster[jid.toLowerCase()]['contact'];
1203        }
1204    }
1205    /** Function: setPresence
1206     *
1207     *  Sets presence
1208     *
1209     *  Parameters:
1210     *    (String) fulljid: full jid with presence
1211     *    (Integer) priority: priority attribute from presence
1212     *    (String) show: show attribute from presence
1213     *    (String) status: status attribute from presence
1214     */
1215    this.setPresence = function(fulljid, priority, show, status)
1216        {
1217                var barejid = Strophe.getBareJidFromJid(fulljid);
1218        var resource = Strophe.getResourceFromJid(fulljid);
1219        var jid_lower = barejid.toLowerCase();
1220       
1221                if( show != 'unavailable')
1222                {
1223            if (!this.roster[jid_lower])
1224                        {
1225                this.addContact(barejid, 'not-in-roster');
1226            }
1227            var presence =
1228                        {
1229                resource:resource, priority:priority, show:show, status:status
1230            }
1231           
1232                        if (!this.roster[jid_lower]['presence'])
1233                        {
1234                this.roster[jid_lower]['presence'] = {}
1235            }
1236            this.roster[jid_lower]['presence'][resource] = presence
1237        }
1238                else if (this.roster[jid_lower] && this.roster[jid_lower]['presence'] && this.roster[jid_lower]['presence'][resource])
1239                {
1240            delete this.roster[jid_lower]['presence'][resource];
1241        }
1242       
1243                this.addChange(jid_lower);
1244       
1245                if (TrophyIM.activeChats['divs'][jid_lower])
1246                {
1247            TrophyIM.setTabPresence(jid_lower, TrophyIM.activeChats['divs'][jid_lower]['tab']);
1248        }
1249    }
1250    /** Function: addChange
1251     *
1252     *  Adds given jid to this.changes, keeping this.changes sorted and
1253     *  preventing duplicates.
1254     *
1255     *  Parameters
1256     *    (String) jid : jid to add to this.changes
1257     */
1258    this.addChange = function(jid) {
1259        for (var c = 0; c < this.changes.length; c++) {
1260            if (this.changes[c] == jid) {
1261                return;
1262            }
1263        }
1264        this.changes[this.changes.length] = jid;
1265        this.changes.sort();
1266    }
1267    /** Function: getPresence
1268     *
1269     *  Returns best presence for given jid as Array(resource, priority, show,
1270     *  status)
1271     *
1272     *  Parameter: (String) fulljid - jid to return best presence for
1273     */
1274    this.getPresence = function(fulljid) {
1275        var jid = Strophe.getBareJidFromJid(fulljid);
1276        var current = null;
1277        if (this.roster[jid.toLowerCase()] &&
1278        this.roster[jid.toLowerCase()]['presence']) {
1279            for (var resource in this.roster[jid.toLowerCase()]['presence']) {
1280                var presence = this.roster[jid.toLowerCase()]['presence'][resource];
1281                if (current == null) {
1282                    current = presence
1283                } else {
1284                    if(presence['priority'] > current['priority'] && ((presence['show'] == "chat"
1285                    || presence['show'] == "available") || (current['show'] != "chat" ||
1286                    current['show'] != "available"))) {
1287                        current = presence
1288                    }
1289                }
1290            }
1291        }
1292        return current;
1293    }
1294    /** Function: groupHasChanges
1295     *
1296     *  Returns true if current group has members in this.changes
1297     *
1298     *  Parameters:
1299     *    (String) group - name of group to check
1300     */
1301    this.groupHasChanges = function(group) {
1302        for (var c = 0; c < this.changes.length; c++) {
1303            if (this.groups[group][this.changes[c]]) {
1304                return true;
1305            }
1306        }
1307        return false;
1308    }
1309    /** Fuction: save
1310     *
1311     *  Saves roster data to JSON store
1312     */
1313    this.save = function() {
1314        if (TrophyIM.JSONStore.store_working) {
1315            TrophyIM.JSONStore.setData({roster:this.roster,
1316            groups:this.groups, active_chat:TrophyIM.activeChats['current'],
1317            chat_history:TrophyIM.chatHistory});
1318        }
1319    }
1320}
1321/** Class: TrophyIMJSONStore
1322 *
1323 *
1324 *  This object is the mechanism by which TrophyIM stores and retrieves its
1325 *  variables from the url provided by TROPHYIM_JSON_STORE
1326 *
1327 */
1328function TrophyIMJSONStore() {
1329    this.store_working = false;
1330    /** Function _newXHR
1331     *
1332     *  Set up new cross-browser xmlhttprequest object
1333     *
1334     *  Parameters:
1335     *    (function) handler = what to set onreadystatechange to
1336     */
1337     this._newXHR = function (handler) {
1338        var xhr = null;
1339        if (window.XMLHttpRequest) {
1340            xhr = new XMLHttpRequest();
1341            if (xhr.overrideMimeType) {
1342            xhr.overrideMimeType("text/xml");
1343            }
1344        } else if (window.ActiveXObject) {
1345            xhr = new ActiveXObject("Microsoft.XMLHTTP");
1346        }
1347        return xhr;
1348    }
1349    /** Function getData
1350     *  Gets data from JSONStore
1351     *
1352     *  Parameters:
1353     *    (Array) vars = Variables to get from JSON store
1354     *
1355     *  Returns:
1356     *    Object with variables indexed by names given in parameter 'vars'
1357     */
1358    this.getData = function(vars) {
1359        if (typeof(TROPHYIM_JSON_STORE) != undefined) {
1360            Strophe.debug("Retrieving JSONStore data");
1361            var xhr = this._newXHR();
1362            var getdata = "get=" + vars.join(",");
1363            try {
1364                xhr.open("POST", TROPHYIM_JSON_STORE, false);
1365            } catch (e) {
1366                Strophe.error("JSONStore open failed.");
1367                return false;
1368            }
1369            xhr.setRequestHeader('Content-type',
1370            'application/x-www-form-urlencoded');
1371            xhr.setRequestHeader('Content-length', getdata.length);
1372            xhr.send(getdata);
1373            if (xhr.readyState == 4 && xhr.status == 200) {
1374                try {
1375                    var dataObj = JSON.parse(xhr.responseText);
1376                    return this.emptyFix(dataObj);
1377                } catch(e) {
1378                    Strophe.error("Could not parse JSONStore response" +
1379                    xhr.responseText);
1380                    return false;
1381                }
1382            } else {
1383                Strophe.error("JSONStore open failed. Status: " + xhr.status);
1384                return false;
1385            }
1386        }
1387    }
1388    /** Function emptyFix
1389     *    Fix for bugs in external JSON implementations such as
1390     *    http://bugs.php.net/bug.php?id=41504.
1391     *    A.K.A. Don't use PHP, people.
1392     */
1393    this.emptyFix = function(obj) {
1394        if (typeof(obj) == "object") {
1395            for (var i in obj) {
1396                if (i == '_empty_') {
1397                    obj[""] = this.emptyFix(obj['_empty_']);
1398                    delete obj['_empty_'];
1399                } else {
1400                    obj[i] = this.emptyFix(obj[i]);
1401                }
1402            }
1403        }
1404        return obj
1405    }
1406    /** Function delData
1407     *    Deletes data from JSONStore
1408     *
1409     *  Parameters:
1410     *    (Array) vars  = Variables to delete from JSON store
1411     *
1412     *  Returns:
1413     *    Status of delete attempt.
1414     */
1415    this.delData = function(vars) {
1416        if (typeof(TROPHYIM_JSON_STORE) != undefined) {
1417            Strophe.debug("Retrieving JSONStore data");
1418            var xhr = this._newXHR();
1419            var deldata = "del=" + vars.join(",");
1420            try {
1421                xhr.open("POST", TROPHYIM_JSON_STORE, false);
1422            } catch (e) {
1423                Strophe.error("JSONStore open failed.");
1424                return false;
1425            }
1426            xhr.setRequestHeader('Content-type',
1427            'application/x-www-form-urlencoded');
1428            xhr.setRequestHeader('Content-length', deldata.length);
1429            xhr.send(deldata);
1430            if (xhr.readyState == 4 && xhr.status == 200) {
1431                try {
1432                    var dataObj = JSON.parse(xhr.responseText);
1433                    return dataObj;
1434                } catch(e) {
1435                    Strophe.error("Could not parse JSONStore response");
1436                    return false;
1437                }
1438            } else {
1439                Strophe.error("JSONStore open failed. Status: " + xhr.status);
1440                return false;
1441            }
1442        }
1443    }
1444    /** Function setData
1445     *    Stores data in JSONStore, overwriting values if they exist
1446     *
1447     *  Parameters:
1448     *    (Object) vars : Object containing named vars to store ({name: value,
1449     *    othername: othervalue})
1450     *
1451     *  Returns:
1452     *    Status of storage attempt
1453     */
1454    this.setData = function(vars) {
1455        if (typeof(TROPHYIM_JSON_STORE) != undefined) {
1456            Strophe.debug("Storing JSONStore data");
1457            var senddata = "set=" + JSON.stringify(vars);
1458            var xhr = this._newXHR();
1459            try {
1460                xhr.open("POST", TROPHYIM_JSON_STORE, false);
1461            } catch (e) {
1462                Strophe.error("JSONStore open failed.");
1463                return false;
1464            }
1465            xhr.setRequestHeader('Content-type',
1466            'application/x-www-form-urlencoded');
1467            xhr.setRequestHeader('Content-length', senddata.length);
1468            xhr.send(senddata);
1469            if (xhr.readyState == 4 && xhr.status == 200 && xhr.responseText ==
1470            "OK") {
1471                return true;
1472            } else {
1473                Strophe.error("JSONStore open failed. Status: " + xhr.status);
1474                return false;
1475            }
1476        }
1477    }
1478    var testData = true;
1479    if (this.setData({testData:testData})) {
1480        var testResult = this.getData(['testData']);
1481        if (testResult && testResult['testData'] == true) {
1482            this.store_working = true;
1483        }
1484    }
1485}
1486/** Constants: Node types
1487 *
1488 * Implementations of constants that IE doesn't have, but we need.
1489 */
1490if (document.ELEMENT_NODE == null) {
1491    document.ELEMENT_NODE = 1;
1492    document.ATTRIBUTE_NODE = 2;
1493    document.TEXT_NODE = 3;
1494    document.CDATA_SECTION_NODE = 4;
1495    document.ENTITY_REFERENCE_NODE = 5;
1496    document.ENTITY_NODE = 6;
1497    document.PROCESSING_INSTRUCTION_NODE = 7;
1498    document.COMMENT_NODE = 8;
1499    document.DOCUMENT_NODE = 9;
1500    document.DOCUMENT_TYPE_NODE = 10;
1501    document.DOCUMENT_FRAGMENT_NODE = 11;
1502    document.NOTATION_NODE = 12;
1503}
1504
1505/** Function: importNode
1506 *
1507 *  document.importNode implementation for IE, which doesn't have importNode
1508 *
1509 *  Parameters:
1510 *    (Object) node - dom object
1511 *    (Boolean) allChildren - import node's children too
1512 */
1513if (!document.importNode) {
1514    document.importNode = function(node, allChildren) {
1515        switch (node.nodeType) {
1516            case document.ELEMENT_NODE:
1517                var newNode = document.createElement(node.nodeName);
1518                if (node.attributes && node.attributes.length > 0) {
1519                    for(var i = 0; i < node.attributes.length; i++) {
1520                        newNode.setAttribute(node.attributes[i].nodeName,
1521                        node.getAttribute(node.attributes[i].nodeName));
1522                    }
1523                }
1524                if (allChildren && node.childNodes &&
1525                node.childNodes.length > 0) {
1526                    for (var i = 0; i < node.childNodes.length; i++) {
1527                        newNode.appendChild(document.importNode(
1528                        node.childNodes[i], allChildren));
1529                    }
1530                }
1531                return newNode;
1532                break;
1533            case document.TEXT_NODE:
1534            case document.CDATA_SECTION_NODE:
1535            case document.COMMENT_NODE:
1536                return document.createTextNode(node.nodeValue);
1537                break;
1538        }
1539    };
1540}
1541
1542/** Function: getElementsByClassName
1543 *
1544 *  DOMObject.getElementsByClassName implementation for browsers that don't
1545 *  support it yet.
1546 *
1547 *  Developed by Robert Nyman, http://www.robertnyman.com
1548 *  Code/licensing: http://code.google.com/p/getelementsbyclassname/
1549*/
1550var getElementsByClassName = function (className, tag, elm){
1551    if (document.getElementsByClassName) {
1552        getElementsByClassName = function (className, tag, elm) {
1553            elm = elm || document;
1554            var elements = elm.getElementsByClassName(className),
1555                nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
1556                returnElements = [],
1557                current;
1558            for(var i=0, il=elements.length; i<il; i+=1){
1559                current = elements[i];
1560                if(!nodeName || nodeName.test(current.nodeName)) {
1561                    returnElements.push(current);
1562                }
1563            }
1564            return returnElements;
1565        };
1566    } else if (document.evaluate) {
1567        getElementsByClassName = function (className, tag, elm) {
1568            tag = tag || "*";
1569            elm = elm || document;
1570            var classes = className.split(" "),
1571                classesToCheck = "",
1572                xhtmlNamespace = "http://www.w3.org/1999/xhtml",
1573                namespaceResolver = (document.documentElement.namespaceURI ===
1574                    xhtmlNamespace)? xhtmlNamespace : null,
1575                returnElements = [],
1576                elements,
1577                node;
1578            for(var j=0, jl=classes.length; j<jl; j+=1){
1579                classesToCheck += "[contains(concat(' ', @class, ' '), ' " +
1580                    classes[j] + " ')]";
1581            }
1582            try {
1583                elements = document.evaluate(".//" + tag + classesToCheck,
1584                    elm, namespaceResolver, 0, null);
1585            } catch (e) {
1586                elements = document.evaluate(".//" + tag + classesToCheck,
1587                    elm, null, 0, null);
1588            }
1589            while ((node = elements.iterateNext())) {
1590                returnElements.push(node);
1591            }
1592            return returnElements;
1593        };
1594    } else {
1595        getElementsByClassName = function (className, tag, elm) {
1596            tag = tag || "*";
1597            elm = elm || document;
1598            var classes = className.split(" "),
1599                classesToCheck = [],
1600                elements = (tag === "*" && elm.all)? elm.all :
1601                     elm.getElementsByTagName(tag),
1602                current,
1603                returnElements = [],
1604                match;
1605            for(var k=0, kl=classes.length; k<kl; k+=1){
1606                classesToCheck.push(new RegExp("(^|\\s)" + classes[k] +
1607                    "(\\s|$)"));
1608            }
1609            for(var l=0, ll=elements.length; l<ll; l+=1){
1610                current = elements[l];
1611                match = false;
1612                for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
1613                    match = classesToCheck[m].test(current.className);
1614                    if (!match) {
1615                        break;
1616                    }
1617                }
1618                if (match) {
1619                    returnElements.push(current);
1620                }
1621            }
1622            return returnElements;
1623        };
1624    }
1625    return getElementsByClassName(className, tag, elm);
1626};
1627
1628/**
1629 *
1630 * Bootstrap self into window.onload and window.onunload
1631 */
1632var oldonload = window.onload;
1633window.onload = function() {
1634    if(oldonload) {
1635        oldonload();
1636    }
1637    TrophyIM.load();
1638};
1639var oldonunload = window.onunload;
1640window.onunload = function() {
1641    if(oldonunload) {
1642        oldonunload();
1643    }
1644    TrophyIM.storeData();
1645}
Note: See TracBrowser for help on using the repository browser.