Explorar el Código

Ipython notebook support (#4070)

* added marked and notebookjs javascript libraries

* added ipython notebook render support using javascript libraries

* recompiled gogs.css to include ipynb-related css

* removed superflous javascript library files
Herbert hace 8 años
padre
commit
9af0dd23dd

+ 97 - 22
public/css/gogs.css

@@ -812,7 +812,7 @@ footer .ui.language .menu {
   border: solid 1px #ccc;
   border-bottom-color: #bbb;
   border-radius: 3px;
-  box-shadow: inset 0 -1px 0 #bbb;
+  box-shadow: inset 0 -1px 0 #bbbbbb;
 }
 .markdown:not(code) input[type="checkbox"] {
   vertical-align: middle !important;
@@ -883,7 +883,7 @@ footer .ui.language .menu {
 }
 .install form label {
   text-align: right;
-  width: 320px !important;
+  width: 320px;
 }
 .install form input {
   width: 35% !important;
@@ -892,7 +892,7 @@ footer .ui.language .menu {
   text-align: left;
 }
 .install form .field .help {
-  margin-left: 335px !important;
+  margin-left: 335px;
 }
 .install form .field.optional .title {
   margin-left: 38%;
@@ -928,18 +928,18 @@ footer .ui.language .menu {
   text-align: center;
 }
 #create-page-form form .header {
-  padding-left: 280px !important;
+  padding-left: 280px;
 }
 #create-page-form form .inline.field > label {
   text-align: right;
-  width: 250px !important;
+  width: 250px;
   word-wrap: break-word;
 }
 #create-page-form form .help {
-  margin-left: 265px !important;
+  margin-left: 265px;
 }
 #create-page-form form .optional .title {
-  margin-left: 250px !important;
+  margin-left: 250px;
 }
 #create-page-form form input,
 #create-page-form form textarea {
