FIX planté lors du passage de la version 1 à la version 2 des données mutables
[euphorik.git] / js / client.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 /*jslint laxbreak:true */
20
21 /**
22 * Représente l'utilisateur du site.
23 */
24 euphorik.Client = function(util, communication) {
25 this.util = util;
26 this.communication = communication;
27
28 this.cookie = null;
29 this.regexCookie = /cookie=([^;]*)/;
30
31 // données personnels
32 this.resetDonneesPersonnelles();
33
34 this.setStatut(euphorik.Client.statutType.deconnected);
35
36 // si true alors chaque modification du client est mémorisé sur le serveur
37 this.autoflush = $.browser.opera;
38 };
39
40 // les statuts possibes du client
41 euphorik.Client.statutType = {
42 // mode enregistré, peut poster des messages et modifier son profile
43 auth_registered : 0,
44 // mode identifié, peut poster des messages mais n'a pas accès au profile
45 auth_not_registered : 1,
46 // mode déconnecté, ne peut pas poster de message
47 deconnected : 2
48 };
49
50 euphorik.Client.prototype.resetDonneesPersonnelles = function() {
51 this.id = 0;
52 this.pseudo = euphorik.conf.pseudoDefaut;
53 this.login = "";
54 this.password = "";
55 this.email = "";
56 this.css = $("link#cssPrincipale").attr("href");
57 this.chatOrder = "reverse";
58 this.nickFormat = "nick";
59 this.viewTimes = true;
60 this.viewTooltips = true;
61 this.cookie = undefined;
62
63 this.pagePrincipale = 1;
64 this.ekMaster = false;
65 this.ostentatiousMaster = "light";
66
67 // les conversations, une conversation est un objet possédant les propriétés suivantes :
68 // - root (entier)
69 // - page (entier)
70 // - reduit (bool)
71 this.conversations = [];
72 };
73
74 euphorik.Client.prototype.setCss = function(css) {
75 if (this.css === css || !css) {
76 return;
77 }
78
79 this.css = css;
80 $("link#cssPrincipale").attr("href", this.css);
81 if (this.autoflush) {
82 this.flush(true);
83 }
84 };
85
86 euphorik.Client.prototype.pageSuivante = function(numConv) {
87 if (numConv < 0 && this.pagePrincipale > 1) {
88 this.pagePrincipale -= 1;
89 } else if (this.conversations[numConv].page > 1) {
90 this.conversations[numConv].page -= 1;
91 }
92 };
93
94 euphorik.Client.prototype.pagePrecedente = function(numConv) {
95 if (numConv < 0) {
96 this.pagePrincipale += 1;
97 } else {
98 this.conversations[numConv].page += 1;
99 }
100 };
101
102 /**
103 * Définit la première page pour la conversation donnée.
104 * @return true si la page a changé sinon false
105 */
106 euphorik.Client.prototype.goPremierePage = function(numConv)
107 {
108 if (numConv < 0) {
109 if (this.pagePrincipale === 1) {
110 return false;
111 }
112 this.pagePrincipale = 1;
113 } else {
114 if (this.conversations[numConv].page === 1) {
115 return false;
116 }
117 this.conversations[numConv].page = 1;
118 }
119 return true;
120 };
121
122 /**
123 * Ajoute une conversation à la vue de l'utilisateur.
124 * Le profile de l'utilisateur est directement sauvegardé sur le serveur.
125 * @param racines la racine de la conversation (integer)
126 * @return true si la conversation a été créée sinon false (par exemple si la conv existe déjà)
127 */
128 euphorik.Client.prototype.ajouterConversation = function(racine) {
129 // vérification s'il elle n'existe pas déjà
130 var existe = false;
131 this.conversations.each(function(i, conv) {
132 if (conv.root === racine) {
133 existe = true;
134 }
135 });
136 if (existe) {
137 return false;
138 }
139
140 this.conversations.push({root : racine, page : 1, reduit : false});
141 if (this.autoflush) {
142 this.flush(true);
143 }
144
145 return true;
146 };
147
148 euphorik.Client.prototype.supprimerConversation = function(num) {
149 if (num < 0 || num >= this.conversations.length) {
150 return;
151 }
152
153 // décalage TODO : supprimer le dernier élément
154 for (var i = num; i < this.conversations.length - 1; i++) {
155 this.conversations[i] = this.conversations[i+1];
156 }
157 this.conversations.pop();
158
159 if (this.autoflush) {
160 this.flush(true);
161 }
162 };
163
164 euphorik.Client.prototype.getJSONConversations = function() {
165 var conversations = [];
166 this.conversations.each(function(i, conv) {
167 conversations.push({ "root" : conv.root, "minimized" : conv.reduit });
168 });
169 return conversations;
170 };
171
172 euphorik.Client.prototype.getJSONProfile = function() {
173 return {
174 "cookie" : this.cookie,
175 "login" : this.login,
176 "password" : this.password,
177 "profile" : this.getJSONProfileInfos()
178 };
179 };
180
181 euphorik.Client.prototype.getJSONProfileInfos = function() {
182 return {
183 "nick" : this.pseudo,
184 "email" : this.email,
185 "css" : this.css,
186 "chat_order" : this.chatOrder,
187 "nick_format" : this.nickFormat,
188 "view_times" : this.viewTimes,
189 "view_tooltips" : this.viewTooltips,
190 "conversations" : this.getJSONConversations(),
191 "ostentatious_master" : this.ostentatiousMaster
192 };
193 };
194
195 /**
196 * .
197 */
198 euphorik.Client.prototype.getCookie = function() {
199 var cookie = this.regexCookie.exec(document.cookie);
200 if (cookie) {
201 this.cookie = cookie[1];
202 } else {
203 this.cookie = undefined;
204 }
205 };
206
207 euphorik.Client.prototype.delCookie = function() {
208 document.cookie = "cookie=; max-age=0";
209 this.cookie = undefined;
210 };
211
212 euphorik.Client.prototype.setCookie = function() {
213 if (!this.cookie) {
214 return;
215 }
216
217 // ne fonctionne pas sous IE....
218 /*document.cookie = "cookie=" + this.cookie + "; max-age=" + (60 * 60 * 24 * 365) */
219
220 document.cookie =
221 "cookie="+this.cookie+"; expires=" + new Date(new Date().getTime() + 1000 * 60 * 60 * 24 * 365).toUTCString();
222 };
223
224 euphorik.Client.prototype.authentifie = function() {
225 return this.statut === euphorik.Client.statutType.auth_registered || this.statut === euphorik.Client.statutType.auth_not_registered;
226 };
227
228 euphorik.Client.prototype.setStatut = function(statut)
229 {
230 // conversation en "enum" si en "string"
231 if (typeof(statut) === "string") {
232 statut =
233 statut === "auth_registered" ?
234 euphorik.Client.statutType.auth_registered :
235 (statut === "auth_not_registered" ? euphorik.Client.statutType.auth_not_registered : euphorik.Client.statutType.deconnected);
236 }
237
238 if (statut === this.statut) {
239 return;
240 }
241
242 this.statut = statut;
243
244 this.majMenu();
245 this.majLogo();
246 };
247
248 /**
249 * Effectue la connexion vers le serveur.
250 * Cette fonction est bloquante tant que la connexion n'a pas été établie.
251 * S'il existe un cookie en local on s'authentifie directement avec lui.
252 * Si il n'est pas possible de s'authentifier alors on affiche un captcha anti-bot.
253 */
254 euphorik.Client.prototype.connexionCookie = function() {
255 this.getCookie();
256 if (!this.cookie) {
257 return false;
258 }
259 return this.connexion("authentification", { "cookie" : this.cookie });
260 };
261
262 euphorik.Client.prototype.connexionLogin = function(login, password) {
263 return this.connexion("authentification", {"login" : login, "password" : password });
264 };
265
266 euphorik.Client.prototype.enregistrement = function(login, password) {
267 if (this.authentifie()) {
268 this.login = login;
269 this.password = password;
270 if(this.flush()) {
271 this.setStatut(euphorik.Client.statutType.auth_registered);
272 return true;
273 }
274 return false;
275 } else {
276 return this.connexion("register", this.getJSONEnregistrement(login, password));
277 }
278 };
279
280 /**
281 * le couple (login, password) est facultatif. S'il n'est pas fournit alors il ne sera pas possible
282 * de s'autentifier avec (login, password).
283 */
284 euphorik.Client.prototype.getJSONEnregistrement = function(login, password) {
285 var mess = {};
286
287 if (login && password) {
288 mess.login = login;
289 mess.password = password;
290 }
291
292 mess.profile = this.getJSONProfileInfos();
293
294 return mess;
295 };
296
297 /**
298 * Connexion. Réalisé de manière synchrone.
299 */
300 euphorik.Client.prototype.connexion = function(action, messageJson) {
301 var thisClient = this;
302
303 this.communication.requete(
304 action,
305 messageJson,
306 function(data) {
307 thisClient.chargerDonnees(data);
308 },
309 function(data) {
310 thisClient.util.messageDialogue(data.error_message);
311 thisClient.delCookie(); // suppression du cookie actuel, cas où le cookie du client ne permet pas une authentification
312 },
313 false
314 );
315 return this.authentifie();
316 };
317
318 euphorik.Client.prototype.deconnexion = function() {
319 this.flush(true);
320 this.delCookie();
321 this.resetDonneesPersonnelles();
322 this.setStatut(euphorik.Client.statutType.deconnected); // deconnexion
323 };
324
325 euphorik.Client.prototype.chargerDonnees = function(data) {
326 // la modification du statut qui suit met à jour le menu, le menu dépend (page admin)
327 // de l'état ekMaster
328 this.ekMaster = data.ek_master ? data.ek_master : false;
329
330 this.setStatut(data.status);
331
332 if (this.authentifie()) {
333 this.cookie = data.cookie;
334 this.setCookie();
335
336 this.id = data.id;
337 this.login = data.login;
338 this.pseudo = data.profile.nick;
339 this.email = data.profile.email;
340 this.setCss(data.profile.css);
341 this.chatOrder = data.profile.chat_order;
342 this.nickFormat = data.profile.nick_format;
343 this.viewTimes = data.profile.view_times;
344 this.viewTooltips = data.profile.view_tooltips;
345 this.ostentatiousMaster = data.profile.ostentatious_master;
346
347 // la page de la conversation principale
348 this.pagePrincipale = 1;
349
350 // les conversations
351 this.conversations = data.profile.conversations;
352 this.conversations.map(function(conv) {
353 return { root : conv.root, page : 1, reduit : conv.minimized };
354 });
355
356 this.majBulle();
357 this.majCssSelectionee();
358 }
359 };
360
361 /**
362 * Met à jour les données personne sur serveur.
363 * @param async de manière asynchrone ? défaut = true
364 * @return false si le flush n'a pas pû se faire sinon true
365 */
366 euphorik.Client.prototype.flush = function(async) {
367 async = async || false;
368
369 if (!this.authentifie()) {
370 return false;
371 }
372
373 var thisClient = this;
374 var ok = true;
375
376 this.communication.requete(
377 "set_profile",
378 this.getJSONProfile(),
379 function(data) {
380 thisClient.majBulle();
381 },
382 function(data) {
383 thisClient.util.messageDialogue(data.error_message);
384 ok = false;
385 },
386 async
387 );
388
389 return ok;
390 };
391
392 euphorik.Client.prototype.majMenu = function() {
393 var displayType = "block";
394
395 $("#menu .admin").css("display", this.ekMaster ? displayType : "none");
396
397 // met à jour le menu
398 if (this.statut === euphorik.Client.statutType.auth_registered) {
399 $("#menu .profile").css("display", displayType).text("profile");
400 $("#menu .logout").css("display", displayType);
401 $("#menu .register").css("display", "none");
402 } else if (this.statut === euphorik.Client.statutType.auth_not_registered) {
403 $("#menu .profile").css("display", "none");
404 $("#menu .logout").css("display", displayType);
405 $("#menu .register").css("display", displayType);
406 } else {
407 $("#menu .profile").css("display", displayType).text("login");
408 $("#menu .logout").css("display", "none");
409 $("#menu .register").css("display", displayType);
410 }
411 };
412
413 /**
414 * Met à jour l'affichage ou non des infos bulles en fonction du profile.
415 */
416 euphorik.Client.prototype.majBulle = function() {
417 this.util.bulleActive = this.viewTooltips;
418 };
419
420 /**
421 * Met à jour la css sélectionnée, lors du chargement des données.
422 */
423 euphorik.Client.prototype.majCssSelectionee = function() {
424 // extraction du numéro de la css courante
425 var numCssCourante = this.css.match(/^.*?\/(\d)\/.*$/);
426 if (numCssCourante && numCssCourante[1]) {
427 $("#menuCss option").removeAttr("selected");
428 $("#menuCss option[value=" + numCssCourante[1]+ "]").attr("selected", "selected");
429 }
430 };
431
432 /**
433 * Change la "class" du logo en fonction du statut de ekMaster.
434 */
435 euphorik.Client.prototype.majLogo = function() {
436 if (this.ekMaster) {
437 $("#logo").addClass("ekMaster");
438 } else {
439 $("#logo").removeClass("ekMaster");
440 }
441 };
442
443 euphorik.Client.prototype.slap = function(userId, raison) {
444 var thisClient = this;
445 this.communication.requete("slap", { "cookie" : thisClient.cookie, "user_id" : userId, "reason" : raison });
446 };
447
448 euphorik.Client.prototype.ban = function(userId, raison, minutes) {
449 var thisClient = this;
450
451 // par défaut un ban correspond à 3 jours
452 minutes = minutes || euphorik.conf.tempsBan;
453 this.communication.requete("ban", { "cookie" : thisClient.cookie, "duration" : minutes, "user_id" : userId, "reason" : raison });
454 };
455
456 euphorik.Client.prototype.kick = function(userId, raison) {
457 this.ban(userId, raison, euphorik.conf.tempsKick);
458 };