瀏覽代碼

Finish minimal example

Steven Silvester 9 年之前
父節點
當前提交
72a07d1867

+ 257 - 0
examples/lab/index.css

@@ -2,6 +2,263 @@
 | Copyright (c) Jupyter Development Team.
 | Distributed under the terms of the Modified BSD License.
 |----------------------------------------------------------------------------*/
+body {
+  margin: 0;
+  padding: 0;
+  background: #EFEFEF;
+  overflow: hidden;
+}
+
+
+.p-AppShell.p-Widget {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+}
+
+
+.p-SideBar {
+  min-width: 36px;
+  max-width: 36px;
+  font-size: 13px;
+  font-family: Helvetica, Arial;
+  background: #F7F7F7;
+}
+
+
+.p-SideBar.p-Widget {
+  overflow: visible;
+}
+
+
+.p-SideBar.p-mod-left {
+  border-right: 1px solid #C0C0C0;
+}
+
+
+.p-SideBar.p-mod-right {
+  border-left: 1px solid #C0C0C0;
+}
+
+
+.p-SideBar-content {
+  height: 35px;
+  transform-origin: 0 0 0;
+}
+
+
+.p-SideBar.p-mod-left > .p-SideBar-content {
+  flex-direction: row-reverse;
+  transform: rotate(-90deg) translateX(-100%);
+}
+
+
+.p-SideBar.p-mod-right > .p-SideBar-content {
+  flex-direction: row;
+  transform: rotate(90deg) translateY(-100%);
+}
+
+
+.p-SideBar-button {
+  padding: 0 18px;
+  line-height: 35px;
+}
+
+
+.p-SideBar-button:hover:not(.p-mod-current) {
+  background: white;
+}
+
+
+.p-SideBar-button.p-mod-current {
+  background: white;
+  min-height: 36px;
+}
+
+
+.p-SideBar.p-mod-left .p-SideBar-button {
+  border-left: 1px solid #C0C0C0;
+}
+
+
+.p-SideBar.p-mod-right .p-SideBar-button {
+  border-right: 1px solid #C0C0C0;
+}
+
+
+#p-left-stack {
+  padding: 5px;
+  background: white;
+}
+
+
+#p-right-stack {
+  padding: 5px;
+  background: white;
+}
+
+
+.red-content {
+  background: #E74C3C;
+  border: 1px solid black;
+  min-width: 100px;
+}
+
+
+.yellow-content {
+  background: #F1C40F;
+  border: 1px solid black;
+  min-width: 100px;
+}
+
+
+.green-content {
+  background: #27AE60;
+  border: 1px solid black;
+  min-width: 100px;
+}
+
+
+.blue-content {
+  background: #3498DB;
+  border: 1px solid black;
+  min-width: 100px;
+}
+
+
+#p-main-dock-panel {
+  padding: 8px;
+}
+
+
+.p-Widget.p-DockSplitPanel {
+  overflow: visible;
+}
+
+.p-DockTabPanel {
+  border-left: 1px solid #C0C0C0;
+  border-right: 1px solid #C0C0C0;
+  border-bottom: 1px solid #B0B0B0;
+  box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.1);
+}
+
+
+.p-DockTabPanel > .p-StackedPanel {
+  padding: 8px;
+  background: white;
+}
+
+
+.p-DockPanel-overlay {
+  background: rgba(64, 151, 234, 0.1);
+  border: 1px dashed #4097EA;
+}
+
+
+.p-DockPanel-overlay.p-mod-root-top,
+.p-DockPanel-overlay.p-mod-root-left,
+.p-DockPanel-overlay.p-mod-root-right,
+.p-DockPanel-overlay.p-mod-root-bottom,
+.p-DockPanel-overlay.p-mod-root-center {
+  border-width: 2px;
+}
+
+
+.p-TabBar {
+  min-height: 24px;
+  max-height: 24px;
+  background: #F7F7F7;
+}
+
+
+/* the child selectors just increase specificity :-( */
+
+.p-TabBar > .p-TabBar-header {
+  flex: 0 0 1px;
+  background: #D0D0D0;
+}
+
+
+.p-TabBar > .p-TabBar-footer {
+  flex: 0 0 1px;
+  background: #C0C0C0;
+}
+
+
+.p-TabBar .p-TabBar-content {
+  min-width: 0;
+  max-height: 22px;
+}
+
+
+.p-TabBar-tab {
+  flex-basis: 125px;
+  min-height: 23px;
+  max-height: 23px;
+  min-width: 35px;
+  margin-left: -1px;
+  border-top: 1px solid #C0C0C0;
+  border-left: 1px solid #C0C0C0;
+  border-right: 1px solid #C0C0C0;
+  padding: 0px 10px;
+  background: #EBEBEB;
+  font: 12px Helvetica, Arial, sans-serif;
+  transform: translateY(-1px);
+}
+
+
+.p-TabBar-tab:last-child {
+  margin-right: -1px;
+}
+
+
+.p-TabBar-tab.p-mod-current {
+  border-top: 1px solid #4097EA;
+  background: white;
+  min-height: 24px;
+  max-height: 24px;
+}
+
+
+.p-TabBar-tab:hover:not(.p-mod-current) {
+  background: #F0F0F0;
+}
+
+
+.p-TabBar-tabIcon,
+.p-TabBar-tabText,
+.p-TabBar-tabCloseIcon {
+  line-height: 22px;
+}
+
+
+.p-TabBar-tab.p-mod-closable > .p-TabBar-tabCloseIcon {
+  margin-left: 4px;
+}
+
+
+.p-TabBar-tab.p-mod-closable > .p-TabBar-tabCloseIcon:before {
+  content: '\f00d';
+  font-family: FontAwesome;
+}
+
+
+.p-TabBar-tab.p-mod-drag-image {
+  min-height: 24px;
+  min-width: 125px;
+  border: none;
+  border-top: 1px solid #4097EA;
+  box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
+  transform: translateX(-40%) translateY(-58%);
+}
+
+
+#p-main-split-panel > .p-SplitPanel-handle {
+  background: #C0C0C0;
+}
+
 
 .p-MenuBar {
   padding-left: 5px;

+ 84 - 0
examples/lab/main.py

@@ -0,0 +1,84 @@
+"""
+Copyright (c) Jupyter Development Team.
+Distributed under the terms of the Modified BSD License.
+"""
+import re
+import subprocess
+import sys
+import threading
+
+import tornado.web
+
+PORT = 8765
+
+
+class MainPageHandler(tornado.web.RequestHandler):
+
+    def initialize(self, base_url, ws_url):
+        self.base_url = base_url
+        self.ws_url = ws_url
+
+    def get(self):
+        return self.render("index.html", static=self.static_url,
+                           base_url=self.base_url, ws_url=self.ws_url)
+
+
+def main(argv):
+
+    url = "http://localhost:%s" % PORT
+
+    nb_command = [sys.executable, '-m', 'notebook', '--no-browser', '--debug',
+                  '--NotebookApp.allow_origin="%s"' % url]
+    nb_server = subprocess.Popen(nb_command, stderr=subprocess.STDOUT,
+                                 stdout=subprocess.PIPE)
+
+    # wait for notebook server to start up
+    while 1:
+        line = nb_server.stdout.readline().decode('utf-8').strip()
+        if not line:
+            continue
+        print(line)
+        if 'Jupyter Notebook is running at:' in line:
+            base_url = re.search('(http.*?)$', line).groups()[0]
+            ws_url = base_url.replace('http', 'ws')
+            break
+
+    while 1:
+        line = nb_server.stdout.readline().decode('utf-8').strip()
+        if not line:
+            continue
+        print(line)
+        if 'Control-C' in line:
+            break
+
+    def print_thread():
+        while 1:
+            line = nb_server.stdout.readline().decode('utf-8').strip()
+            if not line:
+                continue
+            print(line)
+
+    thread = threading.Thread(target=print_thread, daemon=True)
+    thread.start()
+
+    handlers = [
+        (r"/", MainPageHandler, {'base_url': base_url, 'ws_url': ws_url }),
+        (r'/(.*)', tornado.web.StaticFileHandler, {'path': '.'}),
+    ]
+
+    app = tornado.web.Application(handlers, static_path='build',
+                                  template_path='.')
+
+    app.listen(PORT, 'localhost')
+    loop = tornado.ioloop.IOLoop.instance()
+    print('Browse to http://localhost:%s' % PORT)
+    try:
+        loop.start()
+    except KeyboardInterrupt:
+        print(" Shutting down on SIGINT")
+    finally:
+        nb_server.kill()
+        loop.close()
+
+if __name__ == '__main__':
+    main(sys.argv)

+ 3 - 0
examples/lab/webpack.conf.js

@@ -8,6 +8,9 @@ module.exports = {
   resolve: {
     extensions: ['', '.ts', '.js']
   },
+  node: {
+    fs: "empty"
+  },
   module: {
     loaders: [
       { test: /\.ts$/, loader: 'ts-loader' },

+ 0 - 38
src/editor/codemirror-ipython.js

@@ -1,38 +0,0 @@
-// IPython mode is just a slightly altered Python Mode with `?` beeing a extra
-// single operator. Here we define `ipython` mode in the require `python`
-// callback to auto-load python mode, which is more likely not the best things
-// to do, but at least the simple one for now.
-
-(function(mod) {
-  if (typeof exports == "object" && typeof module == "object"){ // CommonJS
-    mod(require("codemirror/lib/codemirror"),
-        require("codemirror/mode/python/python")
-        );
-  } else if (typeof define == "function" && define.amd){ // AMD
-    define(["codemirror/lib/codemirror",
-            "codemirror/mode/python/python"], mod);
-  } else {// Plain browser env
-    mod(CodeMirror);
-  }
-})(function(CodeMirror) {
-    "use strict";
-
-    CodeMirror.defineMode("ipython", function(conf, parserConf) {
-        var pythonConf = {};
-        for (var prop in parserConf) {
-            if (parserConf.hasOwnProperty(prop)) {
-                pythonConf[prop] = parserConf[prop];
-            }
-        }
-        pythonConf.name = 'python';
-        pythonConf.singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!\\?]");
-        if (pythonConf.version === 3) {
-            pythonConf.identifiers = new RegExp("^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*");
-        } else if (pythonConf.version === 2) {
-            pythonConf.identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
-        }
-        return CodeMirror.getMode(conf, pythonConf);
-    }, 'python');
-
-    CodeMirror.defineMIME("text/x-ipython", "ipython");
-})

+ 31 - 0
src/editor/codemirror-ipython.ts

@@ -0,0 +1,31 @@
+// IPython mode is just a slightly altered Python Mode with `?` beeing a extra
+// single operator. Here we define `ipython` mode in the require `python`
+// callback to auto-load python mode, which is more likely not the best things
+// to do, but at least the simple one for now.
+"use strict";
+
+import * as CodeMirror
+  from 'codemirror';
+
+import "codemirror/mode/python/python";
+
+
+CodeMirror.defineMode("ipython", (config: CodeMirror.EditorConfiguration, modeOptions: any) => {
+    var pythonConf: any = {};
+    for (var prop in modeOptions) {
+      if (modeOptions.hasOwnProperty(prop)) {
+        (pythonConf as any)[prop] = (modeOptions as any)[prop];
+      }
+    }
+    pythonConf.name = 'python';
+    pythonConf.singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!\\?]");
+    if (pythonConf.version === 3) {
+      pythonConf.identifiers = new RegExp("^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*");
+    } else if (pythonConf.version === 2) {
+      pythonConf.identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
+    }
+    return CodeMirror.getMode(config, pythonConf);
+}, 'python');
+
+CodeMirror.defineMIME("text/x-ipython", "ipython");
+

+ 1 - 1
src/editor/plugin.ts

@@ -32,7 +32,7 @@ import 'codemirror/mode/javascript/javascript';
 import 'codemirror/mode/julia/julia';
 import 'codemirror/mode/python/python';
 import 'codemirror/mode/r/r';
-import 'codemirror/markdown/markdown';
+import 'codemirror/mode/markdown/markdown';
 import './codemirror-ipython';
 
 

+ 1 - 0
src/filebrowser/plugin.css

@@ -7,6 +7,7 @@
   color: #757575;
   font: 13px Helvetica, Arial, sans-serif;
   height: 500px;
+  min-width: 300px;
 }
 
 

+ 7 - 0
src/filebrowser/plugin.ts

@@ -39,6 +39,12 @@ function register(container: Container): void {
 }
 
 
+export
+function resolve(container: Container): Promise<void> {
+  return container.resolve(FileBrowserProvider).then(() => { return; });
+}
+
+
 /**
  * An implementation of the IFileBrowser provider.
  */
@@ -74,6 +80,7 @@ class FileBrowserProvider implements IFileBrowser {
         newEditor.setModeByFileName(change.newValue.name);
         newEditor.text = change.newValue.content;
         newEditor.title.text = change.newValue.name;
+        this._shell.addToMainArea(newEditor);
       }
     });
   }

+ 1 - 0
src/tsconfig.json

@@ -14,6 +14,7 @@
     "../typings/codemirror/codemirror.d.ts",
     "index.ts",
     "editor/index.ts",
+    "editor/codemirror-ipython.ts",
     "editor/plugin.ts",
     "filebrowser/index.ts",
     "filebrowser/plugin.ts",

+ 3 - 1
typings/codemirror/codemirror.d.ts

@@ -1056,7 +1056,9 @@ declare module CodeMirror {
      * id will be the id for the defined mode. Typically, you should use this second argument to defineMode as your module scope function
      * (modes should not leak anything into the global scope!), i.e. write your whole mode inside this function.
      */
-    function defineMode(id: string, modefactory: ModeFactory<any>): void;
+    function defineMode(id: string, modefactory: ModeFactory<any>, baseMode?: string): void;
+
+    function defineMIME(mime: string, modeSpec: string | modespec): void;
 
     /**
      * The first argument is a configuration object as passed to the mode constructor function, and the second argument