(no commit message)
[euphorik.git] / js / euphorik.js
index a3b0acf..32b8758 100755 (executable)
@@ -1,4 +1,4 @@
-// coding: utf-8\r
+// coding: utf-8\r
 // Copyright 2008 Grégory Burri\r
 //\r
 // This file is part of Euphorik.\r
 // Copyright 2008 Grégory Burri\r
 //\r
 // This file is part of Euphorik.\r
@@ -31,7 +31,9 @@
 var conf = {\r
    nbMessageAffiche : 40, // (par page)
    pseudoDefaut : "<nick>",\r
 var conf = {\r
    nbMessageAffiche : 40, // (par page)
    pseudoDefaut : "<nick>",\r
-   tempsAffichageMessageDialogue : 4000, // en ms\r
+   tempsAffichageMessageDialogue : 4000, // en ms
+   tempsKick : 15, // en minute
+   tempsBan : 60 * 24 * 3, // en minutes (3jours)\r
    smiles : {   \r
       "smile" : [/:\)/g, /:-\)/g],  \r
       "bigsmile" : [/:D/g, /:-D/g],\r
    smiles : {   \r
       "smile" : [/:\)/g, /:-\)/g],  \r
       "bigsmile" : [/:D/g, /:-D/g],\r
@@ -90,7 +92,10 @@ function Util(formateur)
       $("#info").slideUp(50) 
    })
    
       $("#info").slideUp(50) 
    })
    
+   $("body").append('<div id="flecheBulle"></div>').append('<div id="messageBulle"><p></p></div>')
+   
    this.formateur = formateur
    this.formateur = formateur
+   this.bulleActive = true
 }
 
 var messageType = {informatif: 0, question: 1, erreur: 2}
 }
 
 var messageType = {informatif: 0, question: 1, erreur: 2}
@@ -134,6 +139,55 @@ Util.prototype.messageDialogue = function(message, type, boutons, formate)
    this.timeoutMessageDialogue = setTimeout(fermer, conf.tempsAffichageMessageDialogue)   
 }\r
 
    this.timeoutMessageDialogue = setTimeout(fermer, conf.tempsAffichageMessageDialogue)   
 }\r
 
+/**
+  * Affiche un info bulle lorsque le curseur survole l'élément donné.
+  * FIXME : le width de element ne tient pas compte du padding !?
+  */
+Util.prototype.infoBulle = function(message, element)
+{
+   var thisUtil = this
+
+   var cacherBulle = function()
+      {   
+         $("#flecheBulle").hide()
+         $("#messageBulle").hide()
+      }
+
+   element.hover(
+      function(e)
+      {
+         if (!thisUtil.bulleActive)
+            return
+         
+         var m = $("#messageBulle")
+         var f = $("#flecheBulle")
+         
+         $("p", m).html(message)
+      
+         var positionFleche = {
+            left : element.offset().left + element.width() / 2 - f.width() / 2,
+            top : element.offset().top - f.height()
+         }
+         var positionMessage = {
+            left : element.offset().left + element.width() / 2 - m.width() / 2,
+            top : element.offset().top - f.height() - m.height()
+         }
+         var depassementDroit = (positionMessage.left + m.width()) - $("body").width()
+         if (depassementDroit > 0)
+            positionMessage.left -= depassementDroit
+         else
+         {
+            if (positionMessage.left < 0)
+               positionMessage.left = 0
+         }
+         
+         m.css("top", positionMessage.top).css("left", positionMessage.left).show()
+         f.css("top", positionFleche.top).css("left", positionFleche.left).show()
+      },
+      cacherBulle
+   ).click(cacherBulle)
+}
+
 /**
   * Utilisé pour l'envoie de donnée avec la méthode ajax de jQuery.
   */
 /**
   * Utilisé pour l'envoie de donnée avec la méthode ajax de jQuery.
   */
