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

Revision 2390, 42.8 KB checked in by alexandrecorreia, 14 years ago (diff)

Ticket #986 - Lista de contatos refeita e mudanças nos carregamentos dos layouts(xsl).

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