nitdoc: refactor Nitdoc.GitHub JS module into github/* plugin
authorAlexandre Terrasa <alexandre@moz-code.org>
Wed, 12 Feb 2014 00:18:21 +0000 (19:18 -0500)
committerAlexandre Terrasa <alexandre@moz-code.org>
Thu, 20 Feb 2014 19:11:58 +0000 (14:11 -0500)
Signed-off-by: Alexandre Terrasa <alexandre@moz-code.org>

share/nitdoc/js/nitdoc.js
share/nitdoc/js/plugins/github.js [new file with mode: 0644]
share/nitdoc/js/plugins/github/commentbox.js [new file with mode: 0644]
share/nitdoc/js/plugins/github/commitbox.js [new file with mode: 0644]
share/nitdoc/js/plugins/github/github_api.js [new file with mode: 0644]
share/nitdoc/js/plugins/github/loginbox.js [new file with mode: 0644]
share/nitdoc/js/plugins/github/modalbox.js [new file with mode: 0644]
share/nitdoc/js/plugins/github/ui.js [new file with mode: 0644]
share/nitdoc/js/plugins/github/user.js [new file with mode: 0644]
share/nitdoc/js/plugins/github/utils.js [new file with mode: 0644]
share/nitdoc/scripts/Nitdoc.GitHub.js [deleted file]

index dde4546..0bc61a7 100644 (file)
@@ -14,5 +14,6 @@ require.config({
 define([
        "plugins/ui",
        "plugins/quicksearch",
+       "plugins/github",
 ], function() {});
 
diff --git a/share/nitdoc/js/plugins/github.js b/share/nitdoc/js/plugins/github.js
new file mode 100644 (file)
index 0000000..c1fe5d6
--- /dev/null
@@ -0,0 +1,67 @@
+/* This file is part of NIT ( http://www.nitlanguage.org ).\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+   http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+   Documentation generator for the nit language.\r
+   Generate API documentation in HTML format from nit source code.\r
+*/\r
+\r
+/*\r
+ * Nitdoc.Github comment edition module\r
+ *\r
+ * Allows user to modify source code comments directly from the Nitdoc\r
+ */\r
+define([\r
+       "jquery",\r
+       "base64",\r
+       "plugins/github/ui",\r
+       "plugins/github/loginbox",\r
+], function($, Base64, UI, LoginBox) {\r
+       // Load GitHub UI\r
+       var upstream = $("body").attr("data-github-upstream");\r
+       var basesha1 = $("body").attr("data-github-base-sha1");\r
+       if(upstream && basesha1) {\r
+               console.log("init GitHub module (upstream: "+ upstream +", base: " + basesha1 + ")");\r
+\r
+               // parse origin\r
+               var parts = upstream.split(":");\r
+               UI.origin = {\r
+                       user: parts[0],\r
+                       repo: parts[1],\r
+                       branch: parts[2],\r
+                       sha: basesha1\r
+               };\r
+\r
+               // check local session\r
+               if(localStorage.user) {\r
+\r
+                       var session = JSON.parse(localStorage.user);\r
+                       UI.user = UI.tryLogin(session.login, Base64.decode(session.password), session.repo, session.branch);\r
+                       if(!UI.user.login) {\r
+                               console.log("Session found but authentification failed");\r
+                               localStorage.clear();\r
+                       }\r
+\r
+                       // activate ui\r
+                       LoginBox.init("nav.main ul");\r
+                       if(UI.user && UI.user.login) {\r
+                               LoginBox.displayLogout(UI.origin, UI.user);\r
+                               UI.activate(UI.user);\r
+                       } else {\r
+                               LoginBox.displayLogin();\r
+                       }\r
+               } else {\r
+                       console.log("No session found");\r
+               }\r
+       }\r
+});\r
diff --git a/share/nitdoc/js/plugins/github/commentbox.js b/share/nitdoc/js/plugins/github/commentbox.js
new file mode 100644 (file)
index 0000000..58707df
--- /dev/null
@@ -0,0 +1,121 @@
+/* This file is part of NIT ( http://www.nitlanguage.org ).\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+   http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+   Documentation generator for the nit language.\r
+   Generate API documentation in HTML format from nit source code.\r
+*/\r
+\r
+/*\r
+ * Nitdoc.GitHub.CommentBox class\r
+ */\r
+define([\r
+       "jquery",\r
+       "base64",\r
+       "Markdown.Converter",\r
+       "plugins/github/ui",\r
+       "plugins/github/commitbox",\r
+], function($, Base64, mkdown, UI, CommitBox) {\r
+\r
+       // Init new modal box instance\r
+       var CommentBox = function(infos) {\r
+               this.infos = infos;\r
+               this.commentBoxDiv;\r
+       };\r
+\r
+       CommentBox.prototype.open = function(baseArea) {\r
+               //TODO redo\r
+               //UI.addOpenedComments();\r
+               var instance = this;\r
+\r
+               if(this.infos.requestID) {\r
+                       // get comment from last pull request\r
+                       var requests = JSON.parse(localStorage.requests);\r
+                       this.infos.newComment = Base64.decode(requests[this.infos.requestID].comment);\r
+               } else {\r
+                       this.infos.newComment = false;\r
+               }\r
+\r
+               // create comment box\r
+               var tarea = $(document.createElement("textarea"))\r
+               .append(this.infos.newComment === false? this.infos.oldComment: this.infos.newComment)\r
+               .keyup(function(event) {\r
+                       $(event.target).css("height", (event.target.value.split(/\r|\n/).length * 16) + "px");\r
+                       if ( (!instance.infos.requestID && $(event.target).val() != instance.infos.oldComment) || (instance.infos.requestID && $(event.target).val() != instance.infos.oldComment && $(event.target).val() != instance.infos.newComment) ) {\r
+                               $(event.target).parent().find("button.nitdoc-github-commit").removeAttr("disabled");\r
+                       } else {\r
+                               $(event.target).parent().find("button.nitdoc-github-commit").attr("disabled", "disabled");\r
+                       }\r
+               })\r
+               .keydown(function(event) {\r
+                       if(event.keyCode == 13){\r
+                               $(event.target).css("height", ($(event.target).outerHeight() + 6) + "px");\r
+                       }\r
+               });\r
+\r
+               this.commentBoxDiv = $(document.createElement("div"))\r
+               .addClass("nitdoc-github-commentbox")\r
+               .append(tarea)\r
+               .append(\r
+                       $(document.createElement("a"))\r
+                       .addClass("nitdoc-github-preview")\r
+                       .click(function() {\r
+                               var converter = new Markdown.Converter()\r
+                               var html = converter.makeHtml(tarea.val());\r
+                               ModalBox.open("Preview", html, false);\r
+                       })\r
+               )\r
+               .append(\r
+                       $(document.createElement("button"))\r
+                       .addClass("nitdoc-github-button")\r
+                       .addClass("nitdoc-github-commit")\r
+                       .append("Commit")\r
+                       .click(function() {\r
+                               instance.infos.newComment = tarea.val();\r
+                               instance.infos.commentBox = instance;\r
+                               CommitBox.open(instance.infos);\r
+                       })\r
+               )\r
+               .append(\r
+                       $(document.createElement("button"))\r
+                       .addClass("nitdoc-github-button")\r
+                       .addClass("nitdoc-github-cancel")\r
+                       .append("Cancel")\r
+                       .click(function() {instance.close()})\r
+               );\r
+\r
+               baseArea.after(this.commentBoxDiv);\r
+               var cbWidth = this.commentBoxDiv.innerWidth();\r
+               var taWidth = tarea.outerWidth();\r
+               tarea.width(cbWidth - (taWidth - cbWidth));\r
+               tarea.trigger("keyup");\r
+               tarea.focus();\r
+       };\r
+\r
+       CommentBox.prototype.close = function() {\r
+               //TODO redo\r
+               //UI.remOpenedComments();\r
+               if(this.infos.isNew) {\r
+                       this.commentBoxDiv.next().find("span.nitdoc-github-editComment").show();\r
+               } else if(this.infos.requestID) {\r
+                       this.commentBoxDiv.next().show();\r
+                       this.commentBoxDiv.next().next().show();\r
+               } else {\r
+                       this.commentBoxDiv.next().show();\r
+                       this.commentBoxDiv.next().next().find("span.nitdoc-github-editComment").show();\r
+               }\r
+               this.commentBoxDiv.remove();\r
+       };\r
+\r
+       return CommentBox;\r
+});\r
diff --git a/share/nitdoc/js/plugins/github/commitbox.js b/share/nitdoc/js/plugins/github/commitbox.js
new file mode 100644 (file)
index 0000000..5bb31db
--- /dev/null
@@ -0,0 +1,126 @@
+/* This file is part of NIT ( http://www.nitlanguage.org ).\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+   http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+   Documentation generator for the nit language.\r
+   Generate API documentation in HTML format from nit source code.\r
+*/\r
+\r
+/*\r
+ * Nitdoc.GitHub.CommitBox instance\r
+ */\r
+define([\r
+       "jquery",\r
+       "plugins/github/ui",\r
+], function($, UI) {\r
+console.log(UI);\r
+       // Init new commit box instance\r
+       var CommitBox = {\r
+               \r
+               // Open commit box instance\r
+               open: function(infos) {\r
+                       $("body").append(\r
+                               $(document.createElement("div"))\r
+                               .attr("id", "nitdoc-github-commitBox-fade")\r
+                               .addClass("nitdoc-github-fade")\r
+                       );\r
+                       $("body").append(\r
+                               $(document.createElement("div"))\r
+                               .attr("id", "nitdoc-github-commitBox")\r
+                               .addClass("nitdoc-github-modal")\r
+                               .append(\r
+                                       $(document.createElement("a"))\r
+                                       .addClass("nitdoc-github-close")\r
+                                       .attr("title", "Close")\r
+                                       .append("x")\r
+                                       .click(function() { CommitBox.close() })\r
+                               )\r
+                               .append("<h3>Commit changes</h3>")\r
+                               .append(\r
+                                       $(document.createElement("div"))\r
+                                       .append(\r
+                                               $(document.createElement("label"))\r
+                                               .attr("for", "nitdoc-github-commit-message")\r
+                                       )\r
+                                       .append("<br/>")\r
+                                       .append(\r
+                                               $(document.createElement("textarea"))\r
+                                               .attr("id", "nitdoc-github-commit-message")\r
+                                               .append("doc: " + (infos.isNew ? "added" : "modified") + " comment for " + infos.namespace)\r
+                                       )\r
+                                       .append("<br/>")\r
+                                       .append(\r
+                                               $(document.createElement("input"))\r
+                                               .attr({\r
+                                                       id: "nitdoc-github-commit-signedoff",\r
+                                                       type: "checkbox",\r
+                                                       value: "Signed-off-by: " + infos.user.signedOff\r
+                                               })\r
+                                               .change(function(e) {\r
+                                                       if ($(this).is(':checked')) {\r
+                                                               $("#nitdoc-github-commit-button").removeAttr("disabled");\r
+                                                       } else {\r
+                                                               $("#nitdoc-github-commit-button").attr("disabled", "disabled");\r
+                                                       }\r
+                                               })\r
+                                       )\r
+                                       .append(\r
+                                               $(document.createElement("label"))\r
+                                               .attr("for", "nitdoc-github-commit-signedoff")\r
+                                               .text("Signed-off-by: " + infos.user.signedOff)\r
+                                       )\r
+                               ).append(\r
+                                       $(document.createElement("div"))\r
+                                       .addClass("nitdoc-github-buttons")\r
+                                       .append(\r
+                                               $(document.createElement("button"))\r
+                                               .attr({\r
+                                                       id: "nitdoc-github-commit-button",\r
+                                                       disabled: "disabled"\r
+                                               })\r
+                                               .addClass("nitdoc-github-button")\r
+                                               .append(\r
+                                                       $(document.createElement("img"))\r
+                                                       .attr("src", "resources/icons/github-icon.png")\r
+                                               )\r
+                                               .append("Commit")\r
+                                               .mousedown(function() {\r
+                                                       $(this).text("Commiting...");\r
+                                               })\r
+                                               .mouseup(function() {\r
+                                                       infos.message = $("#nitdoc-github-commit-message").val() + "\n\n" + infos.user.signedOff;\r
+                                                       UI.saveChanges(infos);\r
+                                               })\r
+                                       )\r
+                               )\r
+                       );\r
+\r
+                       $("#nitdoc-github-commitBox")\r
+                       .css({\r
+                               top: "50%",\r
+                               marginTop: -($("#nitdoc-github-commitBox").outerHeight() / 2) + "px",\r
+                               left: "50%",\r
+                               marginLeft: -($("#nitdoc-github-commitBox").outerWidth() / 2) + "px"\r
+                       })\r
+                       .find("#nitdoc-github-commit-message").focus();\r
+               },\r
+\r
+               // Close commit box instance\r
+               close: function() {\r
+                       $("#nitdoc-github-commitBox").remove();\r
+                       $("#nitdoc-github-commitBox-fade").remove();\r
+               }\r
+       }\r
+\r
+       return CommitBox;\r
+});\r
diff --git a/share/nitdoc/js/plugins/github/github_api.js b/share/nitdoc/js/plugins/github/github_api.js
new file mode 100644 (file)
index 0000000..d83d4bf
--- /dev/null
@@ -0,0 +1,295 @@
+/* This file is part of NIT ( http://www.nitlanguage.org ).\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+   http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+   Documentation generator for the nit language.\r
+   Generate API documentation in HTML format from nit source code.\r
+*/\r
+\r
+/* \r
+ * GitHub API wrapper for github plugin\r
+ */\r
+define([\r
+       "jquery",\r
+       "base64"\r
+], function($, Base64) {\r
+       return {\r
+\r
+               // try to login the user to github API\r
+               login: function(user) {\r
+                       var res = false;\r
+                       $.ajax({\r
+                               beforeSend: function (xhr) {\r
+                                       xhr.setRequestHeader ("Authorization", user.auth);\r
+                               },\r
+                               type: "GET",\r
+                               url: "https://api.github.com/repos/" + user.login + "/" + user.repo,\r
+                               async: false,\r
+                               dataType: 'json',\r
+                               success: function() {\r
+                                       res = true;\r
+                               }\r
+                       });\r
+                       user.infos = this.getUserInfos(user);\r
+                       user.signedOff = this.getSignedOff(user)\r
+                       return res;\r
+               },\r
+\r
+               // request for user github account infos\r
+               getUserInfos: function(user) {\r
+                       var res = false;\r
+                       $.ajax({\r
+                               beforeSend: function (xhr) {\r
+                                       xhr.setRequestHeader ("Authorization", user.auth);\r
+                               },\r
+                               type: "GET",\r
+                                       url: "https://api.github.com/users/" + user.login,\r
+                               async: false,\r
+                               dataType: 'json',\r
+                               success: function(response) {\r
+                                       res = response;\r
+                               },\r
+                               error: function(response) {\r
+                                       res = response;\r
+                               }\r
+                       });\r
+                       return res;\r
+               },\r
+\r
+               // build signedoff user default signature\r
+               getSignedOff: function(user) {\r
+                       return user.infos.name + " <" + user.infos.email + ">";\r
+               },\r
+\r
+               // get the branches list from a repo\r
+               getBranches: function(user) {\r
+                       var res = false;\r
+                       $.ajax({\r
+                               beforeSend: function (xhr) {\r
+                                       xhr.setRequestHeader ("Authorization", user.auth);\r
+                               },\r
+                               type: "GET",\r
+                               url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/branches",\r
+                               async: false,\r
+                               dataType: 'json',\r
+                               success: function(response) {\r
+                                       res = response;\r
+                               },\r
+                               error: function(response) {\r
+                                       res = response;\r
+                               }\r
+                       });\r
+                       return res;\r
+               },\r
+\r
+               /* GitHub commits */\r
+\r
+               // get the latest commit on `branchName`\r
+               getCommit: function(user, sha) {\r
+                       var res = false;\r
+                       $.ajax({\r
+                               beforeSend: function (xhr) {\r
+                                       xhr.setRequestHeader ("Authorization", user.auth);\r
+                               },\r
+                               type: "GET",\r
+                               url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/git/commits/" + sha,\r
+                               async: false,\r
+                               dataType: 'json',\r
+                               success: function(response) {\r
+                                       res = response;\r
+                               },\r
+                               error: function(response) {\r
+                                       res = response;\r
+                               }\r
+                       });\r
+                       return res;\r
+               },\r
+\r
+               // get the base tree for a commit sha\r
+               getTree: function(user, sha) {\r
+                       var res = false;\r
+                       $.ajax({\r
+                               beforeSend: function (xhr) {\r
+                                       xhr.setRequestHeader ("Authorization", user.auth);\r
+                               },\r
+                               type: "GET",\r
+                               url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/git/trees/" + sha + "?recursive=1",\r
+                               async: false,\r
+                               dataType: 'json',\r
+                               success: function(response) {\r
+                                       res = response;\r
+                               },\r
+                               error: function(response) {\r
+                                       res = response;\r
+                               }\r
+                       });\r
+                       return res;\r
+               },\r
+\r
+               // create a new blob\r
+               createBlob: function(user, content) {\r
+                       var res = false;\r
+                       $.ajax({\r
+                               beforeSend: function (xhr) {\r
+                                       xhr.setRequestHeader ("Authorization", user.auth);\r
+                               },\r
+                               type: "POST",\r
+                               url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/git/blobs",\r
+                               async: false,\r
+                               dataType: 'json',\r
+                               data: JSON.stringify({\r
+                                       content: Base64.encode(content),\r
+                                       encoding: "base64"\r
+                               }),\r
+                               success: function(response) {\r
+                                       res = response;\r
+                               },\r
+                               error: function(response) {\r
+                                       res = response;\r
+                               }\r
+                       });\r
+                       return res;\r
+               },\r
+\r
+               // create a new tree from a base tree\r
+               createTree: function(user, baseTree, path, blob) {\r
+                       var res = false;\r
+                       $.ajax({\r
+                               beforeSend: function (xhr) {\r
+                                       xhr.setRequestHeader ("Authorization", user.auth);\r
+                               },\r
+                               type: "POST",\r
+                               url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/git/trees",\r
+                               data: JSON.stringify({\r
+                                       base_tree: baseTree.sha,\r
+                                       tree: [{\r
+                                               path: path,\r
+                                               mode: "100644", // file (blob)\r
+                                               type: "blob",\r
+                                               sha: blob.sha\r
+                                       }]\r
+                               }),\r
+                               async: false,\r
+                               dataType: 'json',\r
+                               success: function(response) {\r
+                                       res = response;\r
+                               },\r
+                               error: function(response) {\r
+                                       res = response;\r
+                               }\r
+                       });\r
+                       return res;\r
+               },\r
+\r
+               // create a new commit\r
+               createCommit: function(user, message, parentCommit, tree) {\r
+                       var res = false;\r
+                       $.ajax({\r
+                               beforeSend: function (xhr) {\r
+                                       xhr.setRequestHeader ("Authorization", user.auth);\r
+                               },\r
+                               type: "POST",\r
+                               url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/git/commits",\r
+                               data: JSON.stringify({\r
+                                       message: message,\r
+                                       parents: parentCommit,\r
+                                       tree: tree.sha,\r
+                               }),\r
+                               async: false,\r
+                               dataType: 'json',\r
+                               success: function(response) {\r
+                                       res = response;\r
+                               },\r
+                               error: function(response) {\r
+                                       res = response;\r
+                               }\r
+                       });\r
+                       return res;\r
+               },\r
+\r
+               // create a pull request\r
+               createPullRequest: function(user, title, body, origin, head) {\r
+                       var res = false;\r
+                       $.ajax({\r
+                               beforeSend: function (xhr) {\r
+                                       xhr.setRequestHeader ("Authorization", user.auth);\r
+                               },\r
+                               type: "POST",\r
+                               url: "https://api.github.com/repos/" + origin.user + "/" + origin.repo + "/pulls",\r
+                               data: JSON.stringify({\r
+                                       title: title,\r
+                                       body: body,\r
+                                       base: origin.branch,\r
+                                       head: user.login + ":" + head\r
+                               }),\r
+                               async: false,\r
+                               dataType: 'json',\r
+                               success: function(response) {\r
+                                       res = response;\r
+                               },\r
+                               error: function(response) {\r
+                                       res = response;\r
+                               }\r
+                       });\r
+                       return res;\r
+               },\r
+\r
+               // update a pull request\r
+               updatePullRequest: function(user, title, body, state, request) {\r
+                       var res = false;\r
+                               $.ajax({\r
+                               beforeSend: function (xhr) {\r
+                                               xhr.setRequestHeader ("Authorization", user.auth);\r
+                               },\r
+                               type: "PATCH",\r
+                               url: request.url,\r
+                               data: JSON.stringify({\r
+                                       title: title,\r
+                                       body: body,\r
+                                       state: state\r
+                               }),\r
+                               async: false,\r
+                               dataType: 'json',\r
+                               success: function(response) {\r
+                                       res = response;\r
+                               },\r
+                               error: function(response) {\r
+                                       res = response;\r
+                               }\r
+                       });\r
+                       return res;\r
+               },\r
+\r
+               /* Files */\r
+\r
+               getFile: function(user, path, branch) {\r
+                       var res = false;\r
+                       $.ajax({\r
+                               type: "GET",\r
+                               url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/contents/" + path,\r
+                               data: {\r
+                                       ref: branch\r
+                               },\r
+                               async: false,\r
+                               dataType: 'json',\r
+                               success: function(response) {\r
+                                       res = response;\r
+                               },\r
+                               error: function(response) {\r
+                                       res = response;\r
+                               }\r
+                       });\r
+                       return res;\r
+               }\r
+       }\r
+});\r
diff --git a/share/nitdoc/js/plugins/github/loginbox.js b/share/nitdoc/js/plugins/github/loginbox.js
new file mode 100644 (file)
index 0000000..9a3c42b
--- /dev/null
@@ -0,0 +1,215 @@
+/* This file is part of NIT ( http://www.nitlanguage.org ).\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+   http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+   Documentation generator for the nit language.\r
+   Generate API documentation in HTML format from nit source code.\r
+*/\r
+\r
+define([\r
+       "jquery",\r
+       "plugins/github/ui",\r
+       "plugins/github/modalbox",\r
+], function($, UI, ModalBox) {\r
+       var LoginBox = {\r
+               init: function(containerSelector) {\r
+                       this.loginBoxLi = $(document.createElement("li"))\r
+                       .attr("id", "nitdoc-github-li")\r
+                       .append(\r
+                               $(document.createElement("a"))\r
+                               .append(\r
+                                       $(document.createElement("img"))\r
+                                       .attr({\r
+                                               src: "resources/icons/github-icon.png",\r
+                                               alt: "GitHub"\r
+                                       })\r
+                                       .addClass("nitdoc-github-li-img")\r
+                               )\r
+                               .click(function() { LoginBox.toggle() })\r
+                       )\r
+\r
+                       this.loginBoxContent = $(document.createElement("div"));\r
+                       this.loginBox = $(document.createElement("div"))\r
+                       .attr("id", "nitdoc-github-loginbox")\r
+                       .css("display", "none")\r
+                       .append(\r
+                               $(document.createElement("div"))\r
+                               .addClass("nitdoc-github-loginbox-arrow")\r
+                               .append("&nbsp;")\r
+                       )\r
+                       .append(\r
+                               $(document.createElement("h3"))\r
+                               .append("Github Sign In")\r
+                       )\r
+                       .append(this.loginBoxContent);\r
+\r
+                       this.loginBoxLi.append(this.loginBox);\r
+                       $(containerSelector).append(this.loginBoxLi);\r
+               },\r
+\r
+               // Panel of login box to display when the user is logged in\r
+               displayLogout: function(origin, user) {\r
+                       var panel = $(document.createElement("div"))\r
+                       .append(\r
+                               $(document.createElement("h4"))\r
+                               .append("Hello ")\r
+                               .append(\r
+                                       $(document.createElement("a"))\r
+                                       .attr("href", "https://github.com/" + user.login)\r
+                                       .append(user.login)\r
+                               ).append("!")\r
+                       )\r
+                       .append(\r
+                               $(document.createElement("label"))\r
+                               .attr("for", "github-origin")\r
+                               .append("Origin")\r
+                       )\r
+                       .append(\r
+                               $(document.createElement("input"))\r
+                               .attr({\r
+                                       id: "github-origin",\r
+                                       type: "text",\r
+                                       disabled: "disabled",\r
+                                       value: origin.user + ":" + origin.repo + ":" + origin.branch\r
+                               })\r
+                       )\r
+                       .append(\r
+                               $(document.createElement("label"))\r
+                               .attr("for", "github-base")\r
+                               .append("Base")\r
+                       )\r
+                       .append(\r
+                               $(document.createElement("input"))\r
+                               .attr({\r
+                                       id: "github-base",\r
+                                       type: "text",\r
+                                       disabled: "disabled",\r
+                                       value: user.login + ":" + user.repo + ":" + user.branch\r
+                               })\r
+                       )\r
+                       .append(\r
+                               $(document.createElement("button"))\r
+                               .addClass("nitdoc-github-button")\r
+                               .addClass("nitdoc-github-cancel")\r
+                               .append(\r
+                                       $(document.createElement("img"))\r
+                                       .attr("src", "resources/icons/github-icon.png")\r
+                               ).append("Sign Off")\r
+                               .click(function() { // log out user\r
+                                       UI.disactivate();\r
+                                       LoginBox.toggle();\r
+                               })\r
+                       );\r
+                       $(".nitdoc-github-li-img").attr("src", "resources/icons/github-icon-green.png");\r
+                       this.loginBoxContent.empty()\r
+                       this.loginBoxContent.append(panel);\r
+               },\r
+\r
+               // Panel of login box to display when the user is logged out\r
+               displayLogin: function() {\r
+                       var panel = $(document.createElement("form"))\r
+                       .append(\r
+                               $(document.createElement("label"))\r
+                               .attr("for", "nitdoc-github-login-field")\r
+                               .append("Username")\r
+                       )\r
+                       .append(\r
+                               $(document.createElement("input"))\r
+                               .attr({\r
+                                       id: "nitdoc-github-login-field",\r
+                                       type: "text"\r
+                               })\r
+                       )\r
+                       .append(\r
+                               $(document.createElement("label"))\r
+                               .attr("for", "nitdoc-github-password-field")\r
+                               .append("Password")\r
+                       )\r
+                       .append(\r
+                               $(document.createElement("input"))\r
+                               .attr({\r
+                                       id: "nitdoc-github-password-field",\r
+                                       type: "password"\r
+                               })\r
+                       )\r
+                       .append(\r
+                               $(document.createElement("label"))\r
+                               .attr("for", "nitdoc-github-repo-field")\r
+                               .append("Repository")\r
+                       )\r
+                       .append(\r
+                               $(document.createElement("input"))\r
+                               .attr({\r
+                                       id: "nitdoc-github-repo-field",\r
+                                       type: "text"\r
+                               })\r
+                       )\r
+                       .append(\r
+                               $(document.createElement("label"))\r
+                               .attr("for", "nitdoc-github-branch-field")\r
+                               .append("Branch")\r
+                       )\r
+                       .append(\r
+                               $(document.createElement("input"))\r
+                               .attr({\r
+                                       id: "nitdoc-github-branch-field",\r
+                                       type: "text"\r
+                               })\r
+                       )\r
+                       .append(\r
+                               $(document.createElement("button"))\r
+                               .addClass("nitdoc-github-button")\r
+                               .append(\r
+                                       $(document.createElement("img"))\r
+                                       .attr("src", "resources/icons/github-icon.png")\r
+                               ).append("Sign In")\r
+                               .click(function() {\r
+                                       var login = $('#nitdoc-github-login-field').val();\r
+                                       var password = $('#nitdoc-github-password-field').val();\r
+                                       var repo = $('#nitdoc-github-repo-field').val();\r
+                                       var branch = $('#nitdoc-github-branch-field').val();\r
+                                       if(!login || !password || !repo || !branch) {\r
+                                               ModalBox.open("Sign in error", "Please enter your GitHub username, password, repository and branch.", true);\r
+                                       } else {\r
+                                               var user = UI.tryLogin(login, password, repo, branch);\r
+                                               if(user == "error:login") {\r
+                                                       ModalBox.open("Sign in error", "The username, password, repo or branch you entered is incorrect.", true);\r
+                                               } else if(user == "error:sha") {\r
+                                                       ModalBox.open("Base commit not found", "The provided GitHub repository must contains the base commit '" + UI.origin.sha + "'", true);\r
+                                               } else if(user == "error:profile") {\r
+                                                       ModalBox.open("Incomplete GitHub profile", "Please set your public name and email in your <a href='https://github.com/settings/profile'>GitHub profile</a>.<br/><br/>Your public profile informations are used to sign-off your commits.", true);\r
+                                               } else {\r
+                                                       UI.activate(user);\r
+                                                       LoginBox.displayLogout(UI.origin, user);\r
+                                               }\r
+                                       }\r
+                                       return false;\r
+                               })\r
+                       )\r
+                       $(".nitdoc-github-li-img").attr("src", "resources/icons/github-icon.png");\r
+                       this.loginBoxContent.empty()\r
+                       this.loginBoxContent.append(panel);\r
+               },\r
+\r
+               toggle: function() {\r
+                       if(this.loginBox.is(':hidden')) {\r
+                               this.loginBox.show();\r
+                               if (!$('#loginGit').is(':hidden')) { $('#loginGit').focus(); }\r
+                       } else {\r
+                               this.loginBox.hide();\r
+                       }\r
+               }\r
+       };\r
+\r
+       return LoginBox;\r
+});\r
diff --git a/share/nitdoc/js/plugins/github/modalbox.js b/share/nitdoc/js/plugins/github/modalbox.js
new file mode 100644 (file)
index 0000000..6070a3e
--- /dev/null
@@ -0,0 +1,82 @@
+/* This file is part of NIT ( http://www.nitlanguage.org ).\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+   http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+   Documentation generator for the nit language.\r
+   Generate API documentation in HTML format from nit source code.\r
+*/\r
+\r
+/*\r
+ * Nitdoc.GitHub.ModalBox class\r
+ */\r
+define([\r
+       "jquery",\r
+], function($) {\r
+       // Init new modal box instance\r
+       //TODO use DJQuery.UI Dialog: https://jqueryui.com/dialog/#modal-message\r
+       var ModalBox = {\r
+\r
+               // Open modal box instance\r
+               open: function(title, content, isError) {\r
+                       $("body").append(\r
+                               $(document.createElement("div"))\r
+                               .attr("id", "nitdoc-github-modal-fade")\r
+                               .addClass("nitdoc-github-fade")\r
+                       )\r
+                       .append(\r
+                               $(document.createElement("div"))\r
+                               .attr("id", "nitdoc-github-modal")\r
+                               .addClass("nitdoc-github-modal")\r
+                               .append(\r
+                                       $(document.createElement("a"))\r
+                                       .addClass("nitdoc-github-close")\r
+                                       .attr("title", "Close")\r
+                                       .append("x")\r
+                                       .click(function() { ModalBox.close() })\r
+                               )\r
+                               .append("<h3>" + title + "</h3>")\r
+                               .append("<div>" + content + "</div>")\r
+                               .append(\r
+                                       $(document.createElement("div"))\r
+                                       .addClass("nitdoc-github-buttons")\r
+                                       .append(\r
+                                               $(document.createElement("button"))\r
+                                               .addClass("nitdoc-github-button")\r
+                                               .append("Ok")\r
+                                               .click(function() { ModalBox.close() })\r
+                                       )\r
+                               )\r
+                       );\r
+\r
+                       if(isError) {\r
+                               $("#nitdoc-github-modal").addClass("nitdoc-github-error");\r
+                       }\r
+\r
+                       $("#nitdoc-github-modal")\r
+                       .css({\r
+                               top: "50%",\r
+                               marginTop: -($("#nitdoc-github-modal").outerHeight() / 2) + "px",\r
+                               left: "50%",\r
+                               marginLeft: -($("#nitdoc-github-modal").outerWidth() / 2) + "px"\r
+                       })\r
+                       .find("button.nitdoc-github-button").focus();\r
+               },\r
+\r
+               // Close modal box instance\r
+               close: function() {\r
+                       $("#nitdoc-github-modal").remove();\r
+                       $("#nitdoc-github-modal-fade").remove();\r
+               }\r
+       };\r
+       return ModalBox;\r
+});\r
diff --git a/share/nitdoc/js/plugins/github/ui.js b/share/nitdoc/js/plugins/github/ui.js
new file mode 100644 (file)
index 0000000..e669b9b
--- /dev/null
@@ -0,0 +1,337 @@
+/* This file is part of NIT ( http://www.nitlanguage.org ).\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+   http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+   Documentation generator for the nit language.\r
+   Generate API documentation in HTML format from nit source code.\r
+*/\r
+\r
+/*\r
+ * Nitdoc.Github.UI for comment edition module\r
+ */\r
+define([\r
+       "jquery",\r
+       "plugins/github/user",\r
+       "plugins/github/github_api",\r
+       "plugins/github/utils",\r
+       "plugins/github/commentbox",\r
+       "base64",\r
+], function($, User, GithubAPI, Utils, CommentBox, Base64) {\r
+       var UI = {\r
+               openedComments: 0,      // currently edited comments count\r
+               user: false,            // logged user\r
+\r
+               // Activate comment UI for a logged user\r
+               activate: function(loggedUser) {\r
+                       // Save session\r
+                       this.user = loggedUser;\r
+                       this.saveSession(this.user);\r
+               \r
+                       // check local storage synchro with branch\r
+                       if(localStorage.base != this.origin.sha) {\r
+                               console.log("Base changed: cleaned cache");\r
+                               localStorage.requests = "[]";\r
+                               localStorage.base = this.origin.sha;\r
+                       }\r
+\r
+                       // Prevent page unload if there is comments in editing mode\r
+                       $(window).on('beforeunload', function() {\r
+                               if(UI.getOpenedComments() > 0){\r
+                                       return "There is uncommited modified comments. Are you sure you want to leave this page?";\r
+                               }\r
+                       });\r
+\r
+                       this.attachCommentEvents();\r
+                       this.reloadComments();\r
+               },\r
+\r
+               // clear storage\r
+               disactivate: function() {\r
+                       if(UI.getOpenedComments() > 0){\r
+                               if(!confirm('There is uncommited modified comments. Are you sure you want to leave this page?')) {\r
+                                       return false;\r
+                               }\r
+                       }\r
+                       // close session and purge cookie\r
+                       localStorage.clear();\r
+                       $(window).unbind('beforeunload');\r
+                       window.location.reload();\r
+               },\r
+\r
+               // Attempt login through GitHub API\r
+               tryLogin: function(login, password, repo, branch) {\r
+                       var user = new User(login, password, repo, branch);\r
+                       if(!GithubAPI.login(user)) {\r
+                               return "error:login";\r
+                       }\r
+                       // check github profile fields\r
+                       if(!user.infos.name || !user.infos.email) {\r
+                               return "error:profile";\r
+                       }\r
+                       // check correct base commit\r
+                       var commit = GithubAPI.getCommit(user, this.origin.sha);\r
+                       if(!commit || !commit.sha) {\r
+                               return "error:sha";\r
+                       }\r
+                       return user;\r
+               },\r
+\r
+               // Attach edit button on each comment\r
+               attachCommentEvents: function() {\r
+                       // Blocks without comment\r
+                       $("span.noComment").each(function() {\r
+                               //FIXME this should be done by nitdoc\r
+                               var baseComment = $(this).parent().prev();\r
+                               var location = Utils.parseLocation(baseComment.attr("data-comment-location"));\r
+                               var locString = location.path + ":" + location.lstart + "," + location.tabpos + "--" + location.lstart + ",0";\r
+                               baseComment.attr("data-comment-location", locString);\r
+                               $(this).html("<a class='nitdoc-github-editComment noComment'>add comment</a> for ");\r
+                               $(this).addClass("nitdoc-github-editComment");\r
+                       });\r
+                       // Blocks with comment\r
+                       $('.description div.comment').each(function() {\r
+                               var p = $(this).next();\r
+                               p.prepend("<span class='nitdoc-github-editComment'><a class='nitdoc-github-editComment'>edit comment</a> for </span>")\r
+                       });\r
+\r
+                       // Attach links events\r
+                       $('a.nitdoc-github-editComment').each(function() {\r
+                               $(this).css("cursor", "pointer")\r
+                               $(this).click(function() {\r
+                                       // hide link\r
+                                       $(this).parent().hide();\r
+                                       // add infos\r
+                                       var infos = {};\r
+                                       var baseTextarea;\r
+                                       if(!$(this).hasClass("noComment")) {\r
+                                               $(this).parent().parent().prev().hide();\r
+                                               baseTextarea = $(this).parent().parent().prev().prev();\r
+                                       } else {\r
+                                               baseTextarea = $(this).parent().parent().prev();\r
+                                               infos.isNew = true;\r
+                                       }\r
+                                       infos.user = UI.user;\r
+                                       infos.location = Utils.parseLocation(baseTextarea.attr("data-comment-location"));\r
+                                       infos.namespace = baseTextarea.attr("data-comment-namespace");\r
+                                       infos.oldComment = baseTextarea.val();\r
+                                       var box = new CommentBox(infos);\r
+                                       box.open(baseTextarea);\r
+                               });\r
+                       });\r
+               },\r
+\r
+               // reload comments from saved pull request\r
+               reloadComments: function() {\r
+                       if(!localStorage.requests){ return; }\r
+                       var requests = JSON.parse(localStorage.requests);\r
+                       var converter = new Markdown.Converter();\r
+                       // Look for modified comments in page\r
+                       for(i in requests) {\r
+                               if(!requests[i]) { continue; }\r
+                               var request = requests[i];\r
+                               $("textarea[data-comment-location=\"" + request.location + "\"]").each(function () {\r
+                                       var div = $(this).next();\r
+                                       if(request.isClosed) {\r
+                                               if(div.is("div.comment.newComment")) {\r
+                                                       // hide empty comment\r
+                                                       div.next().remove();\r
+                                                       div.next().find("span.noComment").show();\r
+                                                       div.remove();\r
+                                               } else if(div.is("div.comment.locked")) {\r
+                                                       // unlock comment\r
+                                                       div.empty();\r
+                                                       div.append(converter.makeHtml($(this).text()));\r
+                                                       div.removeClass("locked");\r
+                                                       div.css("cursor", "pointer")\r
+                                                       div.next().remove();\r
+                                                       div.next().find("span.nitdoc-github-editComment").show();\r
+                                               }\r
+                                       } else {\r
+                                               // create div for the new coment\r
+                                               if(!div.is("div.comment")) {\r
+                                                       $(this).after("<div class='comment newComment'></div>");\r
+                                                       div = $(this).next();\r
+                                               }\r
+                                               // lock modified comment\r
+                                               if(!div.hasClass("locked")) {\r
+                                                       // convert modified comment to markdown\r
+                                                       div.empty()\r
+                                                       div.append(converter.makeHtml(Base64.decode(request.comment)));\r
+                                                       // lock click\r
+                                                       div.css("cursor", "auto");\r
+                                                       div.addClass("locked");\r
+                                                       div.next().find("span.nitdoc-github-editComment").hide();\r
+                                                       div.after(\r
+                                                               $("<p class='locked inheritance'>")\r
+                                                               .text("comment modified in ")\r
+                                                               .append("<a href='"+ request.request.html_url +"' target='_blank' title='Review on GitHub'>pull request #"+ request.request.number +"</a>")\r
+                                                               .append(" ")\r
+                                                               .append(\r
+                                                                       $("<a data-pullrequest-number='"+ request.request.number +"' class='nitdoc-github-update'>update</a>")\r
+                                                                       .click(function (){\r
+                                                                               $(this).parent().hide();\r
+                                                                               div.hide();\r
+                                                                               var baseTextarea = div.prev();\r
+                                                                               // add infos\r
+                                                                               var infos = {};\r
+                                                                               infos.user = UI.getUser();\r
+                                                                               infos.location = Utils.parseLocation(baseTextarea.attr("data-comment-location"));\r
+                                                                               infos.namespace = baseTextarea.attr("data-comment-namespace");\r
+                                                                               infos.oldComment = baseTextarea.val();\r
+                                                                               infos.requestID = $(this).attr("data-pullrequest-number");\r
+                                                                               var box = new CommentBox(infos);\r
+                                                                               box.open(baseTextarea);                                                         \r
+                                                                       })\r
+                                                               )\r
+                                                               .append(" ")\r
+                                                               .append(\r
+                                                                       $("<a data-pullrequest-number='"+ request.request.number +"' class='nitdoc-github-cancel'>cancel</a>")\r
+                                                                       .click(function (){\r
+                                                                               ui.closePullRequest($(this).attr("data-pullrequest-number"));\r
+                                                                               ui.reloadComments();\r
+                                                                       })\r
+                                                               )\r
+                                                       );\r
+                                               }\r
+                                               // hide "add comment" link\r
+                                               if(div.hasClass("newComment")) {\r
+                                                       div.next().next().find("span.noComment").hide();\r
+                                               }\r
+                                       }\r
+\r
+                               });\r
+                       }\r
+               },\r
+\r
+               // Commit changes and send pull request\r
+               saveChanges: function(infos) {\r
+                       // if pull request update close existing pull request for the comment\r
+                       if(infos.requestID) {\r
+                               closePullRequest(infos.requestID);\r
+                       }\r
+\r
+                       // forge commit\r
+                       var fileContent = getFileContent(infos.location.path);\r
+                       infos.newContent = Utils.mergeComment(fileContent, infos.newComment, infos.location);\r
+\r
+                       // commit\r
+                       infos.request = pushChanges(infos)\r
+                       if(!infos.request) {\r
+                               ModalBox.open("Unable to commit changes!", response, true);\r
+                               return;\r
+                       }\r
+                       saveRequest(infos);\r
+\r
+                       // close boxes and reload comments              \r
+                       CommitBox.close();\r
+                       infos.commentBox.close();\r
+                       reloadComments();\r
+               },\r
+\r
+               /*\r
+                  Creating a new pull request with the new comment take 5 steps:\r
+                       1. get the base tree from latest commit\r
+\r
+                       2. create a new blob with updated file content\r
+                       3. post a new tree from base tree and blob\r
+                       4. post the new commit with new tree\r
+                       5. create the pull request\r
+               */\r
+               pushChanges: function(infos) {\r
+                       var baseTree = GithubAPI.getTree(user, origin.sha);\r
+                       if(!baseTree.sha) {\r
+                               ModalBox.open("Unable to locate base tree!", baseTree.status + ": " + baseTree.statusText, true);\r
+                               return false;\r
+                       }\r
+                       console.log("Base tree: " + baseTree.url);\r
+                       var newBlob = GithubAPI.createBlob(user, infos.newContent);\r
+                       if(!newBlob.sha) {\r
+                               ModalBox.open("Unable to create new blob!", newBlob.status + ": " + newBlob.statusText, true);\r
+                               return false;\r
+                       }\r
+                       console.log("New blob: " + newBlob.url);\r
+                       var newTree = GithubAPI.createTree(user, baseTree, infos.location.path, newBlob);\r
+                       if(!newTree.sha) {\r
+                               ModalBox.open("Unable to create new tree!", newTree.status + ": " + newTree.statusText, true);\r
+                               return false;\r
+                       }\r
+                       console.log("New tree: " + newTree.url);\r
+                       var newCommit = GithubAPI.createCommit(user, infos.message, baseTree.sha, newTree);\r
+                       if(!newCommit.sha) {\r
+                               ModalBox.open("Unable to create new commit!", newCommit.status + ": " + newCommit.statusText, true);\r
+                               return false;\r
+                       }\r
+                       console.log("New commit: " + newCommit.url);\r
+                       var pullRequest = GithubAPI.createPullRequest(user, infos.message.split("\n\n")[0], "Pull request from Nitdoc", origin, newCommit.sha);\r
+                       if(!pullRequest.number) {\r
+                               ModalBox.open("Unable to create pull request!", pullRequest.status + ": " + pullRequest.statusText, true);\r
+                               return false;\r
+                       }\r
+                       console.log("New pull request: " + pullRequest.url);\r
+                       return pullRequest;\r
+               },\r
+\r
+               // close previously opened pull request\r
+               closePullRequest: function(number) {\r
+                       var requests = JSON.parse(localStorage.requests);\r
+                       if(!requests[number]) {\r
+                               ModalBox.open("Unable to close pull request!", "Pull request " + number + "not found", true);\r
+                               return false;\r
+                       }\r
+                       // close pull request\r
+                       var res = GithubAPI.updatePullRequest(user, "Canceled from Nitdoc", "", "closed", requests[number].request);\r
+                       if(!res.id) {\r
+                               ModalBox.open("Unable to close pull request!", res.status + ": " + res.statusText, true);\r
+                               return false;\r
+                       }\r
+                       // update in localstorage\r
+                       requests[number].isClosed = true;\r
+                       localStorage.requests = JSON.stringify(requests);\r
+               },\r
+\r
+               // Get file content from github\r
+               getFileContent: function(githubUrl) {\r
+                       var origFile = GithubAPI.getFile(user, githubUrl);\r
+                       if(!origFile.content) {\r
+                               ModalBox.open("Unable to locate source file!", origFile.status + ": " + origFile.statusText, true);\r
+                               return;\r
+                       }\r
+                       var base64Content = origFile.content.substring(0, origFile.content.length - 1)\r
+                       return Base64.decode(base64Content);\r
+               },\r
+\r
+               // save pull request in local storage\r
+               saveRequest: function(infos) {\r
+                       var requests = [];\r
+                       if(localStorage.requests) {requests = JSON.parse(localStorage.requests)}\r
+                       requests[infos.request.number] = {\r
+                               request: infos.request,\r
+                               location: infos.location.origin,\r
+                               comment: Base64.encode(infos.newComment)\r
+                       };\r
+                       localStorage.requests = JSON.stringify(requests);\r
+               },\r
+\r
+               // save user in local storage\r
+               saveSession: function(user) {\r
+                       var session = {\r
+                               login: user.login,\r
+                               password: Base64.encode(user.password),\r
+                               repo: user.repo,\r
+                               branch: user.branch,\r
+                       };\r
+                       localStorage.user = JSON.stringify(session);\r
+               }\r
+       }\r
+       return UI;\r
+});\r
diff --git a/share/nitdoc/js/plugins/github/user.js b/share/nitdoc/js/plugins/github/user.js
new file mode 100644 (file)
index 0000000..fdb83a7
--- /dev/null
@@ -0,0 +1,33 @@
+/* This file is part of NIT ( http://www.nitlanguage.org ).\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+   http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+   Documentation generator for the nit language.\r
+   Generate API documentation in HTML format from nit source code.\r
+*/\r
+\r
+/*\r
+ * GitHub API user object\r
+ */\r
+define([\r
+       "base64",\r
+], function(Base64) {\r
+       return function(login, password, repo, branch) {\r
+               this.login = login;\r
+               this.password = password;\r
+               this.repo = repo;\r
+               this.auth = "Basic " +  Base64.encode(login + ':' + password);\r
+               this.branch = branch;\r
+       }\r
+});\r
+\r
diff --git a/share/nitdoc/js/plugins/github/utils.js b/share/nitdoc/js/plugins/github/utils.js
new file mode 100644 (file)
index 0000000..77de3ce
--- /dev/null
@@ -0,0 +1,75 @@
+/* This file is part of NIT ( http://www.nitlanguage.org ).\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+   http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+   Documentation generator for the nit language.\r
+   Generate API documentation in HTML format from nit source code.\r
+*/\r
+\r
+/*\r
+ * Nitdoc.Github comment edition module\r
+ *\r
+ * Allows user to modify source code comments directly from the Nitdoc\r
+ */\r
+define([\r
+       "jquery",\r
+       "base64",\r
+       "Markdown.Converter",\r
+       "plugins/utils",\r
+       "plugins/github/ui",\r
+], function($, Base64, mkdown, utils) {\r
+\r
+/*\r
+ * Nitdoc.GitHub.Utils module\r
+ */\r
+\r
+       return {\r
+               // Extract infos from string location "lib/standard/collection/array.nit:457,1--458,0"\r
+               parseLocation: function(location) {\r
+                       var parts = location.split(":");\r
+                       var loc = new Object();\r
+                       loc.origin = location;\r
+                       loc.path = parts[0];\r
+                       loc.lstart = parseInt(parts[1].split("--")[0].split(",")[0]);\r
+                       loc.tabpos = parseInt(parts[1].split("--")[0].split(",")[1]);\r
+                       loc.lend = parseInt(parts[1].split("--")[1].split(",")[0]);\r
+                       return loc;\r
+               },\r
+\r
+               // Meld modified comment into file conten\r
+               mergeComment: function(fileContent, comment, location) {\r
+                       // replace comment in file content\r
+                       var res = new String();\r
+                       var lines = fileContent.split("\n");\r
+                       // copy lines fron 0 to lstart\r
+                       for(var i = 0; i < location.lstart - 1; i++) {\r
+                               res += lines[i] + "\n";\r
+                       }\r
+                       // set comment\r
+                       if(comment && comment != "") {\r
+                               var commentLines = comment.split("\n");\r
+                               for(var i = 0; i < commentLines.length; i++) {\r
+                                       var line = commentLines[i];\r
+                                       var tab = location.tabpos > 1 ? "\t" : "";\r
+                                       res += tab + (line.length > 0 ? "# " : "#") + line + "\n";\r
+                               }\r
+                       }\r
+                       // copy lines fron lend to end\r
+                       for(var i = location.lend - 1; i < lines.length; i++) {\r
+                               res += lines[i];\r
+                               if(i < lines.length - 1) { res += "\n"; }\r
+                       }\r
+                       return res;\r
+               }\r
+       }\r
+});\r
diff --git a/share/nitdoc/scripts/Nitdoc.GitHub.js b/share/nitdoc/scripts/Nitdoc.GitHub.js
deleted file mode 100644 (file)
index 37f4104..0000000
+++ /dev/null
@@ -1,1239 +0,0 @@
-/* This file is part of NIT ( http://www.nitlanguage.org ).\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-   http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-   Documentation generator for the nit language.\r
-   Generate API documentation in HTML format from nit source code.\r
-*/\r
-\r
-/*\r
- * Nitdoc.Github comment edition module\r
- *\r
- * Allows user to modify source code comments directly from the Nitdoc\r
- */\r
-\r
-var Nitdoc = Nitdoc || {};\r
-\r
-Nitdoc.GitHub = {}; // Declare Nitdoc.GitHub submodule\r
-\r
-// Load GitHub UI\r
-$(document).ready(function() {\r
-       //FIXME base should be choosen by user\r
-       var upstream = $("body").attr("data-github-upstream");\r
-       var basesha1 = $("body").attr("data-github-base-sha1");\r
-       if(upstream && basesha1) {\r
-               Nitdoc.GitHub.UI.init(upstream, basesha1);\r
-       }\r
-});\r
-\r
-/*\r
- * Nitdoc.Github.UI for comment edition module\r
- */\r
-Nitdoc.GitHub.UI = function() {\r
-       var openedComments = 0; // currently edited comments count\r
-       var user = false; // logged user\r
-       var origin;\r
-\r
-       var init = function(upstream, basesha1) {\r
-               console.log("init GitHub module (upstream: "+ upstream +", base: " + basesha1 + ")");\r
-\r
-               // parse origin\r
-               var parts = upstream.split(":");\r
-               origin = {\r
-                       user: parts[0],\r
-                       repo: parts[1],\r
-                       branch: parts[2],\r
-                       sha: basesha1\r
-               };\r
-\r
-               // check local session\r
-               if(localStorage.user) {\r
-                       var session = JSON.parse(localStorage.user);\r
-                       var user = tryLogin(session.login, Base64.decode(session.password), session.repo, session.branch);\r
-                       if(!user.login) {\r
-                               console.log("Session found but authentification failed");\r
-                               localStorage.clear();\r
-                       }\r
-               } else {\r
-                       console.log("No session found");\r
-               }\r
-\r
-               // activate ui\r
-               Nitdoc.GitHub.LoginBox.init("nav.main ul");\r
-               if(user && user.login) {\r
-                       Nitdoc.GitHub.LoginBox.displayLogout(origin, user);\r
-                       activate(user);\r
-               } else {\r
-                       Nitdoc.GitHub.LoginBox.displayLogin();\r
-               }\r
-\r
-               // Prevent page unload if there is comments in editing mode\r
-               $(window).on('beforeunload', function() {\r
-                       if(Nitdoc.GitHub.UI.getOpenedComments() > 0){\r
-                               return "There is uncommited modified comments. Are you sure you want to leave this page?";\r
-                       }\r
-               });\r
-       }\r
-\r
-       // Activate comment UI for a logged user\r
-       var activate = function(loggedUser) {\r
-               // Save session\r
-               user = loggedUser;\r
-               saveSession(user);\r
-               \r
-               // check local storage synchro with branch\r
-               if(localStorage.base != origin.sha) {\r
-                       console.log("Base changed: cleaned cache");\r
-                       localStorage.requests = "[]";\r
-                       localStorage.base = origin.sha;\r
-               }\r
-\r
-               attachCommentEvents();\r
-               reloadComments();\r
-       }\r
-\r
-       // clear storage\r
-       var disactivate = function() {\r
-               if(Nitdoc.GitHub.UI.getOpenedComments() > 0){\r
-                       if(!confirm('There is uncommited modified comments. Are you sure you want to leave this page?')) {\r
-                               return false;\r
-                       }\r
-               }\r
-               // close session and purge cookie\r
-               localStorage.clear();\r
-               $(window).unbind('beforeunload');\r
-               window.location.reload();\r
-       }\r
-\r
-       // Attempt login through GitHub API\r
-       var tryLogin = function(login, password, repo, branch) {\r
-               var user = new Nitdoc.GitHub.User(login, password, repo, branch);\r
-               if(!Nitdoc.GitHub.API.login(user)) {\r
-                       return "error:login";\r
-               }\r
-               // check github profile fields\r
-               if(!user.infos.name || !user.infos.email) {\r
-                       return "error:profile";\r
-               }\r
-               // check correct base commit\r
-               var commit = Nitdoc.GitHub.API.getCommit(user, origin.sha);\r
-               if(!commit || !commit.sha) {\r
-                       return "error:sha";\r
-               }\r
-               return user;\r
-       }\r
-\r
-       // Attach edit button on each comment\r
-       var attachCommentEvents = function() {\r
-               // Blocks without comment\r
-               $("span.noComment").each(function() {\r
-                       //FIXME this should be done by nitdoc\r
-                       var baseComment = $(this).parent().prev();\r
-                       var location = Nitdoc.GitHub.Utils.parseLocation(baseComment.attr("data-comment-location"));\r
-                       var locString = location.path + ":" + location.lstart + "," + location.tabpos + "--" + location.lstart + ",0";\r
-                       baseComment.attr("data-comment-location", locString);\r
-                       $(this).html("<a class='nitdoc-github-editComment noComment'>add comment</a> for ");\r
-                       $(this).addClass("nitdoc-github-editComment");\r
-               });\r
-               // Blocks with comment\r
-               $('.description div.comment').each(function() {\r
-                       var p = $(this).next();\r
-                       p.prepend("<span class='nitdoc-github-editComment'><a class='nitdoc-github-editComment'>edit comment</a> for </span>")\r
-               });\r
-\r
-               // Attach links events\r
-               $('a.nitdoc-github-editComment').each(function() {\r
-                       $(this).css("cursor", "pointer")\r
-                       $(this).click(function() {\r
-                               // hide link\r
-                               $(this).parent().hide();\r
-                               // add infos\r
-                               var infos = {};\r
-                               var baseTextarea;\r
-                               if(!$(this).hasClass("noComment")) {\r
-                                       $(this).parent().parent().prev().hide();\r
-                                       baseTextarea = $(this).parent().parent().prev().prev();\r
-                               } else {\r
-                                       baseTextarea = $(this).parent().parent().prev();\r
-                                       infos.isNew = true;\r
-                               }\r
-                               infos.user = Nitdoc.GitHub.UI.getUser();\r
-                               infos.location = Nitdoc.GitHub.Utils.parseLocation(baseTextarea.attr("data-comment-location"));\r
-                               infos.namespace = baseTextarea.attr("data-comment-namespace");\r
-                               infos.oldComment = baseTextarea.val();\r
-                               var box = new Nitdoc.GitHub.CommentBox(infos);\r
-                               box.open(baseTextarea);\r
-                       });\r
-               });\r
-       }\r
-\r
-       // reload comments from saved pull request\r
-       var reloadComments = function() {\r
-               if(!localStorage.requests){ return; }\r
-               var requests = JSON.parse(localStorage.requests);\r
-               var converter = new Markdown.Converter();\r
-               // Look for modified comments in page\r
-               for(i in requests) {\r
-                       if(!requests[i]) { continue; }\r
-                       var request = requests[i];\r
-                       $("textarea[data-comment-location=\"" + request.location + "\"]").each(function () {\r
-                               var div = $(this).next();\r
-                               if(request.isClosed) {\r
-                                       if(div.is("div.comment.newComment")) {\r
-                                               // hide empty comment\r
-                                               div.next().remove();\r
-                                               div.next().find("span.noComment").show();\r
-                                               div.remove();\r
-                                       } else if(div.is("div.comment.locked")) {\r
-                                               // unlock comment\r
-                                               div.empty();\r
-                                               div.append(converter.makeHtml($(this).text()));\r
-                                               div.removeClass("locked");\r
-                                               div.css("cursor", "pointer")\r
-                                               div.next().remove();\r
-                                               div.next().find("span.nitdoc-github-editComment").show();\r
-                                       }\r
-                               } else {\r
-                                       // create div for the new coment\r
-                                       if(!div.is("div.comment")) {\r
-                                               $(this).after("<div class='comment newComment'></div>");\r
-                                               div = $(this).next();\r
-                                       }\r
-                                       // lock modified comment\r
-                                       if(!div.hasClass("locked")) {\r
-                                               // convert modified comment to markdown\r
-                                               div.empty()\r
-                                               div.append(converter.makeHtml(Base64.decode(request.comment)));\r
-                                               // lock click\r
-                                               div.css("cursor", "auto");\r
-                                               div.addClass("locked");\r
-                                               div.next().find("span.nitdoc-github-editComment").hide();\r
-                                               div.after(\r
-                                                       $("<p class='locked inheritance'>")\r
-                                                       .text("comment modified in ")\r
-                                                       .append("<a href='"+ request.request.html_url +"' target='_blank' title='Review on GitHub'>pull request #"+ request.request.number +"</a>")\r
-                                                       .append(" ")\r
-                                                       .append(\r
-                                                               $("<a data-pullrequest-number='"+ request.request.number +"' class='nitdoc-github-update'>update</a>")\r
-                                                               .click(function (){\r
-                                                                       $(this).parent().hide();\r
-                                                                       div.hide();\r
-                                                                       var baseTextarea = div.prev();\r
-                                                                       // add infos\r
-                                                                       var infos = {};\r
-                                                                       infos.user = Nitdoc.GitHub.UI.getUser();\r
-                                                                       infos.location = Nitdoc.GitHub.Utils.parseLocation(baseTextarea.attr("data-comment-location"));\r
-                                                                       infos.namespace = baseTextarea.attr("data-comment-namespace");\r
-                                                                       infos.oldComment = baseTextarea.val();\r
-                                                                       infos.requestID = $(this).attr("data-pullrequest-number");\r
-                                                                       var box = new Nitdoc.GitHub.CommentBox(infos);\r
-                                                                       box.open(baseTextarea);                                                         \r
-                                                               })\r
-                                                       )\r
-                                                       .append(" ")\r
-                                                       .append(\r
-                                                               $("<a data-pullrequest-number='"+ request.request.number +"' class='nitdoc-github-cancel'>cancel</a>")\r
-                                                               .click(function (){\r
-                                                                       ui.closePullRequest($(this).attr("data-pullrequest-number"));\r
-                                                                       ui.reloadComments();\r
-                                                               })\r
-                                                       )\r
-                                               );\r
-                                       }\r
-                                       // hide "add comment" link\r
-                                       if(div.hasClass("newComment")) {\r
-                                               div.next().next().find("span.noComment").hide();\r
-                                       }\r
-                               }\r
-\r
-                       });\r
-               }\r
-       }\r
-\r
-       // Commit changes and send pull request\r
-       var saveChanges = function(infos) {\r
-               // if pull request update close existing pull request for the comment\r
-               if(infos.requestID) {\r
-                       closePullRequest(infos.requestID);\r
-               }\r
-\r
-               // forge commit\r
-               var fileContent = getFileContent(infos.location.path);\r
-               infos.newContent = Nitdoc.GitHub.Utils.mergeComment(fileContent, infos.newComment, infos.location);\r
-\r
-               // commit\r
-               infos.request = pushChanges(infos)\r
-               if(!infos.request) {\r
-                       Nitdoc.GitHub.ModalBox.open("Unable to commit changes!", response, true);\r
-                       return;\r
-               }\r
-               saveRequest(infos);\r
-\r
-               // close boxes and reload comments              \r
-               Nitdoc.GitHub.CommitBox.close();\r
-               infos.commentBox.close();\r
-               reloadComments();\r
-       }\r
-\r
-       /*\r
-          Creating a new pull request with the new comment take 5 steps:\r
-               1. get the base tree from latest commit\r
-\r
-               2. create a new blob with updated file content\r
-               3. post a new tree from base tree and blob\r
-               4. post the new commit with new tree\r
-               5. create the pull request\r
-       */\r
-       var pushChanges = function(infos) {\r
-               var baseTree = Nitdoc.GitHub.API.getTree(user, origin.sha);\r
-               if(!baseTree.sha) {\r
-                       Nitdoc.GitHub.ModalBox.open("Unable to locate base tree!", baseTree.status + ": " + baseTree.statusText, true);\r
-                       return false;\r
-               }\r
-               console.log("Base tree: " + baseTree.url);\r
-               var newBlob = Nitdoc.GitHub.API.createBlob(user, infos.newContent);\r
-               if(!newBlob.sha) {\r
-                       Nitdoc.GitHub.ModalBox.open("Unable to create new blob!", newBlob.status + ": " + newBlob.statusText, true);\r
-                       return false;\r
-               }\r
-               console.log("New blob: " + newBlob.url);\r
-               var newTree = Nitdoc.GitHub.API.createTree(user, baseTree, infos.location.path, newBlob);\r
-               if(!newTree.sha) {\r
-                       Nitdoc.GitHub.ModalBox.open("Unable to create new tree!", newTree.status + ": " + newTree.statusText, true);\r
-                       return false;\r
-               }\r
-               console.log("New tree: " + newTree.url);\r
-               var newCommit = Nitdoc.GitHub.API.createCommit(user, infos.message, baseTree.sha, newTree);\r
-               if(!newCommit.sha) {\r
-                       Nitdoc.GitHub.ModalBox.open("Unable to create new commit!", newCommit.status + ": " + newCommit.statusText, true);\r
-                       return false;\r
-               }\r
-               console.log("New commit: " + newCommit.url);\r
-               var pullRequest = Nitdoc.GitHub.API.createPullRequest(user, infos.message.split("\n\n")[0], "Pull request from Nitdoc", origin, newCommit.sha);\r
-               if(!pullRequest.number) {\r
-                       Nitdoc.GitHub.ModalBox.open("Unable to create pull request!", pullRequest.status + ": " + pullRequest.statusText, true);\r
-                       return false;\r
-               }\r
-               console.log("New pull request: " + pullRequest.url);\r
-               return pullRequest;\r
-       }\r
-\r
-       // close previously opened pull request\r
-       var closePullRequest = function(number) {\r
-               var requests = JSON.parse(localStorage.requests);\r
-               if(!requests[number]) {\r
-                       Nitdoc.GitHub.ModalBox.open("Unable to close pull request!", "Pull request " + number + "not found", true);\r
-                       return false;\r
-               }\r
-               // close pull request\r
-               var res = Nitdoc.GitHub.API.updatePullRequest(user, "Canceled from Nitdoc", "", "closed", requests[number].request);\r
-               if(!res.id) {\r
-                       Nitdoc.GitHub.ModalBox.open("Unable to close pull request!", res.status + ": " + res.statusText, true);\r
-                       return false;\r
-               }\r
-               // update in localstorage\r
-               requests[number].isClosed = true;\r
-               localStorage.requests = JSON.stringify(requests);\r
-       }\r
-\r
-       // Get file content from github\r
-       var getFileContent = function(githubUrl) {\r
-               var origFile = Nitdoc.GitHub.API.getFile(user, githubUrl);\r
-               if(!origFile.content) {\r
-                       Nitdoc.GitHub.ModalBox.open("Unable to locate source file!", origFile.status + ": " + origFile.statusText, true);\r
-                       return;\r
-               }\r
-               var base64Content = origFile.content.substring(0, origFile.content.length - 1)\r
-               return Base64.decode(base64Content);\r
-       }\r
-\r
-       // save pull request in local storage\r
-       var saveRequest = function(infos) {\r
-               var requests = [];\r
-               if(localStorage.requests) {requests = JSON.parse(localStorage.requests)}\r
-               requests[infos.request.number] = {\r
-                       request: infos.request,\r
-                       location: infos.location.origin,\r
-                       comment: Base64.encode(infos.newComment)\r
-               };\r
-               localStorage.requests = JSON.stringify(requests);\r
-       }\r
-\r
-       // save user in local storage\r
-       var saveSession = function(user) {\r
-               var session = {\r
-                       login: user.login,\r
-                       password: Base64.encode(user.password),\r
-                       repo: user.repo,\r
-                       branch: user.branch,\r
-               };\r
-               localStorage.user = JSON.stringify(session);\r
-       }\r
-\r
-       // accessors\r
-\r
-       var getUser = function() { return user; }\r
-       var getOrigin = function() { return origin; }\r
-       var getOpenedComments = function() { return openedComments; }\r
-       var addOpenedComments = function() { openedComments += 1; }\r
-       var remOpenedComments = function() { openedComments -= 1; }\r
-\r
-       // public interface\r
-       var ui = {\r
-               init: init,\r
-               tryLogin: tryLogin,\r
-               activate: activate,\r
-               disactivate: disactivate,\r
-               getUser: getUser,\r
-               getOrigin: getOrigin,\r
-               getOpenedComments: getOpenedComments,\r
-               addOpenedComments: addOpenedComments,\r
-               remOpenedComments: remOpenedComments,\r
-               saveChanges: saveChanges,\r
-               closePullRequest: closePullRequest,\r
-               reloadComments: reloadComments\r
-       }\r
-\r
-       return ui;\r
-}();\r
-\r
-/*\r
- * GitHub API user object\r
- */\r
-Nitdoc.GitHub.User = function(login, password, repo, branch) {\r
-       this.login = login;\r
-       this.password = password;\r
-       this.repo = repo;\r
-       this.auth = "Basic " +  Base64.encode(login + ':' + password);\r
-       this.branch = branch;\r
-};\r
-\r
-/* \r
- * GitHub API module\r
- */\r
-Nitdoc.GitHub.API = function() {\r
-\r
-       // try to login the user to github API\r
-       var login = function(user) {\r
-               var res = false;\r
-               $.ajax({\r
-                       beforeSend: function (xhr) {\r
-                               xhr.setRequestHeader ("Authorization", user.auth);\r
-                       },\r
-                       type: "GET",\r
-                       url: "https://api.github.com/repos/" + user.login + "/" + user.repo,\r
-                       async: false,\r
-                       dataType: 'json',\r
-                       success: function() {\r
-                               res = true;\r
-                       }\r
-               });\r
-               user.infos = getUserInfos(user);\r
-               user.signedOff = getSignedOff(user)\r
-               return res;\r
-       }\r
-\r
-       // request for user github account infos\r
-       var getUserInfos = function(user) {\r
-               var res = false;\r
-               $.ajax({\r
-                       beforeSend: function (xhr) {\r
-                               xhr.setRequestHeader ("Authorization", user.auth);\r
-                       },\r
-                       type: "GET",\r
-                           url: "https://api.github.com/users/" + user.login,\r
-                       async: false,\r
-                       dataType: 'json',\r
-                       success: function(response) {\r
-                               res = response;\r
-                       },\r
-                       error: function(response) {\r
-                               res = response;\r
-                       }\r
-               });\r
-               return res;\r
-       }\r
-\r
-       // build signedoff user default signature\r
-       var getSignedOff = function(user) {\r
-               return user.infos.name + " <" + user.infos.email + ">";\r
-       }\r
-\r
-       // get the branches list from a repo\r
-       var getBranches = function(user) {\r
-               var res = false;\r
-               $.ajax({\r
-                       beforeSend: function (xhr) {\r
-                               xhr.setRequestHeader ("Authorization", user.auth);\r
-                       },\r
-                       type: "GET",\r
-                       url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/branches",\r
-                       async: false,\r
-                       dataType: 'json',\r
-                       success: function(response) {\r
-                               res = response;\r
-                       },\r
-                       error: function(response) {\r
-                               res = response;\r
-                       }\r
-               });\r
-               return res;\r
-    }\r
-\r
-       /* GitHub commits */\r
-\r
-       // get the latest commit on `branchName`\r
-       var getCommit = function(user, sha) {\r
-               var res = false;\r
-               $.ajax({\r
-                       beforeSend: function (xhr) {\r
-                               xhr.setRequestHeader ("Authorization", user.auth);\r
-                       },\r
-                       type: "GET",\r
-                       url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/git/commits/" + sha,\r
-                       async: false,\r
-                       dataType: 'json',\r
-                       success: function(response) {\r
-                               res = response;\r
-                       },\r
-                       error: function(response) {\r
-                               res = response;\r
-                       }\r
-               });\r
-               return res;\r
-    }\r
-\r
-       // get the base tree for a commit sha\r
-       var getTree = function(user, sha) {\r
-               var res = false;\r
-               $.ajax({\r
-                       beforeSend: function (xhr) {\r
-                               xhr.setRequestHeader ("Authorization", user.auth);\r
-                       },\r
-                       type: "GET",\r
-                       url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/git/trees/" + sha + "?recursive=1",\r
-                       async: false,\r
-                       dataType: 'json',\r
-                       success: function(response) {\r
-                               res = response;\r
-                       },\r
-                       error: function(response) {\r
-                               res = response;\r
-                       }\r
-               });\r
-               return res;\r
-       }\r
-\r
-       // create a new blob\r
-       var createBlob = function(user, content) {\r
-               var res = false;\r
-               $.ajax({\r
-                       beforeSend: function (xhr) {\r
-                               xhr.setRequestHeader ("Authorization", user.auth);\r
-                       },\r
-                       type: "POST",\r
-                       url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/git/blobs",\r
-                       async: false,\r
-                       dataType: 'json',\r
-                       data: JSON.stringify({\r
-                               content: Base64.encode(content),\r
-                               encoding: "base64"\r
-                       }),\r
-                       success: function(response) {\r
-                               res = response;\r
-                       },\r
-                       error: function(response) {\r
-                               res = response;\r
-                       }\r
-               });\r
-               return res;\r
-    }\r
-\r
-       // create a new tree from a base tree\r
-       var createTree = function(user, baseTree, path, blob) {\r
-               var res = false;\r
-               $.ajax({\r
-                       beforeSend: function (xhr) {\r
-                               xhr.setRequestHeader ("Authorization", user.auth);\r
-                       },\r
-                       type: "POST",\r
-                       url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/git/trees",\r
-                       data: JSON.stringify({\r
-                               base_tree: baseTree.sha,\r
-                               tree: [{\r
-                                       path: path,\r
-                                       mode: 100644, // file (blob)\r
-                                       type: "blob",\r
-                                       sha: blob.sha\r
-                               }]\r
-                       }),\r
-                       async: false,\r
-                       dataType: 'json',\r
-                       success: function(response) {\r
-                               res = response;\r
-                       },\r
-                       error: function(response) {\r
-                               res = response;\r
-                       }\r
-               });\r
-               return res;\r
-       }\r
-\r
-       // create a new commit\r
-       var createCommit = function(user, message, parentCommit, tree) {\r
-               var res = false;\r
-               $.ajax({\r
-                       beforeSend: function (xhr) {\r
-                               xhr.setRequestHeader ("Authorization", user.auth);\r
-                       },\r
-                       type: "POST",\r
-                       url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/git/commits",\r
-                       data: JSON.stringify({\r
-                               message: message,\r
-                               parents: parentCommit,\r
-                               tree: tree.sha,\r
-                       }),\r
-                       async: false,\r
-                       dataType: 'json',\r
-                       success: function(response) {\r
-                               res = response;\r
-                       },\r
-                       error: function(response) {\r
-                               res = response;\r
-                       }\r
-               });\r
-               return res;\r
-       }\r
-\r
-       // create a pull request\r
-       var createPullRequest = function(user, title, body, origin, head) {\r
-               var res = false;\r
-               $.ajax({\r
-                       beforeSend: function (xhr) {\r
-                               xhr.setRequestHeader ("Authorization", user.auth);\r
-                       },\r
-                       type: "POST",\r
-                       url: "https://api.github.com/repos/" + origin.user + "/" + origin.repo + "/pulls",\r
-                       data: JSON.stringify({\r
-                               title: title,\r
-                               body: body,\r
-                               base: origin.branch,\r
-                               head: user.login + ":" + head\r
-                       }),\r
-                       async: false,\r
-                       dataType: 'json',\r
-                       success: function(response) {\r
-                               res = response;\r
-                       },\r
-                       error: function(response) {\r
-                               res = response;\r
-                       }\r
-               });\r
-               return res;\r
-       }\r
-\r
-       // update a pull request\r
-       var updatePullRequest = function(user, title, body, state, request) {\r
-               var res = false;\r
-                       $.ajax({\r
-                       beforeSend: function (xhr) {\r
-                                       xhr.setRequestHeader ("Authorization", user.auth);\r
-                       },\r
-                       type: "PATCH",\r
-                       url: request.url,\r
-                       data: JSON.stringify({\r
-                               title: title,\r
-                               body: body,\r
-                               state: state\r
-                       }),\r
-                       async: false,\r
-                       dataType: 'json',\r
-                       success: function(response) {\r
-                               res = response;\r
-                       },\r
-                       error: function(response) {\r
-                               res = response;\r
-                       }\r
-               });\r
-               return res;\r
-       }\r
-\r
-       /* Files */\r
-\r
-       var getFile = function(user, path, branch) {\r
-               var res = false;\r
-               $.ajax({\r
-                       type: "GET",\r
-                       url: "https://api.github.com/repos/" + user.login + "/" + user.repo + "/contents/" + path,\r
-                       data: {\r
-                               ref: branch\r
-                       },\r
-                       async: false,\r
-                       dataType: 'json',\r
-                       success: function(response) {\r
-                               res = response;\r
-                       },\r
-                       error: function(response) {\r
-                               res = response;\r
-                       }\r
-               });\r
-               return res;\r
-       }\r
-\r
-       var api = {\r
-               login: login,\r
-               getCommit: getCommit,\r
-               getBranches: getBranches,\r
-               getTree: getTree,\r
-               createBlob: createBlob,\r
-               createTree: createTree,\r
-               createCommit: createCommit,\r
-               createPullRequest: createPullRequest,\r
-               updatePullRequest: updatePullRequest,\r
-               getFile: getFile\r
-       }\r
-\r
-       return api;\r
-}();\r
-\r
-/*\r
- * Nitdoc GitHub loginbox module\r
- */\r
-\r
-Nitdoc.GitHub.LoginBox = function() {\r
-       var loginBox;\r
-       var loginBoxLi;\r
-       var loginBoxContent;\r
-\r
-       var init = function(containerSelector) {\r
-               loginBoxLi = $(document.createElement("li"))\r
-               .attr("id", "nitdoc-github-li")\r
-               .append(\r
-                       $(document.createElement("a"))\r
-                       .append(\r
-                               $(document.createElement("img"))\r
-                               .attr({\r
-                                       src: "resources/icons/github-icon.png",\r
-                                       alt: "GitHub"\r
-                               })\r
-                               .addClass("nitdoc-github-li-img")\r
-                       )\r
-                       .click(function() { Nitdoc.GitHub.LoginBox.toggle() })\r
-               )\r
-\r
-               loginBoxContent = $(document.createElement("div"));\r
-               loginBox = $(document.createElement("div"))\r
-               .attr("id", "nitdoc-github-loginbox")\r
-               .css("display", "none")\r
-               .append(\r
-                       $(document.createElement("div"))\r
-                       .addClass("nitdoc-github-loginbox-arrow")\r
-                       .append("&nbsp;")\r
-               )\r
-               .append(\r
-                       $(document.createElement("h3"))\r
-                       .append("Github Sign In")\r
-               )\r
-               .append(loginBoxContent);\r
-\r
-               loginBoxLi.append(loginBox);\r
-               $(containerSelector).append(loginBoxLi);\r
-       }\r
-\r
-       // Panel of login box to display when the user is logged in\r
-       var displayLogout = function(origin, user) {\r
-               var panel = $(document.createElement("div"))\r
-               .append(\r
-                       $(document.createElement("h4"))\r
-                       .append("Hello ")\r
-                       .append(\r
-                               $(document.createElement("a"))\r
-                               .attr("href", "https://github.com/" + user.login)\r
-                               .append(user.login)\r
-                       ).append("!")\r
-               )\r
-               .append(\r
-                       $(document.createElement("label"))\r
-                       .attr("for", "github-origin")\r
-                       .append("Origin")\r
-               )\r
-               .append(\r
-                       $(document.createElement("input"))\r
-                       .attr({\r
-                               id: "github-origin",\r
-                               type: "text",\r
-                               disabled: "disabled",\r
-                               value: origin.user + ":" + origin.repo + ":" + origin.branch\r
-                       })\r
-               )\r
-               .append(\r
-                       $(document.createElement("label"))\r
-                       .attr("for", "github-base")\r
-                       .append("Base")\r
-               )\r
-               .append(\r
-                       $(document.createElement("input"))\r
-                       .attr({\r
-                               id: "github-base",\r
-                               type: "text",\r
-                               disabled: "disabled",\r
-                               value: user.login + ":" + user.repo + ":" + user.branch\r
-                       })\r
-               )\r
-               .append(\r
-                       $(document.createElement("button"))\r
-                       .addClass("nitdoc-github-button")\r
-                       .addClass("nitdoc-github-cancel")\r
-                       .append(\r
-                               $(document.createElement("img"))\r
-                               .attr("src", "resources/icons/github-icon.png")\r
-                       ).append("Sign Off")\r
-                       .click(function() { // log out user\r
-                               Nitdoc.GitHub.UI.disactivate();\r
-                               Nitdoc.GitHub.LoginBox.toggle();\r
-                       })\r
-               );\r
-               $(".nitdoc-github-li-img").attr("src", "resources/icons/github-icon-green.png");\r
-               loginBoxContent.empty()\r
-               loginBoxContent.append(panel);\r
-       }\r
-\r
-       // Panel of login box to display when the user is logged out\r
-       var displayLogin = function() {\r
-               var panel = $(document.createElement("form"))\r
-               .append(\r
-                       $(document.createElement("label"))\r
-                       .attr("for", "nitdoc-github-login-field")\r
-                       .append("Username")\r
-               )\r
-               .append(\r
-                       $(document.createElement("input"))\r
-                       .attr({\r
-                               id: "nitdoc-github-login-field",\r
-                               type: "text"\r
-                       })\r
-               )\r
-               .append(\r
-                       $(document.createElement("label"))\r
-                       .attr("for", "nitdoc-github-password-field")\r
-                       .append("Password")\r
-               )\r
-               .append(\r
-                       $(document.createElement("input"))\r
-                       .attr({\r
-                               id: "nitdoc-github-password-field",\r
-                               type: "password"\r
-                       })\r
-               )\r
-               .append(\r
-                       $(document.createElement("label"))\r
-                       .attr("for", "nitdoc-github-repo-field")\r
-                       .append("Repository")\r
-               )\r
-               .append(\r
-                       $(document.createElement("input"))\r
-                       .attr({\r
-                               id: "nitdoc-github-repo-field",\r
-                               type: "text"\r
-                       })\r
-               )\r
-               .append(\r
-                       $(document.createElement("label"))\r
-                       .attr("for", "nitdoc-github-branch-field")\r
-                       .append("Branch")\r
-               )\r
-               .append(\r
-                       $(document.createElement("input"))\r
-                       .attr({\r
-                               id: "nitdoc-github-branch-field",\r
-                               type: "text"\r
-                       })\r
-               )\r
-               .append(\r
-                       $(document.createElement("button"))\r
-                       .addClass("nitdoc-github-button")\r
-                       .append(\r
-                               $(document.createElement("img"))\r
-                               .attr("src", "resources/icons/github-icon.png")\r
-                       ).append("Sign In")\r
-                       .click(function() {\r
-                               var login = $('#nitdoc-github-login-field').val();\r
-                               var password = $('#nitdoc-github-password-field').val();\r
-                               var repo = $('#nitdoc-github-repo-field').val();\r
-                               var branch = $('#nitdoc-github-branch-field').val();\r
-                               if(!login || !password || !repo || !branch) {\r
-                                       Nitdoc.GitHub.ModalBox.open("Sign in error", "Please enter your GitHub username, password, repository and branch.", true);\r
-                               } else {\r
-                                       var user = Nitdoc.GitHub.UI.tryLogin(login, password, repo, branch);\r
-                                       if(user == "error:login") {\r
-                                               Nitdoc.GitHub.ModalBox.open("Sign in error", "The username, password, repo or branch you entered is incorrect.", true);\r
-                                       } else if(user == "error:sha") {\r
-                                               Nitdoc.GitHub.ModalBox.open("Base commit not found", "The provided GitHub repository must contains the base commit '" + Nitdoc.GitHub.UI.getOrigin().sha + "'", true);\r
-                                       } else if(user == "error:profile") {\r
-                                               Nitdoc.GitHub.ModalBox.open("Incomplete GitHub profile", "Please set your public name and email in your <a href='https://github.com/settings/profile'>GitHub profile</a>.<br/><br/>Your public profile informations are used to sign-off your commits.", true);\r
-                                       } else {\r
-                                               Nitdoc.GitHub.UI.activate(user);\r
-                                               var origin = Nitdoc.GitHub.UI.getOrigin();\r
-                                               Nitdoc.GitHub.LoginBox.displayLogout(origin, user);\r
-                                       }\r
-                               }\r
-                               return false;\r
-                       })\r
-               )\r
-               $(".nitdoc-github-li-img").attr("src", "resources/icons/github-icon.png");\r
-               loginBoxContent.empty()\r
-               loginBoxContent.append(panel);\r
-       }\r
-\r
-       var toggle = function() {\r
-               if(loginBox.is(':hidden')) {\r
-                       loginBox.show();\r
-                       if (!$('#loginGit').is(':hidden')) { $('#loginGit').focus(); }\r
-               } else {\r
-                       loginBox.hide();\r
-               }\r
-       }\r
-\r
-       // Public interface\r
-       var loginbox = {\r
-               init: init,\r
-               displayLogin: displayLogin,\r
-               displayLogout: displayLogout,\r
-               toggle: toggle,\r
-               \r
-       };\r
-\r
-       return loginbox;\r
-}();\r
-\r
-/*\r
- * Nitdoc.GitHub.CommentBox class\r
- */\r
-\r
-// Init new modal box instance\r
-Nitdoc.GitHub.CommentBox = function(infos) {\r
-       this.infos = infos;\r
-       this.commentBoxDiv;\r
-}\r
-\r
-Nitdoc.GitHub.CommentBox.prototype.open = function(baseArea) {\r
-       Nitdoc.GitHub.UI.addOpenedComments();\r
-       var instance = this;\r
-\r
-       if(this.infos.requestID) {\r
-               // get comment from last pull request\r
-               var requests = JSON.parse(localStorage.requests);\r
-               this.infos.newComment = Base64.decode(requests[this.infos.requestID].comment);\r
-       } else {\r
-               this.infos.newComment = false;\r
-       }\r
-\r
-       // create comment box\r
-       var tarea = $(document.createElement("textarea"))\r
-       .append(this.infos.newComment === false? this.infos.oldComment: this.infos.newComment)\r
-       .keyup(function(event) {\r
-               $(event.target).css("height", (event.target.value.split(/\r|\n/).length * 16) + "px");\r
-               if ( (!instance.infos.requestID && $(event.target).val() != instance.infos.oldComment) || (instance.infos.requestID && $(event.target).val() != instance.infos.oldComment && $(event.target).val() != instance.infos.newComment) ) {\r
-                       $(event.target).parent().find("button.nitdoc-github-commit").removeAttr("disabled");\r
-               } else {\r
-                       $(event.target).parent().find("button.nitdoc-github-commit").attr("disabled", "disabled");\r
-               }\r
-       })\r
-       .keydown(function(event) {\r
-               if(event.keyCode == 13){\r
-                       $(event.target).css("height", ($(event.target).outerHeight() + 6) + "px");\r
-               }\r
-       });\r
-\r
-       this.commentBoxDiv = $(document.createElement("div"))\r
-       .addClass("nitdoc-github-commentbox")\r
-       .append(tarea)\r
-       .append(\r
-               $(document.createElement("a"))\r
-               .addClass("nitdoc-github-preview")\r
-               .click(function() {\r
-                       var converter = new Markdown.Converter()\r
-                       var html = converter.makeHtml(tarea.val());\r
-                       Nitdoc.GitHub.ModalBox.open("Preview", html, false);\r
-               })\r
-       )\r
-       .append(\r
-               $(document.createElement("button"))\r
-               .addClass("nitdoc-github-button")\r
-               .addClass("nitdoc-github-commit")\r
-               .append("Commit")\r
-               .click(function() {\r
-                       instance.infos.newComment = tarea.val();\r
-                       instance.infos.commentBox = instance;\r
-                       Nitdoc.GitHub.CommitBox.open(instance.infos);\r
-               })\r
-       )\r
-       .append(\r
-               $(document.createElement("button"))\r
-               .addClass("nitdoc-github-button")\r
-               .addClass("nitdoc-github-cancel")\r
-               .append("Cancel")\r
-               .click(function() {instance.close()})\r
-       );\r
-\r
-       baseArea.after(this.commentBoxDiv);\r
-       var cbWidth = this.commentBoxDiv.innerWidth();\r
-       var taWidth = tarea.outerWidth();\r
-       tarea.width(cbWidth - (taWidth - cbWidth));\r
-       tarea.trigger("keyup");\r
-       tarea.focus();\r
-}\r
-\r
-Nitdoc.GitHub.CommentBox.prototype.close = function() {\r
-       Nitdoc.GitHub.UI.remOpenedComments();\r
-       if(this.infos.isNew) {\r
-               this.commentBoxDiv.next().find("span.nitdoc-github-editComment").show();\r
-       } else if(this.infos.requestID) {\r
-               this.commentBoxDiv.next().show();\r
-               this.commentBoxDiv.next().next().show();\r
-       } else {\r
-               this.commentBoxDiv.next().show();\r
-               this.commentBoxDiv.next().next().find("span.nitdoc-github-editComment").show();\r
-       }\r
-       this.commentBoxDiv.remove();\r
-}\r
-\r
-/*\r
- * Nitdoc.GitHub.ModalBox class\r
- */\r
-\r
-// Init new modal box instance\r
-Nitdoc.GitHub.ModalBox = function() {\r
-\r
-       // Open modal box instance\r
-       var open = function(title, content, isError) {\r
-               $("body").append(\r
-                       $(document.createElement("div"))\r
-                       .attr("id", "nitdoc-github-modal-fade")\r
-                       .addClass("nitdoc-github-fade")\r
-               )\r
-               .append(\r
-                       $(document.createElement("div"))\r
-                       .attr("id", "nitdoc-github-modal")\r
-                       .addClass("nitdoc-github-modal")\r
-                       .append(\r
-                               $(document.createElement("a"))\r
-                               .addClass("nitdoc-github-close")\r
-                               .attr("title", "Close")\r
-                               .append("x")\r
-                               .click(function() { Nitdoc.GitHub.ModalBox.close() })\r
-                       )\r
-                       .append("<h3>" + title + "</h3>")\r
-                       .append("<div>" + content + "</div>")\r
-                       .append(\r
-                               $(document.createElement("div"))\r
-                               .addClass("nitdoc-github-buttons")\r
-                               .append(\r
-                                       $(document.createElement("button"))\r
-                                       .addClass("nitdoc-github-button")\r
-                                       .append("Ok")\r
-                                       .click(function() { Nitdoc.GitHub.ModalBox.close() })\r
-                               )\r
-                       )\r
-               );\r
-\r
-               if(isError) {\r
-                       $("#nitdoc-github-modal").addClass("nitdoc-github-error");\r
-               }\r
-\r
-               $("#nitdoc-github-modal")\r
-               .css({\r
-                       top: "50%",\r
-                       marginTop: -($("#nitdoc-github-modal").outerHeight() / 2) + "px",\r
-                       left: "50%",\r
-                       marginLeft: -($("#nitdoc-github-modal").outerWidth() / 2) + "px"\r
-               })\r
-               .find("button.nitdoc-github-button").focus();\r
-       }\r
-\r
-       // Close modal box instance\r
-       var close = function() {\r
-               $("#nitdoc-github-modal").remove();\r
-               $("#nitdoc-github-modal-fade").remove();\r
-       }\r
-\r
-       // Public interface\r
-       var modalBox = {\r
-               open: open,\r
-               close: close\r
-       };\r
-\r
-       return modalBox;\r
-}();\r
-\r
-/*\r
- * Nitdoc.GitHub.CommitBox instance\r
- */\r
-\r
-// Init new commit box instance\r
-Nitdoc.GitHub.CommitBox = function() {\r
-\r
-       // Open commit box instance\r
-       var open = function(infos) {\r
-               $("body").append(\r
-                       $(document.createElement("div"))\r
-                       .attr("id", "nitdoc-github-commitBox-fade")\r
-                       .addClass("nitdoc-github-fade")\r
-               );\r
-               $("body").append(\r
-                       $(document.createElement("div"))\r
-                       .attr("id", "nitdoc-github-commitBox")\r
-                       .addClass("nitdoc-github-modal")\r
-                       .append(\r
-                               $(document.createElement("a"))\r
-                               .addClass("nitdoc-github-close")\r
-                               .attr("title", "Close")\r
-                               .append("x")\r
-                               .click(function() { Nitdoc.GitHub.CommitBox.close() })\r
-                       )\r
-                       .append("<h3>Commit changes</h3>")\r
-                       .append(\r
-                               $(document.createElement("div"))\r
-                               .append(\r
-                                       $(document.createElement("label"))\r
-                                       .attr("for", "nitdoc-github-commit-message")\r
-                               )\r
-                               .append("<br/>")\r
-                               .append(\r
-                                       $(document.createElement("textarea"))\r
-                                       .attr("id", "nitdoc-github-commit-message")\r
-                                       .append("doc: " + (infos.isNew ? "added" : "modified") + " comment for " + infos.namespace)\r
-                               )\r
-                               .append("<br/>")\r
-                               .append(\r
-                                       $(document.createElement("input"))\r
-                                       .attr({\r
-                                               id: "nitdoc-github-commit-signedoff",\r
-                                               type: "checkbox",\r
-                                               value: "Signed-off-by: " + infos.user.signedOff\r
-                                       })\r
-                                       .change(function(e) {\r
-                                               if ($(this).is(':checked')) {\r
-                                                       $("#nitdoc-github-commit-button").removeAttr("disabled");\r
-                                               } else {\r
-                                                       $("#nitdoc-github-commit-button").attr("disabled", "disabled");\r
-                                               }\r
-                                       })\r
-                               )\r
-                               .append(\r
-                                       $(document.createElement("label"))\r
-                                       .attr("for", "nitdoc-github-commit-signedoff")\r
-                                       .text("Signed-off-by: " + infos.user.signedOff)\r
-                               )\r
-                       ).append(\r
-                               $(document.createElement("div"))\r
-                               .addClass("nitdoc-github-buttons")\r
-                               .append(\r
-                                       $(document.createElement("button"))\r
-                                       .attr({\r
-                                               id: "nitdoc-github-commit-button",\r
-                                               disabled: "disabled"\r
-                                       })\r
-                                       .addClass("nitdoc-github-button")\r
-                                       .append(\r
-                                               $(document.createElement("img"))\r
-                                               .attr("src", "resources/icons/github-icon.png")\r
-                                       )\r
-                                       .append("Commit")\r
-                                       .mousedown(function() {\r
-                                               $(this).text("Commiting...");\r
-                                       })\r
-                                       .mouseup(function() {\r
-                                               infos.message = $("#nitdoc-github-commit-message").val() + "\n\n" + infos.user.signedOff;\r
-                                               Nitdoc.GitHub.UI.saveChanges(infos);\r
-                                       })\r
-                               )\r
-                       )\r
-               );\r
-\r
-               $("#nitdoc-github-commitBox")\r
-               .css({\r
-                       top: "50%",\r
-                       marginTop: -($("#nitdoc-github-commitBox").outerHeight() / 2) + "px",\r
-                       left: "50%",\r
-                       marginLeft: -($("#nitdoc-github-commitBox").outerWidth() / 2) + "px"\r
-               })\r
-               .find("#nitdoc-github-commit-message").focus();\r
-       }\r
-\r
-       // Close commit box instance\r
-       var close = function() {\r
-               $("#nitdoc-github-commitBox").remove();\r
-               $("#nitdoc-github-commitBox-fade").remove();\r
-       }\r
-\r
-       // Public interface\r
-       var commitBox = {\r
-               open: open,\r
-               close: close\r
-       }\r
-       return commitBox;\r
-}();\r
-\r
-/*\r
- * Nitdoc.GitHub.Utils module\r
- */\r
-\r
-Nitdoc.GitHub.Utils = function() {\r
-       // Extract infos from string location "lib/standard/collection/array.nit:457,1--458,0"\r
-       var parseLocation = function(location) {\r
-               var parts = location.split(":");\r
-               var loc = new Object();\r
-               loc.origin = location;\r
-               loc.path = parts[0];\r
-               loc.lstart = parseInt(parts[1].split("--")[0].split(",")[0]);\r
-               loc.tabpos = parseInt(parts[1].split("--")[0].split(",")[1]);\r
-               loc.lend = parseInt(parts[1].split("--")[1].split(",")[0]);\r
-               return loc;\r
-       }\r
-\r
-       // Meld modified comment into file conten\r
-       var mergeComment = function(fileContent, comment, location) {\r
-               // replace comment in file content\r
-               var res = new String();\r
-               var lines = fileContent.split("\n");\r
-               // copy lines fron 0 to lstart\r
-               for(var i = 0; i < location.lstart - 1; i++) {\r
-                       res += lines[i] + "\n";\r
-               }\r
-               // set comment\r
-               if(comment && comment != "") {\r
-                       var commentLines = comment.split("\n");\r
-                       for(var i = 0; i < commentLines.length; i++) {\r
-                               var line = commentLines[i];\r
-                               var tab = location.tabpos > 1 ? "\t" : "";\r
-                               res += tab + (line.length > 0 ? "# " : "#") + line + "\n";\r
-                       }\r
-               }\r
-               // copy lines fron lend to end\r
-               for(var i = location.lend - 1; i < lines.length; i++) {\r
-                       res += lines[i];\r
-                       if(i < lines.length - 1) { res += "\n"; }\r
-               }\r
-               return res;\r
-       }\r
-\r
-       // Public interface\r
-       var utils = {\r
-               parseLocation: parseLocation,\r
-               mergeComment: mergeComment\r
-       };\r
-\r
-       return utils;\r
-}();\r
-\r