From: Greg Burri Date: Tue, 27 Jan 2009 22:50:47 +0000 (+0000) Subject: MOD begining of #100 (code broken) X-Git-Url: http://git.euphorik.ch/?p=euphorik.git;a=commitdiff_plain;h=e49a1c483f1751f129c0766d1061b3da44b60581 MOD begining of #100 (code broken) --- diff --git a/index.yaws b/index.yaws index 7b391d3..0cf0ca7 100755 --- a/index.yaws +++ b/index.yaws @@ -50,13 +50,15 @@ + + + + + + - - - - - + diff --git a/js/chat/chat.js b/js/chat/chat.js new file mode 100644 index 0000000..a5263e7 --- /dev/null +++ b/js/chat/chat.js @@ -0,0 +1,20 @@ +// 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 . + +/*jslint laxbreak:true */ + diff --git a/js/chat/commandes.js b/js/chat/commandes.js new file mode 100644 index 0000000..dbcc76a --- /dev/null +++ b/js/chat/commandes.js @@ -0,0 +1,120 @@ +// 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 . + + /*jslint laxbreak:true */ + +/** + * Permet d'executer des commandes tapées par l'utilisateur. + * les commandes sont entrées directement dans la ligne de saisie du message sous la forme : + * / + * + * Voici les commandes supportées : + * /nick + * Modifie le pseudo courant + */ +euphorik.Commandes = function(client, pageMinichat, util, formater) { + var thisCommandes = this; + + this.client = client; + this.pageMinichat = pageMinichat; + this.util = util; + this.formater = formater; + + // construction du texte d'aide (liste des commandes) de manière statique + this.texteAide = "

Commandes

    "; + objectEach( + euphorik.Commandes.liste, + function(nom, commande) { + thisCommandes.texteAide += "
  • " + thisCommandes.formater.traitementComplet(commande.usage) + " : " + thisCommandes.formater.traitementComplet(commande.description) + "
  • "; + } + ); + this.texteAide += "