@@ -198,19 +252,16 @@ Util.prototype.replaceSelection = function(input, replaceString) {
          this.setCaretToPos(input, selectionStart + replaceString.length)\r
    }\r
    else if (document.selection)
          this.setCaretToPos(input, selectionStart + replaceString.length)\r
    }\r
    else if (document.selection)
-   {\r
-      var range = document.selection.createRange();\r
+   {
+      input.focus()\r
+      var range = document.selection.createRange()\r
       if (range.parentElement() == input)
       {\r
          var isCollapsed = range.text == ''\r
          range.text = replaceString\r
          if (!isCollapsed)
       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
+         {\r
             range.moveStart('character', -replaceString.length);\r
             range.moveStart('character', -replaceString.length);\r
-            range.select();\r
          }\r
       }\r
    }\r
          }\r
       }\r
    }\r
@@ -247,10 +298,21 @@ function Pages()
    this.pages = {}
 }
 
    this.pages = {}
 }
 
+/**
+  * Accepte soit un objet soit un string.
+  * un string correspond au nom de la page, par exemple : "page" -> "page.html"
+  */
 Pages.prototype.ajouterPage = function(page)
 {
 Pages.prototype.ajouterPage = function(page)
 {
-   page.pages = this // la magie des langages dynamiques : le foutoire
-   this.pages[page.nom] = page
+   if (typeof page == "string")
+   {
+      this.pages[page] = page
+   }
+   else
+   {
+      page.pages = this // la magie des langages dynamiques : le foutoire
+      this.pages[page.nom] = page
+   }
 }
 
 Pages.prototype.afficherPage = function(nomPage, forcerChargement)
 }
 
 Pages.prototype.afficherPage = function(nomPage, forcerChargement)
@@ -267,7 +329,12 @@ Pages.prototype.afficherPage = function(nomPage, forcerChargement)
    $("#menu li." + nomPage).addClass("courante")
       
    this.pageCourante = page
    $("#menu li." + nomPage).addClass("courante")
       
    this.pageCourante = page
-   $("#page").html(this.pageCourante.contenu()).removeClass().addClass(this.pageCourante.nom)
+   var contenu = ""
+   if (typeof page == "string")
+      $.ajax({async: false, url: "pages/" + page + ".html", success : function(page) { contenu += page }})
+   else
+      contenu += this.pageCourante.contenu()
+   $("#page").html(contenu).removeClass().addClass(this.pageCourante.nom)
    
    if (this.pageCourante.charger)
       this.pageCourante.charger()
    
    if (this.pageCourante.charger)
       this.pageCourante.charger()
@@ -465,6 +532,9 @@ function Client(util)
    this.resetDonneesPersonnelles()
    
    this.setStatut(statutType.deconnected)\r
    this.resetDonneesPersonnelles()
    
    this.setStatut(statutType.deconnected)\r
+   \r
+   // si true alors chaque modification du client est mémorisé sur le serveur\r
+   this.autoflush = $.browser["opera"]\r
 }
 \r
 Client.prototype.resetDonneesPersonnelles = function()\r
 }
 \r
 Client.prototype.resetDonneesPersonnelles = function()\r
@@ -476,6 +546,8 @@ Client.prototype.resetDonneesPersonnelles = function()
    this.email = ""\r
    this.css = $("link#cssPrincipale").attr("href")
    this.nickFormat = "nick"
    this.email = ""\r
    this.css = $("link#cssPrincipale").attr("href")
    this.nickFormat = "nick"
+   this.viewTimes = true
+   this.viewTooltips = true
    this.cookie = undefined
    
    this.pagePrincipale = 1
    this.cookie = undefined
    
    this.pagePrincipale = 1
@@ -494,7 +566,9 @@ Client.prototype.setCss = function(css)
 
    this.css = css
    $("link#cssPrincipale").attr("href", this.css)
 
    this.css = css
    $("link#cssPrincipale").attr("href", this.css)
-   this.majMenu()
+   this.majMenu()\r
+   \r
+   if (this.autoflush) this.flush(true)
 }
 
 Client.prototype.pageSuivante = function(numConv)
 }
 
 Client.prototype.pageSuivante = function(numConv)
