nitdoc: Adding an action to "sign in" button
[nit.git] / share / nitdoc / scripts / js-facilities.js
1 // User
2 var userB64 = null;
3 var sessionStarted = false;
4
5 /*
6 * JQuery Case Insensitive :icontains selector
7 */
8 $.expr[':'].icontains = function(obj, index, meta, stack){
9 return (obj.textContent.replace(/\[[0-9]+\]/g, "") || obj.innerText.replace(/\[[0-9]+\]/g, "") || jQuery(obj).text().replace(/\[[0-9]+\]/g, "") || '').toLowerCase().indexOf(meta[3].toLowerCase()) >= 0;
10 };
11
12 /*
13 * Quick Search global vars
14 */
15
16 // Current search results preview table
17 var currentTable = null;
18
19 //Hightlighted index in search result preview table
20 var currentIndex = -1;
21
22
23 /*
24 * Add folding and filtering facilities to class description page.
25 */
26 $(document).ready(function() {
27
28 /*
29 * Highlight the spoted element
30 */
31 highlightBlock(currentAnchor());
32
33 /*
34 * Nav block folding
35 */
36
37 // Menu nav folding
38 $(".menu nav h3")
39 .prepend(
40 $(document.createElement("a"))
41 .html("-")
42 .addClass("fold")
43 )
44 .css("cursor", "pointer")
45 .click( function() {
46 if($(this).find("a.fold").html() == "+") {
47 $(this).find("a.fold").html("-");
48 } else {
49 $(this).find("a.fold").html("+");
50 }
51 $(this).nextAll().toggle();
52 })
53
54 // Insert search field
55 $("nav.main ul")
56 .append(
57 $(document.createElement("li"))
58 .append(
59 $(document.createElement("form"))
60 .append(
61 $(document.createElement("input"))
62 .attr({
63 id: "search",
64 type: "text",
65 autocomplete: "off",
66 value: "quick search..."
67 })
68 .addClass("notUsed")
69
70 // Key management
71 .keyup(function(e) {
72 switch(e.keyCode) {
73
74 // Select previous result on "Up"
75 case 38:
76 // If already on first result, focus search input
77 if(currentIndex == 0) {
78 $("#search").val($(currentTable.find("tr")[currentIndex]).data("searchDetails").name);
79 $("#search").focus();
80 // Else select previous result
81 } else if(currentIndex > 0) {
82 $(currentTable.find("tr")[currentIndex]).removeClass("activeSearchResult");
83 currentIndex--;
84 $(currentTable.find("tr")[currentIndex]).addClass("activeSearchResult");
85 $("#search").val($(currentTable.find("tr")[currentIndex]).data("searchDetails").name);
86 $("#search").focus();
87 }
88 break;
89
90 // Select next result on "Down"
91 case 40:
92 if(currentIndex < currentTable.find("tr").length - 1) {
93 $(currentTable.find("tr")[currentIndex]).removeClass("activeSearchResult");
94 currentIndex++;
95 $(currentTable.find("tr")[currentIndex]).addClass("activeSearchResult");
96 $("#search").val($(currentTable.find("tr")[currentIndex]).data("searchDetails").name);
97 $("#search").focus();
98 }
99 break;
100 // Go to url on "Enter"
101 case 13:
102 if(currentIndex > -1) {
103 window.location = $(currentTable.find("tr")[currentIndex]).data("searchDetails").url;
104 return false;
105 }
106 if($("#search").val().length == 0)
107 return false
108
109 window.location = "full-index.html#q=" + $("#search").val();
110 if(window.location.href.indexOf("full-index.html") > -1) {
111 location.reload();
112 }
113 return false;
114 break;
115
116 // Hide results preview on "Escape"
117 case 27:
118 $(this).blur();
119 if(currentTable != null) {
120 currentTable.remove();
121 currentTable = null;
122 }
123 break;
124
125 default:
126 if($("#search").val().length == 0) {
127 return false;
128 }
129
130 // Remove previous table
131 if(currentTable != null) {
132 currentTable.remove();
133 }
134
135 // Build results table
136 currentIndex = -1;
137 currentTable = $(document.createElement("table"));
138
139 // Escape regexp related characters in query
140 var query = $("#search").val();
141 query = query.replace(/\[/gi, "\\[");
142 query = query.replace(/\|/gi, "\\|");
143 query = query.replace(/\*/gi, "\\*");
144 query = query.replace(/\+/gi, "\\+");
145 query = query.replace(/\\/gi, "\\\\");
146 query = query.replace(/\?/gi, "\\?");
147 query = query.replace(/\(/gi, "\\(");
148 query = query.replace(/\)/gi, "\\)");
149
150 var index = 0;
151 var regexp = new RegExp("^" + query, "i");
152 for(var entry in entries) {
153 if(index > 10) {
154 break;
155 }
156 var result = entry.match(regexp);
157 if(result != null && result.toString().toUpperCase() == $("#search").val().toUpperCase()) {
158 for(var i = 0; i < entries[entry].length; i++) {
159 if(index > 10) {
160 break;
161 }
162 currentTable.append(
163 $(document.createElement("tr"))
164 .data("searchDetails", {name: entry, url: entries[entry][i]["url"]})
165 .data("index", index)
166 .append($(document.createElement("td")).html(entry))
167 .append(
168 $(document.createElement("td"))
169 .addClass("entryInfo")
170 .html(entries[entry][i]["txt"] + "&nbsp;&raquo;"))
171 .mouseover( function() {
172 $(currentTable.find("tr")[currentIndex]).removeClass("activeSearchResult");
173 $(this).addClass("activeSearchResult");
174 currentIndex = $(this).data("index");
175 })
176 .mouseout( function() {
177 $(this).removeClass("activeSearchResult");
178 })
179 .click( function() {
180 window.location = $(this).data("searchDetails")["url"];
181 })
182 );
183 index++;
184 }
185 }
186 }
187
188 // Initialize table properties
189 currentTable.attr("id", "searchTable");
190 currentTable.css("position", "absolute");
191 currentTable.width($("#search").outerWidth());
192 $("header").append(currentTable);
193 currentTable.offset({left: $("#search").offset().left + ($("#search").outerWidth() - currentTable.outerWidth()), top: $("#search").offset().top + $("#search").outerHeight()});
194
195 // Preselect first entry
196 if(currentTable.find("tr").length > 0) {
197 currentIndex = 0;
198 $(currentTable.find("tr")[currentIndex]).addClass("activeSearchResult");
199 $("#search").focus();
200 }
201 break;
202 }
203 })
204 .focusout(function() {
205 if($(this).val() == "") {
206 $(this).addClass("notUsed");
207 $(this).val("quick search...");
208 }
209 })
210 .focusin(function() {
211 if($(this).val() == "quick search...") {
212 $(this).removeClass("notUsed");
213 $(this).val("");
214 }
215 })
216 )
217 .submit( function() {
218 return false;
219 })
220 )
221 );
222
223 // Close quicksearch list on click
224 $(document).click(function(e) {
225 if(e.target != $("#search")[0] && e.target != $("#searchTable")[0]) {
226 if(currentTable != null) {
227 currentTable.remove();
228 currentTable = null;
229 }
230 }
231 });
232
233 // Insert filter field
234 $("article.filterable h2, nav.filterable h3")
235 .after(
236 $(document.createElement("div"))
237 .addClass("filter")
238 .append(
239 $(document.createElement("input"))
240 .attr({
241 type: "text",
242 value: "filter..."
243 })
244 .addClass("notUsed")
245 .keyup(function() {
246 $(this).parent().parent().find("ul li:not(:icontains('" + $(this).val() + "'))").addClass("hide");
247 $(this).parent().parent().find("ul li:icontains('" + $(this).val() + "')").removeClass("hide");
248 })
249 .focusout(function() {
250 if($(this).val() == "") {
251 $(this).addClass("notUsed");
252 $(this).val("filter...");
253 }
254 })
255 .focusin(function() {
256 if($(this).val() == "filter...") {
257 $(this).removeClass("notUsed");
258 $(this).val("");
259 }
260 })
261 )
262 );
263
264 // Filter toggle between H I R in nav porperties list
265 $("nav.properties.filterable .filter")
266 .append(
267 $(document.createElement("a"))
268 .html("H")
269 .attr({
270 title: "hide inherited properties"
271 })
272 .click( function() {
273 if($(this).hasClass("hidden")) {
274 $(this).parent().parent().find("li.inherit").show();
275 } else {
276 $(this).parent().parent().find("li.inherit").hide();
277 }
278
279 $(this).toggleClass("hidden");
280 })
281 )
282 .append(
283 $(document.createElement("a"))
284 .html("R")
285 .attr({
286 title: "hide redefined properties"
287 })
288 .click( function() {
289 if($(this).hasClass("hidden")) {
290 $(this).parent().parent().find("li.redef").show();
291 } else {
292 $(this).parent().parent().find("li.redef").hide();
293 }
294
295 $(this).toggleClass("hidden");
296 })
297 )
298 .append(
299 $(document.createElement("a"))
300 .html("I")
301 .attr({
302 title: "hide introduced properties"
303 })
304 .click( function() {
305 if($(this).hasClass("hidden")) {
306 $(this).parent().parent().find("li.intro").show();
307 } else {
308 $(this).parent().parent().find("li.intro").hide();
309 }
310
311 $(this).toggleClass("hidden");
312 })
313 );
314
315 // Filter toggle between I R in
316 $("article.properties.filterable .filter, article.classes.filterable .filter")
317 .append(
318 $(document.createElement("a"))
319 .html("I")
320 .attr({
321 title: "hide introduced properties"
322 })
323 .click( function() {
324 if($(this).hasClass("hidden")) {
325 $(this).parent().parent().find("li.intro").show();
326 } else {
327 $(this).parent().parent().find("li.intro").hide();
328 }
329
330 $(this).toggleClass("hidden");
331 })
332 )
333 .append(
334 $(document.createElement("a"))
335 .html("R")
336 .attr({
337 title: "hide redefined properties"
338 })
339 .click( function() {
340 if($(this).hasClass("hidden")) {
341 $(this).parent().parent().find("li.redef").show();
342 } else {
343 $(this).parent().parent().find("li.redef").hide();
344 }
345
346 $(this).toggleClass("hidden");
347 })
348 );
349
350 /*
351 * Anchors jumps
352 */
353 $("a[href*='#']").click( function() {
354 highlightBlock($(this).attr("href").split(/#/)[1]);
355 });
356
357 //Preload filter fields with query string
358 preloadFilters();
359 // Hide Authenfication form
360 $(".popover").hide();
361 // Display Login modal
362 $("#logGitHub").click(function(){ displayLogginModal(); });
363 // Update display
364 updateDisplaying();
365 // If cookie existing the session is opened
366 if(sessionStarted){ userB64 = "Basic " + getUserPass("logginNitdoc"); }
367
368 // Sign In an github user or Log out him
369 $("#signIn").click(function(){
370 if(!sessionStarted){
371 if($('#loginGit').val() == "" || $('#passwordGit').val() == ""){ displayMessage('The comment field is empty!', 40, 45); }
372 else
373 {
374 userName = $('#loginGit').val();
375 password = $('#passwordGit').val();
376 repoName = $('#repositoryGit').val();
377 branchName = $('#branchGit').val();
378 userB64 = "Basic " + base64.encode(userName+':'+password);
379 setCookie("logginNitdoc", base64.encode(userName+':'+password+':'+repoName+':'+branchName), 1);
380 $('#loginGit').val("");
381 $('#passwordGit').val("");
382 }
383 }
384 else
385 {
386 // Delete cookie and reset settings
387 del_cookie("logginNitdoc");
388 }
389 displayLogginModal();
390 });
391 });
392
393 /* Parse current URL and return anchor name */
394 function currentAnchor() {
395 var index = document.location.hash.indexOf("#");
396 if (index >= 0) {
397 return document.location.hash.substring(index + 1);
398 }
399 return null;
400 }
401
402 /* Prealod filters field using search query */
403 function preloadFilters() {
404 // Parse URL and get query string
405 var search = currentAnchor();
406
407 if(search == null || search.indexOf("q=") == -1)
408 return;
409
410 search = search.substring(2, search.length);
411
412 if(search == "" || search == "undefined")
413 return;
414
415 $(":text").val(search);
416 $(".filter :text")
417 .removeClass("notUsed")
418 .trigger("keyup");
419
420 }
421
422 /* Hightlight the spoted block */
423 function highlightBlock(a) {
424 if(a == undefined) {
425 return;
426 }
427
428 $(".highlighted").removeClass("highlighted");
429
430 var target = $("#" + a);
431
432 if(target.is("article")) {
433 target.parent().addClass("highlighted");
434 }
435
436 target.addClass("highlighted");
437 target.show();
438 }
439
440 function displayLogginModal(){
441 if ($('.popover').is(':hidden')) { $('.popover').show(); }
442 else { $('.popover').hide(); }
443 updateDisplaying();
444 }
445
446 function updateDisplaying(){
447 if (checkCookie())
448 {
449 $('#loginGit').hide();
450 $('#passwordGit').hide();
451 $('#lbpasswordGit').hide();
452 $('#lbloginGit').hide();
453 $('#repositoryGit').hide();
454 $('#lbrepositoryGit').hide();
455 $('#lbbranchGit').hide();
456 $('#branchGit').hide();
457 $("#liGitHub").attr("class", "current");
458 $("#imgGitHub").attr("src", "resources/icons/github-icon-w.png");
459 $('#nickName').text(userName);
460 $('#githubAccount').attr("href", "https://github.com/"+userName);
461 $('#logginMessage').css({'display' : 'block'});
462 $('#logginMessage').css({'text-align' : 'center'});
463 $('.popover').css({'height' : '80px'});
464 $('#signIn').text("Sign out");
465 sessionStarted = true;
466 }
467 else
468 {
469 sessionStarted = false;
470 $('#logginMessage').css({'display' : 'none'});
471 $("#liGitHub").attr("class", "");
472 $("#imgGitHub").attr("src", "resources/icons/github-icon.png");
473 $('#loginGit').val("");
474 $('#passwordGit').val("");
475 $('#nickName').text("");
476 $('.popover').css({'height' : '280px'});
477 $('#logginMessage').css({'display' : 'none'});
478 $('#repositoryGit').val($('#repoName').attr('name'));
479 $('#branchGit').val('wikidoc');
480 $('#signIn').text("Sign In");
481 $('#loginGit').show();
482 $('#passwordGit').show();
483 $('#lbpasswordGit').show();
484 $('#lbloginGit').show();
485 $('#repositoryGit').show();
486 $('#lbrepositoryGit').show();
487 $('#lbbranchGit').show();
488 $('#branchGit').show();
489 }
490 }
491
492 function setCookie(c_name, value, exdays)
493 {
494 var exdate=new Date();
495 exdate.setDate(exdate.getDate() + exdays);
496 var c_value=escape(value) + ((exdays==null) ? "" : "; expires="+exdate.toUTCString());
497 document.cookie=c_name + "=" + c_value;
498 }
499
500 function del_cookie(c_name)
501 {
502 document.cookie = c_name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
503 }
504
505 function getCookie(c_name)
506 {
507 var c_value = document.cookie;
508 var c_start = c_value.indexOf(" " + c_name + "=");
509 if (c_start == -1) { c_start = c_value.indexOf(c_name + "="); }
510 if (c_start == -1) { c_value = null; }
511 else
512 {
513 c_start = c_value.indexOf("=", c_start) + 1;
514 var c_end = c_value.indexOf(";", c_start);
515 if (c_end == -1) { c_end = c_value.length; }
516 c_value = unescape(c_value.substring(c_start,c_end));
517 }
518 return c_value;
519 }
520
521 function getUserPass(c_name){
522 var cookie = base64.decode(getCookie(c_name));
523 return base64.encode(cookie.split(':')[0] + ':' + cookie.split(':')[1]);
524 }
525
526 function checkCookie()
527 {
528 var cookie=getCookie("logginNitdoc");
529 if (cookie!=null && cookie!="")
530 {
531 cookie = base64.decode(cookie);
532 userName = cookie.split(':')[0];
533 repoName = cookie.split(':')[2];
534 branchName = cookie.split(':')[3];
535 return true;
536 }
537 else { return false; }
538 }
539
540
541 /*
542 * Base64
543 */
544 base64 = {};
545 base64.PADCHAR = '=';
546 base64.ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
547 base64.getbyte64 = function(s,i) {
548 // This is oddly fast, except on Chrome/V8.
549 // Minimal or no improvement in performance by using a
550 // object with properties mapping chars to value (eg. 'A': 0)
551 var idx = base64.ALPHA.indexOf(s.charAt(i));
552 if (idx == -1) {
553 throw "Cannot decode base64";
554 }
555 return idx;
556 }
557
558 base64.decode = function(s) {
559 // convert to string
560 s = "" + s;
561 var getbyte64 = base64.getbyte64;
562 var pads, i, b10;
563 var imax = s.length
564 if (imax == 0) {
565 return s;
566 }
567
568 if (imax % 4 != 0) {
569 throw "Cannot decode base64";
570 }
571
572 pads = 0
573 if (s.charAt(imax -1) == base64.PADCHAR) {
574 pads = 1;
575 if (s.charAt(imax -2) == base64.PADCHAR) {
576 pads = 2;
577 }
578 // either way, we want to ignore this last block
579 imax -= 4;
580 }
581
582 var x = [];
583 for (i = 0; i < imax; i += 4) {
584 b10 = (getbyte64(s,i) << 18) | (getbyte64(s,i+1) << 12) |
585 (getbyte64(s,i+2) << 6) | getbyte64(s,i+3);
586 x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 0xff, b10 & 0xff));
587 }
588
589 switch (pads) {
590 case 1:
591 b10 = (getbyte64(s,i) << 18) | (getbyte64(s,i+1) << 12) | (getbyte64(s,i+2) << 6)
592 x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 0xff));
593 break;
594 case 2:
595 b10 = (getbyte64(s,i) << 18) | (getbyte64(s,i+1) << 12);
596 x.push(String.fromCharCode(b10 >> 16));
597 break;
598 }
599 return x.join('');
600 }
601
602 base64.getbyte = function(s,i) {
603 var x = s.charCodeAt(i);
604 if (x > 255) {
605 throw "INVALID_CHARACTER_ERR: DOM Exception 5";
606 }
607 return x;
608 }
609
610
611 base64.encode = function(s) {
612 if (arguments.length != 1) {
613 throw "SyntaxError: Not enough arguments";
614 }
615 var padchar = base64.PADCHAR;
616 var alpha = base64.ALPHA;
617 var getbyte = base64.getbyte;
618
619 var i, b10;
620 var x = [];
621
622 // convert to string
623 s = "" + s;
624
625 var imax = s.length - s.length % 3;
626
627 if (s.length == 0) {
628 return s;
629 }
630 for (i = 0; i < imax; i += 3) {
631 b10 = (getbyte(s,i) << 16) | (getbyte(s,i+1) << 8) | getbyte(s,i+2);
632 x.push(alpha.charAt(b10 >> 18));
633 x.push(alpha.charAt((b10 >> 12) & 0x3F));
634 x.push(alpha.charAt((b10 >> 6) & 0x3f));
635 x.push(alpha.charAt(b10 & 0x3f));
636 }
637 switch (s.length - imax) {
638 case 1:
639 b10 = getbyte(s,i) << 16;
640 x.push(alpha.charAt(b10 >> 18) + alpha.charAt((b10 >> 12) & 0x3F) +
641 padchar + padchar);
642 break;
643 case 2:
644 b10 = (getbyte(s,i) << 16) | (getbyte(s,i+1) << 8);
645 x.push(alpha.charAt(b10 >> 18) + alpha.charAt((b10 >> 12) & 0x3F) +
646 alpha.charAt((b10 >> 6) & 0x3f) + padchar);
647 break;
648 }
649 return x.join('');
650 }
651
652 $.fn.spin = function(opts) {
653 this.each(function() {
654 var $this = $(this),
655 data = $this.data();
656
657 if (data.spinner) {
658 data.spinner.stop();
659 delete data.spinner;
660 }
661 if (opts !== false) {
662 data.spinner = new Spinner($.extend({color: $this.css('color')}, opts)).spin(this);
663 }
664 });
665 return this;
666 };