c3082b88b200f29f7acee01ed1184238110ddcf1
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/>.
21 * Représente une conversation.
22 * Une conversation, au niveau XHTML, est formé de deux partie, le titre et les messages.
23 * Le titre comprend la navigation par page, un bouton pour la fermer, un bouton pour la plier, un bouton
24 * pour créer un lien ainsi que le premier message.
25 * @param conversations l'ensemble des conversations
26 * @param num le numéro de la conversation
28 euphorik
.Conversation = function(conversations
, num
) {
29 this.conversations
= conversations
;
31 // peut changer au cours de la vie de la conversation, n'est pas un id !
34 this.id
= Math
.floor(Math
.random() * 1000000).toString(36);
36 this.util
= this.conversations
.util
;
37 this.formateur
= this.conversations
.formateur
;
38 this.client
= this.conversations
.client
;
40 this.idDernierMessageAffiche
= 0;
41 this.racine
= undefined;
44 this.messagesParId
= {};
46 this.nbMessageMax
= euphorik
.conf
.nbMessageAffiche
; // Le nombre de message affiché par page
48 var messagesXHTML
= '<div class="messages"></div>';
49 var messageRacineXHTML
= '<div class="messageRacine"></div>';
50 var reverse
= this.client
.chatOrder
=== "reverse";
53 '<td class="conversation" id="' + this.getId() + '">' +
54 (reverse
? messagesXHTML : "") +
55 '<div class="titre">' +
56 (reverse
? messageRacineXHTML : "") +
58 (num
=== 0 ? '' : '<div class="fermer"></div><div class="lien"></div><div class="reduire"></div>') +
59 '<span class="next"><</span><span class="numPage">1</span><span class="prev">></span>' +
61 (reverse
? "" : messageRacineXHTML
) +
63 (reverse
? "" : messagesXHTML
) +
66 $("#conversations tr").append(XHTML
);
68 this.util
.infoBulle("Aller à la première page", $("#" + this.getId() + " .numPage"), euphorik
.Util
.positionBulleType
.haut
);
70 this.util
.infoBulle("Créer un lien vers la conversation", $("#" + this.getId() + " .lien"));
71 this.util
.infoBulle("Fermer la conversation", $("#" + this.getId() + " .fermer"));
76 * @racine un message représentant la racine de la conversation, vaut undefined pour la conversation générale
78 euphorik
.Conversation
.prototype.setRacine = function(racineElement
) {
79 this.racine
= new euphorik
.Message(this.client
, this.formateur
, racineElement
);
83 * Met à jour la racine, décide de l'afficher ou non.
84 * On l'affiche uniquement si le message racine n'est pas déjà affiché sur la liste des messages.
86 euphorik
.Conversation
.prototype.majRacine = function() {
91 if (!(this.racine
.id
in this.messagesParId
)) {
92 this.messagesParId
[this.racine
.id
] = this.racine
;
93 var element
= $(this.racine
.XHTML(true, this.getId()));
94 this.attacherEventsSurMessage(element
);
95 $("#" + this.getId() + " .titre .messageRacine").html(element
);
99 euphorik
.Conversation
.prototype.enleverMiseEnEvidence = function() {
100 $("#" + this.getId() + " .message").removeClass("cache");
103 euphorik
.Conversation
.prototype.colorerEntetes = function() {
104 var thisConversation
= this;
106 var messagesReponse
= "";
107 var messagesRepondu
= "";
108 var messagesProprietaire
= "";
109 this.messages
.each(function(i
, mess
) {
110 if (mess
.appartientAuClient
) {
111 messagesProprietaire
+= "#" + mess
.getId(thisConversation
.getId()) + ",";
112 } else if (mess
.clientARepondu
) {
113 messagesRepondu
+= "#" + mess
.getId(thisConversation
.getId()) + ",";
114 } else if (mess
.estUneReponse
) {
115 messagesReponse
+= "#" + mess
.getId(thisConversation
.getId()) + ",";
118 $(messagesReponse
).addClass("reponse");
119 $(messagesRepondu
).addClass("repondu");
120 $(messagesProprietaire
).addClass("proprietaire");
123 euphorik
.Conversation
.prototype.decolorerEntetes = function() {
124 $("#" + this.getId() + " .messages .message")
125 .removeClass("reponse")
126 .removeClass("repondu")
127 .removeClass("proprietaire");
131 * Défini la page courante et s'il l'on se trouve sur la dernière page.
132 * @pageCourante la page courante
133 * @dernierePage true si c'est la dernière page sinon false
135 euphorik
.Conversation
.prototype.setPage = function(pageCourante
, dernierePage
) {
136 $("#" + this.getId() + " .numPage").text(pageCourante
);
137 $("#" + this.getId() + " .next").css("display", pageCourante
=== 1 ? "none" : "inline");
138 $("#" + this.getId() + " .prev").css("display", dernierePage
? "none" : "inline");
142 * Evenement déclanché lors de l'insertion du lien de la conversation dans le message courant.
144 euphorik
.Conversation
.prototype.eventLien = function(fun
) {
145 var thisConversation
= this;
147 $("#" + this.getId() + " .titre .lien").click(
149 fun(thisConversation
.num
);
155 * Evenement déclanché lors de la fermeture de la conversation.
157 euphorik
.Conversation
.prototype.eventFermer = function(fun
) {
158 var thisConversation
= this;
160 $("#" + this.getId() + " .titre .fermer").click(
162 fun(thisConversation
.num
);
168 * @funNext appelé lorsque l'on passe à la page suivante (de 2 à 1 par exemple)
169 * @funPrev appelé lorsque l'on passe à la page précédente (de 1 à 2 par exemple)
170 * @funReset appelé lorsque l'on souhaite revenir à la page une
172 euphorik
.Conversation
.prototype.setFunPage = function(funNext
, funPrev
, funReset
) {
173 var thisConversation
= this;
175 $("#" + this.getId() + " .next").click(
176 function() { funNext(thisConversation
.num
); }
178 $("#" + this.getId() + " .prev").click(
179 function() { funPrev(thisConversation
.num
); }
181 $("#" + this.getId() + " .numPage").click(
182 function() { funReset(thisConversation
.num
); }
187 * Retourne l'id de la conversation sous la forme (par exemple) "conv3".
189 euphorik
.Conversation
.prototype.getId = function() {
190 return "conv" + this.id
;
193 euphorik
.Conversation
.prototype.ajouterMessage = function(message
) {
194 this.messages
.push(message
);
195 this.messagesParId
[message
.id
] = message
;
197 // enlève les messages exedentaires
198 if (this.messages
.length
> this.nbMessageMax
) {
199 delete this.messagesParId
[this.messages
.shift().id
];
204 * 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 ?
206 euphorik
.Conversation
.prototype.viderMessages = function() {
208 this.messagesParId
= {};
209 this.idDernierMessageAffiche
= 0;
210 $("#" + this.getId() + " .messages .message").remove();
212 // enlève également la racine
213 $("#" + this.getId() + " .titre .messageRacine").empty();
216 euphorik
.Conversation
.prototype.idMessageFromString = function(idString
) {
217 return parseInt(idString
.substr(4 + this.getId().length
), 36);
221 * Après l'ajout d'un ou plusieurs message cette méthode est appelée afin
222 * d'afficher les messages non-affichés.
223 * FIXME : méthode super lourde, à optimiser.
225 euphorik
.Conversation
.prototype.flush = function() {
226 var thisConversation
= this;
227 var reverse
= this.client
.chatOrder
=== "reverse";
229 // est-ce que le prochain message est pair ? (permet d'alterner le style des messages)
230 var messagePair
= (this.idDernierMessageAffiche
=== 0 ? true :
231 ($("#" + this.getId() + " .messages div:" + (reverse
? "first" : "last")).attr("class").search("messagePair") === -1)
234 // construction de l'XHTML des messages
236 this.messages
.each(function(i
, mess
) {
237 if (mess
.id
> thisConversation
.idDernierMessageAffiche
) {
238 XHTML
+= mess
.XHTML(messagePair
, thisConversation
.getId());
239 messagePair
= !messagePair
;
245 // pour chaque nouveau message au niveau du document on lui assigne ses événements
246 DOM
.each(function() { thisConversation
.attacherEventsSurMessage(this); });
249 DOM
.prependTo("#" + this.getId() + " .messages");
251 DOM
.appendTo("#" + this.getId() + " .messages");
254 // enlève les messages exedentaires au niveau du document
255 var nbMessagesAffiche
= $("#" + this.getId() + " .messages .message").size();
256 if (nbMessagesAffiche
> this.nbMessageMax
) {
258 $("#" + this.getId() + " .messages .message").slice(this.nbMessageMax
, nbMessagesAffiche
).remove();
260 $("#" + this.getId() + " .messages .message").slice(0, nbMessagesAffiche
- this.nbMessageMax
).remove();
264 if (this.messages
.length
> 0) {
265 this.idDernierMessageAffiche
= this.messages
[this.messages
.length
-1].id
;
268 // met à jour la racine de la conversation
273 * Attache des événements à un message donné.
274 * @element le message du DOM
276 euphorik
.Conversation
.prototype.attacherEventsSurMessage = function(element
) {
278 var idMess
= this.idMessageFromString($(element
).attr("id"));
280 this.util
.infoBulle("Extraction de la conversation à partir de ce message", $(".extraire", element
));
281 this.util
.infoBulle("Extraction de la conversation complète", $(".extraireCompletement", element
));
283 var thisConversation
= this;
284 $(".lienConv", element
).click(
286 // FIXME : ya pas mieux ?
287 var racine
= $(event
.target
).text();
288 thisConversation
.conversations
.ouvrirConversation(parseInt(idString
.substring(1, racine
.length
- 1), 36));
295 if ($(event
.target
).is("a") || $(event
.target
).parents("#outilsBan").length
> 0) {
299 // extraction d'une conversation
300 if ($(event
.target
).is(".extraire")) {
301 thisConversation
.conversations
.ouvrirConversation(idMess
);
305 if ($(event
.target
).is(".extraireCompletement")) {
306 thisConversation
.conversations
.ouvrirConversation(thisConversation
.messagesParId
[idMess
].racineId
);
310 // met ou enlève la mise en evidence du message
311 thisConversation
.conversations
.toggleMessageRepond(thisConversation
.messagesParId
[idMess
]);
313 // donne le focus à la ligne de saisie
314 $("form input.message").focus();
318 // mise en évidence de la conversation
319 $(".entete", element
).hover(
321 thisConversation
.decolorerEntetes();
322 thisConversation
.afficherConversation(idMess
);
324 // quand on sort de l'entête du message la mise en évidence est enlevée
326 thisConversation
.enleverMiseEnEvidence();
327 thisConversation
.decolorerEntetes();
328 thisConversation
.colorerEntetes();
332 // est-ce que l'on affichage la date du message ?
333 if (thisConversation
.client
.viewTimes
) {
334 $(".dateComplete", element
).show();
336 $(".dateComplete", element
).hide();
339 $("a[@rel*=lightbox]", element
).lightBox();
341 // les outils de bannissement (uniquement pour les ekMaster)
342 if (thisConversation
.client
.ekMaster
) {
343 $(".pseudo", element
).hover(
345 var userId
= parseInt($(".id", this).text(), 10);
346 var pseudo
= $(this);
347 var h
= pseudo
.outerHeight();
348 var offset
= pseudo
.offset();
349 // TODO : calculer automatiquement la largeur plutôt que d'inscrire des valeurs en brut'
350 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();
351 $("img", thisConversation
.util
.outilsBan
).unbind("click");
352 $("#slap", thisConversation
.util
.outilsBan
).click(
354 thisConversation
.client
.slap(userId
, $("#outilsBan input").val());
355 $("#outilsBan input").val("");
356 $("#outilsBan").hide();
359 $("#kick", thisConversation
.util
.outilsBan
).click(
361 thisConversation
.client
.kick(userId
, $("#outilsBan input").val());
362 $("#outilsBan input").val("");
363 $("#outilsBan").hide();
366 $("#ban", thisConversation
.util
.outilsBan
).click(
368 thisConversation
.client
.ban(userId
, $("#outilsBan input").val());
369 $("#outilsBan input").val("");
370 $("#outilsBan").hide();
375 $("#outilsBan", this).hide();
382 * Etablit une liste des messages à mettre en evidence et des messages à cacher.
383 * Puis applique un plan diabolique.
384 * @param id l'id du message
386 euphorik
.Conversation
.prototype.afficherConversation = function(id
) {
387 var thisConversation
= this;
389 var message
= this.messagesParId
[id
];
394 var mess
= message
.getConversation(this);
396 // FIXME : cet appel est très lent
397 $("#" + this.getId() + " .messages .message").each(
400 var statut
= mess
[thisConversation
.idMessageFromString(jq
.attr("id"))];
402 jq
.addClass("cache");
404 jq
.removeClass("cache");
406 // "repondu" et "reponse" sont prioritaitres à "proprietaire"
407 // contrairement à la vue normale (sans mise en évidence d'une conversation)
409 jq
.addClass("repondu");
412 jq
.addClass("reponse");
415 jq
.addClass("proprietaire");
424 * Supprime une conversation.
425 * Ne l'enlève pas du DOM.
427 euphorik
.Conversation
.prototype.supprimer = function() {
428 $("#" + this.getId()).remove();