"; +}; + +euphorik.Commandes.statut = {ok : 0, pas_une_commande : 1, erreur_commande : 2}; + +euphorik.Commandes.liste = { + "nick" : { + description : "Change le pseudo courant", + usage : "/nick ", + exec : function(args, client) { + + if (args.length === 0) { + return [euphorik.Commandes.statut.erreur_commande, 'Utilisation de la commande : ' + this.usage]; + } + + client.pseudo = args[0]; + $("form#posterMessage input.pseudo").val(client.pseudo); + + return [euphorik.Commandes.statut.ok, '']; + } + }, + "cpf" : { + description : "Envoie le message \"C'est pas faux\"", + usage : "/cpf", + exec : function(args, client, pageMinichat) { + pageMinichat.envoyerMessage("C'est pas faux"); + return [euphorik.Commandes.statut.ok, '']; + } + }, + "osef" : { + description : "Envoie le message \"On s'en fout !\"", + usage : "/osef", + exec : function(args, client, pageMinichat) { + pageMinichat.envoyerMessage("On s'en fout !"); + return [euphorik.Commandes.statut.ok, '']; + } + } +}; + +/** + * Execute une commande. + * @return [statut, message], 'message' n'est utilisé que pour le statut 'erreur_commande'. + */ +euphorik.Commandes.prototype.exec = function(chaine) { + chaine = chaine.trim(); + + var fragments = chaine.split(/\s+/); + if (fragments.length === 0 || fragments[0].charAt(0) != '/') { + return [euphorik.Commandes.statut.pas_une_commande, '']; + } + + var nomCommande = fragments[0].slice(1); + var args = fragments.slice(1); + + if (nomCommande === "") { + return [euphorik.Commandes.statut.erreur_commande, 'La commande est vide']; + } + // commandes spéciales pour afficher l'aide : "?", "h", "help", "aide" + if (nomCommande === "?" || nomCommande === "h" || nomCommande === "help" || nomCommande === "aide") { + this.util.messageDialog( + this.texteAide, + euphorik.Util.messageType.informatif, + {"fermer" : function(){}}, + false, + -1 + ); + return [euphorik.Commandes.statut.ok, '']; + } + + if (euphorik.Commandes.liste.hasOwnProperty(nomCommande)) { + return euphorik.Commandes.liste[nomCommande].exec(args, this.client, this.pageMinichat); + } + + return [euphorik.Commandes.statut.erreur_commande, 'La commande /' + nomCommande + ' est inconnue']; +}; diff --git a/js/chat/conversation.js b/js/chat/conversation.js new file mode 100644 index 0000000..635f50a --- /dev/null +++ b/js/chat/conversation.js @@ -0,0 +1,473 @@ +// 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 . + + /*jslint laxbreak:true */ + +/** + * Représente une conversation. + * Une conversation, au niveau XHTML, est formé de deux partie, le titre et les messages. + * Le titre comprend la navigation par page, un bouton pour la fermer, un bouton pour la plier, un bouton + * pour créer un lien ainsi que le premier message. + * @param conversations l'ensemble des conversations + * @param num le numéro de la conversation + */ +euphorik.Conversation = function(conversations, num) { + this.conversations = conversations; + + // peut changer au cours de la vie de la conversation, n'est pas un id ! + this.num = num; + + this.id = Math.floor(Math.random() * 1000000).toString(36); + + this.util = this.conversations.util; + this.formater = this.conversations.formater; + this.client = this.conversations.client; + + this.idDernierMessageAffiche = 0; + this.racine = undefined; + + this.messages = []; + this.messagesParId = {}; + + this.nbMessageMax = euphorik.conf.nbMessageAffiche; // Le nombre de message affiché par page + + var messagesXHTML = '
'; + var messageRacineXHTML = '
'; + var reverse = this.client.chatOrder === "reverse"; + + var XHTML = + '' + + (reverse ? messagesXHTML : "") + + '
' + + (reverse ? messageRacineXHTML : "") + + '
+ '<1>' + + '
' + + (reverse ? "" : messageRacineXHTML) + + '
' + + (reverse ? "" : messagesXHTML) + + //'
' + + ''; + + $("#conversations tr").append(XHTML); + + // les infos bulles + this.util.infoBulle("Aller à la première page", $("#" + this.getId() + " .titre .numPage"), euphorik.Util.positionBulleType.haut); + if (this.num !== 0) { + this.util.infoBulle("Créer un lien vers la conversation", $("#" + this.getId() + " .titre .creerLien")); + this.util.infoBulle("Fermer la conversation", $("#" + this.getId() + " .titre .fermer")); + } + + // les différents événements liés à la conversation + var thisConversation = this; + $("#" + this.getId() + " .titre .creerLien").click(function() { + thisConversation.util.replaceSelection( + $("form#posterMessage input.message")[0], + "{" + thisConversation.client.conversations[thisConversation.num - 1].root.toString(36) + "}" + ); + }); + $("#" + this.getId() + " .titre .fermer").click(function() { + thisConversation.conversations.supprimerConversation(thisConversation.num); + }); + /* + $("#" + this.getId() + " .titre .reduire").click(function() { + $("#" + thisConversation.getId() + " .titre, #" + thisConversation.getId() + " .messages").hide() + var e = $("#" + thisConversation.getId() + " .messageReduit"); + e.get()[0].innerHTML = thisConversation.getMessageReduit() + });*/ +}; +/* +euphorik.Conversation.prototype.getMessageReduit = function() { + return '' + + '' + + '' + + '' + + 'Blabla blablablabla bla blabla ..' + + '' + + ''; +}*/ + +/** + * @racine un message représentant la racine de la conversation, vaut undefined pour la conversation générale + */ +euphorik.Conversation.prototype.setRacine = function(racineElement) { + this.racine = new euphorik.Message(this.client, this.formater, racineElement); +}; + +/** + * Met à jour la racine, décide de l'afficher ou non. + * On l'affiche uniquement si le message racine n'est pas déjà affiché sur la liste des messages. + */ +euphorik.Conversation.prototype.majRacine = function() { + if (!this.racine) { + return; + } + + if (!(this.racine.id in this.messagesParId)) { + this.messagesParId[this.racine.id] = this.racine; + var element = $(this.racine.XHTML(true, this.getId())); + this.attacherEventsSurMessage(element); + $("#" + this.getId() + " .titre .messageRacine").html(element); + } +}; + +euphorik.Conversation.prototype.enleverMiseEnEvidence = function() { + $("#" + this.getId() + " .message").removeClass("cache"); +}; + +euphorik.Conversation.prototype.colorerEntetes = function() { + var thisConversation = this; + + var messagesReponse = ""; + var messagesRepondu = ""; + var messagesProprietaire = ""; + this.messages.each(function(i, mess) { + if (mess.appartientAuClient) { + messagesProprietaire += "#" + mess.getId(thisConversation.getId()) + ","; + } else if (mess.clientARepondu) { + messagesRepondu += "#" + mess.getId(thisConversation.getId()) + ","; + } else if (mess.estUneReponse) { + messagesReponse += "#" + mess.getId(thisConversation.getId()) + ","; + } + }); + $(messagesReponse).addClass("reponse"); + $(messagesRepondu).addClass("repondu"); + $(messagesProprietaire).addClass("proprietaire"); +}; + +euphorik.Conversation.prototype.decolorerEntetes = function() { + $("#" + this.getId() + " .messages .message") + .removeClass("reponse") + .removeClass("repondu") + .removeClass("proprietaire"); +}; + +/** + * Défini la page courante et s'il l'on se trouve sur la dernière page. + * @pageCourante la page courante + * @dernierePage true si c'est la dernière page sinon false + */ +euphorik.Conversation.prototype.setPage = function(pageCourante, dernierePage) { + $("#" + this.getId() + " .numPage").text(pageCourante); + $("#" + this.getId() + " .next").css("display", pageCourante === 1 ? "none" : "inline"); + $("#" + this.getId() + " .prev").css("display", dernierePage ? "none" : "inline"); +}; + +/** + * @funNext appelé lorsque l'on passe à la page suivante (de 2 à 1 par exemple) + * @funPrev appelé lorsque l'on passe à la page précédente (de 1 à 2 par exemple) + * @funReset appelé lorsque l'on souhaite revenir à la page une + */ +euphorik.Conversation.prototype.setFunPage = function(funNext, funPrev, funReset) { + var thisConversation = this; + + $("#" + this.getId() + " .next").click( + function() { funNext(thisConversation.num); } + ); + $("#" + this.getId() + " .prev").click( + function() { funPrev(thisConversation.num); } + ); + $("#" + this.getId() + " .numPage").click( + function() { funReset(thisConversation.num); } + ); +}; + +/** + * Retourne l'id de la conversation sous la forme (par exemple) "conv3". + */ +euphorik.Conversation.prototype.getId = function() { + return "conv" + this.id; +}; + +/** + * Après avoir créé un message celui ci est ajouté à une conversation via cette méthode. + */ +euphorik.Conversation.prototype.ajouterMessage = function(message) { + this.messages.push(message); + this.messagesParId[message.id] = message; + + // enlève le message exedentaire si nécessaire + if (this.messages.length > this.nbMessageMax) { + delete this.messagesParId[this.messages.shift().id]; + } + + // met à jour le membre 'estReponduPar' des messages de la conversation + for (var i = 0; i < this.messages.length - 1; i++) { + var autreMess = this.messages[i]; + if (autreMess.id in message.repondA) { + autreMess.estReponduPar[message.id] = true; + } + } +}; + +/** + * FIXME : méthode très lourde. ne serait-ce pas mieux de virer d'un coup l'élément conversation et d'en remettre un vide ? + */ +euphorik.Conversation.prototype.viderMessages = function() { + this.messages = []; + this.messagesParId = {}; + this.idDernierMessageAffiche = 0; + $("#" + this.getId() + " .messages .message").remove(); + + // enlève également la racine + $("#" + this.getId() + " .titre .messageRacine").empty(); +}; + +euphorik.Conversation.prototype.idMessageFromString = function(idString) { + return parseInt(idString.substr(4 + this.getId().length), 36); +}; + +/** + * Après l'ajout d'un ou plusieurs message cette méthode est appelée afin + * d'afficher les messages non-affichés. + * FIXME : méthode super lourde, à optimiser. + */ +euphorik.Conversation.prototype.flush = function() { + var thisConversation = this; + var reverse = this.client.chatOrder === "reverse"; + + var messagePair = (this.idDernierMessageAffiche === 0 ? true : + ($("#" + this.getId() + " .messages div:" + (reverse ? "first" : "last")).attr("class").search("messagePair") === -1) + ); + + // permet d'itérer sur les nouveaux messages à afficher + var pourChaqueNouveauMessage = function(f) { + thisConversation.messages.each(function(i, mess) { + if (mess.id > thisConversation.idDernierMessageAffiche) { + f(mess); + } + }); + }; + + // construction de l'XHTML des messages + var XHTML = ""; + pourChaqueNouveauMessage(function(mess) { + XHTML += mess.XHTML(messagePair, thisConversation.getId()); + messagePair = !messagePair; + }); + + var DOM = $(XHTML); + + // pour chaque nouveau message au niveau du document on lui assigne ses événements + DOM.each(function() { thisConversation.attacherEventsSurMessage(this); }); + + if (reverse) { + DOM.prependTo("#" + this.getId() + " .messages"); + } else { + DOM.appendTo("#" + this.getId() + " .messages"); + } + + // enlève les messages exedentaires au niveau du document + var nbMessagesAffiche = $("#" + this.getId() + " .messages .message").size(); + if (nbMessagesAffiche > this.nbMessageMax) { + if (reverse) { + $("#" + this.getId() + " .messages .message").slice(this.nbMessageMax, nbMessagesAffiche).remove(); + } else { + $("#" + this.getId() + " .messages .message").slice(0, nbMessagesAffiche - this.nbMessageMax).remove(); + } + } + + // met à jour la classe des messages auquels repondent les nouveaux messages + // dans le cas où ce message appartient au client courant (c'est un peu de la triche) TODO : ya mieux ? + pourChaqueNouveauMessage(function(mess) { + if (mess.auteurId === thisConversation.client.id) { + objectEach(mess.repondA, function(messId) { + var mess = thisConversation.messagesParId[messId]; + if (mess) { + mess.clientARepondu = true; + $("#conversations #" + mess.getId(thisConversation.getId())).addClass("repondu"); + } + }); + } + }); + + if (this.messages.length > 0) { + this.idDernierMessageAffiche = this.messages[this.messages.length-1].id; + } + + // met à jour la racine de la conversation + this.majRacine(); +}; + +/** + * Attache des événements à un message donné. + * Utilisé lorsqu'un message est ajouté au document HTML. + * @element le message du DOM + */ +euphorik.Conversation.prototype.attacherEventsSurMessage = function(element) { + // l'id du message + var idMess = this.idMessageFromString($(element).attr("id")); + + if (idMess in this.conversations.messagesRepond) { + $(element).addClass("repondEnEvidence"); + } + + var thisConversation = this; + $(".lienConv", element).click( + function(event) { + // FIXME : ya pas mieux ? + var racine = $(event.target).text(); + thisConversation.conversations.ouvrirConversation(parseInt(racine.substring(1, racine.length - 1), 36)); + return false; + } + ); + + $(element).click(function(event) { + if ($(event.target).is("a") || $(event.target).parents("#outilsBan").length > 0) { + return; + } else if ($(event.target).is(".extraire")) { + thisConversation.util.outilsMessage.hide(); + thisConversation.conversations.ouvrirConversation(idMess); + return; + } else if ($(event.target).is(".extraireCompletement")) { + thisConversation.util.outilsMessage.hide(); + thisConversation.conversations.ouvrirConversation(thisConversation.messagesParId[idMess].racineId); + return; + } + + // met ou enlève la mise en evidence du message + thisConversation.conversations.toggleMessageRepond(thisConversation.messagesParId[idMess]); + + // donne le focus à la ligne de saisie + $("form input.message").focus(); + }).hover(function() { // affiche les outils liées au message + var top = $(this).offset().top; + var left = $(this).offset().left + $(this).outerWidth() - thisConversation.util.outilsMessage.outerWidth(); + $(".extraire", thisConversation.util.outilsMessage).unbind(); + $(".extraireCompletement", thisConversation.util.outilsMessage).unbind(); + // TODO : ces deux appels devraient se trouver dans "PageMinichat" lors de la création de thisConversation.util + // malheureusement lors de la modification du DOM (suppression des conversations) les événements liés sont supprimés + thisConversation.util.infoBulle("Extraction de la conversation à partir de ce message", $(".extraire", thisConversation.util.outilsMessage)); + thisConversation.util.infoBulle("Extraction de la conversation complète", $(".extraireCompletement", thisConversation.util.outilsMessage)); + thisConversation.util.outilsMessage.css("top", top).css("left", left).prependTo(this).show(); + }, function() { + thisConversation.util.outilsMessage.hide(); + }); + + // mise en évidence de la conversation + $(".entete", element).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(); + } + ); + + // est-ce que l'on affichage la date du message ? + if (thisConversation.client.viewTimes) { + $(".dateComplete", element).show(); + } else { + $(".dateComplete", element).hide(); + } + + $("a[@rel*=lightbox]", element).lightBox(); + + // les outils de bannissement (uniquement pour les ekMaster) + if (thisConversation.client.ekMaster) { + $(".pseudo", element).hover( + function(e) { + var userId = parseInt($(".id", this).text(), 10); + var pseudo = $(this); + var h = pseudo.outerHeight(); + var offset = pseudo.offset(); + // TODO : calculer automatiquement la largeur plutôt que d'inscrire des valeurs en brut' + thisConversation.util.outilsBan.css("top", offset.top - 2).css("left", offset.left - 2).height(h < 16 ? 16 : h).width(pseudo.outerWidth() + 16 * 3 + 12 + 64).prependTo(this).show(); + $("img", thisConversation.util.outilsBan).unbind("click"); + $("#slap", thisConversation.util.outilsBan).click( + function() { + thisConversation.client.slap(userId, $("#outilsBan input").val()); + $("#outilsBan input").val(""); + $("#outilsBan").hide(); + } + ); + $("#kick", thisConversation.util.outilsBan).click( + function() { + thisConversation.client.kick(userId, $("#outilsBan input").val()); + $("#outilsBan input").val(""); + $("#outilsBan").hide(); + } + ); + $("#ban", thisConversation.util.outilsBan).click( + function() { + thisConversation.client.ban(userId, $("#outilsBan input").val()); + $("#outilsBan input").val(""); + $("#outilsBan").hide(); + } + ); + }, + function() { + thisConversation.util.outilsBan.hide(); + } + ); + } +}; + +/** + * Etablit une liste des messages à mettre en evidence et des messages à cacher. + * Puis applique un plan diabolique. + * @param id l'id du message + */ +euphorik.Conversation.prototype.afficherConversation = function(id) { + var thisConversation = this; + + var message = this.messagesParId[id]; + if (!message) { + return; + } + + var mess = message.getConversation(this); + + // FIXME : cet appel est très lent + $("#" + this.getId() + " .messages .message").each( + function() { + var jq = $(this); + var statut = mess[thisConversation.idMessageFromString(jq.attr("id"))]; + if (statut === undefined) { + jq.addClass("cache"); + } else { + jq.removeClass("cache"); + switch (statut) { + // "repondu" et "reponse" sont prioritaitres à "proprietaire" + // contrairement à la vue normale (sans mise en évidence d'une conversation) + case 3 : + jq.addClass("repondu"); + break; + case 2 : + jq.addClass("reponse"); + break; + case 1 : + jq.addClass("proprietaire"); + break; + } + } + } + ); +}; + +/** + * Supprime la conversation du DOM. + */ +euphorik.Conversation.prototype.supprimer = function() { + $("#" + this.getId()).remove(); +}; diff --git a/js/chat/conversations.js b/js/chat/conversations.js new file mode 100644 index 0000000..063220c --- /dev/null +++ b/js/chat/conversations.js @@ -0,0 +1,416 @@ +// 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 . + +/*jslint laxbreak:true */ + +/** + * Représente l'ensemble des conversations affichés. + */ +euphorik.Conversations = function(client, formater, util, communication, fragment) { + this.client = client; + this.formater = formater; + this.util = util; + this.fragment = fragment; + + // un ensemble des messages (id) auquel l'utilisateur répond (vider après l'envoie du message courant) + this.messagesRepond = {}; + + this.conversations = []; // les conversations, la première représente la conversation principale + + this.nouvelleConversation(0); + + this.trollIdCourant = 0; + + this.comet = communication.createCometConnection("chat"); +}; + +// les messages auquels l'utilisateur répond et qui sont insérés dans le document XHTML +// ont leur id prefixé par cette valeur, cela permet de les distinguer des "vrais" messages +euphorik.Conversations.prototype.prefixIdMessage = "rep"; + +/** + * Permet de définir un message comme étant ou n'étant plus un message auquel l'utilisateur + * répond. + */ +euphorik.Conversations.prototype.toggleMessageRepond = function(mess) { + // est-ce que l'on répond déjà à ce message ? si oui alors on l'enlève de la liste + if (mess.id in this.messagesRepond) { + this.enleverMessageRepond(mess); + return; + } + + this.ajouterMessageRepond(mess); +}; + +/** + * Met à jour le fragment de l'url renseignant sur les conversations ouvertes. + */ +euphorik.Conversations.prototype.mettreAJourFragment = function() { + conv = []; + for(var i = 1; i < this.conversations.length; i++) { + conv.push(this.conversations[i].racine.id); + } + this.fragment.setVal("conv", conv); + this.fragment.write(); +}; + +/** + * Enlève tous les messages auquel l'utilisateur souhaite répondre. + */ +euphorik.Conversations.prototype.enleverMessagesRepond = function() { + var thisConversations = this; + + objectEach(this.messagesRepond, function(messId, mess) { + thisConversations.enleverMessageRepond(mess); + }); + + // on réinitialise pour être sur que tout est bien enlevé + this.messagesRepond = {}; + $("#conversations .message").removeClass("repondEnEvidence"); + $("form#posterMessage #repondA .messages").empty(); +}; + +/** + * Définit un message comme n'y répondant plus. + */ +euphorik.Conversations.prototype.enleverMessageRepond = function(mess) { + $(this.exprIdsPotentiels(mess)).removeClass("repondEnEvidence"); + $("#" + mess.getId(this.prefixIdMessage)).remove(); + delete this.messagesRepond[mess.id]; + this.rafraichireNombreMessagesRepond(); +}; + +/** + * Définit un message comme y répondant. + */ +euphorik.Conversations.prototype.ajouterMessageRepond = function(mess) { + var thisConversations = this; + + // est-ce que le message fait partie de la même conversation que les autres messages ? + // TODO : solution plus élégante pour prendre un mess parmis messagesRepond !? + var mess2; + for (mess2 in this.messagesRepond) { + if (this.messagesRepond.hasOwnProperty(mess2)) { + mess2 = this.messagesRepond[mess2]; + break; + } + } + + if (mess2 && mess2.racineId !== mess.racineId) { + this.util.messageDialog("Impossible de répondre à deux messages ne faisant pas partie de la même conversation"); + return; + } + + $("form#posterMessage #repondA .messages").append(mess.XHTML(undefined, this.prefixIdMessage)); + this.messagesRepond[mess.id] = mess; + + // ajout la classe 'repondEnEvidence' au message. comme il peut se trouver potentiellement dans + // chaque conversation on construit tous les id potentiels + $(mess.getId(this.prefixIdMessage) + ", " + this.exprIdsPotentiels(mess)).addClass("repondEnEvidence"); + + $("#" + mess.getId(this.prefixIdMessage)).click( + function() { + $(this).fadeOut("normal", function() { + thisConversations.enleverMessageRepond(mess); + $("form#posterMessage #repondA .messages").hide(); + }); + } + ); + this.rafraichireNombreMessagesRepond(); +}; + +/** + * Construit tous les id potentiels d'un message, renvoie par exemple : + * "conv9b28mess1h, conv9b2amess1h, conv9b32mess1h" + */ +euphorik.Conversations.prototype.exprIdsPotentiels = function(mess) { + var exprMess = ""; + this.conversations.each(function(i, conv) { + exprMess += (mess !== "" ? ", " : "") + "#" + mess.getId(conv.getId()); + }); + return exprMess; +}; + +/** + * Met à jour le nombre qui indique à l'utilisateur à combien de messages il répond. + */ +euphorik.Conversations.prototype.rafraichireNombreMessagesRepond = function() { + // TODO : ya pas mieux pour trouver le nombre d'objet ? + var nb = objectMemberCount(this.messagesRepond); + + $("#posterMessage #repondA .nb").text(nb); + + var boite = $("#posterMessage #repondA"); + if (nb > 0) { + boite.show(); + } else { + boite.hide(); + } +}; + +/** + * Affiche les messages auquel l'utilisateur souhaite répondre au sein des messages des conversations. + * Utilisé lorsqu'une conversation est extraite. + */ +euphorik.Conversations.prototype.afficherMessagesRepondConversations = function() { + var expr = ""; + objectEach(this.messagesRepond, function(messId, mess) { + expr += "#" + mess.getId() + ","; + }); + $(expr).addClass("repondEnEvidence"); +}; + +/** + * Crée un message JSON contenant le message demandant un rafraichissement. + */ +euphorik.Conversations.prototype.getJSONrafraichirMessages = function() { + var mess = { + "message_count" : euphorik.conf.nbMessageAffiche, + "main_page" : this.client.pagePrincipale, + "conversations" : this.getJSONConversations(), + "troll_id" : this.trollIdCourant + }; + + if (this.client.cookie) { + mess.cookie = this.client.cookie; + } + mess.last_message_id = this.conversations[0].idDernierMessageAffiche; + + return mess; +}; + +euphorik.Conversations.prototype.getJSONConversations = function() { + var thisConversations = this; + var clientConv = []; + + this.client.conversations.each(function(i, conv) { + clientConv.push({ + root : conv.root, + page : conv.page, + last_message_id : thisConversations.conversations[i + 1] ? thisConversations.conversations[i + 1].idDernierMessageAffiche : 0 + }); + }); + return clientConv; +}; + +/** + * Ajoute un ensemble de messages puis les affiches. + * @param elements un tableau d'éléments JSON représentant les messages, voir protocole.txt + * @param numConversation le numéro de la conversation auquel appartiennent les messages + * @return true si les messages on été ajoutés, false si la conversation n'existe pas et qu'il n'y a pas de message + */ +euphorik.Conversations.prototype.ajouterMessages = function(elements, numConversation) { + if (!elements.messages.length) { + return this.conversations[numConversation] !== undefined; + } + + for (var i = 0; i < elements.messages.length; i++) { + if (this.ajouterMessage(elements.messages[i], numConversation)) { + // si une nouvelle conversation a été créée alors on lui donne la racine + // TODO : ce block ne devrait pas se trouver ici mais dans "nouvelleConversation" + this.conversations[numConversation].setRacine(elements.first); + this.mettreAJourFragment(); + } + } + + this.flush(numConversation); + + // renseigne la conversation sur la page courante et si c'est la dernière + this.conversations[numConversation].setPage( + numConversation === 0 ? this.client.pagePrincipale : this.client.conversations[numConversation - 1].page, + elements.last_page + ); + + return true; +}; + +/** + * Création d'un nouveau message. + * Les message sont données dans l'ordre de leur id. + * @param element un element JSON représentant le message + * @param numConversation le numéro de la conversation, 0 = principale + * @return true si une nouvelle conversation a été créée sinon false + */ +euphorik.Conversations.prototype.ajouterMessage = function(element, numConversation) { + var message = + new euphorik.Message( + this.client, + this.formater, + element + ); + + var nouvelleConversation = false; + + if (!this.conversations[numConversation]) { + nouvelleConversation = true; + this.nouvelleConversation(numConversation); + } + + this.conversations[numConversation].ajouterMessage(message); + return nouvelleConversation; +}; + +euphorik.Conversations.prototype.nouvelleConversation = function(num) { + var thisConversations = this; + + this.conversations[num] = new euphorik.Conversation(this, num); + + this.conversations[num].setFunPage( + function(num) { // page suivante + thisConversations.client.pageSuivante(num - 1); + thisConversations.rafraichirMessages(true); + }, + function(num) { // page précédente + thisConversations.client.pagePrecedente(num - 1); + thisConversations.rafraichirMessages(true); + }, + function(num) { // retour à la page une + if (thisConversations.client.goPremierePage(num - 1)) { + thisConversations.rafraichirMessages(true); + } + } + ); + + this.ajusterLargeurConversations(); +}; + +/** + * Enlève une conversation. + */ +euphorik.Conversations.prototype.supprimerConversation = function(num) { + if (num <= 0 || num >= this.conversations.length) { + return; // la numéro 0 ne peut être supprimé + } + this.conversations[num].supprimer(); + + // les numéros sont réassigné + for (var i = num; i < this.conversations.length - 1; i++) { + this.conversations[i] = this.conversations[i+1]; + this.conversations[i].num -= 1; + } + this.conversations.pop(); + this.ajusterLargeurConversations(); + + this.client.supprimerConversation(num - 1); + + this.rafraichirMessages(true); + this.mettreAJourFragment(); +}; + +/** + * Ajuste la largeur des conversations en fonction de leur nombre. modifie l'attribut CSS 'width'. + */ +euphorik.Conversations.prototype.ajusterLargeurConversations = function() { + // TODO : trouver mieux ! + var largeurPourcent = (100 / this.conversations.length); + // obsolète !? + // 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 td").css("width", largeurPourcent + "%"); +}; + +/** + * Demande à toutes les conversations de se flusher (afficher les messages non-affichés). + */ +euphorik.Conversations.prototype.flushAll = function() { + for (var i = 0; i < this.conversations.length; i++) { + this.flush(i); + } +}; + +/** + * Demande à une conversation de se flusher. + */ +euphorik.Conversations.prototype.flush = function(numConv) { + this.conversations[numConv].flush(); +}; + +euphorik.Conversations.prototype.ouvrirConversation = function(racine) { + if (this.client.ajouterConversation(racine)) { + this.rafraichirMessages(true); + } else { + this.util.messageDialog("Cette conversation est déjà ouverte"); + } +}; + +euphorik.Conversations.prototype.viderMessages = function() { + this.conversations.each(function(i, conv) { + conv.viderMessages(); + }); +}; + +/** + * Met à jour les messages de manière continue. + * (AJAX-Comet-style proof) + * @param vider vide tous les messages avant d'afficher les nouveaux + */ +euphorik.Conversations.prototype.rafraichirMessages = function(vider) { + var thisConversations = this; + + vider = vider || false; + + if (vider) { + this.conversations.each(function(i, conv) { + conv.idDernierMessageAffiche = 0; + }); + } + + thisConversations.util.showWaitBar(); // pour faire patienter le user :) + + this.comet.waitEvent( + function() { return thisConversations.getJSONrafraichirMessages(); }, + { + "new_troll" : + function(data) { + thisConversations.trollIdCourant = data.troll_id; + $("#trollCourant .troll").html(thisConversations.formater.traitementComplet(data.content)).unbind("click").click( + function() { + thisConversations.ouvrirConversation(data.message_id); + } + ); + + $("#trollCourant .troll a[@rel*=lightbox]").lightBox(); + }, + "new_messages" : + function(data) { + + if (vider) { + thisConversations.viderMessages(); + } + + // ajoute les messages reçus à leur conversation respective + data.conversations.each(function(numConv, conv) { + if (!thisConversations.ajouterMessages(conv, numConv)) { + thisConversations.util.messageDialog("La conversation {" + thisConversations.client.conversations[numConv - 1].root.toString(36) + "} n'existe pas"); + thisConversations.client.supprimerConversation(numConv - 1); + } + }); + + if (vider) { + thisConversations.afficherMessagesRepondConversations(); + } + + vider = false; + + thisConversations.util.hideWaitBar(); + } + } + ); +}; diff --git a/js/chat/message.js b/js/chat/message.js new file mode 100644 index 0000000..c24be1d --- /dev/null +++ b/js/chat/message.js @@ -0,0 +1,155 @@ +// 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 . + +euphorik.Reponse = function(id, pseudo, login) { + this.id = id; + this.pseudo = pseudo; + this.login = login; + this.pseudo = pseudo || ""; + this.login = login || ""; +}; + +/** + * Représente un message. + */ +euphorik.Message = function(client, formater, element) { + this.client = client; + this.formater = formater; + + this.id = element.id; + this.auteurId = element.user_id; + this.racineId = element.root; + this.date = element.date; + this.pseudo = element.nick; + this.login = element.login; + this.contenu = element.content; + + // l'ensemble des id des messages qui reponde à ce message, exemple : {45:true, 32:true} (le 'true' ne sert à rien ^_^) + // mis à jour au fur à mesure que des messages sont ajoutés aux conversations + this.estReponduPar = {}; + + this.appartientAuClient = element.owner; + this.clientARepondu = element.answered; + this.estUneReponse = element.is_a_reply; + this.systeme = element.system; // est-ce un message 'système' ? + this.setRepondA(element.answer_to); // un ensemble de reponse (voir Reponse) indexé par l'id du message de la reponses + this.ekMaster = element.ek_master; + this.degreeOstentatoire = element.ostentatious_master; +}; + +/** + * @param pre est un prefix permettant de créer un Id différent pour deux mêmes messages. + * Cela est utile pour afficher plusieurs mêmes messages au sein d'un document XHTML. + * voir également la fonction 'XHTML()'. + */ +euphorik.Message.prototype.getId = function(pre) { + pre = pre || ""; + return pre + "mess" + this.id.toString(36); +}; + +euphorik.Message.prototype.setRepondA = function(repondAJSON) { + var thisMessage = this; + this.repondA = {}; + + repondAJSON.each(function(i, reponse) { + thisMessage.repondA[reponse.id] = new euphorik.Reponse(reponse.id, reponse.nick, reponse.login); + }); +}; + +/** + * Renvoie les messages faisant partie d'une conversation. + * @param messages l'ensemble des messages de la conversation + * @return les id des messages qui ont été mis en evidence sous la forme + * d'un hash (object) {id => 0 | 1 | 2 | 3}. 1 : proprietaire, 2 : reponse directe, 3 : message repondu + */ +euphorik.Message.prototype.getConversation = function(messages) { + var thisMessage = this; + + // les messages faisant partie de la conversation + var messagesEnEvidence = {}; + messagesEnEvidence[this.id] = 1; + + // parcours en profondeur + var f = function(ids, premierNiveau, ensemble, evidence) { + objectEach(ids, function(id) { + if (!messagesEnEvidence[id] || premierNiveau) { + var message = messages.messagesParId[id]; + if (message) { + messagesEnEvidence[id] = premierNiveau ? evidence : (message.auteurId === thisMessage.auteurId ? 1 : 0); + f(message[ensemble], false, ensemble, evidence); + } + } + }); + }; + + // remonte le temps + f(this.estReponduPar, true, "estReponduPar", 2); + + // descent le temps + f(this.repondA, true, "repondA", 3); + + return messagesEnEvidence; +}; + +/** + * Renvoie le message sous la forme de code XHTML (string) prêt à être inséré dans un document. + * Aucun callback n'est affecté. + */ +euphorik.Message.prototype.XHTML = function(messagePair, pre) { + if (messagePair === undefined) { + messagePair = true; + } + pre = pre || ""; + + thisMessage = this; + + // construit l'identifiant de la personne + var identifiant = + this.client.nickFormat === "nick" || this.login === "" ? this.formater.traitementComplet(this.pseudo) : + (this.client.nickFormat === "login" ? this.formater.traitementComplet(this.login) : + this.formater.traitementComplet(this.pseudo) + "(" + this.formater.traitementComplet(this.login) +")" ); + + var XHTMLrepondA = ""; + var debut = true; + objectEach(this.repondA, function(id, rep) { + if (!debut) { + XHTMLrepondA += ", "; + } + XHTMLrepondA += thisMessage.formater.traitementComplet(rep.pseudo); + debut = false; + }); + if (XHTMLrepondA) { + XHTMLrepondA = "" + XHTMLrepondA + ""; + } + + return "
" + + "" + + "[" + this.date + "]" + + "" + this.auteurId + "" + identifiant + "" + + "" + + "" + + XHTMLrepondA + + "" + this.formater.traitementComplet(this.contenu, this.pseudo) + "" + + "
"; +}; diff --git a/js/pageMinichat.js b/js/pageMinichat.js new file mode 100755 index 0000000..0b9c5b3 --- /dev/null +++ b/js/pageMinichat.js @@ -0,0 +1,294 @@ +// 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 . + +/*jslint laxbreak:true */ + +euphorik.PageMinichat = function(client, formater, util, communication) { + this.nom = "minichat"; + + this.client = client; + this.formater = formater; + this.util = util; + this.communication = communication; + this.commandes = new euphorik.Commandes(this.client, this, this.util, this.formater); + + // permet d'éviter d'envoyer plusieurs messages simultanément en pressant + // rapidement sur "enter" par exemple + this.envoieMessageEnCours = false; +}; + +euphorik.PageMinichat.prototype.contenu = function() { + // le fait que tout soit collé est fait exprès, permet d'éviter d'avoir des espaces supplémentaires entre les spans + var formulaireXHTML = '' + + '
' + + '

' + + ' ' + + ' ' + + ' 0' + + ' ' + + ' ' + + ' ' + + '

' + + '
'; + + var trollXHTML = '
Troll de la semaine :
'; + var conversationXHTML = '
'; + + if (this.client.chatOrder === "reverse") { + return trollXHTML + formulaireXHTML + conversationXHTML; + } else { + return trollXHTML + conversationXHTML + formulaireXHTML; + } +}; + +euphorik.PageMinichat.prototype.classes = function() { + return this.client.chatOrder === "reverse" ? "orderReverse" : "orderChrono"; +}; + +euphorik.PageMinichat.prototype.charger = function() { + thisPage = this; + + $("#posterMessage input.pseudo").val(this.client.pseudo); + + // cet appel ne doit pas être fait avant l'appel à 'charger' + this.conversations = new euphorik.Conversations(this.client, this.formater, this.util, this.communication, this.fragment); + + this.chargerConversationsFragment(); + + this.conversations.rafraichirMessages(true); + + this.util.setCaretToEnd($("form#posterMessage input.message")[0]); + + // les outils de bannissement (uniquement pour les ekMaster) + if (this.client.ekMaster) { + // TODO : augmentation un peu space, à revoir + this.util.outilsBan = $( + '' + + ' ' + + '

' + + ' Ban de 3 jours' + + ' Ban de 15 min' + + ' Avertissement' + + '
' + ); + + this.util.infoBulle("Slap", $("#slap", this.util.outilsBan)); + this.util.infoBulle("Kick (" + euphorik.conf.tempsKick + "min)", $("#kick", this.util.outilsBan)); + this.util.infoBulle("Ban (" + euphorik.conf.tempsBan / 24 / 60 + " jours)", $("#ban", this.util.outilsBan)); + this.util.infoBulle("La raison", $("input", this.util.outilsBan)); + } + + // la barre d'outils liée à chaque message + this.util.outilsMessage = $('
').prependTo("#page.minichat"); + this.util.infoBulle("Ouvrir la conversation liée au troll de la semaine", $("#trollCourant .troll")); + this.util.infoBulle("Cliquer sur les messages pour les enlevers de la liste", + $("form#posterMessage #repondA").hover( + function() { + thisPage.util.afficherBoite( + $(".messages", this), + $(this), + euphorik.Util.positionTypeX.centre, + thisPage.client.chatOrder === "reverse" ? euphorik.Util.positionTypeY.bas : euphorik.Util.positionTypeY.haut + ); + }, + function() { $(".messages", this).hide(); } + ).click( + function(e) { + if ($(e.target).is(".nb")) { + thisPage.conversations.enleverMessagesRepond(); + } + } + ), + euphorik.Util.positionBulleType.droite + ); + + // + $("body").append('
'); + // affichage des smiles + $("#smiles").append(this.formater.getSmilesHTML()).children().each( + function(i) { + var opacityBase = $(this).css("opacity"); + $(this).click( + function() { + thisPage.util.replaceSelection($("form#posterMessage input.message")[0], thisPage.formater.smiles[$(this).attr("class")][0].source.replace(/\\/g, "")); + } + ).hover( + function() { $(this).animate({opacity: 1}, 200); }, + function() { $(this).animate({opacity: opacityBase}, 200); } + ); + } + ); + $("form#posterMessage button.smiles").hover( + // affichage de la boite présentant les smiles + function(e){ thisPage.util.afficherBoite($("#smiles"), $(e.target), euphorik.Util.positionTypeX.centre, euphorik.Util.positionTypeY.basRecouvrement); }, + function(){} + ); + $("#smiles").hover( + function(){}, + function() { + $("#smiles").hide(); + } + ); + //
+ + // événements + var nouveauMessage = + function() { + // captcha anti bot + if ($("form#posterMessage input.captcha").val() !== "") { + return; + } + + var message = $("form#posterMessage input.message").val(); + + // traitement des commandes.. + var retCommandes = thisPage.commandes.exec(message); + switch (retCommandes[0]) { + case euphorik.Commandes.statut.pas_une_commande : + thisPage.envoyerMessage(message); + break; + case euphorik.Commandes.statut.erreur_commande : + thisPage.util.messageDialog(retCommandes[1], euphorik.Util.messageType.erreur); + break; + case euphorik.Commandes.statut.ok : + $("form#posterMessage input.message").val(""); + break; + } + + $("form#posterMessage input.message").focus(); + }; + + $("form#posterMessage").keypress( + function(e) { + if (e.which === 13) { // return + nouveauMessage(); + } + } + ); + + $("form#posterMessage button.return").click(nouveauMessage); + + // interdiction de submiter le formulaire + $("form#posterMessage").submit(function(){ return false; }); + + $("input.pseudo").click( + function() { + var input = $("input.pseudo")[0]; + if (input.value === euphorik.conf.pseudoDefaut) { + input.value = ""; + } + } + ); +}; + +euphorik.PageMinichat.prototype.chargerConversationsFragment = function() { + var thisPageMinichat = this; + + // attention : "conv" doit être un tableau d'entier + try { + var conv = this.fragment.getVal("conv"); + if (conv) { + conv.each(function(i, racine) { + thisPageMinichat.client.ajouterConversation(racine) + }); + } + } catch(e) { + ;; console.log(e) + } +}; + +euphorik.PageMinichat.prototype.decharger = function() { + this.conversations.comet.stopAttenteCourante(); + + $("body #smiles").remove(); + + this.fragment.delVal("conv"); +}; + +/** + * Envoie un nouve message donné, le pseudo utilisé est celui se trouvant + * dans la zone de saisie (form#posterMessage input.pseudo). + */ +euphorik.PageMinichat.prototype.envoyerMessage = function(message) { + var thisPageMinichat = this; + var pseudo = $("form#posterMessage input.pseudo").val(); + + // (un pseudo vide est autorisé) + pseudo = this.formater.filtrerInputPseudo(pseudo); + + if (pseudo === euphorik.conf.pseudoDefaut) { + this.util.messageDialog("Le pseudo ne peut pas être " + euphorik.conf.pseudoDefaut); + return; + } + + message = message.trim(); + if (!message) { + this.util.messageDialog("Le message est vide"); + return; + } + + this.client.pseudo = pseudo; + + if (!this.client.authentifie()) { + if (!this.client.enregistrement()) { + this.util.messageDialog("login impossible"); + return; + } + } + + // évite le double post + if (this.envoieMessageEnCours) { + this.util.messageDialog("Message en cours d'envoie..."); + return; + } + this.envoieMessageEnCours = true; + + this.communication.requete( + "put_message", + this.getJSONMessage(pseudo, message), + function() { + $("form#posterMessage input.message").val(""); + thisPageMinichat.conversations.enleverMessagesRepond(); + thisPageMinichat.envoieMessageEnCours = false; + }, + function(data) { + thisPageMinichat.util.messageDialog(data.error_message); + thisPageMinichat.envoieMessageEnCours = false; + }, + true, + { + error : function() { + thisPageMinichat.envoieMessageEnCours = false; + } + } + ); +}; + +euphorik.PageMinichat.prototype.getJSONMessage = function(pseudo, message) { + var repondA = []; + objectEach(this.conversations.messagesRepond, function(id) { + repondA.push(parseInt(id, 10)); + }); + + return { + "cookie" : this.client.cookie, + "nick" : pseudo, + "content" : message, + "answer_to" : repondA + }; +}; diff --git a/js/pageMinichat/commandes.js b/js/pageMinichat/commandes.js deleted file mode 100644 index dbcc76a..0000000 --- a/js/pageMinichat/commandes.js +++ /dev/null @@ -1,120 +0,0 @@ -// 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 . - - /*jslint laxbreak:true */ - -/** - * Permet d'executer des commandes tapées par l'utilisateur. - * les commandes sont entrées directement dans la ligne de saisie du message sous la forme : - * / - * - * Voici les commandes supportées : - * /nick - * Modifie le pseudo courant - */ -euphorik.Commandes = function(client, pageMinichat, util, formater) { - var thisCommandes = this; - - this.client = client; - this.pageMinichat = pageMinichat; - this.util = util; - this.formater = formater; - - // construction du texte d'aide (liste des commandes) de manière statique - this.texteAide = "

Commandes

    "; - objectEach( - euphorik.Commandes.liste, - function(nom, commande) { - thisCommandes.texteAide += "
  • " + thisCommandes.formater.traitementComplet(commande.usage) + " : " + thisCommandes.formater.traitementComplet(commande.description) + "
  • "; - } - ); - this.texteAide += "
"; -}; - -euphorik.Commandes.statut = {ok : 0, pas_une_commande : 1, erreur_commande : 2}; - -euphorik.Commandes.liste = { - "nick" : { - description : "Change le pseudo courant", - usage : "/nick ", - exec : function(args, client) { - - if (args.length === 0) { - return [euphorik.Commandes.statut.erreur_commande, 'Utilisation de la commande : ' + this.usage]; - } - - client.pseudo = args[0]; - $("form#posterMessage input.pseudo").val(client.pseudo); - - return [euphorik.Commandes.statut.ok, '']; - } - }, - "cpf" : { - description : "Envoie le message \"C'est pas faux\"", - usage : "/cpf", - exec : function(args, client, pageMinichat) { - pageMinichat.envoyerMessage("C'est pas faux"); - return [euphorik.Commandes.statut.ok, '']; - } - }, - "osef" : { - description : "Envoie le message \"On s'en fout !\"", - usage : "/osef", - exec : function(args, client, pageMinichat) { - pageMinichat.envoyerMessage("On s'en fout !"); - return [euphorik.Commandes.statut.ok, '']; - } - } -}; - -/** - * Execute une commande. - * @return [statut, message], 'message' n'est utilisé que pour le statut 'erreur_commande'. - */ -euphorik.Commandes.prototype.exec = function(chaine) { - chaine = chaine.trim(); - - var fragments = chaine.split(/\s+/); - if (fragments.length === 0 || fragments[0].charAt(0) != '/') { - return [euphorik.Commandes.statut.pas_une_commande, '']; - } - - var nomCommande = fragments[0].slice(1); - var args = fragments.slice(1); - - if (nomCommande === "") { - return [euphorik.Commandes.statut.erreur_commande, 'La commande est vide']; - } - // commandes spéciales pour afficher l'aide : "?", "h", "help", "aide" - if (nomCommande === "?" || nomCommande === "h" || nomCommande === "help" || nomCommande === "aide") { - this.util.messageDialog( - this.texteAide, - euphorik.Util.messageType.informatif, - {"fermer" : function(){}}, - false, - -1 - ); - return [euphorik.Commandes.statut.ok, '']; - } - - if (euphorik.Commandes.liste.hasOwnProperty(nomCommande)) { - return euphorik.Commandes.liste[nomCommande].exec(args, this.client, this.pageMinichat); - } - - return [euphorik.Commandes.statut.erreur_commande, 'La commande /' + nomCommande + ' est inconnue']; -}; diff --git a/js/pageMinichat/conversation.js b/js/pageMinichat/conversation.js deleted file mode 100644 index 635f50a..0000000 --- a/js/pageMinichat/conversation.js +++ /dev/null @@ -1,473 +0,0 @@ -// 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 . - - /*jslint laxbreak:true */ - -/** - * Représente une conversation. - * Une conversation, au niveau XHTML, est formé de deux partie, le titre et les messages. - * Le titre comprend la navigation par page, un bouton pour la fermer, un bouton pour la plier, un bouton - * pour créer un lien ainsi que le premier message. - * @param conversations l'ensemble des conversations - * @param num le numéro de la conversation - */ -euphorik.Conversation = function(conversations, num) { - this.conversations = conversations; - - // peut changer au cours de la vie de la conversation, n'est pas un id ! - this.num = num; - - this.id = Math.floor(Math.random() * 1000000).toString(36); - - this.util = this.conversations.util; - this.formater = this.conversations.formater; - this.client = this.conversations.client; - - this.idDernierMessageAffiche = 0; - this.racine = undefined; - - this.messages = []; - this.messagesParId = {}; - - this.nbMessageMax = euphorik.conf.nbMessageAffiche; // Le nombre de message affiché par page - - var messagesXHTML = '
'; - var messageRacineXHTML = '
'; - var reverse = this.client.chatOrder === "reverse"; - - var XHTML = - '' + - (reverse ? messagesXHTML : "") + - '
' + - (reverse ? messageRacineXHTML : "") + - '
- '<1>' + - '
' + - (reverse ? "" : messageRacineXHTML) + - '
' + - (reverse ? "" : messagesXHTML) + - //'
' + - ''; - - $("#conversations tr").append(XHTML); - - // les infos bulles - this.util.infoBulle("Aller à la première page", $("#" + this.getId() + " .titre .numPage"), euphorik.Util.positionBulleType.haut); - if (this.num !== 0) { - this.util.infoBulle("Créer un lien vers la conversation", $("#" + this.getId() + " .titre .creerLien")); - this.util.infoBulle("Fermer la conversation", $("#" + this.getId() + " .titre .fermer")); - } - - // les différents événements liés à la conversation - var thisConversation = this; - $("#" + this.getId() + " .titre .creerLien").click(function() { - thisConversation.util.replaceSelection( - $("form#posterMessage input.message")[0], - "{" + thisConversation.client.conversations[thisConversation.num - 1].root.toString(36) + "}" - ); - }); - $("#" + this.getId() + " .titre .fermer").click(function() { - thisConversation.conversations.supprimerConversation(thisConversation.num); - }); - /* - $("#" + this.getId() + " .titre .reduire").click(function() { - $("#" + thisConversation.getId() + " .titre, #" + thisConversation.getId() + " .messages").hide() - var e = $("#" + thisConversation.getId() + " .messageReduit"); - e.get()[0].innerHTML = thisConversation.getMessageReduit() - });*/ -}; -/* -euphorik.Conversation.prototype.getMessageReduit = function() { - return '' + - '' + - '' + - '' + - 'Blabla blablablabla bla blabla ..' + - '' + - ''; -}*/ - -/** - * @racine un message représentant la racine de la conversation, vaut undefined pour la conversation générale - */ -euphorik.Conversation.prototype.setRacine = function(racineElement) { - this.racine = new euphorik.Message(this.client, this.formater, racineElement); -}; - -/** - * Met à jour la racine, décide de l'afficher ou non. - * On l'affiche uniquement si le message racine n'est pas déjà affiché sur la liste des messages. - */ -euphorik.Conversation.prototype.majRacine = function() { - if (!this.racine) { - return; - } - - if (!(this.racine.id in this.messagesParId)) { - this.messagesParId[this.racine.id] = this.racine; - var element = $(this.racine.XHTML(true, this.getId())); - this.attacherEventsSurMessage(element); - $("#" + this.getId() + " .titre .messageRacine").html(element); - } -}; - -euphorik.Conversation.prototype.enleverMiseEnEvidence = function() { - $("#" + this.getId() + " .message").removeClass("cache"); -}; - -euphorik.Conversation.prototype.colorerEntetes = function() { - var thisConversation = this; - - var messagesReponse = ""; - var messagesRepondu = ""; - var messagesProprietaire = ""; - this.messages.each(function(i, mess) { - if (mess.appartientAuClient) { - messagesProprietaire += "#" + mess.getId(thisConversation.getId()) + ","; - } else if (mess.clientARepondu) { - messagesRepondu += "#" + mess.getId(thisConversation.getId()) + ","; - } else if (mess.estUneReponse) { - messagesReponse += "#" + mess.getId(thisConversation.getId()) + ","; - } - }); - $(messagesReponse).addClass("reponse"); - $(messagesRepondu).addClass("repondu"); - $(messagesProprietaire).addClass("proprietaire"); -}; - -euphorik.Conversation.prototype.decolorerEntetes = function() { - $("#" + this.getId() + " .messages .message") - .removeClass("reponse") - .removeClass("repondu") - .removeClass("proprietaire"); -}; - -/** - * Défini la page courante et s'il l'on se trouve sur la dernière page. - * @pageCourante la page courante - * @dernierePage true si c'est la dernière page sinon false - */ -euphorik.Conversation.prototype.setPage = function(pageCourante, dernierePage) { - $("#" + this.getId() + " .numPage").text(pageCourante); - $("#" + this.getId() + " .next").css("display", pageCourante === 1 ? "none" : "inline"); - $("#" + this.getId() + " .prev").css("display", dernierePage ? "none" : "inline"); -}; - -/** - * @funNext appelé lorsque l'on passe à la page suivante (de 2 à 1 par exemple) - * @funPrev appelé lorsque l'on passe à la page précédente (de 1 à 2 par exemple) - * @funReset appelé lorsque l'on souhaite revenir à la page une - */ -euphorik.Conversation.prototype.setFunPage = function(funNext, funPrev, funReset) { - var thisConversation = this; - - $("#" + this.getId() + " .next").click( - function() { funNext(thisConversation.num); } - ); - $("#" + this.getId() + " .prev").click( - function() { funPrev(thisConversation.num); } - ); - $("#" + this.getId() + " .numPage").click( - function() { funReset(thisConversation.num); } - ); -}; - -/** - * Retourne l'id de la conversation sous la forme (par exemple) "conv3". - */ -euphorik.Conversation.prototype.getId = function() { - return "conv" + this.id; -}; - -/** - * Après avoir créé un message celui ci est ajouté à une conversation via cette méthode. - */ -euphorik.Conversation.prototype.ajouterMessage = function(message) { - this.messages.push(message); - this.messagesParId[message.id] = message; - - // enlève le message exedentaire si nécessaire - if (this.messages.length > this.nbMessageMax) { - delete this.messagesParId[this.messages.shift().id]; - } - - // met à jour le membre 'estReponduPar' des messages de la conversation - for (var i = 0; i < this.messages.length - 1; i++) { - var autreMess = this.messages[i]; - if (autreMess.id in message.repondA) { - autreMess.estReponduPar[message.id] = true; - } - } -}; - -/** - * FIXME : méthode très lourde. ne serait-ce pas mieux de virer d'un coup l'élément conversation et d'en remettre un vide ? - */ -euphorik.Conversation.prototype.viderMessages = function() { - this.messages = []; - this.messagesParId = {}; - this.idDernierMessageAffiche = 0; - $("#" + this.getId() + " .messages .message").remove(); - - // enlève également la racine - $("#" + this.getId() + " .titre .messageRacine").empty(); -}; - -euphorik.Conversation.prototype.idMessageFromString = function(idString) { - return parseInt(idString.substr(4 + this.getId().length), 36); -}; - -/** - * Après l'ajout d'un ou plusieurs message cette méthode est appelée afin - * d'afficher les messages non-affichés. - * FIXME : méthode super lourde, à optimiser. - */ -euphorik.Conversation.prototype.flush = function() { - var thisConversation = this; - var reverse = this.client.chatOrder === "reverse"; - - var messagePair = (this.idDernierMessageAffiche === 0 ? true : - ($("#" + this.getId() + " .messages div:" + (reverse ? "first" : "last")).attr("class").search("messagePair") === -1) - ); - - // permet d'itérer sur les nouveaux messages à afficher - var pourChaqueNouveauMessage = function(f) { - thisConversation.messages.each(function(i, mess) { - if (mess.id > thisConversation.idDernierMessageAffiche) { - f(mess); - } - }); - }; - - // construction de l'XHTML des messages - var XHTML = ""; - pourChaqueNouveauMessage(function(mess) { - XHTML += mess.XHTML(messagePair, thisConversation.getId()); - messagePair = !messagePair; - }); - - var DOM = $(XHTML); - - // pour chaque nouveau message au niveau du document on lui assigne ses événements - DOM.each(function() { thisConversation.attacherEventsSurMessage(this); }); - - if (reverse) { - DOM.prependTo("#" + this.getId() + " .messages"); - } else { - DOM.appendTo("#" + this.getId() + " .messages"); - } - - // enlève les messages exedentaires au niveau du document - var nbMessagesAffiche = $("#" + this.getId() + " .messages .message").size(); - if (nbMessagesAffiche > this.nbMessageMax) { - if (reverse) { - $("#" + this.getId() + " .messages .message").slice(this.nbMessageMax, nbMessagesAffiche).remove(); - } else { - $("#" + this.getId() + " .messages .message").slice(0, nbMessagesAffiche - this.nbMessageMax).remove(); - } - } - - // met à jour la classe des messages auquels repondent les nouveaux messages - // dans le cas où ce message appartient au client courant (c'est un peu de la triche) TODO : ya mieux ? - pourChaqueNouveauMessage(function(mess) { - if (mess.auteurId === thisConversation.client.id) { - objectEach(mess.repondA, function(messId) { - var mess = thisConversation.messagesParId[messId]; - if (mess) { - mess.clientARepondu = true; - $("#conversations #" + mess.getId(thisConversation.getId())).addClass("repondu"); - } - }); - } - }); - - if (this.messages.length > 0) { - this.idDernierMessageAffiche = this.messages[this.messages.length-1].id; - } - - // met à jour la racine de la conversation - this.majRacine(); -}; - -/** - * Attache des événements à un message donné. - * Utilisé lorsqu'un message est ajouté au document HTML. - * @element le message du DOM - */ -euphorik.Conversation.prototype.attacherEventsSurMessage = function(element) { - // l'id du message - var idMess = this.idMessageFromString($(element).attr("id")); - - if (idMess in this.conversations.messagesRepond) { - $(element).addClass("repondEnEvidence"); - } - - var thisConversation = this; - $(".lienConv", element).click( - function(event) { - // FIXME : ya pas mieux ? - var racine = $(event.target).text(); - thisConversation.conversations.ouvrirConversation(parseInt(racine.substring(1, racine.length - 1), 36)); - return false; - } - ); - - $(element).click(function(event) { - if ($(event.target).is("a") || $(event.target).parents("#outilsBan").length > 0) { - return; - } else if ($(event.target).is(".extraire")) { - thisConversation.util.outilsMessage.hide(); - thisConversation.conversations.ouvrirConversation(idMess); - return; - } else if ($(event.target).is(".extraireCompletement")) { - thisConversation.util.outilsMessage.hide(); - thisConversation.conversations.ouvrirConversation(thisConversation.messagesParId[idMess].racineId); - return; - } - - // met ou enlève la mise en evidence du message - thisConversation.conversations.toggleMessageRepond(thisConversation.messagesParId[idMess]); - - // donne le focus à la ligne de saisie - $("form input.message").focus(); - }).hover(function() { // affiche les outils liées au message - var top = $(this).offset().top; - var left = $(this).offset().left + $(this).outerWidth() - thisConversation.util.outilsMessage.outerWidth(); - $(".extraire", thisConversation.util.outilsMessage).unbind(); - $(".extraireCompletement", thisConversation.util.outilsMessage).unbind(); - // TODO : ces deux appels devraient se trouver dans "PageMinichat" lors de la création de thisConversation.util - // malheureusement lors de la modification du DOM (suppression des conversations) les événements liés sont supprimés - thisConversation.util.infoBulle("Extraction de la conversation à partir de ce message", $(".extraire", thisConversation.util.outilsMessage)); - thisConversation.util.infoBulle("Extraction de la conversation complète", $(".extraireCompletement", thisConversation.util.outilsMessage)); - thisConversation.util.outilsMessage.css("top", top).css("left", left).prependTo(this).show(); - }, function() { - thisConversation.util.outilsMessage.hide(); - }); - - // mise en évidence de la conversation - $(".entete", element).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(); - } - ); - - // est-ce que l'on affichage la date du message ? - if (thisConversation.client.viewTimes) { - $(".dateComplete", element).show(); - } else { - $(".dateComplete", element).hide(); - } - - $("a[@rel*=lightbox]", element).lightBox(); - - // les outils de bannissement (uniquement pour les ekMaster) - if (thisConversation.client.ekMaster) { - $(".pseudo", element).hover( - function(e) { - var userId = parseInt($(".id", this).text(), 10); - var pseudo = $(this); - var h = pseudo.outerHeight(); - var offset = pseudo.offset(); - // TODO : calculer automatiquement la largeur plutôt que d'inscrire des valeurs en brut' - thisConversation.util.outilsBan.css("top", offset.top - 2).css("left", offset.left - 2).height(h < 16 ? 16 : h).width(pseudo.outerWidth() + 16 * 3 + 12 + 64).prependTo(this).show(); - $("img", thisConversation.util.outilsBan).unbind("click"); - $("#slap", thisConversation.util.outilsBan).click( - function() { - thisConversation.client.slap(userId, $("#outilsBan input").val()); - $("#outilsBan input").val(""); - $("#outilsBan").hide(); - } - ); - $("#kick", thisConversation.util.outilsBan).click( - function() { - thisConversation.client.kick(userId, $("#outilsBan input").val()); - $("#outilsBan input").val(""); - $("#outilsBan").hide(); - } - ); - $("#ban", thisConversation.util.outilsBan).click( - function() { - thisConversation.client.ban(userId, $("#outilsBan input").val()); - $("#outilsBan input").val(""); - $("#outilsBan").hide(); - } - ); - }, - function() { - thisConversation.util.outilsBan.hide(); - } - ); - } -}; - -/** - * Etablit une liste des messages à mettre en evidence et des messages à cacher. - * Puis applique un plan diabolique. - * @param id l'id du message - */ -euphorik.Conversation.prototype.afficherConversation = function(id) { - var thisConversation = this; - - var message = this.messagesParId[id]; - if (!message) { - return; - } - - var mess = message.getConversation(this); - - // FIXME : cet appel est très lent - $("#" + this.getId() + " .messages .message").each( - function() { - var jq = $(this); - var statut = mess[thisConversation.idMessageFromString(jq.attr("id"))]; - if (statut === undefined) { - jq.addClass("cache"); - } else { - jq.removeClass("cache"); - switch (statut) { - // "repondu" et "reponse" sont prioritaitres à "proprietaire" - // contrairement à la vue normale (sans mise en évidence d'une conversation) - case 3 : - jq.addClass("repondu"); - break; - case 2 : - jq.addClass("reponse"); - break; - case 1 : - jq.addClass("proprietaire"); - break; - } - } - } - ); -}; - -/** - * Supprime la conversation du DOM. - */ -euphorik.Conversation.prototype.supprimer = function() { - $("#" + this.getId()).remove(); -}; diff --git a/js/pageMinichat/conversations.js b/js/pageMinichat/conversations.js deleted file mode 100644 index 063220c..0000000 --- a/js/pageMinichat/conversations.js +++ /dev/null @@ -1,416 +0,0 @@ -// 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 . - -/*jslint laxbreak:true */ - -/** - * Représente l'ensemble des conversations affichés. - */ -euphorik.Conversations = function(client, formater, util, communication, fragment) { - this.client = client; - this.formater = formater; - this.util = util; - this.fragment = fragment; - - // un ensemble des messages (id) auquel l'utilisateur répond (vider après l'envoie du message courant) - this.messagesRepond = {}; - - this.conversations = []; // les conversations, la première représente la conversation principale - - this.nouvelleConversation(0); - - this.trollIdCourant = 0; - - this.comet = communication.createCometConnection("chat"); -}; - -// les messages auquels l'utilisateur répond et qui sont insérés dans le document XHTML -// ont leur id prefixé par cette valeur, cela permet de les distinguer des "vrais" messages -euphorik.Conversations.prototype.prefixIdMessage = "rep"; - -/** - * Permet de définir un message comme étant ou n'étant plus un message auquel l'utilisateur - * répond. - */ -euphorik.Conversations.prototype.toggleMessageRepond = function(mess) { - // est-ce que l'on répond déjà à ce message ? si oui alors on l'enlève de la liste - if (mess.id in this.messagesRepond) { - this.enleverMessageRepond(mess); - return; - } - - this.ajouterMessageRepond(mess); -}; - -/** - * Met à jour le fragment de l'url renseignant sur les conversations ouvertes. - */ -euphorik.Conversations.prototype.mettreAJourFragment = function() { - conv = []; - for(var i = 1; i < this.conversations.length; i++) { - conv.push(this.conversations[i].racine.id); - } - this.fragment.setVal("conv", conv); - this.fragment.write(); -}; - -/** - * Enlève tous les messages auquel l'utilisateur souhaite répondre. - */ -euphorik.Conversations.prototype.enleverMessagesRepond = function() { - var thisConversations = this; - - objectEach(this.messagesRepond, function(messId, mess) { - thisConversations.enleverMessageRepond(mess); - }); - - // on réinitialise pour être sur que tout est bien enlevé - this.messagesRepond = {}; - $("#conversations .message").removeClass("repondEnEvidence"); - $("form#posterMessage #repondA .messages").empty(); -}; - -/** - * Définit un message comme n'y répondant plus. - */ -euphorik.Conversations.prototype.enleverMessageRepond = function(mess) { - $(this.exprIdsPotentiels(mess)).removeClass("repondEnEvidence"); - $("#" + mess.getId(this.prefixIdMessage)).remove(); - delete this.messagesRepond[mess.id]; - this.rafraichireNombreMessagesRepond(); -}; - -/** - * Définit un message comme y répondant. - */ -euphorik.Conversations.prototype.ajouterMessageRepond = function(mess) { - var thisConversations = this; - - // est-ce que le message fait partie de la même conversation que les autres messages ? - // TODO : solution plus élégante pour prendre un mess parmis messagesRepond !? - var mess2; - for (mess2 in this.messagesRepond) { - if (this.messagesRepond.hasOwnProperty(mess2)) { - mess2 = this.messagesRepond[mess2]; - break; - } - } - - if (mess2 && mess2.racineId !== mess.racineId) { - this.util.messageDialog("Impossible de répondre à deux messages ne faisant pas partie de la même conversation"); - return; - } - - $("form#posterMessage #repondA .messages").append(mess.XHTML(undefined, this.prefixIdMessage)); - this.messagesRepond[mess.id] = mess; - - // ajout la classe 'repondEnEvidence' au message. comme il peut se trouver potentiellement dans - // chaque conversation on construit tous les id potentiels - $(mess.getId(this.prefixIdMessage) + ", " + this.exprIdsPotentiels(mess)).addClass("repondEnEvidence"); - - $("#" + mess.getId(this.prefixIdMessage)).click( - function() { - $(this).fadeOut("normal", function() { - thisConversations.enleverMessageRepond(mess); - $("form#posterMessage #repondA .messages").hide(); - }); - } - ); - this.rafraichireNombreMessagesRepond(); -}; - -/** - * Construit tous les id potentiels d'un message, renvoie par exemple : - * "conv9b28mess1h, conv9b2amess1h, conv9b32mess1h" - */ -euphorik.Conversations.prototype.exprIdsPotentiels = function(mess) { - var exprMess = ""; - this.conversations.each(function(i, conv) { - exprMess += (mess !== "" ? ", " : "") + "#" + mess.getId(conv.getId()); - }); - return exprMess; -}; - -/** - * Met à jour le nombre qui indique à l'utilisateur à combien de messages il répond. - */ -euphorik.Conversations.prototype.rafraichireNombreMessagesRepond = function() { - // TODO : ya pas mieux pour trouver le nombre d'objet ? - var nb = objectMemberCount(this.messagesRepond); - - $("#posterMessage #repondA .nb").text(nb); - - var boite = $("#posterMessage #repondA"); - if (nb > 0) { - boite.show(); - } else { - boite.hide(); - } -}; - -/** - * Affiche les messages auquel l'utilisateur souhaite répondre au sein des messages des conversations. - * Utilisé lorsqu'une conversation est extraite. - */ -euphorik.Conversations.prototype.afficherMessagesRepondConversations = function() { - var expr = ""; - objectEach(this.messagesRepond, function(messId, mess) { - expr += "#" + mess.getId() + ","; - }); - $(expr).addClass("repondEnEvidence"); -}; - -/** - * Crée un message JSON contenant le message demandant un rafraichissement. - */ -euphorik.Conversations.prototype.getJSONrafraichirMessages = function() { - var mess = { - "message_count" : euphorik.conf.nbMessageAffiche, - "main_page" : this.client.pagePrincipale, - "conversations" : this.getJSONConversations(), - "troll_id" : this.trollIdCourant - }; - - if (this.client.cookie) { - mess.cookie = this.client.cookie; - } - mess.last_message_id = this.conversations[0].idDernierMessageAffiche; - - return mess; -}; - -euphorik.Conversations.prototype.getJSONConversations = function() { - var thisConversations = this; - var clientConv = []; - - this.client.conversations.each(function(i, conv) { - clientConv.push({ - root : conv.root, - page : conv.page, - last_message_id : thisConversations.conversations[i + 1] ? thisConversations.conversations[i + 1].idDernierMessageAffiche : 0 - }); - }); - return clientConv; -}; - -/** - * Ajoute un ensemble de messages puis les affiches. - * @param elements un tableau d'éléments JSON représentant les messages, voir protocole.txt - * @param numConversation le numéro de la conversation auquel appartiennent les messages - * @return true si les messages on été ajoutés, false si la conversation n'existe pas et qu'il n'y a pas de message - */ -euphorik.Conversations.prototype.ajouterMessages = function(elements, numConversation) { - if (!elements.messages.length) { - return this.conversations[numConversation] !== undefined; - } - - for (var i = 0; i < elements.messages.length; i++) { - if (this.ajouterMessage(elements.messages[i], numConversation)) { - // si une nouvelle conversation a été créée alors on lui donne la racine - // TODO : ce block ne devrait pas se trouver ici mais dans "nouvelleConversation" - this.conversations[numConversation].setRacine(elements.first); - this.mettreAJourFragment(); - } - } - - this.flush(numConversation); - - // renseigne la conversation sur la page courante et si c'est la dernière - this.conversations[numConversation].setPage( - numConversation === 0 ? this.client.pagePrincipale : this.client.conversations[numConversation - 1].page, - elements.last_page - ); - - return true; -}; - -/** - * Création d'un nouveau message. - * Les message sont données dans l'ordre de leur id. - * @param element un element JSON représentant le message - * @param numConversation le numéro de la conversation, 0 = principale - * @return true si une nouvelle conversation a été créée sinon false - */ -euphorik.Conversations.prototype.ajouterMessage = function(element, numConversation) { - var message = - new euphorik.Message( - this.client, - this.formater, - element - ); - - var nouvelleConversation = false; - - if (!this.conversations[numConversation]) { - nouvelleConversation = true; - this.nouvelleConversation(numConversation); - } - - this.conversations[numConversation].ajouterMessage(message); - return nouvelleConversation; -}; - -euphorik.Conversations.prototype.nouvelleConversation = function(num) { - var thisConversations = this; - - this.conversations[num] = new euphorik.Conversation(this, num); - - this.conversations[num].setFunPage( - function(num) { // page suivante - thisConversations.client.pageSuivante(num - 1); - thisConversations.rafraichirMessages(true); - }, - function(num) { // page précédente - thisConversations.client.pagePrecedente(num - 1); - thisConversations.rafraichirMessages(true); - }, - function(num) { // retour à la page une - if (thisConversations.client.goPremierePage(num - 1)) { - thisConversations.rafraichirMessages(true); - } - } - ); - - this.ajusterLargeurConversations(); -}; - -/** - * Enlève une conversation. - */ -euphorik.Conversations.prototype.supprimerConversation = function(num) { - if (num <= 0 || num >= this.conversations.length) { - return; // la numéro 0 ne peut être supprimé - } - this.conversations[num].supprimer(); - - // les numéros sont réassigné - for (var i = num; i < this.conversations.length - 1; i++) { - this.conversations[i] = this.conversations[i+1]; - this.conversations[i].num -= 1; - } - this.conversations.pop(); - this.ajusterLargeurConversations(); - - this.client.supprimerConversation(num - 1); - - this.rafraichirMessages(true); - this.mettreAJourFragment(); -}; - -/** - * Ajuste la largeur des conversations en fonction de leur nombre. modifie l'attribut CSS 'width'. - */ -euphorik.Conversations.prototype.ajusterLargeurConversations = function() { - // TODO : trouver mieux ! - var largeurPourcent = (100 / this.conversations.length); - // obsolète !? - // 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 td").css("width", largeurPourcent + "%"); -}; - -/** - * Demande à toutes les conversations de se flusher (afficher les messages non-affichés). - */ -euphorik.Conversations.prototype.flushAll = function() { - for (var i = 0; i < this.conversations.length; i++) { - this.flush(i); - } -}; - -/** - * Demande à une conversation de se flusher. - */ -euphorik.Conversations.prototype.flush = function(numConv) { - this.conversations[numConv].flush(); -}; - -euphorik.Conversations.prototype.ouvrirConversation = function(racine) { - if (this.client.ajouterConversation(racine)) { - this.rafraichirMessages(true); - } else { - this.util.messageDialog("Cette conversation est déjà ouverte"); - } -}; - -euphorik.Conversations.prototype.viderMessages = function() { - this.conversations.each(function(i, conv) { - conv.viderMessages(); - }); -}; - -/** - * Met à jour les messages de manière continue. - * (AJAX-Comet-style proof) - * @param vider vide tous les messages avant d'afficher les nouveaux - */ -euphorik.Conversations.prototype.rafraichirMessages = function(vider) { - var thisConversations = this; - - vider = vider || false; - - if (vider) { - this.conversations.each(function(i, conv) { - conv.idDernierMessageAffiche = 0; - }); - } - - thisConversations.util.showWaitBar(); // pour faire patienter le user :) - - this.comet.waitEvent( - function() { return thisConversations.getJSONrafraichirMessages(); }, - { - "new_troll" : - function(data) { - thisConversations.trollIdCourant = data.troll_id; - $("#trollCourant .troll").html(thisConversations.formater.traitementComplet(data.content)).unbind("click").click( - function() { - thisConversations.ouvrirConversation(data.message_id); - } - ); - - $("#trollCourant .troll a[@rel*=lightbox]").lightBox(); - }, - "new_messages" : - function(data) { - - if (vider) { - thisConversations.viderMessages(); - } - - // ajoute les messages reçus à leur conversation respective - data.conversations.each(function(numConv, conv) { - if (!thisConversations.ajouterMessages(conv, numConv)) { - thisConversations.util.messageDialog("La conversation {" + thisConversations.client.conversations[numConv - 1].root.toString(36) + "} n'existe pas"); - thisConversations.client.supprimerConversation(numConv - 1); - } - }); - - if (vider) { - thisConversations.afficherMessagesRepondConversations(); - } - - vider = false; - - thisConversations.util.hideWaitBar(); - } - } - ); -}; diff --git a/js/pageMinichat/message.js b/js/pageMinichat/message.js deleted file mode 100644 index c24be1d..0000000 --- a/js/pageMinichat/message.js +++ /dev/null @@ -1,155 +0,0 @@ -// 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 . - -euphorik.Reponse = function(id, pseudo, login) { - this.id = id; - this.pseudo = pseudo; - this.login = login; - this.pseudo = pseudo || ""; - this.login = login || ""; -}; - -/** - * Représente un message. - */ -euphorik.Message = function(client, formater, element) { - this.client = client; - this.formater = formater; - - this.id = element.id; - this.auteurId = element.user_id; - this.racineId = element.root; - this.date = element.date; - this.pseudo = element.nick; - this.login = element.login; - this.contenu = element.content; - - // l'ensemble des id des messages qui reponde à ce message, exemple : {45:true, 32:true} (le 'true' ne sert à rien ^_^) - // mis à jour au fur à mesure que des messages sont ajoutés aux conversations - this.estReponduPar = {}; - - this.appartientAuClient = element.owner; - this.clientARepondu = element.answered; - this.estUneReponse = element.is_a_reply; - this.systeme = element.system; // est-ce un message 'système' ? - this.setRepondA(element.answer_to); // un ensemble de reponse (voir Reponse) indexé par l'id du message de la reponses - this.ekMaster = element.ek_master; - this.degreeOstentatoire = element.ostentatious_master; -}; - -/** - * @param pre est un prefix permettant de créer un Id différent pour deux mêmes messages. - * Cela est utile pour afficher plusieurs mêmes messages au sein d'un document XHTML. - * voir également la fonction 'XHTML()'. - */ -euphorik.Message.prototype.getId = function(pre) { - pre = pre || ""; - return pre + "mess" + this.id.toString(36); -}; - -euphorik.Message.prototype.setRepondA = function(repondAJSON) { - var thisMessage = this; - this.repondA = {}; - - repondAJSON.each(function(i, reponse) { - thisMessage.repondA[reponse.id] = new euphorik.Reponse(reponse.id, reponse.nick, reponse.login); - }); -}; - -/** - * Renvoie les messages faisant partie d'une conversation. - * @param messages l'ensemble des messages de la conversation - * @return les id des messages qui ont été mis en evidence sous la forme - * d'un hash (object) {id => 0 | 1 | 2 | 3}. 1 : proprietaire, 2 : reponse directe, 3 : message repondu - */ -euphorik.Message.prototype.getConversation = function(messages) { - var thisMessage = this; - - // les messages faisant partie de la conversation - var messagesEnEvidence = {}; - messagesEnEvidence[this.id] = 1; - - // parcours en profondeur - var f = function(ids, premierNiveau, ensemble, evidence) { - objectEach(ids, function(id) { - if (!messagesEnEvidence[id] || premierNiveau) { - var message = messages.messagesParId[id]; - if (message) { - messagesEnEvidence[id] = premierNiveau ? evidence : (message.auteurId === thisMessage.auteurId ? 1 : 0); - f(message[ensemble], false, ensemble, evidence); - } - } - }); - }; - - // remonte le temps - f(this.estReponduPar, true, "estReponduPar", 2); - - // descent le temps - f(this.repondA, true, "repondA", 3); - - return messagesEnEvidence; -}; - -/** - * Renvoie le message sous la forme de code XHTML (string) prêt à être inséré dans un document. - * Aucun callback n'est affecté. - */ -euphorik.Message.prototype.XHTML = function(messagePair, pre) { - if (messagePair === undefined) { - messagePair = true; - } - pre = pre || ""; - - thisMessage = this; - - // construit l'identifiant de la personne - var identifiant = - this.client.nickFormat === "nick" || this.login === "" ? this.formater.traitementComplet(this.pseudo) : - (this.client.nickFormat === "login" ? this.formater.traitementComplet(this.login) : - this.formater.traitementComplet(this.pseudo) + "(" + this.formater.traitementComplet(this.login) +")" ); - - var XHTMLrepondA = ""; - var debut = true; - objectEach(this.repondA, function(id, rep) { - if (!debut) { - XHTMLrepondA += ", "; - } - XHTMLrepondA += thisMessage.formater.traitementComplet(rep.pseudo); - debut = false; - }); - if (XHTMLrepondA) { - XHTMLrepondA = "" + XHTMLrepondA + ""; - } - - return "
" + - "" + - "[" + this.date + "]" + - "" + this.auteurId + "" + identifiant + "" + - "" + - "" + - XHTMLrepondA + - "" + this.formater.traitementComplet(this.contenu, this.pseudo) + "" + - "
"; -}; diff --git a/js/pageMinichat/pageMinichat.js b/js/pageMinichat/pageMinichat.js deleted file mode 100755 index 0b9c5b3..0000000 --- a/js/pageMinichat/pageMinichat.js +++ /dev/null @@ -1,294 +0,0 @@ -// 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 . - -/*jslint laxbreak:true */ - -euphorik.PageMinichat = function(client, formater, util, communication) { - this.nom = "minichat"; - - this.client = client; - this.formater = formater; - this.util = util; - this.communication = communication; - this.commandes = new euphorik.Commandes(this.client, this, this.util, this.formater); - - // permet d'éviter d'envoyer plusieurs messages simultanément en pressant - // rapidement sur "enter" par exemple - this.envoieMessageEnCours = false; -}; - -euphorik.PageMinichat.prototype.contenu = function() { - // le fait que tout soit collé est fait exprès, permet d'éviter d'avoir des espaces supplémentaires entre les spans - var formulaireXHTML = '' + - '
' + - '

' + - ' ' + - ' ' + - ' 0' + - ' ' + - ' ' + - ' ' + - '

' + - '
'; - - var trollXHTML = '
Troll de la semaine :
'; - var conversationXHTML = '
'; - - if (this.client.chatOrder === "reverse") { - return trollXHTML + formulaireXHTML + conversationXHTML; - } else { - return trollXHTML + conversationXHTML + formulaireXHTML; - } -}; - -euphorik.PageMinichat.prototype.classes = function() { - return this.client.chatOrder === "reverse" ? "orderReverse" : "orderChrono"; -}; - -euphorik.PageMinichat.prototype.charger = function() { - thisPage = this; - - $("#posterMessage input.pseudo").val(this.client.pseudo); - - // cet appel ne doit pas être fait avant l'appel à 'charger' - this.conversations = new euphorik.Conversations(this.client, this.formater, this.util, this.communication, this.fragment); - - this.chargerConversationsFragment(); - - this.conversations.rafraichirMessages(true); - - this.util.setCaretToEnd($("form#posterMessage input.message")[0]); - - // les outils de bannissement (uniquement pour les ekMaster) - if (this.client.ekMaster) { - // TODO : augmentation un peu space, à revoir - this.util.outilsBan = $( - '' + - ' ' + - '

' + - ' Ban de 3 jours' + - ' Ban de 15 min' + - ' Avertissement' + - '
' - ); - - this.util.infoBulle("Slap", $("#slap", this.util.outilsBan)); - this.util.infoBulle("Kick (" + euphorik.conf.tempsKick + "min)", $("#kick", this.util.outilsBan)); - this.util.infoBulle("Ban (" + euphorik.conf.tempsBan / 24 / 60 + " jours)", $("#ban", this.util.outilsBan)); - this.util.infoBulle("La raison", $("input", this.util.outilsBan)); - } - - // la barre d'outils liée à chaque message - this.util.outilsMessage = $('
').prependTo("#page.minichat"); - this.util.infoBulle("Ouvrir la conversation liée au troll de la semaine", $("#trollCourant .troll")); - this.util.infoBulle("Cliquer sur les messages pour les enlevers de la liste", - $("form#posterMessage #repondA").hover( - function() { - thisPage.util.afficherBoite( - $(".messages", this), - $(this), - euphorik.Util.positionTypeX.centre, - thisPage.client.chatOrder === "reverse" ? euphorik.Util.positionTypeY.bas : euphorik.Util.positionTypeY.haut - ); - }, - function() { $(".messages", this).hide(); } - ).click( - function(e) { - if ($(e.target).is(".nb")) { - thisPage.conversations.enleverMessagesRepond(); - } - } - ), - euphorik.Util.positionBulleType.droite - ); - - // - $("body").append('
'); - // affichage des smiles - $("#smiles").append(this.formater.getSmilesHTML()).children().each( - function(i) { - var opacityBase = $(this).css("opacity"); - $(this).click( - function() { - thisPage.util.replaceSelection($("form#posterMessage input.message")[0], thisPage.formater.smiles[$(this).attr("class")][0].source.replace(/\\/g, "")); - } - ).hover( - function() { $(this).animate({opacity: 1}, 200); }, - function() { $(this).animate({opacity: opacityBase}, 200); } - ); - } - ); - $("form#posterMessage button.smiles").hover( - // affichage de la boite présentant les smiles - function(e){ thisPage.util.afficherBoite($("#smiles"), $(e.target), euphorik.Util.positionTypeX.centre, euphorik.Util.positionTypeY.basRecouvrement); }, - function(){} - ); - $("#smiles").hover( - function(){}, - function() { - $("#smiles").hide(); - } - ); - //
- - // événements - var nouveauMessage = - function() { - // captcha anti bot - if ($("form#posterMessage input.captcha").val() !== "") { - return; - } - - var message = $("form#posterMessage input.message").val(); - - // traitement des commandes.. - var retCommandes = thisPage.commandes.exec(message); - switch (retCommandes[0]) { - case euphorik.Commandes.statut.pas_une_commande : - thisPage.envoyerMessage(message); - break; - case euphorik.Commandes.statut.erreur_commande : - thisPage.util.messageDialog(retCommandes[1], euphorik.Util.messageType.erreur); - break; - case euphorik.Commandes.statut.ok : - $("form#posterMessage input.message").val(""); - break; - } - - $("form#posterMessage input.message").focus(); - }; - - $("form#posterMessage").keypress( - function(e) { - if (e.which === 13) { // return - nouveauMessage(); - } - } - ); - - $("form#posterMessage button.return").click(nouveauMessage); - - // interdiction de submiter le formulaire - $("form#posterMessage").submit(function(){ return false; }); - - $("input.pseudo").click( - function() { - var input = $("input.pseudo")[0]; - if (input.value === euphorik.conf.pseudoDefaut) { - input.value = ""; - } - } - ); -}; - -euphorik.PageMinichat.prototype.chargerConversationsFragment = function() { - var thisPageMinichat = this; - - // attention : "conv" doit être un tableau d'entier - try { - var conv = this.fragment.getVal("conv"); - if (conv) { - conv.each(function(i, racine) { - thisPageMinichat.client.ajouterConversation(racine) - }); - } - } catch(e) { - ;; console.log(e) - } -}; - -euphorik.PageMinichat.prototype.decharger = function() { - this.conversations.comet.stopAttenteCourante(); - - $("body #smiles").remove(); - - this.fragment.delVal("conv"); -}; - -/** - * Envoie un nouve message donné, le pseudo utilisé est celui se trouvant - * dans la zone de saisie (form#posterMessage input.pseudo). - */ -euphorik.PageMinichat.prototype.envoyerMessage = function(message) { - var thisPageMinichat = this; - var pseudo = $("form#posterMessage input.pseudo").val(); - - // (un pseudo vide est autorisé) - pseudo = this.formater.filtrerInputPseudo(pseudo); - - if (pseudo === euphorik.conf.pseudoDefaut) { - this.util.messageDialog("Le pseudo ne peut pas être " + euphorik.conf.pseudoDefaut); - return; - } - - message = message.trim(); - if (!message) { - this.util.messageDialog("Le message est vide"); - return; - } - - this.client.pseudo = pseudo; - - if (!this.client.authentifie()) { - if (!this.client.enregistrement()) { - this.util.messageDialog("login impossible"); - return; - } - } - - // évite le double post - if (this.envoieMessageEnCours) { - this.util.messageDialog("Message en cours d'envoie..."); - return; - } - this.envoieMessageEnCours = true; - - this.communication.requete( - "put_message", - this.getJSONMessage(pseudo, message), - function() { - $("form#posterMessage input.message").val(""); - thisPageMinichat.conversations.enleverMessagesRepond(); - thisPageMinichat.envoieMessageEnCours = false; - }, - function(data) { - thisPageMinichat.util.messageDialog(data.error_message); - thisPageMinichat.envoieMessageEnCours = false; - }, - true, - { - error : function() { - thisPageMinichat.envoieMessageEnCours = false; - } - } - ); -}; - -euphorik.PageMinichat.prototype.getJSONMessage = function(pseudo, message) { - var repondA = []; - objectEach(this.conversations.messagesRepond, function(id) { - repondA.push(parseInt(id, 10)); - }); - - return { - "cookie" : this.client.cookie, - "nick" : pseudo, - "content" : message, - "answer_to" : repondA - }; -};