@@ -547,7 +621,10 @@ Client.prototype.ajouterConversation = function(racine)
       if (this.conversations[i].root == racine)
          return false
          
       if (this.conversations[i].root == racine)
          return false
          
-   this.conversations.push({root : racine, page : 1})
+   this.conversations.push({root : racine, page : 1})\r
+   \r
+   if (this.autoflush) this.flush(true)\r
+   
    return true
 }
 
    return true
 }
 
@@ -558,7 +635,9 @@ Client.prototype.supprimerConversation = function(num)
    // 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]
    // 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()
+   this.conversations.pop()\r
+   \r
+   if (this.autoflush) this.flush(true)
 }
 
 Client.prototype.getJSONLogin = function(login, password)
 }
 
 Client.prototype.getJSONLogin = function(login, password)
@@ -614,6 +693,8 @@ Client.prototype.getJSONProfile = function()
       "email" : this.email,
       "css" : this.css,
       "nick_format" : this.nickFormat,
       "email" : this.email,
       "css" : this.css,
       "nick_format" : this.nickFormat,
+      "view_times" : this.viewTimes,
+      "view_tooltips" : this.viewTooltips,
       "main_page" : this.pagePrincipale < 1 ? 1 : this.pagePrincipale,
       "conversations" : this.getJSONConversations()
    }
       "main_page" : this.pagePrincipale < 1 ? 1 : this.pagePrincipale,
       "conversations" : this.getJSONConversations()
    }
@@ -634,14 +715,16 @@ Client.prototype.delCookie = function()
    document.cookie = "cookie=; max-age=0"\r
 }
 
    document.cookie = "cookie=; max-age=0"\r
 }
 
-Client.prototype.setCookie = function(cookie)
+Client.prototype.setCookie = function()
 {
 {
-   if (this.cookie == null)
+   if (this.cookie == null || this.cookie == undefined)
       return
       
       return
       
-   document.cookie =
-      "cookie="+this.cookie+
-      "; max-age="  + (60 * 60 * 24 * 365)
+   // ne fonctionne pas sous IE....
+   /*document.cookie = "cookie=" + this.cookie + "; max-age="  + (60 * 60 * 24 * 365) */
+   
+   document.cookie = 
+      "cookie="+this.cookie+"; expires=" + new Date(new Date().getTime() + 1000 * 60 * 60 * 24 * 365).toUTCString()
 }
 
 Client.prototype.authentifie = function()
 }
 
 Client.prototype.authentifie = function()
@@ -705,7 +788,7 @@ Client.prototype.enregistrement = function(login, password)
 
 Client.prototype.connexion = function(messageJson)
 {
 
 Client.prototype.connexion = function(messageJson)
 {
-   ;;; dumpObj(messageJson)
+   ;; dumpObj(messageJson)
    thisClient = this
    jQuery.ajax(
       {
    thisClient = this
    jQuery.ajax(
       {
@@ -717,7 +800,7 @@ Client.prototype.connexion = function(messageJson)
          success:
             function(data)
             {
          success:
             function(data)
             {
-               ;;; dumpObj(data)
+               ;; dumpObj(data)
                if (data["reply"] == "error")
                   thisClient.util.messageDialogue(data["error_message"])
                else
                if (data["reply"] == "error")
                   thisClient.util.messageDialogue(data["error_message"])
                else
@@ -755,12 +838,16 @@ Client.prototype.chargerDonnees = function(data)
       this.email = data["email"]\r
       this.setCss(data["css"])
       this.nickFormat = data["nick_format"]
       this.email = data["email"]\r
       this.setCss(data["css"])
       this.nickFormat = data["nick_format"]
+      this.viewTimes = data["view_times"]
+      this.viewTooltips = data["view_tooltips"]
       
       // la page de la conversation principale
       this.pagePrincipale = data["main_page"] == undefined ? 1 : data["main_page"]
       
       // les conversations
       this.conversations = data["conversations"]
       
       // la page de la conversation principale
       this.pagePrincipale = data["main_page"] == undefined ? 1 : data["main_page"]
       
       // les conversations
       this.conversations = data["conversations"]
+      
+      this.majBulle()
    }
 }
 
    }
 }
 
@@ -780,7 +867,7 @@ Client.prototype.flush = function(async)
    var thisClient = this
    var ok = true
    
    var thisClient = this
    var ok = true
    
-   ;;; dumpObj(this.getJSONProfile())
+   ;; dumpObj(this.getJSONProfile())
    jQuery.ajax(
       {
          async: async,
    jQuery.ajax(
       {
          async: async,
@@ -791,12 +878,16 @@ Client.prototype.flush = function(async)
          success:
             function(data)
             {
          success:
             function(data)
             {
-               ;;; dumpObj(data)
+               ;; dumpObj(data)
                if (data["reply"] == "error")
                {
                   thisClient.util.messageDialogue(data["error_message"])
                   ok = false
                }
                if (data["reply"] == "error")
                {
                   thisClient.util.messageDialogue(data["error_message"])
                   ok = false
                }
+               else
+               {
+                  thisClient.majBulle()
+               }
             }
       }
    )
             }
       }
    )
@@ -833,6 +924,14 @@ Client.prototype.majMenu = function()
    }
 }
 
    }
 }
 
