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