@@ -965,7 +965,7 @@ footer .ui.language .menu {
 .user.reset.password form .header,
 .user.signin form .header,
 .user.signup form .header {
-  padding-left: 280px !important;
+  padding-left: 280px;
 }
 .user.activate form .inline.field > label,
 .user.forgot.password form .inline.field > label,
@@ -973,7 +973,7 @@ footer .ui.language .menu {
 .user.signin form .inline.field > label,
 .user.signup form .inline.field > label {
   text-align: right;
-  width: 250px !important;
+  width: 250px;
   word-wrap: break-word;
 }
 .user.activate form .help,
@@ -981,14 +981,14 @@ footer .ui.language .menu {
 .user.reset.password form .help,
 .user.signin form .help,
 .user.signup form .help {
-  margin-left: 265px !important;
+  margin-left: 265px;
 }
 .user.activate form .optional .title,
 .user.forgot.password form .optional .title,
 .user.reset.password form .optional .title,
 .user.signin form .optional .title,
 .user.signup form .optional .title {
-  margin-left: 250px !important;
+  margin-left: 250px;
 }
 .user.activate form input,
 .user.forgot.password form input,
@@ -1014,14 +1014,14 @@ footer .ui.language .menu {
 .user.reset.password form .header,
 .user.signin form .header,
 .user.signup form .header {
-  padding-left: 230px !important;
+  padding-left: 230px;
 }
 .user.activate form .inline.field > label,
 .user.forgot.password form .inline.field > label,
 .user.reset.password form .inline.field > label,
 .user.signin form .inline.field > label,
 .user.signup form .inline.field > label {
-  width: 200px !important;
+  width: 200px;
 }
 .repository.new.repo form,
 .repository.new.migrate form,
@@ -1037,24 +1037,24 @@ footer .ui.language .menu {
 .repository.new.repo form .header,
 .repository.new.migrate form .header,
 .repository.new.fork form .header {
-  padding-left: 280px !important;
+  padding-left: 280px;
 }
 .repository.new.repo form .inline.field > label,
 .repository.new.migrate form .inline.field > label,
 .repository.new.fork form .inline.field > label {
   text-align: right;
-  width: 250px !important;
+  width: 250px;
   word-wrap: break-word;
 }
 .repository.new.repo form .help,
 .repository.new.migrate form .help,
 .repository.new.fork form .help {
-  margin-left: 265px !important;
+  margin-left: 265px;
 }
 .repository.new.repo form .optional .title,
 .repository.new.migrate form .optional .title,
 .repository.new.fork form .optional .title {
-  margin-left: 250px !important;
+  margin-left: 250px;
 }
 .repository.new.repo form input,
 .repository.new.migrate form input,
@@ -1083,7 +1083,7 @@ footer .ui.language .menu {
   width: 50%!important;
 }
 .repository.new.repo .ui.form #auto-init {
-  margin-left: 265px !important;
+  margin-left: 265px;
 }
 .new.webhook form .help {
   margin-left: 25px;
@@ -1306,6 +1306,81 @@ footer .ui.language .menu {
 .repository.file.list #file-content .view-raw img {
   margin-bottom: -5px;
 }
+.repository.file.list #file-content #ipython-notebook {
+  margin-left: 80px;
+}
+.repository.file.list #file-content #ipython-notebook .nb-notebook {
+  line-height: 1.5;
+}
+.repository.file.list #file-content #ipython-notebook .nb-stdout,
+.repository.file.list #file-content #ipython-notebook .nb-stderr {
+  white-space: pre-wrap;
+  margin: 1em 0;
+  padding: 0.1em 0.5em;
+}
+.repository.file.list #file-content #ipython-notebook .nb-stderr {
+  background-color: #FAA;
+}
+.repository.file.list #file-content #ipython-notebook .nb-cell + .nb-cell {
+  margin-top: 0.5em;
+}
+.repository.file.list #file-content #ipython-notebook .nb-output table {
+  border: 1px solid #000;
+  border-collapse: collapse;
+}
+.repository.file.list #file-content #ipython-notebook .nb-output th {
+  font-weight: bold;
+}
+.repository.file.list #file-content #ipython-notebook .nb-output th,
+.repository.file.list #file-content #ipython-notebook .nb-output td {
+  border: 1px solid #000;
+  padding: 0.25em;
+  text-align: left;
+  vertical-align: middle;
+  border-collapse: collapse;
+}
+.repository.file.list #file-content #ipython-notebook .nb-cell {
+  position: relative;
+}
+.repository.file.list #file-content #ipython-notebook .nb-raw-cell {
+  white-space: pre-wrap;
+  background-color: #f5f2f0;
+  font-family: Consolas, Monaco, 'Andale Mono', monospace;
+  padding: 1em;
+  margin: .5em 0;
+}
+.repository.file.list #file-content #ipython-notebook .nb-output {
+  min-height: 1em;
+  width: 100%;
+  overflow-x: scroll;
+  border-right: 1px dotted #CCC;
+}
+.repository.file.list #file-content #ipython-notebook .nb-output img {
+  max-width: 100%;
+}
+.repository.file.list #file-content #ipython-notebook .nb-output:before,
+.repository.file.list #file-content #ipython-notebook .nb-input:before {
+  position: absolute;
+  font-family: monospace;
+  color: #999;
+  left: -7.5em;
+  width: 7em;
+  text-align: right;
+}
+.repository.file.list #file-content #ipython-notebook .nb-input:before {
+  content: "In [" attr(data-prompt-number) "]:";
+}
+.repository.file.list #file-content #ipython-notebook .nb-output:before {
+  content: "Out [" attr(data-prompt-number) "]:";
+}
+.repository.file.list #file-content #ipython-notebook .nb-markdown-cell {
+  background-color: #eee;
+  margin-left: -80px;
+  padding: 11.5px 10px 19.5px 80px;
+}
+.repository.file.list #file-content #ipython-notebook div[style="max-height:1000px;max-width:1500px;overflow:auto;"] {
+  max-height: none !important;
+}
 .repository.file.list #file-content .plain-text {
   font-size: 14px;
   padding: 10px 15px;
@@ -2539,18 +2614,18 @@ footer .ui.language .menu {
   text-align: center;
 }
 .organization.new.org form .header {
-  padding-left: 280px !important;
+  padding-left: 280px;
 }
 .organization.new.org form .inline.field > label {
   text-align: right;
-  width: 250px !important;
+  width: 250px;
   word-wrap: break-word;
 }
 .organization.new.org form .help {
-  margin-left: 265px !important;
+  margin-left: 265px;
 }
 .organization.new.org form .optional .title {
-  margin-left: 250px !important;
+  margin-left: 250px;
 }
 .organization.new.org form input,
 .organization.new.org form textarea {

+ 89 - 0
public/less/_repository.less

@@ -251,6 +251,95 @@
 				}
 			}
 
