├── .gitignore
├── README.md
├── components
└── font-awesome
│ ├── fonts
│ ├── fontawesome-webfont.svg
│ ├── fontawesome-webfont.ttf
│ └── fontawesome-webfont.woff
│ └── package.json
├── ext
├── codemirror.css
├── codemirror.js
├── cssmode.js
├── font-awesome.min.css
├── javascriptmode.js
├── jquery-2.1.4.min.js
└── pythonmode.js
├── index.html
├── jupyter-js-services
├── config.d.ts
├── config.js
├── contents.d.ts
├── contents.js
├── ikernel.d.ts
├── ikernel.js
├── index.d.ts
├── index.js
├── isession.d.ts
├── isession.js
├── kernel.d.ts
├── kernel.js
├── package.json
├── serialize.d.ts
├── serialize.js
├── session.d.ts
├── session.js
├── test.d.ts
├── test.js
├── utils.d.ts
├── utils.js
├── validate.d.ts
└── validate.js
├── main.py
├── package.json
├── phosphor_demo.gif
├── scripts
└── copycss.js
├── src
├── actions.ts
├── cell.ts
├── celltoolbar.ts
├── codecell.ts
├── codemirror-ipython.js
├── codemirror-ipythongfm.js
├── completer.ts
├── contexthint.ts
├── index.css
├── index.ts
├── ipython.min.css
├── keyboard.ts
├── keyboardmanager.ts
├── style.min.css
├── tooltip.ts
├── tsconfig.json
└── utils.ts
└── typings
├── codemirror
└── codemirror.d.ts
├── es6-collections
└── es6-collections.d.ts
├── es6-container-shim.d.ts
├── es6-dataview.d.ts
├── es6-promise
└── es6-promise.d.ts
├── jquery
└── jquery.d.ts
├── requirejs
└── r.d.ts
└── term.js.d.ts
/.gitignore:
--------------------------------------------------------------------------------
1 | *.suo
2 | *.user
3 | .DS_Store
4 | node_modules
5 | typings/tsd.d.ts
6 | npm-debug.log
7 | test/build
8 | coverage
9 | lib
10 | dist
11 | build
12 | docs
13 | src/*.js
14 | src/*.d.ts
15 | src/*.js.map
16 | notebook
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | This is a proof on concept demonstration of integrating the refactoring work
3 | on the Jupyter Notebook with Phosphor widgets. It is not meant to be a fully
4 | functional notebook. Future development will occur in jupyter/notebook and
5 | related jupyter repositories. Note, the demo assumes you have no other
6 | notebook servers running. Enjoy!
7 |
8 |
9 | To install:
10 |
11 | ```
12 | npm install
13 | npm run build
14 | ```
15 |
16 | Requires the development version of Jupyter Notebook:
17 |
18 | `pip install git+https://github.com/jupyter/notebook`
19 |
20 | To run the demo:
21 |
22 | `python main.py`
23 |
24 |
25 | Demo:
26 |
27 |
28 |
--------------------------------------------------------------------------------
/components/font-awesome/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blink1073/jupyter_demo/906c18f008cd1ca60c440d07a981b8092fe9f3d9/components/font-awesome/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/components/font-awesome/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blink1073/jupyter_demo/906c18f008cd1ca60c440d07a981b8092fe9f3d9/components/font-awesome/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/components/font-awesome/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "font-awesome",
3 | "description": "The iconic font and CSS framework",
4 | "version": "4.4.0",
5 | "style": "css/font-awesome.css",
6 | "keywords": ["font", "awesome", "fontawesome", "icon", "font", "bootstrap"],
7 | "homepage": "http://fontawesome.io/",
8 | "bugs": {
9 | "url" : "http://github.com/FortAwesome/Font-Awesome/issues"
10 | },
11 | "author": {
12 | "name": "Dave Gandy",
13 | "email": "dave@fontawesome.io",
14 | "web": "http://twitter.com/davegandy"
15 | },
16 | "repository": {
17 | "type": "git",
18 | "url": "https://github.com/FortAwesome/Font-Awesome.git"
19 | },
20 | "contributors": [
21 | {
22 | "name": "Rob Madole",
23 | "web": "http://twitter.com/robmadole"
24 | },
25 | {
26 | "name": "Geremia Taglialatela",
27 | "web": "http://twitter.com/gtagliala"
28 | },
29 | {
30 | "name": "Travis Chase",
31 | "web": "http://twitter.com/supercodepoet"
32 | }
33 | ],
34 | "license": "OFL-1.1 AND MIT",
35 | "dependencies": {
36 | },
37 | "engines" : {
38 | "node" : ">=0.10.3"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/ext/codemirror.css:
--------------------------------------------------------------------------------
1 | /* BASICS */
2 |
3 | .CodeMirror {
4 | /* Set height, width, borders, and global font properties here */
5 | font-family: monospace;
6 | height: 300px;
7 | color: black;
8 | }
9 |
10 | /* PADDING */
11 |
12 | .CodeMirror-lines {
13 | padding: 4px 0; /* Vertical padding around content */
14 | }
15 | .CodeMirror pre {
16 | padding: 0 4px; /* Horizontal padding of content */
17 | }
18 |
19 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
20 | background-color: white; /* The little square between H and V scrollbars */
21 | }
22 |
23 | /* GUTTER */
24 |
25 | .CodeMirror-gutters {
26 | border-right: 1px solid #ddd;
27 | background-color: #f7f7f7;
28 | white-space: nowrap;
29 | }
30 | .CodeMirror-linenumbers {}
31 | .CodeMirror-linenumber {
32 | padding: 0 3px 0 5px;
33 | min-width: 20px;
34 | text-align: right;
35 | color: #999;
36 | -moz-box-sizing: content-box;
37 | box-sizing: content-box;
38 | }
39 |
40 | .CodeMirror-guttermarker { color: black; }
41 | .CodeMirror-guttermarker-subtle { color: #999; }
42 |
43 | /* CURSOR */
44 |
45 | .CodeMirror div.CodeMirror-cursor {
46 | border-left: 1px solid black;
47 | }
48 | /* Shown when moving in bi-directional text */
49 | .CodeMirror div.CodeMirror-secondarycursor {
50 | border-left: 1px solid silver;
51 | }
52 | .CodeMirror.cm-fat-cursor div.CodeMirror-cursor {
53 | width: auto;
54 | border: 0;
55 | background: #7e7;
56 | }
57 | .CodeMirror.cm-fat-cursor div.CodeMirror-cursors {
58 | z-index: 1;
59 | }
60 |
61 | .cm-animate-fat-cursor {
62 | width: auto;
63 | border: 0;
64 | -webkit-animation: blink 1.06s steps(1) infinite;
65 | -moz-animation: blink 1.06s steps(1) infinite;
66 | animation: blink 1.06s steps(1) infinite;
67 | }
68 | @-moz-keyframes blink {
69 | 0% { background: #7e7; }
70 | 50% { background: none; }
71 | 100% { background: #7e7; }
72 | }
73 | @-webkit-keyframes blink {
74 | 0% { background: #7e7; }
75 | 50% { background: none; }
76 | 100% { background: #7e7; }
77 | }
78 | @keyframes blink {
79 | 0% { background: #7e7; }
80 | 50% { background: none; }
81 | 100% { background: #7e7; }
82 | }
83 |
84 | /* Can style cursor different in overwrite (non-insert) mode */
85 | div.CodeMirror-overwrite div.CodeMirror-cursor {}
86 |
87 | .cm-tab { display: inline-block; text-decoration: inherit; }
88 |
89 | .CodeMirror-ruler {
90 | border-left: 1px solid #ccc;
91 | position: absolute;
92 | }
93 |
94 | /* DEFAULT THEME */
95 |
96 | .cm-s-default .cm-keyword {color: #708;}
97 | .cm-s-default .cm-atom {color: #219;}
98 | .cm-s-default .cm-number {color: #164;}
99 | .cm-s-default .cm-def {color: #00f;}
100 | .cm-s-default .cm-variable,
101 | .cm-s-default .cm-punctuation,
102 | .cm-s-default .cm-property,
103 | .cm-s-default .cm-operator {}
104 | .cm-s-default .cm-variable-2 {color: #05a;}
105 | .cm-s-default .cm-variable-3 {color: #085;}
106 | .cm-s-default .cm-comment {color: #a50;}
107 | .cm-s-default .cm-string {color: #a11;}
108 | .cm-s-default .cm-string-2 {color: #f50;}
109 | .cm-s-default .cm-meta {color: #555;}
110 | .cm-s-default .cm-qualifier {color: #555;}
111 | .cm-s-default .cm-builtin {color: #30a;}
112 | .cm-s-default .cm-bracket {color: #997;}
113 | .cm-s-default .cm-tag {color: #170;}
114 | .cm-s-default .cm-attribute {color: #00c;}
115 | .cm-s-default .cm-header {color: blue;}
116 | .cm-s-default .cm-quote {color: #090;}
117 | .cm-s-default .cm-hr {color: #999;}
118 | .cm-s-default .cm-link {color: #00c;}
119 |
120 | .cm-negative {color: #d44;}
121 | .cm-positive {color: #292;}
122 | .cm-header, .cm-strong {font-weight: bold;}
123 | .cm-em {font-style: italic;}
124 | .cm-link {text-decoration: underline;}
125 | .cm-strikethrough {text-decoration: line-through;}
126 |
127 | .cm-s-default .cm-error {color: #f00;}
128 | .cm-invalidchar {color: #f00;}
129 |
130 | /* Default styles for common addons */
131 |
132 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
133 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
134 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
135 | .CodeMirror-activeline-background {background: #e8f2ff;}
136 |
137 | /* STOP */
138 |
139 | /* The rest of this file contains styles related to the mechanics of
140 | the editor. You probably shouldn't touch them. */
141 |
142 | .CodeMirror {
143 | position: relative;
144 | overflow: hidden;
145 | background: white;
146 | }
147 |
148 | .CodeMirror-scroll {
149 | overflow: scroll !important; /* Things will break if this is overridden */
150 | /* 30px is the magic margin used to hide the element's real scrollbars */
151 | /* See overflow: hidden in .CodeMirror */
152 | margin-bottom: -30px; margin-right: -30px;
153 | padding-bottom: 30px;
154 | height: 100%;
155 | outline: none; /* Prevent dragging from highlighting the element */
156 | position: relative;
157 | -moz-box-sizing: content-box;
158 | box-sizing: content-box;
159 | }
160 | .CodeMirror-sizer {
161 | position: relative;
162 | border-right: 30px solid transparent;
163 | -moz-box-sizing: content-box;
164 | box-sizing: content-box;
165 | }
166 |
167 | /* The fake, visible scrollbars. Used to force redraw during scrolling
168 | before actuall scrolling happens, thus preventing shaking and
169 | flickering artifacts. */
170 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
171 | position: absolute;
172 | z-index: 6;
173 | display: none;
174 | }
175 | .CodeMirror-vscrollbar {
176 | right: 0; top: 0;
177 | overflow-x: hidden;
178 | overflow-y: scroll;
179 | }
180 | .CodeMirror-hscrollbar {
181 | bottom: 0; left: 0;
182 | overflow-y: hidden;
183 | overflow-x: scroll;
184 | }
185 | .CodeMirror-scrollbar-filler {
186 | right: 0; bottom: 0;
187 | }
188 | .CodeMirror-gutter-filler {
189 | left: 0; bottom: 0;
190 | }
191 |
192 | .CodeMirror-gutters {
193 | position: absolute; left: 0; top: 0;
194 | z-index: 3;
195 | }
196 | .CodeMirror-gutter {
197 | white-space: normal;
198 | height: 100%;
199 | -moz-box-sizing: content-box;
200 | box-sizing: content-box;
201 | display: inline-block;
202 | margin-bottom: -30px;
203 | /* Hack to make IE7 behave */
204 | *zoom:1;
205 | *display:inline;
206 | }
207 | .CodeMirror-gutter-wrapper {
208 | position: absolute;
209 | z-index: 4;
210 | height: 100%;
211 | }
212 | .CodeMirror-gutter-elt {
213 | position: absolute;
214 | cursor: default;
215 | z-index: 4;
216 | }
217 | .CodeMirror-gutter-wrapper {
218 | -webkit-user-select: none;
219 | -moz-user-select: none;
220 | user-select: none;
221 | }
222 |
223 | .CodeMirror-lines {
224 | cursor: text;
225 | min-height: 1px; /* prevents collapsing before first draw */
226 | }
227 | .CodeMirror pre {
228 | /* Reset some styles that the rest of the page might have set */
229 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
230 | border-width: 0;
231 | background: transparent;
232 | font-family: inherit;
233 | font-size: inherit;
234 | margin: 0;
235 | white-space: pre;
236 | word-wrap: normal;
237 | line-height: inherit;
238 | color: inherit;
239 | z-index: 2;
240 | position: relative;
241 | overflow: visible;
242 | -webkit-tap-highlight-color: transparent;
243 | }
244 | .CodeMirror-wrap pre {
245 | word-wrap: break-word;
246 | white-space: pre-wrap;
247 | word-break: normal;
248 | }
249 |
250 | .CodeMirror-linebackground {
251 | position: absolute;
252 | left: 0; right: 0; top: 0; bottom: 0;
253 | z-index: 0;
254 | }
255 |
256 | .CodeMirror-linewidget {
257 | position: relative;
258 | z-index: 2;
259 | overflow: auto;
260 | }
261 |
262 | .CodeMirror-widget {}
263 |
264 | .CodeMirror-code {
265 | outline: none;
266 | }
267 |
268 | .CodeMirror-measure {
269 | position: absolute;
270 | width: 100%;
271 | height: 0;
272 | overflow: hidden;
273 | visibility: hidden;
274 | }
275 | .CodeMirror-measure pre { position: static; }
276 |
277 | .CodeMirror div.CodeMirror-cursor {
278 | position: absolute;
279 | border-right: none;
280 | width: 0;
281 | }
282 |
283 | div.CodeMirror-cursors {
284 | visibility: hidden;
285 | position: relative;
286 | z-index: 3;
287 | }
288 | .CodeMirror-focused div.CodeMirror-cursors {
289 | visibility: visible;
290 | }
291 |
292 | .CodeMirror-selected { background: #d9d9d9; }
293 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
294 | .CodeMirror-crosshair { cursor: crosshair; }
295 | .CodeMirror ::selection { background: #d7d4f0; }
296 | .CodeMirror ::-moz-selection { background: #d7d4f0; }
297 |
298 | .cm-searching {
299 | background: #ffa;
300 | background: rgba(255, 255, 0, .4);
301 | }
302 |
303 | /* IE7 hack to prevent it from returning funny offsetTops on the spans */
304 | .CodeMirror span { *vertical-align: text-bottom; }
305 |
306 | /* Used to force a border model for a node */
307 | .cm-force-border { padding-right: .1px; }
308 |
309 | @media print {
310 | /* Hide the cursor when printing */
311 | .CodeMirror div.CodeMirror-cursors {
312 | visibility: hidden;
313 | }
314 | }
315 |
316 | /* See issue #2901 */
317 | .cm-tab-wrap-hack:after { content: ''; }
318 |
319 | /* Help users use markselection to safely style text background */
320 | span.CodeMirror-selectedtext { background: none; }
321 |
--------------------------------------------------------------------------------
/ext/pythonmode.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: http://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | function wordRegexp(words) {
15 | return new RegExp("^((" + words.join(")|(") + "))\\b");
16 | }
17 |
18 | var wordOperators = wordRegexp(["and", "or", "not", "is"]);
19 | var commonKeywords = ["as", "assert", "break", "class", "continue",
20 | "def", "del", "elif", "else", "except", "finally",
21 | "for", "from", "global", "if", "import",
22 | "lambda", "pass", "raise", "return",
23 | "try", "while", "with", "yield", "in"];
24 | var commonBuiltins = ["abs", "all", "any", "bin", "bool", "bytearray", "callable", "chr",
25 | "classmethod", "compile", "complex", "delattr", "dict", "dir", "divmod",
26 | "enumerate", "eval", "filter", "float", "format", "frozenset",
27 | "getattr", "globals", "hasattr", "hash", "help", "hex", "id",
28 | "input", "int", "isinstance", "issubclass", "iter", "len",
29 | "list", "locals", "map", "max", "memoryview", "min", "next",
30 | "object", "oct", "open", "ord", "pow", "property", "range",
31 | "repr", "reversed", "round", "set", "setattr", "slice",
32 | "sorted", "staticmethod", "str", "sum", "super", "tuple",
33 | "type", "vars", "zip", "__import__", "NotImplemented",
34 | "Ellipsis", "__debug__"];
35 | var py2 = {builtins: ["apply", "basestring", "buffer", "cmp", "coerce", "execfile",
36 | "file", "intern", "long", "raw_input", "reduce", "reload",
37 | "unichr", "unicode", "xrange", "False", "True", "None"],
38 | keywords: ["exec", "print"]};
39 | var py3 = {builtins: ["ascii", "bytes", "exec", "print"],
40 | keywords: ["nonlocal", "False", "True", "None"]};
41 |
42 | CodeMirror.registerHelper("hintWords", "python", commonKeywords.concat(commonBuiltins));
43 |
44 | function top(state) {
45 | return state.scopes[state.scopes.length - 1];
46 | }
47 |
48 | CodeMirror.defineMode("python", function(conf, parserConf) {
49 | var ERRORCLASS = "error";
50 |
51 | var singleDelimiters = parserConf.singleDelimiters || new RegExp("^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]");
52 | var doubleOperators = parserConf.doubleOperators || new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
53 | var doubleDelimiters = parserConf.doubleDelimiters || new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
54 | var tripleDelimiters = parserConf.tripleDelimiters || new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
55 |
56 | if (parserConf.version && parseInt(parserConf.version, 10) == 3){
57 | // since http://legacy.python.org/dev/peps/pep-0465/ @ is also an operator
58 | var singleOperators = parserConf.singleOperators || new RegExp("^[\\+\\-\\*/%&|\\^~<>!@]");
59 | var identifiers = parserConf.identifiers|| new RegExp("^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*");
60 | } else {
61 | var singleOperators = parserConf.singleOperators || new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
62 | var identifiers = parserConf.identifiers|| new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
63 | }
64 |
65 | var hangingIndent = parserConf.hangingIndent || conf.indentUnit;
66 |
67 | var myKeywords = commonKeywords, myBuiltins = commonBuiltins;
68 | if(parserConf.extra_keywords != undefined){
69 | myKeywords = myKeywords.concat(parserConf.extra_keywords);
70 | }
71 | if(parserConf.extra_builtins != undefined){
72 | myBuiltins = myBuiltins.concat(parserConf.extra_builtins);
73 | }
74 | if (parserConf.version && parseInt(parserConf.version, 10) == 3) {
75 | myKeywords = myKeywords.concat(py3.keywords);
76 | myBuiltins = myBuiltins.concat(py3.builtins);
77 | var stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i");
78 | } else {
79 | myKeywords = myKeywords.concat(py2.keywords);
80 | myBuiltins = myBuiltins.concat(py2.builtins);
81 | var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i");
82 | }
83 | var keywords = wordRegexp(myKeywords);
84 | var builtins = wordRegexp(myBuiltins);
85 |
86 | // tokenizers
87 | function tokenBase(stream, state) {
88 | // Handle scope changes
89 | if (stream.sol() && top(state).type == "py") {
90 | var scopeOffset = top(state).offset;
91 | if (stream.eatSpace()) {
92 | var lineOffset = stream.indentation();
93 | if (lineOffset > scopeOffset)
94 | pushScope(stream, state, "py");
95 | else if (lineOffset < scopeOffset && dedent(stream, state))
96 | state.errorToken = true;
97 | return null;
98 | } else {
99 | var style = tokenBaseInner(stream, state);
100 | if (scopeOffset > 0 && dedent(stream, state))
101 | style += " " + ERRORCLASS;
102 | return style;
103 | }
104 | }
105 | return tokenBaseInner(stream, state);
106 | }
107 |
108 | function tokenBaseInner(stream, state) {
109 | if (stream.eatSpace()) return null;
110 |
111 | var ch = stream.peek();
112 |
113 | // Handle Comments
114 | if (ch == "#") {
115 | stream.skipToEnd();
116 | return "comment";
117 | }
118 |
119 | // Handle Number Literals
120 | if (stream.match(/^[0-9\.]/, false)) {
121 | var floatLiteral = false;
122 | // Floats
123 | if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; }
124 | if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; }
125 | if (stream.match(/^\.\d+/)) { floatLiteral = true; }
126 | if (floatLiteral) {
127 | // Float literals may be "imaginary"
128 | stream.eat(/J/i);
129 | return "number";
130 | }
131 | // Integers
132 | var intLiteral = false;
133 | // Hex
134 | if (stream.match(/^0x[0-9a-f]+/i)) intLiteral = true;
135 | // Binary
136 | if (stream.match(/^0b[01]+/i)) intLiteral = true;
137 | // Octal
138 | if (stream.match(/^0o[0-7]+/i)) intLiteral = true;
139 | // Decimal
140 | if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) {
141 | // Decimal literals may be "imaginary"
142 | stream.eat(/J/i);
143 | // TODO - Can you have imaginary longs?
144 | intLiteral = true;
145 | }
146 | // Zero by itself with no other piece of number.
147 | if (stream.match(/^0(?![\dx])/i)) intLiteral = true;
148 | if (intLiteral) {
149 | // Integer literals may be "long"
150 | stream.eat(/L/i);
151 | return "number";
152 | }
153 | }
154 |
155 | // Handle Strings
156 | if (stream.match(stringPrefixes)) {
157 | state.tokenize = tokenStringFactory(stream.current());
158 | return state.tokenize(stream, state);
159 | }
160 |
161 | // Handle operators and Delimiters
162 | if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters))
163 | return null;
164 |
165 | if (stream.match(doubleOperators)
166 | || stream.match(singleOperators)
167 | || stream.match(wordOperators))
168 | return "operator";
169 |
170 | if (stream.match(singleDelimiters))
171 | return null;
172 |
173 | if (stream.match(keywords))
174 | return "keyword";
175 |
176 | if (stream.match(builtins))
177 | return "builtin";
178 |
179 | if (stream.match(/^(self|cls)\b/))
180 | return "variable-2";
181 |
182 | if (stream.match(identifiers)) {
183 | if (state.lastToken == "def" || state.lastToken == "class")
184 | return "def";
185 | return "variable";
186 | }
187 |
188 | // Handle non-detected items
189 | stream.next();
190 | return ERRORCLASS;
191 | }
192 |
193 | function tokenStringFactory(delimiter) {
194 | while ("rub".indexOf(delimiter.charAt(0).toLowerCase()) >= 0)
195 | delimiter = delimiter.substr(1);
196 |
197 | var singleline = delimiter.length == 1;
198 | var OUTCLASS = "string";
199 |
200 | function tokenString(stream, state) {
201 | while (!stream.eol()) {
202 | stream.eatWhile(/[^'"\\]/);
203 | if (stream.eat("\\")) {
204 | stream.next();
205 | if (singleline && stream.eol())
206 | return OUTCLASS;
207 | } else if (stream.match(delimiter)) {
208 | state.tokenize = tokenBase;
209 | return OUTCLASS;
210 | } else {
211 | stream.eat(/['"]/);
212 | }
213 | }
214 | if (singleline) {
215 | if (parserConf.singleLineStringErrors)
216 | return ERRORCLASS;
217 | else
218 | state.tokenize = tokenBase;
219 | }
220 | return OUTCLASS;
221 | }
222 | tokenString.isString = true;
223 | return tokenString;
224 | }
225 |
226 | function pushScope(stream, state, type) {
227 | var offset = 0, align = null;
228 | if (type == "py") {
229 | while (top(state).type != "py")
230 | state.scopes.pop();
231 | }
232 | offset = top(state).offset + (type == "py" ? conf.indentUnit : hangingIndent);
233 | if (type != "py" && !stream.match(/^(\s|#.*)*$/, false))
234 | align = stream.column() + 1;
235 | state.scopes.push({offset: offset, type: type, align: align});
236 | }
237 |
238 | function dedent(stream, state) {
239 | var indented = stream.indentation();
240 | while (top(state).offset > indented) {
241 | if (top(state).type != "py") return true;
242 | state.scopes.pop();
243 | }
244 | return top(state).offset != indented;
245 | }
246 |
247 | function tokenLexer(stream, state) {
248 | var style = state.tokenize(stream, state);
249 | var current = stream.current();
250 |
251 | // Handle '.' connected identifiers
252 | if (current == ".") {
253 | style = stream.match(identifiers, false) ? null : ERRORCLASS;
254 | if (style == null && state.lastStyle == "meta") {
255 | // Apply 'meta' style to '.' connected identifiers when
256 | // appropriate.
257 | style = "meta";
258 | }
259 | return style;
260 | }
261 |
262 | // Handle decorators
263 | if (current == "@"){
264 | if(parserConf.version && parseInt(parserConf.version, 10) == 3){
265 | return stream.match(identifiers, false) ? "meta" : "operator";
266 | } else {
267 | return stream.match(identifiers, false) ? "meta" : ERRORCLASS;
268 | }
269 | }
270 |
271 | if ((style == "variable" || style == "builtin")
272 | && state.lastStyle == "meta")
273 | style = "meta";
274 |
275 | // Handle scope changes.
276 | if (current == "pass" || current == "return")
277 | state.dedent += 1;
278 |
279 | if (current == "lambda") state.lambda = true;
280 | if (current == ":" && !state.lambda && top(state).type == "py")
281 | pushScope(stream, state, "py");
282 |
283 | var delimiter_index = current.length == 1 ? "[({".indexOf(current) : -1;
284 | if (delimiter_index != -1)
285 | pushScope(stream, state, "])}".slice(delimiter_index, delimiter_index+1));
286 |
287 | delimiter_index = "])}".indexOf(current);
288 | if (delimiter_index != -1) {
289 | if (top(state).type == current) state.scopes.pop();
290 | else return ERRORCLASS;
291 | }
292 | if (state.dedent > 0 && stream.eol() && top(state).type == "py") {
293 | if (state.scopes.length > 1) state.scopes.pop();
294 | state.dedent -= 1;
295 | }
296 |
297 | return style;
298 | }
299 |
300 | var external = {
301 | startState: function(basecolumn) {
302 | return {
303 | tokenize: tokenBase,
304 | scopes: [{offset: basecolumn || 0, type: "py", align: null}],
305 | lastStyle: null,
306 | lastToken: null,
307 | lambda: false,
308 | dedent: 0
309 | };
310 | },
311 |
312 | token: function(stream, state) {
313 | var addErr = state.errorToken;
314 | if (addErr) state.errorToken = false;
315 | var style = tokenLexer(stream, state);
316 |
317 | state.lastStyle = style;
318 |
319 | var current = stream.current();
320 | if (current && style)
321 | state.lastToken = current;
322 |
323 | if (stream.eol() && state.lambda)
324 | state.lambda = false;
325 | return addErr ? style + " " + ERRORCLASS : style;
326 | },
327 |
328 | indent: function(state, textAfter) {
329 | if (state.tokenize != tokenBase)
330 | return state.tokenize.isString ? CodeMirror.Pass : 0;
331 |
332 | var scope = top(state);
333 | var closing = textAfter && textAfter.charAt(0) == scope.type;
334 | if (scope.align != null)
335 | return scope.align - (closing ? 1 : 0);
336 | else if (closing && state.scopes.length > 1)
337 | return state.scopes[state.scopes.length - 2].offset;
338 | else
339 | return scope.offset;
340 | },
341 |
342 | lineComment: "#",
343 | fold: "indent"
344 | };
345 | return external;
346 | });
347 |
348 | CodeMirror.defineMIME("text/x-python", "python");
349 |
350 | var words = function(str) { return str.split(" "); };
351 |
352 | CodeMirror.defineMIME("text/x-cython", {
353 | name: "python",
354 | extra_keywords: words("by cdef cimport cpdef ctypedef enum except"+
355 | "extern gil include nogil property public"+
356 | "readonly struct union DEF IF ELIF ELSE")
357 | });
358 |
359 | });
360 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Jupyter Demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/jupyter-js-services/config.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Configurable data section.
3 | */
4 | export declare class ConfigSection {
5 | /**
6 | * Create a config section.
7 | */
8 | constructor(sectionName: string, baseUrl: string);
9 | /**
10 | * Get the data for this section.
11 | */
12 | data: any;
13 | /**
14 | * Promose fullfilled when the config section is first loaded.
15 | */
16 | onLoaded: Promise;
17 | /**
18 | * Retrieve the data for this section.
19 | */
20 | load(): Promise;
21 | /**
22 | * Modify the config values stored. Update the local data immediately,
23 | * send the change to the server, and use the updated data from the server
24 | * when the reply comes.
25 | */
26 | update(newdata: any): Promise;
27 | /**
28 | * Handle a finished load, fulfilling the onLoaded promise on the first call.
29 | */
30 | private _loadDone();
31 | private _url;
32 | private _data;
33 | private _loaded;
34 | private _oneLoadFinished;
35 | private _finishFirstLoad;
36 | }
37 | /**
38 | * Configurable object with defaults.
39 | */
40 | export declare class ConfigWithDefaults {
41 | /**
42 | * Create a new config with defaults.
43 | */
44 | constructor(section: ConfigSection, defaults: any, classname?: string);
45 | /**
46 | * Wait for config to have loaded, then get a value or the default.
47 | *
48 | * Note: section.load() must be called somewhere else.
49 | */
50 | get(key: string): Promise;
51 | /**
52 | * Return a config value. If config is not yet loaded, return the default
53 | * instead of waiting for it to load.
54 | */
55 | getSync(key: string): any;
56 | /**
57 | * Set a config value. Send the update to the server, and change our
58 | * local copy of the data immediately.
59 | */
60 | set(key: string, value: any): Promise;
61 | /**
62 | * Get data from the Section with our classname, if available.
63 | * If we have no classname, get all of the data in the Section
64 | */
65 | private _classData();
66 | private _section;
67 | private _defaults;
68 | private _className;
69 | }
70 |
--------------------------------------------------------------------------------
/jupyter-js-services/config.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Jupyter Development Team.
2 | // Distributed under the terms of the Modified BSD License.
3 | var utils = require('./utils');
4 | /**
5 | * The url for the config service.
6 | */
7 | var SERVICE_CONFIG_URL = 'api/config';
8 | /**
9 | * Configurable data section.
10 | */
11 | var ConfigSection = (function () {
12 | /**
13 | * Create a config section.
14 | */
15 | function ConfigSection(sectionName, baseUrl) {
16 | var _this = this;
17 | this._url = "unknown";
18 | this._data = {};
19 | this._loaded = null;
20 | this._oneLoadFinished = false;
21 | this._finishFirstLoad = null;
22 | this._url = utils.urlJoinEncode(baseUrl, SERVICE_CONFIG_URL, sectionName);
23 | this._loaded = new Promise(function (resolve, reject) {
24 | _this._finishFirstLoad = resolve;
25 | });
26 | }
27 | Object.defineProperty(ConfigSection.prototype, "data", {
28 | /**
29 | * Get the data for this section.
30 | */
31 | get: function () {
32 | return this._data;
33 | },
34 | enumerable: true,
35 | configurable: true
36 | });
37 | Object.defineProperty(ConfigSection.prototype, "onLoaded", {
38 | /**
39 | * Promose fullfilled when the config section is first loaded.
40 | */
41 | get: function () {
42 | return this._loaded;
43 | },
44 | enumerable: true,
45 | configurable: true
46 | });
47 | /**
48 | * Retrieve the data for this section.
49 | */
50 | ConfigSection.prototype.load = function () {
51 | var _this = this;
52 | return utils.ajaxRequest(this._url, {
53 | method: "GET",
54 | dataType: "json",
55 | }).then(function (success) {
56 | if (success.xhr.status !== 200) {
57 | throw Error('Invalid Status: ' + success.xhr.status);
58 | }
59 | _this._data = success.data;
60 | _this._loadDone();
61 | return _this._data;
62 | });
63 | };
64 | /**
65 | * Modify the config values stored. Update the local data immediately,
66 | * send the change to the server, and use the updated data from the server
67 | * when the reply comes.
68 | */
69 | ConfigSection.prototype.update = function (newdata) {
70 | var _this = this;
71 | this._data = utils.extend(this._data, newdata);
72 | return utils.ajaxRequest(this._url, {
73 | method: "PATCH",
74 | data: JSON.stringify(newdata),
75 | dataType: "json",
76 | contentType: 'application/json',
77 | }).then(function (success) {
78 | if (success.xhr.status !== 200) {
79 | throw Error('Invalid Status: ' + success.xhr.status);
80 | }
81 | _this._data = success.data;
82 | _this._loadDone();
83 | return _this._data;
84 | });
85 | };
86 | /**
87 | * Handle a finished load, fulfilling the onLoaded promise on the first call.
88 | */
89 | ConfigSection.prototype._loadDone = function () {
90 | if (!this._oneLoadFinished) {
91 | this._oneLoadFinished = true;
92 | this._finishFirstLoad(this._data);
93 | }
94 | };
95 | return ConfigSection;
96 | })();
97 | exports.ConfigSection = ConfigSection;
98 | /**
99 | * Configurable object with defaults.
100 | */
101 | var ConfigWithDefaults = (function () {
102 | /**
103 | * Create a new config with defaults.
104 | */
105 | function ConfigWithDefaults(section, defaults, classname) {
106 | this._section = null;
107 | this._defaults = null;
108 | this._className = "unknown";
109 | this._section = section;
110 | this._defaults = defaults;
111 | this._className = classname;
112 | }
113 | /**
114 | * Wait for config to have loaded, then get a value or the default.
115 | *
116 | * Note: section.load() must be called somewhere else.
117 | */
118 | ConfigWithDefaults.prototype.get = function (key) {
119 | var _this = this;
120 | var that = this;
121 | return this._section.onLoaded.then(function () {
122 | return _this._classData()[key] || _this._defaults[key];
123 | });
124 | };
125 | /**
126 | * Return a config value. If config is not yet loaded, return the default
127 | * instead of waiting for it to load.
128 | */
129 | ConfigWithDefaults.prototype.getSync = function (key) {
130 | return this._classData()[key] || this._defaults[key];
131 | };
132 | /**
133 | * Set a config value. Send the update to the server, and change our
134 | * local copy of the data immediately.
135 | */
136 | ConfigWithDefaults.prototype.set = function (key, value) {
137 | var d = {};
138 | d[key] = value;
139 | if (this._className) {
140 | var d2 = {};
141 | d2[this._className] = d;
142 | return this._section.update(d2);
143 | }
144 | else {
145 | return this._section.update(d);
146 | }
147 | };
148 | /**
149 | * Get data from the Section with our classname, if available.
150 | * If we have no classname, get all of the data in the Section
151 | */
152 | ConfigWithDefaults.prototype._classData = function () {
153 | if (this._className) {
154 | return this._section.data[this._className] || {};
155 | }
156 | else {
157 | return this._section.data;
158 | }
159 | };
160 | return ConfigWithDefaults;
161 | })();
162 | exports.ConfigWithDefaults = ConfigWithDefaults;
163 | //# sourceMappingURL=config.js.map
--------------------------------------------------------------------------------
/jupyter-js-services/contents.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Options for a contents object.
3 | */
4 | export interface IContentsOpts {
5 | type?: string;
6 | format?: string;
7 | content?: any;
8 | ext?: string;
9 | name?: string;
10 | }
11 | /**
12 | * Contents model.
13 | */
14 | export interface IContentsModel {
15 | name: string;
16 | path: string;
17 | type: string;
18 | writable?: boolean;
19 | created: string;
20 | last_modified: string;
21 | mimetype: string;
22 | content: string;
23 | format: string;
24 | }
25 | /**
26 | * Checkpoint model.
27 | */
28 | export interface ICheckpointModel {
29 | id: string;
30 | last_modified: string;
31 | }
32 | /**
33 | * Interface that a content manager should implement.
34 | **/
35 | export interface IContents {
36 | get(path: string, type: string, options: IContentsOpts): Promise;
37 | newUntitled(path: string, options: IContentsOpts): Promise;
38 | delete(path: string): Promise;
39 | rename(path: string, newPath: string): Promise;
40 | save(path: string, model: any): Promise;
41 | listContents(path: string): Promise;
42 | copy(path: string, toDir: string): Promise;
43 | createCheckpoint(path: string): Promise;
44 | restoreCheckpoint(path: string, checkpointID: string): Promise;
45 | deleteCheckpoint(path: string, checkpointID: string): Promise;
46 | listCheckpoints(path: string): Promise;
47 | }
48 | /**
49 | * A contents handle passing file operations to the back-end.
50 | * This includes checkpointing with the normal file operations.
51 | */
52 | export declare class Contents implements IContents {
53 | /**
54 | * Create a new contents object.
55 | */
56 | constructor(baseUrl: string);
57 | /**
58 | * Get a file or directory.
59 | */
60 | get(path: string, options: IContentsOpts): Promise;
61 | /**
62 | * Create a new untitled file or directory in the specified directory path.
63 | */
64 | newUntitled(path: string, options?: IContentsOpts): Promise;
65 | /**
66 | * Delete a file.
67 | */
68 | delete(path: string): Promise;
69 | /**
70 | * Rename a file.
71 | */
72 | rename(path: string, newPath: string): Promise;
73 | /**
74 | * Save a file.
75 | */
76 | save(path: string, model: IContentsOpts): Promise;
77 | /**
78 | * Copy a file into a given directory via POST
79 | * The server will select the name of the copied file.
80 | */
81 | copy(fromFile: string, toDir: string): Promise;
82 | /**
83 | * Create a checkpoint for a file.
84 | */
85 | createCheckpoint(path: string): Promise;
86 | /**
87 | * List available checkpoints for a file.
88 | */
89 | listCheckpoints(path: string): Promise;
90 | /**
91 | * Restore a file to a known checkpoint state.
92 | */
93 | restoreCheckpoint(path: string, checkpointID: string): Promise;
94 | /**
95 | * Delete a checkpoint for a file.
96 | */
97 | deleteCheckpoint(path: string, checkpointID: string): Promise;
98 | /**
99 | * List notebooks and directories at a given path.
100 | */
101 | listContents(path: string): Promise;
102 | /**
103 | * Get an REST url for this file given a path.
104 | */
105 | private _getUrl(...args);
106 | private _apiUrl;
107 | }
108 |
--------------------------------------------------------------------------------
/jupyter-js-services/contents.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Jupyter Development Team.
2 | // Distributed under the terms of the Modified BSD License.
3 | var utils = require('./utils');
4 | /**
5 | * The url for the contents service.
6 | */
7 | var SERVICE_CONTENTS_URL = 'api/contents';
8 | /**
9 | * A contents handle passing file operations to the back-end.
10 | * This includes checkpointing with the normal file operations.
11 | */
12 | var Contents = (function () {
13 | /**
14 | * Create a new contents object.
15 | */
16 | function Contents(baseUrl) {
17 | this._apiUrl = "unknown";
18 | this._apiUrl = utils.urlPathJoin(baseUrl, SERVICE_CONTENTS_URL);
19 | }
20 | /**
21 | * Get a file or directory.
22 | */
23 | Contents.prototype.get = function (path, options) {
24 | var settings = {
25 | method: "GET",
26 | dataType: "json",
27 | };
28 | var url = this._getUrl(path);
29 | var params = {};
30 | if (options.type) {
31 | params.type = options.type;
32 | }
33 | if (options.format) {
34 | params.format = options.format;
35 | }
36 | if (options.content === false) {
37 | params.content = '0';
38 | }
39 | url = url + utils.jsonToQueryString(params);
40 | return utils.ajaxRequest(url, settings).then(function (success) {
41 | if (success.xhr.status !== 200) {
42 | throw Error('Invalid Status: ' + success.xhr.status);
43 | }
44 | validateContentsModel(success.data);
45 | return success.data;
46 | });
47 | };
48 | /**
49 | * Create a new untitled file or directory in the specified directory path.
50 | */
51 | Contents.prototype.newUntitled = function (path, options) {
52 | var settings = {
53 | method: "POST",
54 | dataType: "json",
55 | };
56 | if (options) {
57 | var data = JSON.stringify({
58 | ext: options.ext,
59 | type: options.type
60 | });
61 | settings.data = data;
62 | settings.contentType = 'application/json';
63 | }
64 | var url = this._getUrl(path);
65 | return utils.ajaxRequest(url, settings).then(function (success) {
66 | if (success.xhr.status !== 201) {
67 | throw Error('Invalid Status: ' + success.xhr.status);
68 | }
69 | validateContentsModel(success.data);
70 | return success.data;
71 | });
72 | };
73 | /**
74 | * Delete a file.
75 | */
76 | Contents.prototype.delete = function (path) {
77 | var settings = {
78 | method: "DELETE",
79 | dataType: "json",
80 | };
81 | var url = this._getUrl(path);
82 | return utils.ajaxRequest(url, settings).then(function (success) {
83 | if (success.xhr.status !== 204) {
84 | throw Error('Invalid Status: ' + success.xhr.status);
85 | }
86 | }, // Translate certain errors to more specific ones.
87 | function (error) {
88 | // TODO: update IPEP27 to specify errors more precisely, so
89 | // that error types can be detected here with certainty.
90 | if (error.xhr.status === 400) {
91 | throw new Error('Directory not found');
92 | }
93 | throw error;
94 | });
95 | };
96 | /**
97 | * Rename a file.
98 | */
99 | Contents.prototype.rename = function (path, newPath) {
100 | var data = { path: newPath };
101 | var settings = {
102 | method: "PATCH",
103 | data: JSON.stringify(data),
104 | dataType: "json",
105 | contentType: 'application/json',
106 | };
107 | var url = this._getUrl(path);
108 | return utils.ajaxRequest(url, settings).then(function (success) {
109 | if (success.xhr.status !== 200) {
110 | throw Error('Invalid Status: ' + success.xhr.status);
111 | }
112 | validateContentsModel(success.data);
113 | return success.data;
114 | });
115 | };
116 | /**
117 | * Save a file.
118 | */
119 | Contents.prototype.save = function (path, model) {
120 | var settings = {
121 | method: "PUT",
122 | dataType: "json",
123 | data: JSON.stringify(model),
124 | contentType: 'application/json',
125 | };
126 | var url = this._getUrl(path);
127 | return utils.ajaxRequest(url, settings).then(function (success) {
128 | // will return 200 for an existing file and 201 for a new file
129 | if (success.xhr.status !== 200 && success.xhr.status !== 201) {
130 | throw Error('Invalid Status: ' + success.xhr.status);
131 | }
132 | validateContentsModel(success.data);
133 | return success.data;
134 | });
135 | };
136 | /**
137 | * Copy a file into a given directory via POST
138 | * The server will select the name of the copied file.
139 | */
140 | Contents.prototype.copy = function (fromFile, toDir) {
141 | var settings = {
142 | method: "POST",
143 | data: JSON.stringify({ copy_from: fromFile }),
144 | contentType: 'application/json',
145 | dataType: "json",
146 | };
147 | var url = this._getUrl(toDir);
148 | return utils.ajaxRequest(url, settings).then(function (success) {
149 | if (success.xhr.status !== 201) {
150 | throw Error('Invalid Status: ' + success.xhr.status);
151 | }
152 | validateContentsModel(success.data);
153 | return success.data;
154 | });
155 | };
156 | /**
157 | * Create a checkpoint for a file.
158 | */
159 | Contents.prototype.createCheckpoint = function (path) {
160 | var settings = {
161 | method: "POST",
162 | dataType: "json",
163 | };
164 | var url = this._getUrl(path, 'checkpoints');
165 | return utils.ajaxRequest(url, settings).then(function (success) {
166 | if (success.xhr.status !== 201) {
167 | throw Error('Invalid Status: ' + success.xhr.status);
168 | }
169 | validateCheckpointModel(success.data);
170 | return success.data;
171 | });
172 | };
173 | /**
174 | * List available checkpoints for a file.
175 | */
176 | Contents.prototype.listCheckpoints = function (path) {
177 | var settings = {
178 | method: "GET",
179 | dataType: "json",
180 | };
181 | var url = this._getUrl(path, 'checkpoints');
182 | return utils.ajaxRequest(url, settings).then(function (success) {
183 | if (success.xhr.status !== 200) {
184 | throw Error('Invalid Status: ' + success.xhr.status);
185 | }
186 | if (!Array.isArray(success.data)) {
187 | throw Error('Invalid Checkpoint list');
188 | }
189 | for (var i = 0; i < success.data.length; i++) {
190 | validateCheckpointModel(success.data[i]);
191 | }
192 | return success.data;
193 | });
194 | };
195 | /**
196 | * Restore a file to a known checkpoint state.
197 | */
198 | Contents.prototype.restoreCheckpoint = function (path, checkpointID) {
199 | var settings = {
200 | method: "POST",
201 | dataType: "json",
202 | };
203 | var url = this._getUrl(path, 'checkpoints', checkpointID);
204 | return utils.ajaxRequest(url, settings).then(function (success) {
205 | if (success.xhr.status !== 204) {
206 | throw Error('Invalid Status: ' + success.xhr.status);
207 | }
208 | });
209 | };
210 | /**
211 | * Delete a checkpoint for a file.
212 | */
213 | Contents.prototype.deleteCheckpoint = function (path, checkpointID) {
214 | var settings = {
215 | method: "DELETE",
216 | dataType: "json",
217 | };
218 | var url = this._getUrl(path, 'checkpoints', checkpointID);
219 | return utils.ajaxRequest(url, settings).then(function (success) {
220 | if (success.xhr.status !== 204) {
221 | throw Error('Invalid Status: ' + success.xhr.status);
222 | }
223 | });
224 | };
225 | /**
226 | * List notebooks and directories at a given path.
227 | */
228 | Contents.prototype.listContents = function (path) {
229 | return this.get(path, { type: 'directory' });
230 | };
231 | /**
232 | * Get an REST url for this file given a path.
233 | */
234 | Contents.prototype._getUrl = function () {
235 | var args = [];
236 | for (var _i = 0; _i < arguments.length; _i++) {
237 | args[_i - 0] = arguments[_i];
238 | }
239 | var url_parts = [this._apiUrl].concat(Array.prototype.slice.apply(args));
240 | return utils.urlPathJoin.apply(null, url_parts);
241 | };
242 | return Contents;
243 | })();
244 | exports.Contents = Contents;
245 | /**
246 | * Validate a Contents Model.
247 | */
248 | function validateContentsModel(model) {
249 | var err = new Error('Invalid Contents Model');
250 | if (!model.hasOwnProperty('name') || typeof model.name !== 'string') {
251 | throw err;
252 | }
253 | if (!model.hasOwnProperty('path') || typeof model.path !== 'string') {
254 | throw err;
255 | }
256 | if (!model.hasOwnProperty('type') || typeof model.type !== 'string') {
257 | throw err;
258 | }
259 | if (!model.hasOwnProperty('created') || typeof model.created !== 'string') {
260 | throw err;
261 | }
262 | if (!model.hasOwnProperty('last_modified') ||
263 | typeof model.last_modified !== 'string') {
264 | throw err;
265 | }
266 | if (!model.hasOwnProperty('mimetype')) {
267 | throw err;
268 | }
269 | if (!model.hasOwnProperty('content')) {
270 | throw err;
271 | }
272 | if (!model.hasOwnProperty('format')) {
273 | throw err;
274 | }
275 | }
276 | /**
277 | * Validate a Checkpoint model.
278 | */
279 | function validateCheckpointModel(model) {
280 | var err = new Error('Invalid Checkpoint Model');
281 | if (!model.hasOwnProperty('id') || typeof model.id !== 'string') {
282 | throw err;
283 | }
284 | if (!model.hasOwnProperty('last_modified') ||
285 | typeof model.last_modified !== 'string') {
286 | throw err;
287 | }
288 | }
289 | //# sourceMappingURL=contents.js.map
290 |
--------------------------------------------------------------------------------
/jupyter-js-services/ikernel.d.ts:
--------------------------------------------------------------------------------
1 | import { IDisposable } from 'phosphor-disposable';
2 | import { ISignal } from 'phosphor-signaling';
3 | export interface IKernelOptions {
4 | name: string;
5 | baseUrl: string;
6 | wsUrl?: string;
7 | username?: string;
8 | clientId?: string;
9 | }
10 | /**
11 | * Kernel identification specification.
12 | */
13 | export interface IKernelId {
14 | id: string;
15 | name: string;
16 | }
17 | /**
18 | * Kernel message header content.
19 | */
20 | export interface IKernelMessageHeader {
21 | username: string;
22 | version: string;
23 | session: string;
24 | msg_id: string;
25 | msg_type: string;
26 | }
27 | /**
28 | * Kernel message specification.
29 | */
30 | export interface IKernelMessage {
31 | header: IKernelMessageHeader;
32 | parent_header: IKernelMessageHeader | {};
33 | metadata: any;
34 | content: any;
35 | channel: string;
36 | buffers: (ArrayBuffer | ArrayBufferView)[];
37 | }
38 | /**
39 | * Kernel information specification.
40 | * http://ipython.org/ipython-doc/dev/development/messaging.html#kernel-info
41 | */
42 | export interface IKernelInfo {
43 | protocol_version: string;
44 | implementation: string;
45 | implementation_version: string;
46 | language_info: IKernelLanguageInfo;
47 | banner: string;
48 | help_links: {
49 | [key: string]: string;
50 | };
51 | }
52 | /**
53 | * Kernel language information specification.
54 | */
55 | export interface IKernelLanguageInfo {
56 | name: string;
57 | version: string;
58 | mimetype: string;
59 | file_extension: string;
60 | pygments_lexer: string;
61 | codemirror_mode: string | {};
62 | nbconverter_exporter: string;
63 | }
64 | export declare enum KernelStatus {
65 | Unknown = 0,
66 | Starting = 1,
67 | Idle = 2,
68 | Busy = 3,
69 | Restarting = 4,
70 | Dead = 5,
71 | }
72 | /**
73 | * Contents of a 'complete_request' message.
74 | */
75 | export interface ICompleteRequest {
76 | code: string;
77 | cursor_pos: number;
78 | }
79 | /**
80 | * Contents of a 'complete_reply' message.
81 | */
82 | export interface ICompleteReply {
83 | matches: string[];
84 | cursor_start: number;
85 | cursor_end: number;
86 | metadata: any;
87 | status: string;
88 | }
89 | /**
90 | * Contents of an 'inspect_request' message.
91 | */
92 | export interface IInspectRequest {
93 | code: string;
94 | cursor_pos: number;
95 | detail_level: number;
96 | }
97 | /**
98 | * Contents of an 'inspect_reply' message.
99 | */
100 | export interface IInspectReply {
101 | status: string;
102 | data: any;
103 | metadata: any;
104 | }
105 | /**
106 | * Contents of an 'is_complete_request' message.
107 | */
108 | export interface IIsCompleteRequest {
109 | code: string;
110 | }
111 | /**
112 | * Contents of an 'is_complete_reply' message.
113 | */
114 | export interface IIsCompleteReply {
115 | status: string;
116 | indent: string;
117 | }
118 | /**
119 | * Contents of an 'execute_request' message.
120 | */
121 | export interface IExecuteRequest {
122 | code: string;
123 | silent?: boolean;
124 | store_history?: boolean;
125 | user_expressions?: any;
126 | allow_stdin?: boolean;
127 | stop_on_error?: boolean;
128 | }
129 | /**
130 | * Contents of an 'execute_reply' message.
131 | */
132 | export interface IExecuteReply {
133 | execution_count: number;
134 | data: any;
135 | metadata: any;
136 | }
137 | /**
138 | * Contents of an 'input_reply' message.
139 | */
140 | export interface IInputReply {
141 | value: string;
142 | }
143 | /**
144 | * Contents of a 'comm_info_request' message.
145 | */
146 | export interface ICommInfoRequest {
147 | target?: string;
148 | }
149 | /**
150 | * Contents of `comm_info_reply` message.
151 | */
152 | export interface ICommInfoReply {
153 | /**
154 | * Mapping of comm ids to target names.
155 | */
156 | comms: {
157 | [id: string]: string;
158 | };
159 | }
160 | /**
161 | * Contents of a `comm_open` message.
162 | */
163 | export interface ICommOpen {
164 | comm_id: string;
165 | target_name: string;
166 | data: any;
167 | target_module?: string;
168 | }
169 | /**
170 | * Contents of a `comm_msg` message.
171 | */
172 | export interface ICommMsg {
173 | comm_id: string;
174 | data: any;
175 | }
176 | /**
177 | * Contents of a `comm_close` message.
178 | */
179 | export interface ICommClose {
180 | comm_id: string;
181 | data: any;
182 | }
183 | /**
184 | * Options for an IKernelMessage.
185 | */
186 | export interface IKernelMessageOptions {
187 | msgType: string;
188 | channel: string;
189 | session: string;
190 | username?: string;
191 | msgId?: string;
192 | }
193 | /**
194 | * Interface of a kernel object.
195 | */
196 | export interface IKernel {
197 | /**
198 | * The status changed signal for the kernel.
199 | */
200 | statusChanged: ISignal;
201 | /**
202 | * The unhandled message signal for the kernel.
203 | */
204 | unhandledMessage: ISignal;
205 | /**
206 | * An unhandled comm_open message received from the client.
207 | */
208 | commOpened: ISignal;
209 | /**
210 | * The id of the server-side kernel.
211 | */
212 | id: string;
213 | /**
214 | * The name of the server-side kernel.
215 | */
216 | name: string;
217 | /**
218 | * The client username.
219 | *
220 | * Read-only
221 | */
222 | username: string;
223 | /**
224 | * The client unique id.
225 | *
226 | * Read-only
227 | */
228 | clientId: string;
229 | /**
230 | * The current status of the kernel.
231 | *
232 | * Read-only
233 | */
234 | status: KernelStatus;
235 | /**
236 | * Send a shell message to the kernel.
237 | *
238 | * The future object will yield the result when available.
239 | */
240 | sendShellMessage(msg: IKernelMessage, expectReply: boolean): IKernelFuture;
241 | /**
242 | * Interrupt a kernel via API: POST /kernels/{kernel_id}/interrupt
243 | */
244 | interrupt(): Promise;
245 | /**
246 | * Restart a kernel via API: POST /kernels/{kernel_id}/restart
247 | *
248 | * It is assumed that the API call does not mutate the kernel id or name.
249 | */
250 | restart(): Promise;
251 | /**
252 | * Delete a kernel via API: DELETE /kernels/{kernel_id}
253 | *
254 | * If the given kernel id corresponds to an Kernel object, that
255 | * object is disposed and its websocket connection is cleared.
256 | *
257 | * Any further calls to `sendMessage` for that Kernel will throw
258 | * an exception.
259 | */
260 | shutdown(): Promise;
261 | /**
262 | * Send a "kernel_info_request" message.
263 | *
264 | * See https://ipython.org/ipython-doc/dev/development/messaging.html#kernel-info
265 | */
266 | kernelInfo(): Promise;
267 | /**
268 | * Send a "complete_request" message.
269 | *
270 | * See https://ipython.org/ipython-doc/dev/development/messaging.html#completion
271 | */
272 | complete(contents: ICompleteRequest): Promise;
273 | /**
274 | * Send an "inspect_request" message.
275 | *
276 | * See https://ipython.org/ipython-doc/dev/development/messaging.html#introspection
277 | */
278 | inspect(contents: IInspectRequest): Promise;
279 | /**
280 | * Send an "execute_request" message.
281 | *
282 | * See https://ipython.org/ipython-doc/dev/development/messaging.html#execute
283 | */
284 | execute(contents: IExecuteRequest): IKernelFuture;
285 | /**
286 | * Send an "is_complete_request" message.
287 | *
288 | * See https://ipython.org/ipython-doc/dev/development/messaging.html#code-completeness
289 | */
290 | isComplete(contents: IIsCompleteRequest): Promise;
291 | /**
292 | * Send a 'comm_info_request', and return the contents of the
293 | * 'comm_info_reply'.
294 | */
295 | commInfo(contents: ICommInfoRequest): Promise;
296 | /**
297 | * Send an "input_reply" message.
298 | *
299 | * https://ipython.org/ipython-doc/dev/development/messaging.html#messages-on-the-stdin-router-dealer-sockets
300 | */
301 | sendInputReply(contents: IInputReply): void;
302 | /**
303 | * Connect to a comm, or create a new one.
304 | *
305 | * If a client-side comm already exists, it is returned.
306 | */
307 | connectToComm(targetName: string, commId?: string): IComm;
308 | }
309 | /**
310 | * Object providing a Future interface for message callbacks.
311 | *
312 | * The future will self-dispose after `isDone` is
313 | * set and the registered `onDone` handler is called.
314 | *
315 | * If a `reply is expected, the Future is considered done when
316 | * both a `reply` message and a an `idle` iopub status message have
317 | * been received. Otherwise, it is considered done when the `idle` status is
318 | * received.
319 | */
320 | export interface IKernelFuture extends IDisposable {
321 | /**
322 | * Test whether the future is done.
323 | *
324 | * Read-only.
325 | */
326 | isDone: boolean;
327 | /**
328 | * The reply handler for the kernel future.
329 | */
330 | onReply: (msg: IKernelMessage) => void;
331 | /**
332 | * The stdin handler for the kernel future.
333 | */
334 | onStdin: (msg: IKernelMessage) => void;
335 | /**
336 | * The iopub handler for the kernel future.
337 | */
338 | onIOPub: (msg: IKernelMessage) => void;
339 | /**
340 | * The done handler for the kernel future.
341 | */
342 | onDone: (msg: IKernelMessage) => void;
343 | }
344 | /**
345 | * KernelSpec help link interface.
346 | */
347 | export interface IKernelSpecHelpLink {
348 | text: string;
349 | url: string;
350 | }
351 | /**
352 | * KernelSpec interface.
353 | */
354 | export interface IKernelSpec {
355 | language: string;
356 | argv: string[];
357 | display_name: string;
358 | env: any;
359 | codemirror_mode?: string;
360 | help_links?: IKernelSpecHelpLink[];
361 | }
362 | /**
363 | * KernelSpecId interface.
364 | */
365 | export interface IKernelSpecId {
366 | name: string;
367 | spec: IKernelSpec;
368 | resources: {
369 | [key: string]: string;
370 | };
371 | }
372 | /**
373 | * KernelSpecInfo interface
374 | */
375 | export interface IKernelSpecIds {
376 | default: string;
377 | kernelspecs: {
378 | [key: string]: IKernelSpecId;
379 | };
380 | }
381 | /**
382 | * A client side Comm interface.
383 | */
384 | export interface IComm {
385 | /**
386 | * The uuid for the comm channel.
387 | *
388 | * Read-only
389 | */
390 | commId: string;
391 | /**
392 | * The target name for the comm channel.
393 | *
394 | * Read-only
395 | */
396 | targetName: string;
397 | /**
398 | * The onClose handler.
399 | */
400 | onClose: (data?: any) => void;
401 | /**
402 | * The onMsg handler.
403 | */
404 | onMsg: (data: any) => void;
405 | /**
406 | * Open a comm with optional data.
407 | */
408 | open(data?: any, metadata?: any): IKernelFuture;
409 | /**
410 | * Send a comm message to the kernel.
411 | */
412 | send(data: any, metadata?: any, buffers?: (ArrayBuffer | ArrayBufferView)[]): IKernelFuture;
413 | /**
414 | * Close the comm.
415 | */
416 | close(data?: any, metadata?: any): IKernelFuture;
417 | }
418 |
--------------------------------------------------------------------------------
/jupyter-js-services/ikernel.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Jupyter Development Team.
2 | // Distributed under the terms of the Modified BSD License.
3 | 'use strict';
4 | (function (KernelStatus) {
5 | KernelStatus[KernelStatus["Unknown"] = 0] = "Unknown";
6 | KernelStatus[KernelStatus["Starting"] = 1] = "Starting";
7 | KernelStatus[KernelStatus["Idle"] = 2] = "Idle";
8 | KernelStatus[KernelStatus["Busy"] = 3] = "Busy";
9 | KernelStatus[KernelStatus["Restarting"] = 4] = "Restarting";
10 | KernelStatus[KernelStatus["Dead"] = 5] = "Dead";
11 | })(exports.KernelStatus || (exports.KernelStatus = {}));
12 | var KernelStatus = exports.KernelStatus;
13 | //# sourceMappingURL=ikernel.js.map
--------------------------------------------------------------------------------
/jupyter-js-services/index.d.ts:
--------------------------------------------------------------------------------
1 | export * from './config';
2 | export * from './contents';
3 | export * from './ikernel';
4 | export * from './isession';
5 | export * from './kernel';
6 | export * from './session';
7 |
--------------------------------------------------------------------------------
/jupyter-js-services/index.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Jupyter Development Team.
2 | // Distributed under the terms of the Modified BSD License.
3 | 'use strict';
4 | function __export(m) {
5 | for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
6 | }
7 | __export(require('./config'));
8 | __export(require('./contents'));
9 | __export(require('./ikernel'));
10 | __export(require('./isession'));
11 | __export(require('./kernel'));
12 | __export(require('./session'));
13 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/jupyter-js-services/isession.d.ts:
--------------------------------------------------------------------------------
1 | import { ISignal } from 'phosphor-signaling';
2 | import { IKernel, IKernelId } from './ikernel';
3 | /**
4 | * Notebook Identification specification.
5 | */
6 | export interface INotebookId {
7 | path: string;
8 | }
9 | /**
10 | * Session Identification specification.
11 | */
12 | export interface ISessionId {
13 | id: string;
14 | notebook: INotebookId;
15 | kernel: IKernelId;
16 | }
17 | /**
18 | * Session initialization options.
19 | */
20 | export interface ISessionOptions {
21 | notebookPath: string;
22 | kernelName: string;
23 | baseUrl: string;
24 | wsUrl?: string;
25 | username?: string;
26 | clientId?: string;
27 | }
28 | /**
29 | * Interface of a notebook session object.
30 | */
31 | export interface INotebookSession {
32 | /**
33 | * Get the session died signal.
34 | */
35 | sessionDied: ISignal;
36 | /**
37 | * Unique id of the session.
38 | *
39 | * Read only.
40 | */
41 | id: string;
42 | /**
43 | * The path to the notebook.
44 | *
45 | * Read only.
46 | */
47 | notebookPath: string;
48 | /**
49 | * The kernel.
50 | *
51 | * Read only.
52 | */
53 | kernel: IKernel;
54 | /**
55 | * Rename the notebook.
56 | */
57 | renameNotebook(path: string): Promise;
58 | /**
59 | * Kill the kernel and shutdown the session.
60 | */
61 | shutdown(): Promise;
62 | }
63 |
--------------------------------------------------------------------------------
/jupyter-js-services/isession.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Jupyter Development Team.
2 | // Distributed under the terms of the Modified BSD License.
3 | 'use strict';
4 | //# sourceMappingURL=isession.js.map
--------------------------------------------------------------------------------
/jupyter-js-services/kernel.d.ts:
--------------------------------------------------------------------------------
1 | import { IKernel, IKernelId, IKernelMessage, IKernelMessageOptions, IKernelOptions, IKernelSpecIds } from './ikernel';
2 | /**
3 | * Fetch the kernel specs via API: GET /kernelspecs
4 | */
5 | export declare function getKernelSpecs(baseUrl: string): Promise;
6 | /**
7 | * Fetch the running kernels via API: GET /kernels
8 | */
9 | export declare function listRunningKernels(baseUrl: string): Promise;
10 | /**
11 | * Start a new kernel via API: POST /kernels
12 | *
13 | * Wrap the result in an Kernel object. The promise is fulfilled
14 | * when the kernel is fully ready to send the first message. If
15 | * the kernel fails to become ready, the promise is rejected.
16 | */
17 | export declare function startNewKernel(options: IKernelOptions): Promise;
18 | /**
19 | * Connect to a running kernel.
20 | *
21 | * If the kernel was already started via `startNewKernel`, the existing
22 | * Kernel object is used as the fulfillment value.
23 | *
24 | * Otherwise, if `options` are given, we attempt to connect to the existing
25 | * kernel. The promise is fulfilled when the kernel is fully ready to send
26 | * the first message. If the kernel fails to become ready, the promise is
27 | * rejected.
28 | *
29 | * If the kernel was not already started and no `options` are given,
30 | * the promise is rejected.
31 | */
32 | export declare function connectToKernel(id: string, options?: IKernelOptions): Promise;
33 | /**
34 | * Create a well-formed Kernel Message.
35 | */
36 | export declare function createKernelMessage(options: IKernelMessageOptions, content?: any, metadata?: any, buffers?: (ArrayBuffer | ArrayBufferView)[]): IKernelMessage;
37 |
--------------------------------------------------------------------------------
/jupyter-js-services/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jupyter-js-services",
3 | "version": "0.0.1",
4 | "description": "Client APIs for the Jupyter services REST APIs",
5 | "main": "lib/index.js",
6 | "typings": "lib/index.d.ts",
7 | "dependencies": {
8 | "phosphor-disposable": "^1.0.2",
9 | "phosphor-signaling": "^1.1.0"
10 | },
11 | "devDependencies": {
12 | },
13 | "scripts": {
14 | "postinstall": "npm dedupe"
15 | },
16 | "repository": {
17 | "type": "git",
18 | "url": "https://github.com/jupyter/jupyter-js-services"
19 | },
20 | "keywords": [
21 | "jupyter",
22 | "services",
23 | "notebook"
24 | ],
25 | "files": [
26 | "lib/index.js",
27 | "lib/index.d.ts"
28 | ],
29 | "author": "Project Jupyter",
30 | "license": "BSD-3-Clause",
31 | "bugs": {
32 | "url": "https://github.com/jupyter/jupyter-js-services/issues"
33 | },
34 | "homepage": "https://github.com/jupyter/jupyter-js-services"
35 | }
36 |
--------------------------------------------------------------------------------
/jupyter-js-services/serialize.d.ts:
--------------------------------------------------------------------------------
1 | import { IKernelMessage } from './ikernel';
2 | /**
3 | * Deserialize and return the unpacked message.
4 | */
5 | export declare function deserialize(data: ArrayBuffer | string): IKernelMessage;
6 | /**
7 | * Serialize a kernel message for transport.
8 | */
9 | export declare function serialize(msg: IKernelMessage): string | ArrayBuffer;
10 |
--------------------------------------------------------------------------------
/jupyter-js-services/serialize.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Jupyter Development Team.
2 | // Distributed under the terms of the Modified BSD License.
3 | 'use strict';
4 | /**
5 | * Deserialize and return the unpacked message.
6 | */
7 | function deserialize(data) {
8 | var value;
9 | if (typeof data === "string") {
10 | value = JSON.parse(data);
11 | }
12 | else {
13 | value = deserializeBinary(data);
14 | }
15 | return value;
16 | }
17 | exports.deserialize = deserialize;
18 | /**
19 | * Serialize a kernel message for transport.
20 | */
21 | function serialize(msg) {
22 | var value;
23 | if (msg.buffers && msg.buffers.length) {
24 | value = serializeBinary(msg);
25 | }
26 | else {
27 | value = JSON.stringify(msg);
28 | }
29 | return value;
30 | }
31 | exports.serialize = serialize;
32 | /**
33 | * Deserialize a binary message to a Kernel Message.
34 | */
35 | function deserializeBinary(buf) {
36 | var data = new DataView(buf);
37 | // read the header: 1 + nbufs 32b integers
38 | var nbufs = data.getUint32(0);
39 | var offsets = [];
40 | if (nbufs < 2) {
41 | throw new Error("Invalid incoming Kernel Message");
42 | }
43 | for (var i = 1; i <= nbufs; i++) {
44 | offsets.push(data.getUint32(i * 4));
45 | }
46 | var json_bytes = new Uint8Array(buf.slice(offsets[0], offsets[1]));
47 | var msg = JSON.parse((new TextDecoder('utf8')).decode(json_bytes));
48 | // the remaining chunks are stored as DataViews in msg.buffers
49 | msg.buffers = [];
50 | for (var i = 1; i < nbufs; i++) {
51 | var start = offsets[i];
52 | var stop = offsets[i + 1] || buf.byteLength;
53 | msg.buffers.push(new DataView(buf.slice(start, stop)));
54 | }
55 | return msg;
56 | }
57 | /**
58 | * Implement the binary serialization protocol.
59 | * Serialize Kernel message to ArrayBuffer.
60 | */
61 | function serializeBinary(msg) {
62 | var offsets = [];
63 | var buffers = [];
64 | var encoder = new TextEncoder('utf8');
65 | var json_utf8 = encoder.encode(JSON.stringify(msg, replace_buffers));
66 | buffers.push(json_utf8.buffer);
67 | for (var i = 0; i < msg.buffers.length; i++) {
68 | // msg.buffers elements could be either views or ArrayBuffers
69 | // buffers elements are ArrayBuffers
70 | var b = msg.buffers[i];
71 | buffers.push(b instanceof ArrayBuffer ? b : b.buffer);
72 | }
73 | var nbufs = buffers.length;
74 | offsets.push(4 * (nbufs + 1));
75 | for (i = 0; i + 1 < buffers.length; i++) {
76 | offsets.push(offsets[offsets.length - 1] + buffers[i].byteLength);
77 | }
78 | var msg_buf = new Uint8Array(offsets[offsets.length - 1] + buffers[buffers.length - 1].byteLength);
79 | // use DataView.setUint32 for network byte-order
80 | var view = new DataView(msg_buf.buffer);
81 | // write nbufs to first 4 bytes
82 | view.setUint32(0, nbufs);
83 | // write offsets to next 4 * nbufs bytes
84 | for (i = 0; i < offsets.length; i++) {
85 | view.setUint32(4 * (i + 1), offsets[i]);
86 | }
87 | // write all the buffers at their respective offsets
88 | for (i = 0; i < buffers.length; i++) {
89 | msg_buf.set(new Uint8Array(buffers[i]), offsets[i]);
90 | }
91 | return msg_buf.buffer;
92 | }
93 | /**
94 | * Filter "buffers" key for JSON.stringify
95 | */
96 | function replace_buffers(key, value) {
97 | if (key === "buffers") {
98 | return undefined;
99 | }
100 | return value;
101 | }
102 | //# sourceMappingURL=serialize.js.map
--------------------------------------------------------------------------------
/jupyter-js-services/session.d.ts:
--------------------------------------------------------------------------------
1 | import { INotebookSession, ISessionId, ISessionOptions } from './isession';
2 | /**
3 | * Fetch the running sessions via API: GET /sessions
4 | */
5 | export declare function listRunningSessions(baseUrl: string): Promise;
6 | /**
7 | * Start a new session via API: POST /kernels
8 | *
9 | * Wrap the result in an NotebookSession object. The promise is fulfilled
10 | * when the session is fully ready to send the first message. If
11 | * the session fails to become ready, the promise is rejected.
12 | */
13 | export declare function startNewSession(options: ISessionOptions): Promise;
14 | /**
15 | * Connect to a running notebook session.
16 | *
17 | * If the session was already started via `startNewSession`, the existing
18 | * NotebookSession object is used as the fulfillment value.
19 | *
20 | * Otherwise, if `options` are given, we attempt to connect to the existing
21 | * session. The promise is fulfilled when the session is fully ready to send
22 | * the first message. If the session fails to become ready, the promise is
23 | * rejected.
24 | *
25 | * If the session was not already started and no `options` are given,
26 | * the promise is rejected.
27 | */
28 | export declare function connectToSession(id: string, options?: ISessionOptions): Promise;
29 |
--------------------------------------------------------------------------------
/jupyter-js-services/session.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Jupyter Development Team.
2 | // Distributed under the terms of the Modified BSD License.
3 | 'use strict';
4 | var phosphor_signaling_1 = require('phosphor-signaling');
5 | var ikernel_1 = require('./ikernel');
6 | var kernel_1 = require('./kernel');
7 | var utils = require('./utils');
8 | var validate = require('./validate');
9 | /**
10 | * The url for the session service.
11 | */
12 | var SESSION_SERVICE_URL = 'api/sessions';
13 | /**
14 | * Fetch the running sessions via API: GET /sessions
15 | */
16 | function listRunningSessions(baseUrl) {
17 | var url = utils.urlPathJoin(baseUrl, SESSION_SERVICE_URL);
18 | return utils.ajaxRequest(url, {
19 | method: "GET",
20 | dataType: "json"
21 | }).then(function (success) {
22 | if (success.xhr.status !== 200) {
23 | throw Error('Invalid Status: ' + success.xhr.status);
24 | }
25 | if (!Array.isArray(success.data)) {
26 | throw Error('Invalid Session list');
27 | }
28 | for (var i = 0; i < success.data.length; i++) {
29 | validate.validateSessionId(success.data[i]);
30 | }
31 | return success.data;
32 | }, onSessionError);
33 | }
34 | exports.listRunningSessions = listRunningSessions;
35 | /**
36 | * Start a new session via API: POST /kernels
37 | *
38 | * Wrap the result in an NotebookSession object. The promise is fulfilled
39 | * when the session is fully ready to send the first message. If
40 | * the session fails to become ready, the promise is rejected.
41 | */
42 | function startNewSession(options) {
43 | var url = utils.urlPathJoin(options.baseUrl, SESSION_SERVICE_URL);
44 | var model = {
45 | kernel: { name: options.kernelName },
46 | notebook: { path: options.notebookPath }
47 | };
48 | return utils.ajaxRequest(url, {
49 | method: "POST",
50 | dataType: "json",
51 | data: JSON.stringify(model),
52 | contentType: 'application/json'
53 | }).then(function (success) {
54 | if (success.xhr.status !== 201) {
55 | throw Error('Invalid Status: ' + success.xhr.status);
56 | }
57 | var sessionId = success.data;
58 | validate.validateSessionId(success.data);
59 | return createSession(sessionId, options);
60 | }, onSessionError);
61 | }
62 | exports.startNewSession = startNewSession;
63 | /**
64 | * Connect to a running notebook session.
65 | *
66 | * If the session was already started via `startNewSession`, the existing
67 | * NotebookSession object is used as the fulfillment value.
68 | *
69 | * Otherwise, if `options` are given, we attempt to connect to the existing
70 | * session. The promise is fulfilled when the session is fully ready to send
71 | * the first message. If the session fails to become ready, the promise is
72 | * rejected.
73 | *
74 | * If the session was not already started and no `options` are given,
75 | * the promise is rejected.
76 | */
77 | function connectToSession(id, options) {
78 | var session = runningSessions.get(id);
79 | if (session) {
80 | return Promise.resolve(session);
81 | }
82 | if (options === void 0) {
83 | return Promise.reject(new Error('Please specify session options'));
84 | }
85 | return new Promise(function (resolve, reject) {
86 | listRunningSessions(options.baseUrl).then(function (sessionIds) {
87 | var sessionIds = sessionIds.filter(function (k) { return k.id === id; });
88 | if (!sessionIds.length) {
89 | reject(new Error('No running session with id: ' + id));
90 | }
91 | createSession(sessionIds[0], options).then(function (session) {
92 | resolve(session);
93 | });
94 | });
95 | });
96 | }
97 | exports.connectToSession = connectToSession;
98 | /**
99 | * Create a Promise for a NotebookSession object.
100 | *
101 | * Fulfilled when the NotebookSession is Starting, or rejected if Dead.
102 | */
103 | function createSession(sessionId, options) {
104 | return new Promise(function (resolve, reject) {
105 | options.notebookPath = sessionId.notebook.path;
106 | var kernelOptions = {
107 | name: sessionId.kernel.name,
108 | baseUrl: options.baseUrl,
109 | wsUrl: options.wsUrl,
110 | username: options.username,
111 | clientId: options.clientId
112 | };
113 | var kernelPromise = kernel_1.connectToKernel(sessionId.kernel.id, kernelOptions);
114 | kernelPromise.then(function (kernel) {
115 | var session = new NotebookSession(options, sessionId.id, kernel);
116 | runningSessions.set(session.id, session);
117 | resolve(session);
118 | }).catch(function () {
119 | reject(new Error('Session failed to start'));
120 | });
121 | });
122 | }
123 | /**
124 | * A module private store for running sessions.
125 | */
126 | var runningSessions = new Map();
127 | /**
128 | * Session object for accessing the session REST api. The session
129 | * should be used to start kernels and then shut them down -- for
130 | * all other operations, the kernel object should be used.
131 | **/
132 | var NotebookSession = (function () {
133 | /**
134 | * Construct a new session.
135 | */
136 | function NotebookSession(options, id, kernel) {
137 | this._id = "";
138 | this._notebookPath = "";
139 | this._kernel = null;
140 | this._url = '';
141 | this._isDead = false;
142 | this._id = id;
143 | this._notebookPath = options.notebookPath;
144 | this._kernel = kernel;
145 | this._url = utils.urlPathJoin(options.baseUrl, SESSION_SERVICE_URL, this._id);
146 | this._kernel.statusChanged.connect(this._kernelStatusChanged, this);
147 | }
148 | Object.defineProperty(NotebookSession.prototype, "sessionDied", {
149 | /**
150 | * Get the session died signal.
151 | */
152 | get: function () {
153 | return NotebookSession.sessionDiedSignal.bind(this);
154 | },
155 | enumerable: true,
156 | configurable: true
157 | });
158 | Object.defineProperty(NotebookSession.prototype, "id", {
159 | /**
160 | * Get the session id.
161 | */
162 | get: function () {
163 | return this._id;
164 | },
165 | enumerable: true,
166 | configurable: true
167 | });
168 | Object.defineProperty(NotebookSession.prototype, "kernel", {
169 | /**
170 | * Get the session kernel object.
171 | */
172 | get: function () {
173 | return this._kernel;
174 | },
175 | enumerable: true,
176 | configurable: true
177 | });
178 | Object.defineProperty(NotebookSession.prototype, "notebookPath", {
179 | /**
180 | * Get the notebook path.
181 | */
182 | get: function () {
183 | return this._notebookPath;
184 | },
185 | enumerable: true,
186 | configurable: true
187 | });
188 | /**
189 | * Rename the notebook.
190 | */
191 | NotebookSession.prototype.renameNotebook = function (path) {
192 | var _this = this;
193 | if (this._isDead) {
194 | return Promise.reject(new Error('Session is dead'));
195 | }
196 | var model = {
197 | kernel: { name: this._kernel.name, id: this._kernel.id },
198 | notebook: { path: path }
199 | };
200 | return utils.ajaxRequest(this._url, {
201 | method: "PATCH",
202 | dataType: "json",
203 | data: JSON.stringify(model),
204 | contentType: 'application/json'
205 | }).then(function (success) {
206 | if (success.xhr.status !== 200) {
207 | throw Error('Invalid Status: ' + success.xhr.status);
208 | }
209 | var data = success.data;
210 | validate.validateSessionId(data);
211 | _this._notebookPath = data.notebook.path;
212 | }, onSessionError);
213 | };
214 | /**
215 | * DELETE /api/sessions/[:session_id]
216 | *
217 | * Kill the kernel and shutdown the session.
218 | */
219 | NotebookSession.prototype.shutdown = function () {
220 | var _this = this;
221 | if (this._isDead) {
222 | return Promise.reject(new Error('Session is dead'));
223 | }
224 | this._isDead = true;
225 | return utils.ajaxRequest(this._url, {
226 | method: "DELETE",
227 | dataType: "json"
228 | }).then(function (success) {
229 | if (success.xhr.status !== 204) {
230 | throw Error('Invalid Status: ' + success.xhr.status);
231 | }
232 | _this.sessionDied.emit(void 0);
233 | _this.kernel.shutdown();
234 | }, function (rejected) {
235 | _this._isDead = false;
236 | if (rejected.xhr.status === 410) {
237 | throw Error('The kernel was deleted but the session was not');
238 | }
239 | onSessionError(rejected);
240 | });
241 | };
242 | /**
243 | * React to changes in the Kernel status.
244 | */
245 | NotebookSession.prototype._kernelStatusChanged = function (sender, state) {
246 | if (state == ikernel_1.KernelStatus.Dead) {
247 | this.shutdown();
248 | }
249 | };
250 | /**
251 | * A signal emitted when the session dies.
252 | */
253 | NotebookSession.sessionDiedSignal = new phosphor_signaling_1.Signal();
254 | return NotebookSession;
255 | })();
256 | /**
257 | * Handle an error on a session Ajax call.
258 | */
259 | function onSessionError(error) {
260 | console.error("API request failed (" + error.statusText + "): ");
261 | throw Error(error.statusText);
262 | }
263 | //# sourceMappingURL=session.js.map
--------------------------------------------------------------------------------
/jupyter-js-services/test.d.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blink1073/jupyter_demo/906c18f008cd1ca60c440d07a981b8092fe9f3d9/jupyter-js-services/test.d.ts
--------------------------------------------------------------------------------
/jupyter-js-services/test.js:
--------------------------------------------------------------------------------
1 | var index_1 = require('./index');
2 | var BASEURL = 'http://localhost:8888';
3 | var WSURL = 'ws://localhost:8888';
4 | index_1.getKernelSpecs(BASEURL).then(function (kernelSpecs) {
5 | return index_1.startNewKernel({
6 | baseUrl: BASEURL,
7 | wsUrl: WSURL,
8 | name: kernelSpecs.default,
9 | });
10 | }).then(function (kernel) {
11 | index_1.getConfigSection('notebook', BASEURL).then(function (section) {
12 | var defaults = { default_cell_type: 'code' };
13 | var config = new index_1.ConfigWithDefaults(section, defaults, 'Notebook');
14 | console.log(config.get('default_cell_type')); // 'code'
15 | config.set('foo', 'bar').then(function (data) {
16 | console.log(data.foo); // 'bar'
17 | });
18 | });
19 | });
20 | //# sourceMappingURL=test.js.map
--------------------------------------------------------------------------------
/jupyter-js-services/utils.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copy the contents of one object to another, recursively.
3 | *
4 | * http://stackoverflow.com/questions/12317003/something-like-jquery-extend-but-standalone
5 | */
6 | export declare function extend(target: any, source: any): any;
7 | /**
8 | * Get a random 128b hex string (not a formal UUID)
9 | */
10 | export declare function uuid(): string;
11 | /**
12 | * Join a sequence of url components with '/'.
13 | */
14 | export declare function urlPathJoin(...paths: string[]): string;
15 | /**
16 | * Encode just the components of a multi-segment uri,
17 | * leaving '/' separators.
18 | */
19 | export declare function encodeURIComponents(uri: string): string;
20 | /**
21 | * Join a sequence of url components with '/',
22 | * encoding each component with encodeURIComponent.
23 | */
24 | export declare function urlJoinEncode(...args: string[]): string;
25 | /**
26 | * Return a serialized object string suitable for a query.
27 | *
28 | * http://stackoverflow.com/a/30707423
29 | */
30 | export declare function jsonToQueryString(json: any): string;
31 | /**
32 | * Input settings for an AJAX request.
33 | */
34 | export interface IAjaxSettings {
35 | method: string;
36 | dataType: string;
37 | contentType?: string;
38 | data?: any;
39 | }
40 | /**
41 | * Success handler for AJAX request.
42 | */
43 | export interface IAjaxSuccess {
44 | data: any;
45 | statusText: string;
46 | xhr: XMLHttpRequest;
47 | }
48 | /**
49 | * Error handler for AJAX request.
50 | */
51 | export interface IAjaxError {
52 | xhr: XMLHttpRequest;
53 | statusText: string;
54 | error: ErrorEvent;
55 | }
56 | /**
57 | * Asynchronous XMLHTTPRequest handler.
58 | *
59 | * http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promisifying-xmlhttprequest
60 | */
61 | export declare function ajaxRequest(url: string, settings: IAjaxSettings): Promise;
62 | /**
63 | * A Promise that can be resolved or rejected by another object.
64 | */
65 | export declare class PromiseDelegate {
66 | /**
67 | * Construct a new Promise delegate.
68 | */
69 | constructor();
70 | /**
71 | * Get the underlying Promise.
72 | */
73 | promise: Promise;
74 | /**
75 | * Resolve the underlying Promise with an optional value or another Promise.
76 | */
77 | resolve(value?: T | Thenable): void;
78 | /**
79 | * Reject the underlying Promise with an optional reason.
80 | */
81 | reject(reason?: any): void;
82 | private _promise;
83 | private _resolve;
84 | private _reject;
85 | }
86 |
--------------------------------------------------------------------------------
/jupyter-js-services/utils.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Jupyter Development Team.
2 | // Distributed under the terms of the Modified BSD License.
3 | 'use strict';
4 | /**
5 | * Copy the contents of one object to another, recursively.
6 | *
7 | * http://stackoverflow.com/questions/12317003/something-like-jquery-extend-but-standalone
8 | */
9 | function extend(target, source) {
10 | target = target || {};
11 | for (var prop in source) {
12 | if (typeof source[prop] === 'object') {
13 | target[prop] = extend(target[prop], source[prop]);
14 | }
15 | else {
16 | target[prop] = source[prop];
17 | }
18 | }
19 | return target;
20 | }
21 | exports.extend = extend;
22 | /**
23 | * Get a random 128b hex string (not a formal UUID)
24 | */
25 | function uuid() {
26 | var s = [];
27 | var hexDigits = "0123456789abcdef";
28 | var nChars = hexDigits.length;
29 | for (var i = 0; i < 32; i++) {
30 | s[i] = hexDigits.charAt(Math.floor(Math.random() * nChars));
31 | }
32 | return s.join("");
33 | }
34 | exports.uuid = uuid;
35 | /**
36 | * Join a sequence of url components with '/'.
37 | */
38 | function urlPathJoin() {
39 | var paths = [];
40 | for (var _i = 0; _i < arguments.length; _i++) {
41 | paths[_i - 0] = arguments[_i];
42 | }
43 | var url = '';
44 | for (var i = 0; i < paths.length; i++) {
45 | var path = paths[i];
46 | if (path === '') {
47 | continue;
48 | }
49 | if (i > 0) {
50 | path = path.replace(/\/\/+/, '/');
51 | }
52 | if (url.length > 0 && url.charAt(url.length - 1) != '/') {
53 | url = url + '/' + paths[i];
54 | }
55 | else {
56 | url = url + paths[i];
57 | }
58 | }
59 | return url;
60 | }
61 | exports.urlPathJoin = urlPathJoin;
62 | /**
63 | * Encode just the components of a multi-segment uri,
64 | * leaving '/' separators.
65 | */
66 | function encodeURIComponents(uri) {
67 | return uri.split('/').map(encodeURIComponent).join('/');
68 | }
69 | exports.encodeURIComponents = encodeURIComponents;
70 | /**
71 | * Join a sequence of url components with '/',
72 | * encoding each component with encodeURIComponent.
73 | */
74 | function urlJoinEncode() {
75 | var args = [];
76 | for (var _i = 0; _i < arguments.length; _i++) {
77 | args[_i - 0] = arguments[_i];
78 | }
79 | return encodeURIComponents(urlPathJoin.apply(null, args));
80 | }
81 | exports.urlJoinEncode = urlJoinEncode;
82 | /**
83 | * Return a serialized object string suitable for a query.
84 | *
85 | * http://stackoverflow.com/a/30707423
86 | */
87 | function jsonToQueryString(json) {
88 | return '?' + Object.keys(json).map(function (key) {
89 | return encodeURIComponent(key) + '=' + encodeURIComponent(json[key]);
90 | }).join('&');
91 | }
92 | exports.jsonToQueryString = jsonToQueryString;
93 | /**
94 | * Asynchronous XMLHTTPRequest handler.
95 | *
96 | * http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promisifying-xmlhttprequest
97 | */
98 | function ajaxRequest(url, settings) {
99 | return new Promise(function (resolve, reject) {
100 | var req = new XMLHttpRequest();
101 | req.open(settings.method, url);
102 | if (settings.contentType) {
103 | req.setRequestHeader('Content-Type', settings.contentType);
104 | }
105 | req.onload = function () {
106 | var response = req.response;
107 | if (settings.dataType === 'json' && req.response) {
108 | response = JSON.parse(req.response);
109 | }
110 | resolve({ data: response, statusText: req.statusText, xhr: req });
111 | };
112 | req.onerror = function (err) {
113 | reject({ xhr: req, statusText: req.statusText, error: err });
114 | };
115 | if (settings.data) {
116 | req.send(settings.data);
117 | }
118 | else {
119 | req.send();
120 | }
121 | });
122 | }
123 | exports.ajaxRequest = ajaxRequest;
124 | /**
125 | * A Promise that can be resolved or rejected by another object.
126 | */
127 | var PromiseDelegate = (function () {
128 | /**
129 | * Construct a new Promise delegate.
130 | */
131 | function PromiseDelegate() {
132 | var _this = this;
133 | this._promise = new Promise(function (resolve, reject) {
134 | _this._resolve = resolve;
135 | _this._reject = reject;
136 | });
137 | }
138 | Object.defineProperty(PromiseDelegate.prototype, "promise", {
139 | /**
140 | * Get the underlying Promise.
141 | */
142 | get: function () {
143 | return this._promise;
144 | },
145 | enumerable: true,
146 | configurable: true
147 | });
148 | /**
149 | * Resolve the underlying Promise with an optional value or another Promise.
150 | */
151 | PromiseDelegate.prototype.resolve = function (value) {
152 | // Note: according to the Promise spec, and the `this` context for resolve
153 | // and reject are ignored
154 | this._resolve(value);
155 | };
156 | /**
157 | * Reject the underlying Promise with an optional reason.
158 | */
159 | PromiseDelegate.prototype.reject = function (reason) {
160 | // Note: according to the Promise spec, and the `this` context for resolve
161 | // and reject are ignored
162 | this._reject(reason);
163 | };
164 | return PromiseDelegate;
165 | })();
166 | exports.PromiseDelegate = PromiseDelegate;
167 | //# sourceMappingURL=utils.js.map
--------------------------------------------------------------------------------
/jupyter-js-services/validate.d.ts:
--------------------------------------------------------------------------------
1 | import { IKernelId, IKernelMessage, IKernelSpecId } from './ikernel';
2 | import { INotebookId, ISessionId } from './isession';
3 | /**
4 | * Validate an Kernel Message as being a valid Comm Message.
5 | */
6 | export declare function validateCommMessage(msg: IKernelMessage): boolean;
7 | /**
8 | * Validate an object as being of IKernelMessage type.
9 | */
10 | export declare function validateKernelMessage(msg: IKernelMessage): void;
11 | /**
12 | * Validate an object as being of IKernelID type
13 | */
14 | export declare function validateKernelId(info: IKernelId): void;
15 | /**
16 | * Validate an object as being of ISessionId type.
17 | */
18 | export declare function validateSessionId(info: ISessionId): void;
19 | /**
20 | * Validate an object as being of INotebookId type.
21 | */
22 | export declare function validateNotebookId(model: INotebookId): void;
23 | /**
24 | * Validate an object as being of IKernelSpecID type.
25 | */
26 | export declare function validateKernelSpec(info: IKernelSpecId): void;
27 |
--------------------------------------------------------------------------------
/jupyter-js-services/validate.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Jupyter Development Team.
2 | // Distributed under the terms of the Modified BSD License.
3 | 'use strict';
4 | var COMM_FIELDS = ['comm_id', 'data'];
5 | var HEADER_FIELDS = ['username', 'version', 'session', 'msg_id', 'msg_type'];
6 | var MESSAGE_FIELDS = ['header', 'parent_header', 'metadata', 'content',
7 | 'channel', 'buffers'];
8 | /**
9 | * Validate an Kernel Message as being a valid Comm Message.
10 | */
11 | function validateCommMessage(msg) {
12 | for (var i = 0; i < COMM_FIELDS.length; i++) {
13 | if (!msg.content.hasOwnProperty(COMM_FIELDS[i])) {
14 | console.log('*****invalid', COMM_FIELDS[i]);
15 | return false;
16 | }
17 | }
18 | if (msg.header.msg_type === 'comm_open') {
19 | if (!msg.content.hasOwnProperty('target_name') ||
20 | typeof msg.content.target_name !== 'string') {
21 | console.log('***TARGET NAME');
22 | return false;
23 | }
24 | if (msg.content.hasOwnProperty('target_module') &&
25 | msg.content.target_module !== null &&
26 | typeof msg.content.target_module !== 'string') {
27 | return false;
28 | }
29 | }
30 | if (typeof msg.content.comm_id !== 'string') {
31 | console.log("COMM_ID");
32 | return false;
33 | }
34 | return true;
35 | }
36 | exports.validateCommMessage = validateCommMessage;
37 | function validateKernelHeader(header) {
38 | for (var i = 0; i < HEADER_FIELDS.length; i++) {
39 | if (!header.hasOwnProperty(HEADER_FIELDS[i])) {
40 | throw Error('Invalid Kernel message');
41 | }
42 | if (typeof header[HEADER_FIELDS[i]] !== 'string') {
43 | throw Error('Invalid Kernel message');
44 | }
45 | }
46 | }
47 | /**
48 | * Validate an object as being of IKernelMessage type.
49 | */
50 | function validateKernelMessage(msg) {
51 | for (var i = 0; i < MESSAGE_FIELDS.length; i++) {
52 | if (!msg.hasOwnProperty(MESSAGE_FIELDS[i])) {
53 | throw Error('Invalid Kernel message');
54 | }
55 | }
56 | validateKernelHeader(msg.header);
57 | if (Object.keys(msg.parent_header).length > 0) {
58 | validateKernelHeader(msg.parent_header);
59 | }
60 | if (typeof msg.channel !== 'string') {
61 | throw Error('Invalid Kernel message');
62 | }
63 | if (!Array.isArray(msg.buffers)) {
64 | throw Error('Invalid Kernel message');
65 | }
66 | }
67 | exports.validateKernelMessage = validateKernelMessage;
68 | /**
69 | * Validate an object as being of IKernelID type
70 | */
71 | function validateKernelId(info) {
72 | if (!info.hasOwnProperty('name') || !info.hasOwnProperty('id')) {
73 | throw Error('Invalid kernel id');
74 | }
75 | if ((typeof info.id !== 'string') || (typeof info.name !== 'string')) {
76 | throw Error('Invalid kernel id');
77 | }
78 | }
79 | exports.validateKernelId = validateKernelId;
80 | /**
81 | * Validate an object as being of ISessionId type.
82 | */
83 | function validateSessionId(info) {
84 | if (!info.hasOwnProperty('id') ||
85 | !info.hasOwnProperty('notebook') ||
86 | !info.hasOwnProperty('kernel')) {
87 | throw Error('Invalid Session Model');
88 | }
89 | validateKernelId(info.kernel);
90 | if (typeof info.id !== 'string') {
91 | throw Error('Invalid Session Model');
92 | }
93 | validateNotebookId(info.notebook);
94 | }
95 | exports.validateSessionId = validateSessionId;
96 | /**
97 | * Validate an object as being of INotebookId type.
98 | */
99 | function validateNotebookId(model) {
100 | if ((!model.hasOwnProperty('path')) || (typeof model.path !== 'string')) {
101 | throw Error('Invalid Notebook Model');
102 | }
103 | }
104 | exports.validateNotebookId = validateNotebookId;
105 | /**
106 | * Validate an object as being of IKernelSpecID type.
107 | */
108 | function validateKernelSpec(info) {
109 | var err = new Error("Invalid KernelSpec Model");
110 | if (!info.hasOwnProperty('name') || typeof info.name !== 'string') {
111 | throw err;
112 | }
113 | if (!info.hasOwnProperty('spec') || !info.hasOwnProperty('resources')) {
114 | throw err;
115 | }
116 | var spec = info.spec;
117 | if (!spec.hasOwnProperty('language') || typeof spec.language !== 'string') {
118 | throw err;
119 | }
120 | if (!spec.hasOwnProperty('display_name') ||
121 | typeof spec.display_name !== 'string') {
122 | throw err;
123 | }
124 | if (!spec.hasOwnProperty('argv') || !Array.isArray(spec.argv)) {
125 | throw err;
126 | }
127 | }
128 | exports.validateKernelSpec = validateKernelSpec;
129 | //# sourceMappingURL=validate.js.map
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright (c) 2015 Phosphor Contributors
3 | Distributed under the terms of the BSD 3-Clause License.
4 | The full license is in the file LICENSE, distributed with this software.
5 | """
6 | import subprocess
7 | import sys
8 |
9 | import webbrowser
10 | import tornado.web
11 |
12 |
13 | class MainPageHandler(tornado.web.RequestHandler):
14 |
15 | def get(self):
16 | return self.render("index.html", static=self.static_url)
17 |
18 |
19 | def main(argv):
20 |
21 | url = "http://localhost:8765"
22 |
23 | handlers = [
24 | (r"/", MainPageHandler),
25 | (r'/(.*)', tornado.web.StaticFileHandler,
26 | {'path': '.'}),
27 | (r'/components/font-awesome/fonts/(.*)', tornado.web.StaticFileHandler,
28 | {'path': './components/font-awesome/fonts/'}),
29 | ]
30 |
31 | nb_command = [sys.executable, '-m', 'notebook', '--no-browser',
32 | '--NotebookApp.allow_origin="%s"' % url]
33 | nb_server = subprocess.Popen(nb_command, stderr=subprocess.STDOUT,
34 | stdout=subprocess.PIPE)
35 |
36 | # wait for notebook server to start up
37 | while 1:
38 | line = nb_server.stdout.readline().decode('utf-8').strip()
39 | if not line:
40 | continue
41 | print(line)
42 | if 'The IPython Notebook is running at: http://localhost:8888/':
43 | break
44 | if 'Control-C' in line:
45 | raise ValueError(
46 | 'The port 8888 was already taken, kill running notebook servers'
47 | )
48 |
49 | app = tornado.web.Application(handlers, static_path='build',
50 | template_path='.')
51 |
52 | app.listen(8765, 'localhost')
53 | loop = tornado.ioloop.IOLoop.instance()
54 | print('Browse to http://localhost:8765')
55 | #loop.add_callback(webbrowser.open, url)
56 | try:
57 | loop.start()
58 | except KeyboardInterrupt:
59 | print(" Shutting down on SIGINT")
60 | finally:
61 | nb_server.kill()
62 | loop.close()
63 |
64 | if __name__ == '__main__':
65 | main(sys.argv)
66 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "clean": "rimraf build",
4 | "build:src": "tsc --project src",
5 | "build:css": "node scripts/copycss.js",
6 | "build:browser": "browserify -t browserify-css build/index.js -o build/bundle.js",
7 | "build": "npm run build:src && npm run build:css && npm run build:browser",
8 | "postinstall": "npm dedupe && cd jupyter-js-services && npm install"
9 | },
10 | "dependencies": {
11 | "phosphor-arrays": "^1.0.4",
12 | "phosphor-boxpanel": "^0.9.3",
13 | "phosphor-disposable": "^1.0.2",
14 | "phosphor-dockpanel": "^0.9.1",
15 | "phosphor-domutil": "^0.9.4",
16 | "phosphor-keymap": "^0.1.0",
17 | "phosphor-menus": "^0.9.4",
18 | "phosphor-properties": "^1.1.0",
19 | "phosphor-splitpanel": "^0.9.4",
20 | "phosphor-stackedpanel": "^0.9.4",
21 | "phosphor-tabs": "^0.9.5",
22 | "phosphor-widget": "^0.9.8",
23 | "term.js": "^0.0.7"
24 | },
25 | "devDependencies": {
26 | "browserify": "^11.0.1",
27 | "browserify-css": "^0.6.1",
28 | "browserify-istanbul": "^0.2.1",
29 | "coveralls": "^2.11.4",
30 | "expect.js": "^0.3.1",
31 | "glob-copy": "^0.1.0",
32 | "mocha": "^2.2.5",
33 | "rimraf": "^2.4.2",
34 | "glob": "^5.0.14",
35 | "less": "~2",
36 | "jquery": "^2.1.4",
37 | "jupyter-js-output-area": "^0.0.5",
38 | "jupyter-js-services": "git://github.com/jupyter/jupyter-js-services.git",
39 | "mkdirp": "^0.5.1",
40 | "requirejs": "^2.1.20",
41 | "typedoc": "git://github.com/phosphorjs/typedoc.git",
42 | "typescript": "^1.6.2",
43 | "underscore": "^1.8.3"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/phosphor_demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blink1073/jupyter_demo/906c18f008cd1ca60c440d07a981b8092fe9f3d9/phosphor_demo.gif
--------------------------------------------------------------------------------
/scripts/copycss.js:
--------------------------------------------------------------------------------
1 | var cp = require('glob-copy');
2 | cp.sync('src/*.css', 'build');
3 |
--------------------------------------------------------------------------------
/src/celltoolbar.ts:
--------------------------------------------------------------------------------
1 | // Copyright (c) Jupyter Development Team.
2 | // Distributed under the terms of the Modified BSD License.
3 | "use strict";
4 |
5 | export
6 | declare var CellToolbar: any;
7 |
8 |
9 | CellToolbar = function (options) {
10 | /**
11 | * Constructor
12 | *
13 | * Parameters:
14 | * options: dictionary
15 | * Dictionary of keyword arguments.
16 | * events: $(Events) instance
17 | * cell: Cell instance
18 | * notebook: Notebook instance
19 | *
20 | * TODO: This leaks, when cell are deleted
21 | * There is still a reference to each celltoolbars.
22 | */
23 | CellToolbar._instances.push(this);
24 | this.notebook = options.notebook;
25 | this.cell = options.cell;
26 | this.create_element();
27 | this.rebuild();
28 | return this;
29 | };
30 |
31 |
32 | CellToolbar.prototype.create_element = function () {
33 | this.inner_element = $('').addClass('celltoolbar');
34 | this.element = $('').addClass('ctb_hideshow')
35 | .append(this.inner_element);
36 | };
37 |
38 |
39 | // The default css style for the outer celltoolbar div
40 | // (ctb_hideshow) is display: none.
41 | // To show the cell toolbar, *both* of the following conditions must be met:
42 | // - A parent container has class `ctb_global_show`
43 | // - The celltoolbar has the class `ctb_show`
44 | // This allows global show/hide, as well as per-cell show/hide.
45 |
46 | CellToolbar.global_hide = function () {
47 | $('body').removeClass('ctb_global_show');
48 | };
49 |
50 |
51 | CellToolbar.global_show = function () {
52 | $('body').addClass('ctb_global_show');
53 | };
54 |
55 |
56 | CellToolbar.prototype.hide = function () {
57 | this.element.removeClass('ctb_show');
58 | };
59 |
60 |
61 | CellToolbar.prototype.show = function () {
62 | this.element.addClass('ctb_show');
63 | };
64 |
65 |
66 | /**
67 | * Class variable that should contain a dict of all available callback
68 | * we need to think of wether or not we allow nested namespace
69 | * @property _callback_dict
70 | * @private
71 | * @static
72 | * @type Dict
73 | */
74 | CellToolbar._callback_dict = {};
75 |
76 |
77 | /**
78 | * Class variable that should contain the reverse order list of the button
79 | * to add to the toolbar of each cell
80 | * @property _ui_controls_list
81 | * @private
82 | * @static
83 | * @type List
84 | */
85 | CellToolbar._ui_controls_list = [];
86 |
87 |
88 | /**
89 | * Class variable that should contain the CellToolbar instances for each
90 | * cell of the notebook
91 | *
92 | * @private
93 | * @property _instances
94 | * @static
95 | * @type List
96 | */
97 | CellToolbar._instances = [];
98 |
99 |
100 | /**
101 | * keep a list of all the available presets for the toolbar
102 | * @private
103 | * @property _presets
104 | * @static
105 | * @type Dict
106 | */
107 | CellToolbar._presets = {};
108 |
109 |
110 | // this is by design not a prototype.
111 | /**
112 | * Register a callback to create an UI element in a cell toolbar.
113 | * @method register_callback
114 | * @param name {String} name to use to refer to the callback. It is advised to use a prefix with the name
115 | * for easier sorting and avoid collision
116 | * @param callback {function(div, cell)} callback that will be called to generate the ui element
117 | * @param [cell_types] {List_of_String|undefined} optional list of cell types. If present the UI element
118 | * will be added only to cells of types in the list.
119 | *
120 | *
121 | * The callback will receive the following element :
122 | *
123 | * * a div in which to add element.
124 | * * the cell it is responsible from
125 | *
126 | * @example
127 | *
128 | * Example that create callback for a button that toggle between `true` and `false` label,
129 | * with the metadata under the key 'foo' to reflect the status of the button.
130 | *
131 | * // first param reference to a DOM div
132 | * // second param reference to the cell.
133 | * var toggle = function(div, cell) {
134 | * var button_container = $(div)
135 | *
136 | * // let's create a button that show the current value of the metadata
137 | * var button = $('').button({label:String(cell.metadata.foo)});
138 | *
139 | * // On click, change the metadata value and update the button label
140 | * button.click(function(){
141 | * var v = cell.metadata.foo;
142 | * cell.metadata.foo = !v;
143 | * button.button("option", "label", String(!v));
144 | * })
145 | *
146 | * // add the button to the DOM div.
147 | * button_container.append(button);
148 | * }
149 | *
150 | * // now we register the callback under the name `foo` to give the
151 | * // user the ability to use it later
152 | * CellToolbar.register_callback('foo', toggle);
153 | */
154 | CellToolbar.register_callback = function(name, callback, cell_types) {
155 | // Overwrite if it already exists.
156 | CellToolbar._callback_dict[name] = cell_types ? {callback: callback, cell_types: cell_types} : callback;
157 | };
158 |
159 |
160 | /**
161 | * Register a preset of UI element in a cell toolbar.
162 | * Not supported Yet.
163 | * @method register_preset
164 | * @param name {String} name to use to refer to the preset. It is advised to use a prefix with the name
165 | * for easier sorting and avoid collision
166 | * @param preset_list {List_of_String} reverse order of the button in the toolbar. Each String of the list
167 | * should correspond to a name of a registerd callback.
168 | *
169 | * @private
170 | * @example
171 | *
172 | * CellToolbar.register_callback('foo.c1', function(div, cell){...});
173 | * CellToolbar.register_callback('foo.c2', function(div, cell){...});
174 | * CellToolbar.register_callback('foo.c3', function(div, cell){...});
175 | * CellToolbar.register_callback('foo.c4', function(div, cell){...});
176 | * CellToolbar.register_callback('foo.c5', function(div, cell){...});
177 | *
178 | * CellToolbar.register_preset('foo.foo_preset1', ['foo.c1', 'foo.c2', 'foo.c5'])
179 | * CellToolbar.register_preset('foo.foo_preset2', ['foo.c4', 'foo.c5'])
180 | */
181 | CellToolbar.register_preset = function(name, preset_list, notebook) {
182 | CellToolbar._presets[name] = preset_list;
183 | //events.trigger('preset_added.CellToolbar', {name: name});
184 | // When "register_callback" is called by a custom extension, it may be executed after notebook is loaded.
185 | // In that case, activate the preset if needed.
186 | if (notebook && notebook.metadata && notebook.metadata.celltoolbar === name){
187 | CellToolbar.activate_preset(name);
188 | }
189 | };
190 |
191 | /**
192 | * unregister the selected preset,
193 | *
194 | * return true if preset successfully unregistered
195 | * false otherwise
196 | *
197 | **/
198 | CellToolbar.unregister_preset = function(name){
199 | if(CellToolbar._presets[name]){
200 | delete CellToolbar._presets[name];
201 | //events.trigger('unregistered_preset.CellToolbar', {name: name});
202 | return true
203 | }
204 | return false
205 | }
206 |
207 |
208 | /**
209 | * List the names of the presets that are currently registered.
210 | *
211 | * @method list_presets
212 | * @static
213 | */
214 | CellToolbar.list_presets = function() {
215 | var keys = [];
216 | for (var k in CellToolbar._presets) {
217 | keys.push(k);
218 | }
219 | return keys;
220 | };
221 |
222 |
223 | /**
224 | * Activate an UI preset from `register_preset`
225 | *
226 | * This does not update the selection UI.
227 | *
228 | * @method activate_preset
229 | * @param preset_name {String} string corresponding to the preset name
230 | *
231 | * @static
232 | * @private
233 | * @example
234 | *
235 | * CellToolbar.activate_preset('foo.foo_preset1');
236 | */
237 | CellToolbar.activate_preset = function(preset_name){
238 | var preset = CellToolbar._presets[preset_name];
239 |
240 | if(preset !== undefined){
241 | CellToolbar._ui_controls_list = preset;
242 | CellToolbar.rebuild_all();
243 | }
244 |
245 | //events.trigger('preset_activated.CellToolbar', {name: preset_name});
246 | };
247 |
248 |
249 | /**
250 | * This should be called on the class and not on a instance as it will trigger
251 | * rebuild of all the instances.
252 | * @method rebuild_all
253 | * @static
254 | *
255 | */
256 | CellToolbar.rebuild_all = function(){
257 | for(var i=0; i < CellToolbar._instances.length; i++){
258 | CellToolbar._instances[i].rebuild();
259 | }
260 | };
261 |
262 | /**
263 | * Rebuild all the button on the toolbar to update its state.
264 | * @method rebuild
265 | */
266 | CellToolbar.prototype.rebuild = function(){
267 | /**
268 | * strip evrything from the div
269 | * which is probably inner_element
270 | * or this.element.
271 | */
272 | this.inner_element.empty();
273 | this.ui_controls_list = [];
274 |
275 | var callbacks = CellToolbar._callback_dict;
276 | var preset = CellToolbar._ui_controls_list;
277 | // Yes we iterate on the class variable, not the instance one.
278 | for (var i=0; i < preset.length; i++) {
279 | var key = preset[i];
280 | var callback = callbacks[key];
281 | if (!callback) continue;
282 |
283 | if (typeof callback === 'object') {
284 | if (callback.cell_types.indexOf(this.cell.cell_type) === -1) continue;
285 | callback = callback.callback;
286 | }
287 |
288 | var local_div = $('').addClass('button_container');
289 | try {
290 | callback(local_div, this.cell, this);
291 | this.ui_controls_list.push(key);
292 | } catch (e) {
293 | console.log("Error in cell toolbar callback " + key, e);
294 | continue;
295 | }
296 | // only append if callback succeeded.
297 | this.inner_element.append(local_div);
298 | }
299 |
300 | // If there are no controls or the cell is a rendered TextCell hide the toolbar.
301 | if (!this.ui_controls_list.length) {
302 | this.hide();
303 | } else {
304 | this.show();
305 | }
306 | };
307 |
308 |
309 | CellToolbar.utils = {};
310 |
311 |
312 | /**
313 | * A utility function to generate bindings between a checkbox and cell/metadata
314 | * @method utils.checkbox_ui_generator
315 | * @static
316 | *
317 | * @param name {string} Label in front of the checkbox
318 | * @param setter {function( cell, newValue )}
319 | * A setter method to set the newValue
320 | * @param getter {function( cell )}
321 | * A getter methods which return the current value.
322 | *
323 | * @return callback {function( div, cell )} Callback to be passed to `register_callback`
324 | *
325 | * @example
326 | *
327 | * An exmple that bind the subkey `slideshow.isSectionStart` to a checkbox with a `New Slide` label
328 | *
329 | * var newSlide = CellToolbar.utils.checkbox_ui_generator('New Slide',
330 | * // setter
331 | * function(cell, value){
332 | * // we check that the slideshow namespace exist and create it if needed
333 | * if (cell.metadata.slideshow == undefined){cell.metadata.slideshow = {}}
334 | * // set the value
335 | * cell.metadata.slideshow.isSectionStart = value
336 | * },
337 | * //geter
338 | * function(cell){ var ns = cell.metadata.slideshow;
339 | * // if the slideshow namespace does not exist return `undefined`
340 | * // (will be interpreted as `false` by checkbox) otherwise
341 | * // return the value
342 | * return (ns == undefined)? undefined: ns.isSectionStart
343 | * }
344 | * );
345 | *
346 | * CellToolbar.register_callback('newSlide', newSlide);
347 | *
348 | */
349 | CellToolbar.utils.checkbox_ui_generator = function(name, setter, getter){
350 | return function(div, cell, celltoolbar) {
351 | var button_container = $(div);
352 |
353 | var chkb = $('').attr('type', 'checkbox');
354 | var lbl = $('').append($('').text(name));
355 | lbl.append(chkb);
356 | chkb.attr("checked", getter(cell));
357 |
358 | chkb.click(function(){
359 | var v = getter(cell);
360 | setter(cell, !v);
361 | (chkb).attr("checked", !v);
362 | });
363 | button_container.append($('').append(lbl));
364 | };
365 | };
366 |
367 |
368 | /**
369 | * A utility function to generate bindings between a input field and cell/metadata
370 | * @method utils.input_ui_generator
371 | * @static
372 | *
373 | * @param name {string} Label in front of the input field
374 | * @param setter {function( cell, newValue )}
375 | * A setter method to set the newValue
376 | * @param getter {function( cell )}
377 | * A getter methods which return the current value.
378 | *
379 | * @return callback {function( div, cell )} Callback to be passed to `register_callback`
380 | *
381 | */
382 | CellToolbar.utils.input_ui_generator = function(name, setter, getter){
383 | return function(div, cell, celltoolbar) {
384 | var button_container = $(div);
385 |
386 | var text = $('').attr('type', 'text');
387 | var lbl = $('').append($('').text(name));
388 | lbl.append(text);
389 | text.attr("value", getter(cell));
390 |
391 | text.keyup(function(){
392 | setter(cell, text.val());
393 | });
394 | button_container.append($('').append(lbl));
395 | //IPython.keyboard_manager.register_events(text);
396 | };
397 | };
398 |
399 | /**
400 | * A utility function to generate bindings between a dropdown list cell
401 | * @method utils.select_ui_generator
402 | * @static
403 | *
404 | * @param list_list {list_of_sublist} List of sublist of metadata value and name in the dropdown list.
405 | * subslit shoud contain 2 element each, first a string that woul be displayed in the dropdown list,
406 | * and second the corresponding value to be passed to setter/return by getter. the corresponding value
407 | * should not be "undefined" or behavior can be unexpected.
408 | * @param setter {function( cell, newValue )}
409 | * A setter method to set the newValue
410 | * @param getter {function( cell )}
411 | * A getter methods which return the current value of the metadata.
412 | * @param [label=""] {String} optionnal label for the dropdown menu
413 | *
414 | * @return callback {function( div, cell )} Callback to be passed to `register_callback`
415 | *
416 | * @example
417 | *
418 | * var select_type = CellToolbar.utils.select_ui_generator([
419 | * ["" , "None" ],
420 | * ["Header Slide" , "header_slide" ],
421 | * ["Slide" , "slide" ],
422 | * ["Fragment" , "fragment" ],
423 | * ["Skip" , "skip" ],
424 | * ],
425 | * // setter
426 | * function(cell, value){
427 | * // we check that the slideshow namespace exist and create it if needed
428 | * if (cell.metadata.slideshow == undefined){cell.metadata.slideshow = {}}
429 | * // set the value
430 | * cell.metadata.slideshow.slide_type = value
431 | * },
432 | * //geter
433 | * function(cell){ var ns = cell.metadata.slideshow;
434 | * // if the slideshow namespace does not exist return `undefined`
435 | * // (will be interpreted as `false` by checkbox) otherwise
436 | * // return the value
437 | * return (ns == undefined)? undefined: ns.slide_type
438 | * }
439 | * CellToolbar.register_callback('slideshow.select', select_type);
440 | *
441 | */
442 | CellToolbar.utils.select_ui_generator = function(list_list, setter, getter, label) {
443 | label = label || "";
444 | return function(div, cell, celltoolbar) {
445 | var button_container = $(div);
446 | var lbl = $("").append($('').text(label));
447 | var select = $('');
448 | for(var i=0; i < list_list.length; i++){
449 | var opt = $('')
450 | .attr('value', list_list[i][1])
451 | .text(list_list[i][0]);
452 | select.append(opt);
453 | }
454 | select.val(getter(cell));
455 | select.change(function(){
456 | setter(cell, select.val());
457 | });
458 | button_container.append($('').append(lbl).append(select));
459 | };
460 | };
461 |
462 |
--------------------------------------------------------------------------------
/src/codecell.ts:
--------------------------------------------------------------------------------
1 | // Copyright (c) Jupyter Development Team.
2 | // Distributed under the terms of the Modified BSD License.
3 | /**
4 | *
5 | *
6 | * @module codecell
7 | * @namespace codecell
8 | * @class CodeCell
9 | */
10 | "use strict";
11 |
12 | import { IKernel, KernelStatus } from '../jupyter-js-services';
13 |
14 | var outputarea = require('jupyter-js-output-area');
15 | var utils = require('./utils');
16 | var keyboard = require('./keyboard');
17 | var cell = require('./cell');
18 | var completer = require('./completer');
19 | var celltoolbar = require('./celltoolbar');
20 | var $ = require('jquery');
21 |
22 | var Cell = cell.Cell;
23 |
24 | /* local util for codemirror */
25 | var posEq = function(a, b) {return a.line === b.line && a.ch === b.ch;};
26 |
27 | /**
28 | *
29 | * function to delete until previous non blanking space character
30 | * or first multiple of 4 tabstop.
31 | * @private
32 | */
33 | (CodeMirror).commands.delSpaceToPrevTabStop = function(cm){
34 | var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
35 | if (!posEq(from, to)) { cm.replaceRange("", from, to); return; }
36 | var cur = cm.getCursor(), line = cm.getLine(cur.line);
37 | var tabsize = cm.getOption('tabSize');
38 | var chToPrevTabStop = cur.ch-(Math.ceil(cur.ch/tabsize)-1)*tabsize;
39 | from = {ch:cur.ch-chToPrevTabStop,line:cur.line};
40 | var select = cm.getRange(from,cur);
41 | if( select.match(/^\ +$/) !== null){
42 | cm.replaceRange("",from,cur);
43 | } else {
44 | cm.deleteH(-1,"char");
45 | }
46 | };
47 |
48 | var keycodes = keyboard.keycodes;
49 |
50 | export
51 | var CodeCell = function (kernel: IKernel, options) {
52 | /**
53 | * Constructor
54 | *
55 | * A Cell conceived to write code.
56 | *
57 | * Parameters:
58 | * kernel: Kernel instance
59 | * options: dictionary
60 | * Dictionary of keyword arguments.
61 | * events: $(Events) instance
62 | * config: dictionary
63 | * keyboard_manager: KeyboardManager instance
64 | * notebook: Notebook instance
65 | * tooltip: Tooltip instance
66 | */
67 | this.kernel = kernel;
68 | this.collapsed = false;
69 | this.events = options.events;
70 | this.tooltip = options.tooltip;
71 |
72 | // create all attributed in constructor function
73 | // even if null for V8 VM optimisation
74 | this.input_prompt_number = null;
75 | this.celltoolbar = null;
76 |
77 | this.last_msg_id = null;
78 | this.completer = null;
79 |
80 | Cell.apply(this,[{
81 | config: $.extend({}, (CodeCell).options_default),
82 | keyboard_manager: options.keyboard_manager,
83 | events: this.events}]);
84 |
85 | // Attributes we want to override in this subclass.
86 | this.cell_type = "code";
87 | var that = this;
88 | this.element.focusout(
89 | function() { that.auto_highlight(); }
90 | );
91 | };
92 |
93 | (CodeCell).options_default = {
94 | cm_config : {
95 | extraKeys: {
96 | "Tab" : "indentMore",
97 | "Shift-Tab" : "indentLess",
98 | "Backspace" : "delSpaceToPrevTabStop",
99 | "Cmd-/" : "toggleComment",
100 | "Ctrl-/" : "toggleComment"
101 | },
102 | mode: 'text',
103 | theme: 'ipython',
104 | matchBrackets: true,
105 | autoCloseBrackets: true
106 | },
107 | highlight_modes : {
108 | 'magic_javascript' :{'reg':['^%%javascript']},
109 | 'magic_perl' :{'reg':['^%%perl']},
110 | 'magic_ruby' :{'reg':['^%%ruby']},
111 | 'magic_python' :{'reg':['^%%python3?']},
112 | 'magic_shell' :{'reg':['^%%bash']},
113 | 'magic_r' :{'reg':['^%%R']},
114 | 'magic_text/x-cython' :{'reg':['^%%cython']},
115 | },
116 | };
117 |
118 | (CodeCell).config_defaults = (CodeCell).options_default;
119 |
120 | (CodeCell).msg_cells = {};
121 |
122 | CodeCell.prototype = Object.create(Cell.prototype);
123 |
124 | /** @method create_element */
125 | CodeCell.prototype.create_element = function () {
126 | Cell.prototype.create_element.apply(this, arguments);
127 | var that = this;
128 |
129 | var cell = $('').addClass('cell code_cell');
130 | cell.attr('tabindex','2');
131 |
132 | var input = $('').addClass('input');
133 | this.input = input;
134 | var prompt = $('').addClass('prompt input_prompt');
135 | var inner_cell = $('').addClass('inner_cell');
136 | this.celltoolbar = new celltoolbar.CellToolbar({
137 | cell: this,
138 | notebook: this.notebook});
139 | inner_cell.append(this.celltoolbar.element);
140 | var input_area = $('').addClass('input_area');
141 | this.code_mirror = new (CodeMirror)(input_area.get(0), this._options.cm_config);
142 |
143 | this.code_mirror.setOption("mode", "python");
144 | // In case of bugs that put the keyboard manager into an inconsistent state,
145 | // ensure KM is enabled when CodeMirror is focused:
146 | this.code_mirror.on('focus', function () {
147 | if (that.keyboard_manager) {
148 | that.keyboard_manager.enable();
149 | }
150 | });
151 | this.code_mirror.on('keydown', $.proxy(this.handle_keyevent,this));
152 | $(this.code_mirror.getInputField()).attr("spellcheck", "false");
153 |
154 | inner_cell.append(input_area);
155 | input.append(prompt).append(inner_cell);
156 |
157 | this.element = cell;
158 |
159 | this.output_model = new outputarea.OutputModel();
160 | this.output_view = new outputarea.OutputView(this.output_model, document);
161 | this.output_view.el.className = 'output_area';
162 |
163 | var output_area = $('').addClass('output_area');
164 | var output_prompt = $('').addClass('prompt output_prompt');
165 |
166 | output_area.append(output_prompt);
167 | output_area.append(this.output_view.el);
168 | cell.append(input).append(output_area);
169 |
170 | this.completer = new completer.Completer(this, this.events);
171 | };
172 |
173 | /** @method bind_events */
174 | CodeCell.prototype.bind_events = function () {
175 | Cell.prototype.bind_events.apply(this);
176 | var that = this;
177 |
178 | this.element.focusout(
179 | function() { that.auto_highlight(); }
180 | );
181 | };
182 |
183 |
184 | /**
185 | * This method gets called in CodeMirror's onKeyDown/onKeyPress
186 | * handlers and is used to provide custom key handling. Its return
187 | * value is used to determine if CodeMirror should ignore the event:
188 | * true = ignore, false = don't ignore.
189 | * @method handle_codemirror_keyevent
190 | */
191 |
192 | CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
193 |
194 | var that = this;
195 | // whatever key is pressed, first, cancel the tooltip request before
196 | // they are sent, and remove tooltip if any, except for tab again
197 | var tooltip_closed = null;
198 | if (event.type === 'keydown' && event.which !== keycodes.tab ) {
199 | tooltip_closed = this.tooltip.remove_and_cancel_tooltip();
200 | }
201 |
202 | var cur = editor.getCursor();
203 | if (event.keyCode === keycodes.enter){
204 | this.auto_highlight();
205 | }
206 |
207 | if (event.which === keycodes.down && event.type === 'keypress' && this.tooltip.time_before_tooltip >= 0) {
208 | // triger on keypress (!) otherwise inconsistent event.which depending on plateform
209 | // browser and keyboard layout !
210 | // Pressing '(' , request tooltip, don't forget to reappend it
211 | // The second argument says to hide the tooltip if the docstring
212 | // is actually empty
213 | this.tooltip.pending(that, true);
214 | } else if ( tooltip_closed && event.which === keycodes.esc && event.type === 'keydown') {
215 | // If tooltip is active, cancel it. The call to
216 | // remove_and_cancel_tooltip above doesn't pass, force=true.
217 | // Because of this it won't actually close the tooltip
218 | // if it is in sticky mode. Thus, we have to check again if it is open
219 | // and close it with force=true.
220 | if (!this.tooltip._hidden) {
221 | this.tooltip.remove_and_cancel_tooltip(true);
222 | }
223 | // If we closed the tooltip, don't let CM or the global handlers
224 | // handle this event.
225 | event.codemirrorIgnore = true;
226 | event._ipkmIgnore = true;
227 | event.preventDefault();
228 | return true;
229 | } else if (event.keyCode === keycodes.tab && event.type === 'keydown' && event.shiftKey) {
230 | if (editor.somethingSelected() || editor.getSelections().length !== 1){
231 | var anchor = editor.getCursor("anchor");
232 | var head = editor.getCursor("head");
233 | if( anchor.line !== head.line){
234 | return false;
235 | }
236 | }
237 | var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
238 | if (pre_cursor.trim() === "") {
239 | // Don't show tooltip if the part of the line before the cursor
240 | // is empty. In this case, let CodeMirror handle indentation.
241 | return false;
242 | }
243 | this.tooltip.request(that);
244 | event.codemirrorIgnore = true;
245 | event.preventDefault();
246 | return true;
247 | } else if (event.keyCode === keycodes.tab && event.type === 'keydown') {
248 | // Tab completion.
249 | this.tooltip.remove_and_cancel_tooltip();
250 |
251 | // completion does not work on multicursor, it might be possible though in some cases
252 | if (editor.somethingSelected() || editor.getSelections().length > 1) {
253 | return false;
254 | }
255 | var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
256 | if (pre_cursor.trim() === "") {
257 | // Don't autocomplete if the part of the line before the cursor
258 | // is empty. In this case, let CodeMirror handle indentation.
259 | return false;
260 | } else {
261 | event.codemirrorIgnore = true;
262 | event.preventDefault();
263 | this.completer.startCompletion();
264 | return true;
265 | }
266 | }
267 |
268 | // keyboard event wasn't one of those unique to code cells, let's see
269 | // if it's one of the generic ones (i.e. check edit mode shortcuts)
270 | return Cell.prototype.handle_codemirror_keyevent.apply(this, [editor, event]);
271 | };
272 |
273 | // Kernel related calls.
274 |
275 | CodeCell.prototype.set_kernel = function (kernel) {
276 | this.kernel = kernel;
277 | };
278 |
279 | /**
280 | * Execute current code cell to the kernel
281 | * @method execute
282 | */
283 | CodeCell.prototype.execute = function (stop_on_error) {
284 |
285 | this.output_model.state = [];
286 |
287 | if (stop_on_error === undefined) {
288 | stop_on_error = true;
289 | }
290 |
291 |
292 | if (this.get_text().trim().length === 0) {
293 | // nothing to do
294 | this.set_input_prompt(null);
295 | return;
296 | }
297 | this.set_input_prompt('*');
298 | this.element.addClass("running");
299 |
300 | var options = {
301 | code: this.get_text(),
302 | silent: false,
303 | store_history: true,
304 | stop_on_error: stop_on_error
305 | }
306 | var future = this.kernel.execute(options);
307 | future.onReply = (msg) => {
308 | this._handle_execute_reply(msg);
309 | /*s
310 | payload : {
311 | set_next_input : $.proxy(this._handle_set_next_input, this),
312 | page : $.proxy(this._open_with_pager, this)
313 | }
314 | */
315 | }
316 |
317 | future.onIOPub = (msg) => {
318 | this.output_model.consumeMessage(msg);
319 | }
320 |
321 | future.onInput = (msg) => {
322 | this._handle_input_request(msg);
323 | }
324 |
325 | this.render();
326 | this.events.trigger('execute.CodeCell', {cell: this});
327 | };
328 |
329 | CodeCell.prototype._open_with_pager = function (payload) {
330 | this.events.trigger('open_with_text.Pager', payload);
331 | };
332 |
333 | /**
334 | * @method _handle_execute_reply
335 | * @private
336 | */
337 | CodeCell.prototype._handle_execute_reply = function (msg) {
338 | this.set_input_prompt(msg.content.execution_count);
339 | this.element.removeClass("running");
340 | this.events.trigger('set_dirty.Notebook', {value: true});
341 | };
342 |
343 | /**
344 | * @method _handle_set_next_input
345 | * @private
346 | */
347 | CodeCell.prototype._handle_set_next_input = function (payload) {
348 | var data = {'cell': this, 'text': payload.text, replace: payload.replace};
349 | this.events.trigger('set_next_input.Notebook', data);
350 | };
351 |
352 | /**
353 | * @method _handle_input_request
354 | * @private
355 | */
356 | CodeCell.prototype._handle_input_request = function (msg) {
357 | //this.output_area.append_raw_input(msg);
358 | };
359 |
360 |
361 | // Basic cell manipulation.
362 |
363 | CodeCell.prototype.select = function () {
364 | var cont = Cell.prototype.select.apply(this);
365 | if (cont) {
366 | this.code_mirror.refresh();
367 | this.auto_highlight();
368 | }
369 | return cont;
370 | };
371 |
372 | CodeCell.prototype.render = function () {
373 | var cont = Cell.prototype.render.apply(this);
374 | // Always execute, even if we are already in the rendered state
375 | return cont;
376 | };
377 |
378 | CodeCell.prototype.select_all = function () {
379 | var start = {line: 0, ch: 0};
380 | var nlines = this.code_mirror.lineCount();
381 | var last_line = this.code_mirror.getLine(nlines-1);
382 | var end = {line: nlines-1, ch: last_line.length};
383 | this.code_mirror.setSelection(start, end);
384 | };
385 |
386 |
387 | CodeCell.prototype.collapse_output = function () {
388 | //this.output_area.collapse();
389 | };
390 |
391 |
392 | CodeCell.prototype.expand_output = function () {
393 | //this.output_area.expand();
394 | //this.output_area.unscroll_area();
395 | };
396 |
397 | CodeCell.prototype.scroll_output = function () {
398 | //this.output_area.expand();
399 | //this.output_area.scroll_if_long();
400 | };
401 |
402 | CodeCell.prototype.toggle_output = function () {
403 | //this.output_area.toggle_output();
404 | };
405 |
406 | CodeCell.prototype.toggle_output_scroll = function () {
407 | //this.output_area.toggle_scroll();
408 | };
409 |
410 |
411 | (CodeCell).input_prompt_classical = function (prompt_value, lines_number) {
412 | var ns;
413 | if (prompt_value === undefined || prompt_value === null) {
414 | ns = " ";
415 | } else {
416 | ns = encodeURIComponent(prompt_value);
417 | }
418 | return 'In [' + ns + ']:';
419 | };
420 |
421 | (CodeCell).input_prompt_continuation = function (prompt_value, lines_number) {
422 | var html = [(CodeCell).input_prompt_classical(prompt_value, lines_number)];
423 | for(var i=1; i < lines_number; i++) {
424 | html.push(['...:']);
425 | }
426 | return html.join('
');
427 | };
428 |
429 | (CodeCell).input_prompt_function = (CodeCell).input_prompt_classical;
430 |
431 |
432 | CodeCell.prototype.set_input_prompt = function (number) {
433 | var nline = 1;
434 | if (this.code_mirror !== undefined) {
435 | nline = this.code_mirror.lineCount();
436 | }
437 | this.input_prompt_number = number;
438 | var prompt_html = (CodeCell).input_prompt_function(this.input_prompt_number, nline);
439 | // This HTML call is okay because the user contents are escaped.
440 | this.element.find('div.input_prompt').html(prompt_html);
441 | };
442 |
443 |
444 | CodeCell.prototype.clear_input = function () {
445 | this.code_mirror.setValue('');
446 | };
447 |
448 |
449 | CodeCell.prototype.get_text = function () {
450 | return this.code_mirror.getValue();
451 | };
452 |
453 |
454 | CodeCell.prototype.set_text = function (code) {
455 | return this.code_mirror.setValue(code);
456 | };
457 |
458 |
459 | CodeCell.prototype.clear_output = function (wait) {
460 | this.output_model.state = [];
461 | this.set_input_prompt();
462 | };
463 |
464 |
465 | // JSON serialization
466 |
467 | CodeCell.prototype.fromJSON = function (data) {
468 | return;
469 | Cell.prototype.fromJSON.apply(this, arguments);
470 | if (data.cell_type === 'code') {
471 | if (data.source !== undefined) {
472 | this.set_text(data.source);
473 | // make this value the starting point, so that we can only undo
474 | // to this state, instead of a blank cell
475 | this.code_mirror.clearHistory();
476 | this.auto_highlight();
477 | }
478 | this.set_input_prompt(data.execution_count);
479 | //this.output_area.trusted = data.metadata.trusted || false;
480 | //this.output_area.fromJSON(data.outputs, data.metadata);
481 | }
482 | };
483 |
484 |
485 | CodeCell.prototype.toJSON = function () {
486 | return;
487 | var data = Cell.prototype.toJSON.apply(this);
488 | data.source = this.get_text();
489 | // is finite protect against undefined and '*' value
490 | if (isFinite(this.input_prompt_number)) {
491 | data.execution_count = this.input_prompt_number;
492 | } else {
493 | data.execution_count = null;
494 | }
495 | var outputs = this.output_area.toJSON();
496 | data.outputs = outputs;
497 | /*
498 | data.metadata.trusted = this.output_area.trusted;
499 | data.metadata.collapsed = this.output_area.collapsed;
500 | if (this.output_area.scroll_state === 'auto') {
501 | delete data.metadata.scrolled;
502 | } else {
503 | data.metadata.scrolled = this.output_area.scroll_state;
504 | }
505 | return data;
506 | */
507 | };
508 |
509 | /**
510 | * handle cell level logic when the cursor moves away from a cell
511 | * @method unselect
512 | * @return is the action being taken
513 | */
514 | CodeCell.prototype.unselect = function (leave_selected) {
515 | var cont = Cell.prototype.unselect.apply(this, [leave_selected]);
516 | if (cont) {
517 | // When a code cell is unselected, make sure that the corresponding
518 | // tooltip and completer to that cell is closed.
519 | this.tooltip.remove_and_cancel_tooltip(true);
520 | if (this.completer !== null) {
521 | this.completer.close();
522 | }
523 | }
524 | return cont;
525 | };
526 |
--------------------------------------------------------------------------------
/src/codemirror-ipython.js:
--------------------------------------------------------------------------------
1 | // IPython mode is just a slightly altered Python Mode with `?` beeing a extra
2 | // single operator. Here we define `ipython` mode in the require `python`
3 | // callback to auto-load python mode, which is more likely not the best things
4 | // to do, but at least the simple one for now.
5 |
6 | (function(mod) {
7 | if (typeof exports == "object" && typeof module == "object"){ // CommonJS
8 | mod(require("codemirror/lib/codemirror"),
9 | require("codemirror/mode/python/python")
10 | );
11 | } else if (typeof define == "function" && define.amd){ // AMD
12 | define(["codemirror/lib/codemirror",
13 | "codemirror/mode/python/python"], mod);
14 | } else {// Plain browser env
15 | mod(CodeMirror);
16 | }
17 | })(function(CodeMirror) {
18 | "use strict";
19 |
20 | CodeMirror.defineMode("ipython", function(conf, parserConf) {
21 | var pythonConf = {};
22 | for (var prop in parserConf) {
23 | if (parserConf.hasOwnProperty(prop)) {
24 | pythonConf[prop] = parserConf[prop];
25 | }
26 | }
27 | pythonConf.name = 'python';
28 | pythonConf.singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!\\?]");
29 | if (pythonConf.version === 3) {
30 | pythonConf.identifiers = new RegExp("^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*");
31 | } else if (pythonConf.version === 2) {
32 | pythonConf.identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
33 | }
34 | return CodeMirror.getMode(conf, pythonConf);
35 | }, 'python');
36 |
37 | CodeMirror.defineMIME("text/x-ipython", "ipython");
38 | })
39 |
--------------------------------------------------------------------------------
/src/codemirror-ipythongfm.js:
--------------------------------------------------------------------------------
1 | // IPython GFM (GitHub Flavored Markdown) mode is just a slightly altered GFM
2 | // Mode with support for latex.
3 | //
4 | // Latex support was supported by Codemirror GFM as of
5 | // https://github.com/codemirror/CodeMirror/pull/567
6 | // But was later removed in
7 | // https://github.com/codemirror/CodeMirror/commit/d9c9f1b1ffe984aee41307f3e927f80d1f23590c
8 |
9 |
10 | (function(mod) {
11 | if (typeof exports == "object" && typeof module == "object"){ // CommonJS
12 | mod(require("codemirror/lib/codemirror")
13 | ,require("codemirror/addon/mode/multiplex")
14 | ,require("codemirror/mode/gfm/gfm")
15 | ,require("codemirror/mode/stex/stex")
16 | );
17 | } else if (typeof define == "function" && define.amd){ // AMD
18 | define(["codemirror/lib/codemirror"
19 | ,"codemirror/addon/mode/multiplex"
20 | ,"codemirror/mode/python/python"
21 | ,"codemirror/mode/stex/stex"
22 | ], mod);
23 | } else {// Plain browser env
24 | mod(CodeMirror);
25 | }
26 | })( function(CodeMirror){
27 | "use strict";
28 |
29 | CodeMirror.defineMode("ipythongfm", function(config, parserConfig) {
30 |
31 | var gfm_mode = CodeMirror.getMode(config, "gfm");
32 | var tex_mode = CodeMirror.getMode(config, "stex");
33 |
34 | return CodeMirror.multiplexingMode(
35 | gfm_mode,
36 | {
37 | open: "$", close: "$",
38 | mode: tex_mode,
39 | delimStyle: "delimit"
40 | },
41 | {
42 | // not sure this works as $$ is interpreted at (opening $, closing $, as defined just above)
43 | open: "$$", close: "$$",
44 | mode: tex_mode,
45 | delimStyle: "delimit"
46 | },
47 | {
48 | open: "\\(", close: "\\)",
49 | mode: tex_mode,
50 | delimStyle: "delimit"
51 | },
52 | {
53 | open: "\\[", close: "\\]",
54 | mode: tex_mode,
55 | delimStyle: "delimit"
56 | }
57 | // .. more multiplexed styles can follow here
58 | );
59 | }, 'gfm');
60 |
61 | CodeMirror.defineMIME("text/x-ipythongfm", "ipythongfm");
62 | })
63 |
--------------------------------------------------------------------------------
/src/completer.ts:
--------------------------------------------------------------------------------
1 | // Copyright (c) Jupyter Development Team.
2 | // Distributed under the terms of the Modified BSD License.
3 | "use strict";
4 |
5 | var utils = require('./utils');
6 | var keyboard = require('./keyboard');
7 | require('./contexthint');
8 |
9 | // easier key mapping
10 | var keycodes = keyboard.keycodes;
11 |
12 | var prepend_n_prc = function(str, n) {
13 | for( var i =0 ; i< n ; i++){
14 | str = '%'+str ;
15 | }
16 | return str;
17 | };
18 |
19 | var _existing_completion = function(item, completion_array){
20 | for( var i=0; i < completion_array.length; i++) {
21 | if (completion_array[i].trim().substr(-item.length) == item) {
22 | return true;
23 | }
24 | }
25 | return false;
26 | };
27 |
28 | // what is the common start of all completions
29 | function shared_start(B, drop_prct) {
30 | if (B.length == 1) {
31 | return B[0];
32 | }
33 | var A = [];
34 | var common;
35 | var min_lead_prct = 10;
36 | for (var i = 0; i < B.length; i++) {
37 | var str = B[i].str;
38 | var localmin = 0;
39 | if(drop_prct === true){
40 | while ( str.substr(0, 1) == '%') {
41 | localmin = localmin+1;
42 | str = str.substring(1);
43 | }
44 | }
45 | min_lead_prct = Math.min(min_lead_prct, localmin);
46 | A.push(str);
47 | }
48 |
49 | if (A.length > 1) {
50 | var tem1, tem2, s;
51 | A = A.slice(0).sort();
52 | tem1 = A[0];
53 | s = tem1.length;
54 | tem2 = A.pop();
55 | while (s && tem2.indexOf(tem1) == -1) {
56 | tem1 = tem1.substring(0, --s);
57 | }
58 | if (tem1 === "" || tem2.indexOf(tem1) !== 0) {
59 | return {
60 | str:prepend_n_prc('', min_lead_prct),
61 | type: "computed",
62 | from: B[0].from,
63 | to: B[0].to
64 | };
65 | }
66 | return {
67 | str: prepend_n_prc(tem1, min_lead_prct),
68 | type: "computed",
69 | from: B[0].from,
70 | to: B[0].to
71 | };
72 | }
73 | return null;
74 | }
75 |
76 |
77 | export
78 | var Completer = function (cell, events) {
79 | this.cell = cell;
80 | this.editor = cell.code_mirror;
81 | var that = this;
82 | events.on('kernel_busy.Kernel', function () {
83 | that.skip_kernel_completion = true;
84 | });
85 | events.on('kernel_idle.Kernel', function () {
86 | that.skip_kernel_completion = false;
87 | });
88 | };
89 |
90 | Completer.prototype.startCompletion = function () {
91 | /**
92 | * call for a 'first' completion, that will set the editor and do some
93 | * special behavior like autopicking if only one completion available.
94 | */
95 | if (this.editor.somethingSelected()|| this.editor.getSelections().length > 1) return;
96 | this.done = false;
97 | // use to get focus back on opera
98 | this.carry_on_completion(true);
99 | };
100 |
101 |
102 | // easy access for julia to monkeypatch
103 | //
104 | (Completer).reinvoke_re = /[%0-9a-z._/\\:~-]/i;
105 |
106 | Completer.prototype.reinvoke= function(pre_cursor, block, cursor){
107 | return (Completer).reinvoke_re.test(pre_cursor);
108 | };
109 |
110 | /**
111 | *
112 | * pass true as parameter if this is the first invocation of the completer
113 | * this will prevent the completer to dissmiss itself if it is not on a
114 | * word boundary like pressing tab after a space, and make it autopick the
115 | * only choice if there is only one which prevent from popping the UI. as
116 | * well as fast-forwarding the typing if all completion have a common
117 | * shared start
118 | **/
119 | Completer.prototype.carry_on_completion = function (first_invocation) {
120 | /**
121 | * Pass true as parameter if you want the completer to autopick when
122 | * only one completion. This function is automatically reinvoked at
123 | * each keystroke with first_invocation = false
124 | */
125 | var cur = this.editor.getCursor();
126 | var line = this.editor.getLine(cur.line);
127 | var pre_cursor = this.editor.getRange({
128 | line: cur.line,
129 | ch: cur.ch - 1
130 | }, cur);
131 |
132 | // we need to check that we are still on a word boundary
133 | // because while typing the completer is still reinvoking itself
134 | // so dismiss if we are on a "bad" caracter
135 | if (!this.reinvoke(pre_cursor) && !first_invocation) {
136 | this.close();
137 | return;
138 | }
139 |
140 | this.autopick = false;
141 | if (first_invocation) {
142 | this.autopick = true;
143 | }
144 |
145 | // We want a single cursor position.
146 | if (this.editor.somethingSelected()|| this.editor.getSelections().length > 1) {
147 | return;
148 | }
149 |
150 | // one kernel completion came back, finish_completing will be called with the results
151 | // we fork here and directly call finish completing if kernel is busy
152 | var cursor_pos = utils.to_absolute_cursor_pos(this.editor, cur);
153 | if (this.skip_kernel_completion) {
154 | this.finish_completing({ content: {
155 | matches: [],
156 | cursor_start: cursor_pos,
157 | cursor_end: cursor_pos,
158 | }});
159 | } else {
160 | var request = { code: this.editor.getValue(),
161 | cursor_pos: cursor_pos };
162 | this.cell.kernel.complete(request).then(content => {
163 | this.finish_completing(content);
164 | });
165 | }
166 | };
167 |
168 | Completer.prototype.finish_completing = function (content) {
169 | /**
170 | * let's build a function that wrap all that stuff into what is needed
171 | * for the new completer:
172 | */
173 | var start = content.cursor_start;
174 | var end = content.cursor_end;
175 | var matches = content.matches;
176 |
177 | var cur = this.editor.getCursor();
178 | if (end === null) {
179 | // adapted message spec replies don't have cursor position info,
180 | // interpret end=null as current position,
181 | // and negative start relative to that
182 | end = utils.to_absolute_cursor_pos(this.editor, cur);
183 | if (start === null) {
184 | start = end;
185 | } else if (start < 0) {
186 | start = end + start;
187 | }
188 | }
189 | var results = (CodeMirror).contextHint(this.editor);
190 | var filtered_results = [];
191 | //remove results from context completion
192 | //that are already in kernel completion
193 | var i;
194 | for (i=0; i < results.length; i++) {
195 | if (!_existing_completion(results[i].str, matches)) {
196 | filtered_results.push(results[i]);
197 | }
198 | }
199 |
200 | // append the introspection result, in order, at at the beginning of
201 | // the table and compute the replacement range from current cursor
202 | // positon and matched_text length.
203 | var from = utils.from_absolute_cursor_pos(this.editor, start);
204 | var to = utils.from_absolute_cursor_pos(this.editor, end);
205 | for (i = matches.length - 1; i >= 0; --i) {
206 | filtered_results.unshift({
207 | str: matches[i],
208 | type: "introspection",
209 | from: from,
210 | to: to
211 | });
212 | }
213 |
214 | // one the 2 sources results have been merge, deal with it
215 | this.raw_result = filtered_results;
216 |
217 | // if empty result return
218 | if (!this.raw_result || !this.raw_result.length) return;
219 |
220 | // When there is only one completion, use it directly.
221 | if (this.autopick && this.raw_result.length == 1) {
222 | this.insert(this.raw_result[0]);
223 | return;
224 | }
225 |
226 | if (this.raw_result.length == 1) {
227 | // test if first and only completion totally matches
228 | // what is typed, in this case dismiss
229 | var str = this.raw_result[0].str;
230 | var pre_cursor = this.editor.getRange({
231 | line: cur.line,
232 | ch: cur.ch - str.length
233 | }, cur);
234 | if (pre_cursor == str) {
235 | this.close();
236 | return;
237 | }
238 | }
239 |
240 | if (!this.visible) {
241 | this.complete = $('').addClass('completions');
242 | this.complete.attr('id', 'complete');
243 |
244 | // Currently webkit doesn't use the size attr correctly. See:
245 | // https://code.google.com/p/chromium/issues/detail?id=4579
246 | this.sel = $('')
247 | .attr('tabindex', -1)
248 | .attr('multiple', 'true');
249 | this.complete.append(this.sel);
250 | this.visible = true;
251 | $('body').append(this.complete);
252 |
253 | //build the container
254 | var that = this;
255 | this.sel.dblclick(function () {
256 | that.pick();
257 | });
258 | this.sel.focus(function () {
259 | that.editor.focus();
260 | });
261 | this._handle_keydown = function (cm, event) {
262 | that.keydown(event);
263 | };
264 | this.editor.on('keydown', this._handle_keydown);
265 | this._handle_keypress = function (cm, event) {
266 | that.keypress(event);
267 | };
268 | this.editor.on('keypress', this._handle_keypress);
269 | }
270 | this.sel.attr('size', Math.min(10, this.raw_result.length));
271 |
272 | // After everything is on the page, compute the postion.
273 | // We put it above the code if it is too close to the bottom of the page.
274 | var pos = this.editor.cursorCoords(
275 | utils.from_absolute_cursor_pos(this.editor, start)
276 | );
277 | var left = pos.left-3;
278 | var top;
279 | var cheight = this.complete.height();
280 | var wheight = $(window).height();
281 | if (pos.bottom+cheight+5 > wheight) {
282 | top = pos.top-cheight-4;
283 | } else {
284 | top = pos.bottom+1;
285 | }
286 | this.complete.css('left', left + 'px');
287 | this.complete.css('top', top + 'px');
288 |
289 | // Clear and fill the list.
290 | this.sel.text('');
291 | this.build_gui_list(this.raw_result);
292 | return true;
293 | };
294 |
295 | Completer.prototype.insert = function (completion) {
296 | this.editor.replaceRange(completion.str, completion.from, completion.to);
297 | };
298 |
299 | Completer.prototype.build_gui_list = function (completions) {
300 | for (var i = 0; i < completions.length; ++i) {
301 | var opt = $('').text(completions[i].str).addClass(completions[i].type);
302 | this.sel.append(opt);
303 | }
304 | this.sel.children().first().attr('selected', 'true');
305 | this.sel.scrollTop(0);
306 | };
307 |
308 | Completer.prototype.close = function () {
309 | this.done = true;
310 | $('#complete').remove();
311 | this.editor.off('keydown', this._handle_keydown);
312 | this.editor.off('keypress', this._handle_keypress);
313 | this.visible = false;
314 | };
315 |
316 | Completer.prototype.pick = function () {
317 | this.insert(this.raw_result[this.sel[0].selectedIndex]);
318 | this.close();
319 | };
320 |
321 | Completer.prototype.keydown = function (event) {
322 | var code = event.keyCode;
323 |
324 | // Enter
325 | var options;
326 | var index;
327 | if (code == keycodes.enter) {
328 | event.codemirrorIgnore = true;
329 | event._ipkmIgnore = true;
330 | event.preventDefault();
331 | this.pick();
332 | // Escape or backspace
333 | } else if (code == keycodes.esc || code == keycodes.backspace) {
334 | event.codemirrorIgnore = true;
335 | event._ipkmIgnore = true;
336 | event.preventDefault();
337 | this.close();
338 | } else if (code == keycodes.tab) {
339 | //all the fastforwarding operation,
340 | //Check that shared start is not null which can append with prefixed completion
341 | // like %pylab , pylab have no shred start, and ff will result in py
342 | // to erase py
343 | var sh = shared_start(this.raw_result, true);
344 | if (sh.str !== '') {
345 | this.insert(sh);
346 | }
347 | this.close();
348 | this.carry_on_completion();
349 | } else if (code == keycodes.up || code == keycodes.down) {
350 | // need to do that to be able to move the arrow
351 | // when on the first or last line ofo a code cell
352 | event.codemirrorIgnore = true;
353 | event._ipkmIgnore = true;
354 | event.preventDefault();
355 |
356 | options = this.sel.find('option');
357 | index = this.sel[0].selectedIndex;
358 | if (code == keycodes.up) {
359 | index--;
360 | }
361 | if (code == keycodes.down) {
362 | index++;
363 | }
364 | index = Math.min(Math.max(index, 0), options.length-1);
365 | this.sel[0].selectedIndex = index;
366 | } else if (code == keycodes.pageup || code == keycodes.pagedown) {
367 | event._ipkmIgnore = true;
368 |
369 | options = this.sel.find('option');
370 | index = this.sel[0].selectedIndex;
371 | if (code == keycodes.pageup) {
372 | index -= 10; // As 10 is the hard coded size of the drop down menu
373 | } else {
374 | index += 10;
375 | }
376 | index = Math.min(Math.max(index, 0), options.length-1);
377 | this.sel[0].selectedIndex = index;
378 | } else if (code == keycodes.left || code == keycodes.right) {
379 | this.close();
380 | }
381 | };
382 |
383 | Completer.prototype.keypress = function (event) {
384 | /**
385 | * FIXME: This is a band-aid.
386 | * on keypress, trigger insertion of a single character.
387 | * This simulates the old behavior of completion as you type,
388 | * before events were disconnected and CodeMirror stopped
389 | * receiving events while the completer is focused.
390 | */
391 |
392 | var that = this;
393 | var code = event.keyCode;
394 |
395 | // don't handle keypress if it's not a character (arrows on FF)
396 | // or ENTER/TAB
397 | if (event.charCode === 0 ||
398 | code == keycodes.tab ||
399 | code == keycodes.enter
400 | ) return;
401 |
402 | this.close();
403 | this.editor.focus();
404 | setTimeout(function () {
405 | that.carry_on_completion();
406 | }, 50);
407 | };
408 |
--------------------------------------------------------------------------------
/src/contexthint.ts:
--------------------------------------------------------------------------------
1 | // Copyright (c) Jupyter Development Team.
2 | // Distributed under the terms of the Modified BSD License.
3 |
4 | // highly adapted for codemiror jshint
5 | "use strict";
6 |
7 | var forEach = function(arr, f) {
8 | for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
9 | };
10 |
11 | var arrayContains = function(arr, item) {
12 | if (!Array.prototype.indexOf) {
13 | var i = arr.length;
14 | while (i--) {
15 | if (arr[i] === item) {
16 | return true;
17 | }
18 | }
19 | return false;
20 | }
21 | return arr.indexOf(item) != -1;
22 | };
23 |
24 | (CodeMirror).contextHint = function (editor) {
25 | // Find the token at the cursor
26 | var cur = editor.getCursor(),
27 | token = editor.getTokenAt(cur),
28 | tprop = token;
29 | // If it's not a 'word-style' token, ignore the token.
30 | // If it is a property, find out what it is a property of.
31 | var list = [];
32 | var clist = getCompletions(token, editor);
33 | for (var i = 0; i < clist.length; i++) {
34 | list.push({
35 | str: clist[i],
36 | type: "context",
37 | from: {
38 | line: cur.line,
39 | ch: token.start
40 | },
41 | to: {
42 | line: cur.line,
43 | ch: token.end
44 | }
45 | });
46 | }
47 | return list;
48 | };
49 |
50 | // find all 'words' of current cell
51 | var getAllTokens = function (editor) {
52 | var found = [];
53 |
54 | // add to found if not already in it
55 |
56 |
57 | function maybeAdd(str) {
58 | if (!arrayContains(found, str)) found.push(str);
59 | }
60 |
61 | // loop through all token on all lines
62 | var lineCount = editor.lineCount();
63 | // loop on line
64 | for (var l = 0; l < lineCount; l++) {
65 | var line = editor.getLine(l);
66 | //loop on char
67 | for (var c = 1; c < line.length; c++) {
68 | var tk = editor.getTokenAt({
69 | line: l,
70 | ch: c
71 | });
72 | // if token has a class, it has geat chances of beeing
73 | // of interest. Add it to the list of possible completions.
74 | // we could skip token of ClassName 'comment'
75 | // or 'number' and 'operator'
76 | if (tk.className !== null) {
77 | maybeAdd(tk.string);
78 | }
79 | // jump to char after end of current token
80 | c = tk.end;
81 | }
82 | }
83 | return found;
84 | };
85 |
86 | var getCompletions = function(token, editor) {
87 | var candidates = getAllTokens(editor);
88 | // filter all token that have a common start (but nox exactly) the lenght of the current token
89 | var lambda = function (x) {
90 | return (x.indexOf(token.string) === 0 && x != token.string);
91 | };
92 | var filterd = candidates.filter(lambda);
93 | return filterd;
94 | };
95 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | /*-----------------------------------------------------------------------------
2 | | Copyright (c) 2014-2015, PhosphorJS Contributors
3 | |
4 | | Distributed under the terms of the BSD 3-Clause License.
5 | |
6 | | The full license is in the file LICENSE, distributed with this software.
7 | |----------------------------------------------------------------------------*/
8 | body {
9 | margin: 0;
10 | padding: 0;
11 | background: #F5F6F7;
12 | }
13 |
14 |
15 | #main {
16 | position: absolute;
17 | top: 30px;
18 | left: 5px;
19 | right: 5px;
20 | bottom: 5px;
21 | }
22 |
23 |
24 | .TerminalWidget {
25 | min-width: 50px;
26 | min-height: 50px;
27 | background: black;
28 | }
29 |
30 |
31 | .fileItem {
32 | color: #2F2F2F;
33 | display: inline-block;
34 | font: 14px Helvetica, Arial, sans-serif;
35 | }
36 |
37 |
38 | .list_item > div {
39 | white-space: nowrap;
40 | }
41 |
42 |
43 | /*
44 | .content {
45 | border: 1px solid black;
46 | min-width: 50px;
47 | min-height: 50px;
48 | overflow: auto;
49 | }
50 | */
51 |
52 | .FileBrowser {
53 | min-width: 200px;
54 | }
55 |
56 |
57 | .files_inner {
58 | position: absolute;
59 | top: 0;
60 | left: 0;
61 | right: 2px;
62 | bottom: 2px;
63 | padding: 5px;
64 | display: flex;
65 | flex-direction: column;
66 | background-color: white;
67 | border: 1px solid #C0C0C0;
68 | box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
69 | }
70 |
71 |
72 | .files_header {
73 | flex-grow: 0;
74 | margin-bottom: 5px;
75 | }
76 |
77 |
78 | .list_container {
79 | flex-grow: 1;
80 | overflow: auto;
81 | margin: 0;
82 | border-radius: 0;
83 | }
84 |
85 |
86 | .CodeMirrorWidget {
87 | min-width: 50px;
88 | min-height: 50px;
89 | border: 1px solid #C0C0C0;
90 | z-index: 0;
91 | }
92 |
93 |
94 | .NotebookWidget {
95 | min-width: 150px;
96 | min-height: 150px;
97 | overflow: auto;
98 | border: 1px solid #C0C0C0;
99 | }
100 |
101 | .red {
102 | background: #E74C3C;
103 | }
104 |
105 |
106 | .yellow {
107 | background: #F1C40F;
108 | }
109 |
110 |
111 | .green {
112 | background: #27AE60;
113 | }
114 |
115 |
116 | .blue {
117 | background: #3498DB;
118 | }
119 |
120 |
121 | .p-DockTabPanel {
122 | padding-right: 2px;
123 | padding-bottom: 2px;
124 | }
125 |
126 |
127 | .p-DockTabPanel > .p-StackedPanel {
128 | padding: 5px;
129 | background: white;
130 | border: 1px solid #C0C0C0;
131 | border-top: none;
132 | box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
133 | }
134 |
135 |
136 | .p-DockTabPanel-overlay {
137 | background: rgba(255, 255, 255, 0.6);
138 | border: 1px solid rgba(0, 0, 0, 0.6);
139 | }
140 |
141 |
142 | .p-TabBar {
143 | min-height: 24px;
144 | }
145 |
146 |
147 | .p-TabBar-content {
148 | bottom: 1px;
149 | align-items: flex-end;
150 | }
151 |
152 |
153 | .p-TabBar-content > .p-Tab {
154 | flex-basis: 125px;
155 | max-height: 21px;
156 | min-width: 35px;
157 | margin-left: -1px;
158 | border: 1px solid #C0C0C0;
159 | border-bottom: none;
160 | padding: 0px 10px;
161 | background: #E5E5E5;
162 | font: 12px Helvetica, Arial, sans-serif;
163 | }
164 |
165 |
166 | .p-TabBar-content > .p-Tab.p-mod-first {
167 | margin-left: 0;
168 | }
169 |
170 |
171 | .p-TabBar-content > .p-Tab.p-mod-selected {
172 | min-height: 24px;
173 | background: white;
174 | transform: translateY(1px);
175 | }
176 |
177 |
178 | .p-TabBar-content > .p-Tab:hover:not(.p-mod-selected) {
179 | background: #F0F0F0;
180 | }
181 |
182 |
183 | .p-TabBar-content > .p-Tab > span {
184 | line-height: 21px;
185 | }
186 |
187 |
188 | .p-TabBar-footer {
189 | display: block;
190 | height: 1px;
191 | background: #C0C0C0;
192 | }
193 |
194 |
195 | .p-Tab.p-mod-closable > .p-Tab-close-icon {
196 | margin-left: 4px;
197 | }
198 |
199 |
200 | .p-Tab.p-mod-closable > .p-Tab-close-icon:before {
201 | content: '\f00d';
202 | font-family: FontAwesome;
203 | }
204 |
205 |
206 | .p-Tab.p-mod-docking {
207 | font: 12px Helvetica, Arial, sans-serif;
208 | height: 24px;
209 | width: 125px;
210 | padding: 0px 10px;
211 | background: white;
212 | box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
213 | transform: translateX(-50px) translateY(-14px);
214 | }
215 |
216 |
217 | .p-Tab.p-mod-docking > span {
218 | line-height: 21px;
219 | }
220 |
221 | .p-Menu {
222 | background: white;
223 | color: rgba(0, 0, 0, 0.87);
224 | border: 1px solid #C0C0C0;
225 | font: 12px Helvetica, Arial, sans-serif;
226 | box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.2);
227 | }
228 |
229 |
230 | .p-Menu-item.p-mod-active {
231 | background: #E5E5E5;
232 | }
233 |
234 |
235 | .p-Menu-item.p-mod-disabled {
236 | color: rgba(0, 0, 0, 0.26);
237 | }
238 |
239 |
240 | .p-Menu-item.p-mod-separator-type > span::after {
241 | border-top: 1px solid #DDDDDD;
242 | }
243 |
244 |
245 | .p-Menu-item-icon::before,
246 | .p-Menu-item-submenu-icon::before {
247 | font-family: FontAwesome;
248 | }
249 |
250 |
251 | .p-Menu-item.p-mod-check-type.p-mod-checked > .p-Menu-item-icon::before {
252 | content: '\f00c';
253 | }
254 |
255 |
256 | .p-Menu-item.p-mod-has-submenu > .p-Menu-item-submenu-icon::before {
257 | content: '\f0da';
258 | }
259 |
260 |
261 | .p-Menu-item.copy > .p-Menu-item-icon::before {
262 | content: '\f0c5';
263 | }
264 |
265 |
266 | .p-Menu-item.cut > .p-Menu-item-icon::before {
267 | content: '\f0c4';
268 | }
269 |
270 |
271 | .p-Menu-item.paste > .p-Menu-item-icon::before {
272 | content: '\f0ea';
273 | }
274 |
275 |
276 | .p-Menu-item.close > .p-Menu-item-icon::before {
277 | content: '\f00d';
278 | }
279 |
280 |
281 | .p-Menu-item.undo > .p-Menu-item-icon::before {
282 | content: '\f0e2';
283 | }
284 |
285 |
286 | .p-Menu-item.repeat > .p-Menu-item-icon::before {
287 | content: '\f01e';
288 | }
289 |
290 |
291 | .p-MenuBar {
292 | padding-left: 5px;
293 | background: #FCFCFC;
294 | color: rgba(0, 0, 0, 0.87);
295 | border-bottom: 1px solid #DDDDDD;
296 | font: 13px Helvetica, Arial, sans-serif;
297 | }
298 |
299 |
300 | .p-MenuBar-menu {
301 | transform: translateY(-1px);
302 | }
303 |
304 |
305 | .p-MenuBar-item {
306 | padding: 4px 8px;
307 | border-left: 1px solid transparent;
308 | border-right: 1px solid transparent;
309 | }
310 |
311 |
312 | .p-MenuBar-item.p-mod-active {
313 | background: #E5E5E5;
314 | }
315 |
316 |
317 | .p-MenuBar-item.p-mod-disabled {
318 | color: rgba(0, 0, 0, 0.26);
319 | }
320 |
321 |
322 | .p-MenuBar-item.p-mod-separator-type {
323 | margin: 2px;
324 | padding: 0;
325 | border: none;
326 | border-left: 1px solid #DDDDDD;
327 | }
328 |
329 |
330 | .p-MenuBar.p-mod-active > .p-MenuBar-content > .p-MenuBar-item.p-mod-active {
331 | z-index: 1000000;
332 | background: white;
333 | border-left: 1px solid #C0C0C0;
334 | border-right: 1px solid #C0C0C0;
335 | box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.2);
336 | }
337 |
--------------------------------------------------------------------------------
/src/keyboard.ts:
--------------------------------------------------------------------------------
1 | // Copyright (c) Jupyter Development Team.
2 | // Distributed under the terms of the Modified BSD License.
3 | /**
4 | *
5 | *
6 | * @module keyboard
7 | * @namespace keyboard
8 | * @class ShortcutManager
9 | */
10 |
11 | "use strict";
12 |
13 | var utils = require('./utils');
14 | var _ = require('underscore');
15 |
16 | /**
17 | * Setup global keycodes and inverse keycodes.
18 | *
19 | * See http://unixpapa.com/js/key.html for a complete description. The short of
20 | * it is that there are different keycode sets. Firefox uses the "Mozilla keycodes"
21 | * and Webkit/IE use the "IE keycodes". These keycode sets are mostly the same
22 | * but have minor differences.
23 | **/
24 |
25 | // These apply to Firefox, (Webkit and IE)
26 | // This does work **only** on US keyboard.
27 | var _keycodes = {
28 | 'a': 65, 'b': 66, 'c': 67, 'd': 68, 'e': 69, 'f': 70, 'g': 71, 'h': 72, 'i': 73,
29 | 'j': 74, 'k': 75, 'l': 76, 'm': 77, 'n': 78, 'o': 79, 'p': 80, 'q': 81, 'r': 82,
30 | 's': 83, 't': 84, 'u': 85, 'v': 86, 'w': 87, 'x': 88, 'y': 89, 'z': 90,
31 | '1 !': 49, '2 @': 50, '3 #': 51, '4 $': 52, '5 %': 53, '6 ^': 54,
32 | '7 &': 55, '8 *': 56, '9 (': 57, '0 )': 48,
33 | '[ {': 219, '] }': 221, '` ~': 192, ', <': 188, '. >': 190, '/ ?': 191,
34 | '\\ |': 220, '\' "': 222,
35 | 'numpad0': 96, 'numpad1': 97, 'numpad2': 98, 'numpad3': 99, 'numpad4': 100,
36 | 'numpad5': 101, 'numpad6': 102, 'numpad7': 103, 'numpad8': 104, 'numpad9': 105,
37 | 'multiply': 106, 'add': 107, 'subtract': 109, 'decimal': 110, 'divide': 111,
38 | 'f1': 112, 'f2': 113, 'f3': 114, 'f4': 115, 'f5': 116, 'f6': 117, 'f7': 118,
39 | 'f8': 119, 'f9': 120, 'f11': 122, 'f12': 123, 'f13': 124, 'f14': 125, 'f15': 126,
40 | 'backspace': 8, 'tab': 9, 'enter': 13, 'shift': 16, 'ctrl': 17, 'alt': 18,
41 | 'meta': 91, 'capslock': 20, 'esc': 27, 'space': 32, 'pageup': 33, 'pagedown': 34,
42 | 'end': 35, 'home': 36, 'left': 37, 'up': 38, 'right': 39, 'down': 40,
43 | 'insert': 45, 'delete': 46, 'numlock': 144,
44 | };
45 |
46 | // These apply to Firefox and Opera
47 | var _mozilla_keycodes = {
48 | '; :': 59, '= +': 61, '- _': 173, 'meta': 224, 'minus':173
49 | };
50 |
51 | // This apply to Webkit and IE
52 | var _ie_keycodes = {
53 | '; :': 186, '= +': 187, '- _': 189, 'minus':189
54 | };
55 |
56 | var browser = utils.browser[0];
57 | var platform = utils.platform;
58 |
59 | if (browser === 'Firefox' || browser === 'Opera' || browser === 'Netscape') {
60 | $.extend(_keycodes, _mozilla_keycodes);
61 | } else if (browser === 'Safari' || browser === 'Chrome' || browser === 'MSIE') {
62 | $.extend(_keycodes, _ie_keycodes);
63 | }
64 |
65 | export
66 | var keycodes: any = {};
67 | var inv_keycodes: any = {};
68 | var name: string;
69 | for (name in _keycodes) {
70 | var names = name.split(' ');
71 | if (names.length === 1) {
72 | var n = names[0];
73 | keycodes[n] = _keycodes[n];
74 | inv_keycodes[_keycodes[n]] = n;
75 | } else {
76 | var primary = names[0];
77 | var secondary = names[1];
78 | keycodes[primary] = _keycodes[name];
79 | keycodes[secondary] = _keycodes[name];
80 | inv_keycodes[_keycodes[name]] = primary;
81 | }
82 | }
83 |
84 | export
85 | var normalize_key = function (key) {
86 | return inv_keycodes[keycodes[key]];
87 | };
88 |
89 | export
90 | var normalize_shortcut = function (shortcut) {
91 | /**
92 | * @function _normalize_shortcut
93 | * @private
94 | * return a dict containing the normalized shortcut and the number of time it should be pressed:
95 | *
96 | * Put a shortcut into normalized form:
97 | * 1. Make lowercase
98 | * 2. Replace cmd by meta
99 | * 3. Sort '-' separated modifiers into the order alt-ctrl-meta-shift
100 | * 4. Normalize keys
101 | **/
102 | if (platform === 'MacOS') {
103 | shortcut = shortcut.toLowerCase().replace('cmdtrl-', 'cmd-');
104 | } else {
105 | shortcut = shortcut.toLowerCase().replace('cmdtrl-', 'ctrl-');
106 | }
107 |
108 | shortcut = shortcut.toLowerCase().replace('cmd', 'meta');
109 | shortcut = shortcut.replace(/-$/, 'minus'); // catch shortcuts using '-' key
110 | shortcut = shortcut.replace(/,$/, 'comma'); // catch shortcuts using '-' key
111 | if(shortcut.indexOf(',') !== -1){
112 | var sht = shortcut.split(',');
113 | sht = _.map(sht, normalize_shortcut);
114 | return shortcut;
115 | }
116 | shortcut = shortcut.replace(/comma/g, ','); // catch shortcuts using '-' key
117 | var values = shortcut.split("-");
118 | if (values.length === 1) {
119 | return normalize_key(values[0]);
120 | } else {
121 | var modifiers = values.slice(0,-1);
122 | var key = normalize_key(values[values.length-1]);
123 | modifiers.sort();
124 | return modifiers.join('-') + '-' + key;
125 | }
126 | };
127 |
128 |
129 | export
130 | var shortcut_to_event = function (shortcut, type) {
131 | /**
132 | * Convert a shortcut (shift-r) to a jQuery Event object
133 | **/
134 | type = type || 'keydown';
135 | shortcut = normalize_shortcut(shortcut);
136 | shortcut = shortcut.replace(/-$/, 'minus'); // catch shortcuts using '-' key
137 | var values = shortcut.split("-");
138 | var modifiers: any = values.slice(0,-1);
139 | var key = values[values.length-1];
140 | var opts: any = {which: keycodes[key]};
141 | if (modifiers.indexOf('alt') !== -1) {opts.altKey = true;}
142 | if (modifiers.indexOf('ctrl') !== -1) {opts.ctrlKey = true;}
143 | if (modifiers.indexOf('meta') !== -1) {opts.metaKey = true;}
144 | if (modifiers.indexOf('shift') !== -1) {opts.shiftKey = true;}
145 | return $.Event(type, opts);
146 | };
147 |
148 | export
149 | var only_modifier_event = function(event){
150 | /**
151 | * Return `true` if the event only contains modifiers keys.
152 | * false otherwise
153 | **/
154 | var key = inv_keycodes[event.which];
155 | return ((event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) &&
156 | (key === 'alt'|| key === 'ctrl'|| key === 'meta'|| key === 'shift'));
157 |
158 | };
159 |
160 | export
161 | var event_to_shortcut = function (event) {
162 | /**
163 | * Convert a jQuery Event object to a normalized shortcut string (shift-r)
164 | **/
165 | var shortcut = '';
166 | var key = inv_keycodes[event.which];
167 | if (event.altKey && key !== 'alt') {shortcut += 'alt-';}
168 | if (event.ctrlKey && key !== 'ctrl') {shortcut += 'ctrl-';}
169 | if (event.metaKey && key !== 'meta') {shortcut += 'meta-';}
170 | if (event.shiftKey && key !== 'shift') {shortcut += 'shift-';}
171 | shortcut += key;
172 | return shortcut;
173 | };
174 |
175 | // Shortcut manager class
176 | export
177 | var ShortcutManager = function (delay, events, actions, env) {
178 | /**
179 | * A class to deal with keyboard event and shortcut
180 | *
181 | * @class ShortcutManager
182 | * @constructor
183 | */
184 | this._shortcuts = {};
185 | this.delay = delay || 800; // delay in milliseconds
186 | this.events = events;
187 | this.actions = actions;
188 | this.actions.extend_env(env);
189 | this._queue = [];
190 | this._cleartimeout = null;
191 | Object.seal(this);
192 | };
193 |
194 | ShortcutManager.prototype.clearsoon = function(){
195 | /**
196 | * Clear the pending shortcut soon, and cancel previous clearing
197 | * that might be registered.
198 | **/
199 | var that = this;
200 | clearTimeout(this._cleartimeout);
201 | this._cleartimeout = setTimeout(function(){that.clearqueue();}, this.delay);
202 | };
203 |
204 |
205 | ShortcutManager.prototype.clearqueue = function(){
206 | /**
207 | * clear the pending shortcut sequence now.
208 | **/
209 | this._queue = [];
210 | clearTimeout(this._cleartimeout);
211 | };
212 |
213 |
214 | var flatten_shorttree = function(tree){
215 | /**
216 | * Flatten a tree of shortcut sequences.
217 | * use full to iterate over all the key/values of available shortcuts.
218 | **/
219 | var dct = {};
220 | for(var key in tree){
221 | var value = tree[key];
222 | if(typeof(value) === 'string'){
223 | dct[key] = value;
224 | } else {
225 | var ftree=flatten_shorttree(value);
226 | for(var subkey in ftree){
227 | dct[key+','+subkey] = ftree[subkey];
228 | }
229 | }
230 | }
231 | return dct;
232 | };
233 |
234 | ShortcutManager.prototype.get_action_shortcut = function(name){
235 | var ftree = flatten_shorttree(this._shortcuts);
236 | var res = {};
237 | for (var sht in ftree ){
238 | if(ftree[sht] === name){
239 | return sht;
240 | }
241 | }
242 | return undefined;
243 | };
244 |
245 | ShortcutManager.prototype.help = function () {
246 | var help = [];
247 | var ftree = flatten_shorttree(this._shortcuts);
248 | for (var shortcut in ftree) {
249 | var action = this.actions.get(ftree[shortcut]);
250 | var help_string = action.help||'== no help ==';
251 | var help_index = action.help_index;
252 | if (help_string) {
253 | var shortstring = (action.shortstring||shortcut);
254 | help.push({
255 | shortcut: shortstring,
256 | help: help_string,
257 | help_index: help_index}
258 | );
259 | }
260 | }
261 | help.sort(function (a, b) {
262 | if (a.help_index === b.help_index) {
263 | return 0;
264 | }
265 | if (a.help_index === undefined || a.help_index > b.help_index){
266 | return 1;
267 | }
268 | return -1;
269 | });
270 | return help;
271 | };
272 |
273 | ShortcutManager.prototype.clear_shortcuts = function () {
274 | this._shortcuts = {};
275 | };
276 |
277 | ShortcutManager.prototype.get_shortcut = function (shortcut){
278 | /**
279 | * return a node of the shortcut tree which an action name (string) if leaf,
280 | * and an object with `object.subtree===true`
281 | **/
282 | if(typeof(shortcut) === 'string'){
283 | shortcut = shortcut.split(',');
284 | }
285 |
286 | return this._get_leaf(shortcut, this._shortcuts);
287 | };
288 |
289 |
290 | ShortcutManager.prototype._get_leaf = function(shortcut_array, tree){
291 | /**
292 | * @private
293 | * find a leaf/node in a subtree of the keyboard shortcut
294 | *
295 | **/
296 | if(shortcut_array.length === 1){
297 | return tree[shortcut_array[0]];
298 | } else if( typeof(tree[shortcut_array[0]]) !== 'string'){
299 | return this._get_leaf(shortcut_array.slice(1), tree[shortcut_array[0]]);
300 | }
301 | return null;
302 | };
303 |
304 | ShortcutManager.prototype.set_shortcut = function( shortcut, action_name){
305 | if( typeof(action_name) !== 'string'){throw new Error('action is not a string' + String(action_name));}
306 | if( typeof(shortcut) === 'string'){
307 | shortcut = shortcut.split(',');
308 | }
309 | return this._set_leaf(shortcut, action_name, this._shortcuts);
310 | };
311 |
312 | ShortcutManager.prototype._is_leaf = function(shortcut_array, tree){
313 | if(shortcut_array.length === 1){
314 | return(typeof(tree[shortcut_array[0]]) === 'string');
315 | } else {
316 | var subtree = tree[shortcut_array[0]];
317 | return this._is_leaf(shortcut_array.slice(1), subtree );
318 | }
319 | };
320 |
321 | ShortcutManager.prototype._remove_leaf = function(shortcut_array, tree, allow_node){
322 | if(shortcut_array.length === 1){
323 | var current_node = tree[shortcut_array[0]];
324 | if(typeof(current_node) === 'string'){
325 | delete tree[shortcut_array[0]];
326 | } else {
327 | throw('try to delete non-leaf');
328 | }
329 | } else {
330 | this._remove_leaf(shortcut_array.slice(1), tree[shortcut_array[0]], allow_node);
331 | if(_.keys(tree[shortcut_array[0]]).length === 0){
332 | delete tree[shortcut_array[0]];
333 | }
334 | }
335 | };
336 |
337 | ShortcutManager.prototype._set_leaf = function(shortcut_array, action_name, tree){
338 | var current_node = tree[shortcut_array[0]];
339 | if(shortcut_array.length === 1){
340 | if(current_node !== undefined && typeof(current_node) !== 'string'){
341 | console.warn('[warning], you are overriting a long shortcut with a shorter one');
342 | }
343 | tree[shortcut_array[0]] = action_name;
344 | return true;
345 | } else {
346 | if(typeof(current_node) === 'string'){
347 | console.warn('you are trying to set a shortcut that will be shadowed'+
348 | 'by a more specific one. Aborting for :', action_name, 'the follwing '+
349 | 'will take precedence', current_node);
350 | return false;
351 | } else {
352 | tree[shortcut_array[0]] = tree[shortcut_array[0]]||{};
353 | }
354 | this._set_leaf(shortcut_array.slice(1), action_name, tree[shortcut_array[0]]);
355 | return true;
356 | }
357 | };
358 |
359 | ShortcutManager.prototype.add_shortcut = function (shortcut, data, suppress_help_update) {
360 | /**
361 | * Add a action to be handled by shortcut manager.
362 | *
363 | * - `shortcut` should be a `Shortcut Sequence` of the for `Ctrl-Alt-C,Meta-X`...
364 | * - `data` could be an `action name`, an `action` or a `function`.
365 | * if a `function` is passed it will be converted to an anonymous `action`.
366 | *
367 | **/
368 | var action_name = this.actions.get_name(data);
369 | if (! action_name){
370 | throw new Error('does not know how to deal with' + String(data));
371 | }
372 | shortcut = normalize_shortcut(shortcut);
373 | this.set_shortcut(shortcut, action_name);
374 |
375 | if (!suppress_help_update) {
376 | // update the keyboard shortcuts notebook help
377 | this.events.trigger('rebuild.QuickHelp');
378 | }
379 | };
380 |
381 | ShortcutManager.prototype.add_shortcuts = function (data) {
382 | /**
383 | * Convenient methods to call `add_shortcut(key, value)` on several items
384 | *
385 | * data : Dict of the form {key:value, ...}
386 | **/
387 | for (var shortcut in data) {
388 | this.add_shortcut(shortcut, data[shortcut], true);
389 | }
390 | // update the keyboard shortcuts notebook help
391 | this.events.trigger('rebuild.QuickHelp');
392 | };
393 |
394 | ShortcutManager.prototype.remove_shortcut = function (shortcut, suppress_help_update) {
395 | /**
396 | * Remove the binding of shortcut `sortcut` with its action.
397 | * throw an error if trying to remove a non-exiting shortcut
398 | **/
399 | shortcut = normalize_shortcut(shortcut);
400 | if( typeof(shortcut) === 'string'){
401 | shortcut = shortcut.split(',');
402 | }
403 | /*
404 | * The shortcut error should be explicit here, because it will be
405 | * seen by users.
406 | */
407 | try
408 | {
409 | this._remove_leaf(shortcut, this._shortcuts);
410 | if (!suppress_help_update) {
411 | // update the keyboard shortcuts notebook help
412 | this.events.trigger('rebuild.QuickHelp');
413 | }
414 | } catch (ex) {
415 | throw new Error('trying to remove a non-existent shortcut' + String(shortcut));
416 | }
417 | };
418 |
419 |
420 |
421 | ShortcutManager.prototype.call_handler = function (event) {
422 | /**
423 | * Call the corresponding shortcut handler for a keyboard event
424 | * @method call_handler
425 | * @return {Boolean} `true|false`, `false` if no handler was found, otherwise the value return by the handler.
426 | * @param event {event}
427 | *
428 | * given an event, call the corresponding shortcut.
429 | * return false is event wan handled, true otherwise
430 | * in any case returning false stop event propagation
431 | **/
432 |
433 |
434 | this.clearsoon();
435 | if(only_modifier_event(event)){
436 | return true;
437 | }
438 | var shortcut = event_to_shortcut(event);
439 | this._queue.push(shortcut);
440 | var action_name = this.get_shortcut(this._queue);
441 |
442 | if (typeof(action_name) === 'undefined'|| action_name === null){
443 | this.clearqueue();
444 | return true;
445 | }
446 |
447 | if (this.actions.exists(action_name)) {
448 | event.preventDefault();
449 | this.clearqueue();
450 | return this.actions.call(action_name, event);
451 | }
452 |
453 | return false;
454 | };
455 |
456 |
457 | ShortcutManager.prototype.handles = function (event) {
458 | var shortcut = event_to_shortcut(event);
459 | var action_name = this.get_shortcut(this._queue.concat(shortcut));
460 | return (typeof(action_name) !== 'undefined');
461 | };
462 |
463 |
--------------------------------------------------------------------------------
/src/keyboardmanager.ts:
--------------------------------------------------------------------------------
1 | // Copyright (c) Jupyter Development Team.
2 | // Distributed under the terms of the Modified BSD License.
3 | /**
4 | *
5 | *
6 | * @module keyboardmanager
7 | * @namespace keyboardmanager
8 | * @class KeyboardManager
9 | */
10 | "use strict";
11 | var utils = require('./utils');
12 | var keyboard = require('./keyboard');
13 |
14 | // Main keyboard manager for the notebook
15 | var keycodes = keyboard.keycodes;
16 |
17 | export
18 | var KeyboardManager = function (options) {
19 | /**
20 | * A class to deal with keyboard event and shortcut
21 | *
22 | * @class KeyboardManager
23 | * @constructor
24 | * @param options {dict} Dictionary of keyword arguments :
25 | * @param options.events {$(Events)} instance
26 | * @param options.pager: {Pager} pager instance
27 | */
28 | this.mode = 'command';
29 | this.enabled = true;
30 | this.pager = options.pager;
31 | this.quick_help = undefined;
32 | this.notebook = options.notebook;
33 | this.last_mode = undefined;
34 | this.bind_events();
35 | this.env = {pager:this.pager, notebook: this.notebook};
36 | this.actions = options.actions;
37 | this.command_shortcuts = new keyboard.ShortcutManager(undefined, options.events, this.actions, this.env );
38 | this.command_shortcuts.add_shortcuts(this.get_default_common_shortcuts());
39 | this.command_shortcuts.add_shortcuts(this.get_default_command_shortcuts());
40 | this.edit_shortcuts = new keyboard.ShortcutManager(undefined, options.events, this.actions, this.env);
41 | this.edit_shortcuts.add_shortcuts(this.get_default_common_shortcuts());
42 | this.edit_shortcuts.add_shortcuts(this.get_default_edit_shortcuts());
43 | Object.seal(this);
44 | };
45 |
46 |
47 |
48 |
49 | /**
50 | * Return a dict of common shortcut
51 | * @method get_default_common_shortcuts
52 | *
53 | * @example Example of returned shortcut
54 | * ```
55 | * 'shortcut-key': 'action-name'
56 | * // a string representing the shortcut as dash separated value.
57 | * // e.g. 'shift' , 'shift-enter', 'cmd-t'
58 | *```
59 | */
60 | KeyboardManager.prototype.get_default_common_shortcuts = function() {
61 | return {
62 | 'shift' : 'ipython.ignore',
63 | 'shift-enter' : 'ipython.run-select-next',
64 | 'ctrl-enter' : 'ipython.execute-in-place',
65 | 'alt-enter' : 'ipython.execute-and-insert-after',
66 | // cmd on mac, ctrl otherwise
67 | 'cmdtrl-s' : 'ipython.save-notebook',
68 | };
69 | };
70 |
71 | KeyboardManager.prototype.get_default_edit_shortcuts = function() {
72 | return {
73 | 'cmdtrl-shift-p' : 'ipython.command-palette',
74 | 'esc' : 'ipython.go-to-command-mode',
75 | 'ctrl-m' : 'ipython.go-to-command-mode',
76 | 'up' : 'ipython.move-cursor-up-or-previous-cell',
77 | 'down' : 'ipython.move-cursor-down-or-next-cell',
78 | 'ctrl-shift--' : 'ipython.split-cell-at-cursor',
79 | 'ctrl-shift-subtract' : 'ipython.split-cell-at-cursor',
80 | };
81 | };
82 |
83 | KeyboardManager.prototype.get_default_command_shortcuts = function() {
84 | return {
85 | 'cmdtrl-shift-p': 'ipython.command-palette',
86 | 'shift-space': 'ipython.scroll-up',
87 | 'shift-v' : 'ipython.paste-cell-before',
88 | 'shift-m' : 'ipython.merge-selected-cells',
89 | 'shift-o' : 'ipython.toggle-output-scrolling-selected-cell',
90 | 'enter' : 'ipython.enter-edit-mode',
91 | 'space' : 'ipython.scroll-down',
92 | 'down' : 'ipython.select-next-cell',
93 | 'i,i' : 'ipython.interrupt-kernel',
94 | '0,0' : 'ipython.restart-kernel',
95 | 'd,d' : 'ipython.delete-cell',
96 | 'esc': 'ipython.close-pager',
97 | 'up' : 'ipython.select-previous-cell',
98 | 'k' : 'ipython.select-previous-cell',
99 | 'j' : 'ipython.select-next-cell',
100 | 'shift-k': 'ipython.extend-selection-previous',
101 | 'shift-j': 'ipython.extend-selection-next',
102 | 'x' : 'ipython.cut-selected-cell',
103 | 'c' : 'ipython.copy-selected-cell',
104 | 'v' : 'ipython.paste-cell-after',
105 | 'a' : 'ipython.insert-cell-before',
106 | 'b' : 'ipython.insert-cell-after',
107 | 'y' : 'ipython.change-selected-cell-to-code-cell',
108 | 'm' : 'ipython.change-selected-cell-to-markdown-cell',
109 | 'r' : 'ipython.change-selected-cell-to-raw-cell',
110 | '1' : 'ipython.change-selected-cell-to-heading-1',
111 | '2' : 'ipython.change-selected-cell-to-heading-2',
112 | '3' : 'ipython.change-selected-cell-to-heading-3',
113 | '4' : 'ipython.change-selected-cell-to-heading-4',
114 | '5' : 'ipython.change-selected-cell-to-heading-5',
115 | '6' : 'ipython.change-selected-cell-to-heading-6',
116 | 'o' : 'ipython.toggle-output-visibility-selected-cell',
117 | 's' : 'ipython.save-notebook',
118 | 'l' : 'ipython.toggle-line-number-selected-cell',
119 | 'h' : 'ipython.show-keyboard-shortcut-help-dialog',
120 | 'z' : 'ipython.undo-last-cell-deletion',
121 | 'q' : 'ipython.close-pager',
122 | };
123 | };
124 |
125 | KeyboardManager.prototype.bind_events = function () {
126 | var that = this;
127 | $(document).keydown(function (event) {
128 | if((event)._ipkmIgnore===true||(event.originalEvent||({}))._ipkmIgnore===true){
129 | return false;
130 | }
131 | return that.handle_keydown(event);
132 | });
133 | };
134 |
135 | KeyboardManager.prototype.set_notebook = function (notebook) {
136 | this.notebook = notebook;
137 | this.actions.extend_env({notebook:notebook});
138 | };
139 |
140 | KeyboardManager.prototype.set_quickhelp = function (notebook) {
141 | this.actions.extend_env({quick_help:notebook});
142 | };
143 |
144 |
145 | KeyboardManager.prototype.handle_keydown = function (event) {
146 |
147 | if (!this.notebook.node.contains(event.target)) {
148 | return;
149 | }
150 | /**
151 | * returning false from this will stop event propagation
152 | **/
153 |
154 | if (event.which === keycodes.esc) {
155 | // Intercept escape at highest level to avoid closing
156 | // websocket connection with firefox
157 | event.preventDefault();
158 | }
159 |
160 | if (!this.enabled) {
161 | if (event.which === keycodes.esc) {
162 | this.notebook.command_mode();
163 | return false;
164 | }
165 | return true;
166 | }
167 |
168 | if (this.mode === 'edit') {
169 | return this.edit_shortcuts.call_handler(event);
170 | } else if (this.mode === 'command') {
171 | return this.command_shortcuts.call_handler(event);
172 | }
173 | return true;
174 | };
175 |
176 | KeyboardManager.prototype.edit_mode = function () {
177 | this.last_mode = this.mode;
178 | this.mode = 'edit';
179 | };
180 |
181 | KeyboardManager.prototype.command_mode = function () {
182 | this.last_mode = this.mode;
183 | this.mode = 'command';
184 | };
185 |
186 | KeyboardManager.prototype.enable = function () {
187 | this.enabled = true;
188 | };
189 |
190 | KeyboardManager.prototype.disable = function () {
191 | this.enabled = false;
192 | };
193 |
194 | KeyboardManager.prototype.register_events = function (e) {
195 | e = $(e);
196 | var that = this;
197 | var handle_focus = function () {
198 | that.disable();
199 | };
200 | var handle_blur = function () {
201 | that.enable();
202 | };
203 | e.on('focusin', handle_focus);
204 | e.on('focusout', handle_blur);
205 | // TODO: Very strange. The focusout event does not seem fire for the
206 | // bootstrap textboxes on FF25&26... This works around that by
207 | // registering focus and blur events recursively on all inputs within
208 | // registered element.
209 | e.find('input').blur(handle_blur);
210 | e.on('DOMNodeInserted', function (event) {
211 | var target = $(event.target);
212 | if (target.is('input')) {
213 | target.blur(handle_blur);
214 | } else {
215 | target.find('input').blur(handle_blur);
216 | }
217 | });
218 | // There are times (raw_input) where we remove the element from the DOM before
219 | // focusout is called. In this case we bind to the remove event of jQueryUI,
220 | // which gets triggered upon removal, iff it is focused at the time.
221 | // is_focused must be used to check for the case where an element within
222 | // the element being removed is focused.
223 | e.on('remove', function () {
224 | if (utils.is_focused(e[0])) {
225 | that.enable();
226 | }
227 | });
228 | };
229 |
--------------------------------------------------------------------------------
/src/tooltip.ts:
--------------------------------------------------------------------------------
1 | // Copyright (c) Jupyter Development Team.
2 | // Distributed under the terms of the Modified BSD License.
3 | "use strict";
4 |
5 | var utils = require('./utils');
6 |
7 | // tooltip constructor
8 | export
9 | var Tooltip = function (events, element) {
10 | var that = this;
11 | this.events = events;
12 | this.time_before_tooltip = 1200;
13 |
14 | // handle to html
15 | this.tooltip = $(element);
16 | this._hidden = true;
17 |
18 | // variable for consecutive call
19 | this._old_cell = null;
20 | this._old_request = null;
21 | this._consecutive_counter = 0;
22 |
23 | // 'sticky ?'
24 | this._sticky = false;
25 |
26 | // display tooltip if the docstring is empty?
27 | this._hide_if_no_docstring = false;
28 |
29 | // contain the button in the upper right corner
30 | this.buttons = $('').addClass('tooltipbuttons');
31 |
32 | // will contain the docstring
33 | this.text = $('').addClass('tooltiptext').addClass('smalltooltip');
34 |
35 | // build the buttons menu on the upper right
36 | // expand the tooltip to see more
37 | var expandlink = $('').attr('href', "#").addClass("ui-corner-all") //rounded corner
38 | .attr('role', "button").attr('id', 'expanbutton').attr('title', 'Grow the tooltip vertically (press shift-tab twice)').click(function () {
39 | that.expand();
40 | event.preventDefault();
41 | }).append(
42 | $('').text('Expand').addClass('ui-icon').addClass('ui-icon-plus'));
43 |
44 | // close the tooltip
45 | var closelink = $('').attr('href', "#").attr('role', "button").addClass('ui-button');
46 | var closespan = $('').text('Close').addClass('ui-icon').addClass('ui-icon-close');
47 | closelink.append(closespan);
48 | closelink.click(function () {
49 | that.remove_and_cancel_tooltip(true);
50 | event.preventDefault();
51 | });
52 |
53 | this._clocklink = $('').attr('href', "#");
54 | this._clocklink.attr('role', "button");
55 | this._clocklink.addClass('ui-button');
56 | this._clocklink.attr('title', 'Tooltip will linger for 10 seconds while you type');
57 | var clockspan = $('').text('Close');
58 | clockspan.addClass('ui-icon');
59 | clockspan.addClass('ui-icon-clock');
60 | this._clocklink.append(clockspan);
61 | this._clocklink.click(function () {
62 | that.cancel_stick();
63 | event.preventDefault();
64 | });
65 |
66 |
67 |
68 |
69 | //construct the tooltip
70 | // add in the reverse order you want them to appear
71 | this.buttons.append(closelink);
72 | this.buttons.append(expandlink);
73 | this.buttons.append(this._clocklink);
74 | this._clocklink.hide();
75 |
76 |
77 | // we need a phony element to make the small arrow
78 | // of the tooltip in css
79 | // we will move the arrow later
80 | this.arrow = $('').addClass('pretooltiparrow');
81 | this.tooltip.append(this.buttons);
82 | this.tooltip.append(this.arrow);
83 | this.tooltip.append(this.text);
84 |
85 | // function that will be called if you press tab 1, 2, 3... times in a row
86 | this.tabs_functions = [function (cell, text, cursor) {
87 | that._request_tooltip(cell, text, cursor);
88 | }, function () {
89 | that.expand();
90 | }, function () {
91 | that.stick();
92 | }, function (cell) {
93 | that.cancel_stick();
94 | that.showInPager(cell);
95 | }];
96 | // call after all the tabs function above have bee call to clean their effects
97 | // if necessary
98 | this.reset_tabs_function = function (cell, text) {
99 | this._old_cell = (cell) ? cell : null;
100 | this._old_request = (text) ? text : null;
101 | this._consecutive_counter = 0;
102 | };
103 | };
104 |
105 | Tooltip.prototype.is_visible = function () {
106 | return !this._hidden;
107 | };
108 |
109 | Tooltip.prototype.showInPager = function (cell) {
110 | /**
111 | * reexecute last call in pager by appending ? to show back in pager
112 | */
113 | this.events.trigger('open_with_text.Pager', this._reply);
114 | this.remove_and_cancel_tooltip();
115 | };
116 |
117 | // grow the tooltip verticaly
118 | Tooltip.prototype.expand = function () {
119 | this.text.removeClass('smalltooltip');
120 | this.text.addClass('bigtooltip');
121 | $('#expanbutton').hide('slow');
122 | };
123 |
124 | // deal with all the logic of hiding the tooltip
125 | // and reset it's status
126 | Tooltip.prototype._hide = function () {
127 | this._hidden = true;
128 | this.tooltip.fadeOut('fast');
129 | $('#expanbutton').show('slow');
130 | this.text.removeClass('bigtooltip');
131 | this.text.addClass('smalltooltip');
132 | // keep scroll top to be sure to always see the first line
133 | this.text.scrollTop(0);
134 | this.code_mirror = null;
135 | };
136 |
137 | // return true on successfully removing a visible tooltip; otherwise return
138 | // false.
139 | Tooltip.prototype.remove_and_cancel_tooltip = function (force) {
140 | /**
141 | * note that we don't handle closing directly inside the calltip
142 | * as in the completer, because it is not focusable, so won't
143 | * get the event.
144 | */
145 | this.cancel_pending();
146 | if (!this._hidden) {
147 | if (force || !this._sticky) {
148 | this.cancel_stick();
149 | this._hide();
150 | }
151 | this.reset_tabs_function();
152 | return true;
153 | } else {
154 | return false;
155 | }
156 | };
157 |
158 | // cancel autocall done after '(' for example.
159 | Tooltip.prototype.cancel_pending = function () {
160 | if (this._tooltip_timeout !== null) {
161 | clearTimeout(this._tooltip_timeout);
162 | this._tooltip_timeout = null;
163 | }
164 | };
165 |
166 | // will trigger tooltip after timeout
167 | Tooltip.prototype.pending = function (cell, hide_if_no_docstring) {
168 | var that = this;
169 | this._tooltip_timeout = setTimeout(function () {
170 | that.request(cell, hide_if_no_docstring);
171 | }, that.time_before_tooltip);
172 | };
173 |
174 | // easy access for julia monkey patching.
175 | (Tooltip).last_token_re = /[a-z_][0-9a-z._]*$/gi;
176 |
177 | Tooltip.prototype._request_tooltip = function (cell, text, cursor_pos) {
178 | var request = { code: text,
179 | cursor_pos: cursor_pos,
180 | detail_level: 0};
181 | cell.kernel.inspect(request).then(contents => {
182 | this._show(contents);
183 | });
184 | }
185 |
186 | // make an immediate completion request
187 | Tooltip.prototype.request = function (cell, hide_if_no_docstring) {
188 | /**
189 | * request(codecell)
190 | * Deal with extracting the text from the cell and counting
191 | * call in a row
192 | */
193 | this.cancel_pending();
194 | var editor = cell.code_mirror;
195 | var cursor = editor.getCursor();
196 | var cursor_pos = utils.to_absolute_cursor_pos(editor, cursor);
197 | var text = cell.get_text();
198 |
199 | this._hide_if_no_docstring = hide_if_no_docstring;
200 |
201 | if(editor.somethingSelected()){
202 | // get only the most recent selection.
203 | text = editor.getSelection();
204 | }
205 |
206 | // need a permanent handle to code_mirror for future auto recall
207 | this.code_mirror = editor;
208 |
209 | // now we treat the different number of keypress
210 | // first if same cell, same text, increment counter by 1
211 | if (this._old_cell == cell && this._old_request == text && this._hidden === false) {
212 | this._consecutive_counter++;
213 | } else {
214 | // else reset
215 | this.cancel_stick();
216 | this.reset_tabs_function (cell, text);
217 | }
218 |
219 | this.tabs_functions[this._consecutive_counter](cell, text, cursor_pos);
220 |
221 | // then if we are at the end of list function, reset
222 | if (this._consecutive_counter == this.tabs_functions.length) {
223 | this.reset_tabs_function (cell, text, cursor);
224 | }
225 |
226 | return;
227 | };
228 |
229 | // cancel the option of having the tooltip to stick
230 | Tooltip.prototype.cancel_stick = function () {
231 | clearTimeout(this._stick_timeout);
232 | this._stick_timeout = null;
233 | this._clocklink.hide('slow');
234 | this._sticky = false;
235 | };
236 |
237 | // put the tooltip in a sicky state for 10 seconds
238 | // it won't be removed by remove_and_cancell() unless you called with
239 | // the first parameter set to true.
240 | // remove_and_cancell_tooltip(true)
241 | Tooltip.prototype.stick = function (time) {
242 | time = (time !== undefined) ? time : 10;
243 | var that = this;
244 | this._sticky = true;
245 | this._clocklink.show('slow');
246 | this._stick_timeout = setTimeout(function () {
247 | that._sticky = false;
248 | that._clocklink.hide('slow');
249 | }, time * 1000);
250 | };
251 |
252 | // should be called with the kernel reply to actually show the tooltip
253 | Tooltip.prototype._show = function (reply) {
254 | /**
255 | * move the bubble if it is not hidden
256 | * otherwise fade it
257 | */
258 | this._reply = reply;
259 | var content = reply;
260 | if (!content.found) {
261 | // object not found, nothing to show
262 | return;
263 | }
264 | this.name = content.name;
265 |
266 | // do some math to have the tooltip arrow on more or less on left or right
267 | // position of the editor
268 | var cm_pos = $(this.code_mirror.getWrapperElement()).position();
269 |
270 | // anchor and head positions are local within CodeMirror element
271 | var anchor = this.code_mirror.cursorCoords(false, 'local');
272 | var head = this.code_mirror.cursorCoords(true, 'local');
273 | // locate the target at the center of anchor, head
274 | var center_left = (head.left + anchor.left) / 2;
275 | // locate the left edge of the tooltip, at most 450 px left of the arrow
276 | var edge_left = Math.max(center_left - 450, 0);
277 | // locate the arrow at the cursor. A 24 px offset seems necessary.
278 | var arrow_left = center_left - edge_left - 24;
279 |
280 | // locate left, top within container element
281 | var left = (cm_pos.left + edge_left) + 'px';
282 | var top = (cm_pos.top + head.bottom + 10) + 'px';
283 |
284 | if (this._hidden === false) {
285 | this.tooltip.animate({
286 | left: left,
287 | top: top
288 | });
289 | } else {
290 | this.tooltip.css({
291 | left: left
292 | });
293 | this.tooltip.css({
294 | top: top
295 | });
296 | }
297 | this.arrow.animate({
298 | 'left': arrow_left + 'px'
299 | });
300 |
301 | this._hidden = false;
302 | this.tooltip.fadeIn('fast');
303 | this.text.children().remove();
304 |
305 | // This should support rich data types, but only text/plain for now
306 | // Any HTML within the docstring is escaped by the fixConsole() method.
307 | var pre = $('').html(utils.fixConsole(content.data['text/plain']));
308 | this.text.append(pre);
309 | // keep scroll top to be sure to always see the first line
310 | this.text.scrollTop(0);
311 | };
312 |
--------------------------------------------------------------------------------
/src/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "experimentalDecorators": true,
4 | "declaration": true,
5 | "noImplicitAny": false,
6 | "noEmitOnError": true,
7 | "sourceMap": true,
8 | "module": "commonjs",
9 | "moduleResolution": "node",
10 | "target": "ES5",
11 | "outDir": "../build"
12 | },
13 | "files": [
14 | "../typings/es6-collections/es6-collections.d.ts",
15 | "../typings/es6-promise/es6-promise.d.ts",
16 | "../typings/es6-dataview.d.ts",
17 | "../typings/requirejs/r.d.ts",
18 | "../typings/jquery/jquery.d.ts",
19 | "../typings/codemirror/codemirror.d.ts",
20 | "../node_modules/phosphor-widget/lib/index.d.ts",
21 | "../typings/term.js.d.ts",
22 | "../jupyter-js-services/index.d.ts",
23 | "index.ts",
24 | "actions.ts",
25 | "cell.ts",
26 | "celltoolbar.ts",
27 | "codecell.ts",
28 | "completer.ts",
29 | "contexthint.ts",
30 | "keyboard.ts",
31 | "keyboardmanager.ts",
32 | "tooltip.ts",
33 | "utils.ts"
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/typings/es6-collections/es6-collections.d.ts:
--------------------------------------------------------------------------------
1 | // Type definitions for es6-collections v0.5.1
2 | // Project: https://github.com/WebReflection/es6-collections/
3 | // Definitions by: Ron Buckton
4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped
5 |
6 | /* *****************************************************************************
7 | Copyright (c) Microsoft Corporation. All rights reserved.
8 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use
9 | this file except in compliance with the License. You may obtain a copy of the
10 | License at http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
14 | WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
15 | MERCHANTABLITY OR NON-INFRINGEMENT.
16 |
17 | See the Apache Version 2.0 License for specific language governing permissions
18 | and limitations under the License.
19 | ***************************************************************************** */
20 |
21 | interface IteratorResult {
22 | done: boolean;
23 | value?: T;
24 | }
25 |
26 | interface Iterator {
27 | next(value?: any): IteratorResult;
28 | return?(value?: any): IteratorResult;
29 | throw?(e?: any): IteratorResult;
30 | }
31 |
32 | interface ForEachable {
33 | forEach(callbackfn: (value: T) => void): void;
34 | }
35 |
36 | interface Map {
37 | clear(): void;
38 | delete(key: K): boolean;
39 | forEach(callbackfn: (value: V, index: K, map: Map) => void, thisArg?: any): void;
40 | get(key: K): V;
41 | has(key: K): boolean;
42 | set(key: K, value?: V): Map;
43 | entries(): Iterator<[K, V]>;
44 | keys(): Iterator;
45 | values(): Iterator;
46 | size: number;
47 | }
48 |
49 | interface MapConstructor {
50 | new (): Map;
51 | new (iterable: ForEachable<[K, V]>): Map;
52 | prototype: Map;
53 | }
54 |
55 | declare var Map: MapConstructor;
56 |
57 | interface Set {
58 | add(value: T): Set;
59 | clear(): void;
60 | delete(value: T): boolean;
61 | forEach(callbackfn: (value: T, index: T, set: Set) => void, thisArg?: any): void;
62 | has(value: T): boolean;
63 | entries(): Iterator<[T, T]>;
64 | keys(): Iterator;
65 | values(): Iterator;
66 | size: number;
67 | }
68 |
69 | interface SetConstructor {
70 | new (): Set;
71 | new (iterable: ForEachable): Set;
72 | prototype: Set;
73 | }
74 |
75 | declare var Set: SetConstructor;
76 |
77 | interface WeakMap {
78 | delete(key: K): boolean;
79 | clear(): void;
80 | get(key: K): V;
81 | has(key: K): boolean;
82 | set(key: K, value?: V): WeakMap;
83 | }
84 |
85 | interface WeakMapConstructor {
86 | new (): WeakMap;
87 | new (iterable: ForEachable<[K, V]>): WeakMap;
88 | prototype: WeakMap;
89 | }
90 |
91 | declare var WeakMap: WeakMapConstructor;
92 |
93 | interface WeakSet {
94 | delete(value: T): boolean;
95 | clear(): void;
96 | add(value: T): WeakSet;
97 | has(value: T): boolean;
98 | }
99 |
100 | interface WeakSetConstructor {
101 | new (): WeakSet;
102 | new (iterable: ForEachable): WeakSet;
103 | prototype: WeakSet;
104 | }
105 |
106 | declare var WeakSet: WeakSetConstructor;
107 |
108 | declare module "es6-collections" {
109 | var Map: MapConstructor;
110 | var Set: SetConstructor;
111 | var WeakMap: WeakMapConstructor;
112 | var WeakSet: WeakSetConstructor;
113 | }
--------------------------------------------------------------------------------
/typings/es6-container-shim.d.ts:
--------------------------------------------------------------------------------
1 | /*! *****************************************************************************
2 | Copyright (c) Microsoft Corporation. All rights reserved.
3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use
4 | this file except in compliance with the License. You may obtain a copy of the
5 | License at http://www.apache.org/licenses/LICENSE-2.0
6 |
7 | THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
8 | KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
9 | WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
10 | MERCHANTABLITY OR NON-INFRINGEMENT.
11 |
12 | See the Apache Version 2.0 License for specific language governing permissions
13 | and limitations under the License.
14 | ***************************************************************************** */
15 |
16 | // This file is derived from the TypeScript lib.es6.d.ts file:
17 | // https://github.com/Microsoft/TypeScript/blob/81711f9388d1823761616bce83776846a3fea773/bin/lib.es6.d.ts
18 |
19 | interface Map {
20 | clear(): void;
21 | delete(key: K): boolean;
22 | forEach(callbackfn: (value: V, index: K, map: Map) => void, thisArg?: any): void;
23 | get(key: K): V;
24 | has(key: K): boolean;
25 | set(key: K, value?: V): Map;
26 | size: number;
27 | }
28 |
29 |
30 | interface MapConstructor {
31 | new (): Map;
32 | prototype: Map;
33 | }
34 |
35 |
36 | declare var Map: MapConstructor;
37 |
38 |
39 | interface WeakMap {
40 | clear(): void;
41 | delete(key: K): boolean;
42 | get(key: K): V;
43 | has(key: K): boolean;
44 | set(key: K, value?: V): WeakMap;
45 | }
46 |
47 |
48 | interface WeakMapConstructor {
49 | new (): WeakMap;
50 | prototype: WeakMap;
51 | }
52 |
53 |
54 | declare var WeakMap: WeakMapConstructor;
55 |
56 |
57 | interface Set {
58 | add(value: T): Set;
59 | clear(): void;
60 | delete(value: T): boolean;
61 | forEach(callbackfn: (value: T, index: T, set: Set) => void, thisArg?: any): void;
62 | has(value: T): boolean;
63 | size: number;
64 | }
65 |
66 |
67 | interface SetConstructor {
68 | new (): Set;
69 | prototype: Set;
70 | }
71 |
72 |
73 | declare var Set: SetConstructor;
74 |
--------------------------------------------------------------------------------
/typings/es6-dataview.d.ts:
--------------------------------------------------------------------------------
1 | /*! *****************************************************************************
2 | Copyright (c) Microsoft Corporation. All rights reserved.
3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use
4 | this file except in compliance with the License. You may obtain a copy of the
5 | License at http://www.apache.org/licenses/LICENSE-2.0
6 |
7 | THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
8 | KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
9 | WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
10 | MERCHANTABLITY OR NON-INFRINGEMENT.
11 |
12 | See the Apache Version 2.0 License for specific language governing permissions
13 | and limitations under the License.
14 | *****************************************************************************
15 | */
16 |
17 | // Typescript has a bug in the DataView type: https://github.com/Microsoft/TypeScript/issues/3896
18 | // so we correct it
19 | interface DataView {
20 | getUint32(byteOffset: number, littleEndian?: boolean): number;
21 | setUint32(byteOffset: number, value: number, littleEndian?: boolean): void;
22 | }
23 |
--------------------------------------------------------------------------------
/typings/es6-promise/es6-promise.d.ts:
--------------------------------------------------------------------------------
1 | // Type definitions for es6-promise
2 | // Project: https://github.com/jakearchibald/ES6-Promise
3 | // Definitions by: François de Campredon , vvakame
4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped
5 |
6 | interface Thenable {
7 | then(onFulfilled?: (value: R) => U | Thenable, onRejected?: (error: any) => U | Thenable): Thenable;
8 | }
9 |
10 | declare class Promise implements Thenable {
11 | /**
12 | * If you call resolve in the body of the callback passed to the constructor,
13 | * your promise is fulfilled with result object passed to resolve.
14 | * If you call reject your promise is rejected with the object passed to resolve.
15 | * For consistency and debugging (eg stack traces), obj should be an instanceof Error.
16 | * Any errors thrown in the constructor callback will be implicitly passed to reject().
17 | */
18 | constructor(callback: (resolve : (value?: R | Thenable) => void, reject: (error?: any) => void) => void);
19 |
20 | /**
21 | * onFulfilled is called when/if "promise" resolves. onRejected is called when/if "promise" rejects.
22 | * Both are optional, if either/both are omitted the next onFulfilled/onRejected in the chain is called.
23 | * Both callbacks have a single parameter , the fulfillment value or rejection reason.
24 | * "then" returns a new promise equivalent to the value you return from onFulfilled/onRejected after being passed through Promise.resolve.
25 | * If an error is thrown in the callback, the returned promise rejects with that error.
26 | *
27 | * @param onFulfilled called when/if "promise" resolves
28 | * @param onRejected called when/if "promise" rejects
29 | */
30 | then(onFulfilled?: (value: R) => U | Thenable, onRejected?: (error: any) => U | Thenable): Promise;
31 |
32 | /**
33 | * Sugar for promise.then(undefined, onRejected)
34 | *
35 | * @param onRejected called when/if "promise" rejects
36 | */
37 | catch(onRejected?: (error: any) => U | Thenable): Promise;
38 | }
39 |
40 | declare module Promise {
41 | /**
42 | * Make a new promise from the thenable.
43 | * A thenable is promise-like in as far as it has a "then" method.
44 | */
45 | function resolve(value?: R | Thenable): Promise;
46 |
47 | /**
48 | * Make a promise that rejects to obj. For consistency and debugging (eg stack traces), obj should be an instanceof Error
49 | */
50 | function reject(error: any): Promise;
51 |
52 | /**
53 | * Make a promise that fulfills when every item in the array fulfills, and rejects if (and when) any item rejects.
54 | * the array passed to all can be a mixture of promise-like objects and other objects.
55 | * The fulfillment value is an array (in order) of fulfillment values. The rejection value is the first rejection value.
56 | */
57 | function all(promises: (R | Thenable)[]): Promise;
58 |
59 | /**
60 | * Make a Promise that fulfills when any item fulfills, and rejects if any item rejects.
61 | */
62 | function race(promises: (R | Thenable)[]): Promise;
63 | }
64 |
65 | declare module 'es6-promise' {
66 | var foo: typeof Promise; // Temp variable to reference Promise in local context
67 | module rsvp {
68 | export var Promise: typeof foo;
69 | }
70 | export = rsvp;
71 | }
72 |
--------------------------------------------------------------------------------
/typings/requirejs/r.d.ts:
--------------------------------------------------------------------------------
1 | // Type definitions for RequireJS 2.1.8
2 | // Project: http://requirejs.org/
3 | // Definitions by: Josh Baldwin
4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped
5 |
6 | /*
7 | require-2.1.8.d.ts may be freely distributed under the MIT license.
8 |
9 | Copyright (c) 2013 Josh Baldwin https://github.com/jbaldwin/require.d.ts
10 |
11 | Permission is hereby granted, free of charge, to any person
12 | obtaining a copy of this software and associated documentation
13 | files (the "Software"), to deal in the Software without
14 | restriction, including without limitation the rights to use,
15 | copy, modify, merge, publish, distribute, sublicense, and/or sell
16 | copies of the Software, and to permit persons to whom the
17 | Software is furnished to do so, subject to the following conditions:
18 |
19 | The above copyright notice and this permission notice shall be
20 | included in all copies or substantial portions of the Software.
21 |
22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
24 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
29 | OTHER DEALINGS IN THE SOFTWARE.
30 | */
31 |
32 | declare module 'module' {
33 | var mod: {
34 | config: () => any;
35 | id: string;
36 | uri: string;
37 | }
38 | export = mod;
39 | }
40 |
41 | interface RequireError extends Error {
42 |
43 | /**
44 | * The error ID that maps to an ID on a web page.
45 | **/
46 | requireType: string;
47 |
48 | /**
49 | * Required modules.
50 | **/
51 | requireModules: string[];
52 |
53 | /**
54 | * The original error, if there is one (might be null).
55 | **/
56 | originalError: Error;
57 | }
58 |
59 | interface RequireShim {
60 |
61 | /**
62 | * List of dependencies.
63 | **/
64 | deps?: string[];
65 |
66 | /**
67 | * Name the module will be exported as.
68 | **/
69 | exports?: string;
70 |
71 | /**
72 | * Initialize function with all dependcies passed in,
73 | * if the function returns a value then that value is used
74 | * as the module export value instead of the object
75 | * found via the 'exports' string.
76 | * @param dependencies
77 | * @return
78 | **/
79 | init?: (...dependencies: any[]) => any;
80 | }
81 |
82 | interface RequireConfig {
83 |
84 | // The root path to use for all module lookups.
85 | baseUrl?: string;
86 |
87 | // Path mappings for module names not found directly under
88 | // baseUrl.
89 | paths?: { [key: string]: any; };
90 |
91 | // Dictionary of Shim's.
92 | // does not cover case of key->string[]
93 | shim?: { [key: string]: RequireShim; };
94 |
95 | /**
96 | * For the given module prefix, instead of loading the
97 | * module with the given ID, substitude a different
98 | * module ID.
99 | *
100 | * @example
101 | * requirejs.config({
102 | * map: {
103 | * 'some/newmodule': {
104 | * 'foo': 'foo1.2'
105 | * },
106 | * 'some/oldmodule': {
107 | * 'foo': 'foo1.0'
108 | * }
109 | * }
110 | * });
111 | **/
112 | map?: {
113 | [id: string]: {
114 | [id: string]: string;
115 | };
116 | };
117 |
118 | /**
119 | * AMD configurations, use module.config() to access in
120 | * define() functions
121 | **/
122 | config?: { [id: string]: {}; };
123 |
124 | /**
125 | * Configures loading modules from CommonJS packages.
126 | **/
127 | packages?: {};
128 |
129 | /**
130 | * The number of seconds to wait before giving up on loading
131 | * a script. The default is 7 seconds.
132 | **/
133 | waitSeconds?: number;
134 |
135 | /**
136 | * A name to give to a loading context. This allows require.js
137 | * to load multiple versions of modules in a page, as long as
138 | * each top-level require call specifies a unique context string.
139 | **/
140 | context?: string;
141 |
142 | /**
143 | * An array of dependencies to load.
144 | **/
145 | deps?: string[];
146 |
147 | /**
148 | * A function to pass to require that should be require after
149 | * deps have been loaded.
150 | * @param modules
151 | **/
152 | callback?: (...modules: any[]) => void;
153 |
154 | /**
155 | * If set to true, an error will be thrown if a script loads
156 | * that does not call define() or have shim exports string
157 | * value that can be checked.
158 | **/
159 | enforceDefine?: boolean;
160 |
161 | /**
162 | * If set to true, document.createElementNS() will be used
163 | * to create script elements.
164 | **/
165 | xhtml?: boolean;
166 |
167 | /**
168 | * Extra query string arguments appended to URLs that RequireJS
169 | * uses to fetch resources. Most useful to cachce bust when
170 | * the browser or server is not configured correcty.
171 | *
172 | * @example
173 | * urlArgs: "bust= + (new Date()).getTime()
174 | **/
175 | urlArgs?: string;
176 |
177 | /**
178 | * Specify the value for the type="" attribute used for script
179 | * tags inserted into the document by RequireJS. Default is
180 | * "text/javascript". To use Firefox's JavasScript 1.8
181 | * features, use "text/javascript;version=1.8".
182 | **/
183 | scriptType?: string;
184 |
185 | }
186 |
187 | // todo: not sure what to do with this guy
188 | interface RequireModule {
189 |
190 | /**
191 | *
192 | **/
193 | config(): {};
194 |
195 | }
196 |
197 | /**
198 | *
199 | **/
200 | interface RequireMap {
201 |
202 | /**
203 | *
204 | **/
205 | prefix: string;
206 |
207 | /**
208 | *
209 | **/
210 | name: string;
211 |
212 | /**
213 | *
214 | **/
215 | parentMap: RequireMap;
216 |
217 | /**
218 | *
219 | **/
220 | url: string;
221 |
222 | /**
223 | *
224 | **/
225 | originalName: string;
226 |
227 | /**
228 | *
229 | **/
230 | fullName: string;
231 | }
232 |
233 | interface Require {
234 |
235 | /**
236 | * Configure require.js
237 | **/
238 | config(config: RequireConfig): Require;
239 |
240 | /**
241 | * CommonJS require call
242 | * @param module Module to load
243 | * @return The loaded module
244 | */
245 | (module: string): any;
246 |
247 | /**
248 | * Start the main app logic.
249 | * Callback is optional.
250 | * Can alternatively use deps and callback.
251 | * @param modules Required modules to load.
252 | **/
253 | (modules: string[]): void;
254 |
255 | /**
256 | * @see Require()
257 | * @param ready Called when required modules are ready.
258 | **/
259 | (modules: string[], ready: Function): void;
260 |
261 | /**
262 | * @see http://requirejs.org/docs/api.html#errbacks
263 | * @param ready Called when required modules are ready.
264 | **/
265 | (modules: string[], ready: Function, errback: Function): void;
266 |
267 | /**
268 | * Generate URLs from require module
269 | * @param module Module to URL
270 | * @return URL string
271 | **/
272 | toUrl(module: string): string;
273 |
274 | /**
275 | * Returns true if the module has already been loaded and defined.
276 | * @param module Module to check
277 | **/
278 | defined(module: string): boolean;
279 |
280 | /**
281 | * Returns true if the module has already been requested or is in the process of loading and should be available at some point.
282 | * @param module Module to check
283 | **/
284 | specified(module: string): boolean;
285 |
286 | /**
287 | * On Error override
288 | * @param err
289 | **/
290 | onError(err: RequireError, errback?: (err: RequireError) => void): void;
291 |
292 | /**
293 | * Undefine a module
294 | * @param module Module to undefine.
295 | **/
296 | undef(module: string): void;
297 |
298 | /**
299 | * Semi-private function, overload in special instance of undef()
300 | **/
301 | onResourceLoad(context: Object, map: RequireMap, depArray: RequireMap[]): void;
302 | }
303 |
304 | interface RequireDefine {
305 |
306 | /**
307 | * Define Simple Name/Value Pairs
308 | * @param config Dictionary of Named/Value pairs for the config.
309 | **/
310 | (config: { [key: string]: any; }): void;
311 |
312 | /**
313 | * Define function.
314 | * @param func: The function module.
315 | **/
316 | (func: () => any): void;
317 |
318 | /**
319 | * Define function with dependencies.
320 | * @param deps List of dependencies module IDs.
321 | * @param ready Callback function when the dependencies are loaded.
322 | * callback param deps module dependencies
323 | * callback return module definition
324 | **/
325 | (deps: string[], ready: Function): void;
326 |
327 | /**
328 | * Define module with simplified CommonJS wrapper.
329 | * @param ready
330 | * callback require requirejs instance
331 | * callback exports exports object
332 | * callback module module
333 | * callback return module definition
334 | **/
335 | (ready: (require: Require, exports: { [key: string]: any; }, module: RequireModule) => any): void;
336 |
337 | /**
338 | * Define a module with a name and dependencies.
339 | * @param name The name of the module.
340 | * @param deps List of dependencies module IDs.
341 | * @param ready Callback function when the dependencies are loaded.
342 | * callback deps module dependencies
343 | * callback return module definition
344 | **/
345 | (name: string, deps: string[], ready: Function): void;
346 |
347 | /**
348 | * Define a module with a name.
349 | * @param name The name of the module.
350 | * @param ready Callback function when the dependencies are loaded.
351 | * callback return module definition
352 | **/
353 | (name: string, ready: Function): void;
354 |
355 | /**
356 | * Used to allow a clear indicator that a global define function (as needed for script src browser loading) conforms
357 | * to the AMD API, any global define function SHOULD have a property called "amd" whose value is an object.
358 | * This helps avoid conflict with any other existing JavaScript code that could have defined a define() function
359 | * that does not conform to the AMD API.
360 | * define.amd.jQuery is specific to jQuery and indicates that the loader is able to account for multiple version
361 | * of jQuery being loaded simultaneously.
362 | */
363 | amd: Object;
364 | }
365 |
366 | // Ambient declarations for 'require' and 'define'
367 | declare var requirejs: Require;
368 | declare var require: Require;
369 | declare var define: RequireDefine;
370 |
371 |
372 | declare module 'requirejs' {
373 | export = requirejs;
374 | }
375 |
--------------------------------------------------------------------------------
/typings/term.js.d.ts:
--------------------------------------------------------------------------------
1 |
2 | declare module 'term.js' {
3 |
4 | /**
5 | * A terminal configuration.
6 | */
7 | export
8 | interface ITerminalConfig {
9 | convertEol?: boolean;
10 | termName?: string;
11 | rows?: number;
12 | cols?: number;
13 | cursorBlink?: boolean;
14 | visualBell?: boolean;
15 | popOnBell?: boolean;
16 | scrollback?: number;
17 | screenKeys?: number;
18 | useStyle?: boolean;
19 | }
20 |
21 |
22 | /**
23 | * Typing for a term.js terminal object.
24 | */
25 | export
26 | class Terminal {
27 | constructor(config: ITerminalConfig);
28 |
29 | options: ITerminalConfig;
30 |
31 | element: HTMLElement;
32 |
33 | colors: number[];
34 |
35 | rows: number;
36 |
37 | cols: number;
38 |
39 | open(el: HTMLElement): void;
40 |
41 | write(msg: string): void;
42 |
43 | resize(width: number, height: number): void;
44 |
45 | destroy(): void;
46 |
47 | }
48 | }
49 |
--------------------------------------------------------------------------------