Happy New Year !
[platal.git] / htdocs / javascript / xorg.js
CommitLineData
0337d704 1/***************************************************************************
ba6ae046 2 * Copyright (C) 2003-2013 Polytechnique.org *
0337d704 3 * http://opensource.polytechnique.org/ *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the Free Software *
17 * Foundation, Inc., *
18 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
19 ***************************************************************************/
20
0337d704 21// {{{ function getNow()
80dcbd9a
FB
22var days = ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'];
23var months = ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet',
34cc65fd 24 'août', 'septembre', 'octobre', 'novembre', 'décembre'];
0337d704 25
0337d704 26function getNow() {
80dcbd9a
FB
27 var dt = new Date();
28 var dy = dt.getDay();
29 var mh = dt.getMonth();
30 var wd = dt.getDate();
31 var yr = dt.getYear();
80dcbd9a
FB
32 var hr = dt.getHours();
33 var mi = dt.getMinutes();
34cc65fd
FB
34 var se = dt.getSeconds();
35
36 if (yr<1000) {
37 yr += 1900;
38 }
80dcbd9a
FB
39 if (mi < 10) {
40 mi = '0' + mi;
41 }
80dcbd9a
FB
42 if (se < 10) {
43 se = '0' + se;
44 }
9f449375 45
80dcbd9a
FB
46 $(".date-heure").html(days[dy] + ' ' + wd + ' ' + months[mh] + ' ' + yr + '<br />'
47 + hr + ':' + mi + ':' + se);
9f449375 48}
49
50// }}}
a27c6df8 51// {{{ Search Engine
52
53function canAddSearchEngine()
54{
34cc65fd
FB
55 if (((typeof window.sidebar === "object") && $.isFunction(window.sidebar.addSearchEngine))
56 || ((typeof window.external === "object") && $.isFunction(window.external.AddSearchProvider))) {
350ba5ac
FB
57 return true;
58 }
59 return false;
a27c6df8 60}
39fd8f50 61
b09e5dea 62function addSearchEngine()
63{
350ba5ac 64 var searchURI = "http://www.polytechnique.org/xorg.opensearch.xml";
34cc65fd 65 if ((typeof window.sidebar === "object") && $.isFunction(window.sidebar.addSearchEngine)) {
350ba5ac
FB
66 window.sidebar.addSearchEngine(
67 searchURI,
68 "http://www.polytechnique.org/images/xorg.png",
69 "Annuaire Polytechnique.org",
70 "Academic");
71 } else {
72 try {
73 window.external.AddSearchProvider(searchURI);
74 } catch(e) {
75 alert("Impossible d'installer la barre de recherche");
76 }
b09e5dea 77 }
39fd8f50 78}
79
39fd8f50 80// }}}
0337d704 81
82/***************************************************************************
83 * POPUP THINGS
84 */
85
769dc7d5
VZ
86// {{{ function goodiesPopup()
87
048c44a3
FB
88(function($) {
89 var goodies = {
90 ical: {
91 default_title: 'Calendrier iCal',
92 sites: [
93 {url_prefix: '',
94 img: 'images/icons/calendar_view_day.gif',
95 title: 'Calendrier iCal'},
96 {url_prefix: 'http://www.google.com/calendar/render?cid=',
97 img: 'images/goodies/add-google-calendar.gif',
98 title: 'Ajouter à Google Calendar'},
99 {url_prefix: 'https://www.google.com/calendar/hosted/polytechnique.org/render?cid=',
100 img: 'images/goodies/add-google-calendar.gif',
101 title: 'Ajouter à Google Apps / Calendar'}
102 ]
103 },
104
105 rss: {
106 default_title: 'Fils RSS',
107 sites: [
108 {url_prefix: '',
109 img: 'images/icons/feed.gif',
110 title: 'Fil rss'},
111 {url_prefix: 'http://fusion.google.com/add?feedurl=',
112 img: 'images/goodies/add-google.gif',
113 alt: 'Add to Google',
114 title: 'Ajouter à iGoogle/Google Reader'},
115 {url_prefix: 'http://www.netvibes.com/subscribe.php?url=',
116 img: 'images/goodies/add-netvibes.gif',
117 title: 'Ajouter à Netvibes'},
118 {url_prefix: 'http://add.my.yahoo.com/content?.intl=fr&url=',
119 img: 'images/goodies/add-yahoo.gif',
120 alt: 'Add to My Yahoo!',
121 title: 'Ajouter à My Yahoo!'}
122 ]
123 }
124 };
125
126 $.fn.extend({
127 goodiesPopup: function goodiesPopup(type) {
128 var text = '<div style="text-align: center; line-height: 2.2">';
34cc65fd
FB
129 var site;
130 var entry;
131 var s_alt;
132 var s_img;
133 var s_title;
134 var s_url;
b3d92c8e 135 var href = this.attr('href');
34cc65fd
FB
136
137 for (site in goodies[type].sites) {
138 entry = goodies[type].sites[site];
139 s_alt = entry.alt || "";
140 s_img = entry.img;
141 s_title = entry.title || "";
b3d92c8e 142 s_url = entry.url_prefix.length > 0 ? entry.url_prefix + escape(href) : href;
048c44a3
FB
143
144 text += '<a href="' + s_url + '"><img src="' + s_img + '" title="' + s_title + '" alt="' + s_alt + '"></a><br />';
b3d92c8e 145 }
048c44a3 146 text += '<a href="https://www.polytechnique.org/Xorg/Goodies">Plus de bonus</a> ...</div>';
769dc7d5 147
048c44a3
FB
148 return this.overlib({
149 text: text,
34cc65fd 150 caption: this.attr('title') || goodies.default_title,
048c44a3
FB
151 close_text: 'Fermer',
152 delay: 800,
153 sticky: true,
154 width: 150
155 });
156 }
157 });
158}(jQuery));
769dc7d5
VZ
159
160// }}}
0337d704 161// {{{ function auto_links()
162
0337d704 163function auto_links() {
80dcbd9a
FB
164 var url = document.URL;
165 var fqdn = url.replace(/^https?:\/\/([^\/]*)\/.*$/,'$1');
63c89179
FB
166 var light = url.indexOf('display=light') > url.indexOf('?');
167 var resource_page = url.contains('rss') || url.contains('ical');
e83d83e8 168
b804b882
FB
169 $("a,link").each(function(i) {
170 var node = $(this);
171 var href = this.href;
63c89179
FB
172 var matches;
173 var rss;
174 var ical;
175
b804b882 176 if(!href || node.hasClass('xdx')
63c89179 177 || href.startsWith('mailto:') || href.startsWith('javascript:')) {
b804b882
FB
178 return;
179 }
63c89179 180 if ((!href.contains(fqdn) && !this.className.contains('popup')) || node.hasClass('popup')) {
b804b882 181 node.click(function () {
ecd28ce8 182 window.open($.plURL(this.href));
b804b882
FB
183 return false;
184 });
185 }
63c89179 186 if (href.contains(fqdn) && light) {
b804b882
FB
187 href = href.replace(/([^\#\?]*)\??([^\#]*)(\#.*)?/, "$1?display=light&$2$3");
188 this.href = href;
189 }
63c89179
FB
190 rss = href.contains('rss');
191 ical = href.contains('ical');
b804b882 192 if (rss || ical) {
63c89179 193 if (!href.startsWith('http')) {
b804b882 194 href = 'http://' + fqdn + '/' + href;
e83d83e8 195 }
b804b882 196 }
34cc65fd 197 if (this.nodeName.toLowerCase() === 'a' && !resource_page) {
63c89179 198 if (rss && !href.contains('prefs/rss') && (href.contains('xml') || href.contains('hash'))) {
048c44a3 199 node.goodiesPopup('rss');
b804b882 200 } else if (ical) {
048c44a3 201 node.goodiesPopup('ical');
769dc7d5 202 }
3def38d5 203 }
34cc65fd
FB
204 matches = /^popup_([0-9]*)x([0-9]*)$/.exec(this.className);
205 if (matches) {
206 node.popWin(matches[1], matches[2]);
b804b882
FB
207 }
208 });
209 $('.popup2').popWin(840, 600);
210 $('.popup3').popWin(640, 800);
0337d704 211}
212
e83d83e8 213
0337d704 214// }}}
215
7143ad2b
FB
216/***************************************************************************
217 * Password check
218 */
219
220// {{{ function checkPassword
221
5ff39ae1
FB
222/* {{{ SHA1 Implementation */
223
224/*
225 * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
226 * in FIPS PUB 180-1
227 * Version 2.1a Copyright Paul Johnston 2000 - 2002.
228 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
229 * Distributed under the BSD License
230 * See http://pajhome.org.uk/crypt/md5 for details.
231 */
232
233/*
234 * Configurable variables. You may need to tweak these to be compatible with
235 * the server-side, but the defaults work in most cases.
236 */
237var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
238var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
239var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
240
241/*
242 * These are the functions you'll usually want to call
243 * They take string arguments and return either hex or base-64 encoded strings
244 */
245function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));}
246function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));}
247function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));}
248function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));}
249function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}
250function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}
251
252/*
253 * Perform a simple self-test to see if the VM is working
254 */
255function sha1_vm_test()
256{
34cc65fd 257 return hex_sha1("abc") === "a9993e364706816aba3e25717850c26c9cd0d89d";
5ff39ae1
FB
258}
259
260/*
261 * Calculate the SHA-1 of an array of big-endian words, and a bit length
262 */
263function core_sha1(x, len)
264{
34cc65fd
FB
265 var w, a, b, c, d, e;
266 var olda, oldb, oldc, oldd, olde;
267 var i, j, t;
268
5ff39ae1
FB
269 /* append padding */
270 x[len >> 5] |= 0x80 << (24 - len % 32);
271 x[((len + 64 >> 9) << 4) + 15] = len;
272
34cc65fd
FB
273 w = Array(80);
274 a = 1732584193;
275 b = -271733879;
276 c = -1732584194;
277 d = 271733878;
278 e = -1009589776;
5ff39ae1 279
34cc65fd 280 for(i = 0; i < x.length; i += 16)
5ff39ae1 281 {
34cc65fd
FB
282 olda = a;
283 oldb = b;
284 oldc = c;
285 oldd = d;
286 olde = e;
5ff39ae1 287
34cc65fd 288 for(j = 0; j < 80; j++)
5ff39ae1
FB
289 {
290 if(j < 16) w[j] = x[i + j];
291 else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
34cc65fd 292 t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
5ff39ae1
FB
293 safe_add(safe_add(e, w[j]), sha1_kt(j)));
294 e = d;
295 d = c;
296 c = rol(b, 30);
297 b = a;
298 a = t;
299 }
300
301 a = safe_add(a, olda);
302 b = safe_add(b, oldb);
303 c = safe_add(c, oldc);
304 d = safe_add(d, oldd);
305 e = safe_add(e, olde);
306 }
307 return Array(a, b, c, d, e);
308
309}
310
311/*
312 * Perform the appropriate triplet combination function for the current
313 * iteration
314 */
315function sha1_ft(t, b, c, d)
316{
317 if(t < 20) return (b & c) | ((~b) & d);
318 if(t < 40) return b ^ c ^ d;
319 if(t < 60) return (b & c) | (b & d) | (c & d);
320 return b ^ c ^ d;
321}
322
323/*
324 * Determine the appropriate additive constant for the current iteration
325 */
326function sha1_kt(t)
327{
328 return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
329 (t < 60) ? -1894007588 : -899497514;
330}
331
332/*
333 * Calculate the HMAC-SHA1 of a key and some data
334 */
335function core_hmac_sha1(key, data)
336{
337 var bkey = str2binb(key);
34cc65fd
FB
338 var i, ipad, opad;
339 var hash;
340
5ff39ae1
FB
341 if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz);
342
34cc65fd
FB
343 ipad = Array(16);
344 opad = Array(16);
345 for(i = 0; i < 16; i++)
5ff39ae1
FB
346 {
347 ipad[i] = bkey[i] ^ 0x36363636;
348 opad[i] = bkey[i] ^ 0x5C5C5C5C;
349 }
350
34cc65fd 351 hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
5ff39ae1
FB
352 return core_sha1(opad.concat(hash), 512 + 160);
353}
354
355/*
356 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
357 * to work around bugs in some JS interpreters.
358 */
359function safe_add(x, y)
360{
361 var lsw = (x & 0xFFFF) + (y & 0xFFFF);
362 var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
363 return (msw << 16) | (lsw & 0xFFFF);
364}
365
366/*
367 * Bitwise rotate a 32-bit number to the left.
368 */
369function rol(num, cnt)
370{
371 return (num << cnt) | (num >>> (32 - cnt));
372}
373
374/*
375 * Convert an 8-bit or 16-bit string to an array of big-endian words
376 * In 8-bit function, characters >255 have their hi-byte silently ignored.
377 */
378function str2binb(str)
379{
380 var bin = Array();
381 var mask = (1 << chrsz) - 1;
34cc65fd
FB
382 var i;
383 for(i = 0; i < str.length * chrsz; i += chrsz)
5ff39ae1
FB
384 bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32);
385 return bin;
386}
387
388/*
389 * Convert an array of big-endian words to a string
390 */
391function binb2str(bin)
392{
393 var str = "";
394 var mask = (1 << chrsz) - 1;
34cc65fd
FB
395 var i;
396 for(i = 0; i < bin.length * 32; i += chrsz)
5ff39ae1
FB
397 str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask);
398 return str;
399}
400
401/*
402 * Convert an array of big-endian words to a hex string.
403 */
404function binb2hex(binarray)
405{
406 var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
407 var str = "";
34cc65fd
FB
408 var i;
409 for(i = 0; i < binarray.length * 4; i++)
5ff39ae1
FB
410 {
411 str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
412 hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF);
413 }
414 return str;
415}
416
417/*
418 * Convert an array of big-endian words to a base-64 string
419 */
420function binb2b64(binarray)
421{
422 var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
423 var str = "";
34cc65fd
FB
424 var i, j, triplet;
425 for(i = 0; i < binarray.length * 4; i += 3)
5ff39ae1 426 {
34cc65fd 427 triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16)
5ff39ae1
FB
428 | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 )
429 | ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
34cc65fd 430 for(j = 0; j < 4; j++)
5ff39ae1
FB
431 {
432 if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
433 else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
434 }
435 }
436 return str;
437}
438
439/* }}} */
440
441function hash_encrypt(a) {
442 return hex_sha1(a);
443}
444
445var hexa_h = "0123456789abcdef";
446
447function dechex(a) {
448 return hexa_h.charAt(a);
449}
450
451function hexdec(a) {
452 return hexa_h.indexOf(a);
453}
454
455function hash_xor(a, b) {
34cc65fd 456 var c,i,j,k,d;
5ff39ae1
FB
457 c = "";
458 i = a.length;
459 j = b.length;
460 if (i < j) {
5ff39ae1
FB
461 d = a; a = b; b = d;
462 k = i; i = j; j = k;
463 }
34cc65fd 464 for (k = 0; k < j; k++) {
5ff39ae1 465 c += dechex(hexdec(a.charAt(k)) ^ hexdec(b.charAt(k)));
34cc65fd
FB
466 }
467 for (; k < i; k++) {
5ff39ae1 468 c += a.charAt(k);
34cc65fd 469 }
5ff39ae1
FB
470 return c;
471}
472
0ba43ee4
VZ
473function getType(c) {
474 if (c >= 'a' && c <= 'z') {
7143ad2b 475 return 1;
0ba43ee4 476 } else if (c >= 'A' && c <= 'Z') {
7143ad2b 477 return 2;
0ba43ee4 478 } else if (c >= '0' && c <= '9') {
7143ad2b
FB
479 return 3;
480 } else {
481 return 4;
482 }
483}
484
4baa7323 485function differentTypes(password) {
7143ad2b 486 var prev = 0;
34cc65fd 487 var type;
4baa7323
SJ
488
489 for (i = 0 ; i < password.length ; ++i) {
34cc65fd
FB
490 type = getType(password.charAt(i));
491 if (prev !== 0 && prev !== type) {
4baa7323
SJ
492 return true;
493 }
494 prev = type;
495 }
496 return false;
497}
498
499function passwordStrength(password) {
7143ad2b 500 var prop = 0;
4baa7323 501 var prev = 0;
eaa3f284 502 var firstType = true;
4baa7323 503 var types = Array(0, 0, 0, 0, 0);
34cc65fd 504 var type;
4baa7323
SJ
505
506 for (i = 0 ; i < password.length ; ++i) {
34cc65fd
FB
507 type = getType(password.charAt(i));
508 if (prev !== 0 && prev !== type) {
7143ad2b 509 prop += 5;
4baa7323 510 firstType = false;
7143ad2b 511 }
eaa3f284 512 prop += i;
34cc65fd 513 if (types[type] === 0 && !firstType) {
eaa3f284 514 prop += 15;
7143ad2b
FB
515 }
516 types[type]++;
517 prev = type;
518 }
4baa7323
SJ
519 if (password.length < 6) {
520 prop *= 0.75;
521 }
522 if (firstType) {
aca1582e 523 prop *= 0.75;
eaa3f284 524 }
7143ad2b
FB
525 if (prop > 100) {
526 prop = 100;
527 } else if (prop < 0) {
528 prop = 0;
529 }
4baa7323
SJ
530
531 return prop;
532}
533
534function checkPassword(box, okLabel) {
535 var password = box.value;
536 var prop = passwordStrength(password);
34cc65fd 537 var submitButton;
4baa7323 538
de99248c 539 if (prop >= 60) {
00681970
FB
540 color = "#4f4";
541 bgcolor = "#050";
de99248c 542 ok = true;
23f6d4cc 543 } else if (prop >= 35) {
de99248c 544 color = "#ff4";
00681970 545 bgcolor = "#750";
b19839fd 546 ok = true;
de99248c
FB
547 } else {
548 color = "#f20";
00681970 549 bgcolor = "#700";
de99248c
FB
550 ok = false;
551 }
552 $("#passwords_measure")
00681970
FB
553 .stop()
554 .animate({ width: prop + "%",
555 backgroundColor: color
556 }, 750)
557 .parent().stop()
558 .animate({ backgroundColor: bgcolor }, 750);
34cc65fd 559 submitButton = $(":submit[name='" + passwordprompt_submit + "']");
4baa7323 560 if (ok && password.length >= 6 && differentTypes(password)) {
7b7d0970 561 submitButton.attr("value", okLabel);
de99248c 562 submitButton.removeAttr("disabled");
7143ad2b 563 } else {
7b7d0970 564 submitButton.attr("value", "Mot de passe trop faible");
de99248c 565 submitButton.attr("disabled", "disabled");
7143ad2b
FB
566 }
567}
568
30439e34 569function hashResponse(password1, password2, hasConfirmation, doAuth) {
34cc65fd
FB
570 var pw1 = $('[name=' + password1 + ']').val();
571 var pw2;
5ff39ae1
FB
572
573 if (hasConfirmation) {
574 pw2 = $('[name=' + password2 + ']').val();
34cc65fd 575 if (pw1 !== pw2) {
5ff39ae1
FB
576 alert("\nErreur : les deux champs ne sont pas identiques !");
577 return false;
578 }
579 $('[name=' + password2 + ']').val('');
34cc65fd 580 } else if (pw1 === '********') {
5ff39ae1
FB
581 return true;
582 }
583
584 if (pw1.length < 6) {
585 alert("\nErreur : le nouveau mot de passe doit faire au moins 6 caractères !");
586 return false;
587 }
588 if (!differentTypes(pw1)) {
589 alert ("\nErreur : le nouveau mot de passe doit comporter au moins deux types de caractères parmi les suivants : lettres minuscules, lettres majuscules, chiffres, caractères spéciaux.");
590 return false;
591 }
592
b80cbf0d 593 alert("Le mot de passe va être chiffré avant de nous parvenir par Internet ! Ainsi il ne circulera pas en clair.");
5ff39ae1
FB
594 $('[name=' + password1 + ']').val('');
595 $('[name=pwhash]').val(hash_encrypt(pw1));
30439e34
SJ
596
597 if (doAuth) {
598 $('[name=password]').val(pw1);
599 doChallengeResponse();
600 }
601
5ff39ae1
FB
602 return true;
603}
604
605function correctUserName() {
606 var u = document.forms.login.username;
34cc65fd
FB
607 var mots;
608
5ff39ae1 609 // login with no space
460098c8 610 if (!u.value.contains(' ')) {
34cc65fd
FB
611 return true;
612 }
613 mots = u.value.split(' ');
5ff39ae1 614 // jean paul.du pont -> jean-paul.du-pont
460098c8 615 if (u.value.contains('.')) {
34cc65fd
FB
616 u.value = mots.join('-');
617 return true;
618 }
5ff39ae1 619 // jean dupont -> jean.dupont
34cc65fd
FB
620 if (mots.length === 2) {
621 u.value = mots[0] + "." + mots[1];
622 return true;
623 }
5ff39ae1 624 // jean dupont 2001 -> jean.dupont.2001
34cc65fd
FB
625 if (mots.length === 3 && mots[2] > 1920 && mots[2] < 3000) {
626 u.value = mots.join('.');
627 return true;
628 }
5ff39ae1 629 // jean de la vallee -> jean.de-la-vallee
34cc65fd
FB
630 if (mots[1].toUpperCase() === 'DE') {
631 u.value = mots[0] + "." + mots.join('-').substr(mots[0].length+1);
632 return true;
633 }
5ff39ae1 634 // jean paul dupont -> jean-paul.dupont
34cc65fd
FB
635 if (mots.length === 3 && mots[0].toUpperCase() === 'JEAN') {
636 u.value = mots[0] + "-" + mots[1] + "." + mots[2];
637 return true;
638 }
5ff39ae1
FB
639
640 alert('Ton email ne doit pas contenir de blanc.\nLe format standard est\n\nprenom.nom.promotion\n\nSi ton nom ou ton prenom est composé,\nsépare les mots par des -');
641
642 return false;
643}
644
645function doChallengeResponse() {
34cc65fd 646 var new_pass, old_pass, str;
5ff39ae1 647
34cc65fd
FB
648 if (!correctUserName()) {
649 return false;
650 }
5ff39ae1 651
34cc65fd
FB
652 new_pass = hash_encrypt(document.forms.login.password.value);
653 old_pass = hash_encrypt(document.forms.login.password.value.substr(0, 10));
5ff39ae1
FB
654
655 str = document.forms.login.username.value + ":" +
656 new_pass + ":" +
657 document.forms.loginsub.challenge.value;
658
659 document.forms.loginsub.response.value = hash_encrypt(str);
34cc65fd 660 if (new_pass !== old_pass) {
5ff39ae1
FB
661 document.forms.loginsub.xorpass.value = hash_xor(new_pass, old_pass);
662 }
663 document.forms.loginsub.username.value = document.forms.login.username.value;
664 document.forms.loginsub.remember.value = document.forms.login.remember.checked;
5ff39ae1
FB
665 document.forms.login.password.value = "";
666 document.forms.loginsub.submit();
667}
668
669function doChallengeResponseLogged() {
34cc65fd 670 var str = document.forms.loginsub.username.value + ":" +
5ff39ae1
FB
671 hash_encrypt(document.forms.login.password.value) + ":" +
672 document.forms.loginsub.challenge.value;
673
674 document.forms.loginsub.response.value = hash_encrypt(str);
675 document.forms.loginsub.remember.value = document.forms.login.remember.checked;
676 document.forms.login.password.value = "";
677 document.forms.loginsub.submit();
678}
679
7143ad2b 680// }}}
b0e935d6
FB
681// {{{ send test email
682
683function sendTestEmail(token, hruid)
684{
685 var url = 'emails/test';
686 var msg = "Un email a été envoyé avec succès";
34cc65fd 687 if (hruid) {
b0e935d6
FB
688 url += '/' + hruid;
689 msg += " sur l'adresse de " + hruid + ".";
690 } else {
691 msg += " sur ton addresse.";
692 }
fd4ec421 693 $('#mail_sent').successMessage(url + '?token=' + token, msg);
b0e935d6
FB
694 return false;
695}
696
697// }}}
6a686adb
FB
698// {{{ jQuery object extension
699
700(function($) {
102f3fc2
FB
701 /* Add new functions to jQuery namesapce */
702 $.extend({
063410c8
FB
703 /* The goal of the following functions is to provide an AJAX API that
704 * take a different callback in case of HTTP success code (2XX) and in
705 * other cases.
706 */
707
102f3fc2
FB
708 xajax: function(source, method, data, onSuccess, onError, type) {
709 /* Shift argument */
710 if ($.isFunction(data)) {
711 type = type || onError;
712 onError = onSuccess;
713 onSuccess = data;
714 data = null;
6a686adb 715 }
102f3fc2
FB
716 if (onError != null && !$.isFunction(onError)) {
717 type = type || onError;
718 onError = null;
6a686adb 719 }
6a686adb 720
102f3fc2
FB
721 function ajaxHandler(data, textStatus, xhr) {
722 if (textStatus == 'success') {
723 if (onSuccess) {
724 onSuccess(data, textStatus, xhr);
725 }
726 } else if (textStatus == 'error') {
727 if (onError) {
728 onError(data, textStatus, xhr);
729 } else {
730 alert("Une error s'est produite lors du traitement de la requête.\n"
731 + "Ta session a peut-être expiré");
732 }
733 }
734 }
735 return $.ajax({
736 url: source,
737 type: method,
738 success: ajaxHandler,
739 data : data,
740 dataType: type
741 });
742 },
743
744 xget: function(source, data, onSuccess, onError, type) {
745 return $.xajax(source, 'GET', data, onSuccess, onError, type);
746 },
747
748 xgetJSON: function(source, data, onSuccess, onError) {
749 return $.xget(source, data, onSuccess, onError, 'json');
750 },
751
752 xgetScript: function(source, onSuccess, onError) {
753 return $.xget(source, null, onSuccess, onError, 'script');
754 },
755
063410c8
FB
756 xgetText: function(source, data, onSuccess, onError) {
757 return $.xget(source, data, onSuccess, onError, 'text');
758 },
759
102f3fc2
FB
760 xpost: function(source, data, onSuccess, onError, type) {
761 return $.xajax(source, 'POST', data, onSuccess, onError, type);
6a686adb 762 }
102f3fc2
FB
763 });
764
765 /* Add new functions to jQuery objects */
766 $.fn.extend({
767 tmpMessage: function(message, success) {
768 if (success) {
769 this.html("<img src='images/icons/wand.gif' alt='' /> " + message)
770 .css('color', 'green');
771 } else {
772 this.html("<img src='images/icons/error.gif' alt='' /> " + message)
773 .css('color', 'red');
774 }
775 return this.css('fontWeight', 'bold')
776 .show()
777 .delay(1000)
778 .fadeOut(500);
779 },
780
781 updateHtml: function(source, callback) {
782 var elements = this;
783 function handler(data) {
784 elements.html(data);
785 if (callback) {
786 callback(data);
787 }
788 }
789 $.xget(source, handler, 'text');
790 return this;
791 },
792
793 successMessage: function(source, message) {
794 var elements = this;
795 $.xget(source, function() {
796 elements.tmpMessage(message, true);
797 });
798 return this;
799 },
800
801 wiki: function(text, withTitle) {
802 if (text == '') {
803 return this.html('');
804 }
805 var url = 'wiki_preview';
806 if (!withTitle) {
807 url += '/notitile';
808 }
809 var $this = this;
810 $.post(url, { text: text },
811 function (data) {
812 $this.html(data);
813 }, 'text');
814 return this;
063410c8
FB
815 },
816
817 popWin: function(w, h) {
818 return this.click(function() {
ecd28ce8 819 window.open($.plURL(this.href), '_blank',
063410c8
FB
820 'toolbar=0,location=0,directories=0,status=0,'
821 +'menubar=0,scrollbars=1,resizable=1,'
822 +'width='+w+',height='+h);
823 return false;
824 });
6a686adb 825 }
102f3fc2 826 });
6a686adb
FB
827})(jQuery);
828
829// }}}
830// {{{ preview wiki
831
832function previewWiki(idFrom, idTo, withTitle, idShow)
833{
834 $('#' + idTo).wiki($('#' + idFrom).val(), withTitle);
835 if (idShow != null) {
836 $('#' + idShow).show();
837 }
838}
839
840// }}}
9f4004f3
SJ
841// {{{ updatepromofields
842
843function updatepromofields(egal1, egal2, promo2) {
844 var comparator = egal1.val();
845
846 if (comparator == '=') {
847 egal2.attr('disabled', 'disabled');
848 promo2.attr('disabled', 'disabled');
849 } else if (comparator == '<=' || comparator == '>=') {
850 egal2.removeAttr('disabled');
851 promo2.removeAttr('disabled');
852 if (comparator == '<=') {
853 egal2.val('>=');
854 } else {
855 egal2.val('<=');
856 }
857 }
858}
859
860// }}}
7143ad2b 861
aaffb7b2
FB
862/***************************************************************************
863 * Quick search
864 */
865
60a4e0b3 866/* quick search {{{ */
aaffb7b2
FB
867(function($) {
868 function findPos(obj) {
869 var curleft = obj.offsetLeft || 0;
870 var curtop = obj.offsetTop || 0;
871 while (obj = obj.offsetParent) {
872 curleft += obj.offsetLeft
873 curtop += obj.offsetTop
874 }
875 return {x:curleft,y:curtop};
876 }
877
878 $.template('quickMinifiche',
0b2c582e 879 '<div class="contact grayed" style="clear: both">' +
aaffb7b2
FB
880 '<div class="identity">' +
881 '<div class="photo"><img src="photo/${hrpid}" alt="${directory_name}" /></div>' +
882 '<div class="nom">' +
0f8ca11e 883 '{{if is_female}}&bull;{{/if}}<a>${directory_name}</a>' +
aaffb7b2
FB
884 '</div>' +
885 '<div class="edu">${promo}</div>' +
886 '</div>' +
887 '<div class="noprint bits"></div>' +
888 '<div class="long"></div>' +
889 '</div>');
890
60a4e0b3 891
b1ae686e 892 function buildPopup(input, destination, linkBindFunction)
60a4e0b3 893 {
b1ae686e 894 var $popup = destination;
60a4e0b3 895 var selected = null;
c145766b 896 var hovered = 0;
60a4e0b3
FB
897
898 function updateSelection()
899 {
900 var sel = $popup.children('.contact').addClass('grayed');
901 if (selected !== null) {
902 while (selected < 0) {
903 selected += sel.length;
904 }
905 if (selected >= sel.length) {
906 selected -= sel.length;
907 }
908 sel.eq(selected).removeClass('grayed');
909 }
910 }
911
912 function formatProfile(i, profile) {
913 var data = $.tmpl('quickMinifiche', profile)
c145766b 914 .css('cursor', 'pointer')
60a4e0b3
FB
915 .hover(function() {
916 selected = i;
917 updateSelection();
c145766b 918 hovered++;
60a4e0b3
FB
919 }, function() {
920 if (selected === i) {
921 selected = null;
922 updateSelection();
923 }
c145766b 924 hovered--;
60a4e0b3 925 }).mouseup(function() {
8ca09823 926 var sel = $(this).find('a');
c145766b 927 if (!sel.attr('hovered')) {
8ca09823 928 sel.click();
60a4e0b3
FB
929 }
930 });
c145766b
FB
931 data.find('a').hover(function() { $(this).attr('hovered', true) },
932 function() { $(this).attr('hovered', false) });
60a4e0b3
FB
933 return data;
934 }
935
b1ae686e
FB
936 if (!$popup) {
937 $popup = $('<div>').hide()
938 .addClass('contact-list')
939 .css({
940 position: 'absolute',
941 width: '300px',
942 top: input.css('bottom'),
b1ae686e
FB
943 clear: 'both',
944 'text-align': 'left'
945 });
946 input.after($popup);
947 }
60a4e0b3
FB
948
949 return {
950 hide: function(ignoreIfHover) {
c145766b 951 if (ignoreIfHover && hovered !== 0) {
60a4e0b3
FB
952 return true;
953 }
954 selected = null;
955 updateSelection();
956 $popup.hide();
957 return true;
958 },
959
960 show: function() {
974c4947
FB
961 var pos = findPos(input.get(0));
962 $popup.css('left', pos.x - 300 + input.width()).show();
60a4e0b3
FB
963 return true;
964 },
965
966 selected: function() {
967 return selected !== null;
968 },
969
970 unselect: function() {
971 selected = null;
972 updateSelection();
973 },
974
975 selectNext: function() {
976 if (selected === null) {
977 selected = 0;
978 } else {
979 selected++;
980 }
981 updateSelection();
982 return true;
983 },
984
985 selectPrev: function() {
986 if (selected === null) {
987 selected = -1;
988 } else {
989 selected--;
990 }
991 updateSelection();
992 return true;
993 },
994
995 activeCurrent: function() {
996 var sel = $popup.children('.contact');
997 if (selected !== null) {
998 sel.eq(selected).find('a').click();
999 return false;
1000 }
1001 return true;
1002 },
1003
0f8ca11e 1004 updateContent: function(profiles, extra) {
60a4e0b3 1005 var profile;
0f8ca11e 1006 var $this;
60a4e0b3
FB
1007 $popup.empty();
1008 for (var i = 0, len = profiles.length; i < len; i++) {
0f8ca11e
FB
1009 (function(elt) {
1010 var profile = formatProfile(i, elt);
1011 profile.find('a').each(function() {
1012 linkBindFunction.call(this, elt, $this, extra);
1013 });
1014 profile.appendTo($popup);
1015 }(profiles[i]));
60a4e0b3
FB
1016 }
1017 if (len === 1) {
1018 selected = 0;
1019 } else {
1020 selected = null;
1021 }
1022 updateSelection();
1023 if (len > 0) {
1024 this.show();
1025 } else {
1026 this.hide();
1027 }
1028 return true;
1029 }
1030 };
1031 }
1032
aaffb7b2 1033 $.fn.extend({
c2c5ac82 1034 quickSearch: function(options) {
8ca09823
FB
1035 return this.each(function() {
1036 var $this = $(this);
1037 var $input = this;
aaffb7b2 1038 var $popup;
b1ae686e 1039 var previous = null;
599ff0d3 1040 var pending = false;
aaffb7b2
FB
1041 var disabled = false;
1042 var updatePopup;
aaffb7b2 1043
c2c5ac82 1044 options = options || { };
b1ae686e
FB
1045 options = $.extend({
1046 destination: null,
1047 minChars: 3,
1048 shortChars: 5,
1049 shortTimeout: 300,
1050 longTimeout: 100,
1051 queryParams: {
1052 offset: 0,
1053 count: 10,
2b13c66c 1054 allow_special: true
b1ae686e
FB
1055 },
1056 loadingClassLeft: 'ac_loading',
1057 loadingClassRight: 'ac_loading_left',
0f8ca11e
FB
1058 selectAction: function(profile, popup, extra) {
1059 var type = extra.link_type || 'profile';
1060 switch (type) {
1061 case 'profile':
1062 $(this).attr('href', 'profile/' + profile.hrpid)
1063 .popWin(840, 600)
241ba494 1064 .click(function() { $popup.hide(); return false; });
0f8ca11e
FB
1065 break;
1066 case 'admin':
1067 $(this).attr('href', 'admin/user/' + profile.hrpid)
ecd28ce8 1068 .click(function() { window.open($.plURL(this.href)); return false });
0f8ca11e
FB
1069 break;
1070 }
b1ae686e
FB
1071 }
1072 }, options);
b1ae686e
FB
1073 options.loadingClass = $this.css('text-align') === 'right' ? options.loadingClassRight
1074 : options.loadingClassLeft;
c8985ea9 1075 $this.attr('autocomplete', 'off');
0f8ca11e 1076 $popup = buildPopup($this, options.destination, options.selectAction);
aaffb7b2
FB
1077
1078 function markPending() {
1079 pending = true;
1080 }
1081
599ff0d3 1082 function performUpdate(quick)
aaffb7b2 1083 {
599ff0d3 1084 if (updatePopup === markPending) {
aaffb7b2
FB
1085 return true;
1086 }
599ff0d3 1087 updatePopup = markPending;
c2c5ac82
FB
1088 $this.addClass(options.loadingClass);
1089 $.xapi('search', $.extend({ 'quick': quick }, options.queryParams), function(data) {
b1ae686e 1090 if (data.profile_count > options.queryParams.count || data.profile_count < 0) {
599ff0d3 1091 return $popup.hide();
aaffb7b2 1092 }
0f8ca11e 1093 $popup.updateContent(data.profiles, data);
aaffb7b2 1094 previous = quick;
c54829c1
FB
1095 }, function(data, text) {
1096 if (text !== 'abort') {
1097 disabled = true;
1098 }
599ff0d3 1099 }).complete(function() {
c2c5ac82 1100 $this.removeClass(options.loadingClass);
aaffb7b2
FB
1101 updatePopup = doUpdatePopup;
1102 if (pending) {
c2c5ac82 1103 updatePopup();
aaffb7b2 1104 }
599ff0d3 1105 });
aaffb7b2
FB
1106 return true;
1107 }
0b2c582e 1108
599ff0d3
FB
1109 function doUpdatePopup(dontDelay)
1110 {
c2c5ac82 1111 var quick = $this.val();
599ff0d3 1112 if ($.isFunction(quick.trim)) {
599ff0d3
FB
1113 quick = quick.trim();
1114 }
1115 pending = false;
b1ae686e 1116 if (disabled || quick.length < options.minChars) {
599ff0d3
FB
1117 previous = quick;
1118 return $popup.hide();
1119 } else if (!dontDelay) {
b1ae686e 1120 var timeout = quick.length < options.shortChars ? options.shortTimeout : options.longTimeout;
599ff0d3 1121 setTimeout(function() {
c2c5ac82 1122 updatePopup(true);
599ff0d3
FB
1123 }, timeout);
1124 return true;
1125 } else if (previous === quick) {
1126 return $popup.show();
1127 }
c2c5ac82 1128 return performUpdate(quick);
599ff0d3
FB
1129 }
1130
aaffb7b2
FB
1131 updatePopup = doUpdatePopup;
1132
8ca09823 1133 return $this.keyup(function(e) {
0b2c582e
FB
1134 if (e.keyCode !== 27 /* escape */ && e.keyCode !== 13 /* enter */
1135 && e.keyCode !== 9 /* tab */ && e.keyCode !== 38 /* up */
1136 && e.keyCode !== 40 /* down */) {
c2c5ac82 1137 return updatePopup();
aaffb7b2
FB
1138 }
1139 return true;
1140 })
1141 .keydown(function(e) {
0b2c582e
FB
1142 switch (e.keyCode) {
1143 case 9: /* Tab */
1144 case 40: /* Down */
60a4e0b3 1145 $popup.selectNext();
0b2c582e
FB
1146 return false;
1147
1148 case 38:
60a4e0b3 1149 $popup.selectPrev();
0b2c582e
FB
1150 return false;
1151
1152 case 13: /* Return */
60a4e0b3 1153 return $popup.activeCurrent();
0b2c582e
FB
1154
1155 case 27: /* Escape */
60a4e0b3
FB
1156 if ($popup.selected()) {
1157 $popup.unselect();
1158 } else {
1159 $popup.hide();
1160 }
1161 return true;
aaffb7b2
FB
1162 }
1163 return true;
1164 })
1165 .blur(function() {
60a4e0b3 1166 return $popup.hide(true);
aaffb7b2 1167 })
8ca09823 1168 .focus(updatePopup);});
aaffb7b2
FB
1169 }
1170 });
1171}(jQuery));
7143ad2b 1172
0337d704 1173/***************************************************************************
048c44a3
FB
1174 * Overlib made simple
1175 */
1176
1177(function($) {
1178 $.fn.extend({
1179 overlib: function(text, width, height) {
1180 var args = [ ];
34cc65fd
FB
1181 var key;
1182
1183 if (typeof text === 'string') {
048c44a3 1184 args.push(text);
34cc65fd 1185 if (width) {
c8985ea9 1186 args.push(WIDTH, width);
34cc65fd
FB
1187 }
1188 if (height) {
c8985ea9 1189 args.push(HEIGHT, height);
34cc65fd 1190 }
048c44a3 1191 } else {
34cc65fd 1192 for (key in text) {
048c44a3
FB
1193 switch (key) {
1194 case 'text':
1195 args.unshift(text[key]);
1196 break;
1197 case 'caption':
1198 args.push(CAPTION, text[key]);
1199 break;
1200 case 'close_text':
1201 args.push(CLOSETEXT, text[key]);
1202 break;
1203 case 'delay':
1204 args.push(DELAY, text[key]);
1205 break;
1206 case 'sticky':
1207 if (text[key]) {
1208 args.push(STICKY);
1209 }
1210 break;
1211 case 'width':
1212 args.push(WIDTH, text[key]);
1213 break;
1214 case 'height':
1215 args.push(HEIGHT, text[key]);
1216 break;
1217 }
1218 }
1219 }
1220 return this
1221 .mouseover(function () {
1222 return overlib.apply(null, args);
1223 })
1224 .mouseout(nd);
1225 }
1226 });
1227}(jQuery));
60a4e0b3 1228/* }}} */
048c44a3
FB
1229
1230/***************************************************************************
0337d704 1231 * The real OnLoad
1232 */
1233
4171c0bf 1234$(function() {
80dcbd9a
FB
1235 auto_links();
1236 getNow();
1237 setInterval(getNow, 1000);
1238 $("#quick")
1239 .focus(function() {
1240 if ($(this).val() === 'Recherche dans l\'annuaire') {
1241 $(this).val('');
1242 }
1243 $("#quick_button").show();
1244 })
1245 .blur(function() {
1246 $("#quick_button").hide();
aaffb7b2
FB
1247 })
1248 .quickSearch();
80dcbd9a
FB
1249 $("#quick_button").click(function() {
1250 if ($("#quick").val() === 'Recherche dans l\'annuaire'
1251 || $("#quick").val() === '') {
1252 return false;
1253 }
1254 return true;
1255 });
1256});
0337d704 1257
a14159bf 1258// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8: