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

Revision 2345, 42.9 KB checked in by alexandrecorreia, 14 years ago (diff)

Ticket #986 - Implementado function para adição de contatos e caixa de menu.

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