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