MOD avancement dans la Grande Restructuration
[euphorik.git] / js / euphorik.js
index 4b56fa3..28cba42 100755 (executable)
-// coding: utf-8\r
-\r
-/**\r
-  * Contient la base javascript pour le site euphorik.ch.\r
+// coding: utf-8
+// Copyright 2008 Grégory Burri
+//
+// This file is part of Euphorik.
+//
+// Euphorik 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 3 of the License, or
+// (at your option) any later version.
+//
+// Euphorik 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 Euphorik.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+  * Contient la base javascript pour le site euphorik.ch.
   * Chaque page possède son propre fichier js nommé "page<nom de la page>.js".
   * Auteur : GBurri
   * Date : 6.11.2007
   */
   * Chaque page possède son propre fichier js nommé "page<nom de la page>.js".
   * Auteur : GBurri
   * Date : 6.11.2007
   */
-  
 
 
-/**
-  * La configuration.\r
-  * Normalement 'const' à la place de 'var' mais non supporté par IE7.
-  */\r
-var conf = {\r
-   nbMessageAffiche : 10, // (par page)
-   pseudoDefaut : "<nick>",\r
-   tempsAffichageMessageDialogue : 4000, // en ms\r
-   smiles : {   \r
-      "smile" : [/:\)/g, /:-\)/g],  \r
-      "bigsmile" : [/:D/g, /:-D/g],\r
-      "clin" : [/;\)/g, /;-\)/g],\r
-      "cool" : [/8\)/g, /8-\)/g],\r
-      "eheheh" : [/:P/g, /:-P/g],
-      "lol" : [/\[-lol\]/g],
-      "spliff" : [/\[-spliff\]/g],\r
-      "oh" : [/:o/g, /:O/g],
-      "heink" : [/\[-heink\]/g],
-      "hum" : [/\[-hum\]/g],
-      "boh" : [/\[-boh\]/g],
-      "sniff" : [/:\(/g, /:-\(/g],
-      "triste" : [/\[-triste\]/g],\r
-      "pascontent" : [/>\(/g, /&gt;\(/g],\r
-      "argn" : [/\[-argn\]/g],
-      "redface" : [/\[-redface\]/g],\r
-      "bunny" : [/\[-lapin\]/g],\r
-      "chat" : [/\[-chat\]/g],\r
-      "renne" : [/\[-renne\]/g],\r
-      "star" : [/\[-star\]/g],\r
-      "kirby" : [/\[-kirby\]/g],
-      "slurp" : [/\[-slurp\]/g],
-      "agreed" : [/\[-agreed\]/g],
-      "dodo" : [/\[-dodo\]/g],
-      "bn" : [/\[-bn\]/g]\r
-   }\r
-}\r
+// tout euphorik est contenu dans cet objet
+var euphorik = {}
+// ;; euphorik.include = 
+// ;; euphorik.include = function(f) { var s = document.createElement('script'); s.type = 'text/javascript'; s.src = "js/" + f + ".js"; document.getElementsByTagName('head')[0].appendChild(s); }
 
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-\r
-String.prototype.trim = function()\r
-{\r
-       return jQuery.trim(this) // anciennement : this.replace(/^\s+|\s+$/g, "");\r
-}\r
-\r
-String.prototype.ltrim = function()\r
-{\r
-       return this.replace(/^\s+/, "");\r
-}\r
-\r
-String.prototype.rtrim = function()\r
-{\r
-       return this.replace(/\s+$/, "");\r
-}\r
-\r
-///////////////////////////////////////////////////////////////////////////////////////////////////\r
-\r
-/**\r
-  * Cette classe regroupe des fonctions utilitaires (helpers).\r
-  */
-function Util()
-{
-   $("#info .fermer").click(function(){
-      $("#info").slideUp(50) 
-   })
-}
 
 
-var messageType = {informatif: 0, question: 1, erreur: 2}
+// version jQuery : function(f) { jQuery.ajax({async : false, url : "js/" + f + ".js", dataType : "script"}) }
+// mais comme il n'est pas encore chargé...
+;; euphorik.include = function(f) {
+;;    var req, url = 'js/' + f + '.js'
+;;    if  (window.XMLHttpRequest) {
+;;       req = new XMLHttpRequest(); req.open("GET", url, false /* async */); req.send(null);
+;;    } else if (window.ActiveXObject) {    
+;;       req = new ActiveXObject((navigator.userAgent.toLowerCase().indexOf('msie 5') != -1) ? "Microsoft.XMLHTTP" : "Msxml2.XMLHTTP");
+;;       if (req) { req.open("GET", url, false); req.send(); }
+;;    }
+;;    if (req!==false) { if (req.status==200) { window.eval(req.responseText); } else if (req.status==404) { alert("erreur de chargement (404) de : " + url) } }
+;; } 
 
 
-/**
-  * Affiche une boite de dialogue avec un message à l'intérieur.
-  * @param message le message (string)\r
-  * @param type voir 'messageType'. par défaut messageType.informatif\r
-  * @param les boutons sous la forme d'un objet ou les clefs sont les labels des boutons\r
-  *        et les valeurs les fonctions executées lorsqu'un bouton est activé.
-  */
-Util.prototype.messageDialogue = function(message, type, boutons)
-{
-   if (type == undefined)
-      type = messageType.informatif
+;; euphorik.include("jquery")
+;; euphorik.include("jquery.lightbox")
+;; euphorik.include("md5")
+;; euphorik.include("json2")
 
 
-   if (this.timeoutMessageDialogue != undefined)
-      clearTimeout(this.timeoutMessageDialogue)
-      
-   var fermer = function(){$("#info").slideUp(100)}
-   fermer()   
-   
-   $("#info .message").html(message)
-   switch(type)
-   {
-      case messageType.informatif : $("#info #icone").attr("class", "information"); break
-      case messageType.question : $("#info #icone").attr("class", "interrogation"); break
-      case messageType.erreur : $("#info #icone").attr("class", "exclamation"); break
-   }   
-   $("#info .boutons").html("")
-   for (var b in boutons)
-      $("#info .boutons").append("<div>" + b + "</div>").find("div:last").click(boutons[b]).click(fermer)
-   
-   $("#info").slideDown(200)
-   this.timeoutMessageDialogue = setTimeout(fermer, conf.tempsAffichageMessageDialogue)   
-}\r
+;; euphorik.include("conf")
+;; euphorik.include("util")\r
+;; euphorik.include("formateur")\r
+;; euphorik.include("pages")
 
 
-/**
-  * Utilisé pour l'envoie de donnée avec la méthode ajax de jQuery.
-  */
-Util.prototype.jsonVersAction = function(json)
-{
-   return {action : JSON.stringify(json) }
-}
+;; euphorik.include("pageMinichat")
+;; euphorik.include("pageAdmin")
+;; euphorik.include("pageProfile")
+;; euphorik.include("pageRegister")
+;; euphorik.include("pageAbout")
 \r
 \r
-Util.prototype.md5 = function(chaine)\r
-{\r
-   return hex_md5(chaine)\r
-}
-\r
-// pompé de http://www.faqts.com/knowledge_base/view.phtml/aid/13562/fid/130\r
-Util.prototype.setSelectionRange = function(input, selectionStart, selectionEnd)
-{\r
-   if (input.setSelectionRange)
-   {\r
-      input.focus()\r
-      input.setSelectionRange(selectionStart, selectionEnd)\r
-   }\r
-   else if (input.createTextRange)
-   {\r
-      var range = input.createTextRange()\r
-      range.collapse(true)\r
-      range.moveEnd('character', selectionEnd)\r
-      range.moveStart('character', selectionStart)\r
-      range.select()\r
-   }\r
-}
-\r
-Util.prototype.setCaretToEnd = function(input)
-{\r
-   this.setSelectionRange(input, input.value.length, input.value.length)\r
-}\r
-Util.prototype.setCaretToBegin = function(input)
-{\r
-   this.setSelectionRange(input, 0, 0)\r
-}\r
-Util.prototype.setCaretToPos = function(input, pos)
-{\r
-   this.setSelectionRange(input, pos, pos)\r
-}\r
-Util.prototype.selectString = function(input, string)
-{\r
-   var match = new RegExp(string, "i").exec(input.value)\r
-   if (match)
-   {\r
-      this.setSelectionRange (input, match.index, match.index + match[0].length)\r
-   }\r
-}\r
-Util.prototype.replaceSelection = function(input, replaceString) {\r
-   if (input.setSelectionRange)
-   {\r
-      var selectionStart = input.selectionStart\r
-      var selectionEnd = input.selectionEnd\r
-      input.value = input.value.substring(0, selectionStart) + replaceString + input.value.substring(selectionEnd)
-      \r
-      if (selectionStart != selectionEnd) // has there been a selection\r
-         this.setSelectionRange(input, selectionStart, selectionStart + replaceString.length)\r
-      else // set caret\r
-         this.setCaretToPos(input, selectionStart + replaceString.length)\r
-   }\r
-   else if (document.selection)
-   {\r
-      var range = document.selection.createRange();\r
-      if (range.parentElement() == input)
-      {\r
-         var isCollapsed = range.text == ''\r
-         range.text = replaceString\r
-         if (!isCollapsed)
-         {
-            // there has been a selection\r
-            // it appears range.select() should select the newly \r
-            // inserted text but that fails with IE\r
-            range.moveStart('character', -replaceString.length);\r
-            range.select();\r
-         }\r
-      }\r
-   }\r
-}
-
-Util.prototype.rot13 = function(chaine)
-{
-   var ACode = 'A'.charCodeAt(0)
-   var aCode = 'a'.charCodeAt(0)
-   var MCode = 'M'.charCodeAt(0)
-   var mCode = 'm'.charCodeAt(0)
-   var ZCode = 'Z'.charCodeAt(0)
-   var zCode = 'z'.charCodeAt(0)
-
-   var f = function(ch, pos) {
-      if (pos == ch.length)
-         return ""
-      
-      var c = ch.charCodeAt(pos);
-      return String.fromCharCode(
-         c +
-         (c >= ACode && c <= MCode || c >= aCode && c <= mCode ? 13 :
-         (c > MCode && c <= ZCode || c > mCode && c <= zCode ? -13 : 0))
-      ) + f(ch, pos + 1)
-   }
-   return f(chaine, 0)
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-function Pages()
-{
-   this.pageCourante = null
-   this.pages = {}
-}
-
-Pages.prototype.ajouterPage = function(page)
-{
-   page.pages = this // la magie des langages dynamiques : le foutoire
-   this.pages[page.nom] = page
-}
-
-Pages.prototype.afficherPage = function(nomPage, forcerChargement)
-{\r
-   if (forcerChargement == undefined) forcerChargement = false\r
-
-   var page = this.pages[nomPage]
-   if (page == undefined || (!forcerChargement && page == this.pageCourante)) return
-   
-   if (this.pageCourante != null && this.pageCourante.decharger)
-      this.pageCourante.decharger()
-  
-   $("#menu div").removeClass("courante")
-   $("#menu div." + nomPage).addClass("courante")
-      
-   this.pageCourante = page
-   $("#page").html(this.pageCourante.contenu()).removeClass().addClass(this.pageCourante.nom)
-   
-   if (this.pageCourante.charger)
-      this.pageCourante.charger()
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-function Formateur()
-{
-   this.smiles = conf.smiles\r
-   this.protocoles = "http|https|ed2k"\r
-   \r
-   this.regexUrl = new RegExp("(?:(?:" + this.protocoles + ")://|www\\.)[^ ]*", "gi")\r
-   this.regexImg = new RegExp("^.*?\\.(gif|jpg|png|jpeg|bmp|tiff)$", "i")\r
-   this.regexDomaine = new RegExp("^(?:(?:" + this.protocoles + ")://|www\\.).*?([^/.]+\\.[^/.]+)(?:$|/).*$", "i")\r
-   this.regexTestProtocoleExiste = new RegExp("^(?:" + this.protocoles + ")://.*$", "i")\r
-   this.regexNomProtocole = new RegExp("^(.*?)://")
-}
-
-/**
-  * Formate un pseudo saise par l'utilisateur.
-  * @param pseudo le pseudo brut
-  * @return le pseudo filtré
-  */
-Formateur.prototype.filtrerInputPseudo = function(pseudo)
-{
-   return pseudo.replace(/{|}/g, "").trim()
-}
-\r
-Formateur.prototype.getSmilesHTML = function()\r
-{\r
-   var XHTML = ""\r
-   for (var sNom in this.smiles)\r
-   {\r
-      XHTML += "<img class=\"" + sNom + "\" src=\"img/smileys/" + sNom + ".gif\" />"\r
-   }\r
-   return XHTML\r
-}\r
-
-/**
-  * Formatage complet d'un texte.
-  * @M le message
-  * @pseudo facultatif, permet de contruire le label des images sous la forme : "<Pseudo> : <Message>"
-  */
-Formateur.prototype.traitementComplet = function(M, pseudo)
-{
-   return this.traiterLiensConv(this.traiterSmiles(this.traiterURL(this.remplacerBalisesHTML(M), pseudo)))
-}
-
-/**
-  * Transforme les liens en entités clickables.
-  * Un lien vers une conversation permet d'ouvrire celle ci, elle se marque comme ceci dans un message :
-  * "{5F}" ou 5F est la racine de la conversation.
-  * Ce lien sera transformer en <span class="lienConv">{5F}</span> pouvant être clické pour créer la conv 5F.
-  */
-Formateur.prototype.traiterLiensConv = function(M)
-{
-   return M.replace(
-      /\{\w+\}/g,
-      function(lien)
-      {
-         return "<span class=\"lienConv\">" + lien + "</span>"
-      }
-   )
-}
 \r
 \r
+// tout un tas d'améliorations de JavaScript ;)\r
 /**\r
 /**\r
-  * FIXME : Cette méthode est attrocement lourde ! A optimiser.
-  * moyenne su échantillon : 234ms\r
-  */
-Formateur.prototype.traiterSmiles = function(M)
-{  
-   for (var sNom in this.smiles)
-   {
-      ss = this.smiles[sNom]
-      for (var i = 0; i < ss.length; i++)       
-         M = M.replace(ss[i], "<img src=\"img/smileys/" + sNom + ".gif\" />")
-   }
-   return M
-}
-
-Formateur.prototype.remplacerBalisesHTML = function(M)
-{
-   return M.replace(/</g, "&lt;").replace(/>/g, "&gt;")
-}
-
-Formateur.prototype.traiterURL = function(M, pseudo)
-{
-   thisFormateur = this
-         
-   var traitementUrl = function(url)
-   {    \r
-      // si ya pas de protocole on rajoute "http://"\r
-      if (!thisFormateur.regexTestProtocoleExiste.test(url))\r
-         url = "http://" + url
-      var extension = thisFormateur.getShort(url)
-      return "<a " + (extension[1] ? "title=\"" + (pseudo == undefined ? "" : thisFormateur.traiterPourFenetreLightBox(pseudo, url) + ": ") +  thisFormateur.traiterPourFenetreLightBox(M, url) + "\"" + " rel=\"lightbox\"" : "") + " href=\"" + url + "\" >[" + extension[0] + "]</a>"
-   }
-   return M.replace(this.regexUrl, traitementUrl)
-}
-\r
-/**\r
-  * Renvoie une version courte de l'url.\r
-  * par exemple : http://en.wikipedia.org/wiki/Yakov_Smirnoff devient wikipedia.org\r
-  */
-Formateur.prototype.getShort = function(url)
-{\r
-      var estUneImage = false
-      var versionShort = null
-      var rechercheImg = this.regexImg.exec(url)
-      
-      if (rechercheImg != null)\r
-      {
-         versionShort = rechercheImg[1].toLowerCase()\r
-         if (versionShort == "jpeg") versionShort = "jpg" // jpeg -> jpg\r
-         estUneImage = true\r
-      }\r
-      else\r
-      {\r
-         var rechercheDomaine = this.regexDomaine.exec(url)\r
-         if (rechercheDomaine != null && rechercheDomaine.length >= 2)\r
-            versionShort = rechercheDomaine[1]\r
-         else\r
-         {\r
-            var nomProtocole = this.regexNomProtocole.exec(url)\r
-            if (nomProtocole != null && nomProtocole.length >= 2)\r
-               versionShort = nomProtocole[1]\r
-         }\r
+  * Pour chaque propriété de l'objet execute f(p, v) ou p est le nom de la propriété et v sa valeur.\r
+  * Ne parcours pas les propriétés des prototypes.\r
+  */\r
+Object.prototype.each = function(f) {\r
+   for (var k in this) {\r
+      if (this.hasOwnProperty(k)) {\r
+         f(k, this[k])\r
       }\r
       }\r
-      
-      return [versionShort == null ? "url" : versionShort, estUneImage]
- }
-/**
-  * Traite les pseudo et messages à être affiché dans le titre d'une image visualisé avec lightbox.
-  */
-Formateur.prototype.traiterPourFenetreLightBox = function(M, urlCourante)
-{
-   thisFormateur = this
-   var traitementUrl = function(url)
-   {
-      return "[" + thisFormateur.getShort(url)[0] + (urlCourante == url ? ": image courante" : "") + "]"
-   }
-   \r
-   return this.remplacerBalisesHTML(M).replace(this.regexUrl, traitementUrl)
-}
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-// les statuts possibes du client
-var statutType = {
-   // mode enregistré, peut poster des messages et modifier son profile
-   auth_registered : 0,
-   // mode identifié, peut poster des messages mais n'a pas accès au profile
-   auth_not_registered : 1,
-   // mode déconnecté, ne peut pas poster de message
-   deconnected : 2
-}
-\r
-function Client(util)\r
-{
-   this.util = util
-   \r
-   this.cookie = null
-   this.regexCookie = new RegExp("^cookie=([^;]*)")
-   
-   // données personnels\r
-   this.resetDonneesPersonnelles()
-   
-   this.setStatut(statutType.deconnected)
-   
-   // le dernier message d'erreur recut du serveur (par exemple une connexion foireuse : "login impossible")
-   this.dernierMessageErreur = ""\r
-}
-\r
-Client.prototype.resetDonneesPersonnelles = function()\r
-{
-   this.id = 0\r
-   this.pseudo = conf.pseudoDefaut\r
-   this.login = ""\r
-   this.password = ""\r
-   this.email = ""\r
-   this.css = $("link#cssPrincipale").attr("href")
-   this.nickFormat = "nick"
-   
-   this.pagePrincipale = 1
-   this.ekMaster = false
-   
-   // les conversations, une conversation est un objet possédant les attributs suivants :
-   // - racine (entier)
-   // - page (entier)
-   this.conversations = new Array()\r
-}
-
-Client.prototype.setCss = function(css)
-{
-   if (this.css == css || css == "")
-      return
-
-   this.css = css
-   $("link#cssPrincipale").attr("href", this.css)
-   this.majMenu()
-}
-
-Client.prototype.pageSuivante = function(numConv)
-{
-   if (numConv < 0 && this.pagePrincipale > 1)
-      this.pagePrincipale -= 1
-   else if (this.conversations[numConv].page > 1)
-      this.conversations[numConv].page -= 1
-}
-
-Client.prototype.pagePrecedente = function(numConv)
-{
-   if (numConv < 0)
-      this.pagePrincipale += 1
-   else 
-      this.conversations[numConv].page += 1
-}
-
-/**
-  * Définit la première page pour la conversation donnée.
-  * @return true si la page a changé sinon false
-  */
-Client.prototype.goPremierePage = function(numConv)
-{
-   if (numConv < 0)
-   {
-      if (this.pagePrincipale == 1)
-         return false
-      this.pagePrincipale = 1
-   }
-   else
-   {
-      if (this.conversations[numConv].page == 1)
-         return false
-      this.conversations[numConv].page = 1
-   }
-   return true
-}
-
-/**
-  * Ajoute une conversation à la vue de l'utilisateur.
-  * Le profile de l'utilisateur est directement sauvegardé sur le serveur.
-  * @param racines la racine de la conversation (integer)
-  * @return true si la conversation a été créée sinon false (par exemple si la conv existe déjà)
-  */
-Client.prototype.ajouterConversation = function(racine)
-{
-   // vérification s'il elle n'existe pas déjà
-   for (var i = 0; i < this.conversations.length; i++)
-      if (this.conversations[i].root == racine)
-         return false
-         
-   this.conversations.push({root : racine, page : 1})
-   return true
-}
-
-Client.prototype.supprimerConversation = function(num)
-{
-   if (num < 0 || num >= this.conversations.length) return
-   
-   // décalage TODO : supprimer le dernier élément 
-   for (var i = num; i < this.conversations.length - 1; i++)
-      this.conversations[i] = this.conversations[i+1]
-   this.conversations.pop()
-}
-
-Client.prototype.getJSONLogin = function(login, password)
-{
-   return {
-      "action" : "authentification",
-      "login" : login,
-      "password" : password
-   }
-}
-
-Client.prototype.getJSONLoginCookie = function()
-{
-   return {
-      "action" : "authentification",
-      "cookie" : this.cookie
-   }
-}  
-
-/**
-  * le couple (login, password) est facultatif. S'il n'est pas fournit alors il ne sera pas possible
-  * de s'autentifier avec (login, password).
-  */
-Client.prototype.getJSONEnregistrement = function(login, password)
-{
-   var mess = { "action" : "register" }
-   
-   if (login != undefined && password != undefined)
-   {
-      mess["login"] = login
-      mess["password"] = password
-   }
-   
-   return mess;
-}
-
-Client.prototype.getJSONConversations = function()
-{
-   var conversations = new Array()
-   for (var i = 0; i < this.conversations.length; i++)
-      conversations.push({ "root" : this.conversations[i].root, "page" : this.conversations[i].page})
-   return conversations
-}
-
-Client.prototype.getJSONProfile = function()
-{
-   return {
-      "action" : "set_profile",
-      "cookie" : this.cookie,
-      "login" : this.login,
-      "password" : this.password,
-      "nick" : this.pseudo,
-      "email" : this.email,
-      "css" : this.css,
-      "nick_format" : this.nickFormat,
-      "main_page" : this.pagePrincipale < 1 ? 1 : this.pagePrincipale,
-      "conversations" : this.getJSONConversations()
-   }
-}
-
-/**
-  * Renvoie null si pas définit.
-  */
-Client.prototype.getCookie = function()
-{
-   var cookie = this.regexCookie.exec(document.cookie)
-   if (cookie == null) this.cookie = null
-   else this.cookie = cookie[1]
+   }\r
 }\r
 \r
 }\r
 \r
-Client.prototype.delCookie = function()\r
-{\r
-   document.cookie = "cookie=; max-age=0"\r
-}
-
-Client.prototype.setCookie = function(cookie)
-{
-   if (this.cookie == null)
-      return
-      
-   document.cookie =
-      "cookie="+this.cookie+
-      "; max-age="  + (60 * 60 * 24 * 365)
-}
-
-Client.prototype.authentifie = function()
-{
-   return this.statut == statutType.auth_registered || this.statut == statutType.auth_not_registered
-}
-
-Client.prototype.setStatut = function(statut)
-{  
-   // conversation en "enum" si en "string"\r
-   if (typeof(statut) == "string")\r
-   {
-      statut =
-         statut == "auth_registered" ?
-            statutType.auth_registered :
-         (statut == "auth_not_registered" ? statutType.auth_not_registered : statutType.deconnected)\r
-   }   \r
-   \r
-   if (statut == this.statut) return   \r
-   \r
-   this.statut = statut   \r
-   this.majMenu()
-}
-\r
-/**\r
-  * Effectue la connexion vers le serveur.\r
-  * Cette fonction est bloquante tant que la connexion n'a pas été établie.\r
-  * S'il existe un cookie en local on s'authentifie directement avec lui.\r
-  * Si il n'est pas possible de s'authentifier alors on affiche un captcha anti-bot.\r
-  */\r
-Client.prototype.connexionCookie = function()\r
-{\r
-   this.getCookie()\r
-   if (this.cookie == null) return false;
-   return this.connexion(this.getJSONLoginCookie())\r
-}
-
-Client.prototype.connexionLogin = function(login, password)
-{
-   return this.connexion(this.getJSONLogin(login, password))
-}\r
-
-Client.prototype.enregistrement = function(login, password)
-{ 
-   if (this.authentifie())
-   {
-      this.login = login
-      this.password = password
-      if(this.flush())
-      {
-         this.setStatut(statutType.auth_registered)
-         return true
-      }
-      return false
-   }
-   else\r
-   {
-      return this.connexion(this.getJSONEnregistrement(login, password))\r
-   }
-}
-
-Client.prototype.connexion = function(messageJson)
-{
-   ;;; dumpObj(messageJson)
-   thisClient = this
-   jQuery.ajax(
-      {
-         async: false,
-         type: "POST",
-         url: "request",
-         dataType: "json",
-         data: this.util.jsonVersAction(messageJson),
-         success:
-            function(data)
-            {
-               ;;; dumpObj(data)
-               thisClient.chargerDonnees(data)
-            }
-      }
-   )
-   return this.authentifie()
+Array.prototype.each = function(f) {\r
+   for (var i = 0; i < this.length; i++) {\r
+      f(i, this[i])\r
+   }\r
 }\r
 }\r
-\r
-Client.prototype.deconnexion = function()\r
-{
-   this.flush(true)
-   this.delCookie()\r
-   this.setStatut(statutType.deconnected) // deconnexion\r
-   this.resetDonneesPersonnelles()\r
-}
-
-Client.prototype.chargerDonnees = function(data)
-{
-   // la modification du statut qui suit met à jour le menu, le menu dépend (page admin)
-   // de l'état ekMaster
-   this.ekMaster = data["ek_master"] != undefined ? data["ek_master"] : false
-   
-   this.setStatut(data["status"]) 
-   
-   if (this.authentifie())
-   {
-      this.cookie = data["cookie"]
-      this.setCookie()
-      
-      this.id = data["id"]\r
-      this.login = data["login"]
-      this.pseudo = data["nick"]\r
-      this.email = data["email"]\r
-      this.setCss(data["css"])
-      this.nickFormat = data["nick_format"]
-      
-      // la page de la conversation principale
-      this.pagePrincipale = data["main_page"] == undefined ? 1 : data["main_page"]
-      
-      // les conversations
-      this.conversations = data["conversations"]
-   }
-   this.dernierMessageErreur = data["error_message"]
-}
 
 
-/**
-  * Met à jour les données personne sur serveur.
-  * @param async de manière asynchrone ? défaut = true
-  * @return false si le flush n'a pas pû se faire sinon true
-  */
-Client.prototype.flush = function(async)
-{
-   if (async == undefined)
-      async = false
-      
-   if (!this.authentifie())
-      return false
-
-   thisClient = this
-   var ok = true
-   
-   ;;; dumpObj(this.getJSONProfile())
-   jQuery.ajax(
-      {
-         async: async,
-         type: "POST",
-         url: "request",
-         dataType: "json",
-         data: this.util.jsonVersAction(this.getJSONProfile()),
-         success:
-            function(data)
-            {
-               ;;; dumpObj(data)
-               if (data["reply"] == "error")
-               {
-                  thisClient.dernierMessageErreur = data["error_message"]
-                  ok = false
-               }
-            }
-      }
-   )
-   
-   return ok
+String.prototype.trim = function() {
+       return jQuery.trim(this) // anciennement : this.replace(/^\s+|\s+$/g, "");
 }
 
 }
 
-Client.prototype.majMenu = function()
-{
-   // TODO : à virer : ne plus changer de style de display ... spa beau .. ou trouver une autre méthode
-   var displayType = this.css == "css/3/euphorik.css" ? "block" : "inline" //this.client
-
-   $("#menu .admin").css("display", this.ekMaster ? "inline" : "none")
-
-   // met à jour le menu   
-   if (this.statut == statutType.auth_registered)
-   {
-      $("#menu .profile").css("display", displayType).text("profile")\r
-      $("#menu .logout").css("display", displayType)
-      $("#menu .register").css("display", "none")
-   }
-   else if (this.statut == statutType.auth_not_registered)
-   {
-      $("#menu .profile").css("display", "none")\r
-      $("#menu .logout").css("display", displayType)
-      $("#menu .register").css("display", displayType)
-   }
-   else
-   {
-      $("#menu .profile").css("display", displayType).text("login")\r
-      $("#menu .logout").css("display", "none")
-      $("#menu .register").css("display", displayType)
-   }
+String.prototype.ltrim = function() {
+       return this.replace(/^\s+/, "");
 }
 
 }
 
-Client.prototype.slap = function(userId, raison)
-{
-   var thisClient = this
-   
-   jQuery.ajax({
-      type: "POST",
-      url: "request",
-      dataType: "json",
-      data: this.util.jsonVersAction(
-         {
-            "action" : "slap",
-            "cookie" : thisClient.cookie,
-            "user_id" : userId,
-            "reason" : raison
-         }),
-      success: 
-         function(data)
-         {
-            if (data["reply"] == "error")
-               thisClient.util.messageDialogue(data["error_message"])
-         }
-   })
+String.prototype.rtrim = function() {
+       return this.replace(/\s+$/, "");
 }
 
 }
 
-Client.prototype.ban = function(userId, raison, minutes)
-{
-   var thisClient = this
-
-   // par défaut un ban correspond à 3 jours
-   if (typeof(minutes) == "undefined")
-      minutes = 60 * 24 * 3
-      
-   jQuery.ajax({
-      type: "POST",
-      url: "request",
-      dataType: "json",
-      data: this.util.jsonVersAction(
-         {
-            "action" : "ban",
-            "cookie" : thisClient.cookie,
-            "duration" : minutes,
-            "user_id" : userId,
-            "reason" : raison
-         }),
-      success: 
-         function(data)
-         {
-            if (data["reply"] == "error")
-               thisClient.util.messageDialogue(data["error_message"])
-         }
-   })
-}
-
-Client.prototype.kick = function(userId, raison)
-{
-   this.ban(userId, raison, 15)
-}
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-/**
-   * classe permettant de gérer les événements (push serveur).
-   * @page la page
-   */
-function PageEvent(page, util)
-{
-   this.page = page
-   this.util = util
-   
-   // l'objet JSONHttpRequest représentant la connexion d'attente
-   this.attenteCourante = null
-}
-
-/**
-  * Arrête l'attente courante s'il y en a une.
-  */
-PageEvent.prototype.stopAttenteCourante = function()
-{
-   if (this.attenteCourante != null)
-      this.attenteCourante.abort()   
-}
 
 
-/**
-  * Attend un événement lié à la page. 
-  * @funSend une fonction renvoyant les données json à envoyer
-  * @funReceive une fonction qui accepte un paramètre correspondant au données reçues
-  */
-PageEvent.prototype.waitEvent = function(funSend, funReceive)
-{
-   var thisPageEvent = this
-      
-   this.stopAttenteCourante()
-      
-   // on doit conserver l'ordre des valeurs de l'objet JSON (le serveur les veux dans l'ordre définit dans le protocole)
-   // TODO : ya pas mieux ?
-   var dataToSend = 
-   {
-      "action" : "wait_event",
-      "page" : this.page
-   }
-   var poulpe = funSend()
-   for (v in poulpe)
-      dataToSend[v] = poulpe[v]
-   
-   ;;; dumpObj(dataToSend)
-   this.attenteCourante = jQuery.ajax({
-      type: "POST",
-      url: "request",
-      dataType: "json",
-      data: this.util.jsonVersAction(dataToSend),
-      success:
-         function(data)
-         {            
-            ;;; dumpObj(data)
-            
-            funReceive(data)
-            
-            // rappel de la fonction dans 100 ms
-            setTimeout(function(){ thisPageEvent.waitEvent(funSend, funReceive) }, 100);
-         },
-      error:
-         function(XMLHttpRequest, textStatus, errorThrown)
-         {
-            setTimeout(function(){ thisPageEvent.rafraichirMessages(funSend, funReceive) }, 1000);
-         }
-   })
-
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-function initialiserListeStyles(client)
-{
-   $("#menuCss").change(
-      function()
-      {
-         client.setCss("css/" + $("option:selected", this).attr("value") + "/euphorik.css")
-      }
-   )
-}
-            
-// charge dynamiquement le script de debug
-;;; jQuery.ajax({async : false, url : "js/debug.js", dataType : "script"})
-      \r
 // le main
 $(document).ready(
    function()
 // le main
 $(document).ready(
    function()
-   {  
-      var util = new Util()
+   {
+      var formateur = new euphorik.Formateur()
+      var util = new euphorik.Util(formateur)
       var client = new Client(util)
       var client = new Client(util)
-      var pages = new Pages()
-      var formateur = new Formateur()\r
-      \r
-      // connexion vers le serveur (utilise un cookie qui traine)\r
+      var pages = new euphorik.Pages()
+      
+      // connexion vers le serveur (utilise un cookie qui traine)
       client.connexionCookie()
       
       client.connexionCookie()
       
-      initialiserListeStyles(client)
+      $("#menuCss").change(function(){ client.setCss("styles/" + $("option:selected", this).attr("value") + "/euphorik.css")})
 
 
-      // TODO : pourquoi $(document).unload ne fonctionne pas ?
+      // FIXME : ne fonctionne pas sous opera
+      // voir : http://dev.jquery.com/ticket/2892#preview
       $(window).unload(function(){client.flush()})
       
       $("#menu .minichat").click(function(){ pages.afficherPage("minichat") })
       $("#menu .admin").click(function(){ pages.afficherPage("admin") })
       $(window).unload(function(){client.flush()})
       
       $("#menu .minichat").click(function(){ pages.afficherPage("minichat") })
       $("#menu .admin").click(function(){ pages.afficherPage("admin") })
-      $("#menu .profile").click(function(){ pages.afficherPage("profile") })\r
+      $("#menu .profile").click(function(){ pages.afficherPage("profile") })
       $("#menu .logout").click(function(){
       $("#menu .logout").click(function(){
-         util.messageDialogue("Êtes-vous sur de vouloir vous délogger ?", messageType.question,
+         util.messageDialogue("Êtes-vous sur de vouloir vous délogger ?", euphorik.Util.messageType.question,
             {"Oui" : function()
                {
                   client.deconnexion();
             {"Oui" : function()
                {
                   client.deconnexion();
@@ -958,12 +128,17 @@ $(document).ready(
       })
       $("#menu .register").click(function(){ pages.afficherPage("register") })
       $("#menu .about").click(function(){ pages.afficherPage("about") })
       })
       $("#menu .register").click(function(){ pages.afficherPage("register") })
       $("#menu .about").click(function(){ pages.afficherPage("about") })
+      
+      // TODO : simplifier et pouvoir créer des liens par exemple : <span class="lien" href="conditions">Conditions d'utilisation</span>
+      $("#footer .conditions").click(function(){ pages.afficherPage("conditions_utilisation") })
 
       pages.ajouterPage(new PageMinichat(client, formateur, util))
       pages.ajouterPage(new PageAdmin(client, formateur, util))
       pages.ajouterPage(new PageProfile(client, formateur, util))
       pages.ajouterPage(new PageRegister(client, formateur, util))
       pages.ajouterPage(new PageAbout(client, formateur, util))
 
       pages.ajouterPage(new PageMinichat(client, formateur, util))
       pages.ajouterPage(new PageAdmin(client, formateur, util))
       pages.ajouterPage(new PageProfile(client, formateur, util))
       pages.ajouterPage(new PageRegister(client, formateur, util))
       pages.ajouterPage(new PageAbout(client, formateur, util))
+      pages.ajouterPage("conditions_utilisation")
+      
       pages.afficherPage("minichat")
    }
       pages.afficherPage("minichat")
    }
-)
\ No newline at end of file
+)