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