X-Git-Url: http://git.euphorik.ch/?p=euphorik.git;a=blobdiff_plain;f=js%2FpageMinichat%2Fconversations.js;fp=js%2FpageMinichat%2Fconversations.js;h=0c0f3d05d96e4d4a3c119543624e230f789e127f;hp=0000000000000000000000000000000000000000;hb=904f2d76c25b7fd04b1f90dfa095c7bf0f8c7ce5;hpb=c4669f8724bdf389a3541b113b0c1e20a70cc879 diff --git a/js/pageMinichat/conversations.js b/js/pageMinichat/conversations.js new file mode 100644 index 0000000..0c0f3d0 --- /dev/null +++ b/js/pageMinichat/conversations.js @@ -0,0 +1,421 @@ +// 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 . + +/** + * Représente l'ensemble des conversations affichés. + */ +function Conversations(client, formateur, util) +{ + this.client = client + this.formateur = formateur + this.util = util + + // un ensemble des messages (id) auquel l'utilisateur répond (vider après l'envoie du message courant) + this.messagesRepond = {} + + this.conversations = new Array() // les conversations, la première représente la conversation principale + + this.nouvelleConversation(0) + + this.trollIdCourant = 0 + + this.pageEvent = new euphorik.PageEvent("chat", this.util) +} + +// les messages insérés dans le document XHTML on leur id prefixé par cette valeur +// cela permet de les distinguer des "vrais" messages +Conversations.prototype.prefixIdMessage = "rep" + +/** + * Permet de définir un message comme étant ou n'étant plus un message auquel l'utilisateur + * répond. + */ +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) +} + +/** + * Enlève tous les messages auquel l'utilisateur souhaite répond. + */ +Conversations.prototype.enleverMessagesRepond = function() +{ + for (var messId in this.messagesRepond) + this.enleverMessageRepond(this.messagesRepond[messId]) + + // 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. + */ +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. + */ +Conversations.prototype.ajouterMessageRepond = function(mess) +{ + var thisMessages = 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){ break; } + mess2 = this.messagesRepond[mess2] + + if (mess2 != undefined && mess2.racineId != mess.racineId) + { + this.util.messageDialogue("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(){ + thisMessages.enleverMessageRepond(mess) + $("form#posterMessage #repondA .messages").hide() + }) + } + ) + this.rafraichireNombreMessagesRepond() +} + +/** + * Construit tous les id potentiels d'un message, renvoie par exemple : + * "conv9b28mess1h, conv9b2amess1h, conv9b32mess1h" + */ +Conversations.prototype.exprIdsPotentiels = function(mess) +{ + var exprMess = "" + for(var i = 0; i < this.conversations.length; i++) + { + exprMess += (mess != "" ? ", " : "") + "#" + mess.getId(this.conversations[i].getId()) + } + return exprMess +} + +/** + * Met à jour le nombre qui indique à l'utilisateur à combien de messages il répond. + */ +Conversations.prototype.rafraichireNombreMessagesRepond = function() +{ + // TODO : ya pas mieux pour trouver le nombre d'objet ? + var nb = 0 + for (var m in this.messagesRepond) + nb += 1 + $("#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. + */ +Conversations.prototype.afficherMessagesRepondConversations = function() +{ + var expr = "" + for(var messId in this.messagesRepond) + expr += "#" + this.messagesRepond[messId].getId() + "," + $(expr).addClass("repondEnEvidence") +} + +/** + * Crée un message JSON contenant le message demandant un rafraichissement. + */ +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 != null) mess["cookie"] = this.client.cookie + mess["last_message_id"] = this.conversations[0].idDernierMessageAffiche + + return mess +} + +Conversations.prototype.getJSONConversations = function() +{ + var clientConv = [] + + for (var i = 0; i < this.client.conversations.length; i++) + { + clientConv.push( + { + root : this.client.conversations[i].root, + page : this.client.conversations[i].page, + last_message_id : this.conversations[i + 1] == undefined ? 0 : this.conversations[i + 1].idDernierMessageAffiche + } + ) + } + 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 + */ +Conversations.prototype.ajouterMessages = function(elements, numConversation) +{ + if (elements["messages"].length == 0) + return this.conversations[numConversation] != undefined + + for (var i = 0; i < elements["messages"].length; i++) + // si une nouvelle conversation a été créée alors on lui donne la racine + if(this.ajouterMessage(elements["messages"][i], numConversation)) + this.conversations[numConversation].setRacine(elements["first"]) + + 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 + */ +Conversations.prototype.ajouterMessage = function(element, numConversation) +{ + var thisMessages = this + + // pas d'utilisation de jquery pour des raisons de performance + var message = new Message( + this.client, + this.formateur, + element + ) + + var nouvelleConversation = false + + if (this.conversations[numConversation] == null) + { + nouvelleConversation = true + this.nouvelleConversation( + numConversation, + function(num) // fermeture de la conversation + { + thisMessages.supprimerConversation(num) + }, + function(num) // insertion du lien vers la conversation + { + thisPage.util.replaceSelection( + $("form#posterMessage input.message")[0], + "{" + thisMessages.client.conversations[num-1].root.toString(36) + "}" + ) + } + ) + } + + this.conversations[numConversation].ajouterMessage(message) + return nouvelleConversation +} + +Conversations.prototype.nouvelleConversation = function(num, funFermer, funLien) +{ + var thisMessages = this + + this.conversations[num] = new Conversation(this, num) + + if (funFermer != undefined) + this.conversations[num].eventFermer(funFermer) + if (funLien != undefined) + this.conversations[num].eventLien(funLien) + + this.conversations[num].setFunPage( + function(num) // page suivante + { + thisMessages.client.pageSuivante(num - 1) + thisMessages.rafraichirMessages(true) + }, + function(num) // page précédente + { + thisMessages.client.pagePrecedente(num - 1) + thisMessages.rafraichirMessages(true) + }, + function(num) // retour à la page une + { + if (thisMessages.client.goPremierePage(num - 1)) + thisMessages.rafraichirMessages(true) + } + ) + + this.ajusterLargeurConversations() +} + +/** + * Enlève une conversation. + */ +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() + + // décalage TODO : supprimer le dernier élément + for (var i = num; i < this.conversations.length - 1; i++) + { + this.conversations[i] = this.conversations[i+1] + this.conversations[i].num -= 1 + } + this.conversations.pop() + this.ajusterLargeurConversations() + + this.client.supprimerConversation(num-1) + + this.rafraichirMessages(true) +} + +/** + * Ajuste la largeur des conversations en fonction de leur nombre. modifie l'attribut CSS 'width'. + */ +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). + */ +Conversations.prototype.flushAll = function() +{ + for (var i = 0; i < this.conversations.length; i++) + this.flush(i) +} + +/** + * Demande à une conversation de se flusher. + */ +Conversations.prototype.flush = function(numConv) +{ + this.conversations[numConv].flush() +} + +Conversations.prototype.ouvrirConversation = function(racine) +{ + if (this.client.ajouterConversation(racine)) + this.rafraichirMessages(true) + else + this.util.messageDialogue("Cette conversation est déjà ouverte") +} + +Conversations.prototype.viderMessages = function() +{ + for (var i = 0; i < this.conversations.length; i++) + this.conversations[i].viderMessages() +} + +/** + * Met à jour les messages de manière continue. + * (AJAX-Comet-style proof) + * @param vider vide tous les messages avant d'afficher les nouveaux + */ +Conversations.prototype.rafraichirMessages = function(vider) +{ + var thisMessages = this + + if (vider == undefined) + vider = false + + if (vider) + for (var i = 0; i < this.conversations.length; i++) + this.conversations[i].idDernierMessageAffiche = 0 + + this.pageEvent.waitEvent( + function() { return thisMessages.getJSONrafraichirMessages() }, + { + "new_troll" : + function(data) + { + thisMessages.trollIdCourant = data["troll_id"] + $("#trollCourant .troll").html(thisMessages.formateur.traitementComplet(data["content"])).unbind("click").click( + function() + { + thisMessages.ouvrirConversation(data["message_id"]) + } + ) + + $("#trollCourant .troll a[@rel*=lightbox]").lightBox() + }, + "new_messages" : + function(data) + { + if (vider) + thisMessages.viderMessages() + // ajoute les messages reçus à leur conversation respective + for (var numConv = 0; numConv < data["conversations"].length; numConv++) + { + if (!thisMessages.ajouterMessages(data["conversations"][numConv], numConv)) + { + thisMessages.util.messageDialogue("La conversation {" + thisMessages.client.conversations[numConv -1].root.toString(36) + "} n'existe pas") + thisMessages.client.supprimerConversation(numConv - 1) + } + } + if (vider) + thisMessages.afficherMessagesRepondConversations() + vider = false + } + } + ) +}