70f8d2b170d31f458a59cb5cfd5f2b471692f121
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
) +
65 '<div class="messageReduit" style="height:200px; width:50px"></div>' +
68 $("#conversations tr").append(XHTML
);
70 // les différents événements liés à la conversation
71 var thisConversation
= this;
72 $("#" + this.getId() + " .titre .lien").click(function() {
73 thisConversation
.util
.replaceSelection(
74 $("form#posterMessage input.message")[0],
75 "{" + thisConversation
.client
.conversations
[thisConversation
.num
- 1].root
.toString(36) + "}"
78 $("#" + this.getId() + " .titre .fermer").click(function() {
79 thisConversation
.conversations
.supprimerConversation(num
);
81 $("#" + this.getId() + " .titre .reduire").click(function() {
82 $("#" + thisConversation
.getId() + " .titre, #" + thisConversation
.getId() + " .messages").hide()
83 var e
= $("#" + thisConversation
.getId() + " .messageReduit");
84 e
.get()[0].innerHTML
= thisConversation
.getMessageReduit()
87 this.util
.infoBulle("Aller à la première page", $("#" + this.getId() + " .numPage"), euphorik
.Util
.positionBulleType
.haut
);
89 this.util
.infoBulle("Créer un lien vers la conversation", $("#" + this.getId() + " .lien"));
90 this.util
.infoBulle("Fermer la conversation", $("#" + this.getId() + " .fermer"));
94 euphorik
.Conversation
.prototype.getMessageReduit = function() {
96 '<svg:svg version="1.1" baseProfile="full" width="100px" height="200px">' +
97 '<svg:image x="10" y="10" height="10" width="10" class="fermer" />' +
98 '<svg:text transform="rotate(-90)" y="15" x="-200" >' +
99 'Blabla blablablabla bla blabla ..' +
105 * @racine un message représentant la racine de la conversation, vaut undefined pour la conversation générale
107 euphorik
.Conversation
.prototype.setRacine = function(racineElement
) {
108 this.racine
= new euphorik
.Message(this.client
, this.formateur
, racineElement
);
112 * Met à jour la racine, décide de l'afficher ou non.
113 * On l'affiche uniquement si le message racine n'est pas déjà affiché sur la liste des messages.
115 euphorik
.Conversation
.prototype.majRacine = function() {
120 if (!(this.racine
.id
in this.messagesParId
)) {
121 this.messagesParId
[this.racine
.id
] = this.racine
;
122 var element
= $(this.racine
.XHTML(true, this.getId()));
123 this.attacherEventsSurMessage(element
);
124 $("#" + this.getId() + " .titre .messageRacine").html(element
);
128 euphorik
.Conversation
.prototype.enleverMiseEnEvidence = function() {
129 $("#" + this.getId() + " .message").removeClass("cache");
132 euphorik
.Conversation
.prototype.colorerEntetes = function() {
133 var thisConversation
= this;
135 var messagesReponse
= "";
136 var messagesRepondu
= "";
137 var messagesProprietaire
= "";
138 this.messages
.each(function(i
, mess
) {
139 if (mess
.appartientAuClient
) {
140 messagesProprietaire
+= "#" + mess
.getId(thisConversation
.getId()) + ",";
141 } else if (mess
.clientARepondu
) {
142 messagesRepondu
+= "#" + mess
.getId(thisConversation
.getId()) + ",";
143 } else if (mess
.estUneReponse
) {
144 messagesReponse
+= "#" + mess
.getId(thisConversation
.getId()) + ",";
147 $(messagesReponse
).addClass("reponse");
148 $(messagesRepondu
).addClass("repondu");
149 $(messagesProprietaire
).addClass("proprietaire");
152 euphorik
.Conversation
.prototype.decolorerEntetes = function() {
153 $("#" + this.getId() + " .messages .message")
154 .removeClass("reponse")
155 .removeClass("repondu")
156 .removeClass("proprietaire");
160 * Défini la page courante et s'il l'on se trouve sur la dernière page.
161 * @pageCourante la page courante
162 * @dernierePage true si c'est la dernière page sinon false
164 euphorik
.Conversation
.prototype.setPage = function(pageCourante
, dernierePage
) {
165 $("#" + this.getId() + " .numPage").text(pageCourante
);
166 $("#" + this.getId() + " .next").css("display", pageCourante
=== 1 ? "none" : "inline");
167 $("#" + this.getId() + " .prev").css("display", dernierePage
? "none" : "inline");
171 * @funNext appelé lorsque l'on passe à la page suivante (de 2 à 1 par exemple)
172 * @funPrev appelé lorsque l'on passe à la page précédente (de 1 à 2 par exemple)
173 * @funReset appelé lorsque l'on souhaite revenir à la page une
175 euphorik
.Conversation
.prototype.setFunPage = function(funNext
, funPrev
, funReset
) {
176 var thisConversation
= this;
178 $("#" + this.getId() + " .next").click(
179 function() { funNext(thisConversation
.num
); }
181 $("#" + this.getId() + " .prev").click(
182 function() { funPrev(thisConversation
.num
); }
184 $("#" + this.getId() + " .numPage").click(
185 function() { funReset(thisConversation
.num
); }
190 * Retourne l'id de la conversation sous la forme (par exemple) "conv3".
192 euphorik
.Conversation
.prototype.getId = function() {
193 return "conv" + this.id
;
197 * Après avoir créé un message celui ci est ajouté à une conversation via cette méthode.
199 euphorik
.Conversation
.prototype.ajouterMessage = function(message
) {
200 this.messages
.push(message
);
201 this.messagesParId
[message
.id
] = message
;
203 // enlève le message exedentaire si nécessaire
204 if (this.messages
.length
> this.nbMessageMax
) {
205 delete this.messagesParId
[this.messages
.shift().id
];
208 // met à jour le membre 'estReponduPar' des messages de la conversation
209 for (var i
= 0; i
< this.messages
.length
- 1; i
++) {
210 var autreMess
= this.messages
[i
];
211 if (autreMess
.id
in message
.repondA
) {
212 autreMess
.estReponduPar
[message
.id
] = true;
218 * 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 ?
220 euphorik
.Conversation
.prototype.viderMessages = function() {
222 this.messagesParId
= {};
223 this.idDernierMessageAffiche
= 0;
224 $("#" + this.getId() + " .messages .message").remove();
226 // enlève également la racine
227 $("#" + this.getId() + " .titre .messageRacine").empty();
230 euphorik
.Conversation
.prototype.idMessageFromString = function(idString
) {
231 return parseInt(idString
.substr(4 + this.getId().length
), 36);
235 * Après l'ajout d'un ou plusieurs message cette méthode est appelée afin
236 * d'afficher les messages non-affichés.
237 * FIXME : méthode super lourde, à optimiser.
239 euphorik
.Conversation
.prototype.flush = function() {
240 var thisConversation
= this;
241 var reverse
= this.client
.chatOrder
=== "reverse";
243 var messagePair
= (this.idDernierMessageAffiche
=== 0 ? true :
244 ($("#" + this.getId() + " .messages div:" + (reverse
? "first" : "last")).attr("class").search("messagePair") === -1)
247 // construction de l'XHTML des messages
249 this.messages
.each(function(i
, mess
) {
250 if (mess
.id
> thisConversation
.idDernierMessageAffiche
) {
251 XHTML
+= mess
.XHTML(messagePair
, thisConversation
.getId());
252 messagePair
= !messagePair
;
258 // pour chaque nouveau message au niveau du document on lui assigne ses événements
259 DOM
.each(function() { thisConversation
.attacherEventsSurMessage(this); });
262 DOM
.prependTo("#" + this.getId() + " .messages");
264 DOM
.appendTo("#" + this.getId() + " .messages");
267 // enlève les messages exedentaires au niveau du document
268 var nbMessagesAffiche
= $("#" + this.getId() + " .messages .message").size();
269 if (nbMessagesAffiche
> this.nbMessageMax
) {
271 $("#" + this.getId() + " .messages .message").slice(this.nbMessageMax
, nbMessagesAffiche
).remove();
273 $("#" + this.getId() + " .messages .message").slice(0, nbMessagesAffiche
- this.nbMessageMax
).remove();
277 if (this.messages
.length
> 0) {
278 this.idDernierMessageAffiche
= this.messages
[this.messages
.length
-1].id
;
281 // met à jour la racine de la conversation
286 * Attache des événements à un message donné.
287 * @element le message du DOM
289 euphorik
.Conversation
.prototype.attacherEventsSurMessage = function(element
) {
291 var idMess
= this.idMessageFromString($(element
).attr("id"));
293 if (idMess
in this.conversations
.messagesRepond
) {
294 $(element
).addClass("repondEnEvidence");
297 var thisConversation
= this;
298 $(".lienConv", element
).click(
300 // FIXME : ya pas mieux ?
301 var racine
= $(event
.target
).text();
302 thisConversation
.conversations
.ouvrirConversation(parseInt(racine
.substring(1, racine
.length
- 1), 36));
307 $(element
).click(function(event
) {
308 if ($(event
.target
).is("a") || $(event
.target
).parents("#outilsBan").length
> 0) {
312 // met ou enlève la mise en evidence du message
313 thisConversation
.conversations
.toggleMessageRepond(thisConversation
.messagesParId
[idMess
]);
315 // donne le focus à la ligne de saisie
316 $("form input.message").focus();
317 }).hover(function(event
) { // affiche les outils liées au message
318 var top
= $(this).offset().top
319 var left
= $(this).offset().left
+ $(this).width() - thisConversation
.util
.outilsMessage
.width()
320 thisConversation
.util
.outilsMessage
.css("top", top
+ 1).css("left", left
).prependTo(this).show();
323 // extraction d'une conversation
324 /*if ($(event.target).is(".extraire")) {
325 thisConversation.conversations.ouvrirConversation(idMess);
329 if ($(event.target).is(".extraireCompletement")) {
330 thisConversation.conversations.ouvrirConversation(thisConversation.messagesParId[idMess].racineId);
334 thisConversation
.util
.outilsMessage
.hide();
337 // mise en évidence de la conversation
338 $(".entete", element
).hover(
340 thisConversation
.decolorerEntetes();
341 thisConversation
.afficherConversation(idMess
);
343 // quand on sort de l'entête du message la mise en évidence est enlevée
345 thisConversation
.enleverMiseEnEvidence();
346 thisConversation
.decolorerEntetes();
347 thisConversation
.colorerEntetes();
351 // est-ce que l'on affichage la date du message ?
352 if (thisConversation
.client
.viewTimes
) {
353 $(".dateComplete", element
).show();
355 $(".dateComplete", element
).hide();
358 $("a[@rel*=lightbox]", element
).lightBox();
360 // les outils de bannissement (uniquement pour les ekMaster)
361 if (thisConversation
.client
.ekMaster
) {
362 $(".pseudo", element
).hover(
364 var userId
= parseInt($(".id", this).text(), 10);
365 var pseudo
= $(this);
366 var h
= pseudo
.outerHeight();
367 var offset
= pseudo
.offset();
368 // TODO : calculer automatiquement la largeur plutôt que d'inscrire des valeurs en brut'
369 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();
370 $("img", thisConversation
.util
.outilsBan
).unbind("click");
371 $("#slap", thisConversation
.util
.outilsBan
).click(
373 thisConversation
.client
.slap(userId
, $("#outilsBan input").val());
374 $("#outilsBan input").val("");
375 $("#outilsBan").hide();
378 $("#kick", thisConversation
.util
.outilsBan
).click(
380 thisConversation
.client
.kick(userId
, $("#outilsBan input").val());
381 $("#outilsBan input").val("");
382 $("#outilsBan").hide();
385 $("#ban", thisConversation
.util
.outilsBan
).click(
387 thisConversation
.client
.ban(userId
, $("#outilsBan input").val());
388 $("#outilsBan input").val("");
389 $("#outilsBan").hide();
394 thisConversation
.util
.outilsBan
.hide();
401 * Etablit une liste des messages à mettre en evidence et des messages à cacher.
402 * Puis applique un plan diabolique.
403 * @param id l'id du message
405 euphorik
.Conversation
.prototype.afficherConversation = function(id
) {
406 var thisConversation
= this;
408 var message
= this.messagesParId
[id
];
413 var mess
= message
.getConversation(this);
415 // FIXME : cet appel est très lent
416 $("#" + this.getId() + " .messages .message").each(
419 var statut
= mess
[thisConversation
.idMessageFromString(jq
.attr("id"))];
420 if (statut
=== undefined) {
421 jq
.addClass("cache");
423 jq
.removeClass("cache");
425 // "repondu" et "reponse" sont prioritaitres à "proprietaire"
426 // contrairement à la vue normale (sans mise en évidence d'une conversation)
428 jq
.addClass("repondu");
431 jq
.addClass("reponse");
434 jq
.addClass("proprietaire");
443 * Supprime une conversation.
444 * Ne l'enlève pas du DOM.
446 euphorik
.Conversation
.prototype.supprimer = function() {
447 $("#" + this.getId()).remove();