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 function Conversation(conversations
, num
)
30 this.conversations
= conversations
31 this.num
= num
// peut changer au cours de la vie de la conversation, n'est pas un id !
32 this.id
= Math
.floor(Math
.random() * 1000000).toString(36)
34 this.util
= this.conversations
.util
35 this.formateur
= this.conversations
.formateur
36 this.client
= this.conversations
.client
38 this.idDernierMessageAffiche
= 0
39 this.racine
= undefined
42 this.messagesParId
= {}
44 this.nbMessageMax
= euphorik
.conf
.nbMessageAffiche
// Le nombre de message affiché par page
46 var messagesXHTML
= '<div class="messages"></div>'
47 var messageRacineXHTML
= '<div class="messageRacine"></div>'
48 var reverse
= this.client
.chatOrder
== "reverse"
51 '<td class="conversation" id="' + this.getId() + '">' +
52 (reverse
? messagesXHTML : "") +
53 '<div class="titre">' +
54 (reverse
? messageRacineXHTML : "") +
56 (num
== 0 ? '' : '<div class="fermer"></div><div class="lien"></div><div class="reduire"></div>') +
57 '<span class="next"><</span><span class="numPage">1</span><span class="prev">></span>' +
59 (reverse
? "" : messageRacineXHTML
) +
61 (reverse
? "" : messagesXHTML
) +
64 $("#conversations tr").append(XHTML
)
66 this.util
.infoBulle("Aller à la première page", $("#" + this.getId() + " .numPage"), euphorik
.Util
.positionBulleType
.haut
)
69 this.util
.infoBulle("Créer un lien vers la conversation", $("#" + this.getId() + " .lien"))
70 this.util
.infoBulle("Fermer la conversation", $("#" + this.getId() + " .fermer"))
75 * @racine un message représentant la racine de la conversation, vaut undefined pour la conversation générale
77 Conversation
.prototype.setRacine = function(racineElement
)
79 this.racine
= new 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 Conversation
.prototype.majRacine = function()
88 if (this.racine
== undefined)
91 if (!(this.racine
.id
in this.messagesParId
))
93 this.messagesParId
[this.racine
.id
] = this.racine
94 var element
= $(this.racine
.XHTML(true, this.getId()))
95 this.attacherEventsSurMessage(element
)
96 $("#" + this.getId() + " .titre .messageRacine").html(element
)
100 Conversation
.prototype.enleverMiseEnEvidence = function()
102 $("#" + this.getId() + " .message").removeClass("cache")
105 Conversation
.prototype.colorerEntetes = function()
107 var messagesReponse
= ""
108 var messagesRepondu
= ""
109 var messagesProprietaire
= ""
110 for (var i
= 0; i
< this.messages
.length
; i
++)
112 if (this.messages
[i
].appartientAuClient
)
113 messagesProprietaire
+= "#" + this.messages
[i
].getId(this.getId()) + ","
114 else if (this.messages
[i
].clientARepondu
)
115 messagesRepondu
+= "#" + this.messages
[i
].getId(this.getId()) + ","
116 else if (this.messages
[i
].estUneReponse
)
117 messagesReponse
+= "#" + this.messages
[i
].getId(this.getId()) + ","
119 $(messagesReponse
).addClass("reponse")
120 $(messagesRepondu
).addClass("repondu")
121 $(messagesProprietaire
).addClass("proprietaire")
124 Conversation
.prototype.decolorerEntetes = function()
126 $("#" + this.getId() + " .messages .message")
127 .removeClass("reponse")
128 .removeClass("repondu")
129 .removeClass("proprietaire")
133 * Défini la page courante et s'il l'on se trouve sur la dernière page.
134 * @pageCourante la page courante
135 * @dernierePage true si c'est la dernière page sinon false
137 Conversation
.prototype.setPage = function(pageCourante
, dernierePage
)
139 $("#" + this.getId() + " .numPage").text(pageCourante
)
140 $("#" + this.getId() + " .next").css("display", pageCourante
== 1 ? "none" : "inline")
141 $("#" + this.getId() + " .prev").css("display", dernierePage
? "none" : "inline")
145 * Evenement déclanché lors de l'insertion du lien de la conversation dans le message courant.
147 Conversation
.prototype.eventLien = function(fun
)
149 var thisConversation
= this
151 $("#" + this.getId() + " .titre .lien").click(
154 fun(thisConversation
.num
)
160 * Evenement déclanché lors de la fermeture de la conversation.
162 Conversation
.prototype.eventFermer = function(fun
)
164 var thisConversation
= this
166 $("#" + this.getId() + " .titre .fermer").click(
169 fun(thisConversation
.num
)
175 * @funNext appelé lorsque l'on passe à la page suivante (de 2 à 1 par exemple)
176 * @funPrev appelé lorsque l'on passe à la page précédente (de 1 à 2 par exemple)
177 * @funReset appelé lorsque l'on souhaite revenir à la page une
179 Conversation
.prototype.setFunPage = function(funNext
, funPrev
, funReset
)
181 var thisConversation
= this
183 $("#" + this.getId() + " .next").click(
184 function() { funNext(thisConversation
.num
) }
186 $("#" + this.getId() + " .prev").click(
187 function() { funPrev(thisConversation
.num
) }
189 $("#" + this.getId() + " .numPage").click(
190 function() { funReset(thisConversation
.num
) }
195 * Retourne l'id de la conversation sous la forme (par exemple) "conv3".
197 Conversation
.prototype.getId = function()
199 return "conv" + this.id
202 Conversation
.prototype.ajouterMessage = function(message
)
204 this.messages
.push(message
)
205 this.messagesParId
[message
.id
] = message
206 if (this.messages
.length
> this.nbMessageMax
)
207 delete this.messagesParId
[this.messages
.shift().id
]
211 * 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 ?
213 Conversation
.prototype.viderMessages = function()
216 this.messagesParId
= {}
217 this.idDernierMessageAffiche
= 0
218 $("#" + this.getId() + " .messages .message").remove()
220 // enlève également la racine
221 $("#" + this.getId() + " .titre .messageRacine").empty()
224 Conversation
.prototype.idMessageFromString = function(idString
)
226 return parseInt(idString
.substr(4 + this.getId().length
), 36)
230 * Après l'ajout d'un ou plusieurs message cette méthode est appelée afin
231 * d'afficher les messages non-affichés.
232 * FIXME : méthode super lourde, à optimiser.
234 Conversation
.prototype.flush = function()
236 var thisConversation
= this
237 var reverse
= this.client
.chatOrder
== "reverse"
239 // est-ce que le prochain message est pair ? (permet d'alterner le style des messages)
240 var messagePair
= (this.idDernierMessageAffiche
== 0 ? true :
241 ($("#" + this.getId() + " .messages div:" + (reverse
? "first" : "last")).attr("class").search("messagePair") == -1)
244 // construction de l'XHTML des messages
246 for (var i
= 0; i
< this.messages
.length
; i
++)
247 if (this.messages
[i
].id
> this.idDernierMessageAffiche
)
249 XHTML
+= this.messages
[i
].XHTML(messagePair
, this.getId())
250 messagePair
= !messagePair
255 // pour chaque nouveau message au niveau du document on crée ses événements
256 DOM
.each(function() { thisConversation
.attacherEventsSurMessage(this) })
258 DOM
.prependTo("#" + this.getId() + " .messages")
260 DOM
.appendTo("#" + this.getId() + " .messages")
262 // enlève les messages exedentaires
263 var nbMessagesAffiche
= $("#" + this.getId() + " .messages .message").size()
264 if (nbMessagesAffiche
> this.nbMessageMax
)
267 $("#" + this.getId() + " .messages .message").slice(this.nbMessageMax
, nbMessagesAffiche
).remove()
269 $("#" + this.getId() + " .messages .message").slice(0, nbMessagesAffiche
- this.nbMessageMax
).remove()
272 if (this.messages
.length
> 0)
273 this.idDernierMessageAffiche
= this.messages
[this.messages
.length
-1].id
275 // met à jour la racine de la conversation
279 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(
291 // FIXME : ya pas mieux ?
292 var racine
= $(event
.target
).text()
293 thisConversation
.conversations
.ouvrirConversation(parseInt(idString
.substring(1, racine
.length
- 1), 36))
301 if ($(event
.target
).is("a") || $(event
.target
).parents("#outilsBan").length
> 0) return
303 // extraction d'une conversation
304 if ($(event
.target
).is(".extraire"))
306 thisConversation
.conversations
.ouvrirConversation(idMess
)
310 if ($(event
.target
).is(".extraireCompletement"))
312 thisConversation
.conversations
.ouvrirConversation(thisConversation
.messagesParId
[idMess
].racineId
)
316 // met ou enlève la mise en evidence du message
317 thisConversation
.conversations
.toggleMessageRepond(thisConversation
.messagesParId
[idMess
])
319 // donne le focus à la ligne de saisie
320 $("form input.message").focus()
324 // mise en évidence de la conversation
325 $(".entete", element
).hover(
328 thisConversation
.decolorerEntetes()
329 thisConversation
.afficherConversation(idMess
)
331 // quand on sort de l'entête du message la mise en évidence est enlevée
334 thisConversation
.enleverMiseEnEvidence()
335 thisConversation
.decolorerEntetes()
336 thisConversation
.colorerEntetes()
340 if (thisConversation
.client
.viewTimes
)
341 $(".dateComplete", element
).show()
343 $(".dateComplete", element
).hide()
345 $("a[@rel*=lightbox]", element
).lightBox()
347 // les outils de bannissement (uniquement pour les ekMaster)
348 if (thisConversation
.client
.ekMaster
)
349 $(".pseudo", element
).hover(
352 var userId
= parseInt($(".id", this).text())
354 var h
= pseudo
.outerHeight()
355 var offset
= pseudo
.offset()
356 // TODO : calculer automatiquement la largeur plutôt que d'inscrire des valeurs en brut'
357 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()
358 $("img", thisConversation
.util
.outilsBan
).unbind("click")
359 $("#slap", thisConversation
.util
.outilsBan
).click(
362 thisConversation
.client
.slap(userId
, $("#outilsBan input").val())
363 $("#outilsBan input").val("")
364 $("#outilsBan").hide()
367 $("#kick", thisConversation
.util
.outilsBan
).click(
370 thisConversation
.client
.kick(userId
, $("#outilsBan input").val())
371 $("#outilsBan input").val("")
372 $("#outilsBan").hide()
375 $("#ban", thisConversation
.util
.outilsBan
).click(
378 thisConversation
.client
.ban(userId
, $("#outilsBan input").val())
379 $("#outilsBan input").val("")
380 $("#outilsBan").hide()
386 $("#outilsBan", this).hide()
392 * Etablit une liste des messages à mettre en evidence et des messages à cacher.
393 * Puis applique un plan diabolique.
394 * @param id l'id du message
396 Conversation
.prototype.afficherConversation = function(id
)
398 var thisConversation
= this
400 var message
= this.messagesParId
[id
]
401 if (message
== undefined) return
403 var mess
= message
.getConversation(this)
405 // FIXME : cet appel est très lent
406 $("#" + this.getId() + " .messages .message").each(
410 var statut
= mess
[thisConversation
.idMessageFromString(jq
.attr("id"))]
411 if (statut
== undefined)
415 jq
.removeClass("cache")
418 // "repondu" et "reponse" sont prioritaitres à "proprietaire"
419 // contrairement à la vue normale (sans mise en évidence d'une conversation)
421 jq
.addClass("repondu")
424 jq
.addClass("reponse")
427 jq
.addClass("proprietaire")
436 * Supprime une conversation.
438 Conversation
.prototype.supprimer = function()
440 $("#" + this.getId()).remove()