From 650c44a784cabc8a1f2bd1daa7e5e61ccf74ca6f Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Fri, 6 Jun 2008 21:07:26 +0000 Subject: [PATCH] REPORT de la branche 1.0 (tag 1.0.1) --- css/1/pageAbout.css | 10 + css/2/pageAbout.css | 10 + css/2/pageMinichat.css | 6 +- doc/TODO.txt | 44 ++- doc/technique.txt | 9 + js/euphorik.js | 494 ++++++++++++++++-------------- js/pageMinichat.js | 218 +++++++------ modules/erl/euphorik_bd.erl | 18 +- modules/erl/euphorik_daemon.erl | 3 +- modules/erl/euphorik_requests.erl | 15 +- modules/erl/euphorik_test.erl | 14 +- pages/about.html | 10 +- 12 files changed, 483 insertions(+), 368 deletions(-) diff --git a/css/1/pageAbout.css b/css/1/pageAbout.css index f21cd61..687e6d1 100644 --- a/css/1/pageAbout.css +++ b/css/1/pageAbout.css @@ -2,3 +2,13 @@ #page.about { } + +#page.about .faqCouleurProprietaire { + color: #31732f; +} +#page.about .faqCouleurReponse { + color: #bf2911; +} +#page.about .faqCouleurRepondu { + color: #84196c; +} diff --git a/css/2/pageAbout.css b/css/2/pageAbout.css index f21cd61..10eeae3 100644 --- a/css/2/pageAbout.css +++ b/css/2/pageAbout.css @@ -2,3 +2,13 @@ #page.about { } + +#page.about .faqCouleurProprietaire { + color: #31732f; +} +#page.about .faqCouleurReponse { + color: #bf2911; +} +#page.about .faqCouleurRepondu { + color: #84196c; +} \ No newline at end of file diff --git a/css/2/pageMinichat.css b/css/2/pageMinichat.css index 0c5b96a..f0e4785 100755 --- a/css/2/pageMinichat.css +++ b/css/2/pageMinichat.css @@ -139,13 +139,13 @@ zoom: 1 } #page.minichat #conversations div.reponse { - border-color: #bd7a11 + border-color: #bf2911 } #page.minichat #conversations div.repondu { - border-color: #b711bd + border-color: #84196c } #page.minichat #conversations div.proprietaire { - border-color: #bd1129 + border-color: #31732f } #page.minichat #conversations div.systeme { background-color: #555555 diff --git a/doc/TODO.txt b/doc/TODO.txt index 22ad3a2..cebd646 100755 --- a/doc/TODO.txt +++ b/doc/TODO.txt @@ -2,6 +2,7 @@ === v1.0.1 === * Pouvoir afficher les utilisateurs (print_users(admin)) qui sont admin +<<<<<<< .working * Mettre dans la FAQ la signification des couleurs associées aux messages. * Ne pas pouvoir poster avec "" * Ajouter euphorik_common.erl au repo !! @@ -13,6 +14,18 @@ * La compilation DOIT se faire sur la machine cible, il faut donc d'abord copier les fichiers dans /tmp sur euphorik.ch puis lancer la compilation à distance et finalement copier les fichiers sur /var/www/euphorik * Appliquer les flags suivant à Yaws : http://forum.trapexit.org/mailinglists/viewtopic.php?t=6725&sid=8729e02f79c3ef0e0794add77b74b6ce +======= +* Ne pas pouvoir poster avec "" -> mettre en constante +* Ajouter euphorik_common.erl au repo !! +* Compilation : + * Compiler avec le flag +debug_info pour le developpement + * Compiler avec le flag +native lors de la mise en production + * Faire d'abord des tests en local pour voir s'il y a vraiment des gains, utiliser le module test_euphorik + * Regarder également si la comsommation de la mémoire est différentes + * La compilation DOIT se faire sur la machine cible, il faut donc d'abord copier les fichiers dans /tmp sur euphorik.ch + puis lancer la compilation à distance et finalement copier les fichiers sur /var/www/euphorik +* Appliquer les flags suivant à Yaws : http://forum.trapexit.org/mailinglists/viewtopic.php?t=6725&sid=8729e02f79c3ef0e0794add77b74b6ce +>>>>>>> .merge-right.r271 === v1.1 === * Revoir le système de conversation : * Pouvoir extraire "toute la conversation" ou seulement une "sous conversation" (ce qui est actuellement le cas) @@ -193,23 +206,35 @@ * processus : 1) copie des fichiers (+minimisation) 2) Execution d'un scripte erlang pour recharger tous les modules au sein du noeud - 3) Executer euphorik_bd:update() pour mettre à jour la BD + 3) Executer euphorik_bd:update() pour mettre à jour la BD [ok] Ajouter dans la FAQ et/ou dans la page d'enregistrement les conditions d'utilisation, genre "chacun est responsable de ses dires" https://linuxfr.org/bouchot/ [ok] Limiter la mise en évidence de la conversation lorsque le curseur se trouve sur les pseudos [ok] Cleaner le code (erl, js, xhtml, css) et eventuellement profiler un peu (le refresh est lent sous opera) [ok] Afficher l'ip dans le print_users(). [ok] Enlever le petit carré mis en couleur et mettre le pseudo + date en couleur à la place - +[ok] Mettre dans la FAQ la signification des couleurs associées aux messages. + + === Bugs === 1 : Critique 2 : Urgent 3 : Peu grave [1] Il arrive qu'après le poste d'un message le refresh ne se fasse plus, peut-être une "race-condition" dans la classe PageEvent de euphorik.js - * Observé uniquement sur Firefox - * Après quelques analyses il apparait que firefox attend alors que le processus n'existe plus du coté yaws + * Observé sur opera et firefox + * Après quelques analyses il apparait que firefox attend alors que le processus n'existe plus du coté yaws + * Cela arrive après 5-10min + * Regarder du coté des paramètres (options) du socket coté yaws s'il n'y a pas un indice, par exemple un timeout + * solution de secours : timeout de (1 à 5 min) sur la connexion ajax + * Est-ce que yaws tient compte du "Keep-Alive 300" de l'entête HTTP ? (=5min) (normalement pas puisque HTTP/1.1) après avoir regardé les sources il me semble que non + * Normalement si le socket est fermé du coté de yaws, le client devrait être avertis... !? + * Après beaucoup d'investigation il semblerai que se soit le firewall/routeur qui coupe la connexion sans prévenir, + pour éviter cela il est possible de mettre 'keepalive' à true au niveau du socket, voir : + - http://erlang.org/doc/man/inet.html#setopts-2 + - http://forums.globalscape.com/tm.aspx?m=4114 +[2] Le minificateur js doit ajouter un espace après une expression régulière sinon il est possible que le caractère qui suit celle ci soit pris pour un modificateur de la regexp [2] Le widget select qui permet la sélection des css n'est pas initialisé correctement au chargement du site -[2] Traiter les tags TODO et FIXME dans le code +[2] Traiter les tags TODO et FIXME dans le code [2] Le changement de skin n'est pas mémorisé lorsque l'on est pas connecté (normal puisque le style est mémorisé dans le profil) * solution 1 : permettre le changement de skin uniquement pour les personnes enregistré ? * solution 2 : mémoriser le skin courant dans un cookie @@ -218,7 +243,6 @@ [2] Plein de bugs sous MS internet explorer 7 * click sur le lien du conv insère sont id systématiquement au début du message * le changement de skin foire complétement -[2] griser le login dans le profil pour montrer qu'on ne peut pas l'éditer [3] Quand on revient en arrière dans firefox le message en rédaction est perdu * Pas sous Opera, apparemment Firefox recharge toute la page (donc impossible qu'il puisse remettre le message) * Eventuellement sauvegarder le message en rédaction dans le profile... @@ -269,8 +293,16 @@ * Peut être un bug lié à jQuery * Reproduit sur Firefox 2 et 3 ! [ok] Lors d'un logout il faut faire un full refresh (pour mettre à jour les messages auquel on répond par exemple) +<<<<<<< .working +[ok] Après être passé de la page Admin à Chat le client continu de réaliser de temps en temp des requêtes "lists_banned_ips" + * action=%7B%22action%22%3A%22list_banned_ips%22%2C%22cookie%22%3A%22<>%22%7D +======= [ok] Après être passé de la page Admin à Chat le client continu de réaliser de temps en temp des requêtes "lists_banned_ips" * action=%7B%22action%22%3A%22list_banned_ips%22%2C%22cookie%22%3A%22<>%22%7D +[ok] Le widget select qui permet la sélection des css n'est pas initialisé correctement au chargement du site +[ok] Il est possible d'envoyer plusieurs fois le même message en pressant très rapidement plusieurs fois sur ENTER... (à vérifier) +[ok] griser le login dans le profil pour montrer qu'on ne peut pas l'éditer +>>>>>>> .merge-right.r271 === Idées === Une fois l'idée validée elle est déplacée dans une version à venir. diff --git a/doc/technique.txt b/doc/technique.txt index 1d45db1..74a6360 100644 --- a/doc/technique.txt +++ b/doc/technique.txt @@ -12,6 +12,15 @@ Sequences : * Conversation * Message +=== Compilation avec +native === +Mesure du temps d'execution pour : + * euphorik_test:start(20, 20) : 20 personnes postants 20 messages + sans +native : 3:39 + avec +native : 3.41 + +Conclusion : + l'ajout de +native n'a pas de répercussions significatives sur les performances, cela provient + surement du fait que le gros du travail est fait du coté de la base de donnée Mnesia. === Séquences === * Attente de nouveaux messages diff --git a/js/euphorik.js b/js/euphorik.js index f330209..e564583 100755 --- a/js/euphorik.js +++ b/js/euphorik.js @@ -1,23 +1,23 @@ -// 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 . - -/** - * Contient la base javascript pour le site euphorik.ch. +// 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 . + +/** + * Contient la base javascript pour le site euphorik.ch. * Chaque page possède son propre fichier js nommé "page.js". * Auteur : GBurri * Date : 6.11.2007 @@ -25,66 +25,66 @@ /** - * La configuration. + * La configuration. * Normalement 'const' à la place de 'var' mais non supporté par IE7. - */ -var conf = { + */ +var conf = { nbMessageAffiche : 40, // (par page) - pseudoDefaut : "", + pseudoDefaut : "", tempsAffichageMessageDialogue : 4000, // en ms tempsKick : 15, // en minute - tempsBan : 60 * 24 * 3, // en minutes (3jours) - smiles : { - "smile" : [/:\)/g, /:-\)/g], - "bigsmile" : [/:D/g, /:-D/g], - "clin" : [/;\)/g, /;-\)/g], - "cool" : [/8\)/g, /8-\)/g], + tempsBan : 60 * 24 * 3, // en minutes (3jours) + smiles : { + "smile" : [/:\)/g, /:-\)/g], + "bigsmile" : [/:D/g, /:-D/g], + "clin" : [/;\)/g, /;-\)/g], + "cool" : [/8\)/g, /8-\)/g], "eheheh" : [/:P/g, /:-P/g], "lol" : [/\[-lol\]/g], - "spliff" : [/\[-spliff\]/g], + "spliff" : [/\[-spliff\]/g], "oh" : [/:o/g, /:O/g], "heink" : [/\[-heink\]/g], "hum" : [/\[-hum\]/g], "boh" : [/\[-boh\]/g], "sniff" : [/:\(/g, /:-\(/g], - "triste" : [/\[-triste\]/g], - "pascontent" : [/>\(/g, />\(/g], + "triste" : [/\[-triste\]/g], + "pascontent" : [/>\(/g, />\(/g], "argn" : [/\[-argn\]/g], - "redface" : [/\[-redface\]/g], - "bunny" : [/\[-lapin\]/g], - "chat" : [/\[-chat\]/g], - "renne" : [/\[-renne\]/g], - "star" : [/\[-star\]/g], + "redface" : [/\[-redface\]/g], + "bunny" : [/\[-lapin\]/g], + "chat" : [/\[-chat\]/g], + "renne" : [/\[-renne\]/g], + "star" : [/\[-star\]/g], "kirby" : [/\[-kirby\]/g], "slurp" : [/\[-slurp\]/g], "agreed" : [/\[-agreed\]/g], "dodo" : [/\[-dodo\]/g], - "bn" : [/\[-bn\]/g] - } -} + "bn" : [/\[-bn\]/g] + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +String.prototype.trim = function() +{ + return jQuery.trim(this) // anciennement : this.replace(/^\s+|\s+$/g, ""); +} + +String.prototype.ltrim = function() +{ + return this.replace(/^\s+/, ""); +} + +String.prototype.rtrim = function() +{ + return this.replace(/\s+$/, ""); +} /////////////////////////////////////////////////////////////////////////////////////////////////// - -String.prototype.trim = function() -{ - return jQuery.trim(this) // anciennement : this.replace(/^\s+|\s+$/g, ""); -} - -String.prototype.ltrim = function() -{ - return this.replace(/^\s+/, ""); -} - -String.prototype.rtrim = function() -{ - return this.replace(/\s+$/, ""); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -/** + +/** * Cette classe regroupe des fonctions utilitaires (helpers). - * @formateur est permet de formater les messages affichés à l'aide de messageDialogue (facultatif) + * @formateur est permet de formater les messages affichés à l'aide de messageDialogue (facultatif) */ function Util(formateur) { @@ -102,9 +102,9 @@ var messageType = {informatif: 0, question: 1, erreur: 2} /** * Affiche une boite de dialogue avec un message à l'intérieur. - * @param message le message (string) - * @param type voir 'messageType'. par défaut messageType.informatif - * @param les boutons sous la forme d'un objet ou les clefs sont les labels des boutons + * @param message le message (string) + * @param type voir 'messageType'. par défaut messageType.informatif + * @param les boutons sous la forme d'un objet ou les clefs sont les labels des boutons * et les valeurs les fonctions executées lorsqu'un bouton est activé. * @param formate faut-il formaté le message ? true par défaut */ @@ -137,7 +137,7 @@ Util.prototype.messageDialogue = function(message, type, boutons, formate) $("#info").slideDown(200) this.timeoutMessageDialogue = setTimeout(fermer, conf.tempsAffichageMessageDialogue) -} +} /** * Affiche un info bulle lorsque le curseur survole l'élément donné. @@ -158,12 +158,17 @@ Util.prototype.infoBulle = function(message, element) { if (!thisUtil.bulleActive) return - + var m = $("#messageBulle") var f = $("#flecheBulle") + // remplie le paragraphe de la bulle avec le message $("p", m).html(message) - + + // réinitialise la position, évite le cas ou la boite est collé à droite et remplie avec un texte la faisant dépassé + // dans ce cas la hauteur n'est pas calculé correctement + m.css("top", 0).css("left", 0) + var positionFleche = { left : element.offset().left + element.width() / 2 - f.width() / 2, top : element.offset().top - f.height() @@ -195,76 +200,76 @@ Util.prototype.jsonVersAction = function(json) { return {action : JSON.stringify(json) } } - -Util.prototype.md5 = function(chaine) -{ - return hex_md5(chaine) + +Util.prototype.md5 = function(chaine) +{ + return hex_md5(chaine) } - -// pompé de http://www.faqts.com/knowledge_base/view.phtml/aid/13562/fid/130 + +// pompé de http://www.faqts.com/knowledge_base/view.phtml/aid/13562/fid/130 Util.prototype.setSelectionRange = function(input, selectionStart, selectionEnd) -{ +{ if (input.setSelectionRange) - { - input.focus() - input.setSelectionRange(selectionStart, selectionEnd) - } + { + input.focus() + input.setSelectionRange(selectionStart, selectionEnd) + } else if (input.createTextRange) - { - var range = input.createTextRange() - range.collapse(true) - range.moveEnd('character', selectionEnd) - range.moveStart('character', selectionStart) - range.select() - } -} - + { + var range = input.createTextRange() + range.collapse(true) + range.moveEnd('character', selectionEnd) + range.moveStart('character', selectionStart) + range.select() + } +} + Util.prototype.setCaretToEnd = function(input) -{ - this.setSelectionRange(input, input.value.length, input.value.length) -} +{ + this.setSelectionRange(input, input.value.length, input.value.length) +} Util.prototype.setCaretToBegin = function(input) -{ - this.setSelectionRange(input, 0, 0) -} +{ + this.setSelectionRange(input, 0, 0) +} Util.prototype.setCaretToPos = function(input, pos) -{ - this.setSelectionRange(input, pos, pos) -} +{ + this.setSelectionRange(input, pos, pos) +} Util.prototype.selectString = function(input, string) -{ - var match = new RegExp(string, "i").exec(input.value) +{ + var match = new RegExp(string, "i").exec(input.value) if (match) - { - this.setSelectionRange (input, match.index, match.index + match[0].length) - } -} -Util.prototype.replaceSelection = function(input, replaceString) { + { + this.setSelectionRange (input, match.index, match.index + match[0].length) + } +} +Util.prototype.replaceSelection = function(input, replaceString) { if (input.setSelectionRange) - { - var selectionStart = input.selectionStart - var selectionEnd = input.selectionEnd + { + var selectionStart = input.selectionStart + var selectionEnd = input.selectionEnd input.value = input.value.substring(0, selectionStart) + replaceString + input.value.substring(selectionEnd) - - if (selectionStart != selectionEnd) // has there been a selection - this.setSelectionRange(input, selectionStart, selectionStart + replaceString.length) - else // set caret - this.setCaretToPos(input, selectionStart + replaceString.length) - } + + if (selectionStart != selectionEnd) // has there been a selection + this.setSelectionRange(input, selectionStart, selectionStart + replaceString.length) + else // set caret + this.setCaretToPos(input, selectionStart + replaceString.length) + } else if (document.selection) { - input.focus() - var range = document.selection.createRange() + input.focus() + var range = document.selection.createRange() if (range.parentElement() == input) - { - var isCollapsed = range.text == '' - range.text = replaceString + { + var isCollapsed = range.text == '' + range.text = replaceString if (!isCollapsed) - { - range.moveStart('character', -replaceString.length); - } - } - } + { + range.moveStart('character', -replaceString.length); + } + } + } } Util.prototype.rot13 = function(chaine) @@ -316,8 +321,8 @@ Pages.prototype.ajouterPage = function(page) } Pages.prototype.afficherPage = function(nomPage, forcerChargement) -{ - if (forcerChargement == undefined) forcerChargement = false +{ + if (forcerChargement == undefined) forcerChargement = false var page = this.pages[nomPage] if (page == undefined || (!forcerChargement && page == this.pageCourante)) return @@ -349,13 +354,13 @@ Pages.prototype.afficherPage = function(nomPage, forcerChargement) */ function Formateur() { - this.smiles = conf.smiles - this.protocoles = "http|https|ed2k" - - this.regexUrl = new RegExp("(?:(?:" + this.protocoles + ")://|www\\.)[^ ]*", "gi") - this.regexImg = new RegExp("^.*?\\.(gif|jpg|png|jpeg|bmp|tiff)$", "i") - this.regexDomaine = new RegExp("^(?:(?:" + this.protocoles + ")://|www\\.).*?([^/.]+\\.[^/.]+)(?:$|/).*$", "i") - this.regexTestProtocoleExiste = new RegExp("^(?:" + this.protocoles + ")://.*$", "i") + this.smiles = conf.smiles + this.protocoles = "http|https|ed2k" + + this.regexUrl = new RegExp("(?:(?:" + this.protocoles + ")://|www\\.)[^ ]*", "gi") + this.regexImg = new RegExp("^.*?\\.(gif|jpg|png|jpeg|bmp|tiff)$", "i") + this.regexDomaine = new RegExp("^(?:(?:" + this.protocoles + ")://|www\\.).*?([^/.]+\\.[^/.]+)(?:$|/).*$", "i") + this.regexTestProtocoleExiste = new RegExp("^(?:" + this.protocoles + ")://.*$", "i") this.regexNomProtocole = new RegExp("^(.*?)://") } @@ -368,16 +373,16 @@ Formateur.prototype.filtrerInputPseudo = function(pseudo) { return pseudo.replace(/{|}/g, "").trim() } - -Formateur.prototype.getSmilesHTML = function() -{ - var XHTML = "" - for (var sNom in this.smiles) - { - XHTML += "\""" - } - return XHTML -} + +Formateur.prototype.getSmilesHTML = function() +{ + var XHTML = "" + for (var sNom in this.smiles) + { + XHTML += "\""" + } + return XHTML +} /** * Formatage complet d'un texte. @@ -405,10 +410,10 @@ Formateur.prototype.traiterLiensConv = function(M) } ) } - -/** + +/** * FIXME : Cette méthode est attrocement lourde ! A optimiser. - * moyenne sur échantillon : 234ms + * moyenne sur échantillon : 234ms */ Formateur.prototype.traiterSmiles = function(M) { @@ -431,9 +436,9 @@ Formateur.prototype.traiterURL = function(M, pseudo) thisFormateur = this var traitementUrl = function(url) - { - // si ya pas de protocole on rajoute "http://" - if (!thisFormateur.regexTestProtocoleExiste.test(url)) + { + // si ya pas de protocole on rajoute "http://" + if (!thisFormateur.regexTestProtocoleExiste.test(url)) url = "http://" + url var extension = thisFormateur.getShort(url) return "[" + extension[0] + "]" @@ -461,35 +466,35 @@ Formateur.prototype.traiterWikiSyntaxe = function(M) } ) } - -/** - * Renvoie une version courte de l'url. - * par exemple : http://en.wikipedia.org/wiki/Yakov_Smirnoff devient wikipedia.org + +/** + * Renvoie une version courte de l'url. + * par exemple : http://en.wikipedia.org/wiki/Yakov_Smirnoff devient wikipedia.org */ Formateur.prototype.getShort = function(url) -{ +{ var estUneImage = false var versionShort = null var rechercheImg = this.regexImg.exec(url) - if (rechercheImg != null) + if (rechercheImg != null) { - versionShort = rechercheImg[1].toLowerCase() - if (versionShort == "jpeg") versionShort = "jpg" // jpeg -> jpg - estUneImage = true - } - else - { - var rechercheDomaine = this.regexDomaine.exec(url) - if (rechercheDomaine != null && rechercheDomaine.length >= 2) - versionShort = rechercheDomaine[1] - else - { - var nomProtocole = this.regexNomProtocole.exec(url) - if (nomProtocole != null && nomProtocole.length >= 2) - versionShort = nomProtocole[1] - } - } + versionShort = rechercheImg[1].toLowerCase() + if (versionShort == "jpeg") versionShort = "jpg" // jpeg -> jpg + estUneImage = true + } + else + { + var rechercheDomaine = this.regexDomaine.exec(url) + if (rechercheDomaine != null && rechercheDomaine.length >= 2) + versionShort = rechercheDomaine[1] + else + { + var nomProtocole = this.regexNomProtocole.exec(url) + if (nomProtocole != null && nomProtocole.length >= 2) + versionShort = nomProtocole[1] + } + } return [versionShort == null ? "url" : versionShort, estUneImage] } @@ -504,7 +509,7 @@ Formateur.prototype.traiterPourFenetreLightBox = function(M, urlCourante) { return "[" + thisFormateur.getShort(url)[0] + (urlCourante == url ? "*" : "") + "]" } - + return this.remplacerBalisesHTML(M).replace(this.regexUrl, traitementUrl) } @@ -520,30 +525,30 @@ var statutType = { // mode déconnecté, ne peut pas poster de message deconnected : 2 } - -function Client(util) + +function Client(util) { this.util = util - + this.cookie = null this.regexCookie = new RegExp("^cookie=([^;]*)") - // données personnels + // données personnels this.resetDonneesPersonnelles() - this.setStatut(statutType.deconnected) - - // si true alors chaque modification du client est mémorisé sur le serveur - this.autoflush = $.browser["opera"] + this.setStatut(statutType.deconnected) + + // si true alors chaque modification du client est mémorisé sur le serveur + this.autoflush = $.browser["opera"] } - -Client.prototype.resetDonneesPersonnelles = function() + +Client.prototype.resetDonneesPersonnelles = function() { - this.id = 0 - this.pseudo = conf.pseudoDefaut - this.login = "" - this.password = "" - this.email = "" + this.id = 0 + this.pseudo = conf.pseudoDefaut + this.login = "" + this.password = "" + this.email = "" this.css = $("link#cssPrincipale").attr("href") this.nickFormat = "nick" this.viewTimes = true @@ -556,7 +561,7 @@ Client.prototype.resetDonneesPersonnelles = function() // les conversations, une conversation est un objet possédant les attributs suivants : // - racine (entier) // - page (entier) - this.conversations = new Array() + this.conversations = new Array() } Client.prototype.setCss = function(css) @@ -566,8 +571,6 @@ Client.prototype.setCss = function(css) this.css = css $("link#cssPrincipale").attr("href", this.css) - this.majMenu() - if (this.autoflush) this.flush(true) } @@ -621,9 +624,9 @@ Client.prototype.ajouterConversation = function(racine) if (this.conversations[i].root == racine) return false - this.conversations.push({root : racine, page : 1}) - - if (this.autoflush) this.flush(true) + this.conversations.push({root : racine, page : 1}) + + if (this.autoflush) this.flush(true) return true } @@ -635,8 +638,8 @@ 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] - this.conversations.pop() - + this.conversations.pop() + if (this.autoflush) this.flush(true) } @@ -708,11 +711,11 @@ Client.prototype.getCookie = function() var cookie = this.regexCookie.exec(document.cookie) if (cookie == null) this.cookie = null else this.cookie = cookie[1] -} - -Client.prototype.delCookie = function() -{ - document.cookie = "cookie=; max-age=0" +} + +Client.prototype.delCookie = function() +{ + document.cookie = "cookie=; max-age=0" } Client.prototype.setCookie = function() @@ -734,38 +737,38 @@ Client.prototype.authentifie = function() Client.prototype.setStatut = function(statut) { - // conversation en "enum" si en "string" - if (typeof(statut) == "string") + // conversation en "enum" si en "string" + if (typeof(statut) == "string") { statut = statut == "auth_registered" ? statutType.auth_registered : - (statut == "auth_not_registered" ? statutType.auth_not_registered : statutType.deconnected) - } - - if (statut == this.statut) return - - this.statut = statut + (statut == "auth_not_registered" ? statutType.auth_not_registered : statutType.deconnected) + } + + if (statut == this.statut) return + + this.statut = statut this.majMenu() } - -/** - * Effectue la connexion vers le serveur. - * Cette fonction est bloquante tant que la connexion n'a pas été établie. - * S'il existe un cookie en local on s'authentifie directement avec lui. - * Si il n'est pas possible de s'authentifier alors on affiche un captcha anti-bot. - */ -Client.prototype.connexionCookie = function() -{ - this.getCookie() + +/** + * Effectue la connexion vers le serveur. + * Cette fonction est bloquante tant que la connexion n'a pas été établie. + * S'il existe un cookie en local on s'authentifie directement avec lui. + * Si il n'est pas possible de s'authentifier alors on affiche un captcha anti-bot. + */ +Client.prototype.connexionCookie = function() +{ + this.getCookie() if (this.cookie == null) return false; - return this.connexion(this.getJSONLoginCookie()) + return this.connexion(this.getJSONLoginCookie()) } Client.prototype.connexionLogin = function(login, password) { return this.connexion(this.getJSONLogin(login, password)) -} +} Client.prototype.enregistrement = function(login, password) { @@ -780,9 +783,9 @@ Client.prototype.enregistrement = function(login, password) } return false } - else + else { - return this.connexion(this.getJSONEnregistrement(login, password)) + return this.connexion(this.getJSONEnregistrement(login, password)) } } @@ -809,14 +812,14 @@ Client.prototype.connexion = function(messageJson) } ) return this.authentifie() -} - -Client.prototype.deconnexion = function() +} + +Client.prototype.deconnexion = function() { this.flush(true) this.delCookie() - this.resetDonneesPersonnelles() - this.setStatut(statutType.deconnected) // deconnexion + this.resetDonneesPersonnelles() + this.setStatut(statutType.deconnected) // deconnexion } Client.prototype.chargerDonnees = function(data) @@ -832,10 +835,10 @@ Client.prototype.chargerDonnees = function(data) this.cookie = data["cookie"] this.setCookie() - this.id = data["id"] + this.id = data["id"] this.login = data["login"] - this.pseudo = data["nick"] - this.email = data["email"] + this.pseudo = data["nick"] + this.email = data["email"] this.setCss(data["css"]) this.nickFormat = data["nick_format"] this.viewTimes = data["view_times"] @@ -848,6 +851,7 @@ Client.prototype.chargerDonnees = function(data) this.conversations = data["conversations"] this.majBulle() + this.majCssSelectionee() } } @@ -897,8 +901,6 @@ Client.prototype.flush = function(async) 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 displayType = "block" $("#menu .admin").css("display", this.ekMaster ? displayType : "none") @@ -906,19 +908,19 @@ Client.prototype.majMenu = function() // met à jour le menu if (this.statut == statutType.auth_registered) { - $("#menu .profile").css("display", displayType).text("profile") + $("#menu .profile").css("display", displayType).text("profile") $("#menu .logout").css("display", displayType) $("#menu .register").css("display", "none") } else if (this.statut == statutType.auth_not_registered) { - $("#menu .profile").css("display", "none") + $("#menu .profile").css("display", "none") $("#menu .logout").css("display", displayType) $("#menu .register").css("display", displayType) } else { - $("#menu .profile").css("display", displayType).text("login") + $("#menu .profile").css("display", displayType).text("login") $("#menu .logout").css("display", "none") $("#menu .register").css("display", displayType) } @@ -932,6 +934,20 @@ Client.prototype.majBulle = function() this.util.bulleActive = this.viewTooltips } +/** + * Met à jour la css sélectionnée, lors du chargement des données. + */ +Client.prototype.majCssSelectionee = function() +{ + // extraction du numéro de la css courante + var numCssCourante = this.css.match(/^.*?\/(\d)\/.*$/) + if (numCssCourante[1] != undefined) + { + $("#menuCss option").removeAttr("selected") + $("#menuCss option[value=" + numCssCourante[1]+ "]").attr("selected", "selected") + } +} + Client.prototype.slap = function(userId, raison) { var thisClient = this @@ -1064,6 +1080,8 @@ PageEvent.prototype.waitEvent = function(funSend, funsReceive) url: "request", dataType: "json", 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 + // Obsolète (voir TODO) + //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) @@ -1108,7 +1126,7 @@ function initialiserListeStyles(client) // charge dynamiquement le script de debug ;; jQuery.ajax({async : false, url : "js/debug.js", dataType : "script"}) - + // le main $(document).ready( function() @@ -1116,9 +1134,9 @@ $(document).ready( var formateur = new Formateur() var util = new Util(formateur) var client = new Client(util) - var pages = new Pages() - - // connexion vers le serveur (utilise un cookie qui traine) + var pages = new Pages() + + // connexion vers le serveur (utilise un cookie qui traine) client.connexionCookie() initialiserListeStyles(client) @@ -1129,7 +1147,7 @@ $(document).ready( $("#menu .minichat").click(function(){ pages.afficherPage("minichat") }) $("#menu .admin").click(function(){ pages.afficherPage("admin") }) - $("#menu .profile").click(function(){ pages.afficherPage("profile") }) + $("#menu .profile").click(function(){ pages.afficherPage("profile") }) $("#menu .logout").click(function(){ util.messageDialogue("Êtes-vous sur de vouloir vous délogger ?", messageType.question, {"Oui" : function() diff --git a/js/pageMinichat.js b/js/pageMinichat.js index 03024bc..da53627 100755 --- a/js/pageMinichat.js +++ b/js/pageMinichat.js @@ -1,19 +1,19 @@ -// 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, -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License +// 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, +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// 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 . function PageMinichat(client, formateur, util) @@ -24,6 +24,10 @@ function PageMinichat(client, formateur, util) this.formateur = formateur this.util = util + // permet d'éviter d'envoyer plusieurs messages simultanément en pressant + // rapidement sur "enter" par exemple + this.envoieMessageEnCours = false + this.regexMessageTagMatch = /\{.*?\}>/g this.regexMessageTagReplace = /^(.*?\{.*?\}>)*/ } @@ -54,7 +58,7 @@ PageMinichat.prototype.charger = function() this.messages = new Messages(this.client, this.formateur, this.util) this.messages.rafraichirMessages(true) - + this.util.setCaretToEnd($("form input.message")[0]) // les outils de bannissement (uniquement pour les ekMaster) @@ -173,9 +177,9 @@ PageMinichat.prototype.getJSONMessage = function(pseudo, message, repondA) } PageMinichat.prototype.envoyerMessage = function(pseudo, message) -{ +{ var thisPageMinichat = this - + // (un pseudo vide est autorisé) pseudo = this.formateur.filtrerInputPseudo(pseudo) @@ -187,53 +191,75 @@ PageMinichat.prototype.envoyerMessage = function(pseudo, message) for(var i = 0; i < tags.length; i++) repondA.push(parseInt(/\{(.*?)\}>/.exec(tags[i])[1], 36)) message = message.replace(this.regexMessageTagReplace, "") - } - - message = message.trim() - if (message == "") + } + + message = message.trim() + if (message == "") { - this.util.messageDialogue("Le message est vide") - return - } - - if (!this.client.authentifie()) - if (!this.client.enregistrement()) - { - this.util.messageDialogue("login impossible") - return + this.util.messageDialogue("Le message est vide") + return + } + + if (!this.client.authentifie()) + if (!this.client.enregistrement()) + { + this.util.messageDialogue("login impossible") + return } - this.client.pseudo = pseudo - - ;; dumpObj(this.getJSONMessage(pseudo, message, repondA)) - jQuery.ajax( - { - url : "request", - type: "POST", - data : this.util.jsonVersAction(this.getJSONMessage(pseudo, message, repondA)), + this.client.pseudo = pseudo + + // évite le double post + if (this.envoieMessageEnCours) + { + this.util.messageDialogue("Message en cours d'envoie...") + return + } + this.envoieMessageEnCours = true + + ;; dumpObj(this.getJSONMessage(pseudo, message, repondA)) + jQuery.ajax( + { + url : "request", + type: "POST", + data : this.util.jsonVersAction(this.getJSONMessage(pseudo, message, repondA)), dataType : "json", beforeSend : function(xmlHttpRequest) { + // TODO : ça marche ça ?? xmlHttpRequest.setRequestHeader("X-Requested-With", "") - }, - success : function(data, textStatus) + }, + success : function(data, textStatus) { ;; dumpObj(data) if(data["reply"] == "ok") - { + { $("form input.message").val("") // met à jour la classe des messages auquel repond celui ci (c'est un peu de la triche) TODO : ya mieux ? for (var i = 0; i < repondA.length; i++) + { + for (var j = 0; j < thisPageMinichat.messages.conversations.length; j++) + { + var mess = thisPageMinichat.messages.conversations[j].messagesParId[repondA[i]] + if (mess != undefined) + mess.clientARepondu = true + } $("#conversations div#mess" + repondA[i].toString(36)).addClass("repondu") + } } else if (data["reply"] == "error") { thisPageMinichat.util.messageDialogue(data["error_message"]) - } - } - } + } + thisPageMinichat.envoieMessageEnCours = false + }, + error : function() + { + thisPageMinichat.envoieMessageEnCours = false + } + } ) } @@ -561,7 +587,7 @@ Conversation.prototype.flush = function(funClickOuvrirConv) var DOM = $(XHTML) DOM.each( function() - { + { $(".lienConv", this).click( function(event) { @@ -570,6 +596,49 @@ Conversation.prototype.flush = function(funClickOuvrirConv) funClickOuvrirConv(parseInt(racine.substring(1, racine.length - 1), 36)) return false } + ) + + thisConversation.util.infoBulle("Extraction de la conversation", $(".extraire", this)) + + // l'id du message + var idMess36 = $(this).attr("id").substr(4) + var idMess = parseInt(idMess36, 36) + + $(this).click( + function(event) + { + if ($(event.target).is("a") || $(event.target).parents("#outilsBan").length > 0) return + + // extraction d'une conversation + if ($(event.target).is(".extraire")) + { + funClickOuvrirConv(idMess) + return + } + + var valCourant = $("input.message").val() + if (valCourant == undefined) valCourant = "" + var tag = $(".pseudo span.ident", this).text() + "{" + idMess36 + "}" + ">" + if (valCourant.indexOf(tag, 0) == -1) + $("input.message").val(tag + " " + valCourant) + thisConversation.util.setCaretToEnd($("form input.message")[0]) + } + ) + + // mise en évidence de la conversation + $(".entete", this).hover( + function() + { + thisConversation.decolorerEntetes() + thisConversation.afficherConversation(idMess) + }, + // quand on sort de l'entête du message la mise en évidence est enlevée + function() + { + thisConversation.enleverMiseEnEvidence() + thisConversation.decolorerEntetes() + thisConversation.colorerEntetes() + } ) if (thisConversation.client.viewTimes) @@ -619,50 +688,7 @@ Conversation.prototype.flush = function(funClickOuvrirConv) { $("#outilsBan", this).hide() } - ) - - thisConversation.util.infoBulle("Extraction de la conversation", $(".extraire", this)) - - // l'id du message - var idMess36 = $(this).attr("id").substr(4) - var idMess = parseInt(idMess36, 36) - - $(this).click( - function(event) - { - if ($(event.target).is("a") || $(event.target).parents("#outilsBan").length > 0) return - - // extraction d'une conversation - if ($(event.target).is(".extraire")) - { - funClickOuvrirConv(idMess) - return - } - - var valCourant = $("input.message").val() - if (valCourant == undefined) valCourant = "" - var tag = $(".pseudo span.ident", this).text() + "{" + idMess36 + "}" + ">" - if (valCourant.indexOf(tag, 0) == -1) - $("input.message").val(tag + " " + valCourant) - thisConversation.util.setCaretToEnd($("form input.message")[0]) - } - ) - - // mise en évidence de la conversation - $(".entete", this).hover( - function() - { - thisConversation.decolorerEntetes() - thisConversation.afficherConversation(idMess) - }, - // quand on sort de l'entête du message la mise en évidence est enlevée - function() - { - thisConversation.enleverMiseEnEvidence() - thisConversation.decolorerEntetes() - thisConversation.colorerEntetes() - } - ) + ) } ) DOM.prependTo("#conversations #" + this.getId()) @@ -817,7 +843,7 @@ Messages.prototype.ajouterMessage = function(element, numConversation) element["nick"], element["login"], element["content"] - ) + ) message.appartientAuClient = element["owner"] message.clientARepondu = element["answered"] @@ -904,10 +930,10 @@ Messages.prototype.supprimerConversation = function(num) * Ajuste la largeur des conversations en fonction de leur nombre. modifie l'attribut CSS 'width'. */ Messages.prototype.ajusterLargeurConversations = function() -{ - var largeurPourcent = (100 / this.conversations.length) - // le "- 0.01" evite que IE se chie dessus lamentablement et affiche les conversations les unes au dessus des autres - if($.browser["msie"]) +{ + var largeurPourcent = (100 / this.conversations.length) + // le "- 0.01" evite que IE se chie dessus lamentablement et affiche les conversations les unes au dessus des autres + if($.browser["msie"]) largeurPourcent -= 0.05 $("#conversations .conversation").css("width", largeurPourcent + "%") } diff --git a/modules/erl/euphorik_bd.erl b/modules/erl/euphorik_bd.erl index 2b18d5b..b72d7a8 100755 --- a/modules/erl/euphorik_bd.erl +++ b/modules/erl/euphorik_bd.erl @@ -303,12 +303,19 @@ update_pseudo_user(UserId, Pseudo) -> % Affiche N user trié par leur date de dernière connexion. -print_users(N) -> +% Opt est une liste d'option d'affichage : +% * ekmaster : n'affiche que les admins +print_users(N, Opt) -> + AfficheQueLesEkMaster = lists:any(fun(O) -> O =:= ekmaster end, Opt), resultat_transaction(mnesia:transaction(fun() -> C = cursor( qlc:keysort( #user.date_derniere_connexion, - q([E || E <- mnesia:table(user)]), + if AfficheQueLesEkMaster -> + q([E || E <- mnesia:table(user), E#user.ek_master =:= true]); + true -> + q([E || E <- mnesia:table(user)]) + end, [{order, descending}] ), [{tmpdir, ?KEY_SORT_TEMP_DIR}] @@ -324,10 +331,13 @@ print_users(N) -> end)). +% Affiche tous les users. +print_users(Opt) -> + print_users(all_remaining, Opt). + % Affiche tous les users. print_users() -> - print_users(all_remaining). - + print_users(all_remaining, []). print_user(User) when is_record(User, user) -> #user{id = Id, pseudo = Pseudo, login = Login, ek_master = Ek_master, date_derniere_connexion = Date, last_ip = IP} = User, diff --git a/modules/erl/euphorik_daemon.erl b/modules/erl/euphorik_daemon.erl index dc33a7f..1813e0e 100755 --- a/modules/erl/euphorik_daemon.erl +++ b/modules/erl/euphorik_daemon.erl @@ -60,5 +60,4 @@ reload_euphorik() -> end, [euphorik_minichat_conversation, euphorik_protocole, euphorik_requests, euphorik_bd, euphorik_daemon] ). - - + \ No newline at end of file diff --git a/modules/erl/euphorik_requests.erl b/modules/erl/euphorik_requests.erl index 524f735..28019da 100755 --- a/modules/erl/euphorik_requests.erl +++ b/modules/erl/euphorik_requests.erl @@ -23,27 +23,20 @@ -module(euphorik_requests). --export([ - tester/0, - out/1 -]). +-export([out/1]). -include_lib("xmerl/include/xmerl.hrl"). -include_lib("yaws/include/yaws_api.hrl"). -% Test du module (TODO) -tester() -> - que_dal. - - out(A) -> %io:format("~p~n", [A]), % utilisé parfois pendant le debug IP = case inet:peername(A#arg.clisock) of {ok, {Adresse, _Port}} -> Adresse; _ -> inconnue end, - % passive -> active, permet de recevoir {tcp_closed, _} lorsque le socket se ferme - inet:setopts(A#arg.clisock, [{active, true}]), + % passive -> active, permet de recevoir {tcp_closed, _} lorsque le socket se ferme + % keepalive -> true, evite que des firewalls coupe la connexion TCP sans prévenir + inet:setopts(A#arg.clisock, [{active, true}, {keepalive, true}]), {value, {_, Contenu}} = lists:keysearch("action", 1, yaws_api:parse_post(A)), Ret = traiter_donnees(Contenu, IP), {content, "application/json", Ret}. diff --git a/modules/erl/euphorik_test.erl b/modules/erl/euphorik_test.erl index c602292..d319997 100644 --- a/modules/erl/euphorik_test.erl +++ b/modules/erl/euphorik_test.erl @@ -21,12 +21,13 @@ -module(euphorik_test). --export([start/1, stop/1]). +-export([start/2, stop/1]). -include("../include/euphorik_bd.hrl"). % N est le nombre d'utilisateur -start(N) -> +% M est le nombre de message que chaque utilisateur va poster +start(N, M) -> Ids = creer_users(N), lists:map( fun(Id) -> @@ -35,7 +36,7 @@ start(N) -> fun() -> {A1, A2, A3} = now(), random:seed(A1, A2, A3), - loop(Id) + loop(Id, M) end ) end, @@ -102,13 +103,14 @@ tire_element_rand(N, L, Elements) -> tire_element_rand(N-1, L, [E | Elements]) end. - -loop(User_id) -> +loop(User_id, 0) -> + io:format("~p a fini~n", [User_id]); +loop(User_id, M) -> % attend un temp aléatoire compris entre 1 sec et 5 sec timer:sleep(1000 * random:uniform(5)), % poste un message aléatoire par une personne aléatoire répondant à des messages aléatoires {Message, Repond_a} = {message_rand(), messages_id_rand()}, io:format("~p poste ~p et repond a ~w~n", [User_id, Message, Repond_a]), euphorik_bd:nouveau_message(Message, User_id, Repond_a), - loop(User_id). + loop(User_id, M - 1). \ No newline at end of file diff --git a/pages/about.html b/pages/about.html index c142b72..12f162e 100644 --- a/pages/about.html +++ b/pages/about.html @@ -1,7 +1,7 @@

euphorik.ch

-

Version : 1.0.0

+

Version : 1.0.1

Auteur : Pifou

FAQ

@@ -16,7 +16,13 @@

C'est quoi un "troll de la semaine" ?

Simplement un sujet de débat à tendance trollifique. Chaque lundi à 3 heure du matin un nouveau troll est choisi au hasard parmis ceux proposés par les administrateurs.

- + +

A quoi correspondent les couleurs liés aux messages ?

+
    +
  • Vert : messages appartenant à l'utilisateur courant.
  • +
  • Rouge : messages répondant à l'utilisateur courant.
  • +
  • Bleu : messages auquels l'utilisateur courant à répondu.
  • +

Quels-sont les navigateurs supportés ?

Le site a été testé sous "Firefox 2 et 3", "Safari 3" et "Opera 9". -- 2.45.2