ADD création d'un message associé au troll de la semaine lors de l'élection de celui ci.
[euphorik.git] / js / euphorik.js
1 // coding: utf-8
2 // Copyright 2008 Grégory Burri
3 //
4 // This file is part of Euphorik.
5 //
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.
10 //
11 // Euphorik is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
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/>.
18
19 /**
20 * Contient la base javascript pour le site euphorik.ch.
21 * Chaque page possède son propre fichier js nommé "page<nom de la page>.js".
22 * Auteur : GBurri
23 * Date : 6.11.2007
24 */
25
26
27 /**
28 * La configuration.
29 * Normalement 'const' à la place de 'var' mais non supporté par IE7.
30 */
31 var conf = {
32 nbMessageAffiche : 40, // (par page)
33 pseudoDefaut : "<nick>",
34 tempsAffichageMessageDialogue : 4000, // en ms
35 smiles : {
36 "smile" : [/:\)/g, /:-\)/g],
37 "bigsmile" : [/:D/g, /:-D/g],
38 "clin" : [/;\)/g, /;-\)/g],
39 "cool" : [/8\)/g, /8-\)/g],
40 "eheheh" : [/:P/g, /:-P/g],
41 "lol" : [/\[-lol\]/g],
42 "spliff" : [/\[-spliff\]/g],
43 "oh" : [/:o/g, /:O/g],
44 "heink" : [/\[-heink\]/g],
45 "hum" : [/\[-hum\]/g],
46 "boh" : [/\[-boh\]/g],
47 "sniff" : [/:\(/g, /:-\(/g],
48 "triste" : [/\[-triste\]/g],
49 "pascontent" : [/>\(/g, /&gt;\(/g],
50 "argn" : [/\[-argn\]/g],
51 "redface" : [/\[-redface\]/g],
52 "bunny" : [/\[-lapin\]/g],
53 "chat" : [/\[-chat\]/g],
54 "renne" : [/\[-renne\]/g],
55 "star" : [/\[-star\]/g],
56 "kirby" : [/\[-kirby\]/g],
57 "slurp" : [/\[-slurp\]/g],
58 "agreed" : [/\[-agreed\]/g],
59 "dodo" : [/\[-dodo\]/g],
60 "bn" : [/\[-bn\]/g]
61 }
62 }
63
64 ///////////////////////////////////////////////////////////////////////////////////////////////////
65
66 String.prototype.trim = function()
67 {
68 return jQuery.trim(this) // anciennement : this.replace(/^\s+|\s+$/g, "");
69 }
70
71 String.prototype.ltrim = function()
72 {
73 return this.replace(/^\s+/, "");
74 }
75
76 String.prototype.rtrim = function()
77 {
78 return this.replace(/\s+$/, "");
79 }
80
81 ///////////////////////////////////////////////////////////////////////////////////////////////////
82
83 /**
84 * Cette classe regroupe des fonctions utilitaires (helpers).
85 * @formateur est permet de formater les messages affichés à l'aide de messageDialogue (facultatif)
86 */
87 function Util(formateur)
88 {
89 $("#info .fermer").click(function(){
90 $("#info").slideUp(50)
91 })
92
93 this.formateur = formateur
94 }
95
96 var messageType = {informatif: 0, question: 1, erreur: 2}
97
98 /**
99 * Affiche une boite de dialogue avec un message à l'intérieur.
100 * @param message le message (string)
101 * @param type voir 'messageType'. par défaut messageType.informatif
102 * @param les boutons sous la forme d'un objet ou les clefs sont les labels des boutons
103 * et les valeurs les fonctions executées lorsqu'un bouton est activé.
104 * @param formate faut-il formaté le message ? true par défaut
105 */
106 Util.prototype.messageDialogue = function(message, type, boutons, formate)
107 {
108 var thisUtil = this
109
110 if (type == undefined)
111 type = messageType.informatif
112
113 if (formate == undefined)
114 formate = true
115
116 if (this.timeoutMessageDialogue != undefined)
117 clearTimeout(this.timeoutMessageDialogue)
118
119 var fermer = function(){$("#info").slideUp(100)}
120 fermer()
121
122 $("#info .message").html(thisUtil.formateur == undefined || !formate ? message : thisUtil.formateur.traitementComplet(message))
123 switch(type)
124 {
125 case messageType.informatif : $("#info #icone").attr("class", "information"); break
126 case messageType.question : $("#info #icone").attr("class", "interrogation"); break
127 case messageType.erreur : $("#info #icone").attr("class", "exclamation"); break
128 }
129 $("#info .boutons").html("")
130 for (var b in boutons)
131 $("#info .boutons").append("<div>" + b + "</div>").find("div:last").click(boutons[b]).click(fermer)
132
133 $("#info").slideDown(200)
134 this.timeoutMessageDialogue = setTimeout(fermer, conf.tempsAffichageMessageDialogue)
135 }
136
137 /**
138 * Utilisé pour l'envoie de donnée avec la méthode ajax de jQuery.
139 */
140 Util.prototype.jsonVersAction = function(json)
141 {
142 return {action : JSON.stringify(json) }
143 }
144
145 Util.prototype.md5 = function(chaine)
146 {
147 return hex_md5(chaine)
148 }
149
150 // pompé de http://www.faqts.com/knowledge_base/view.phtml/aid/13562/fid/130
151 Util.prototype.setSelectionRange = function(input, selectionStart, selectionEnd)
152 {
153 if (input.setSelectionRange)
154 {
155 input.focus()
156 input.setSelectionRange(selectionStart, selectionEnd)
157 }
158 else if (input.createTextRange)
159 {
160 var range = input.createTextRange()
161 range.collapse(true)
162 range.moveEnd('character', selectionEnd)
163 range.moveStart('character', selectionStart)
164 range.select()
165 }
166 }
167
168 Util.prototype.setCaretToEnd = function(input)
169 {
170 this.setSelectionRange(input, input.value.length, input.value.length)
171 }
172 Util.prototype.setCaretToBegin = function(input)
173 {
174 this.setSelectionRange(input, 0, 0)
175 }
176 Util.prototype.setCaretToPos = function(input, pos)
177 {
178 this.setSelectionRange(input, pos, pos)
179 }
180 Util.prototype.selectString = function(input, string)
181 {
182 var match = new RegExp(string, "i").exec(input.value)
183 if (match)
184 {
185 this.setSelectionRange (input, match.index, match.index + match[0].length)
186 }
187 }
188 Util.prototype.replaceSelection = function(input, replaceString) {
189 if (input.setSelectionRange)
190 {
191 var selectionStart = input.selectionStart
192 var selectionEnd = input.selectionEnd
193 input.value = input.value.substring(0, selectionStart) + replaceString + input.value.substring(selectionEnd)
194
195 if (selectionStart != selectionEnd) // has there been a selection
196 this.setSelectionRange(input, selectionStart, selectionStart + replaceString.length)
197 else // set caret
198 this.setCaretToPos(input, selectionStart + replaceString.length)
199 }
200 else if (document.selection)
201 {
202 var range = document.selection.createRange();
203 if (range.parentElement() == input)
204 {
205 var isCollapsed = range.text == ''
206 range.text = replaceString
207 if (!isCollapsed)
208 {
209 // there has been a selection
210 // it appears range.select() should select the newly
211 // inserted text but that fails with IE
212 range.moveStart('character', -replaceString.length);
213 range.select();
214 }
215 }
216 }
217 }
218
219 Util.prototype.rot13 = function(chaine)
220 {
221 var ACode = 'A'.charCodeAt(0)
222 var aCode = 'a'.charCodeAt(0)
223 var MCode = 'M'.charCodeAt(0)
224 var mCode = 'm'.charCodeAt(0)
225 var ZCode = 'Z'.charCodeAt(0)
226 var zCode = 'z'.charCodeAt(0)
227
228 var f = function(ch, pos) {
229 if (pos == ch.length)
230 return ""
231
232 var c = ch.charCodeAt(pos);
233 return String.fromCharCode(
234 c +
235 (c >= ACode && c <= MCode || c >= aCode && c <= mCode ? 13 :
236 (c > MCode && c <= ZCode || c > mCode && c <= zCode ? -13 : 0))
237 ) + f(ch, pos + 1)
238 }
239 return f(chaine, 0)
240 }
241
242 ///////////////////////////////////////////////////////////////////////////////////////////////////
243
244 function Pages()
245 {
246 this.pageCourante = null
247 this.pages = {}
248 }
249
250 Pages.prototype.ajouterPage = function(page)
251 {
252 page.pages = this // la magie des langages dynamiques : le foutoire
253 this.pages[page.nom] = page
254 }
255
256 Pages.prototype.afficherPage = function(nomPage, forcerChargement)
257 {
258 if (forcerChargement == undefined) forcerChargement = false
259
260 var page = this.pages[nomPage]
261 if (page == undefined || (!forcerChargement && page == this.pageCourante)) return
262
263 if (this.pageCourante != null && this.pageCourante.decharger)
264 this.pageCourante.decharger()
265
266 $("#menu li").removeClass("courante")
267 $("#menu li." + nomPage).addClass("courante")
268
269 this.pageCourante = page
270 $("#page").html(this.pageCourante.contenu()).removeClass().addClass(this.pageCourante.nom)
271
272 if (this.pageCourante.charger)
273 this.pageCourante.charger()
274 }
275
276 ///////////////////////////////////////////////////////////////////////////////////////////////////
277
278 /**
279 * Classe permettant de formater du texte par exemple pour la substitution des liens dans les
280 * message par "[url]".
281 * TODO : améliorer l'efficacité des méthods notamment lié au smiles.
282 */
283 function Formateur()
284 {
285 this.smiles = conf.smiles
286 this.protocoles = "http|https|ed2k"
287
288 this.regexUrl = new RegExp("(?:(?:" + this.protocoles + ")://|www\\.)[^ ]*", "gi")
289 this.regexImg = new RegExp("^.*?\\.(gif|jpg|png|jpeg|bmp|tiff)$", "i")
290 this.regexDomaine = new RegExp("^(?:(?:" + this.protocoles + ")://|www\\.).*?([^/.]+\\.[^/.]+)(?:$|/).*$", "i")
291 this.regexTestProtocoleExiste = new RegExp("^(?:" + this.protocoles + ")://.*$", "i")
292 this.regexNomProtocole = new RegExp("^(.*?)://")
293 }
294
295 /**
296 * Formate un pseudo saise par l'utilisateur.
297 * @param pseudo le pseudo brut
298 * @return le pseudo filtré
299 */
300 Formateur.prototype.filtrerInputPseudo = function(pseudo)
301 {
302 return pseudo.replace(/{|}/g, "").trim()
303 }
304
305 Formateur.prototype.getSmilesHTML = function()
306 {
307 var XHTML = ""
308 for (var sNom in this.smiles)
309 {
310 XHTML += "<img class=\"" + sNom + "\" src=\"img/smileys/" + sNom + ".gif\" alt =\"" + sNom + "\" />"
311 }
312 return XHTML
313 }
314
315 /**
316 * Formatage complet d'un texte.
317 * @M le message
318 * @pseudo facultatif, permet de contruire le label des images sous la forme : "<Pseudo> : <Message>"
319 */
320 Formateur.prototype.traitementComplet = function(M, pseudo)
321 {
322 return this.traiterLiensConv(this.traiterSmiles(this.traiterURL(this.traiterWikiSyntaxe(this.remplacerBalisesHTML(M)), pseudo)))
323 }
324
325 /**
326 * Transforme les liens en entités clickables.
327 * Un lien vers une conversation permet d'ouvrire celle ci, elle se marque comme ceci dans un message :
328 * "{5F}" ou 5F est la racine de la conversation.
329 * Ce lien sera transformer en <span class="lienConv">{5F}</span> pouvant être clické pour créer la conv 5F.
330 */
331 Formateur.prototype.traiterLiensConv = function(M)
332 {
333 return M.replace(
334 /\{\w+\}/g,
335 function(lien)
336 {
337 return "<span class=\"lienConv\">" + lien + "</span>"
338 }
339 )
340 }
341
342 /**
343 * FIXME : Cette méthode est attrocement lourde ! A optimiser.
344 * moyenne sur échantillon : 234ms
345 */
346 Formateur.prototype.traiterSmiles = function(M)
347 {
348 for (var sNom in this.smiles)
349 {
350 ss = this.smiles[sNom]
351 for (var i = 0; i < ss.length; i++)
352 M = M.replace(ss[i], "<img src=\"img/smileys/" + sNom + ".gif\" alt =\"" + sNom + "\" />")
353 }
354 return M
355 }
356
357 Formateur.prototype.remplacerBalisesHTML = function(M)
358 {
359 return M.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;")
360 }
361
362 Formateur.prototype.traiterURL = function(M, pseudo)
363 {
364 thisFormateur = this
365
366 var traitementUrl = function(url)
367 {
368 // si ya pas de protocole on rajoute "http://"
369 if (!thisFormateur.regexTestProtocoleExiste.test(url))
370 url = "http://" + url
371 var extension = thisFormateur.getShort(url)
372 return "<a " + (extension[1] ? "title=\"" + (pseudo == undefined ? "" : thisFormateur.traiterPourFenetreLightBox(pseudo, url) + ": ") + thisFormateur.traiterPourFenetreLightBox(M, url) + "\"" + " rel=\"lightbox\"" : "") + " href=\"" + url + "\" >[" + extension[0] + "]</a>"
373 }
374 return M.replace(this.regexUrl, traitementUrl)
375 }
376
377 /**
378 * Formatage en utilisant un sous-ensemble des règles de mediwiki.
379 * par exemple ''italic'' devient <i>italic</i>
380 */
381 Formateur.prototype.traiterWikiSyntaxe = function(M)
382 {
383 return M.replace(
384 /'''(.*?)'''/g,
385 function(texte, capture)
386 {
387 return "<b>" + capture + "</b>"
388 }
389 ).replace(
390 /''(.*?)''/g,
391 function(texte, capture)
392 {
393 return "<i>" + capture + "</i>"
394 }
395 )
396 }
397
398 /**
399 * Renvoie une version courte de l'url.
400 * par exemple : http://en.wikipedia.org/wiki/Yakov_Smirnoff devient wikipedia.org
401 */
402 Formateur.prototype.getShort = function(url)
403 {
404 var estUneImage = false
405 var versionShort = null
406 var rechercheImg = this.regexImg.exec(url)
407
408 if (rechercheImg != null)
409 {
410 versionShort = rechercheImg[1].toLowerCase()
411 if (versionShort == "jpeg") versionShort = "jpg" // jpeg -> jpg
412 estUneImage = true
413 }
414 else
415 {
416 var rechercheDomaine = this.regexDomaine.exec(url)
417 if (rechercheDomaine != null && rechercheDomaine.length >= 2)
418 versionShort = rechercheDomaine[1]
419 else
420 {
421 var nomProtocole = this.regexNomProtocole.exec(url)
422 if (nomProtocole != null && nomProtocole.length >= 2)
423 versionShort = nomProtocole[1]
424 }
425 }
426
427 return [versionShort == null ? "url" : versionShort, estUneImage]
428 }
429
430 /**
431 * Traite les pseudo et messages à être affiché dans le titre d'une image visualisé avec lightbox.
432 */
433 Formateur.prototype.traiterPourFenetreLightBox = function(M, urlCourante)
434 {
435 thisFormateur = this
436 var traitementUrl = function(url)
437 {
438 return "[" + thisFormateur.getShort(url)[0] + (urlCourante == url ? "*" : "") + "]"
439 }
440
441 return this.remplacerBalisesHTML(M).replace(this.regexUrl, traitementUrl)
442 }
443
444
445 ///////////////////////////////////////////////////////////////////////////////////////////////////
446
447 // les statuts possibes du client
448 var statutType = {
449 // mode enregistré, peut poster des messages et modifier son profile
450 auth_registered : 0,
451 // mode identifié, peut poster des messages mais n'a pas accès au profile
452 auth_not_registered : 1,
453 // mode déconnecté, ne peut pas poster de message
454 deconnected : 2
455 }
456
457 function Client(util)
458 {
459 this.util = util
460
461 this.cookie = null
462 this.regexCookie = new RegExp("^cookie=([^;]*)")
463
464 // données personnels
465 this.resetDonneesPersonnelles()
466
467 this.setStatut(statutType.deconnected)
468 }
469
470 Client.prototype.resetDonneesPersonnelles = function()
471 {
472 this.id = 0
473 this.pseudo = conf.pseudoDefaut
474 this.login = ""
475 this.password = ""
476 this.email = ""
477 this.css = $("link#cssPrincipale").attr("href")
478 this.nickFormat = "nick"
479 this.cookie = undefined
480
481 this.pagePrincipale = 1
482 this.ekMaster = false
483
484 // les conversations, une conversation est un objet possédant les attributs suivants :
485 // - racine (entier)
486 // - page (entier)
487 this.conversations = new Array()
488 }
489
490 Client.prototype.setCss = function(css)
491 {
492 if (this.css == css || css == "")
493 return
494
495 this.css = css
496 $("link#cssPrincipale").attr("href", this.css)
497 this.majMenu()
498 }
499
500 Client.prototype.pageSuivante = function(numConv)
501 {
502 if (numConv < 0 && this.pagePrincipale > 1)
503 this.pagePrincipale -= 1
504 else if (this.conversations[numConv].page > 1)
505 this.conversations[numConv].page -= 1
506 }
507
508 Client.prototype.pagePrecedente = function(numConv)
509 {
510 if (numConv < 0)
511 this.pagePrincipale += 1
512 else
513 this.conversations[numConv].page += 1
514 }
515
516 /**
517 * Définit la première page pour la conversation donnée.
518 * @return true si la page a changé sinon false
519 */
520 Client.prototype.goPremierePage = function(numConv)
521 {
522 if (numConv < 0)
523 {
524 if (this.pagePrincipale == 1)
525 return false
526 this.pagePrincipale = 1
527 }
528 else
529 {
530 if (this.conversations[numConv].page == 1)
531 return false
532 this.conversations[numConv].page = 1
533 }
534 return true
535 }
536
537 /**
538 * Ajoute une conversation à la vue de l'utilisateur.
539 * Le profile de l'utilisateur est directement sauvegardé sur le serveur.
540 * @param racines la racine de la conversation (integer)
541 * @return true si la conversation a été créée sinon false (par exemple si la conv existe déjà)
542 */
543 Client.prototype.ajouterConversation = function(racine)
544 {
545 // vérification s'il elle n'existe pas déjà
546 for (var i = 0; i < this.conversations.length; i++)
547 if (this.conversations[i].root == racine)
548 return false
549
550 this.conversations.push({root : racine, page : 1})
551 return true
552 }
553
554 Client.prototype.supprimerConversation = function(num)
555 {
556 if (num < 0 || num >= this.conversations.length) return
557
558 // décalage TODO : supprimer le dernier élément
559 for (var i = num; i < this.conversations.length - 1; i++)
560 this.conversations[i] = this.conversations[i+1]
561 this.conversations.pop()
562 }
563
564 Client.prototype.getJSONLogin = function(login, password)
565 {
566 return {
567 "action" : "authentification",
568 "login" : login,
569 "password" : password
570 }
571 }
572
573 Client.prototype.getJSONLoginCookie = function()
574 {
575 return {
576 "action" : "authentification",
577 "cookie" : this.cookie
578 }
579 }
580
581 /**
582 * le couple (login, password) est facultatif. S'il n'est pas fournit alors il ne sera pas possible
583 * de s'autentifier avec (login, password).
584 */
585 Client.prototype.getJSONEnregistrement = function(login, password)
586 {
587 var mess = { "action" : "register" }
588
589 if (login != undefined && password != undefined)
590 {
591 mess["login"] = login
592 mess["password"] = password
593 }
594
595 return mess;
596 }
597
598 Client.prototype.getJSONConversations = function()
599 {
600 var conversations = new Array()
601 for (var i = 0; i < this.conversations.length; i++)
602 conversations.push({ "root" : this.conversations[i].root, "page" : this.conversations[i].page})
603 return conversations
604 }
605
606 Client.prototype.getJSONProfile = function()
607 {
608 return {
609 "action" : "set_profile",
610 "cookie" : this.cookie,
611 "login" : this.login,
612 "password" : this.password,
613 "nick" : this.pseudo,
614 "email" : this.email,
615 "css" : this.css,
616 "nick_format" : this.nickFormat,
617 "main_page" : this.pagePrincipale < 1 ? 1 : this.pagePrincipale,
618 "conversations" : this.getJSONConversations()
619 }
620 }
621
622 /**
623 * Renvoie null si pas définit.
624 */
625 Client.prototype.getCookie = function()
626 {
627 var cookie = this.regexCookie.exec(document.cookie)
628 if (cookie == null) this.cookie = null
629 else this.cookie = cookie[1]
630 }
631
632 Client.prototype.delCookie = function()
633 {
634 document.cookie = "cookie=; max-age=0"
635 }
636
637 Client.prototype.setCookie = function(cookie)
638 {
639 if (this.cookie == null)
640 return
641
642 document.cookie =
643 "cookie="+this.cookie+
644 "; max-age=" + (60 * 60 * 24 * 365)
645 }
646
647 Client.prototype.authentifie = function()
648 {
649 return this.statut == statutType.auth_registered || this.statut == statutType.auth_not_registered
650 }
651
652 Client.prototype.setStatut = function(statut)
653 {
654 // conversation en "enum" si en "string"
655 if (typeof(statut) == "string")
656 {
657 statut =
658 statut == "auth_registered" ?
659 statutType.auth_registered :
660 (statut == "auth_not_registered" ? statutType.auth_not_registered : statutType.deconnected)
661 }
662
663 if (statut == this.statut) return
664
665 this.statut = statut
666 this.majMenu()
667 }
668
669 /**
670 * Effectue la connexion vers le serveur.
671 * Cette fonction est bloquante tant que la connexion n'a pas été établie.
672 * S'il existe un cookie en local on s'authentifie directement avec lui.
673 * Si il n'est pas possible de s'authentifier alors on affiche un captcha anti-bot.
674 */
675 Client.prototype.connexionCookie = function()
676 {
677 this.getCookie()
678 if (this.cookie == null) return false;
679 return this.connexion(this.getJSONLoginCookie())
680 }
681
682 Client.prototype.connexionLogin = function(login, password)
683 {
684 return this.connexion(this.getJSONLogin(login, password))
685 }
686
687 Client.prototype.enregistrement = function(login, password)
688 {
689 if (this.authentifie())
690 {
691 this.login = login
692 this.password = password
693 if(this.flush())
694 {
695 this.setStatut(statutType.auth_registered)
696 return true
697 }
698 return false
699 }
700 else
701 {
702 return this.connexion(this.getJSONEnregistrement(login, password))
703 }
704 }
705
706 Client.prototype.connexion = function(messageJson)
707 {
708 ;;; dumpObj(messageJson)
709 thisClient = this
710 jQuery.ajax(
711 {
712 async: false,
713 type: "POST",
714 url: "request",
715 dataType: "json",
716 data: this.util.jsonVersAction(messageJson),
717 success:
718 function(data)
719 {
720 ;;; dumpObj(data)
721 if (data["reply"] == "error")
722 thisClient.util.messageDialogue(data["error_message"])
723 else
724 thisClient.chargerDonnees(data)
725 }
726 }
727 )
728 return this.authentifie()
729 }
730
731 Client.prototype.deconnexion = function()
732 {
733 this.flush(true)
734 this.delCookie()
735 this.resetDonneesPersonnelles()
736 this.setStatut(statutType.deconnected) // deconnexion
737 }
738
739 Client.prototype.chargerDonnees = function(data)
740 {
741 // la modification du statut qui suit met à jour le menu, le menu dépend (page admin)
742 // de l'état ekMaster
743 this.ekMaster = data["ek_master"] != undefined ? data["ek_master"] : false
744
745 this.setStatut(data["status"])
746
747 if (this.authentifie())
748 {
749 this.cookie = data["cookie"]
750 this.setCookie()
751
752 this.id = data["id"]
753 this.login = data["login"]
754 this.pseudo = data["nick"]
755 this.email = data["email"]
756 this.setCss(data["css"])
757 this.nickFormat = data["nick_format"]
758
759 // la page de la conversation principale
760 this.pagePrincipale = data["main_page"] == undefined ? 1 : data["main_page"]
761
762 // les conversations
763 this.conversations = data["conversations"]
764 }
765 }
766
767 /**
768 * Met à jour les données personne sur serveur.
769 * @param async de manière asynchrone ? défaut = true
770 * @return false si le flush n'a pas pû se faire sinon true
771 */
772 Client.prototype.flush = function(async)
773 {
774 if (async == undefined)
775 async = false
776
777 if (!this.authentifie())
778 return false
779
780 var thisClient = this
781 var ok = true
782
783 ;;; dumpObj(this.getJSONProfile())
784 jQuery.ajax(
785 {
786 async: async,
787 type: "POST",
788 url: "request",
789 dataType: "json",
790 data: this.util.jsonVersAction(this.getJSONProfile()),
791 success:
792 function(data)
793 {
794 ;;; dumpObj(data)
795 if (data["reply"] == "error")
796 {
797 thisClient.util.messageDialogue(data["error_message"])
798 ok = false
799 }
800 }
801 }
802 )
803
804 return ok
805 }
806
807 Client.prototype.majMenu = function()
808 {
809 // TODO : à virer : ne plus changer de style de display ... spa beau .. ou trouver une autre méthode
810 // var displayType = this.css == "css/3/euphorik.css" ? "block" : "inline" //this.client
811 displayType = "block"
812
813 $("#menu .admin").css("display", this.ekMaster ? displayType : "none")
814
815 // met à jour le menu
816 if (this.statut == statutType.auth_registered)
817 {
818 $("#menu .profile").css("display", displayType).text("profile")
819 $("#menu .logout").css("display", displayType)
820 $("#menu .register").css("display", "none")
821 }
822 else if (this.statut == statutType.auth_not_registered)
823 {
824 $("#menu .profile").css("display", "none")
825 $("#menu .logout").css("display", displayType)
826 $("#menu .register").css("display", displayType)
827 }
828 else
829 {
830 $("#menu .profile").css("display", displayType).text("login")
831 $("#menu .logout").css("display", "none")
832 $("#menu .register").css("display", displayType)
833 }
834 }
835
836 Client.prototype.slap = function(userId, raison)
837 {
838 var thisClient = this
839
840 jQuery.ajax({
841 type: "POST",
842 url: "request",
843 dataType: "json",
844 data: this.util.jsonVersAction(
845 {
846 "action" : "slap",
847 "cookie" : thisClient.cookie,
848 "user_id" : userId,
849 "reason" : raison
850 }),
851 success:
852 function(data)
853 {
854 if (data["reply"] == "error")
855 thisClient.util.messageDialogue(data["error_message"])
856 }
857 })
858 }
859
860 Client.prototype.ban = function(userId, raison, minutes)
861 {
862 var thisClient = this
863
864 // par défaut un ban correspond à 3 jours
865 if (typeof(minutes) == "undefined")
866 minutes = 60 * 24 * 3
867
868 jQuery.ajax({
869 type: "POST",
870 url: "request",
871 dataType: "json",
872 data: this.util.jsonVersAction(
873 {
874 "action" : "ban",
875 "cookie" : thisClient.cookie,
876 "duration" : minutes,
877 "user_id" : userId,
878 "reason" : raison
879 }),
880 success:
881 function(data)
882 {
883 if (data["reply"] == "error")
884 thisClient.util.messageDialogue(data["error_message"])
885 }
886 })
887 }
888
889 Client.prototype.kick = function(userId, raison)
890 {
891 this.ban(userId, raison, 15)
892 }
893
894 ///////////////////////////////////////////////////////////////////////////////////////////////////
895
896 /**
897 * classe permettant de gérer les événements (push serveur).
898 * @page la page
899 */
900 function PageEvent(page, util)
901 {
902 this.page = page
903 this.util = util
904
905 // l'objet JSONHttpRequest représentant la connexion d'attente
906 this.attenteCourante = null
907 }
908
909 /**
910 * Arrête l'attente courante s'il y en a une.
911 */
912 PageEvent.prototype.stopAttenteCourante = function()
913 {
914 if (this.attenteCourante != null)
915 this.attenteCourante.abort()
916 }
917
918 /**
919 * Attend un événement lié à la page.
920 * @funSend une fonction renvoyant les données json à envoyer
921 * @funReceive une fonction qui accepte un paramètre correspondant au données reçues
922 */
923 PageEvent.prototype.waitEvent = function(funSend, funReceive)
924 {
925 var thisPageEvent = this
926
927 this.stopAttenteCourante()
928
929 // on doit conserver l'ordre des valeurs de l'objet JSON (le serveur les veux dans l'ordre définit dans le protocole)
930 // TODO : ya pas mieux ?
931 var dataToSend =
932 {
933 "action" : "wait_event",
934 "page" : this.page
935 }
936 var poulpe = funSend()
937 for (v in poulpe)
938 dataToSend[v] = poulpe[v]
939
940 ;;; dumpObj(dataToSend)
941 this.attenteCourante = jQuery.ajax({
942 type: "POST",
943 url: "request",
944 dataType: "json",
945 data: this.util.jsonVersAction(dataToSend),
946 success:
947 function(data)
948 {
949 ;;; dumpObj(data)
950
951 funReceive(data)
952
953 // rappel de la fonction dans 100 ms
954 setTimeout(function(){ thisPageEvent.waitEvent(funSend, funReceive) }, 100);
955 },
956 error:
957 function(XMLHttpRequest, textStatus, errorThrown)
958 {
959 setTimeout(function(){ thisPageEvent.waitEvent(funSend, funReceive) }, 1000);
960 }
961 })
962
963 }
964
965 ///////////////////////////////////////////////////////////////////////////////////////////////////
966
967 function initialiserListeStyles(client)
968 {
969 $("#menuCss").change(
970 function()
971 {
972 client.setCss("css/" + $("option:selected", this).attr("value") + "/euphorik.css")
973 }
974 )
975 }
976
977 // charge dynamiquement le script de debug
978 ;;; jQuery.ajax({async : false, url : "js/debug.js", dataType : "script"})
979
980 // le main
981 $(document).ready(
982 function()
983 {
984 var formateur = new Formateur()
985 var util = new Util(formateur)
986 var client = new Client(util)
987 var pages = new Pages()
988
989 // connexion vers le serveur (utilise un cookie qui traine)
990 client.connexionCookie()
991
992 initialiserListeStyles(client)
993
994 // FIXME : ne fonctionne pas sous opera
995 // voir : http://dev.jquery.com/ticket/2892#preview
996 $(window).unload(function(){client.flush()})
997
998 $("#menu .minichat").click(function(){ pages.afficherPage("minichat") })
999 $("#menu .admin").click(function(){ pages.afficherPage("admin") })
1000 $("#menu .profile").click(function(){ pages.afficherPage("profile") })
1001 $("#menu .logout").click(function(){
1002 util.messageDialogue("Êtes-vous sur de vouloir vous délogger ?", messageType.question,
1003 {"Oui" : function()
1004 {
1005 client.deconnexion();
1006 pages.afficherPage("minichat", true)
1007 },
1008 "Non" : function(){}
1009 }
1010 )
1011 })
1012 $("#menu .register").click(function(){ pages.afficherPage("register") })
1013 $("#menu .about").click(function(){ pages.afficherPage("about") })
1014
1015 pages.ajouterPage(new PageMinichat(client, formateur, util))
1016 pages.ajouterPage(new PageAdmin(client, formateur, util))
1017 pages.ajouterPage(new PageProfile(client, formateur, util))
1018 pages.ajouterPage(new PageRegister(client, formateur, util))
1019 pages.ajouterPage(new PageAbout(client, formateur, util))
1020 pages.afficherPage("minichat")
1021 }
1022 )