+			#ipython-notebook {
+				margin-left: 80px;
+
+				.nb-notebook {
+					line-height: 1.5;    
+				}
+
+				.nb-stdout, .nb-stderr {
+					white-space: pre-wrap;
+					margin: 1em 0;
+					padding: 0.1em 0.5em;
+				}
+
+				.nb-stderr {
+					background-color: #FAA;
+				}
+
+				.nb-cell + .nb-cell {
+					margin-top: 0.5em;
+				}
+
+				.nb-output table {
+					border: 1px solid #000;
+					border-collapse: collapse;
+				}
+
+				.nb-output th {
+					font-weight: bold;
+				}
+
+				.nb-output th, .nb-output td {
+					border: 1px solid #000;
+					padding: 0.25em;    
+					text-align: left;
+					vertical-align: middle;
+					border-collapse: collapse;
+				}
+
+				.nb-cell {
+					position: relative;    
+				}
+
+				.nb-raw-cell {
+					white-space: pre-wrap;
+					background-color: #f5f2f0;
+					font-family: Consolas, Monaco, 'Andale Mono', monospace;
+					padding: 1em;
+					margin: .5em 0;
+				}
+
+				.nb-output {
+					min-height: 1em;    
+					width: 100%;
+					overflow-x: scroll;
+					border-right: 1px dotted #CCC;
+				}
+
+				.nb-output img {
+					max-width: 100%;    
+				}
+
+				.nb-output:before, .nb-input:before {
+					position: absolute;    
+					font-family: monospace;
+					color: #999;
+					left: -7.5em;
+					width: 7em;
+					text-align: right;
+				}
+
+				.nb-input:before {
+					content: "In [" attr(data-prompt-number) "]:";
+				}
+				.nb-output:before {
+					content: "Out [" attr(data-prompt-number) "]:";
+				}
+
+				.nb-markdown-cell {
+					background-color: #eee;
+					margin-left: -80px;
+					padding: 11.5px 10px 19.5px 80px;
+				}
+
+				// Fix pandas dataframe formatting
+				div[style="max-height:1000px;max-width:1500px;overflow:auto;"] {
+					max-height: none !important;    
+				}
+			}
+
 			.plain-text {
 				font-size: 14px;
 				padding: 10px 15px;

+ 19 - 0
public/plugins/marked-0.3.6/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2011-2014, Christopher Jeffrey (https://github.com/chjj/)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 5 - 0
public/plugins/marked-0.3.6/marked.min.js


+ 21 - 0
public/plugins/notebookjs-0.2.6/LICENSE.txt

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014, Jeremy Singer-Vine
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
public/plugins/notebookjs-0.2.6/notebook.min.js


+ 2 - 0
routers/repo/view.go

@@ -156,6 +156,8 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
 		ctx.Data["IsMarkdown"] = isMarkdown
 		ctx.Data["ReadmeExist"] = isMarkdown && markdown.IsReadmeFile(blob.Name())
 
+		ctx.Data["IsIPyNB"] = strings.HasSuffix(blob.Name(), ".ipynb")
+
 		if isMarkdown {
 			ctx.Data["FileContent"] = string(markdown.Render(buf, path.Dir(treeLink), ctx.Repo.Repository.ComposeMetas()))
 		} else {

+ 6 - 0
templates/base/head.tmpl

@@ -21,6 +21,12 @@
 	<link rel="stylesheet" href="{{AppSubUrl}}/assets/font-awesome-4.6.3/css/font-awesome.min.css">
 	<link rel="stylesheet" href="{{AppSubUrl}}/assets/octicons-4.3.0/octicons.min.css">
 
+	<!-- notebook.js for rendering ipython notebooks and marked.js for rendering markdown in notebooks -->
+	{{if .IsIPyNB }}
+		<script src="{{AppSubUrl}}/plugins/notebookjs-0.2.6/notebook.min.js"></script>
+		<script src="{{AppSubUrl}}/plugins/marked-0.3.6/marked.min.js"></script>
+	{{end}}
+
 	{{if .RequireSimpleMDE}}
 		<link rel="stylesheet" href="{{AppSubUrl}}/plugins/simplemde-1.10.1/simplemde.min.css">
 		<script src="{{AppSubUrl}}/plugins/simplemde-1.10.1/simplemde.min.js"></script>

+ 20 - 0
templates/repo/view_file.tmpl

@@ -39,6 +39,26 @@
 		<div class="file-view {{if .IsMarkdown}}markdown{{else if .ReadmeInList}}plain-text{{else if .IsTextFile}}code-view{{end}} has-emoji">
 			{{if or .IsMarkdown .ReadmeInList}}
 				{{if .FileContent}}{{.FileContent | Str2html}}{{end}}
+			{{else if .IsIPyNB}}
+				{{if .FileContent}}
+					<div id="ipython-notebook"></div>
+					<script>
+						var rendered = null;
+						$.getJSON("{{.RawFileLink}}", null, function(notebook_json) {
+							var notebook = nb.parse(notebook_json);
+							rendered = notebook.render();
+							$("#ipython-notebook").append(rendered);
+							$("#ipython-notebook code").each(function(i, block) {
+								$(block).addClass("py").addClass("python");
+								hljs.highlightBlock(block);
+							});
+
+							$("#ipython-notebook .nb-markdown-cell").each(function(i, markdown) {
+								$(markdown).html(marked($(markdown).html()));
+							});
+						});
+					</script>
+				{{end}}
 			{{else if not .IsTextFile}}
 				<div class="view-raw ui center">
 					{{if .IsImageFile}}

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio