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

Revision 2293, 59.0 KB checked in by alexandrecorreia, 14 years ago (diff)

Ticket #986 - Implementado recebimento das mensagens dentro das janelas.

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