6481014b1ccb67c3b21c1ae758630eefaea6f1ce
2 // Copyright 2008 Grégory Burri
4 // This file is part of Euphorik.
6 // Euphorik is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
11 // Euphorik is distributed in the hope that it will be useful,
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with Euphorik. If not, see <http://www.gnu.org/licenses/>.
19 /*jslint laxbreak:true */
22 * Représente une conversation.
23 * Une conversation, au niveau XHTML, est formé de deux partie, le titre et les messages.
24 * Le titre comprend la navigation par page, un bouton pour la fermer, un bouton pour la plier, un bouton
25 * pour créer un lien ainsi que le premier message.
26 * @param conversations l'ensemble des conversations
27 * @param num le numéro de la conversation
29 euphorik
.Conversation = function(conversations
, num
) {
30 this.conversations
= conversations
;
32 // peut changer au cours de la vie de la conversation, n'est pas un id !
35 this.id
= Math
.floor(Math
.random() * 1000000).toString(36);
37 this.util
= this.conversations
.util
;
38 this.formateur
= this.conversations
.formateur
;
39 this.client
= this.conversations
.client
;
41 this.idDernierMessageAffiche
= 0;
42 this.racine
= undefined;
45 this.messagesParId
= {};
47 this.nbMessageMax
= euphorik
.conf
.nbMessageAffiche
; // Le nombre de message affiché par page
49 var messagesXHTML
= '<div class="messages"></div>';
50 var messageRacineXHTML
= '<div class="messageRacine"></div>';
51 var reverse
= this.client
.chatOrder
=== "reverse";
54 '<td class="conversation" id="' + this.getId() + '">' +
55 (reverse
? messagesXHTML : "") +
56 '<div class="titre">' +
57 (reverse
? messageRacineXHTML : "") +
59 (num
=== 0 ? '' : '<div class="fermer"></div><div class="lien"></div><div class="reduire"></div>') +
60 '<span class="next"><</span><span class="numPage">1</span><span class="prev">></span>' +
62 (reverse
? "" : messageRacineXHTML
) +
64 (reverse
? "" : messagesXHTML
) +
67 $("#conversations tr").append(XHTML
);
69 this.util
.infoBulle("Aller à la première page", $("#" + this.getId() + " .numPage"), euphorik
.Util
.positionBulleType
.haut
);
71 this.util
.infoBulle("Créer un lien vers la conversation", $("#" + this.getId() + " .lien"));
72 this.util
.infoBulle("Fermer la conversation", $("#" + this.getId() + " .fermer"));
77 * Met à jour la racine, décide de l'afficher ou non.
78 * On l'affiche uniquement si le message racine n'est pas déjà affiché sur la liste des messages.
80 euphorik
.Conversation
.prototype.majRacine = function() {
85 if (!(this.racine
.id
in this.messagesParId
)) {
86 this.messagesParId
[this.racine
.id
] = this.racine
;
87 var element
= $(this.racine
.XHTML(true, this.getId()));
88 this.attacherEventsSurMessage(element
);
89 $("#" + this.getId() + " .titre .messageRacine").html(element
);
93 euphorik
.Conversation
.prototype.enleverMiseEnEvidence = function() {
94 $("#" + this.getId() + " .message").removeClass("cache");
97 euphorik
.Conversation
.prototype.colorerEntetes = function() {
98 var thisConversation
= this;
100 var messagesReponse
= "";
101 var messagesRepondu
= "";
102 var messagesProprietaire
= "";
103 this.messages
.each(function(i
, mess
) {
104 if (mess
.appartientAuClient
) {
105 messagesProprietaire
+= "#" + mess
.getId(thisConversation
.getId()) + ",";
106 } else if (mess
.clientARepondu
) {
107 messagesRepondu
+= "#" + mess
.getId(thisConversation
.getId()) + ",";
108 } else if (mess
.estUneReponse
) {
109 messagesReponse
+= "#" + mess
.getId(thisConversation
.getId()) + ",";
112 $(messagesReponse
).addClass("reponse");
113 $(messagesRepondu
).addClass("repondu");
114 $(messagesProprietaire
).addClass("proprietaire");
117 euphorik
.Conversation
.prototype.decolorerEntetes = function() {
118 $("#" + this.getId() + " .messages .message")
119 .removeClass("reponse")
120 .removeClass("repondu")
121 .removeClass("proprietaire");
125 * Défini la page courante et s'il l'on se trouve sur la dernière page.
126 * @pageCourante la page courante
127 * @dernierePage true si c'est la dernière page sinon false
129 euphorik
.Conversation
.prototype.setPage = function(pageCourante
, dernierePage
) {
130 $("#" + this.getId() + " .numPage").text(pageCourante
);
131 $("#" + this.getId() + " .next").css("display", pageCourante
=== 1 ? "none" : "inline");
132 $("#" + this.getId() + " .prev").css("display", dernierePage
? "none" : "inline");
136 * Evenement déclanché lors de l'insertion du lien de la conversation dans le message courant.
138 euphorik
.Conversation
.prototype.eventLien = function(fun
) {
139 var thisConversation
= this;
141 $("#" + this.getId() + " .titre .lien").click(
143 fun(thisConversation
.num
);
149 * Evenement déclanché lors de la fermeture de la conversation.
151 euphorik
.Conversation
.prototype.eventFermer = function(fun
) {
152 var thisConversation
= this;
154 $("#" + this.getId() + " .titre .fermer").click(
156 fun(thisConversation
.num
);
162 * @funNext appelé lorsque l'on passe à la page suivante (de 2 à 1 par exemple)
163 * @funPrev appelé lorsque l'on passe à la page précédente (de 1 à 2 par exemple)
164 * @funReset appelé lorsque l'on souhaite revenir à la page une
166 euphorik
.Conversation
.prototype.setFunPage = function(funNext
, funPrev
, funReset
) {
167 var thisConversation
= this;
169 $("#" + this.getId() + " .next").click(
170 function() { funNext(thisConversation
.num
); }
172 $("#" + this.getId() + " .prev").click(
173 function() { funPrev(thisConversation
.num
); }
175 $("#" + this.getId() + " .numPage").click(
176 function() { funReset(thisConversation
.num
); }
181 * Retourne l'id de la conversation sous la forme (par exemple) "conv3".
183 euphorik
.Conversation
.prototype.getId = function() {
184 return "conv" + this.id
;
188 * Après avoir créé un message celui ci est ajouté à une conversation via cette méthode.
190 euphorik
.Conversation
.prototype.ajouterMessage = function(message
) {
191 this.messages
.push(message
);
192 this.messagesParId
[message
.id
] = message
;
194 // enlève le message exedentaire si nécessaire
195 if (this.messages
.length
> this.nbMessageMax
) {
196 delete this.messagesParId
[this.messages
.shift().id
];
199 // met à jour le membre 'estReponduPar' des messages de la conversation
200 for (var i
= 0; i
< this.messages
.length
- 1; i
++) {
201 var autreMess
= this.messages
[i
];
202 if (autreMess
.id
in message
.repondA
) {
203 autreMess
.estReponduPar
[message
.id
] = true;
209 * 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 ?
211 euphorik
.Conversation
.prototype.viderMessages = function() {
213 this.messagesParId
= {};
214 this.idDernierMessageAffiche
= 0;
215 $("#" + this.getId() + " .messages .message").remove();
217 // enlève également la racine
218 $("#" + this.getId() + " .titre .messageRacine").empty();
221 euphorik
.Conversation
.prototype.idMessageFromString = function(idString
) {
222 return parseInt(idString
.substr(4 + this.getId().length
), 36);
226 * Après l'ajout d'un ou plusieurs message cette méthode est appelée afin
227 * d'afficher les messages non-affichés.
228 * FIXME : méthode super lourde, à optimiser.
230 euphorik
.Conversation
.prototype.flush = function() {
231 var thisConversation
= this;
232 var reverse
= this.client
.chatOrder
=== "reverse";
234 var messagePair
= (this.idDernierMessageAffiche
=== 0 ? true :
235 ($("#" + this.getId() + " .messages div:" + (reverse
? "first" : "last")).attr("class").search("messagePair") === -1)
238 // construction de l'XHTML des messages
240 this.messages
.each(function(i
, mess
) {
241 if (mess
.id
> thisConversation
.idDernierMessageAffiche
) {
242 XHTML
+= mess
.XHTML(messagePair
, thisConversation
.getId());
243 messagePair
= !messagePair
;
249 // pour chaque nouveau message au niveau du document on lui assigne ses événements
250 DOM
.each(function() { thisConversation
.attacherEventsSurMessage(this); });
253 DOM
.prependTo("#" + this.getId() + " .messages");
255 DOM
.appendTo("#" + this.getId() + " .messages");
258 // enlève les messages exedentaires au niveau du document
259 var nbMessagesAffiche
= $("#" + this.getId() + " .messages .message").size();
260 if (nbMessagesAffiche
> this.nbMessageMax
) {
262 $("#" + this.getId() + " .messages .message").slice(this.nbMessageMax
, nbMessagesAffiche
).remove();
264 $("#" + this.getId() + " .messages .message").slice(0, nbMessagesAffiche
- this.nbMessageMax
).remove();
268 if (this.messages
.length
> 0) {
269 this.idDernierMessageAffiche
= this.messages
[this.messages
.length
-1].id
;
272 // met à jour la racine de la conversation
277 * Attache des événements à un message donné.
278 * @element le message du DOM
280 euphorik
.Conversation
.prototype.attacherEventsSurMessage = function(element
) {
282 var idMess
= this.idMessageFromString($(element
).attr("id"));
284 this.util
.infoBulle("Extraction de la conversation à partir de ce message", $(".extraire", element
));
285 this.util
.infoBulle("Extraction de la conversation complète", $(".extraireCompletement", element
));
287 var thisConversation
= this;
288 $(".lienConv", element
).click(
290 // FIXME : ya pas mieux ?
291 var racine
= $(event
.target
).text();
292 thisConversation
.conversations
.ouvrirConversation(parseInt(racine
.substring(1, racine
.length
- 1), 36));
299 if ($(event
.target
).is("a") || $(event
.target
).parents("#outilsBan").length
> 0) {
303 // extraction d'une conversation
304 if ($(event
.target
).is(".extraire")) {
305 thisConversation
.conversations
.ouvrirConversation(idMess
);
309 if ($(event
.target
).is(".extraireCompletement")) {
310 thisConversation
.conversations
.ouvrirConversation(thisConversation
.messagesParId
[idMess
].racineId
);
314 // met ou enlève la mise en evidence du message
315 thisConversation
.conversations
.toggleMessageRepond(thisConversation
.messagesParId
[idMess
]);
317 // donne le focus à la ligne de saisie
318 $("form input.message").focus();
322 // mise en évidence de la conversation
323 $(".entete", element
).hover(
325 thisConversation
.decolorerEntetes();
326 thisConversation
.afficherConversation(idMess
);
328 // quand on sort de l'entête du message la mise en évidence est enlevée
330 thisConversation
.enleverMiseEnEvidence();
331 thisConversation
.decolorerEntetes();
332 thisConversation
.colorerEntetes();
336 // est-ce que l'on affichage la date du message ?
337 if (thisConversation
.client
.viewTimes
) {
338 $(".dateComplete", element
).show();
340 $(".dateComplete", element
).hide();
343 $("a[@rel*=lightbox]", element
).lightBox();
345 // les outils de bannissement (uniquement pour les ekMaster)
346 if (thisConversation
.client
.ekMaster
) {
347 $(".pseudo", element
).hover(
349 var userId
= parseInt($(".id", this).text(), 10);
350 var pseudo
= $(this);
351 var h
= pseudo
.outerHeight();
352 var offset
= pseudo
.offset();
353 // TODO : calculer automatiquement la largeur plutôt que d'inscrire des valeurs en brut'
354 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();
355 $("img", thisConversation
.util
.outilsBan
).unbind("click");
356 $("#slap", thisConversation
.util
.outilsBan
).click(
358 thisConversation
.client
.slap(userId
, $("#outilsBan input").val());
359 $("#outilsBan input").val("");
360 $("#outilsBan").hide();
363 $("#kick", thisConversation
.util
.outilsBan
).click(
365 thisConversation
.client
.kick(userId
, $("#outilsBan input").val());
366 $("#outilsBan input").val("");
367 $("#outilsBan").hide();
370 $("#ban", thisConversation
.util
.outilsBan
).click(
372 thisConversation
.client
.ban(userId
, $("#outilsBan input").val());
373 $("#outilsBan input").val("");
374 $("#outilsBan").hide();
379 $("#outilsBan", this).hide();
386 * Etablit une liste des messages à mettre en evidence et des messages à cacher.
387 * Puis applique un plan diabolique.
388 * @param id l'id du message
390 euphorik
.Conversation
.prototype.afficherConversation = function(id
) {
391 var thisConversation
= this;
393 var message
= this.messagesParId
[id
];
398 var mess
= message
.getConversation(this);
400 // FIXME : cet appel est très lent
401 $("#" + this.getId() + " .messages .message").each(
404 var statut
= mess
[thisConversation
.idMessageFromString(jq
.attr("id"))];
405 if (statut
=== undefined) {
406 jq
.addClass("cache");
408 jq
.removeClass("cache");
410 // "repondu" et "reponse" sont prioritaitres à "proprietaire"
411 // contrairement à la vue normale (sans mise en évidence d'une conversation)
413 jq
.addClass("repondu");
416 jq
.addClass("reponse");
419 jq
.addClass("proprietaire");
428 * Supprime une conversation.
429 * Ne l'enlève pas du DOM.
431 euphorik
.Conversation
.prototype.supprimer = function() {
432 $("#" + this.getId()).remove();