/* Copyright (C) 2006 Nicolas Trani & Anthony Catel This file is part of ACE Client. ACE is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. ACE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with ACE ; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ var Ace = new Class({ /*** * Initialise ACE (sérieux oO?) * @param server Adresse rediriger vers le serveur ace a l'aide de mod_proxy (du serveur apache) vers le serveur ace * @param [container] Si ce paramètre est rempli ace sera injecté dans l'id de l'élement passer en paramètre (sinon ACE sera injecter dans la corps du document) * @param [chan] Si ce paramètre est donner les utilisateur rejoindront automatiquement un channel * @param [login] Si ce paramètre est donner ainsi que le chan l'utilisateur sera directement logué avec le nom d'utilisateur passer en paramètre */ initialize: function(server,container,chan,login){ /*** * Configuration de ace */ this.config = { 'server':server || '', //Le serveur est l'url rediriger a l'aide de mod_proxy (du serveur apache) vers le server ACE 'pool_time':23127, 'container':container || '', //id de l'élément ou inclure ace 'max_log_msg':2, //Nombre maxium de message a stocké dans un cookie (laisser tel quelle il vaut mieux :p) 'ace_rep':'./ace', 'smy_rep':'smiley' } /*** * Paramètre de session */ this.param = { 'sesid':'', 'login':login || '', 'chan':chan || '', //forcer a joindre un chan ou laisser le choix a l'utilisateur 'current_buffer':'undefined', 'buffers':new Hash() } /*** * Variable global a la class */ this.smy_array = new Array(':\\)','prizee','pd','xx',':o',':\\]',':p',':D',' mm',':\\(',';\\)','yacado','kadokado',':\\$','zzz',':x','merde',' pute','gueule','enculé',' nique','connard','salope','speed','gear',':mdr:',':lol:',':timide:',':bye:',':zelda:',':mario:',':sonic:',':coeur:',':alien:',':rire:',':muscle:','bienvenue',':biz:',':bravo:','!!!',':help:',':marteau:',':mur:'); this.smy_url = new Array('1.gif','21.gif','21.gif','18.gif','13.gif','20.gif','7.gif','5.gif','8.gif','10.gif','2.gif','21.gif','21.gif','3.gif','15.gif','16.gif','21.gif','21.gif','21.gif','21.gif','21.gif','21.gif','21.gif','21.gif','21.gif','22.gif','23.gif','11.gif','24.gif','25.gif','26.gif','27.gif','28.gif','29.gif','30.gif','31.gif','32.gif','33.gif','34.gif','35.gif','36.gif','37.gif','38.gif'); this.smy_array_old = new Array(':\\[',':\\)',';\\)',':\\$',':\\|',':D',':\\(',':p','MM'); //tableau des smiley this.current_request; this.timer; this.last_action_ut; this.template();//Création de l'interface de ace if(Cookie.get('Ace_param_0')){ this.restore_session();//Restauration de la session précédente }else{ //Auto login de l'utilisateur if(chan && login){ this.connect(login,chan); } } /*** * Affectation des action aux formulaires */ $('ace_form_login').onsubmit = this.connect.bind(this); $('ace_form_send_message').onsubmit = this.send_message.bind(this); $('ace_form_send_message').addEvent('keypress',function(ev){ //Nécésaire pour IE qui refuse d'envoyé le message si le bouton envoyer est masquer key = ev.keyCode || ev.which; if(key==13){ $('send_button_'+this.param.current_buffer || this.param.chan).click(); $('send_button_'+this.param.current_buffer || this.param.chan).click(); this.send_message.bind(this); } }.bind(this)); window.onunload = this.save_session.bind(this); }, output_debug: function(msg){ /* if(!this.ace_debug_window){ this.ace_debug_window = window.open( 'debug.html', 'ace_debug', 'width=500,height=550,status,scrollbars,resizable,screenX=0,screenY=20,left=20,top=40'); } this.ace_debug_window.document.write(msg); */ }, /*** * Retourne l'unixtime courant * @return int L'unixtime */ get_unixtime: function(){ var d = new Date; return d.getTime(); }, pooler: function(){ if(this.get_unixtime()-this.last_action_ut>=this.config.pool_time){ this.check(); } }, /*** * Parse un message et met les smiley * @param msg Le message a parser */ parse_smiley: function(msg){ var i=0 while(i'); i++; } return msg; }, /*** * Parse un message (je sort =>[]) * @param string msg * @param Object el element ou injecter le message (l'ancien contenu serra supprimer) */ parse_message: function(msg,el){ msg = unescape(msg); msg = msg.replace(//g, ">") ; msg = msg.replace(/\n/g, "
") ; msg = this.parse_smiley(msg); el.setHTML(msg); }, /*** * Effectue une requète ajax de type GET * une fois que le résultat de la requète est recu la méthode parse_raw est appelé * @param string query la requète sur le serveur ace a éffectuer */ request: function(query){ last_req = this.current_request; (function(){if(last_req && last_req.transport.readyState!=4) last_req.transport.abort()}.bind(this)).delay(1000);//On tue la dernière requète pour évité que le client bloque parfois (trop de requète en même temps sur le même site return this.current_request = new Ajax(this.config.server+'/?'+query+'&'+this.get_unixtime(), {method: 'get',onComplete:function(rep){this.parse_raw(rep)}.bind(this)}).request(); }, /*** * Parse les commandes renvoyé par ace et excuce la fonction relative a la commande * @param string raws un ou plusieurs raws a parser (les raws sont séparé par des \n) */ parse_raw: function(raws){ raws = raws.replace(/\n$/,'');//on enlève le retour chariot de fin if(raws=='CLOSE'){ if(this.current_request.transport.readyState==4 && raws.error!='004' && raws.raw!='QUIT'){ this.check(); } if(raws.error!='004'){ this.last_action_ut = this.get_unixtime(); } return; }else{ raws = Json.evaluate(raws); raws.each(function(raw){ switch(raw.raw){ case 'ERR': this.err(raw); break; case 'LOGIN': this.login(raw); break; case 'JOIN' : this.join(raw); break; case 'USER' : this.user(raw); break; case 'PRIVMSG' : this.privmsg(raw); break; case 'CHANMSG' : this.chanmsg(raw); break; case 'LEFT' : this.left(raw); break; case 'SETLVL':this.setlvl(raw); break; case 'TOPIC':this.topic(raw); break; case 'SETTOPIC':this.settopic(raw); break; } //La dernière requète de check est terminé il faut en relancer une if(this.current_request.transport.readyState==4 && raw.error!='004' && raw.raw!='QUIT'){ this.check(); } if(raw.error!='004'){ this.last_action_ut = this.get_unixtime(); } }.bind(this)); } }, /*** * Créer les différents élement de ACE si certain d'entre eux n'existe pas */ template: function(){ if(!$('ace_form_send_message')) new Element('form').setProperty('id','ace_form_send_message').setStyle('display','none').injectInside(this.config.container || document.body); if(!$('tab_box_container')) new Element('div').setProperty('id','tab_box_container').injectInside('ace_form_send_message'); if(!$('message_box_container')) new Element('div').setProperty('id','message_box_container').injectInside('ace_form_send_message'); if(!$('toolbox_container')) new Element('div').setProperty('id','toolbox_container').injectInside('message_box_container'); this.toolbox();//Création de la boite d'action if(!$('topic_container')) new Element('div').setProperty('id','topic_container').injectInside('message_box_container'); if(!$('send_box_container')) new Element('div').setProperty('id','send_box_container').injectAfter('message_box_container'); if(!$('users_list_container')) new Element('div').setProperty('id','users_list_container').injectInside('ace_form_send_message'); if(!$('context_menu')) new Element('div').setProperty('id','context_menu').injectInside(document.body); this.context_menu();//Création du menu contextuel }, /* Méthodes relative au raw de réception */ /*** * Gestion des erreurs * Un raw de type ERR resemble a cela : * ERR 0 2 003 * |-> le numéro d'érreur * @param raw Array un tableau contenant dans chaque element un paramètre du raw */ err: function(raw){ if(raw.error=='004'){ this.clear_session(); window.location.reload() }else if(raw.error == '002'){ this.inform('Mauvaise commenade raw'); }else if(raw.error =='003'){ this.inform('Ce pseudo est déja utilise'); this.clear_session(); }else if(raw.error =='005'){ this.inform('Votre pseudo doit seulement comporter des lettres et des chiffres'); this.clear_session(); }else if(raw.error =='SETTOPIC_ERROR'){ this.inform('Vous n\'avez pas l\'autorisation de modifier le topic'); }else if(raw.error =='006'){ this.inform('Vous avez etez banni de ACE'); this.clear_session(); }else{ this.inform(raw.error); } }, /*** * Gestion de la connection * Un raw de type LOGIN ressemble a cela : * LOGIN 1167848669 0 d2f307c3204122f5c98a766d2392ab97 * |-> identificateur de session de l'utilisateur (sesid) * @param raw Array un tableau contenant dans chaque element un paramètre du raw */ login: function(raw){ this.param.sesid = raw.sessid; this.create_buffer(this.param.chan,'chan'); this.check(); this.timer = this.pooler.periodical(1000,this); Cookie.set('Ace_running', this.get_unixtime(), {duration: false}); var message_box = $('message_box_chan_'+this.param.chan); var div_message = new Element('div').setProperty('class','histo'); this.parse_message("\nboaki > slt @moniczkar83\nboaki > sa va\nboaki > halo\nboaki > il y a quelqu'un\nboaki > halo!!!!!!!!!!!!!!!!!!!!!!!!\nboaki > slt\nboaki > momydo\nboaki > sa va\njpcat > slt a tous\nmyline > bonsoir tout le monde\n",div_message); div_message.injectInside(message_box); // this.write_to_buffer(this.param.chan,"\nboaki > slt%20@moniczkar83\nboaki > sa%20va\nboaki > halo\nboaki > il%20y%20a%20quelqu%27un\nboaki > halo%21%21%21%21%21%21%21%21%21%21%21%21%21%21%21%21%21%21%21%21%21%21%21%21\nboaki > slt\nboaki > momydo\nboaki > sa%20va\njpcat > slt%20a%20tous\nmyline > bonsoir%20tout%20le%20monde\n",{style: 'histo'}); }, /*** * Fonction exécuter lorsque un user join un channel * Un raw de type JOIN ressemble a cela : * JOIN 1167848669 0 test efyx2 * | |-> Pseudo de la personne qui rejoint le channel * |-> Channel * @param raw Array un tableau contenant dans chaque element un paramètre du raw */ join: function(raw){ this.write_to_buffer('chan_'+raw.channel,raw.user+' a rejoint '+raw.channel,{'style':'notice join','user':'*'}); this.add_user(raw.user,'chan_'+raw.channel); }, /*** * Fonction exécuter lorsque l'user rejoint un channel. Ce raw * Un raw de type user ressemble a cela * USER 1167848669 0 test efyx2 1 * | | |-> Niveau de l'utilisateur (voir la documentation pour plus d'informations) * | |-> Pseudo de l'utilisateur * |-> Channel sur lequel est l'utilisateur * @param raw Array un tableau contenant dans chaque element un paramètre du raw */ user: function(raw){ this.add_user(raw.user,'chan_'+raw.channel,raw.level); }, /*** * Réception d'un message priver * { * "time": "1177442902", * "type": "1", * "raw": "PRIVMSG", * "msg": "Salut!", Le message * "sender": "efyx" Le pseudo de l'utilisateur qui envoie le message * } * @param raw Array un tableau contenant dans chaque element un paramètre du raw */ privmsg: function(raw){ this.write_to_buffer(raw.sender,raw.msg); }, /*** * Un utilisateur quitte le channel * @param raw Array un tableau contenant dans chaque element un paramètre du raw */ left: function(raw){ this.write_to_buffer('chan_'+raw.channel,raw.user+' est parti de '+raw.channel,{'style':'notice left','user':'*'}); this.remove_user(raw.user,'chan_'+raw.channel); }, /*** * Reception d'un message sur un channel * { * "time": "1177442770", * "type": "1", * "raw": "CHANMSG", * "msg": "AceRoXl33tKikO0LolMDR", Message envoyé * "sender": "Para", Pseudo de l'envoyeur du message * "channel": "Ace" Channel ou le message est envoyé * } * @param raw Array un tableau contenant dans chaque element un paramètre du raw */ chanmsg: function(raw){ this.write_to_buffer('chan_'+raw.channel,raw.msg,{'user':raw.sender}); }, /*** * Changement du niveau d'un utilisateur * { * "time": "1177442630", * "type": "1", * "raw": "SETLVL", * "channel": "Ace", Channel ou le changement de niveau a lieux * "opeur": "efyx", Pseudo de l'opeur (la personne qui donne le niveau) * "ope": "Para", Pseudo de l'ope (la personne qui recoit le niveau) * "level": "3" Nouveau niveau de l'ope * } * @param raw Array un tableau contenant dans chaque element un paramètre du raw */ setlvl: function(raw){ this.write_to_buffer('chan_'+raw.channel,raw.opeur+' donne le niveau '+raw.level+' a '+raw.ope,{'style':'notice level','user':'*'}); this.level_user(raw.ope,'chan_'+raw.channel,raw.level); }, /*** * Affichage du topic * { * "time": "1177442498", * "type": "0", * "raw": "TOPIC", * "channel": "Ace", Channel ou est le topic * "topic": "Chat%20powered%20by%20AJAX%20Chat%20Engine" Le topic * } * @param raw Array un tableau contenant dans chaque element un paramètre du raw */ topic: function(raw){ this.update_topic('chan_'+raw.channel,raw.topic); this.write_to_buffer('chan_'+raw.channel,'Le topic de '+raw.channel+' est '+raw.topic,{'user':'*','style':'notice topic'}); }, /*** * Changement du topic * * @param raw Array un tableau contenant dans chaque element un paramètre du raw */ settopic: function(raw){ this.update_topic('chan_'+raw.channel,raw.topic); this.write_to_buffer('chan_'+raw.channel,raw.user+' change le topic en : '+raw.topic,{'style':'notice topic','user':'*'}); }, /* Méthode relative a l'envoie de raw */ /*** * Se connect ace si login et chan ne sont pas fourni en paramètre ce sera la valeurs des champs ace_login et ace_chan * @param string [login] * @param string [chan] * @return boolean false */ connect: function(login,chan){ if(!Cookie.get('Ace_running')){ if($type(login)!='object'){//Si le login est passé dans l'instanciation de ace this.param.login = login; }else{ this.param.login = (this.param.login || $('ace_login').value).toLowerCase(); } this.param.chan = chan || this.param.chan || $('ace_chan').value; if(this.param.login && this.param.chan) this.request('CONNECT&'+this.param.login+'&'+this.param.chan); else this.inform('remplisez les champs'); } return false; }, /*** * Met a jour le text du topic * @param string chan le nom du channel * @param string topic le nouveau topic */ update_topic: function(chan,topic){ var topic_el = $('topic_'+chan); if(!topic_el){ topic_input = new Element('input').setProperties({'type':'text','class':'topic_input','id':'topic_input_'+chan}).injectInside('topic_container'); topic_el = new Element('div').setProperties({'class':'topic','id':'topic_'+chan}).injectInside('topic_container'); topic_input.addEvent('blur',function(){ this.request('SETTOPIC&'+this.param.sesid+'&'+chan.substr(5,chan.length)+'&'+escape(topic_input.value)); this.show_hide('topic_input_'+chan); this.show_hide('topic_'+chan,1);}.bind(this) ); topic_el.addEvent('click',function(){ this.show_hide('topic_'+chan); this.show_hide('topic_input_'+chan,1);}.bind(this) ); } $('topic_input_'+chan).value = unescape(topic); this.parse_message('Topic : '+topic,topic_el); this.param.buffers.get(chan).topic = topic; }, /*** * Vérifie si il y des nouveaux messages en attente * @return Object L'objet retourné est l'objet ajax */ check: function(){ if(this.param.sesid){ return this.request('CHECK&'+this.param.sesid); } }, /*** * Envoie un message de QUIT a ACE et supprime les cookies de sessions */ quit: function(){ this.request('QUIT&'+this.param.sesid); $clear(this.timer); this.close_all_buffer(); this.clear_session(); }, /* Méthodes pour la gestion des buffers */ /*** * Créer un buffer si le type est chan une liste d'utilisateur vide sera ajouter * @param string buffer_name * @param string type * @return object message_box */ create_buffer: function(buffer_name,type){ //On vérifie que aucun buffer portant le même nom existe déja pour éviter les conflits if(!$('tab_box_'+buffer_name)){ //affichage du conteneur de ace if(this.config.container) this.show_hide(this.config.container,1); var buffer_name_id = buffer_name; if(type=='chan'){ buffer_name_id = 'chan_'+buffer_name;//Il faut différencié les chan par leur identifiant pour permettre a un user d'avoir le même nom que un channel } this.param.buffers.set(buffer_name_id,{'logs':new Array(),'name':buffer_name,'type':type});//Ajout du buffer au tableau des buffers (oui je sais -_-) if(type=='chan'){//Si c'est un chan on ajoute la liste d'utilisateur this.create_users_list(buffer_name_id); } //Création de la boite de message send_box = new Element('input').setProperties({'type':'text','class':'send_box','id':'send_box_'+buffer_name_id}).injectInside('send_box_container'); message_box = new Element('div').setProperties({'class':'message_box','id':'message_box_'+buffer_name_id}).injectInside('message_box_container'); send_button = new Element('input').setProperties({'type':'submit','class':'send_button','id':'send_button_'+buffer_name_id,'value':'Envoyer'}).injectInside('send_box_container'); //Création de l'onglet tab_box = new Element('div').addClass('tab_box').addClass('active').addClass(type).setProperty('id','tab_box_'+buffer_name_id).injectInside('tab_box_container'); new Element('a').setProperty('href','javascript:void(0)').appendText(buffer_name).addEvent('click',function(){this.switch_buffer(''+buffer_name_id+'');}.bind(this)).injectInside('tab_box_'+buffer_name_id); //si il y a déja au moins un buffer d'ouvert on switch sur le nouveau if(this.param.current_buffer!='undefined'){ this.switch_buffer(buffer_name_id); }else{//Sinon on affiche les différentes partie du layout de ace this.show_hide('ace_form_send_message',1); this.show_hide('tab_box_container',1); this.show_hide('message_box_container',1); this.show_hide('send_box_container',1); this.show_hide('toolbox_container',1); this.show_hide('topic_container',1); this.param.current_buffer = buffer_name_id; } }else{ this.switch_buffer(buffer_name); } return message_box; }, /*** * Créer une liste d'utilisateur vide * @param string buffer_name */ create_users_list: function(buffer_name){ new Element('div').setProperties({'id':'users_list_'+buffer_name+'','class':'users_list'}).injectInside('users_list_container'); Object.extend(this.param.buffers.get(buffer_name),{user_list:new Hash()}); }, /*** * Permet de passer d'un buffer a un autre (cache le courant et affiche ceului passer en paramètre) * @param string buffer_name */ switch_buffer: function(buffer_name){ current_buffer = this.param.current_buffer; if(current_buffer && this.param.current_buffer!=buffer_name){ this.show_hide('send_box_'+current_buffer,0); this.show_hide('message_box_'+current_buffer,0); this.show_hide('send_button_'+current_buffer,0); $('tab_box_'+current_buffer).removeClass('active'); $('tab_box_'+current_buffer).addClass('inactive'); //si c'est un chan on cache la liste d'user et le topic if(this.param.buffers.get(current_buffer).type=='chan'){ this.show_hide('users_list_'+current_buffer,0); this.show_hide('topic_container',0); this.show_hide('topic_'+current_buffer,0); } this.show_hide('send_box_'+buffer_name,1); this.show_hide('message_box_'+buffer_name,1); this.show_hide('send_button_'+buffer_name,1); $('tab_box_'+buffer_name).removeClass('inactive'); $('tab_box_'+buffer_name).addClass('active'); this.remove_message_waiting('tab_box_'+buffer_name); $('send_box_'+buffer_name).focus(); //si c'est un chan on affiche la liste d'user if(this.param.buffers.get(buffer_name).type=='chan'){ this.show_hide('users_list_'+buffer_name,1); this.show_hide('topic_container',1); this.show_hide('topic_'+buffer_name,1); } this.param.current_buffer = buffer_name; } }, /*** * Ferme le buffer et envoie si send_left_raw est a 1 un raw LEFT a ace (pour informer que l'on quitte le channel) * @param string buffer_name * @param int send_left_raw */ close_buffer: function(buffer_name,send_left_raw){ buffer_name = buffer_name || this.param.current_buffer; buffer = this.param.buffers.get(buffer_name); if($('tab_box_'+buffer_name)){ //on switch sur le buffer juste a coté ou on cache si c'est le dernier buffer var prev_buffer = $('tab_box_'+buffer_name); if(prev_buffer.previousSibling){ this.switch_buffer(prev_buffer.previousSibling.id.substr(8,prev_buffer.previousSibling.id.length)); }else if(prev_buffer.nextSibling){ this.switch_buffer(prev_buffer.nextSibling.id.substr(8,prev_buffer.nextSibling.id.length)); }else{ this.show_hide('ace_form_send_message'); this.show_hide('topic_container'); this.show_hide('tab_box_container'); this.show_hide('message_box_container'); this.show_hide('send_box_container'); this.param.current_buffer = 'undefined'; } $('send_box_'+buffer_name).remove(); $('message_box_'+buffer_name).remove(); $('send_button_'+buffer_name).remove(); $('tab_box_'+buffer_name).remove(); //Supprésion du buffer this.param.buffers.remove(buffer_name); //si c'est un chan on vire la liste d'user et envoie un message pour informer que l'on quitte le channel if(buffer.type=='chan'){ $('users_list_'+buffer_name).remove(); $('topic_'+buffer_name).remove(); if(!send_left_raw){//TODO : pas encore implémenté avec cette version de ace //~ this.request('LEFT&'+this.param.sesid+'&'+buffer_name.substr(1,buffer_name.length)); this.quit(); } } } }, /*** * Ferme tout les buffer en cours */ close_all_buffer: function(){ this.param.buffers.each(function(buffer){ left_raw=1; if(buffer.type!='chan'){ left_raw = 0; } this.close_buffer(buffer.name); }); }, /*** * Ecriture d'un message sur le buffer * @param string buffer_name * @param string msg * @param object options */ write_to_buffer: function(buffer_name,msg,options){ options = options || {}; var message_box = $('message_box_'+buffer_name); //si le buffer n'existe pas on le créer if(!message_box){ message_box = this.create_buffer(buffer_name,'pv'); } if(options.user && !options.way) way = 'outgoing'; else way = 'incoming'; if(buffer_name!=this.param.current_buffer){ //changement du style de la tab de l'user qui viens d'envoyé le message //pour dire qu'il y a un message en attente if(this.param.current_buffer!=buffer_name){ this.message_waiting('tab_box_'+buffer_name); } } /* /!\ OUTDATED l'historique de la conversation est enregistré dans tableau On stock au maxiumun 10 messages et de longeur max 150 caractères (cela pour éviter d'obtenir un cookie trop gros <=4ko) Chaque message est représetenté par un objet Json */ if(this.param.buffers.get(buffer_name).logs.length>=this.config.max_log_msg){//Si on est a X message on supprime le message le plus vieux this.param.buffers.get(buffer_name).logs.shift(); } //Création d'un objet message contenant le message et les options objMsg = {'msg':escape(unescape(msg))}; Object.extend(objMsg,options); this.param.buffers.get(buffer_name).logs.push(objMsg);//Ajout du message a l'historique sender = options.user || buffer_name; var style = options.style || 'message'; //Création du message var div_message = new Element('div').setProperty('class',way+' '+style); message = new Element('span').setProperty('class','message_content'); //Création du pseudo et d'un "lien" sur le pseudo pour ouvrir un buffer en cliquant dessus separator = ''; if(sender!='*'){//Si l'utilisateur est * l'utilisateur n'est pas afficher //new Element('a').addEvent('click',function(){this.create_buffer(sender,'pv');}.bind(this)).appendText(sender).setProperties({'href':'javascript:void(0)','class':way+' '+style+' user','style':'color:rgb('+this.user_color(sender)+')'}).injectInside(div_message); new Element('a').appendText(sender).setProperties({'href':'javascript:void(0)','class':way+' '+style+' user','style':'color:rgb('+this.user_color(sender)+')'}).injectInside(div_message); separator = ' > '; } //Ajout de l'heure if(!options.time){ var d = new Date; time = d.getHours()+':'+d.getMinutes(); Object.extend(objMsg,{'time':time}); }else{ time = options.time; } this.add_date(time,div_message); //Affichage du message this.parse_message(separator+msg,message); message.injectInside(div_message) div_message.injectInside(message_box); //Scroll de la boite de message try{ if(message_box.scrollHeight-message_box.scrollTop<=message_box.getStyle('height').toInt()+message_box.getStyle('height').toInt()/2){ message_box.scrollTop = message_box.scrollHeight+20;//(problème de scroll parfois sous FF c'est la raison pour laquel j'ajoute le +40) } }catch(e){ message_box.scrollTop = message_box.scrollHeight+20; } }, /*** * Ajoute la date