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