+/**
+  * Met à jour l'affichage des infos bulles en fonction du profile.
+  */
+Client.prototype.majBulle = function()
+{
+   this.util.bulleActive = this.viewTooltips
+}
+
 Client.prototype.slap = function(userId, raison)
 {
    var thisClient = this
 Client.prototype.slap = function(userId, raison)
 {
    var thisClient = this
@@ -863,7 +962,7 @@ Client.prototype.ban = function(userId, raison, minutes)
 
    // par défaut un ban correspond à 3 jours
    if (typeof(minutes) == "undefined")
 
    // par défaut un ban correspond à 3 jours
    if (typeof(minutes) == "undefined")
-      minutes = 60 * 24 * 3
+      minutes = conf.tempsBan;
       
    jQuery.ajax({
       type: "POST",
       
    jQuery.ajax({
       type: "POST",
@@ -888,13 +987,23 @@ Client.prototype.ban = function(userId, raison, minutes)
 
 Client.prototype.kick = function(userId, raison)
 {
 
 Client.prototype.kick = function(userId, raison)
 {
-   this.ban(userId, raison, 15)
+   this.ban(userId, raison, conf.tempsKick)
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 /**
    * classe permettant de gérer les événements (push serveur).
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 /**
    * classe permettant de gérer les événements (push serveur).
+   * l'information envoyé est sous la forme :
+   *  {
+   *     "action" : "wait_event"
+   *     "page" : <page>
+   *     [..]
+   *  }
+   * l'information reçu est sous la forme :
+   *  {
+   *     "reply" : <reply>
+   *  }
    * @page la page
    */
 function PageEvent(page, util)
    * @page la page
    */
 function PageEvent(page, util)
@@ -904,6 +1013,9 @@ function PageEvent(page, util)
    
    // l'objet JSONHttpRequest représentant la connexion d'attente
    this.attenteCourante = null
    
    // l'objet JSONHttpRequest représentant la connexion d'attente
    this.attenteCourante = null
+   
+   // le multhreading du pauvre, merci javascript de m'offrire autant de primitives pour la gestion de la concurrence...
+   this.stop = false
 }
 
 /**
 }
 
 /**
@@ -911,22 +1023,30 @@ function PageEvent(page, util)
   */
 PageEvent.prototype.stopAttenteCourante = function()
 {
   */
 PageEvent.prototype.stopAttenteCourante = function()
 {
+   this.stop = true
+         
    if (this.attenteCourante != null)
    if (this.attenteCourante != null)
+   {
       this.attenteCourante.abort()   
       this.attenteCourante.abort()   
+   }
 }
 
 /**
   * Attend un événement lié à la page. 
   * @funSend une fonction renvoyant les données json à envoyer
 }
 
 /**
   * 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
+  * @funsReceive est un objet comprenant les fonctions à appeler en fonction du "reply"
+  * les fonctions acceptent un paramètre correspondant au données reçues.
+  * exemple : {"new_message" : function(data){ ... }}
   */
   */
-PageEvent.prototype.waitEvent = function(funSend, funReceive)
+PageEvent.prototype.waitEvent = function(funSend, funsReceive)
 {
 {
-   var thisPageEvent = this
-      
    this.stopAttenteCourante()
    this.stopAttenteCourante()
+   
+   this.stop = false
+   
+   var thisPageEvent = this
       
       
-   // on doit conserver l'ordre des valeurs de l'objet JSON (le serveur les veux dans l'ordre définit dans le protocole)
+   // on doit conserver l'ordre des valeurs de l'objet JSON (le serveur les veut dans l'ordre définit dans le protocole)
    // TODO : ya pas mieux ?
    var dataToSend = 
    {
    // TODO : ya pas mieux ?
    var dataToSend = 
    {
@@ -937,29 +1057,42 @@ PageEvent.prototype.waitEvent = function(funSend, funReceive)
    for (v in poulpe)
       dataToSend[v] = poulpe[v]
    
    for (v in poulpe)
       dataToSend[v] = poulpe[v]
    
-   ;;; dumpObj(dataToSend)
+   ;; dumpObj(dataToSend)
+   
    this.attenteCourante = jQuery.ajax({
       type: "POST",
       url: "request",
    this.attenteCourante = jQuery.ajax({
       type: "POST",
       url: "request",
-      dataType: "json",
+      dataType: "json",\r
+      // Obsolète (voir TODO)\r
+      //timeout: 300000, // timeout de 5min. Gros HACK pas beau. FIXME problème décrit ici : http://groups.google.com/group/jquery-en/browse_thread/thread/8724e64af3333a76
       data: this.util.jsonVersAction(dataToSend),
       success:
          function(data)
          {            
       data: this.util.jsonVersAction(dataToSend),
       success:
          function(data)
          {            
-            ;;; dumpObj(data)
+            ;; dumpObj(data)
             
             
-            funReceive(data)
+            funsReceive[data["reply"]](data)
             
             // rappel de la fonction dans 100 ms
             
             // rappel de la fonction dans 100 ms
-            setTimeout(function(){ thisPageEvent.waitEvent(funSend, funReceive) }, 100);
+            setTimeout(function(){ thisPageEvent.waitEvent2(funSend, funsReceive) }, 100)
          },
       error:
          function(XMLHttpRequest, textStatus, errorThrown)
          {
          },
       error:
          function(XMLHttpRequest, textStatus, errorThrown)
          {
-            setTimeout(function(){ thisPageEvent.waitEvent(funSend, funReceive) }, 1000);
+            ;; console.log("Connexion perdue dans waitEvent")
+            setTimeout(function(){ thisPageEvent.waitEvent2(funSend, funsReceive) }, 1000)
          }
    })
          }
    })
+}
 
 
+/**
+  * Si un stopAttenteCourante survient un peu n'importe quand il faut imédiatement arreter de boucler.
+  */
+PageEvent.prototype.waitEvent2 = function(funSend, funsReceive)
+{
+   if (this.stop)
+      return
+   this.waitEvent(funSend, funsReceive)
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -975,7 +1108,7 @@ function initialiserListeStyles(client)
 }
             
 // charge dynamiquement le script de debug
 }
             
 // charge dynamiquement le script de debug
-;;; jQuery.ajax({async : false, url : "js/debug.js", dataType : "script"})
+;; jQuery.ajax({async : false, url : "js/debug.js", dataType : "script"})
       \r
 // le main
 $(document).ready(
       \r
 // le main
 $(document).ready(
@@ -1011,12 +1144,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")
    }
 )