nitdoc: Add a secure when the user reload the page
[nit.git] / share / nitdoc / scripts / js-facilities.js
1 // User
2 var userB64 = null;
3 var sessionStarted = false;
4 var editComment = 0;
5 var currentfileContent = '';
6
7 // SHA GitHub
8 var shaLastCommit = "";
9 var shaBaseTree;
10 var shaNewTree;
11 var shaNewCommit;
12 var shaBlob;
13 var shaMaster;
14 var repoExist = false;
15 var branchExist = false;
16 var githubRepo;
17
18 // Spinner vars
19 var opts = {
20 lines: 11, // The number of lines to draw
21 length: 7, // The length of each line
22 width: 4, // The line thickness
23 radius: 10, // The radius of the inner circle
24 corners: 1, // Corner roundness (0..1)
25 rotate: 0, // The rotation offset
26 color: '#FFF', // #rgb or #rrggbb
27 speed: 1, // Rounds per second
28 trail: 60, // Afterglow percentage
29 shadow: false, // Whether to render a shadow
30 hwaccel: false, // Whether to use hardware acceleration
31 className: 'spinner', // The CSS class to assign to the spinner
32 zIndex: 99999, // The z-index (defaults to 2000000000)
33 top: '300', // Top position relative to parent in px
34 left: 'auto' // Left position relative to parent in px
35 };
36 var targetSpinner = document.getElementById('waitCommit');
37 var spinner = new Spinner(opts).spin(targetSpinner);
38
39 /*
40 * JQuery Case Insensitive :icontains selector
41 */
42 $.expr[':'].icontains = function(obj, index, meta, stack){
43 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;
44 };
45
46 /*
47 * Quick Search global vars
48 */
49
50 // Current search results preview table
51 var currentTable = null;
52
53 //Hightlighted index in search result preview table
54 var currentIndex = -1;
55
56 // Check if a comment is editing
57 window.onbeforeunload = function() {
58 if(editComment > 0){
59 return 'Are you sure you want to leave this page?';
60 }
61 };
62
63 /*
64 * Add folding and filtering facilities to class description page.
65 */
66 $(document).ready(function() {
67
68 // Hide edit tags
69 $('textarea').hide();
70 $('a[id=commitBtn]').hide();
71 $('a[id=cancelBtn]').hide();
72 // Hide Authenfication form
73 $(".popover").hide();
74 // Update display
75 updateDisplaying();
76 githubRepo = $('#repoName').attr('name');
77 // Load comment from the original repo
78 reloadComment();
79 /*
80 * Highlight the spoted element
81 */
82 highlightBlock(currentAnchor());
83
84 /*
85 * Nav block folding
86 */
87
88 // Menu nav folding
89 $(".menu nav h3")
90 .prepend(
91 $(document.createElement("a"))
92 .html("-")
93 .addClass("fold")
94 )
95 .css("cursor", "pointer")
96 .click( function() {
97 if($(this).find("a.fold").html() == "+") {
98 $(this).find("a.fold").html("-");
99 } else {
100 $(this).find("a.fold").html("+");
101 }
102 $(this).nextAll().toggle();
103 })
104
105 // Insert search field
106 $("nav.main ul")
107 .append(
108 $(document.createElement("li"))
109 .append(
110 $(document.createElement("form"))
111 .append(
112 $(document.createElement("input"))
113 .attr({
114 id: "search",
115 type: "text",
116 autocomplete: "off",
117 value: "quick search..."
118 })
119 .addClass("notUsed")
120
121 // Key management
122 .keyup(function(e) {
123 switch(e.keyCode) {
124
125 // Select previous result on "Up"
126 case 38:
127 // If already on first result, focus search input
128 if(currentIndex == 0) {
129 $("#search").val($(currentTable.find("tr")[currentIndex]).data("searchDetails").name);
130 $("#search").focus();
131 // Else select previous result
132 } else if(currentIndex > 0) {
133 $(currentTable.find("tr")[currentIndex]).removeClass("activeSearchResult");
134 currentIndex--;
135 $(currentTable.find("tr")[currentIndex]).addClass("activeSearchResult");
136 $("#search").val($(currentTable.find("tr")[currentIndex]).data("searchDetails").name);
137 $("#search").focus();
138 }
139 break;
140
141 // Select next result on "Down"
142 case 40:
143 if(currentIndex < currentTable.find("tr").length - 1) {
144 $(currentTable.find("tr")[currentIndex]).removeClass("activeSearchResult");
145 currentIndex++;
146 $(currentTable.find("tr")[currentIndex]).addClass("activeSearchResult");
147 $("#search").val($(currentTable.find("tr")[currentIndex]).data("searchDetails").name);
148 $("#search").focus();
149 }
150 break;
151 // Go to url on "Enter"
152 case 13:
153 if(currentIndex > -1) {
154 window.location = $(currentTable.find("tr")[currentIndex]).data("searchDetails").url;
155 return false;
156 }
157 if($("#search").val().length == 0)
158 return false
159
160 window.location = "full-index.html#q=" + $("#search").val();
161 if(window.location.href.indexOf("full-index.html") > -1) {
162 location.reload();
163 }
164 return false;
165 break;
166
167 // Hide results preview on "Escape"
168 case 27:
169 $(this).blur();
170 if(currentTable != null) {
171 currentTable.remove();
172 currentTable = null;
173 }
174 break;
175
176 default:
177 if($("#search").val().length == 0) {
178 return false;
179 }
180
181 // Remove previous table
182 if(currentTable != null) {
183 currentTable.remove();
184 }
185
186 // Build results table
187 currentIndex = -1;
188 currentTable = $(document.createElement("table"));
189
190 // Escape regexp related characters in query
191 var query = $("#search").val();
192 query = query.replace(/\[/gi, "\\[");
193 query = query.replace(/\|/gi, "\\|");
194 query = query.replace(/\*/gi, "\\*");
195 query = query.replace(/\+/gi, "\\+");
196 query = query.replace(/\\/gi, "\\\\");
197 query = query.replace(/\?/gi, "\\?");
198 query = query.replace(/\(/gi, "\\(");
199 query = query.replace(/\)/gi, "\\)");
200
201 var index = 0;
202 var regexp = new RegExp("^" + query, "i");
203 for(var entry in entries) {
204 if(index > 10) {
205 break;
206 }
207 var result = entry.match(regexp);
208 if(result != null && result.toString().toUpperCase() == $("#search").val().toUpperCase()) {
209 for(var i = 0; i < entries[entry].length; i++) {
210 if(index > 10) {
211 break;
212 }
213 currentTable.append(
214 $(document.createElement("tr"))
215 .data("searchDetails", {name: entry, url: entries[entry][i]["url"]})
216 .data("index", index)
217 .append($(document.createElement("td")).html(entry))
218 .append(
219 $(document.createElement("td"))
220 .addClass("entryInfo")
221 .html(entries[entry][i]["txt"] + "&nbsp;&raquo;"))
222 .mouseover( function() {
223 $(currentTable.find("tr")[currentIndex]).removeClass("activeSearchResult");
224 $(this).addClass("activeSearchResult");
225 currentIndex = $(this).data("index");
226 })
227 .mouseout( function() {
228 $(this).removeClass("activeSearchResult");
229 })
230 .click( function() {
231 window.location = $(this).data("searchDetails")["url"];
232 })
233 );
234 index++;
235 }
236 }
237 }
238
239 // Initialize table properties
240 currentTable.attr("id", "searchTable");
241 currentTable.css("position", "absolute");
242 currentTable.width($("#search").outerWidth());
243 $("header").append(currentTable);
244 currentTable.offset({left: $("#search").offset().left + ($("#search").outerWidth() - currentTable.outerWidth()), top: $("#search").offset().top + $("#search").outerHeight()});
245
246 // Preselect first entry
247 if(currentTable.find("tr").length > 0) {
248 currentIndex = 0;
249 $(currentTable.find("tr")[currentIndex]).addClass("activeSearchResult");
250 $("#search").focus();
251 }
252 break;
253 }
254 })
255 .focusout(function() {
256 if($(this).val() == "") {
257 $(this).addClass("notUsed");
258 $(this).val("quick search...");
259 }
260 })
261 .focusin(function() {
262 if($(this).val() == "quick search...") {
263 $(this).removeClass("notUsed");
264 $(this).val("");
265 }
266 })
267 )
268 .submit( function() {
269 return false;
270 })
271 )
272 );
273
274 // Close quicksearch list on click
275 $(document).click(function(e) {
276 if(e.target != $("#search")[0] && e.target != $("#searchTable")[0]) {
277 if(currentTable != null) {
278 currentTable.remove();
279 currentTable = null;
280 }
281 }
282 });
283
284 // Insert filter field
285 $("article.filterable h2, nav.filterable h3")
286 .after(
287 $(document.createElement("div"))
288 .addClass("filter")
289 .append(
290 $(document.createElement("input"))
291 .attr({
292 type: "text",
293 value: "filter..."
294 })
295 .addClass("notUsed")
296 .keyup(function() {
297 $(this).parent().parent().find("ul li:not(:icontains('" + $(this).val() + "'))").addClass("hide");
298 $(this).parent().parent().find("ul li:icontains('" + $(this).val() + "')").removeClass("hide");
299 })
300 .focusout(function() {
301 if($(this).val() == "") {
302 $(this).addClass("notUsed");
303 $(this).val("filter...");
304 }
305 })
306 .focusin(function() {
307 if($(this).val() == "filter...") {
308 $(this).removeClass("notUsed");
309 $(this).val("");
310 }
311 })
312 )
313 );
314
315 // Filter toggle between H I R in nav porperties list
316 $("nav.properties.filterable .filter")
317 .append(
318 $(document.createElement("a"))
319 .html("H")
320 .attr({
321 title: "hide inherited properties"
322 })
323 .click( function() {
324 if($(this).hasClass("hidden")) {
325 $(this).parent().parent().find("li.inherit").show();
326 } else {
327 $(this).parent().parent().find("li.inherit").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 .append(
350 $(document.createElement("a"))
351 .html("I")
352 .attr({
353 title: "hide introduced properties"
354 })
355 .click( function() {
356 if($(this).hasClass("hidden")) {
357 $(this).parent().parent().find("li.intro").show();
358 } else {
359 $(this).parent().parent().find("li.intro").hide();
360 }
361
362 $(this).toggleClass("hidden");
363 })
364 );
365
366 // Filter toggle between I R in
367 $("article.properties.filterable .filter, article.classes.filterable .filter")
368 .append(
369 $(document.createElement("a"))
370 .html("I")
371 .attr({
372 title: "hide introduced properties"
373 })
374 .click( function() {
375 if($(this).hasClass("hidden")) {
376 $(this).parent().parent().find("li.intro").show();
377 } else {
378 $(this).parent().parent().find("li.intro").hide();
379 }
380
381 $(this).toggleClass("hidden");
382 })
383 )
384 .append(
385 $(document.createElement("a"))
386 .html("R")
387 .attr({
388 title: "hide redefined properties"
389 })
390 .click( function() {
391 if($(this).hasClass("hidden")) {
392 $(this).parent().parent().find("li.redef").show();
393 } else {
394 $(this).parent().parent().find("li.redef").hide();
395 }
396
397 $(this).toggleClass("hidden");
398 })
399 );
400
401 /*
402 * Anchors jumps
403 */
404 $("a[href*='#']").click( function() {
405 highlightBlock($(this).attr("href").split(/#/)[1]);
406 });
407
408 //Preload filter fields with query string
409 preloadFilters();
410 // Hide Authenfication form
411 $(".popover").hide();
412 // Display Login modal
413 $("#logGitHub").click(function(){ displayLogginModal(); });
414 // Update display
415 updateDisplaying();
416 // If cookie existing the session is opened
417 if(sessionStarted){ userB64 = "Basic " + getUserPass("logginNitdoc"); }
418
419 // Sign In an github user or Log out him
420 $("#signIn").click(function(){
421 if(!sessionStarted){
422 if($('#loginGit').val() == "" || $('#passwordGit').val() == ""){ displayMessage('The comment field is empty!', 40, 45); }
423 else
424 {
425 userName = $('#loginGit').val();
426 password = $('#passwordGit').val();
427 repoName = $('#repositoryGit').val();
428 branchName = $('#branchGit').val();
429 userB64 = "Basic " + base64.encode(userName+':'+password);
430 setCookie("logginNitdoc", base64.encode(userName+':'+password+':'+repoName+':'+branchName), 1);
431 $('#loginGit').val("");
432 $('#passwordGit').val("");
433 }
434 }
435 else
436 {
437 // Delete cookie and reset settings
438 del_cookie("logginNitdoc");
439 }
440 displayLogginModal();
441 });
442
443 // Activate edit mode
444 $('pre[class=text_label]').click(function(){
445 // the customer is loggued ?
446 if(!sessionStarted || userName == ""){
447 // No => nothing happen
448 return;
449 }
450 else{
451 var arrayNew = $(this).text().split('\n');
452 var lNew = arrayNew.length - 1;
453 var adapt = "";
454
455 for (var i = 0; i < lNew; i++) {
456 adapt += arrayNew[i];
457 if(i < lNew-1){ adapt += "\n"; }
458 }
459 editComment += 1;
460 // hide comment
461 $(this).hide();
462 // Show edit box
463 $(this).next().show();
464 // Show cancel button
465 $(this).next().next().show();
466 // Show commit button
467 $(this).next().next().next().show();
468 // Add text in edit box
469 if($(this).next().val() == ""){ $(this).next().val(adapt); }
470 // Resize edit box
471 $(this).next().height($(this).next().prop("scrollHeight"));
472 // Select it
473 $(this).next().select();
474 preElement = $(this);
475 }
476 });
477
478 // Disable the edit mode
479 $('a[id=cancelBtn]').click(function(){
480 if(editComment > 0){ editComment -= 1; }
481 // Hide itself
482 $(this).hide();
483 // Hide commitBtn
484 $(this).next().hide();
485 // Hide Textarea
486 $(this).prev().hide();
487 // Show comment
488 $(this).prev().prev().show();
489 });
490
491 // Display commit form
492 $('a[id=commitBtn]').click(function(){
493 updateComment = $(this).prev().prev().val();
494 commentType = $(this).prev().prev().prev().attr('type');
495
496 if(updateComment == ""){ displayMessage('The comment field is empty!', 40, 45); }
497 else{
498 if(!sessionStarted){
499 displayMessage("You need to be loggued before commit something", 45, 40);
500 displayLogginModal();
501 return;
502 }
503 $('#commitMessage').val('New commit');
504 pathFile = $(this).prev().prev().prev().attr('tag');
505 $('#modal').show().prepend('<a class="close"><img src="resources/icons/close.png" class="btn_close" title="Close" alt="Close" /></a>');
506 $('body').append('<div id="fade"></div>');
507 $('#fade').css({'filter' : 'alpha(opacity=80)'}).fadeIn();
508 }
509 });
510
511 // Close commit form
512 $('.btn_close').click(function(){
513 $(this).hide();
514 $(this).next().hide();
515 if(editComment > 0){ editComment -= 1; }
516 });
517
518 //Close Popups and Fade Layer
519 $('body').on('click', 'a.close, #fade', function() {
520 if(editComment > 0){ editComment -= 1; }
521 $('#fade , #modal').fadeOut(function() {
522 $('#fade, a.close').remove();
523 });
524 $('#modalQuestion').hide();
525 });
526
527 $('#loginAction').click(function(){
528 var text;
529 var url;
530 var line;
531 // Look if the customer is logged
532 if(!sessionStarted){
533 displayMessage("You need to be loggued before commit something", 100, 40);
534 $('.popover').show();
535 return;
536 }
537 else{ userB64 = "Basic " + getUserPass("logginNitdoc"); }
538 githubRepo = repoName;
539 // Check if repo exist
540 isRepoExisting();
541 if(repoExist){
542 isBranchExisting();
543 if(branchExist){
544 editComment -= 1;
545 commitMessage = $('#commitMessage').val();
546 if(commitMessage == ""){ commitMessage = "New commit";}
547 if(sessionStarted){
548 if ($.trim(updateComment) == ''){ this.value = (this.defaultValue ? this.defaultValue : ''); }
549 else{
550 displaySpinner();
551 startCommitProcess();
552 }
553 }
554 $('#modal, #modalQuestion').fadeOut(function() {
555 $('#login').val("");
556 $('#password').val("");
557 $('textarea').hide();
558 $('textarea').prev().show();
559 });
560 $('a[id=cancelBtn]').hide();
561 $('a[id=commitBtn]').hide();
562 // Re-load all comment
563 reloadComment();
564 }
565 }
566 else{ editComment -= 1; }
567 });
568
569 // Cancel creating branch
570 $('#btnCancelBranch').click(function(){
571 editComment -= 1;
572 $('#modalQuestion').hide();
573 $('#fade , #modal').fadeOut(function() { $('#fade, a.close').remove(); });
574 return;
575 });
576
577 // Create new branch and continu
578 $('#btnCreateBranch').click(function(){
579 $('#modalQuestion').hide();
580 if($('#btnCreateBranch').text() != 'Ok'){
581 // Create the branch
582 createBranch();
583 commitMessage = $('#commitMessage').val();
584 if(commitMessage == ""){ commitMessage = "New commit"; }
585 if(userB64 != ""){
586 if ($.trim(updateComment) == ''){ this.value = (this.defaultValue ? this.defaultValue : ''); }
587 else{ startCommitProcess(); }
588 }
589 }
590 else
591 {
592 $('#fade , #modalQuestion, #modal').fadeOut(function() { $('#fade, a.close').remove(); });
593 }
594 });
595
596 });
597
598 /* Parse current URL and return anchor name */
599 function currentAnchor() {
600 var index = document.location.hash.indexOf("#");
601 if (index >= 0) {
602 return document.location.hash.substring(index + 1);
603 }
604 return null;
605 }
606
607 /* Prealod filters field using search query */
608 function preloadFilters() {
609 // Parse URL and get query string
610 var search = currentAnchor();
611
612 if(search == null || search.indexOf("q=") == -1)
613 return;
614
615 search = search.substring(2, search.length);
616
617 if(search == "" || search == "undefined")
618 return;
619
620 $(":text").val(search);
621 $(".filter :text")
622 .removeClass("notUsed")
623 .trigger("keyup");
624
625 }
626
627 /* Hightlight the spoted block */
628 function highlightBlock(a) {
629 if(a == undefined) {
630 return;
631 }
632
633 $(".highlighted").removeClass("highlighted");
634
635 var target = $("#" + a);
636
637 if(target.is("article")) {
638 target.parent().addClass("highlighted");
639 }
640
641 target.addClass("highlighted");
642 target.show();
643 }
644
645 // Init process to commit the new comment
646 function startCommitProcess()
647 {
648 var numL = preElement.attr("title");
649 commentLineStart = numL.split('-')[0] - 1;
650 commentLineEnd = (commentLineStart + preElement.text().split('\n').length) - 1;
651 state = true;
652 replaceComment(updateComment, currentfileContent);
653 getLastCommit();
654 getBaseTree();
655 editComment = false;
656 }
657
658 function displayLogginModal(){
659 if ($('.popover').is(':hidden')) { $('.popover').show(); }
660 else { $('.popover').hide(); }
661 updateDisplaying();
662 }
663
664 function updateDisplaying(){
665 if (checkCookie())
666 {
667 $('#loginGit').hide();
668 $('#passwordGit').hide();
669 $('#lbpasswordGit').hide();
670 $('#lbloginGit').hide();
671 $('#repositoryGit').hide();
672 $('#lbrepositoryGit').hide();
673 $('#lbbranchGit').hide();
674 $('#branchGit').hide();
675 $("#liGitHub").attr("class", "current");
676 $("#imgGitHub").attr("src", "resources/icons/github-icon-w.png");
677 $('#nickName').text(userName);
678 $('#githubAccount').attr("href", "https://github.com/"+userName);
679 $('#logginMessage').css({'display' : 'block'});
680 $('#logginMessage').css({'text-align' : 'center'});
681 $('.popover').css({'height' : '80px'});
682 $('#signIn').text("Sign out");
683 sessionStarted = true;
684 }
685 else
686 {
687 sessionStarted = false;
688 $('#logginMessage').css({'display' : 'none'});
689 $("#liGitHub").attr("class", "");
690 $("#imgGitHub").attr("src", "resources/icons/github-icon.png");
691 $('#loginGit').val("");
692 $('#passwordGit').val("");
693 $('#nickName').text("");
694 $('.popover').css({'height' : '280px'});
695 $('#logginMessage').css({'display' : 'none'});
696 $('#repositoryGit').val($('#repoName').attr('name'));
697 $('#branchGit').val('wikidoc');
698 $('#signIn').text("Sign In");
699 $('#loginGit').show();
700 $('#passwordGit').show();
701 $('#lbpasswordGit').show();
702 $('#lbloginGit').show();
703 $('#repositoryGit').show();
704 $('#lbrepositoryGit').show();
705 $('#lbbranchGit').show();
706 $('#branchGit').show();
707 }
708 }
709
710 function setCookie(c_name, value, exdays)
711 {
712 var exdate=new Date();
713 exdate.setDate(exdate.getDate() + exdays);
714 var c_value=escape(value) + ((exdays==null) ? "" : "; expires="+exdate.toUTCString());
715 document.cookie=c_name + "=" + c_value;
716 }
717
718 function del_cookie(c_name)
719 {
720 document.cookie = c_name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
721 }
722
723 function getCookie(c_name)
724 {
725 var c_value = document.cookie;
726 var c_start = c_value.indexOf(" " + c_name + "=");
727 if (c_start == -1) { c_start = c_value.indexOf(c_name + "="); }
728 if (c_start == -1) { c_value = null; }
729 else
730 {
731 c_start = c_value.indexOf("=", c_start) + 1;
732 var c_end = c_value.indexOf(";", c_start);
733 if (c_end == -1) { c_end = c_value.length; }
734 c_value = unescape(c_value.substring(c_start,c_end));
735 }
736 return c_value;
737 }
738
739 function getUserPass(c_name){
740 var cookie = base64.decode(getCookie(c_name));
741 return base64.encode(cookie.split(':')[0] + ':' + cookie.split(':')[1]);
742 }
743
744 function checkCookie()
745 {
746 var cookie=getCookie("logginNitdoc");
747 if (cookie!=null && cookie!="")
748 {
749 cookie = base64.decode(cookie);
750 userName = cookie.split(':')[0];
751 repoName = cookie.split(':')[2];
752 branchName = cookie.split(':')[3];
753 return true;
754 }
755 else { return false; }
756 }
757
758
759 /*
760 * Base64
761 */
762 base64 = {};
763 base64.PADCHAR = '=';
764 base64.ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
765 base64.getbyte64 = function(s,i) {
766 // This is oddly fast, except on Chrome/V8.
767 // Minimal or no improvement in performance by using a
768 // object with properties mapping chars to value (eg. 'A': 0)
769 var idx = base64.ALPHA.indexOf(s.charAt(i));
770 if (idx == -1) {
771 throw "Cannot decode base64";
772 }
773 return idx;
774 }
775
776 base64.decode = function(s) {
777 // convert to string
778 s = "" + s;
779 var getbyte64 = base64.getbyte64;
780 var pads, i, b10;
781 var imax = s.length
782 if (imax == 0) {
783 return s;
784 }
785
786 if (imax % 4 != 0) {
787 throw "Cannot decode base64";
788 }
789
790 pads = 0
791 if (s.charAt(imax -1) == base64.PADCHAR) {
792 pads = 1;
793 if (s.charAt(imax -2) == base64.PADCHAR) {
794 pads = 2;
795 }
796 // either way, we want to ignore this last block
797 imax -= 4;
798 }
799
800 var x = [];
801 for (i = 0; i < imax; i += 4) {
802 b10 = (getbyte64(s,i) << 18) | (getbyte64(s,i+1) << 12) |
803 (getbyte64(s,i+2) << 6) | getbyte64(s,i+3);
804 x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 0xff, b10 & 0xff));
805 }
806
807 switch (pads) {
808 case 1:
809 b10 = (getbyte64(s,i) << 18) | (getbyte64(s,i+1) << 12) | (getbyte64(s,i+2) << 6)
810 x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 0xff));
811 break;
812 case 2:
813 b10 = (getbyte64(s,i) << 18) | (getbyte64(s,i+1) << 12);
814 x.push(String.fromCharCode(b10 >> 16));
815 break;
816 }
817 return x.join('');
818 }
819
820 base64.getbyte = function(s,i) {
821 var x = s.charCodeAt(i);
822 if (x > 255) {
823 throw "INVALID_CHARACTER_ERR: DOM Exception 5";
824 }
825 return x;
826 }
827
828
829 base64.encode = function(s) {
830 if (arguments.length != 1) {
831 throw "SyntaxError: Not enough arguments";
832 }
833 var padchar = base64.PADCHAR;
834 var alpha = base64.ALPHA;
835 var getbyte = base64.getbyte;
836
837 var i, b10;
838 var x = [];
839
840 // convert to string
841 s = "" + s;
842
843 var imax = s.length - s.length % 3;
844
845 if (s.length == 0) {
846 return s;
847 }
848 for (i = 0; i < imax; i += 3) {
849 b10 = (getbyte(s,i) << 16) | (getbyte(s,i+1) << 8) | getbyte(s,i+2);
850 x.push(alpha.charAt(b10 >> 18));
851 x.push(alpha.charAt((b10 >> 12) & 0x3F));
852 x.push(alpha.charAt((b10 >> 6) & 0x3f));
853 x.push(alpha.charAt(b10 & 0x3f));
854 }
855 switch (s.length - imax) {
856 case 1:
857 b10 = getbyte(s,i) << 16;
858 x.push(alpha.charAt(b10 >> 18) + alpha.charAt((b10 >> 12) & 0x3F) +
859 padchar + padchar);
860 break;
861 case 2:
862 b10 = (getbyte(s,i) << 16) | (getbyte(s,i+1) << 8);
863 x.push(alpha.charAt(b10 >> 18) + alpha.charAt((b10 >> 12) & 0x3F) +
864 alpha.charAt((b10 >> 6) & 0x3f) + padchar);
865 break;
866 }
867 return x.join('');
868 }
869
870
871
872 function getLastCommit()
873 {
874 var urlHead = '';
875 if(sessionStarted){ urlHead = "https://api.github.com/repos/"+userName+"/"+githubRepo+"/git/refs/heads/"+branchName;}
876 else{
877 // TODO: get url of the original repo.
878 return;
879 }
880
881 $.ajax({
882 beforeSend: function (xhr) {
883 if (userB64 != ""){ xhr.setRequestHeader ("Authorization", userB64); }
884 },
885 type: "GET",
886 url: urlHead,
887 dataType:"json",
888 async: false,
889 success: function(success)
890 {
891 shaLastCommit = success.object.sha;
892 }
893 });
894 }
895
896 function getBaseTree()
897 {
898 $.ajax({
899 beforeSend: function (xhr) {
900 if (userB64 != ""){ xhr.setRequestHeader ("Authorization", userB64); }
901 },
902 type: "GET",
903 url: "https://api.github.com/repos/"+userName+"/"+githubRepo+"/git/commits/" + shaLastCommit,
904 dataType:"json",
905 async: false,
906 success: function(success)
907 {
908 shaBaseTree = success.tree.sha;
909 if (state){ setBlob(); }
910 else{ return; }
911 },
912 error: function(){
913 return;
914 }
915 });
916 }
917
918 function setNewTree()
919 {
920 $.ajax({
921 beforeSend: function (xhr) { xhr.setRequestHeader ("Authorization", userB64); },
922 type: "POST",
923 url: "https://api.github.com/repos/"+userName+"/"+githubRepo+"/git/trees",
924 async: false,
925 data:'{ "base_tree" : "'+shaBaseTree+'", '+
926 '"tree":[{ '+
927 '"path":"'+ pathFile +'",'+
928 '"mode":"100644",'+
929 '"type":"blob",'+
930 '"sha": "'+ shaBlob +'"'+
931 '}] '+
932 '}',
933 success: function(success)
934 { // si l'appel a bien fonctionné
935 shaNewTree = JSON.parse(success).sha;
936 setNewCommit();
937 },
938 error: function(){
939 return;
940 }
941 });
942 }
943
944 function setNewCommit()
945 {
946 $.ajax({
947 beforeSend: function (xhr) { xhr.setRequestHeader ("Authorization", userB64); },
948 type: "POST",
949 url: "https://api.github.com/repos/"+userName+"/"+githubRepo+"/git/commits",
950 async: false,
951 data:'{ "message" : "'+ commitMessage +'", '+
952 '"parents" :"'+shaLastCommit+'",'+
953 '"tree": "'+shaNewTree+'"'+
954 '}',
955 success: function(success)
956 {
957 shaNewCommit = JSON.parse(success).sha;
958 commit();
959 },
960 error: function(){
961 return;
962 }
963 });
964 }
965
966 //Create a commit
967 function commit()
968 {
969 $.ajax({
970 beforeSend: function (xhr) { xhr.setRequestHeader ("Authorization", userB64); },
971 type: "POST",
972 url: "https://api.github.com/repos/"+userName+"/"+githubRepo+"/git/refs/heads/"+branchName,
973 data:'{ "sha" : "'+shaNewCommit+'", '+
974 '"force" :"true"'+
975 '}',
976 success: function(success) { displayMessage('Commit created successfully', 40, 40); },
977 error:function(error){ displayMessage('Error ' + JSON.parse(error).object.message, 40, 40); }
978 });
979 }
980
981 // Create a blob
982 function setBlob()
983 {
984 $.ajax({
985 beforeSend: function (xhr) { xhr.setRequestHeader ("Authorization", userB64); },
986 type: "POST",
987 url: "https://api.github.com/repos/"+userName+"/"+githubRepo+"/git/blobs",
988 async: false,
989 data:'{ "content" : "'+text.replace(/\r?\n/g, '\\n').replace(/\t/g, '\\t').replace(/\"/g,'\\"')+'", '+
990 '"encoding" :"utf-8"'+
991 '}',
992 success: function(success)
993 {
994 shaBlob = JSON.parse(success).sha;
995 setNewTree();
996 },
997 error:function(error){
998 displayMessage('Error : Problem parsing JSON', 40, 40);
999 return;
1000 }
1001 });
1002 }
1003
1004 // Display file content
1005 function getFileContent(urlFile, newComment)
1006 {
1007 $.ajax({
1008 beforeSend: function (xhr) {
1009 xhr.setRequestHeader ("Accept", "application/vnd.github-blob.raw");
1010 if (userB64 != ""){ xhr.setRequestHeader ("Authorization", userB64); }
1011 },
1012 type: "GET",
1013 url: urlFile,
1014 async:false,
1015 success: function(success)
1016 {
1017 state = true;
1018 replaceComment(newComment, success);
1019 }
1020 });
1021 }
1022
1023 function replaceComment(newComment, fileContent){
1024 var arrayNew = newComment.split('\n');
1025 var lNew = arrayNew.length;
1026 text = "";
1027 var lines = fileContent.split("\n");
1028 for (var i = 0; i < lines.length; i++) {
1029 if(i == commentLineStart){
1030 // We change the comment
1031 for(var j = 0; j < lNew; j++){
1032 if(commentType == 1){ text += "\t# " + arrayNew[j] + "\n"; }
1033 else{
1034 if(arrayNew[j] == ""){ text += "#"+"\n"; }
1035 else{ text += "# " + arrayNew[j] + "\n"; }
1036 }
1037 }
1038 }
1039 else if(i < commentLineStart || i >= commentLineEnd){
1040 if(i == lines.length-1){ text += lines[i]; }
1041 else{ text += lines[i] + "\n"; }
1042 }
1043 }
1044 }
1045
1046 function getCommentLastCommit(path){
1047 var urlRaw;
1048 getLastCommit();
1049 if(shaLastCommit != ""){
1050 if (checkCookie()) { urlRaw="https://rawgithub.com/"+ userName +"/"+ repoName +"/" + shaLastCommit + "/" + path; }
1051 else{ urlRaw="https://rawgithub.com/StefanLage/"+ $('#repoName').attr('name') +"/" + shaLastCommit + "/" + path; }
1052
1053 $.ajax({
1054 type: "GET",
1055 url: urlRaw,
1056 async: false,
1057 success: function(success)
1058 {
1059 currentfileContent = success;
1060 }
1061 });
1062 }
1063 }
1064
1065 function displayMessage(msg, widthDiv, margModal){
1066 spinner.stop();
1067 $('#modal').hide();
1068 $('#btnCreateBranch').css('margin-left',widthDiv + '%');
1069 $('#txtQuestion').text(msg);
1070 $('#btnCreateBranch').text("Ok");
1071 $('#btnCancelBranch').hide();
1072 $('#modalQuestion').css({'left' : margModal + '%'})
1073 $('#modalQuestion').show();
1074 $('#modalQuestion').show().prepend('<a class="close"><img src="resources/icons/close.png" class="btnCloseQuestion" title="Close" alt="Close" /></a>');
1075 $('body').append('<div id="fade"></div>');
1076 $('#fade').css({'filter' : 'alpha(opacity=80)'}).fadeIn();
1077 }
1078
1079 function displaySpinner(){
1080 spinner.spin(targetSpinner);
1081 $("#waitCommit").show();
1082 }
1083
1084 // Check if the repo already exist
1085 function isRepoExisting(){
1086 $.ajax({
1087 beforeSend: function (xhr) {
1088 if (userB64 != "") { xhr.setRequestHeader ("Authorization", userB64); }
1089 },
1090 type: "GET",
1091 url: "https://api.github.com/repos/"+userName+"/"+githubRepo,
1092 async:false,
1093 dataType:'json',
1094 success: function(){ repoExist = true; },
1095 error: function()
1096 {
1097 displayMessage('Repo not found !', 35, 45);
1098 repoExist = false;
1099 }
1100 });
1101 }
1102
1103 // Check if the branch already exist
1104 function isBranchExisting(){
1105 $.ajax({
1106 beforeSend: function (xhr) {
1107 if (userB64 != "") { xhr.setRequestHeader ("Authorization", userB64); }
1108 },
1109 type: "GET",
1110 url: "https://api.github.com/repos/"+userName+"/"+githubRepo+"/git/refs/heads/"+branchName,
1111 async:false,
1112 dataType:'json',
1113 success: function(){ branchExist = true; },
1114 error: function()
1115 {
1116 branchExist = false;
1117 editComment -= 1;
1118 $('#modal').hide();
1119 $('#txtQuestion').text("Are you sure you want to create that branch ?");
1120 $('#btnCancelBranch').show();
1121 $('#btnCreateBranch').text("Yes");
1122 $('#modalQuestion').show();
1123 $('#modalQuestion').show().prepend('<a class="close"><img src="resources/icons/close.png" class="btnCloseQuestion" title="Close" alt="Close" /></a>');
1124 $('body').append('<div id="fade"></div>');
1125 $('#fade').css({'filter' : 'alpha(opacity=80)'}).fadeIn();
1126 }
1127 });
1128 }
1129
1130 function getMasterSha()
1131 {
1132 $.ajax({
1133 beforeSend: function (xhr) {
1134 if (userB64 != ""){ xhr.setRequestHeader ("Authorization", userB64); }
1135 },
1136 type: "GET",
1137 url: "https://api.github.com/repos/"+userName+"/"+githubRepo+"/git/refs/heads/master",
1138 dataType:"json",
1139 async: false,
1140 success: function(success) { shaMaster = success.object.sha; }
1141 });
1142 }
1143
1144 function createBranch(){
1145
1146 getMasterSha();
1147
1148 $.ajax({
1149 beforeSend: function (xhr) { xhr.setRequestHeader ("Authorization", userB64); },
1150 type: "POST",
1151 url: "https://api.github.com/repos/"+userName+"/"+githubRepo+"/git/refs",
1152 data:'{ "ref" : "refs/heads/'+branchName+'",'+
1153 '"sha" : "'+shaMaster+'"'+
1154 '}',
1155 success: function(){ return; },
1156 error: function(){
1157 editComment -= 1;
1158 displayMessage('Impossible to create the new branch : ' + branchName, 40, 40);
1159 }
1160 });
1161 }
1162
1163 $.fn.spin = function(opts) {
1164 this.each(function() {
1165 var $this = $(this),
1166 data = $this.data();
1167
1168 if (data.spinner) {
1169 data.spinner.stop();
1170 delete data.spinner;
1171 }
1172 if (opts !== false) {
1173 data.spinner = new Spinner($.extend({color: $this.css('color')}, opts)).spin(this);
1174 }
1175 });
1176 return this;
1177 };
1178
1179 function reloadComment(){
1180 $.when(getCommentLastCommit($('pre[class=text_label]').attr('tag'))).done(function(){
1181 $('pre[class=text_label]').each(function(){ getCommentOfFunction($(this)); });
1182 });
1183 }
1184
1185 function getCommentOfFunction(element){
1186 var textC = "";
1187 var numL = element.attr("title");
1188 if(numL != null){
1189 commentLineStart = numL.split('-')[0] - 1;
1190 commentLineEnd = (commentLineStart + element.text().split('\n').length) - 1;
1191 var lines = currentfileContent.split("\n");
1192 for (var i = 0; i < lines.length; i++) {
1193 if(i >= commentLineStart-1 && i <= commentLineEnd){
1194 if (lines[i].substr(1,1) == "#"){ textC += lines[i].substr(3,lines[i].length) + "\n";}
1195 else if(lines[i].substr(0,1) == '#'){ textC += lines[i].substr(2,lines[i].length) + "\n"; }
1196 }
1197 }
1198 if (textC != ""){ element.text(textC); }
1199 }
1200 }