##// END OF EJS Templates
Starting work on a Markdown cell.
Brian E. Granger -
Show More
@@ -0,0 +1,187 b''
1
2 //============================================================================
3 // RSTCell
4 //============================================================================
5
6 var IPython = (function (IPython) {
7
8 var RSTCell = function (notebook) {
9 IPython.Cell.apply(this, arguments);
10 this.placeholder = "Type ReStructured Text *here*."
11 this.rendered = false;
12 };
13
14
15 RSTCell.prototype = new IPython.Cell();
16
17
18
19 RSTCell.prototype.create_element = function () {
20 var cell = $("<div>").addClass('cell rst_cell border-box-sizing');
21 var input_area = $('<div/>').addClass('rst_cell_input');
22 this.code_mirror = CodeMirror(input_area.get(0), {
23 indentUnit : 4,
24 enterMode : 'flat',
25 tabMode: 'shift',
26 mode: 'rst',
27 theme: 'default',
28 value: this.placeholder
29 });
30 // The tabindex=-1 makes this div focusable.
31 var render_area = $('<div/>').addClass('rst_cell_render').
32 addClass('rendered_html').attr('tabindex','-1');
33 cell.append(input_area).append(render_area);
34 this.element = cell;
35 };
36
37
38 RSTCell.prototype.bind_events = function () {
39 IPython.Cell.prototype.bind_events.apply(this);
40 var that = this;
41 this.element.keydown(function (event) {
42 if (event.which === 13) {
43 if (that.rendered) {
44 that.edit();
45 event.preventDefault();
46 };
47 };
48 });
49 };
50
51
52 RSTCell.prototype.select = function () {
53 IPython.Cell.prototype.select.apply(this);
54 var output = this.element.find("div.rst_cell_render");
55 output.trigger('focus');
56 };
57
58
59 RSTCell.prototype.edit = function () {
60 if (this.rendered === true) {
61 var rst_cell = this.element;
62 var output = rst_cell.find("div.rst_cell_render");
63 output.hide();
64 rst_cell.find('div.rst_cell_input').show();
65 this.code_mirror.focus();
66 this.code_mirror.refresh();
67 this.rendered = false;
68 };
69 };
70
71
72 RSTCell.prototype.render = function () {
73 if (this.rendered === false) {
74 var text = this.get_source();
75 if (text === '') {text = this.placeholder;};
76 var html = IPython.markdown_converter.makeHtml(text);
77 this.set_rendered(html);
78 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
79 this.element.find('div.rst_cell_input').hide();
80 this.element.find("div.rst_cell_render").show();
81 this.rendered = true;
82 };
83 };
84
85
86 RSTCell.prototype.render_rst = function () {
87 if (this.rendered === false) {
88 var text = this.get_source();
89 if (text === "") {text = this.placeholder;};
90 var settings = {
91 processData : false,
92 cache : false,
93 type : "POST",
94 data : text,
95 headers : {'Content-Type': 'application/x-rst'},
96 success : $.proxy(this.handle_rendered,this)
97 };
98 $.ajax("/rstservice/render", settings);
99 };
100 };
101
102
103 RSTCell.prototype.handle_rendered = function (data, status, xhr) {
104 this.set_rendered(data);
105 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
106 this.element.find('div.rst_cell_input').hide();
107 this.element.find("div.rst_cell_render").show();
108 this.rendered = true;
109 };
110
111
112 RSTCell.prototype.config_mathjax = function () {
113 var rst_cell = this.element;
114 var that = this;
115 rst_cell.click(function () {
116 that.edit();
117 }).focusout(function () {
118 that.render();
119 });
120
121 rst_cell.trigger("focusout");
122 };
123
124
125 RSTCell.prototype.get_source = function () {
126 return this.code_mirror.getValue();
127 };
128
129
130 RSTCell.prototype.set_source = function (text) {
131 this.code_mirror.setValue(text);
132 this.code_mirror.refresh();
133 };
134
135
136 RSTCell.prototype.set_rendered = function (text) {
137 this.element.find('div.rst_cell_render').html(text);
138 };
139
140
141 RSTCell.prototype.get_rendered = function () {
142 return this.element.find('div.rst_cell_render').html();
143 };
144
145
146 RSTCell.prototype.at_top = function () {
147 if (this.rendered) {
148 return true;
149 } else {
150 return false;
151 }
152 };
153
154
155 RSTCell.prototype.at_bottom = function () {
156 if (this.rendered) {
157 return true;
158 } else {
159 return false;
160 }
161 };
162
163
164 RSTCell.prototype.fromJSON = function (data) {
165 if (data.cell_type === 'rst') {
166 if (data.source !== undefined) {
167 this.set_source(data.source);
168 this.set_rendered(data.rendered);
169 };
170 };
171 }
172
173
174 RSTCell.prototype.toJSON = function () {
175 var data = {}
176 data.cell_type = 'rst';
177 data.source = this.get_source();
178 data.rendered = this.get_rendered();
179 return data;
180 };
181
182 IPython.RSTCell = RSTCell;
183
184 return IPython;
185
186 }(IPython));
187
@@ -0,0 +1,32 b''
1 A javascript port of Markdown, as used on Stack Overflow
2 and the rest of Stack Exchange network.
3
4 Largely based on showdown.js by John Fraser (Attacklab).
5
6 Original Markdown Copyright (c) 2004-2005 John Gruber
7 <http://daringfireball.net/projects/markdown/>
8
9
10 Original Showdown code copyright (c) 2007 John Fraser
11
12 Modifications and bugfixes (c) 2009 Dana Robinson
13 Modifications and bugfixes (c) 2009-2011 Stack Exchange Inc.
14
15 Permission is hereby granted, free of charge, to any person obtaining a copy
16 of this software and associated documentation files (the "Software"), to deal
17 in the Software without restriction, including without limitation the rights
18 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19 copies of the Software, and to permit persons to whom the Software is
20 furnished to do so, subject to the following conditions:
21
22 The above copyright notice and this permission notice shall be included in
23 all copies or substantial portions of the Software.
24
25 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31 THE SOFTWARE.
32
This diff has been collapsed as it changes many lines, (1318 lines changed) Show them Hide them
@@ -0,0 +1,1318 b''
1 var Markdown;
2
3 if (typeof exports === "object" && typeof require === "function") // we're in a CommonJS (e.g. Node.js) module
4 Markdown = exports;
5 else
6 Markdown = {};
7
8 // The following text is included for historical reasons, but should
9 // be taken with a pinch of salt; it's not all true anymore.
10
11 //
12 // Wherever possible, Showdown is a straight, line-by-line port
13 // of the Perl version of Markdown.
14 //
15 // This is not a normal parser design; it's basically just a
16 // series of string substitutions. It's hard to read and
17 // maintain this way, but keeping Showdown close to the original
18 // design makes it easier to port new features.
19 //
20 // More importantly, Showdown behaves like markdown.pl in most
21 // edge cases. So web applications can do client-side preview
22 // in Javascript, and then build identical HTML on the server.
23 //
24 // This port needs the new RegExp functionality of ECMA 262,
25 // 3rd Edition (i.e. Javascript 1.5). Most modern web browsers
26 // should do fine. Even with the new regular expression features,
27 // We do a lot of work to emulate Perl's regex functionality.
28 // The tricky changes in this file mostly have the "attacklab:"
29 // label. Major or self-explanatory changes don't.
30 //
31 // Smart diff tools like Araxis Merge will be able to match up
32 // this file with markdown.pl in a useful way. A little tweaking
33 // helps: in a copy of markdown.pl, replace "#" with "//" and
34 // replace "$text" with "text". Be sure to ignore whitespace
35 // and line endings.
36 //
37
38
39 //
40 // Usage:
41 //
42 // var text = "Markdown *rocks*.";
43 //
44 // var converter = new Markdown.Converter();
45 // var html = converter.makeHtml(text);
46 //
47 // alert(html);
48 //
49 // Note: move the sample code to the bottom of this
50 // file before uncommenting it.
51 //
52
53 (function () {
54
55 function identity(x) { return x; }
56 function returnFalse(x) { return false; }
57
58 function HookCollection() { }
59
60 HookCollection.prototype = {
61
62 chain: function (hookname, func) {
63 var original = this[hookname];
64 if (!original)
65 throw new Error("unknown hook " + hookname);
66
67 if (original === identity)
68 this[hookname] = func;
69 else
70 this[hookname] = function (x) { return func(original(x)); }
71 },
72 set: function (hookname, func) {
73 if (!this[hookname])
74 throw new Error("unknown hook " + hookname);
75 this[hookname] = func;
76 },
77 addNoop: function (hookname) {
78 this[hookname] = identity;
79 },
80 addFalse: function (hookname) {
81 this[hookname] = returnFalse;
82 }
83 };
84
85 Markdown.HookCollection = HookCollection;
86
87 // g_urls and g_titles allow arbitrary user-entered strings as keys. This
88 // caused an exception (and hence stopped the rendering) when the user entered
89 // e.g. [push] or [__proto__]. Adding a prefix to the actual key prevents this
90 // (since no builtin property starts with "s_"). See
91 // http://meta.stackoverflow.com/questions/64655/strange-wmd-bug
92 // (granted, switching from Array() to Object() alone would have left only __proto__
93 // to be a problem)
94 function SaveHash() { }
95 SaveHash.prototype = {
96 set: function (key, value) {
97 this["s_" + key] = value;
98 },
99 get: function (key) {
100 return this["s_" + key];
101 }
102 };
103
104 Markdown.Converter = function () {
105 var pluginHooks = this.hooks = new HookCollection();
106 pluginHooks.addNoop("plainLinkText"); // given a URL that was encountered by itself (without markup), should return the link text that's to be given to this link
107 pluginHooks.addNoop("preConversion"); // called with the orignal text as given to makeHtml. The result of this plugin hook is the actual markdown source that will be cooked
108 pluginHooks.addNoop("postConversion"); // called with the final cooked HTML code. The result of this plugin hook is the actual output of makeHtml
109
110 //
111 // Private state of the converter instance:
112 //
113
114 // Global hashes, used by various utility routines
115 var g_urls;
116 var g_titles;
117 var g_html_blocks;
118
119 // Used to track when we're inside an ordered or unordered list
120 // (see _ProcessListItems() for details):
121 var g_list_level;
122
123 this.makeHtml = function (text) {
124
125 //
126 // Main function. The order in which other subs are called here is
127 // essential. Link and image substitutions need to happen before
128 // _EscapeSpecialCharsWithinTagAttributes(), so that any *'s or _'s in the <a>
129 // and <img> tags get encoded.
130 //
131
132 // This will only happen if makeHtml on the same converter instance is called from a plugin hook.
133 // Don't do that.
134 if (g_urls)
135 throw new Error("Recursive call to converter.makeHtml");
136
137 // Create the private state objects.
138 g_urls = new SaveHash();
139 g_titles = new SaveHash();
140 g_html_blocks = [];
141 g_list_level = 0;
142
143 text = pluginHooks.preConversion(text);
144
145 // attacklab: Replace ~ with ~T
146 // This lets us use tilde as an escape char to avoid md5 hashes
147 // The choice of character is arbitray; anything that isn't
148 // magic in Markdown will work.
149 text = text.replace(/~/g, "~T");
150
151 // attacklab: Replace $ with ~D
152 // RegExp interprets $ as a special character
153 // when it's in a replacement string
154 text = text.replace(/\$/g, "~D");
155
156 // Standardize line endings
157 text = text.replace(/\r\n/g, "\n"); // DOS to Unix
158 text = text.replace(/\r/g, "\n"); // Mac to Unix
159
160 // Make sure text begins and ends with a couple of newlines:
161 text = "\n\n" + text + "\n\n";
162
163 // Convert all tabs to spaces.
164 text = _Detab(text);
165
166 // Strip any lines consisting only of spaces and tabs.
167 // This makes subsequent regexen easier to write, because we can
168 // match consecutive blank lines with /\n+/ instead of something
169 // contorted like /[ \t]*\n+/ .
170 text = text.replace(/^[ \t]+$/mg, "");
171
172 // Turn block-level HTML blocks into hash entries
173 text = _HashHTMLBlocks(text);
174
175 // Strip link definitions, store in hashes.
176 text = _StripLinkDefinitions(text);
177
178 text = _RunBlockGamut(text);
179
180 text = _UnescapeSpecialChars(text);
181
182 // attacklab: Restore dollar signs
183 text = text.replace(/~D/g, "$$");
184
185 // attacklab: Restore tildes
186 text = text.replace(/~T/g, "~");
187
188 text = pluginHooks.postConversion(text);
189
190 g_html_blocks = g_titles = g_urls = null;
191
192 return text;
193 };
194
195 function _StripLinkDefinitions(text) {
196 //
197 // Strips link definitions from text, stores the URLs and titles in
198 // hash references.
199 //
200
201 // Link defs are in the form: ^[id]: url "optional title"
202
203 /*
204 text = text.replace(/
205 ^[ ]{0,3}\[(.+)\]: // id = $1 attacklab: g_tab_width - 1
206 [ \t]*
207 \n? // maybe *one* newline
208 [ \t]*
209 <?(\S+?)>? // url = $2
210 (?=\s|$) // lookahead for whitespace instead of the lookbehind removed below
211 [ \t]*
212 \n? // maybe one newline
213 [ \t]*
214 ( // (potential) title = $3
215 (\n*) // any lines skipped = $4 attacklab: lookbehind removed
216 [ \t]+
217 ["(]
218 (.+?) // title = $5
219 [")]
220 [ \t]*
221 )? // title is optional
222 (?:\n+|$)
223 /gm, function(){...});
224 */
225
226 text = text.replace(/^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?(?=\s|$)[ \t]*\n?[ \t]*((\n*)["(](.+?)[")][ \t]*)?(?:\n+)/gm,
227 function (wholeMatch, m1, m2, m3, m4, m5) {
228 m1 = m1.toLowerCase();
229 g_urls.set(m1, _EncodeAmpsAndAngles(m2)); // Link IDs are case-insensitive
230 if (m4) {
231 // Oops, found blank lines, so it's not a title.
232 // Put back the parenthetical statement we stole.
233 return m3;
234 } else if (m5) {
235 g_titles.set(m1, m5.replace(/"/g, "&quot;"));
236 }
237
238 // Completely remove the definition from the text
239 return "";
240 }
241 );
242
243 return text;
244 }
245
246 function _HashHTMLBlocks(text) {
247
248 // Hashify HTML blocks:
249 // We only want to do this for block-level HTML tags, such as headers,
250 // lists, and tables. That's because we still want to wrap <p>s around
251 // "paragraphs" that are wrapped in non-block-level tags, such as anchors,
252 // phrase emphasis, and spans. The list of tags we're looking for is
253 // hard-coded:
254 var block_tags_a = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del"
255 var block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math"
256
257 // First, look for nested blocks, e.g.:
258 // <div>
259 // <div>
260 // tags for inner block must be indented.
261 // </div>
262 // </div>
263 //
264 // The outermost tags must start at the left margin for this to match, and
265 // the inner nested divs must be indented.
266 // We need to do this before the next, more liberal match, because the next
267 // match will start at the first `<div>` and stop at the first `</div>`.
268
269 // attacklab: This regex can be expensive when it fails.
270
271 /*
272 text = text.replace(/
273 ( // save in $1
274 ^ // start of line (with /m)
275 <($block_tags_a) // start tag = $2
276 \b // word break
277 // attacklab: hack around khtml/pcre bug...
278 [^\r]*?\n // any number of lines, minimally matching
279 </\2> // the matching end tag
280 [ \t]* // trailing spaces/tabs
281 (?=\n+) // followed by a newline
282 ) // attacklab: there are sentinel newlines at end of document
283 /gm,function(){...}};
284 */
285 text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))/gm, hashElement);
286
287 //
288 // Now match more liberally, simply from `\n<tag>` to `</tag>\n`
289 //
290
291 /*
292 text = text.replace(/
293 ( // save in $1
294 ^ // start of line (with /m)
295 <($block_tags_b) // start tag = $2
296 \b // word break
297 // attacklab: hack around khtml/pcre bug...
298 [^\r]*? // any number of lines, minimally matching
299 .*</\2> // the matching end tag
300 [ \t]* // trailing spaces/tabs
301 (?=\n+) // followed by a newline
302 ) // attacklab: there are sentinel newlines at end of document
303 /gm,function(){...}};
304 */
305 text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math)\b[^\r]*?.*<\/\2>[ \t]*(?=\n+)\n)/gm, hashElement);
306
307 // Special case just for <hr />. It was easier to make a special case than
308 // to make the other regex more complicated.
309
310 /*
311 text = text.replace(/
312 \n // Starting after a blank line
313 [ ]{0,3}
314 ( // save in $1
315 (<(hr) // start tag = $2
316 \b // word break
317 ([^<>])*?
318 \/?>) // the matching end tag
319 [ \t]*
320 (?=\n{2,}) // followed by a blank line
321 )
322 /g,hashElement);
323 */
324 text = text.replace(/\n[ ]{0,3}((<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g, hashElement);
325
326 // Special case for standalone HTML comments:
327
328 /*
329 text = text.replace(/
330 \n\n // Starting after a blank line
331 [ ]{0,3} // attacklab: g_tab_width - 1
332 ( // save in $1
333 <!
334 (--(?:|(?:[^>-]|-[^>])(?:[^-]|-[^-])*)--) // see http://www.w3.org/TR/html-markup/syntax.html#comments and http://meta.stackoverflow.com/q/95256
335 >
336 [ \t]*
337 (?=\n{2,}) // followed by a blank line
338 )
339 /g,hashElement);
340 */
341 text = text.replace(/\n\n[ ]{0,3}(<!(--(?:|(?:[^>-]|-[^>])(?:[^-]|-[^-])*)--)>[ \t]*(?=\n{2,}))/g, hashElement);
342
343 // PHP and ASP-style processor instructions (<?...?> and <%...%>)
344
345 /*
346 text = text.replace(/
347 (?:
348 \n\n // Starting after a blank line
349 )
350 ( // save in $1
351 [ ]{0,3} // attacklab: g_tab_width - 1
352 (?:
353 <([?%]) // $2
354 [^\r]*?
355 \2>
356 )
357 [ \t]*
358 (?=\n{2,}) // followed by a blank line
359 )
360 /g,hashElement);
361 */
362 text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g, hashElement);
363
364 return text;
365 }
366
367 function hashElement(wholeMatch, m1) {
368 var blockText = m1;
369
370 // Undo double lines
371 blockText = blockText.replace(/^\n+/, "");
372
373 // strip trailing blank lines
374 blockText = blockText.replace(/\n+$/g, "");
375
376 // Replace the element text with a marker ("~KxK" where x is its key)
377 blockText = "\n\n~K" + (g_html_blocks.push(blockText) - 1) + "K\n\n";
378
379 return blockText;
380 }
381
382 function _RunBlockGamut(text, doNotUnhash) {
383 //
384 // These are all the transformations that form block-level
385 // tags like paragraphs, headers, and list items.
386 //
387 text = _DoHeaders(text);
388
389 // Do Horizontal Rules:
390 var replacement = "<hr />\n";
391 text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm, replacement);
392 text = text.replace(/^[ ]{0,2}([ ]?-[ ]?){3,}[ \t]*$/gm, replacement);
393 text = text.replace(/^[ ]{0,2}([ ]?_[ ]?){3,}[ \t]*$/gm, replacement);
394
395 text = _DoLists(text);
396 text = _DoCodeBlocks(text);
397 text = _DoBlockQuotes(text);
398
399 // We already ran _HashHTMLBlocks() before, in Markdown(), but that
400 // was to escape raw HTML in the original Markdown source. This time,
401 // we're escaping the markup we've just created, so that we don't wrap
402 // <p> tags around block-level tags.
403 text = _HashHTMLBlocks(text);
404 text = _FormParagraphs(text, doNotUnhash);
405
406 return text;
407 }
408
409 function _RunSpanGamut(text) {
410 //
411 // These are all the transformations that occur *within* block-level
412 // tags like paragraphs, headers, and list items.
413 //
414
415 text = _DoCodeSpans(text);
416 text = _EscapeSpecialCharsWithinTagAttributes(text);
417 text = _EncodeBackslashEscapes(text);
418
419 // Process anchor and image tags. Images must come first,
420 // because ![foo][f] looks like an anchor.
421 text = _DoImages(text);
422 text = _DoAnchors(text);
423
424 // Make links out of things like `<http://example.com/>`
425 // Must come after _DoAnchors(), because you can use < and >
426 // delimiters in inline links like [this](<url>).
427 text = _DoAutoLinks(text);
428 text = _EncodeAmpsAndAngles(text);
429 text = _DoItalicsAndBold(text);
430
431 // Do hard breaks:
432 text = text.replace(/ +\n/g, " <br>\n");
433
434 return text;
435 }
436
437 function _EscapeSpecialCharsWithinTagAttributes(text) {
438 //
439 // Within tags -- meaning between < and > -- encode [\ ` * _] so they
440 // don't conflict with their use in Markdown for code, italics and strong.
441 //
442
443 // Build a regex to find HTML tags and comments. See Friedl's
444 // "Mastering Regular Expressions", 2nd Ed., pp. 200-201.
445
446 // SE: changed the comment part of the regex
447
448 var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--(?:|(?:[^>-]|-[^>])(?:[^-]|-[^-])*)--)>)/gi;
449
450 text = text.replace(regex, function (wholeMatch) {
451 var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g, "$1`");
452 tag = escapeCharacters(tag, wholeMatch.charAt(1) == "!" ? "\\`*_/" : "\\`*_"); // also escape slashes in comments to prevent autolinking there -- http://meta.stackoverflow.com/questions/95987
453 return tag;
454 });
455
456 return text;
457 }
458
459 function _DoAnchors(text) {
460 //
461 // Turn Markdown link shortcuts into XHTML <a> tags.
462 //
463 //
464 // First, handle reference-style links: [link text] [id]
465 //
466
467 /*
468 text = text.replace(/
469 ( // wrap whole match in $1
470 \[
471 (
472 (?:
473 \[[^\]]*\] // allow brackets nested one level
474 |
475 [^\[] // or anything else
476 )*
477 )
478 \]
479
480 [ ]? // one optional space
481 (?:\n[ ]*)? // one optional newline followed by spaces
482
483 \[
484 (.*?) // id = $3
485 \]
486 )
487 ()()()() // pad remaining backreferences
488 /g, writeAnchorTag);
489 */
490 text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g, writeAnchorTag);
491
492 //
493 // Next, inline-style links: [link text](url "optional title")
494 //
495
496 /*
497 text = text.replace(/
498 ( // wrap whole match in $1
499 \[
500 (
501 (?:
502 \[[^\]]*\] // allow brackets nested one level
503 |
504 [^\[\]] // or anything else
505 )*
506 )
507 \]
508 \( // literal paren
509 [ \t]*
510 () // no id, so leave $3 empty
511 <?( // href = $4
512 (?:
513 \([^)]*\) // allow one level of (correctly nested) parens (think MSDN)
514 |
515 [^()]
516 )*?
517 )>?
518 [ \t]*
519 ( // $5
520 (['"]) // quote char = $6
521 (.*?) // Title = $7
522 \6 // matching quote
523 [ \t]* // ignore any spaces/tabs between closing quote and )
524 )? // title is optional
525 \)
526 )
527 /g, writeAnchorTag);
528 */
529
530 text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()<?((?:\([^)]*\)|[^()])*?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g, writeAnchorTag);
531
532 //
533 // Last, handle reference-style shortcuts: [link text]
534 // These must come last in case you've also got [link test][1]
535 // or [link test](/foo)
536 //
537
538 /*
539 text = text.replace(/
540 ( // wrap whole match in $1
541 \[
542 ([^\[\]]+) // link text = $2; can't contain '[' or ']'
543 \]
544 )
545 ()()()()() // pad rest of backreferences
546 /g, writeAnchorTag);
547 */
548 text = text.replace(/(\[([^\[\]]+)\])()()()()()/g, writeAnchorTag);
549
550 return text;
551 }
552
553 function writeAnchorTag(wholeMatch, m1, m2, m3, m4, m5, m6, m7) {
554 if (m7 == undefined) m7 = "";
555 var whole_match = m1;
556 var link_text = m2;
557 var link_id = m3.toLowerCase();
558 var url = m4;
559 var title = m7;
560
561 if (url == "") {
562 if (link_id == "") {
563 // lower-case and turn embedded newlines into spaces
564 link_id = link_text.toLowerCase().replace(/ ?\n/g, " ");
565 }
566 url = "#" + link_id;
567
568 if (g_urls.get(link_id) != undefined) {
569 url = g_urls.get(link_id);
570 if (g_titles.get(link_id) != undefined) {
571 title = g_titles.get(link_id);
572 }
573 }
574 else {
575 if (whole_match.search(/\(\s*\)$/m) > -1) {
576 // Special case for explicit empty url
577 url = "";
578 } else {
579 return whole_match;
580 }
581 }
582 }
583 url = encodeProblemUrlChars(url);
584 url = escapeCharacters(url, "*_");
585 var result = "<a href=\"" + url + "\"";
586
587 if (title != "") {
588 title = title.replace(/"/g, "&quot;");
589 title = escapeCharacters(title, "*_");
590 result += " title=\"" + title + "\"";
591 }
592
593 result += ">" + link_text + "</a>";
594
595 return result;
596 }
597
598 function _DoImages(text) {
599 //
600 // Turn Markdown image shortcuts into <img> tags.
601 //
602
603 //
604 // First, handle reference-style labeled images: ![alt text][id]
605 //
606
607 /*
608 text = text.replace(/
609 ( // wrap whole match in $1
610 !\[
611 (.*?) // alt text = $2
612 \]
613
614 [ ]? // one optional space
615 (?:\n[ ]*)? // one optional newline followed by spaces
616
617 \[
618 (.*?) // id = $3
619 \]
620 )
621 ()()()() // pad rest of backreferences
622 /g, writeImageTag);
623 */
624 text = text.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g, writeImageTag);
625
626 //
627 // Next, handle inline images: ![alt text](url "optional title")
628 // Don't forget: encode * and _
629
630 /*
631 text = text.replace(/
632 ( // wrap whole match in $1
633 !\[
634 (.*?) // alt text = $2
635 \]
636 \s? // One optional whitespace character
637 \( // literal paren
638 [ \t]*
639 () // no id, so leave $3 empty
640 <?(\S+?)>? // src url = $4
641 [ \t]*
642 ( // $5
643 (['"]) // quote char = $6
644 (.*?) // title = $7
645 \6 // matching quote
646 [ \t]*
647 )? // title is optional
648 \)
649 )
650 /g, writeImageTag);
651 */
652 text = text.replace(/(!\[(.*?)\]\s?\([ \t]*()<?(\S+?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g, writeImageTag);
653
654 return text;
655 }
656
657 function writeImageTag(wholeMatch, m1, m2, m3, m4, m5, m6, m7) {
658 var whole_match = m1;
659 var alt_text = m2;
660 var link_id = m3.toLowerCase();
661 var url = m4;
662 var title = m7;
663
664 if (!title) title = "";
665
666 if (url == "") {
667 if (link_id == "") {
668 // lower-case and turn embedded newlines into spaces
669 link_id = alt_text.toLowerCase().replace(/ ?\n/g, " ");
670 }
671 url = "#" + link_id;
672
673 if (g_urls.get(link_id) != undefined) {
674 url = g_urls.get(link_id);
675 if (g_titles.get(link_id) != undefined) {
676 title = g_titles.get(link_id);
677 }
678 }
679 else {
680 return whole_match;
681 }
682 }
683
684 alt_text = alt_text.replace(/"/g, "&quot;");
685 url = escapeCharacters(url, "*_");
686 var result = "<img src=\"" + url + "\" alt=\"" + alt_text + "\"";
687
688 // attacklab: Markdown.pl adds empty title attributes to images.
689 // Replicate this bug.
690
691 //if (title != "") {
692 title = title.replace(/"/g, "&quot;");
693 title = escapeCharacters(title, "*_");
694 result += " title=\"" + title + "\"";
695 //}
696
697 result += " />";
698
699 return result;
700 }
701
702 function _DoHeaders(text) {
703
704 // Setext-style headers:
705 // Header 1
706 // ========
707 //
708 // Header 2
709 // --------
710 //
711 text = text.replace(/^(.+)[ \t]*\n=+[ \t]*\n+/gm,
712 function (wholeMatch, m1) { return "<h1>" + _RunSpanGamut(m1) + "</h1>\n\n"; }
713 );
714
715 text = text.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm,
716 function (matchFound, m1) { return "<h2>" + _RunSpanGamut(m1) + "</h2>\n\n"; }
717 );
718
719 // atx-style headers:
720 // # Header 1
721 // ## Header 2
722 // ## Header 2 with closing hashes ##
723 // ...
724 // ###### Header 6
725 //
726
727 /*
728 text = text.replace(/
729 ^(\#{1,6}) // $1 = string of #'s
730 [ \t]*
731 (.+?) // $2 = Header text
732 [ \t]*
733 \#* // optional closing #'s (not counted)
734 \n+
735 /gm, function() {...});
736 */
737
738 text = text.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm,
739 function (wholeMatch, m1, m2) {
740 var h_level = m1.length;
741 return "<h" + h_level + ">" + _RunSpanGamut(m2) + "</h" + h_level + ">\n\n";
742 }
743 );
744
745 return text;
746 }
747
748 function _DoLists(text) {
749 //
750 // Form HTML ordered (numbered) and unordered (bulleted) lists.
751 //
752
753 // attacklab: add sentinel to hack around khtml/safari bug:
754 // http://bugs.webkit.org/show_bug.cgi?id=11231
755 text += "~0";
756
757 // Re-usable pattern to match any entirel ul or ol list:
758
759 /*
760 var whole_list = /
761 ( // $1 = whole list
762 ( // $2
763 [ ]{0,3} // attacklab: g_tab_width - 1
764 ([*+-]|\d+[.]) // $3 = first list item marker
765 [ \t]+
766 )
767 [^\r]+?
768 ( // $4
769 ~0 // sentinel for workaround; should be $
770 |
771 \n{2,}
772 (?=\S)
773 (?! // Negative lookahead for another list item marker
774 [ \t]*
775 (?:[*+-]|\d+[.])[ \t]+
776 )
777 )
778 )
779 /g
780 */
781 var whole_list = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
782
783 if (g_list_level) {
784 text = text.replace(whole_list, function (wholeMatch, m1, m2) {
785 var list = m1;
786 var list_type = (m2.search(/[*+-]/g) > -1) ? "ul" : "ol";
787
788 var result = _ProcessListItems(list, list_type);
789
790 // Trim any trailing whitespace, to put the closing `</$list_type>`
791 // up on the preceding line, to get it past the current stupid
792 // HTML block parser. This is a hack to work around the terrible
793 // hack that is the HTML block parser.
794 result = result.replace(/\s+$/, "");
795 result = "<" + list_type + ">" + result + "</" + list_type + ">\n";
796 return result;
797 });
798 } else {
799 whole_list = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/g;
800 text = text.replace(whole_list, function (wholeMatch, m1, m2, m3) {
801 var runup = m1;
802 var list = m2;
803
804 var list_type = (m3.search(/[*+-]/g) > -1) ? "ul" : "ol";
805 var result = _ProcessListItems(list, list_type);
806 result = runup + "<" + list_type + ">\n" + result + "</" + list_type + ">\n";
807 return result;
808 });
809 }
810
811 // attacklab: strip sentinel
812 text = text.replace(/~0/, "");
813
814 return text;
815 }
816
817 var _listItemMarkers = { ol: "\\d+[.]", ul: "[*+-]" };
818
819 function _ProcessListItems(list_str, list_type) {
820 //
821 // Process the contents of a single ordered or unordered list, splitting it
822 // into individual list items.
823 //
824 // list_type is either "ul" or "ol".
825
826 // The $g_list_level global keeps track of when we're inside a list.
827 // Each time we enter a list, we increment it; when we leave a list,
828 // we decrement. If it's zero, we're not in a list anymore.
829 //
830 // We do this because when we're not inside a list, we want to treat
831 // something like this:
832 //
833 // I recommend upgrading to version
834 // 8. Oops, now this line is treated
835 // as a sub-list.
836 //
837 // As a single paragraph, despite the fact that the second line starts
838 // with a digit-period-space sequence.
839 //
840 // Whereas when we're inside a list (or sub-list), that line will be
841 // treated as the start of a sub-list. What a kludge, huh? This is
842 // an aspect of Markdown's syntax that's hard to parse perfectly
843 // without resorting to mind-reading. Perhaps the solution is to
844 // change the syntax rules such that sub-lists must start with a
845 // starting cardinal number; e.g. "1." or "a.".
846
847 g_list_level++;
848
849 // trim trailing blank lines:
850 list_str = list_str.replace(/\n{2,}$/, "\n");
851
852 // attacklab: add sentinel to emulate \z
853 list_str += "~0";
854
855 // In the original attacklab showdown, list_type was not given to this function, and anything
856 // that matched /[*+-]|\d+[.]/ would just create the next <li>, causing this mismatch:
857 //
858 // Markdown rendered by WMD rendered by MarkdownSharp
859 // ------------------------------------------------------------------
860 // 1. first 1. first 1. first
861 // 2. second 2. second 2. second
862 // - third 3. third * third
863 //
864 // We changed this to behave identical to MarkdownSharp. This is the constructed RegEx,
865 // with {MARKER} being one of \d+[.] or [*+-], depending on list_type:
866
867 /*
868 list_str = list_str.replace(/
869 (^[ \t]*) // leading whitespace = $1
870 ({MARKER}) [ \t]+ // list marker = $2
871 ([^\r]+? // list item text = $3
872 (\n+)
873 )
874 (?=
875 (~0 | \2 ({MARKER}) [ \t]+)
876 )
877 /gm, function(){...});
878 */
879
880 var marker = _listItemMarkers[list_type];
881 var re = new RegExp("(^[ \\t]*)(" + marker + ")[ \\t]+([^\\r]+?(\\n+))(?=(~0|\\1(" + marker + ")[ \\t]+))", "gm");
882 var last_item_had_a_double_newline = false;
883 list_str = list_str.replace(re,
884 function (wholeMatch, m1, m2, m3) {
885 var item = m3;
886 var leading_space = m1;
887 var ends_with_double_newline = /\n\n$/.test(item);
888 var contains_double_newline = ends_with_double_newline || item.search(/\n{2,}/) > -1;
889
890 if (contains_double_newline || last_item_had_a_double_newline) {
891 item = _RunBlockGamut(_Outdent(item), /* doNotUnhash = */true);
892 }
893 else {
894 // Recursion for sub-lists:
895 item = _DoLists(_Outdent(item));
896 item = item.replace(/\n$/, ""); // chomp(item)
897 item = _RunSpanGamut(item);
898 }
899 last_item_had_a_double_newline = ends_with_double_newline;
900 return "<li>" + item + "</li>\n";
901 }
902 );
903
904 // attacklab: strip sentinel
905 list_str = list_str.replace(/~0/g, "");
906
907 g_list_level--;
908 return list_str;
909 }
910
911 function _DoCodeBlocks(text) {
912 //
913 // Process Markdown `<pre><code>` blocks.
914 //
915
916 /*
917 text = text.replace(/
918 (?:\n\n|^)
919 ( // $1 = the code block -- one or more lines, starting with a space/tab
920 (?:
921 (?:[ ]{4}|\t) // Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
922 .*\n+
923 )+
924 )
925 (\n*[ ]{0,3}[^ \t\n]|(?=~0)) // attacklab: g_tab_width
926 /g ,function(){...});
927 */
928
929 // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
930 text += "~0";
931
932 text = text.replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g,
933 function (wholeMatch, m1, m2) {
934 var codeblock = m1;
935 var nextChar = m2;
936
937 codeblock = _EncodeCode(_Outdent(codeblock));
938 codeblock = _Detab(codeblock);
939 codeblock = codeblock.replace(/^\n+/g, ""); // trim leading newlines
940 codeblock = codeblock.replace(/\n+$/g, ""); // trim trailing whitespace
941
942 codeblock = "<pre><code>" + codeblock + "\n</code></pre>";
943
944 return "\n\n" + codeblock + "\n\n" + nextChar;
945 }
946 );
947
948 // attacklab: strip sentinel
949 text = text.replace(/~0/, "");
950
951 return text;
952 }
953
954 function hashBlock(text) {
955 text = text.replace(/(^\n+|\n+$)/g, "");
956 return "\n\n~K" + (g_html_blocks.push(text) - 1) + "K\n\n";
957 }
958
959 function _DoCodeSpans(text) {
960 //
961 // * Backtick quotes are used for <code></code> spans.
962 //
963 // * You can use multiple backticks as the delimiters if you want to
964 // include literal backticks in the code span. So, this input:
965 //
966 // Just type ``foo `bar` baz`` at the prompt.
967 //
968 // Will translate to:
969 //
970 // <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
971 //
972 // There's no arbitrary limit to the number of backticks you
973 // can use as delimters. If you need three consecutive backticks
974 // in your code, use four for delimiters, etc.
975 //
976 // * You can use spaces to get literal backticks at the edges:
977 //
978 // ... type `` `bar` `` ...
979 //
980 // Turns to:
981 //
982 // ... type <code>`bar`</code> ...
983 //
984
985 /*
986 text = text.replace(/
987 (^|[^\\]) // Character before opening ` can't be a backslash
988 (`+) // $2 = Opening run of `
989 ( // $3 = The code block
990 [^\r]*?
991 [^`] // attacklab: work around lack of lookbehind
992 )
993 \2 // Matching closer
994 (?!`)
995 /gm, function(){...});
996 */
997
998 text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
999 function (wholeMatch, m1, m2, m3, m4) {
1000 var c = m3;
1001 c = c.replace(/^([ \t]*)/g, ""); // leading whitespace
1002 c = c.replace(/[ \t]*$/g, ""); // trailing whitespace
1003 c = _EncodeCode(c);
1004 return m1 + "<code>" + c + "</code>";
1005 }
1006 );
1007
1008 return text;
1009 }
1010
1011 function _EncodeCode(text) {
1012 //
1013 // Encode/escape certain characters inside Markdown code runs.
1014 // The point is that in code, these characters are literals,
1015 // and lose their special Markdown meanings.
1016 //
1017 // Encode all ampersands; HTML entities are not
1018 // entities within a Markdown code span.
1019 text = text.replace(/&/g, "&amp;");
1020
1021 // Do the angle bracket song and dance:
1022 text = text.replace(/</g, "&lt;");
1023 text = text.replace(/>/g, "&gt;");
1024
1025 // Now, escape characters that are magic in Markdown:
1026 text = escapeCharacters(text, "\*_{}[]\\", false);
1027
1028 // jj the line above breaks this:
1029 //---
1030
1031 //* Item
1032
1033 // 1. Subitem
1034
1035 // special char: *
1036 //---
1037
1038 return text;
1039 }
1040
1041 function _DoItalicsAndBold(text) {
1042
1043 // <strong> must go first:
1044 text = text.replace(/([\W_]|^)(\*\*|__)(?=\S)([^\r]*?\S[\*_]*)\2([\W_]|$)/g,
1045 "$1<strong>$3</strong>$4");
1046
1047 text = text.replace(/([\W_]|^)(\*|_)(?=\S)([^\r\*_]*?\S)\2([\W_]|$)/g,
1048 "$1<em>$3</em>$4");
1049
1050 return text;
1051 }
1052
1053 function _DoBlockQuotes(text) {
1054
1055 /*
1056 text = text.replace(/
1057 ( // Wrap whole match in $1
1058 (
1059 ^[ \t]*>[ \t]? // '>' at the start of a line
1060 .+\n // rest of the first line
1061 (.+\n)* // subsequent consecutive lines
1062 \n* // blanks
1063 )+
1064 )
1065 /gm, function(){...});
1066 */
1067
1068 text = text.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm,
1069 function (wholeMatch, m1) {
1070 var bq = m1;
1071
1072 // attacklab: hack around Konqueror 3.5.4 bug:
1073 // "----------bug".replace(/^-/g,"") == "bug"
1074
1075 bq = bq.replace(/^[ \t]*>[ \t]?/gm, "~0"); // trim one level of quoting
1076
1077 // attacklab: clean up hack
1078 bq = bq.replace(/~0/g, "");
1079
1080 bq = bq.replace(/^[ \t]+$/gm, ""); // trim whitespace-only lines
1081 bq = _RunBlockGamut(bq); // recurse
1082
1083 bq = bq.replace(/(^|\n)/g, "$1 ");
1084 // These leading spaces screw with <pre> content, so we need to fix that:
1085 bq = bq.replace(
1086 /(\s*<pre>[^\r]+?<\/pre>)/gm,
1087 function (wholeMatch, m1) {
1088 var pre = m1;
1089 // attacklab: hack around Konqueror 3.5.4 bug:
1090 pre = pre.replace(/^ /mg, "~0");
1091 pre = pre.replace(/~0/g, "");
1092 return pre;
1093 });
1094
1095 return hashBlock("<blockquote>\n" + bq + "\n</blockquote>");
1096 }
1097 );
1098 return text;
1099 }
1100
1101 function _FormParagraphs(text, doNotUnhash) {
1102 //
1103 // Params:
1104 // $text - string to process with html <p> tags
1105 //
1106
1107 // Strip leading and trailing lines:
1108 text = text.replace(/^\n+/g, "");
1109 text = text.replace(/\n+$/g, "");
1110
1111 var grafs = text.split(/\n{2,}/g);
1112 var grafsOut = [];
1113
1114 //
1115 // Wrap <p> tags.
1116 //
1117 var end = grafs.length;
1118 for (var i = 0; i < end; i++) {
1119 var str = grafs[i];
1120
1121 // if this is an HTML marker, copy it
1122 if (str.search(/~K(\d+)K/g) >= 0) {
1123 grafsOut.push(str);
1124 }
1125 else if (str.search(/\S/) >= 0) {
1126 str = _RunSpanGamut(str);
1127 str = str.replace(/^([ \t]*)/g, "<p>");
1128 str += "</p>"
1129 grafsOut.push(str);
1130 }
1131
1132 }
1133 //
1134 // Unhashify HTML blocks
1135 //
1136 if (!doNotUnhash) {
1137 end = grafsOut.length;
1138 for (var i = 0; i < end; i++) {
1139 // if this is a marker for an html block...
1140 while (grafsOut[i].search(/~K(\d+)K/) >= 0) {
1141 var blockText = g_html_blocks[RegExp.$1];
1142 blockText = blockText.replace(/\$/g, "$$$$"); // Escape any dollar signs
1143 grafsOut[i] = grafsOut[i].replace(/~K\d+K/, blockText);
1144 }
1145 }
1146 }
1147 return grafsOut.join("\n\n");
1148 }
1149
1150 function _EncodeAmpsAndAngles(text) {
1151 // Smart processing for ampersands and angle brackets that need to be encoded.
1152
1153 // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
1154 // http://bumppo.net/projects/amputator/
1155 text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, "&amp;");
1156
1157 // Encode naked <'s
1158 text = text.replace(/<(?![a-z\/?\$!])/gi, "&lt;");
1159
1160 return text;
1161 }
1162
1163 function _EncodeBackslashEscapes(text) {
1164 //
1165 // Parameter: String.
1166 // Returns: The string, with after processing the following backslash
1167 // escape sequences.
1168 //
1169
1170 // attacklab: The polite way to do this is with the new
1171 // escapeCharacters() function:
1172 //
1173 // text = escapeCharacters(text,"\\",true);
1174 // text = escapeCharacters(text,"`*_{}[]()>#+-.!",true);
1175 //
1176 // ...but we're sidestepping its use of the (slow) RegExp constructor
1177 // as an optimization for Firefox. This function gets called a LOT.
1178
1179 text = text.replace(/\\(\\)/g, escapeCharacters_callback);
1180 text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g, escapeCharacters_callback);
1181 return text;
1182 }
1183
1184 function _DoAutoLinks(text) {
1185
1186 // note that at this point, all other URL in the text are already hyperlinked as <a href=""></a>
1187 // *except* for the <http://www.foo.com> case
1188
1189 // automatically add < and > around unadorned raw hyperlinks
1190 // must be preceded by space/BOF and followed by non-word/EOF character
1191 text = text.replace(/(^|\s)(https?|ftp)(:\/\/[-A-Z0-9+&@#\/%?=~_|\[\]\(\)!:,\.;]*[-A-Z0-9+&@#\/%=~_|\[\]])($|\W)/gi, "$1<$2$3>$4");
1192
1193 // autolink anything like <http://example.com>
1194
1195 var replacer = function (wholematch, m1) { return "<a href=\"" + m1 + "\">" + pluginHooks.plainLinkText(m1) + "</a>"; }
1196 text = text.replace(/<((https?|ftp):[^'">\s]+)>/gi, replacer);
1197
1198 // Email addresses: <address@domain.foo>
1199 /*
1200 text = text.replace(/
1201 <
1202 (?:mailto:)?
1203 (
1204 [-.\w]+
1205 \@
1206 [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+
1207 )
1208 >
1209 /gi, _DoAutoLinks_callback());
1210 */
1211
1212 /* disabling email autolinking, since we don't do that on the server, either
1213 text = text.replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,
1214 function(wholeMatch,m1) {
1215 return _EncodeEmailAddress( _UnescapeSpecialChars(m1) );
1216 }
1217 );
1218 */
1219 return text;
1220 }
1221
1222 function _UnescapeSpecialChars(text) {
1223 //
1224 // Swap back in all the special characters we've hidden.
1225 //
1226 text = text.replace(/~E(\d+)E/g,
1227 function (wholeMatch, m1) {
1228 var charCodeToReplace = parseInt(m1);
1229 return String.fromCharCode(charCodeToReplace);
1230 }
1231 );
1232 return text;
1233 }
1234
1235 function _Outdent(text) {
1236 //
1237 // Remove one level of line-leading tabs or spaces
1238 //
1239
1240 // attacklab: hack around Konqueror 3.5.4 bug:
1241 // "----------bug".replace(/^-/g,"") == "bug"
1242
1243 text = text.replace(/^(\t|[ ]{1,4})/gm, "~0"); // attacklab: g_tab_width
1244
1245 // attacklab: clean up hack
1246 text = text.replace(/~0/g, "")
1247
1248 return text;
1249 }
1250
1251 function _Detab(text) {
1252 if (!/\t/.test(text))
1253 return text;
1254
1255 var spaces = [" ", " ", " ", " "],
1256 skew = 0,
1257 v;
1258
1259 return text.replace(/[\n\t]/g, function (match, offset) {
1260 if (match === "\n") {
1261 skew = offset + 1;
1262 return match;
1263 }
1264 v = (offset - skew) % 4;
1265 skew = offset + 1;
1266 return spaces[v];
1267 });
1268 }
1269
1270 //
1271 // attacklab: Utility functions
1272 //
1273
1274 var _problemUrlChars = /(?:["'*()[\]:]|~D)/g;
1275
1276 // hex-encodes some unusual "problem" chars in URLs to avoid URL detection problems
1277 function encodeProblemUrlChars(url) {
1278 if (!url)
1279 return "";
1280
1281 var len = url.length;
1282
1283 return url.replace(_problemUrlChars, function (match, offset) {
1284 if (match == "~D") // escape for dollar
1285 return "%24";
1286 if (match == ":") {
1287 if (offset == len - 1 || /[0-9\/]/.test(url.charAt(offset + 1)))
1288 return ":"
1289 }
1290 return "%" + match.charCodeAt(0).toString(16);
1291 });
1292 }
1293
1294
1295 function escapeCharacters(text, charsToEscape, afterBackslash) {
1296 // First we have to escape the escape characters so that
1297 // we can build a character class out of them
1298 var regexString = "([" + charsToEscape.replace(/([\[\]\\])/g, "\\$1") + "])";
1299
1300 if (afterBackslash) {
1301 regexString = "\\\\" + regexString;
1302 }
1303
1304 var regex = new RegExp(regexString, "g");
1305 text = text.replace(regex, escapeCharacters_callback);
1306
1307 return text;
1308 }
1309
1310
1311 function escapeCharacters_callback(wholeMatch, m1) {
1312 var charCodeToEscape = m1.charCodeAt(0);
1313 return "~E" + charCodeToEscape + "E";
1314 }
1315
1316 }; // end of the Markdown.Converter constructor
1317
1318 })();
@@ -1,158 +1,212 b''
1 """Tornado handlers for the notebook."""
1 """Tornado handlers for the notebook."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Imports
4 # Imports
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6
6
7 import json
7 import json
8 import logging
8 import logging
9 import os
9 import urllib
10 import urllib
10
11
11 from tornado import web
12 from tornado import web
12 from tornado import websocket
13 from tornado import websocket
13
14
15 try:
16 from docutils.core import publish_string
17 except ImportError:
18 publish_string = None
19
14
20
15 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
16 # Top-level handlers
22 # Top-level handlers
17 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
18
24
19
25
20 class NBBrowserHandler(web.RequestHandler):
26 class NBBrowserHandler(web.RequestHandler):
21 def get(self):
27 def get(self):
22 nbm = self.application.notebook_manager
28 nbm = self.application.notebook_manager
23 project = nbm.notebook_dir
29 project = nbm.notebook_dir
24 self.render('nbbrowser.html', project=project)
30 self.render('nbbrowser.html', project=project)
25
31
26
32
27 class NewHandler(web.RequestHandler):
33 class NewHandler(web.RequestHandler):
28 def get(self):
34 def get(self):
29 notebook_id = self.application.notebook_manager.new_notebook()
35 notebook_id = self.application.notebook_manager.new_notebook()
30 self.render('notebook.html', notebook_id=notebook_id)
36 self.render('notebook.html', notebook_id=notebook_id)
31
37
32
38
33 class NamedNotebookHandler(web.RequestHandler):
39 class NamedNotebookHandler(web.RequestHandler):
34 def get(self, notebook_id):
40 def get(self, notebook_id):
35 nbm = self.application.notebook_manager
41 nbm = self.application.notebook_manager
36 if not nbm.notebook_exists(notebook_id):
42 if not nbm.notebook_exists(notebook_id):
37 raise web.HTTPError(404)
43 raise web.HTTPError(404)
38 self.render('notebook.html', notebook_id=notebook_id)
44 self.render('notebook.html', notebook_id=notebook_id)
39
45
40
46
41 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
42 # Kernel handlers
48 # Kernel handlers
43 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
44
50
45
51
46 class MainKernelHandler(web.RequestHandler):
52 class MainKernelHandler(web.RequestHandler):
47
53
48 def get(self):
54 def get(self):
49 rkm = self.application.routing_kernel_manager
55 rkm = self.application.routing_kernel_manager
50 self.finish(json.dumps(rkm.kernel_ids))
56 self.finish(json.dumps(rkm.kernel_ids))
51
57
52 def post(self):
58 def post(self):
53 rkm = self.application.routing_kernel_manager
59 rkm = self.application.routing_kernel_manager
54 notebook_id = self.get_argument('notebook', default=None)
60 notebook_id = self.get_argument('notebook', default=None)
55 kernel_id = rkm.start_kernel(notebook_id)
61 kernel_id = rkm.start_kernel(notebook_id)
56 self.set_header('Location', '/'+kernel_id)
62 self.set_header('Location', '/'+kernel_id)
57 self.finish(json.dumps(kernel_id))
63 self.finish(json.dumps(kernel_id))
58
64
59
65
60 class KernelHandler(web.RequestHandler):
66 class KernelHandler(web.RequestHandler):
61
67
62 SUPPORTED_METHODS = ('DELETE')
68 SUPPORTED_METHODS = ('DELETE')
63
69
64 def delete(self, kernel_id):
70 def delete(self, kernel_id):
65 rkm = self.application.routing_kernel_manager
71 rkm = self.application.routing_kernel_manager
66 rkm.kill_kernel(kernel_id)
72 rkm.kill_kernel(kernel_id)
67 self.set_status(204)
73 self.set_status(204)
68 self.finish()
74 self.finish()
69
75
70
76
71 class KernelActionHandler(web.RequestHandler):
77 class KernelActionHandler(web.RequestHandler):
72
78
73 def post(self, kernel_id, action):
79 def post(self, kernel_id, action):
74 rkm = self.application.routing_kernel_manager
80 rkm = self.application.routing_kernel_manager
75 if action == 'interrupt':
81 if action == 'interrupt':
76 rkm.interrupt_kernel(kernel_id)
82 rkm.interrupt_kernel(kernel_id)
77 self.set_status(204)
83 self.set_status(204)
78 if action == 'restart':
84 if action == 'restart':
79 new_kernel_id = rkm.restart_kernel(kernel_id)
85 new_kernel_id = rkm.restart_kernel(kernel_id)
80 self.write(json.dumps(new_kernel_id))
86 self.write(json.dumps(new_kernel_id))
81 self.finish()
87 self.finish()
82
88
83
89
84 class ZMQStreamHandler(websocket.WebSocketHandler):
90 class ZMQStreamHandler(websocket.WebSocketHandler):
85
91
86 def initialize(self, stream_name):
92 def initialize(self, stream_name):
87 self.stream_name = stream_name
93 self.stream_name = stream_name
88
94
89 def open(self, kernel_id):
95 def open(self, kernel_id):
90 rkm = self.application.routing_kernel_manager
96 rkm = self.application.routing_kernel_manager
91 self.router = rkm.get_router(kernel_id, self.stream_name)
97 self.router = rkm.get_router(kernel_id, self.stream_name)
92 self.client_id = self.router.register_client(self)
98 self.client_id = self.router.register_client(self)
93
99
94 def on_message(self, msg):
100 def on_message(self, msg):
95 self.router.forward_msg(self.client_id, msg)
101 self.router.forward_msg(self.client_id, msg)
96
102
97 def on_close(self):
103 def on_close(self):
98 self.router.unregister_client(self.client_id)
104 self.router.unregister_client(self.client_id)
99
105
100
106
101 #-----------------------------------------------------------------------------
107 #-----------------------------------------------------------------------------
102 # Notebook web service handlers
108 # Notebook web service handlers
103 #-----------------------------------------------------------------------------
109 #-----------------------------------------------------------------------------
104
110
105 class NotebookRootHandler(web.RequestHandler):
111 class NotebookRootHandler(web.RequestHandler):
106
112
107 def get(self):
113 def get(self):
108 nbm = self.application.notebook_manager
114 nbm = self.application.notebook_manager
109 files = nbm.list_notebooks()
115 files = nbm.list_notebooks()
110 self.finish(json.dumps(files))
116 self.finish(json.dumps(files))
111
117
112 def post(self):
118 def post(self):
113 nbm = self.application.notebook_manager
119 nbm = self.application.notebook_manager
114 body = self.request.body.strip()
120 body = self.request.body.strip()
115 format = self.get_argument('format', default='json')
121 format = self.get_argument('format', default='json')
116 name = self.get_argument('name', default=None)
122 name = self.get_argument('name', default=None)
117 if body:
123 if body:
118 notebook_id = nbm.save_new_notebook(body, name=name, format=format)
124 notebook_id = nbm.save_new_notebook(body, name=name, format=format)
119 else:
125 else:
120 notebook_id = nbm.new_notebook()
126 notebook_id = nbm.new_notebook()
121 self.set_header('Location', '/'+notebook_id)
127 self.set_header('Location', '/'+notebook_id)
122 self.finish(json.dumps(notebook_id))
128 self.finish(json.dumps(notebook_id))
123
129
124
130
125 class NotebookHandler(web.RequestHandler):
131 class NotebookHandler(web.RequestHandler):
126
132
127 SUPPORTED_METHODS = ('GET', 'PUT', 'DELETE')
133 SUPPORTED_METHODS = ('GET', 'PUT', 'DELETE')
128
134
129 def get(self, notebook_id):
135 def get(self, notebook_id):
130 nbm = self.application.notebook_manager
136 nbm = self.application.notebook_manager
131 format = self.get_argument('format', default='json')
137 format = self.get_argument('format', default='json')
132 last_mod, name, data = nbm.get_notebook(notebook_id, format)
138 last_mod, name, data = nbm.get_notebook(notebook_id, format)
133 if format == u'json':
139 if format == u'json':
134 self.set_header('Content-Type', 'application/json')
140 self.set_header('Content-Type', 'application/json')
135 self.set_header('Content-Disposition','attachment; filename=%s.json' % name)
141 self.set_header('Content-Disposition','attachment; filename=%s.json' % name)
136 elif format == u'xml':
142 elif format == u'xml':
137 self.set_header('Content-Type', 'application/xml')
143 self.set_header('Content-Type', 'application/xml')
138 self.set_header('Content-Disposition','attachment; filename=%s.ipynb' % name)
144 self.set_header('Content-Disposition','attachment; filename=%s.ipynb' % name)
139 elif format == u'py':
145 elif format == u'py':
140 self.set_header('Content-Type', 'application/x-python')
146 self.set_header('Content-Type', 'application/x-python')
141 self.set_header('Content-Disposition','attachment; filename=%s.py' % name)
147 self.set_header('Content-Disposition','attachment; filename=%s.py' % name)
142 self.set_header('Last-Modified', last_mod)
148 self.set_header('Last-Modified', last_mod)
143 self.finish(data)
149 self.finish(data)
144
150
145 def put(self, notebook_id):
151 def put(self, notebook_id):
146 nbm = self.application.notebook_manager
152 nbm = self.application.notebook_manager
147 format = self.get_argument('format', default='json')
153 format = self.get_argument('format', default='json')
148 name = self.get_argument('name', default=None)
154 name = self.get_argument('name', default=None)
149 nbm.save_notebook(notebook_id, self.request.body, name=name, format=format)
155 nbm.save_notebook(notebook_id, self.request.body, name=name, format=format)
150 self.set_status(204)
156 self.set_status(204)
151 self.finish()
157 self.finish()
152
158
153 def delete(self, notebook_id):
159 def delete(self, notebook_id):
154 nbm = self.application.notebook_manager
160 nbm = self.application.notebook_manager
155 nbm.delete_notebook(notebook_id)
161 nbm.delete_notebook(notebook_id)
156 self.set_status(204)
162 self.set_status(204)
157 self.finish()
163 self.finish()
158
164
165 #-----------------------------------------------------------------------------
166 # RST web service handlers
167 #-----------------------------------------------------------------------------
168
169 _rst_header = """========
170 Heading1
171 ========
172
173 Heading2
174 ========
175
176 Heading3
177 --------
178
179 Heading4
180 ^^^^^^^^
181
182 """
183
184 class RSTHandler(web.RequestHandler):
185
186 def post(self):
187 if publish_string is None:
188 raise web.HTTPError(503)
189 body = self.request.body.strip()
190 source = _rst_header + body
191 template_path=os.path.join(os.path.dirname(__file__), u'templates', u'rst_template.html')
192 print template_path
193 defaults = {'file_insertion_enabled': 0,
194 'raw_enabled': 0,
195 '_disable_config': 1,
196 'stylesheet_path': 0,
197 'initial_header_level': 3,
198 'template': template_path
199 }
200 try:
201 html = publish_string(source, writer_name='html',
202 settings_overrides=defaults
203 )
204 except:
205 raise web.HTTPError(400)
206 print html
207 # html = '\n'.join(html.split('\n')[7:-3])
208 # print html
209 self.set_header('Content-Type', 'text/html')
210 self.finish(html)
211
212
@@ -1,203 +1,204 b''
1 """A tornado based IPython notebook server."""
1 """A tornado based IPython notebook server."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2011 The IPython Development Team
4 # Copyright (C) 2011 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING.txt, distributed as part of this software.
7 # the file COPYING.txt, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 import logging
14 import logging
15 import os
15 import os
16 import signal
16 import signal
17 import sys
17 import sys
18
18
19 import zmq
19 import zmq
20
20
21 # Install the pyzmq ioloop. This has to be done before anything else from
21 # Install the pyzmq ioloop. This has to be done before anything else from
22 # tornado is imported.
22 # tornado is imported.
23 from zmq.eventloop import ioloop
23 from zmq.eventloop import ioloop
24 import tornado.ioloop
24 import tornado.ioloop
25 tornado.ioloop = ioloop
25 tornado.ioloop = ioloop
26
26
27 from tornado import httpserver
27 from tornado import httpserver
28 from tornado import web
28 from tornado import web
29
29
30 from .kernelmanager import KernelManager, RoutingKernelManager
30 from .kernelmanager import KernelManager, RoutingKernelManager
31 from .sessionmanager import SessionManager
31 from .sessionmanager import SessionManager
32 from .handlers import (
32 from .handlers import (
33 NBBrowserHandler, NewHandler, NamedNotebookHandler,
33 NBBrowserHandler, NewHandler, NamedNotebookHandler,
34 MainKernelHandler, KernelHandler, KernelActionHandler, ZMQStreamHandler,
34 MainKernelHandler, KernelHandler, KernelActionHandler, ZMQStreamHandler,
35 NotebookRootHandler, NotebookHandler
35 NotebookRootHandler, NotebookHandler, RSTHandler
36 )
36 )
37 from .notebookmanager import NotebookManager
37 from .notebookmanager import NotebookManager
38
38
39 from IPython.core.application import BaseIPythonApplication
39 from IPython.core.application import BaseIPythonApplication
40 from IPython.core.profiledir import ProfileDir
40 from IPython.core.profiledir import ProfileDir
41 from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
41 from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
42 from IPython.zmq.session import Session
42 from IPython.zmq.session import Session
43 from IPython.zmq.zmqshell import ZMQInteractiveShell
43 from IPython.zmq.zmqshell import ZMQInteractiveShell
44 from IPython.zmq.ipkernel import (
44 from IPython.zmq.ipkernel import (
45 flags as ipkernel_flags,
45 flags as ipkernel_flags,
46 aliases as ipkernel_aliases,
46 aliases as ipkernel_aliases,
47 IPKernelApp
47 IPKernelApp
48 )
48 )
49 from IPython.utils.traitlets import Dict, Unicode, Int, Any, List, Enum
49 from IPython.utils.traitlets import Dict, Unicode, Int, Any, List, Enum
50
50
51 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
52 # Module globals
52 # Module globals
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54
54
55 _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
55 _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
56 _kernel_action_regex = r"(?P<action>restart|interrupt)"
56 _kernel_action_regex = r"(?P<action>restart|interrupt)"
57 _notebook_id_regex = r"(?P<notebook_id>\w+-\w+-\w+-\w+-\w+)"
57 _notebook_id_regex = r"(?P<notebook_id>\w+-\w+-\w+-\w+-\w+)"
58
58
59 LOCALHOST = '127.0.0.1'
59 LOCALHOST = '127.0.0.1'
60
60
61 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
62 # The Tornado web application
62 # The Tornado web application
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64
64
65 class NotebookWebApplication(web.Application):
65 class NotebookWebApplication(web.Application):
66
66
67 def __init__(self, routing_kernel_manager, notebook_manager, log):
67 def __init__(self, routing_kernel_manager, notebook_manager, log):
68 handlers = [
68 handlers = [
69 (r"/", NBBrowserHandler),
69 (r"/", NBBrowserHandler),
70 (r"/new", NewHandler),
70 (r"/new", NewHandler),
71 (r"/%s" % _notebook_id_regex, NamedNotebookHandler),
71 (r"/%s" % _notebook_id_regex, NamedNotebookHandler),
72 (r"/kernels", MainKernelHandler),
72 (r"/kernels", MainKernelHandler),
73 (r"/kernels/%s" % _kernel_id_regex, KernelHandler),
73 (r"/kernels/%s" % _kernel_id_regex, KernelHandler),
74 (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler),
74 (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler),
75 (r"/kernels/%s/iopub" % _kernel_id_regex, ZMQStreamHandler, dict(stream_name='iopub')),
75 (r"/kernels/%s/iopub" % _kernel_id_regex, ZMQStreamHandler, dict(stream_name='iopub')),
76 (r"/kernels/%s/shell" % _kernel_id_regex, ZMQStreamHandler, dict(stream_name='shell')),
76 (r"/kernels/%s/shell" % _kernel_id_regex, ZMQStreamHandler, dict(stream_name='shell')),
77 (r"/notebooks", NotebookRootHandler),
77 (r"/notebooks", NotebookRootHandler),
78 (r"/notebooks/%s" % _notebook_id_regex, NotebookHandler)
78 (r"/notebooks/%s" % _notebook_id_regex, NotebookHandler),
79 (r"/rstservice/render", RSTHandler)
79 ]
80 ]
80 settings = dict(
81 settings = dict(
81 template_path=os.path.join(os.path.dirname(__file__), "templates"),
82 template_path=os.path.join(os.path.dirname(__file__), "templates"),
82 static_path=os.path.join(os.path.dirname(__file__), "static"),
83 static_path=os.path.join(os.path.dirname(__file__), "static"),
83 )
84 )
84 web.Application.__init__(self, handlers, **settings)
85 web.Application.__init__(self, handlers, **settings)
85
86
86 self.routing_kernel_manager = routing_kernel_manager
87 self.routing_kernel_manager = routing_kernel_manager
87 self.log = log
88 self.log = log
88 self.notebook_manager = notebook_manager
89 self.notebook_manager = notebook_manager
89
90
90
91
91 #-----------------------------------------------------------------------------
92 #-----------------------------------------------------------------------------
92 # Aliases and Flags
93 # Aliases and Flags
93 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
94
95
95 flags = dict(ipkernel_flags)
96 flags = dict(ipkernel_flags)
96
97
97 # the flags that are specific to the frontend
98 # the flags that are specific to the frontend
98 # these must be scrubbed before being passed to the kernel,
99 # these must be scrubbed before being passed to the kernel,
99 # or it will raise an error on unrecognized flags
100 # or it will raise an error on unrecognized flags
100 notebook_flags = []
101 notebook_flags = []
101
102
102 aliases = dict(ipkernel_aliases)
103 aliases = dict(ipkernel_aliases)
103
104
104 aliases.update(dict(
105 aliases.update(dict(
105 ip = 'IPythonNotebookApp.ip',
106 ip = 'IPythonNotebookApp.ip',
106 port = 'IPythonNotebookApp.port',
107 port = 'IPythonNotebookApp.port',
107 colors = 'ZMQInteractiveShell.colors',
108 colors = 'ZMQInteractiveShell.colors',
108 editor = 'RichIPythonWidget.editor',
109 editor = 'RichIPythonWidget.editor',
109 ))
110 ))
110
111
111 #-----------------------------------------------------------------------------
112 #-----------------------------------------------------------------------------
112 # IPythonNotebookApp
113 # IPythonNotebookApp
113 #-----------------------------------------------------------------------------
114 #-----------------------------------------------------------------------------
114
115
115 class IPythonNotebookApp(BaseIPythonApplication):
116 class IPythonNotebookApp(BaseIPythonApplication):
116 name = 'ipython-notebook'
117 name = 'ipython-notebook'
117 default_config_file_name='ipython_notebook_config.py'
118 default_config_file_name='ipython_notebook_config.py'
118
119
119 description = """
120 description = """
120 The IPython HTML Notebook.
121 The IPython HTML Notebook.
121
122
122 This launches a Tornado based HTML Notebook Server that serves up an
123 This launches a Tornado based HTML Notebook Server that serves up an
123 HTML5/Javascript Notebook client.
124 HTML5/Javascript Notebook client.
124 """
125 """
125
126
126 classes = [IPKernelApp, ZMQInteractiveShell, ProfileDir, Session,
127 classes = [IPKernelApp, ZMQInteractiveShell, ProfileDir, Session,
127 RoutingKernelManager, NotebookManager,
128 RoutingKernelManager, NotebookManager,
128 KernelManager, SessionManager, RichIPythonWidget]
129 KernelManager, SessionManager, RichIPythonWidget]
129 flags = Dict(flags)
130 flags = Dict(flags)
130 aliases = Dict(aliases)
131 aliases = Dict(aliases)
131
132
132 kernel_argv = List(Unicode)
133 kernel_argv = List(Unicode)
133
134
134 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
135 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
135 default_value=logging.INFO,
136 default_value=logging.INFO,
136 config=True,
137 config=True,
137 help="Set the log level by value or name.")
138 help="Set the log level by value or name.")
138
139
139 # connection info:
140 # connection info:
140 ip = Unicode(LOCALHOST, config=True,
141 ip = Unicode(LOCALHOST, config=True,
141 help="The IP address the notebook server will listen on."
142 help="The IP address the notebook server will listen on."
142 )
143 )
143
144
144 port = Int(8888, config=True,
145 port = Int(8888, config=True,
145 help="The port the notebook server will listen on."
146 help="The port the notebook server will listen on."
146 )
147 )
147
148
148 # the factory for creating a widget
149 # the factory for creating a widget
149 widget_factory = Any(RichIPythonWidget)
150 widget_factory = Any(RichIPythonWidget)
150
151
151 def parse_command_line(self, argv=None):
152 def parse_command_line(self, argv=None):
152 super(IPythonNotebookApp, self).parse_command_line(argv)
153 super(IPythonNotebookApp, self).parse_command_line(argv)
153 if argv is None:
154 if argv is None:
154 argv = sys.argv[1:]
155 argv = sys.argv[1:]
155
156
156 self.kernel_argv = list(argv) # copy
157 self.kernel_argv = list(argv) # copy
157 # kernel should inherit default config file from frontend
158 # kernel should inherit default config file from frontend
158 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
159 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
159 # scrub frontend-specific flags
160 # scrub frontend-specific flags
160 for a in argv:
161 for a in argv:
161 if a.startswith('-') and a.lstrip('-') in notebook_flags:
162 if a.startswith('-') and a.lstrip('-') in notebook_flags:
162 self.kernel_argv.remove(a)
163 self.kernel_argv.remove(a)
163
164
164 def init_configurables(self):
165 def init_configurables(self):
165 # Don't let Qt or ZMQ swallow KeyboardInterupts.
166 # Don't let Qt or ZMQ swallow KeyboardInterupts.
166 signal.signal(signal.SIGINT, signal.SIG_DFL)
167 signal.signal(signal.SIGINT, signal.SIG_DFL)
167
168
168 # Create a KernelManager and start a kernel.
169 # Create a KernelManager and start a kernel.
169 self.kernel_manager = KernelManager(config=self.config, log=self.log)
170 self.kernel_manager = KernelManager(config=self.config, log=self.log)
170 self.routing_kernel_manager = RoutingKernelManager(config=self.config, log=self.log,
171 self.routing_kernel_manager = RoutingKernelManager(config=self.config, log=self.log,
171 kernel_manager=self.kernel_manager, kernel_argv=self.kernel_argv
172 kernel_manager=self.kernel_manager, kernel_argv=self.kernel_argv
172 )
173 )
173 self.notebook_manager = NotebookManager(config=self.config, log=self.log)
174 self.notebook_manager = NotebookManager(config=self.config, log=self.log)
174
175
175 def init_logging(self):
176 def init_logging(self):
176 super(IPythonNotebookApp, self).init_logging()
177 super(IPythonNotebookApp, self).init_logging()
177 # This prevents double log messages because tornado use a root logger that
178 # This prevents double log messages because tornado use a root logger that
178 # self.log is a child of. The logging module dipatches log messages to a log
179 # self.log is a child of. The logging module dipatches log messages to a log
179 # and all of its ancenstors until propagate is set to False.
180 # and all of its ancenstors until propagate is set to False.
180 self.log.propagate = False
181 self.log.propagate = False
181
182
182 def initialize(self, argv=None):
183 def initialize(self, argv=None):
183 super(IPythonNotebookApp, self).initialize(argv)
184 super(IPythonNotebookApp, self).initialize(argv)
184 self.init_configurables()
185 self.init_configurables()
185 self.web_app = NotebookWebApplication(
186 self.web_app = NotebookWebApplication(
186 self.routing_kernel_manager, self.notebook_manager, self.log
187 self.routing_kernel_manager, self.notebook_manager, self.log
187 )
188 )
188 self.http_server = httpserver.HTTPServer(self.web_app)
189 self.http_server = httpserver.HTTPServer(self.web_app)
189 self.http_server.listen(self.port)
190 self.http_server.listen(self.port)
190
191
191 def start(self):
192 def start(self):
192 self.log.info("The IPython Notebook is running at: http://%s:%i" % (self.ip, self.port))
193 self.log.info("The IPython Notebook is running at: http://%s:%i" % (self.ip, self.port))
193 ioloop.IOLoop.instance().start()
194 ioloop.IOLoop.instance().start()
194
195
195 #-----------------------------------------------------------------------------
196 #-----------------------------------------------------------------------------
196 # Main entry point
197 # Main entry point
197 #-----------------------------------------------------------------------------
198 #-----------------------------------------------------------------------------
198
199
199 def launch_new_instance():
200 def launch_new_instance():
200 app = IPythonNotebookApp()
201 app = IPythonNotebookApp()
201 app.initialize()
202 app.initialize()
202 app.start()
203 app.start()
203
204
@@ -1,286 +1,303 b''
1
1
2 /**
2 /**
3 * Primary styles
3 * Primary styles
4 *
4 *
5 * Author: IPython Development Team
5 * Author: IPython Development Team
6 */
6 */
7
7
8
8
9 body {
9 body {
10 background-color: white;
10 background-color: white;
11 /* This makes sure that the body covers the entire window and needs to
11 /* This makes sure that the body covers the entire window and needs to
12 be in a different element than the display: box in wrapper below */
12 be in a different element than the display: box in wrapper below */
13 position: absolute;
13 position: absolute;
14 left: 0px;
14 left: 0px;
15 right: 0px;
15 right: 0px;
16 top: 0px;
16 top: 0px;
17 bottom: 0px;
17 bottom: 0px;
18 overflow: hidden;
18 overflow: hidden;
19 }
19 }
20
20
21 span#save_widget {
21 span#save_widget {
22 position: absolute;
22 position: absolute;
23 left: 0px;
23 left: 0px;
24 padding: 5px 0px;
24 padding: 5px 0px;
25 margin: 0px 0px 0px 0px;
25 margin: 0px 0px 0px 0px;
26 }
26 }
27
27
28 input#notebook_name {
28 input#notebook_name {
29 height: 1em;
29 height: 1em;
30 line-height: 1em;
30 line-height: 1em;
31 padding: 5px;
31 padding: 5px;
32 }
32 }
33
33
34 span#kernel_status {
34 span#kernel_status {
35 position: absolute;
35 position: absolute;
36 padding: 8px 5px 5px 5px;
36 padding: 8px 5px 5px 5px;
37 right: 10px;
37 right: 10px;
38 font-weight: bold;
38 font-weight: bold;
39 }
39 }
40
40
41 .status_idle {
41 .status_idle {
42 color: gray;
42 color: gray;
43 }
43 }
44
44
45 .status_busy {
45 .status_busy {
46 color: red;
46 color: red;
47 }
47 }
48
48
49 .status_restarting {
49 .status_restarting {
50 color: black;
50 color: black;
51 }
51 }
52
52
53 div#left_panel {
53 div#left_panel {
54 overflow-y: auto;
54 overflow-y: auto;
55 top: 0px;
55 top: 0px;
56 left: 0px;
56 left: 0px;
57 margin: 0px;
57 margin: 0px;
58 padding: 0px;
58 padding: 0px;
59 position: absolute;
59 position: absolute;
60 }
60 }
61
61
62 h3.section_header {
62 h3.section_header {
63 padding: 5px;
63 padding: 5px;
64 }
64 }
65
65
66 div.section_content {
66 div.section_content {
67 padding: 5px;
67 padding: 5px;
68 }
68 }
69
69
70
70
71 span.section_row_buttons > button {
71 span.section_row_buttons > button {
72 width: 60px;
72 width: 60px;
73 }
73 }
74
74
75 .section_row {
75 .section_row {
76 margin: 5px 0px;
76 margin: 5px 0px;
77 }
77 }
78
78
79 .section_row_buttons {
79 .section_row_buttons {
80 float: right;
80 float: right;
81 }
81 }
82
82
83 #kernel_persist {
83 #kernel_persist {
84 float: right;
84 float: right;
85 }
85 }
86
86
87 .checkbox_label {
87 .checkbox_label {
88 font-size: 85%;
88 font-size: 85%;
89 float: right;
89 float: right;
90 padding: 0.3em;
90 padding: 0.3em;
91 }
91 }
92
92
93 .section_row_header {
93 .section_row_header {
94 float: left;
94 float: left;
95 font-size: 85%;
95 font-size: 85%;
96 padding: 0.4em 0em;
96 padding: 0.4em 0em;
97 font-weight: bold;
97 font-weight: bold;
98 }
98 }
99
99
100 span.button_label {
100 span.button_label {
101 padding: 0.2em 1em;
101 padding: 0.2em 1em;
102 font-size: 77%;
102 font-size: 77%;
103 float: right;
103 float: right;
104 }
104 }
105
105
106 /* This is needed because FF was adding a 2px margin top and bottom. */
106 /* This is needed because FF was adding a 2px margin top and bottom. */
107 .section_row .ui-button {
107 .section_row .ui-button {
108 margin-top: 0px;
108 margin-top: 0px;
109 margin-bottom: 0px;
109 margin-bottom: 0px;
110 }
110 }
111
111
112 #download_format {
112 #download_format {
113 float: right;
113 float: right;
114 font-size: 85%;
114 font-size: 85%;
115 width: 60px;
115 width: 60px;
116 margin: 1px 5px;
116 margin: 1px 5px;
117 }
117 }
118
118
119 div#left_panel_splitter {
119 div#left_panel_splitter {
120 width: 8px;
120 width: 8px;
121 top: 0px;
121 top: 0px;
122 left: 202px;
122 left: 202px;
123 margin: 0px;
123 margin: 0px;
124 padding: 0px;
124 padding: 0px;
125 position: absolute;
125 position: absolute;
126 }
126 }
127
127
128 div#notebook_panel {
128 div#notebook_panel {
129 /* The L margin will be set in the Javascript code*/
129 /* The L margin will be set in the Javascript code*/
130 margin: 0px 0px 0px 0px;
130 margin: 0px 0px 0px 0px;
131 padding: 0px;
131 padding: 0px;
132 }
132 }
133
133
134 div#notebook {
134 div#notebook {
135 overflow-y: scroll;
135 overflow-y: scroll;
136 overflow-x: auto;
136 overflow-x: auto;
137 width: 100%;
137 width: 100%;
138 padding: 0px 15px 0px 15px;
138 padding: 0px 15px 0px 15px;
139 margin: 0px
139 margin: 0px
140 background-color: white;
140 background-color: white;
141 }
141 }
142
142
143 div#pager_splitter {
143 div#pager_splitter {
144 height: 8px;
144 height: 8px;
145 }
145 }
146
146
147 div#pager {
147 div#pager {
148 padding: 15px;
148 padding: 15px;
149 overflow: auto;
149 overflow: auto;
150 }
150 }
151
151
152 div.cell {
152 div.cell {
153 width: 100%;
153 width: 100%;
154 padding: 5px;
154 padding: 5px;
155 /* This acts as a spacer between cells, that is outside the border */
155 /* This acts as a spacer between cells, that is outside the border */
156 margin: 15px 0px 15px 0px;
156 margin: 15px 0px 15px 0px;
157 }
157 }
158
158
159 div.code_cell {
159 div.code_cell {
160 background-color: white;
160 background-color: white;
161 }
161 }
162
162
163 div.prompt {
163 div.prompt {
164 width: 80px;
164 width: 80px;
165 padding: 0.4em;
165 padding: 0.4em;
166 margin: 0px;
166 margin: 0px;
167 font-family: monospace;
167 font-family: monospace;
168 }
168 }
169
169
170 div.input_prompt {
170 div.input_prompt {
171 color: navy;
171 color: navy;
172 }
172 }
173
173
174 div.output {
174 div.output {
175 /* This is a spacer between the input and output of each cell */
175 /* This is a spacer between the input and output of each cell */
176 margin-top: 15px;
176 margin-top: 15px;
177 }
177 }
178
178
179 div.output_prompt {
179 div.output_prompt {
180 color: darkred;
180 color: darkred;
181 }
181 }
182
182
183 div.input_area {
183 div.input_area {
184 color: black;
184 color: black;
185 }
185 }
186
186
187 div.output_area {
187 div.output_area {
188 text-align: left;
188 text-align: left;
189 color: black;
189 color: black;
190 font-family: monospace;
190 font-family: monospace;
191 }
191 }
192
192
193 div.output_stream {
193 div.output_stream {
194 padding: 0.4em;
194 padding: 0.4em;
195 }
195 }
196
196
197 div.output_latex {
197 div.output_latex {
198 /* Slightly bigger than the rest of the notebook */
198 /* Slightly bigger than the rest of the notebook */
199 font-size: 116%;
199 font-size: 116%;
200 }
200 }
201
201
202 div.output_html {
202 div.output_html {
203 }
203 }
204
204
205 div.output_png {
205 div.output_png {
206 }
206 }
207
207
208 div.html_cell {
208 div.html_cell {
209 background-color: white;
209 background-color: white;
210 }
210 }
211
211
212 div.html_cell_input {
212 div.html_cell_input {
213 color: black;
213 color: black;
214 }
214 }
215
215
216 div.html_cell_render {
216 div.html_cell_render {
217 font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
217 font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
218 /* Slightly bigger than the rest of the notebook */
218 /* Slightly bigger than the rest of the notebook */
219 font-size: 116%;
219 font-size: 116%;
220 outline: none;
220 outline: none;
221 resize: none;
221 resize: none;
222 width: inherit;
222 width: inherit;
223 border-style: none;
223 border-style: none;
224 padding: 5px;
224 padding: 5px;
225 color: black;
225 color: black;
226 }
226 }
227
227
228 div.html_cell_render em {font-style: italic;}
228 div.rst_cell_input {
229 div.html_cell_render strong {font-weight: bold;}
229 color: black;
230 div.html_cell_render u {text-decoration: underline;}
230 }
231 div.html_cell_render :link { text-decoration: underline }
231
232 div.html_cell_render :visited { text-decoration: underline }
232 div.rst_cell_render {
233 div.html_cell_render h1 {font-size: 197%; margin: .67em 0; font-weight: bold;}
233 font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
234 div.html_cell_render h2 {font-size: 153.9%; margin: .75em 0; font-weight: bold;}
234 /* Slightly bigger than the rest of the notebook */
235 div.html_cell_render h3 {font-size: 116%; margin: .83em 0; font-weight: bold;}
235 font-size: 116%;
236 div.html_cell_render h4 {margin: 1.12em 0; font-weight: bold;}
236 outline: none;
237 div.html_cell_render h5 {font-size: 85%.; margin: 1.5em 0; font-weight: bold;}
237 resize: none;
238 div.html_cell_render h6 {font-size: 77%; margin: 1.67em 0; font-weight: bold;}
238 width: inherit;
239 div.html_cell_render ul {list-style:disc; margin-left: 40px;}
239 border-style: none;
240 div.html_cell_render ul ul {list-style:square; margin-left: 40px;}
240 padding: 5px;
241 div.html_cell_render ul ul ul {list-style:circle; margin-left: 40px;}
241 color: black;
242 div.html_cell_render ol {list-style:upper-roman; margin-left: 40px;}
242 }
243 div.html_cell_render ol ol {list-style:upper-alpha;}
243
244 div.html_cell_render ol ol ol {list-style:decimal;}
244 .rendered_html {color: black;}
245 div.html_cell_render ol ol ol ol {list-style:lower-alpha;}
245 .rendered_html em {font-style: italic;}
246 div.html_cell_render ol ol ol ol ol {list-style:lower-roman;}
246 .rendered_html strong {font-weight: bold;}
247 .rendered_html u {text-decoration: underline;}
248 .rendered_html :link { text-decoration: underline }
249 .rendered_html :visited { text-decoration: underline }
250 .rendered_html h1 {font-size: 197%; margin: .67em 0; font-weight: bold;}
251 .rendered_html h2 {font-size: 153.9%; margin: .75em 0; font-weight: bold;}
252 .rendered_html h3 {font-size: 116%; margin: .83em 0; font-weight: bold;}
253 .rendered_html h4 {margin: 1.12em 0; font-weight: bold;}
254 .rendered_html h5 {font-size: 85%.; margin: 1.5em 0; font-weight: bold;}
255 .rendered_html h6 {font-size: 77%; margin: 1.67em 0; font-weight: bold;}
256 .rendered_html ul {list-style:disc; margin-left: 40px;}
257 .rendered_html ul ul {list-style:square; margin-left: 40px;}
258 .rendered_html ul ul ul {list-style:circle; margin-left: 40px;}
259 .rendered_html ol {list-style:upper-roman; margin-left: 40px;}
260 .rendered_html ol ol {list-style:upper-alpha;}
261 .rendered_html ol ol ol {list-style:decimal;}
262 .rendered_html ol ol ol ol {list-style:lower-alpha;}
263 .rendered_html ol ol ol ol ol {list-style:lower-roman;}
247
264
248 .CodeMirror {
265 .CodeMirror {
249 line-height: 1.231; /* Changed from 1em to our global default */
266 line-height: 1.231; /* Changed from 1em to our global default */
250 }
267 }
251
268
252 .CodeMirror-scroll {
269 .CodeMirror-scroll {
253 height: auto; /* Changed to auto to autogrow */
270 height: auto; /* Changed to auto to autogrow */
254 overflow-y: visible; /* Changed from auto to remove scrollbar */
271 overflow-y: visible; /* Changed from auto to remove scrollbar */
255 overflow-x: auto; /* Changed from auto to remove scrollbar */
272 overflow-x: auto; /* Changed from auto to remove scrollbar */
256 }
273 }
257
274
258 /* CSS font colors for translated ANSI colors. */
275 /* CSS font colors for translated ANSI colors. */
259
276
260
277
261 .ansiblack {color: black;}
278 .ansiblack {color: black;}
262 .ansired {color: darkred;}
279 .ansired {color: darkred;}
263 .ansigreen {color: darkgreen;}
280 .ansigreen {color: darkgreen;}
264 .ansiyellow {color: brown;}
281 .ansiyellow {color: brown;}
265 .ansiblue {color: darkblue;}
282 .ansiblue {color: darkblue;}
266 .ansipurple {color: darkviolet;}
283 .ansipurple {color: darkviolet;}
267 .ansicyan {color: steelblue;}
284 .ansicyan {color: steelblue;}
268 .ansigrey {color: grey;}
285 .ansigrey {color: grey;}
269 .ansibold {font-weight: bold;}
286 .ansibold {font-weight: bold;}
270
287
271 .completions {
288 .completions {
272 position: absolute;
289 position: absolute;
273 z-index: 10;
290 z-index: 10;
274 overflow: auto;
291 overflow: auto;
275 border: 1px solid black;
292 border: 1px solid black;
276 }
293 }
277
294
278 .completions select {
295 .completions select {
279 background: white;
296 background: white;
280 outline: none;
297 outline: none;
281 border: none;
298 border: none;
282 padding: 0px;
299 padding: 0px;
283 margin: 0px;
300 margin: 0px;
284 font-family: monospace;
301 font-family: monospace;
285 }
302 }
286
303
@@ -1,155 +1,156 b''
1
1
2 //============================================================================
2 //============================================================================
3 // HTMLCell
3 // HTMLCell
4 //============================================================================
4 //============================================================================
5
5
6 var IPython = (function (IPython) {
6 var IPython = (function (IPython) {
7
7
8 var HTMLCell = function (notebook) {
8 var HTMLCell = function (notebook) {
9 IPython.Cell.apply(this, arguments);
9 IPython.Cell.apply(this, arguments);
10 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$"
10 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$"
11 this.rendered = false;
11 this.rendered = false;
12 };
12 };
13
13
14
14
15 HTMLCell.prototype = new IPython.Cell();
15 HTMLCell.prototype = new IPython.Cell();
16
16
17
17
18
18
19 HTMLCell.prototype.create_element = function () {
19 HTMLCell.prototype.create_element = function () {
20 var cell = $("<div>").addClass('cell html_cell border-box-sizing');
20 var cell = $("<div>").addClass('cell html_cell border-box-sizing');
21 var input_area = $('<div/>').addClass('html_cell_input');
21 var input_area = $('<div/>').addClass('html_cell_input');
22 this.code_mirror = CodeMirror(input_area.get(0), {
22 this.code_mirror = CodeMirror(input_area.get(0), {
23 indentUnit : 4,
23 indentUnit : 4,
24 enterMode : 'flat',
24 enterMode : 'flat',
25 tabMode: 'shift',
25 tabMode: 'shift',
26 mode: 'htmlmixed',
26 mode: 'htmlmixed',
27 theme: 'default',
27 theme: 'default',
28 value: this.placeholder
28 value: this.placeholder
29 });
29 });
30 // The tabindex=-1 makes this div focusable.
30 // The tabindex=-1 makes this div focusable.
31 var render_area = $('<div/>').addClass('html_cell_render').attr('tabindex','-1');
31 var render_area = $('<div/>').addClass('html_cell_render').
32 addClass('rendered_html').attr('tabindex','-1');
32 cell.append(input_area).append(render_area);
33 cell.append(input_area).append(render_area);
33 this.element = cell;
34 this.element = cell;
34 };
35 };
35
36
36
37
37 HTMLCell.prototype.bind_events = function () {
38 HTMLCell.prototype.bind_events = function () {
38 IPython.Cell.prototype.bind_events.apply(this);
39 IPython.Cell.prototype.bind_events.apply(this);
39 var that = this;
40 var that = this;
40 this.element.keydown(function (event) {
41 this.element.keydown(function (event) {
41 if (event.which === 13) {
42 if (event.which === 13) {
42 if (that.rendered) {
43 if (that.rendered) {
43 that.edit();
44 that.edit();
44 event.preventDefault();
45 event.preventDefault();
45 };
46 };
46 };
47 };
47 });
48 });
48 };
49 };
49
50
50
51
51 HTMLCell.prototype.select = function () {
52 HTMLCell.prototype.select = function () {
52 IPython.Cell.prototype.select.apply(this);
53 IPython.Cell.prototype.select.apply(this);
53 var output = this.element.find("div.html_cell_render");
54 var output = this.element.find("div.html_cell_render");
54 output.trigger('focus');
55 output.trigger('focus');
55 };
56 };
56
57
57
58
58 HTMLCell.prototype.edit = function () {
59 HTMLCell.prototype.edit = function () {
59 if (this.rendered === true) {
60 if (this.rendered === true) {
60 var html_cell = this.element;
61 var html_cell = this.element;
61 var output = html_cell.find("div.html_cell_render");
62 var output = html_cell.find("div.html_cell_render");
62 output.hide();
63 output.hide();
63 html_cell.find('div.html_cell_input').show();
64 html_cell.find('div.html_cell_input').show();
64 this.code_mirror.focus();
65 this.code_mirror.focus();
65 this.code_mirror.refresh();
66 this.code_mirror.refresh();
66 this.rendered = false;
67 this.rendered = false;
67 };
68 };
68 };
69 };
69
70
70
71
71 HTMLCell.prototype.render = function () {
72 HTMLCell.prototype.render = function () {
72 if (this.rendered === false) {
73 if (this.rendered === false) {
73 var html_cell = this.element;
74 var html_cell = this.element;
74 var output = html_cell.find("div.html_cell_render");
75 var output = html_cell.find("div.html_cell_render");
75 var text = this.get_source();
76 var text = this.get_source();
76 if (text === "") {text = this.placeholder;};
77 if (text === "") {text = this.placeholder;};
77 this.set_render(text);
78 this.set_rendered(text);
78 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
79 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
79 html_cell.find('div.html_cell_input').hide();
80 html_cell.find('div.html_cell_input').hide();
80 output.show();
81 output.show();
81 this.rendered = true;
82 this.rendered = true;
82 };
83 };
83 };
84 };
84
85
85
86
86 HTMLCell.prototype.config_mathjax = function () {
87 HTMLCell.prototype.config_mathjax = function () {
87 var html_cell = this.element;
88 var html_cell = this.element;
88 var that = this;
89 var that = this;
89 html_cell.click(function () {
90 html_cell.click(function () {
90 that.edit();
91 that.edit();
91 }).focusout(function () {
92 }).focusout(function () {
92 that.render();
93 that.render();
93 });
94 });
94
95
95 html_cell.trigger("focusout");
96 html_cell.trigger("focusout");
96 };
97 };
97
98
98
99
99 HTMLCell.prototype.get_source = function() {
100 HTMLCell.prototype.get_source = function() {
100 return this.code_mirror.getValue();
101 return this.code_mirror.getValue();
101 };
102 };
102
103
103
104
104 HTMLCell.prototype.set_source = function(text) {
105 HTMLCell.prototype.set_source = function(text) {
105 this.code_mirror.setValue(text);
106 this.code_mirror.setValue(text);
106 this.code_mirror.refresh();
107 this.code_mirror.refresh();
107 };
108 };
108
109
109
110
110 HTMLCell.prototype.set_render = function(text) {
111 HTMLCell.prototype.set_rendered = function(text) {
111 this.element.find('div.html_cell_render').html(text);
112 this.element.find('div.html_cell_render').html(text);
112 };
113 };
113
114
114
115
115 HTMLCell.prototype.at_top = function () {
116 HTMLCell.prototype.at_top = function () {
116 if (this.rendered) {
117 if (this.rendered) {
117 return true;
118 return true;
118 } else {
119 } else {
119 return false;
120 return false;
120 }
121 }
121 };
122 };
122
123
123
124
124 HTMLCell.prototype.at_bottom = function () {
125 HTMLCell.prototype.at_bottom = function () {
125 if (this.rendered) {
126 if (this.rendered) {
126 return true;
127 return true;
127 } else {
128 } else {
128 return false;
129 return false;
129 }
130 }
130 };
131 };
131
132
132
133
133 HTMLCell.prototype.fromJSON = function (data) {
134 HTMLCell.prototype.fromJSON = function (data) {
134 if (data.cell_type === 'html') {
135 if (data.cell_type === 'html') {
135 if (data.source !== undefined) {
136 if (data.source !== undefined) {
136 this.set_source(data.source);
137 this.set_source(data.source);
137 this.set_render(data.source);
138 this.set_rendered(data.source);
138 };
139 };
139 };
140 };
140 }
141 }
141
142
142
143
143 HTMLCell.prototype.toJSON = function () {
144 HTMLCell.prototype.toJSON = function () {
144 var data = {}
145 var data = {}
145 data.cell_type = 'html';
146 data.cell_type = 'html';
146 data.source = this.get_source();
147 data.source = this.get_source();
147 return data;
148 return data;
148 };
149 };
149
150
150 IPython.HTMLCell = HTMLCell;
151 IPython.HTMLCell = HTMLCell;
151
152
152 return IPython;
153 return IPython;
153
154
154 }(IPython));
155 }(IPython));
155
156
@@ -1,659 +1,711 b''
1
1
2 //============================================================================
2 //============================================================================
3 // Notebook
3 // Notebook
4 //============================================================================
4 //============================================================================
5
5
6 var IPython = (function (IPython) {
6 var IPython = (function (IPython) {
7
7
8 var utils = IPython.utils;
8 var utils = IPython.utils;
9
9
10 var Notebook = function (selector) {
10 var Notebook = function (selector) {
11 this.element = $(selector);
11 this.element = $(selector);
12 this.element.scroll();
12 this.element.scroll();
13 this.element.data("notebook", this);
13 this.element.data("notebook", this);
14 this.next_prompt_number = 1;
14 this.next_prompt_number = 1;
15 this.kernel = null;
15 this.kernel = null;
16 this.msg_cell_map = {};
16 this.msg_cell_map = {};
17 this.style();
17 this.style();
18 this.create_elements();
18 this.create_elements();
19 this.bind_events();
19 this.bind_events();
20 };
20 };
21
21
22
22
23 Notebook.prototype.style = function () {
23 Notebook.prototype.style = function () {
24 $('div#notebook').addClass('border-box-sizing');
24 $('div#notebook').addClass('border-box-sizing');
25 };
25 };
26
26
27
27
28 Notebook.prototype.create_elements = function () {
28 Notebook.prototype.create_elements = function () {
29 // We add this end_space div to the end of the notebook div to:
29 // We add this end_space div to the end of the notebook div to:
30 // i) provide a margin between the last cell and the end of the notebook
30 // i) provide a margin between the last cell and the end of the notebook
31 // ii) to prevent the div from scrolling up when the last cell is being
31 // ii) to prevent the div from scrolling up when the last cell is being
32 // edited, but is too low on the page, which browsers will do automatically.
32 // edited, but is too low on the page, which browsers will do automatically.
33 this.element.append($('<div class="end_space"></div>').height(50));
33 this.element.append($('<div class="end_space"></div>').height(50));
34 $('div#notebook').addClass('border-box-sizing');
34 $('div#notebook').addClass('border-box-sizing');
35 };
35 };
36
36
37
37
38 Notebook.prototype.bind_events = function () {
38 Notebook.prototype.bind_events = function () {
39 var that = this;
39 var that = this;
40 $(document).keydown(function (event) {
40 $(document).keydown(function (event) {
41 // console.log(event);
41 // console.log(event);
42 if (event.which === 38) {
42 if (event.which === 38) {
43 var cell = that.selected_cell();
43 var cell = that.selected_cell();
44 if (cell.at_top()) {
44 if (cell.at_top()) {
45 event.preventDefault();
45 event.preventDefault();
46 that.select_prev();
46 that.select_prev();
47 };
47 };
48 } else if (event.which === 40) {
48 } else if (event.which === 40) {
49 var cell = that.selected_cell();
49 var cell = that.selected_cell();
50 if (cell.at_bottom()) {
50 if (cell.at_bottom()) {
51 event.preventDefault();
51 event.preventDefault();
52 that.select_next();
52 that.select_next();
53 };
53 };
54 } else if (event.which === 13 && event.shiftKey) {
54 } else if (event.which === 13 && event.shiftKey) {
55 that.execute_selected_cell();
55 that.execute_selected_cell();
56 return false;
56 return false;
57 } else if (event.which === 13 && event.ctrlKey) {
57 } else if (event.which === 13 && event.ctrlKey) {
58 that.execute_selected_cell({terminal:true});
58 that.execute_selected_cell({terminal:true});
59 return false;
59 return false;
60 };
60 };
61 });
61 });
62
62
63 this.element.bind('collapse_pager', function () {
63 this.element.bind('collapse_pager', function () {
64 var app_height = $('div#main_app').height(); // content height
64 var app_height = $('div#main_app').height(); // content height
65 var splitter_height = $('div#pager_splitter').outerHeight(true);
65 var splitter_height = $('div#pager_splitter').outerHeight(true);
66 var new_height = app_height - splitter_height;
66 var new_height = app_height - splitter_height;
67 that.element.animate({height : new_height + 'px'}, 'fast');
67 that.element.animate({height : new_height + 'px'}, 'fast');
68 });
68 });
69
69
70 this.element.bind('expand_pager', function () {
70 this.element.bind('expand_pager', function () {
71 var app_height = $('div#main_app').height(); // content height
71 var app_height = $('div#main_app').height(); // content height
72 var splitter_height = $('div#pager_splitter').outerHeight(true);
72 var splitter_height = $('div#pager_splitter').outerHeight(true);
73 var pager_height = $('div#pager').outerHeight(true);
73 var pager_height = $('div#pager').outerHeight(true);
74 var new_height = app_height - pager_height - splitter_height;
74 var new_height = app_height - pager_height - splitter_height;
75 that.element.animate({height : new_height + 'px'}, 'fast');
75 that.element.animate({height : new_height + 'px'}, 'fast');
76 });
76 });
77
77
78 this.element.bind('collapse_left_panel', function () {
78 this.element.bind('collapse_left_panel', function () {
79 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
79 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
80 var new_margin = splitter_width;
80 var new_margin = splitter_width;
81 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
81 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
82 });
82 });
83
83
84 this.element.bind('expand_left_panel', function () {
84 this.element.bind('expand_left_panel', function () {
85 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
85 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
86 var left_panel_width = IPython.left_panel.width;
86 var left_panel_width = IPython.left_panel.width;
87 var new_margin = splitter_width + left_panel_width;
87 var new_margin = splitter_width + left_panel_width;
88 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
88 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
89 });
89 });
90 };
90 };
91
91
92
92
93 Notebook.prototype.scroll_to_bottom = function () {
93 Notebook.prototype.scroll_to_bottom = function () {
94 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
94 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
95 };
95 };
96
96
97
97
98 Notebook.prototype.scroll_to_top = function () {
98 Notebook.prototype.scroll_to_top = function () {
99 this.element.animate({scrollTop:0}, 0);
99 this.element.animate({scrollTop:0}, 0);
100 };
100 };
101
101
102
102
103 // Cell indexing, retrieval, etc.
103 // Cell indexing, retrieval, etc.
104
104
105
105
106 Notebook.prototype.cell_elements = function () {
106 Notebook.prototype.cell_elements = function () {
107 return this.element.children("div.cell");
107 return this.element.children("div.cell");
108 }
108 }
109
109
110
110
111 Notebook.prototype.ncells = function (cell) {
111 Notebook.prototype.ncells = function (cell) {
112 return this.cell_elements().length;
112 return this.cell_elements().length;
113 }
113 }
114
114
115
115
116 // TODO: we are often calling cells as cells()[i], which we should optimize
116 // TODO: we are often calling cells as cells()[i], which we should optimize
117 // to cells(i) or a new method.
117 // to cells(i) or a new method.
118 Notebook.prototype.cells = function () {
118 Notebook.prototype.cells = function () {
119 return this.cell_elements().toArray().map(function (e) {
119 return this.cell_elements().toArray().map(function (e) {
120 return $(e).data("cell");
120 return $(e).data("cell");
121 });
121 });
122 }
122 }
123
123
124
124
125 Notebook.prototype.find_cell_index = function (cell) {
125 Notebook.prototype.find_cell_index = function (cell) {
126 var result = null;
126 var result = null;
127 this.cell_elements().filter(function (index) {
127 this.cell_elements().filter(function (index) {
128 if ($(this).data("cell") === cell) {
128 if ($(this).data("cell") === cell) {
129 result = index;
129 result = index;
130 };
130 };
131 });
131 });
132 return result;
132 return result;
133 };
133 };
134
134
135
135
136 Notebook.prototype.index_or_selected = function (index) {
136 Notebook.prototype.index_or_selected = function (index) {
137 return index || this.selected_index() || 0;
137 return index || this.selected_index() || 0;
138 }
138 }
139
139
140
140
141 Notebook.prototype.select = function (index) {
141 Notebook.prototype.select = function (index) {
142 if (index !== undefined && index >= 0 && index < this.ncells()) {
142 if (index !== undefined && index >= 0 && index < this.ncells()) {
143 if (this.selected_index() !== null) {
143 if (this.selected_index() !== null) {
144 this.selected_cell().unselect();
144 this.selected_cell().unselect();
145 };
145 };
146 this.cells()[index].select();
146 this.cells()[index].select();
147 if (index === (this.ncells()-1)) {
147 if (index === (this.ncells()-1)) {
148 this.scroll_to_bottom();
148 this.scroll_to_bottom();
149 };
149 };
150 };
150 };
151 return this;
151 return this;
152 };
152 };
153
153
154
154
155 Notebook.prototype.select_next = function () {
155 Notebook.prototype.select_next = function () {
156 var index = this.selected_index();
156 var index = this.selected_index();
157 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
157 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
158 this.select(index+1);
158 this.select(index+1);
159 };
159 };
160 return this;
160 return this;
161 };
161 };
162
162
163
163
164 Notebook.prototype.select_prev = function () {
164 Notebook.prototype.select_prev = function () {
165 var index = this.selected_index();
165 var index = this.selected_index();
166 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
166 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
167 this.select(index-1);
167 this.select(index-1);
168 };
168 };
169 return this;
169 return this;
170 };
170 };
171
171
172
172
173 Notebook.prototype.selected_index = function () {
173 Notebook.prototype.selected_index = function () {
174 var result = null;
174 var result = null;
175 this.cell_elements().filter(function (index) {
175 this.cell_elements().filter(function (index) {
176 if ($(this).data("cell").selected === true) {
176 if ($(this).data("cell").selected === true) {
177 result = index;
177 result = index;
178 };
178 };
179 });
179 });
180 return result;
180 return result;
181 };
181 };
182
182
183
183
184 Notebook.prototype.cell_for_msg = function (msg_id) {
184 Notebook.prototype.cell_for_msg = function (msg_id) {
185 var cell_id = this.msg_cell_map[msg_id];
185 var cell_id = this.msg_cell_map[msg_id];
186 var result = null;
186 var result = null;
187 this.cell_elements().filter(function (index) {
187 this.cell_elements().filter(function (index) {
188 cell = $(this).data("cell");
188 cell = $(this).data("cell");
189 if (cell.cell_id === cell_id) {
189 if (cell.cell_id === cell_id) {
190 result = cell;
190 result = cell;
191 };
191 };
192 });
192 });
193 return result;
193 return result;
194 };
194 };
195
195
196
196
197 Notebook.prototype.selected_cell = function () {
197 Notebook.prototype.selected_cell = function () {
198 return this.cell_elements().eq(this.selected_index()).data("cell");
198 return this.cell_elements().eq(this.selected_index()).data("cell");
199 }
199 }
200
200
201
201
202 // Cell insertion, deletion and moving.
202 // Cell insertion, deletion and moving.
203
203
204
204
205 Notebook.prototype.delete_cell = function (index) {
205 Notebook.prototype.delete_cell = function (index) {
206 var i = index || this.selected_index();
206 var i = index || this.selected_index();
207 if (i !== null && i >= 0 && i < this.ncells()) {
207 if (i !== null && i >= 0 && i < this.ncells()) {
208 this.cell_elements().eq(i).remove();
208 this.cell_elements().eq(i).remove();
209 if (i === (this.ncells())) {
209 if (i === (this.ncells())) {
210 this.select(i-1);
210 this.select(i-1);
211 } else {
211 } else {
212 this.select(i);
212 this.select(i);
213 };
213 };
214 };
214 };
215 return this;
215 return this;
216 };
216 };
217
217
218
218
219 Notebook.prototype.append_cell = function (cell) {
219 Notebook.prototype.append_cell = function (cell) {
220 this.element.find('div.end_space').before(cell.element);
220 this.element.find('div.end_space').before(cell.element);
221 return this;
221 return this;
222 };
222 };
223
223
224
224
225 Notebook.prototype.insert_cell_after = function (cell, index) {
225 Notebook.prototype.insert_cell_after = function (cell, index) {
226 var ncells = this.ncells();
226 var ncells = this.ncells();
227 if (ncells === 0) {
227 if (ncells === 0) {
228 this.append_cell(cell);
228 this.append_cell(cell);
229 return this;
229 return this;
230 };
230 };
231 if (index >= 0 && index < ncells) {
231 if (index >= 0 && index < ncells) {
232 this.cell_elements().eq(index).after(cell.element);
232 this.cell_elements().eq(index).after(cell.element);
233 };
233 };
234 return this
234 return this
235 };
235 };
236
236
237
237
238 Notebook.prototype.insert_cell_before = function (cell, index) {
238 Notebook.prototype.insert_cell_before = function (cell, index) {
239 var ncells = this.ncells();
239 var ncells = this.ncells();
240 if (ncells === 0) {
240 if (ncells === 0) {
241 this.append_cell(cell);
241 this.append_cell(cell);
242 return this;
242 return this;
243 };
243 };
244 if (index >= 0 && index < ncells) {
244 if (index >= 0 && index < ncells) {
245 this.cell_elements().eq(index).before(cell.element);
245 this.cell_elements().eq(index).before(cell.element);
246 };
246 };
247 return this;
247 return this;
248 };
248 };
249
249
250
250
251 Notebook.prototype.move_cell_up = function (index) {
251 Notebook.prototype.move_cell_up = function (index) {
252 var i = index || this.selected_index();
252 var i = index || this.selected_index();
253 if (i !== null && i < this.ncells() && i > 0) {
253 if (i !== null && i < this.ncells() && i > 0) {
254 var pivot = this.cell_elements().eq(i-1);
254 var pivot = this.cell_elements().eq(i-1);
255 var tomove = this.cell_elements().eq(i);
255 var tomove = this.cell_elements().eq(i);
256 if (pivot !== null && tomove !== null) {
256 if (pivot !== null && tomove !== null) {
257 tomove.detach();
257 tomove.detach();
258 pivot.before(tomove);
258 pivot.before(tomove);
259 this.select(i-1);
259 this.select(i-1);
260 };
260 };
261 };
261 };
262 return this;
262 return this;
263 }
263 }
264
264
265
265
266 Notebook.prototype.move_cell_down = function (index) {
266 Notebook.prototype.move_cell_down = function (index) {
267 var i = index || this.selected_index();
267 var i = index || this.selected_index();
268 if (i !== null && i < (this.ncells()-1) && i >= 0) {
268 if (i !== null && i < (this.ncells()-1) && i >= 0) {
269 var pivot = this.cell_elements().eq(i+1)
269 var pivot = this.cell_elements().eq(i+1)
270 var tomove = this.cell_elements().eq(i)
270 var tomove = this.cell_elements().eq(i)
271 if (pivot !== null && tomove !== null) {
271 if (pivot !== null && tomove !== null) {
272 tomove.detach();
272 tomove.detach();
273 pivot.after(tomove);
273 pivot.after(tomove);
274 this.select(i+1);
274 this.select(i+1);
275 };
275 };
276 };
276 };
277 return this;
277 return this;
278 }
278 }
279
279
280
280
281 Notebook.prototype.sort_cells = function () {
281 Notebook.prototype.sort_cells = function () {
282 var ncells = this.ncells();
282 var ncells = this.ncells();
283 var sindex = this.selected_index();
283 var sindex = this.selected_index();
284 var swapped;
284 var swapped;
285 do {
285 do {
286 swapped = false
286 swapped = false
287 for (var i=1; i<ncells; i++) {
287 for (var i=1; i<ncells; i++) {
288 current = this.cell_elements().eq(i).data("cell");
288 current = this.cell_elements().eq(i).data("cell");
289 previous = this.cell_elements().eq(i-1).data("cell");
289 previous = this.cell_elements().eq(i-1).data("cell");
290 if (previous.input_prompt_number > current.input_prompt_number) {
290 if (previous.input_prompt_number > current.input_prompt_number) {
291 this.move_cell_up(i);
291 this.move_cell_up(i);
292 swapped = true;
292 swapped = true;
293 };
293 };
294 };
294 };
295 } while (swapped);
295 } while (swapped);
296 this.select(sindex);
296 this.select(sindex);
297 return this;
297 return this;
298 };
298 };
299
299
300
300
301 Notebook.prototype.insert_code_cell_before = function (index) {
301 Notebook.prototype.insert_code_cell_before = function (index) {
302 // TODO: Bounds check for i
302 // TODO: Bounds check for i
303 var i = this.index_or_selected(index);
303 var i = this.index_or_selected(index);
304 var cell = new IPython.CodeCell(this);
304 var cell = new IPython.CodeCell(this);
305 cell.set_input_prompt();
305 cell.set_input_prompt();
306 this.insert_cell_before(cell, i);
306 this.insert_cell_before(cell, i);
307 this.select(this.find_cell_index(cell));
307 this.select(this.find_cell_index(cell));
308 return cell;
308 return cell;
309 }
309 }
310
310
311
311
312 Notebook.prototype.insert_code_cell_after = function (index) {
312 Notebook.prototype.insert_code_cell_after = function (index) {
313 // TODO: Bounds check for i
313 // TODO: Bounds check for i
314 var i = this.index_or_selected(index);
314 var i = this.index_or_selected(index);
315 var cell = new IPython.CodeCell(this);
315 var cell = new IPython.CodeCell(this);
316 cell.set_input_prompt();
316 cell.set_input_prompt();
317 this.insert_cell_after(cell, i);
317 this.insert_cell_after(cell, i);
318 this.select(this.find_cell_index(cell));
318 this.select(this.find_cell_index(cell));
319 return cell;
319 return cell;
320 }
320 }
321
321
322
322
323 Notebook.prototype.insert_html_cell_before = function (index) {
323 Notebook.prototype.insert_html_cell_before = function (index) {
324 // TODO: Bounds check for i
324 // TODO: Bounds check for i
325 var i = this.index_or_selected(index);
325 var i = this.index_or_selected(index);
326 var cell = new IPython.HTMLCell(this);
326 var cell = new IPython.HTMLCell(this);
327 cell.config_mathjax();
327 cell.config_mathjax();
328 this.insert_cell_before(cell, i);
328 this.insert_cell_before(cell, i);
329 this.select(this.find_cell_index(cell));
329 this.select(this.find_cell_index(cell));
330 return cell;
330 return cell;
331 }
331 }
332
332
333
333
334 Notebook.prototype.insert_html_cell_after = function (index) {
334 Notebook.prototype.insert_html_cell_after = function (index) {
335 // TODO: Bounds check for i
335 // TODO: Bounds check for i
336 var i = this.index_or_selected(index);
336 var i = this.index_or_selected(index);
337 var cell = new IPython.HTMLCell(this);
337 var cell = new IPython.HTMLCell(this);
338 cell.config_mathjax();
338 cell.config_mathjax();
339 this.insert_cell_after(cell, i);
339 this.insert_cell_after(cell, i);
340 this.select(this.find_cell_index(cell));
340 this.select(this.find_cell_index(cell));
341 return cell;
341 return cell;
342 }
342 }
343
343
344
344
345 Notebook.prototype.html_to_code = function (index) {
345 Notebook.prototype.insert_rst_cell_before = function (index) {
346 // TODO: Bounds check for i
347 var i = this.index_or_selected(index);
348 var cell = new IPython.RSTCell(this);
349 cell.config_mathjax();
350 this.insert_cell_before(cell, i);
351 this.select(this.find_cell_index(cell));
352 return cell;
353 }
354
355
356 Notebook.prototype.insert_rst_cell_after = function (index) {
357 // TODO: Bounds check for i
358 var i = this.index_or_selected(index);
359 var cell = new IPython.RSTCell(this);
360 cell.config_mathjax();
361 this.insert_cell_after(cell, i);
362 this.select(this.find_cell_index(cell));
363 return cell;
364 }
365
366
367 Notebook.prototype.to_code = function (index) {
346 // TODO: Bounds check for i
368 // TODO: Bounds check for i
347 var i = this.index_or_selected(index);
369 var i = this.index_or_selected(index);
348 var source_element = this.cell_elements().eq(i);
370 var source_element = this.cell_elements().eq(i);
349 var source_cell = source_element.data("cell");
371 var source_cell = source_element.data("cell");
350 if (source_cell instanceof IPython.HTMLCell) {
372 if (source_cell instanceof IPython.HTMLCell || source_cell instanceof IPython.RSTCell) {
351 this.insert_code_cell_after(i);
373 this.insert_code_cell_after(i);
352 var target_cell = this.cells()[i+1];
374 var target_cell = this.cells()[i+1];
353 target_cell.set_code(source_cell.get_source());
375 target_cell.set_code(source_cell.get_source());
354 source_element.remove();
376 source_element.remove();
355 };
377 };
356 };
378 };
357
379
358
380
359 Notebook.prototype.code_to_html = function (index) {
381 Notebook.prototype.to_rst = function (index) {
382 // TODO: Bounds check for i
383 var i = this.index_or_selected(index);
384 var source_element = this.cell_elements().eq(i);
385 var source_cell = source_element.data("cell");
386 var target_cell = null;
387 if (source_cell instanceof IPython.CodeCell) {
388 this.insert_rst_cell_after(i);
389 var target_cell = this.cells()[i+1];
390 var text = source_cell.get_code();
391 } else if (source_cell instanceof IPython.HTMLCell) {
392 this.insert_rst_cell_after(i);
393 var target_cell = this.cells()[i+1];
394 var text = source_cell.get_source();
395 }
396 if (target_cell !== null) {
397 if (text === "") {text = target_cell.placeholder;};
398 target_cell.set_source(text);
399 source_element.remove();
400 target_cell.edit();
401 }
402 };
403
404
405 Notebook.prototype.to_html = function (index) {
360 // TODO: Bounds check for i
406 // TODO: Bounds check for i
361 var i = this.index_or_selected(index);
407 var i = this.index_or_selected(index);
362 var source_element = this.cell_elements().eq(i);
408 var source_element = this.cell_elements().eq(i);
363 var source_cell = source_element.data("cell");
409 var source_cell = source_element.data("cell");
410 var target_cell = null;
364 if (source_cell instanceof IPython.CodeCell) {
411 if (source_cell instanceof IPython.CodeCell) {
365 this.insert_html_cell_after(i);
412 this.insert_html_cell_after(i);
366 var target_cell = this.cells()[i+1];
413 var target_cell = this.cells()[i+1];
367 var text = source_cell.get_code();
414 var text = source_cell.get_code();
415 } else if (source_cell instanceof IPython.RSTCell) {
416 this.insert_html_cell_after(i);
417 var target_cell = this.cells()[i+1];
418 var text = source_cell.get_source();
419 }
420 if (target_cell !== null) {
368 if (text === "") {text = target_cell.placeholder;};
421 if (text === "") {text = target_cell.placeholder;};
369 target_cell.set_source(text);
422 target_cell.set_source(text);
370 target_cell.set_render(text);
371 source_element.remove();
423 source_element.remove();
372 target_cell.edit();
424 target_cell.edit();
373 };
425 }
374 };
426 };
375
427
376
428
377 // Cell collapsing
429 // Cell collapsing
378
430
379 Notebook.prototype.collapse = function (index) {
431 Notebook.prototype.collapse = function (index) {
380 var i = this.index_or_selected(index);
432 var i = this.index_or_selected(index);
381 this.cells()[i].collapse();
433 this.cells()[i].collapse();
382 };
434 };
383
435
384
436
385 Notebook.prototype.expand = function (index) {
437 Notebook.prototype.expand = function (index) {
386 var i = this.index_or_selected(index);
438 var i = this.index_or_selected(index);
387 this.cells()[i].expand();
439 this.cells()[i].expand();
388 };
440 };
389
441
390
442
391 // Kernel related things
443 // Kernel related things
392
444
393 Notebook.prototype.start_kernel = function () {
445 Notebook.prototype.start_kernel = function () {
394 this.kernel = new IPython.Kernel();
446 this.kernel = new IPython.Kernel();
395 var notebook_id = IPython.save_widget.get_notebook_id();
447 var notebook_id = IPython.save_widget.get_notebook_id();
396 this.kernel.start_kernel(notebook_id, $.proxy(this.kernel_started, this));
448 this.kernel.start_kernel(notebook_id, $.proxy(this.kernel_started, this));
397 };
449 };
398
450
399
451
400 Notebook.prototype.handle_shell_reply = function (e) {
452 Notebook.prototype.handle_shell_reply = function (e) {
401 reply = $.parseJSON(e.data);
453 reply = $.parseJSON(e.data);
402 var header = reply.header;
454 var header = reply.header;
403 var content = reply.content;
455 var content = reply.content;
404 var msg_type = header.msg_type;
456 var msg_type = header.msg_type;
405 // console.log(reply);
457 // console.log(reply);
406 var cell = this.cell_for_msg(reply.parent_header.msg_id);
458 var cell = this.cell_for_msg(reply.parent_header.msg_id);
407 if (msg_type === "execute_reply") {
459 if (msg_type === "execute_reply") {
408 cell.set_input_prompt(content.execution_count);
460 cell.set_input_prompt(content.execution_count);
409 } else if (msg_type === "complete_reply") {
461 } else if (msg_type === "complete_reply") {
410 cell.finish_completing(content.matched_text, content.matches);
462 cell.finish_completing(content.matched_text, content.matches);
411 };
463 };
412 var payload = content.payload || [];
464 var payload = content.payload || [];
413 this.handle_payload(payload);
465 this.handle_payload(payload);
414 };
466 };
415
467
416
468
417 Notebook.prototype.handle_payload = function (payload) {
469 Notebook.prototype.handle_payload = function (payload) {
418 var l = payload.length;
470 var l = payload.length;
419 if (l > 0) {
471 if (l > 0) {
420 IPython.pager.clear();
472 IPython.pager.clear();
421 IPython.pager.expand();
473 IPython.pager.expand();
422 };
474 };
423 for (var i=0; i<l; i++) {
475 for (var i=0; i<l; i++) {
424 IPython.pager.append_text(payload[i].text);
476 IPython.pager.append_text(payload[i].text);
425 };
477 };
426 };
478 };
427
479
428
480
429 Notebook.prototype.handle_iopub_reply = function (e) {
481 Notebook.prototype.handle_iopub_reply = function (e) {
430 reply = $.parseJSON(e.data);
482 reply = $.parseJSON(e.data);
431 var content = reply.content;
483 var content = reply.content;
432 // console.log(reply);
484 // console.log(reply);
433 var msg_type = reply.header.msg_type;
485 var msg_type = reply.header.msg_type;
434 var cell = this.cell_for_msg(reply.parent_header.msg_id);
486 var cell = this.cell_for_msg(reply.parent_header.msg_id);
435 var output_types = ['stream','display_data','pyout','pyerr'];
487 var output_types = ['stream','display_data','pyout','pyerr'];
436 if (output_types.indexOf(msg_type) >= 0) {
488 if (output_types.indexOf(msg_type) >= 0) {
437 this.handle_output(cell, msg_type, content);
489 this.handle_output(cell, msg_type, content);
438 } else if (msg_type === "status") {
490 } else if (msg_type === "status") {
439 if (content.execution_state === "busy") {
491 if (content.execution_state === "busy") {
440 IPython.kernel_status_widget.status_busy();
492 IPython.kernel_status_widget.status_busy();
441 } else if (content.execution_state === "idle") {
493 } else if (content.execution_state === "idle") {
442 IPython.kernel_status_widget.status_idle();
494 IPython.kernel_status_widget.status_idle();
443 };
495 };
444 }
496 }
445 };
497 };
446
498
447
499
448 Notebook.prototype.handle_output = function (cell, msg_type, content) {
500 Notebook.prototype.handle_output = function (cell, msg_type, content) {
449 var json = {};
501 var json = {};
450 json.output_type = msg_type;
502 json.output_type = msg_type;
451 if (msg_type === "stream") {
503 if (msg_type === "stream") {
452 json.text = content.data + '\n';
504 json.text = content.data + '\n';
453 } else if (msg_type === "display_data") {
505 } else if (msg_type === "display_data") {
454 json = this.convert_mime_types(json, content.data);
506 json = this.convert_mime_types(json, content.data);
455 } else if (msg_type === "pyout") {
507 } else if (msg_type === "pyout") {
456 json.prompt_number = content.execution_count;
508 json.prompt_number = content.execution_count;
457 json = this.convert_mime_types(json, content.data);
509 json = this.convert_mime_types(json, content.data);
458 } else if (msg_type === "pyerr") {
510 } else if (msg_type === "pyerr") {
459 json.ename = content.ename;
511 json.ename = content.ename;
460 json.evalue = content.evalue;
512 json.evalue = content.evalue;
461 json.traceback = content.traceback;
513 json.traceback = content.traceback;
462 };
514 };
463 cell.append_output(json);
515 cell.append_output(json);
464 };
516 };
465
517
466
518
467 Notebook.prototype.convert_mime_types = function (json, data) {
519 Notebook.prototype.convert_mime_types = function (json, data) {
468 if (data['text/plain'] !== undefined) {
520 if (data['text/plain'] !== undefined) {
469 json.text = data['text/plain'];
521 json.text = data['text/plain'];
470 };
522 };
471 if (data['text/html'] !== undefined) {
523 if (data['text/html'] !== undefined) {
472 json.html = data['text/html'];
524 json.html = data['text/html'];
473 };
525 };
474 if (data['image/svg+xml'] !== undefined) {
526 if (data['image/svg+xml'] !== undefined) {
475 json.svg = data['image/svg+xml'];
527 json.svg = data['image/svg+xml'];
476 };
528 };
477 if (data['image/png'] !== undefined) {
529 if (data['image/png'] !== undefined) {
478 json.png = data['image/png'];
530 json.png = data['image/png'];
479 };
531 };
480 if (data['text/latex'] !== undefined) {
532 if (data['text/latex'] !== undefined) {
481 json.latex = data['text/latex'];
533 json.latex = data['text/latex'];
482 };
534 };
483 if (data['application/json'] !== undefined) {
535 if (data['application/json'] !== undefined) {
484 json.json = data['application/json'];
536 json.json = data['application/json'];
485 };
537 };
486 if (data['application/javascript'] !== undefined) {
538 if (data['application/javascript'] !== undefined) {
487 json.javascript = data['application/javascript'];
539 json.javascript = data['application/javascript'];
488 }
540 }
489 return json;
541 return json;
490 };
542 };
491
543
492 Notebook.prototype.kernel_started = function () {
544 Notebook.prototype.kernel_started = function () {
493 console.log("Kernel started: ", this.kernel.kernel_id);
545 console.log("Kernel started: ", this.kernel.kernel_id);
494 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
546 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
495 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
547 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
496 };
548 };
497
549
498
550
499 Notebook.prototype.execute_selected_cell = function (options) {
551 Notebook.prototype.execute_selected_cell = function (options) {
500 // add_new: should a new cell be added if we are at the end of the nb
552 // add_new: should a new cell be added if we are at the end of the nb
501 // terminal: execute in terminal mode, which stays in the current cell
553 // terminal: execute in terminal mode, which stays in the current cell
502 default_options = {terminal: false, add_new: true}
554 default_options = {terminal: false, add_new: true}
503 $.extend(default_options, options)
555 $.extend(default_options, options)
504 var that = this;
556 var that = this;
505 var cell = that.selected_cell();
557 var cell = that.selected_cell();
506 var cell_index = that.find_cell_index(cell);
558 var cell_index = that.find_cell_index(cell);
507 if (cell instanceof IPython.CodeCell) {
559 if (cell instanceof IPython.CodeCell) {
508 cell.clear_output();
560 cell.clear_output();
509 var code = cell.get_code();
561 var code = cell.get_code();
510 var msg_id = that.kernel.execute(cell.get_code());
562 var msg_id = that.kernel.execute(cell.get_code());
511 that.msg_cell_map[msg_id] = cell.cell_id;
563 that.msg_cell_map[msg_id] = cell.cell_id;
512 } else if (cell instanceof IPython.HTMLCell) {
564 } else if (cell instanceof IPython.HTMLCell) {
513 cell.render();
565 cell.render();
514 }
566 }
515 if (default_options.terminal) {
567 if (default_options.terminal) {
516 cell.clear_input();
568 cell.clear_input();
517 } else {
569 } else {
518 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
570 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
519 that.insert_code_cell_after();
571 that.insert_code_cell_after();
520 // If we are adding a new cell at the end, scroll down to show it.
572 // If we are adding a new cell at the end, scroll down to show it.
521 that.scroll_to_bottom();
573 that.scroll_to_bottom();
522 } else {
574 } else {
523 that.select(cell_index+1);
575 that.select(cell_index+1);
524 };
576 };
525 };
577 };
526 };
578 };
527
579
528
580
529 Notebook.prototype.execute_all_cells = function () {
581 Notebook.prototype.execute_all_cells = function () {
530 var ncells = this.ncells();
582 var ncells = this.ncells();
531 for (var i=0; i<ncells; i++) {
583 for (var i=0; i<ncells; i++) {
532 this.select(i);
584 this.select(i);
533 this.execute_selected_cell({add_new:false});
585 this.execute_selected_cell({add_new:false});
534 };
586 };
535 this.scroll_to_bottom();
587 this.scroll_to_bottom();
536 };
588 };
537
589
538
590
539 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
591 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
540 var msg_id = this.kernel.complete(line, cursor_pos);
592 var msg_id = this.kernel.complete(line, cursor_pos);
541 this.msg_cell_map[msg_id] = cell.cell_id;
593 this.msg_cell_map[msg_id] = cell.cell_id;
542 };
594 };
543
595
544 // Persistance and loading
596 // Persistance and loading
545
597
546
598
547 Notebook.prototype.fromJSON = function (data) {
599 Notebook.prototype.fromJSON = function (data) {
548 var ncells = this.ncells();
600 var ncells = this.ncells();
549 for (var i=0; i<ncells; i++) {
601 for (var i=0; i<ncells; i++) {
550 // Always delete cell 0 as they get renumbered as they are deleted.
602 // Always delete cell 0 as they get renumbered as they are deleted.
551 this.delete_cell(0);
603 this.delete_cell(0);
552 };
604 };
553 // Only handle 1 worksheet for now.
605 // Only handle 1 worksheet for now.
554 var worksheet = data.worksheets[0];
606 var worksheet = data.worksheets[0];
555 if (worksheet !== undefined) {
607 if (worksheet !== undefined) {
556 var new_cells = worksheet.cells;
608 var new_cells = worksheet.cells;
557 ncells = new_cells.length;
609 ncells = new_cells.length;
558 var cell_data = null;
610 var cell_data = null;
559 var new_cell = null;
611 var new_cell = null;
560 for (var i=0; i<ncells; i++) {
612 for (var i=0; i<ncells; i++) {
561 cell_data = new_cells[i];
613 cell_data = new_cells[i];
562 if (cell_data.cell_type == 'code') {
614 if (cell_data.cell_type == 'code') {
563 new_cell = this.insert_code_cell_after();
615 new_cell = this.insert_code_cell_after();
564 new_cell.fromJSON(cell_data);
616 new_cell.fromJSON(cell_data);
565 } else if (cell_data.cell_type === 'html') {
617 } else if (cell_data.cell_type === 'html') {
566 new_cell = this.insert_html_cell_after();
618 new_cell = this.insert_html_cell_after();
567 new_cell.fromJSON(cell_data);
619 new_cell.fromJSON(cell_data);
568 };
620 };
569 };
621 };
570 };
622 };
571 };
623 };
572
624
573
625
574 Notebook.prototype.toJSON = function () {
626 Notebook.prototype.toJSON = function () {
575 var cells = this.cells();
627 var cells = this.cells();
576 var ncells = cells.length;
628 var ncells = cells.length;
577 cell_array = new Array(ncells);
629 cell_array = new Array(ncells);
578 for (var i=0; i<ncells; i++) {
630 for (var i=0; i<ncells; i++) {
579 cell_array[i] = cells[i].toJSON();
631 cell_array[i] = cells[i].toJSON();
580 };
632 };
581 data = {
633 data = {
582 // Only handle 1 worksheet for now.
634 // Only handle 1 worksheet for now.
583 worksheets : [{cells:cell_array}]
635 worksheets : [{cells:cell_array}]
584 }
636 }
585 return data
637 return data
586 };
638 };
587
639
588 Notebook.prototype.save_notebook = function () {
640 Notebook.prototype.save_notebook = function () {
589 if (IPython.save_widget.test_notebook_name()) {
641 if (IPython.save_widget.test_notebook_name()) {
590 var notebook_id = IPython.save_widget.get_notebook_id();
642 var notebook_id = IPython.save_widget.get_notebook_id();
591 var nbname = IPython.save_widget.get_notebook_name();
643 var nbname = IPython.save_widget.get_notebook_name();
592 // We may want to move the name/id/nbformat logic inside toJSON?
644 // We may want to move the name/id/nbformat logic inside toJSON?
593 var data = this.toJSON();
645 var data = this.toJSON();
594 data.name = nbname;
646 data.name = nbname;
595 data.nbformat = 2;
647 data.nbformat = 2;
596 data.id = notebook_id
648 data.id = notebook_id
597 // We do the call with settings so we can set cache to false.
649 // We do the call with settings so we can set cache to false.
598 var settings = {
650 var settings = {
599 processData : false,
651 processData : false,
600 cache : false,
652 cache : false,
601 type : "PUT",
653 type : "PUT",
602 data : JSON.stringify(data),
654 data : JSON.stringify(data),
603 headers : {'Content-Type': 'application/json'},
655 headers : {'Content-Type': 'application/json'},
604 success : $.proxy(this.notebook_saved,this)
656 success : $.proxy(this.notebook_saved,this)
605 };
657 };
606 IPython.save_widget.status_saving();
658 IPython.save_widget.status_saving();
607 $.ajax("/notebooks/" + notebook_id, settings);
659 $.ajax("/notebooks/" + notebook_id, settings);
608 };
660 };
609 };
661 };
610
662
611
663
612 Notebook.prototype.notebook_saved = function (data, status, xhr) {
664 Notebook.prototype.notebook_saved = function (data, status, xhr) {
613 IPython.save_widget.status_save();
665 IPython.save_widget.status_save();
614 }
666 }
615
667
616
668
617 Notebook.prototype.load_notebook = function (callback) {
669 Notebook.prototype.load_notebook = function (callback) {
618 var that = this;
670 var that = this;
619 var notebook_id = IPython.save_widget.get_notebook_id();
671 var notebook_id = IPython.save_widget.get_notebook_id();
620 // We do the call with settings so we can set cache to false.
672 // We do the call with settings so we can set cache to false.
621 var settings = {
673 var settings = {
622 processData : false,
674 processData : false,
623 cache : false,
675 cache : false,
624 type : "GET",
676 type : "GET",
625 dataType : "json",
677 dataType : "json",
626 success : function (data, status, xhr) {
678 success : function (data, status, xhr) {
627 that.notebook_loaded(data, status, xhr);
679 that.notebook_loaded(data, status, xhr);
628 if (callback !== undefined) {
680 if (callback !== undefined) {
629 callback();
681 callback();
630 };
682 };
631 }
683 }
632 };
684 };
633 IPython.save_widget.status_loading();
685 IPython.save_widget.status_loading();
634 $.ajax("/notebooks/" + notebook_id, settings);
686 $.ajax("/notebooks/" + notebook_id, settings);
635 }
687 }
636
688
637
689
638 Notebook.prototype.notebook_loaded = function (data, status, xhr) {
690 Notebook.prototype.notebook_loaded = function (data, status, xhr) {
639 this.fromJSON(data);
691 this.fromJSON(data);
640 if (this.ncells() === 0) {
692 if (this.ncells() === 0) {
641 this.insert_code_cell_after();
693 this.insert_code_cell_after();
642 };
694 };
643 IPython.save_widget.status_save();
695 IPython.save_widget.status_save();
644 IPython.save_widget.set_notebook_name(data.name);
696 IPython.save_widget.set_notebook_name(data.name);
645 this.start_kernel();
697 this.start_kernel();
646 // fromJSON always selects the last cell inserted. We need to wait
698 // fromJSON always selects the last cell inserted. We need to wait
647 // until that is done before scrolling to the top.
699 // until that is done before scrolling to the top.
648 setTimeout(function () {
700 setTimeout(function () {
649 IPython.notebook.select(0);
701 IPython.notebook.select(0);
650 IPython.notebook.scroll_to_top();
702 IPython.notebook.scroll_to_top();
651 }, 50);
703 }, 50);
652 };
704 };
653
705
654 IPython.Notebook = Notebook;
706 IPython.Notebook = Notebook;
655
707
656 return IPython;
708 return IPython;
657
709
658 }(IPython));
710 }(IPython));
659
711
@@ -1,50 +1,51 b''
1
1
2 //============================================================================
2 //============================================================================
3 // On document ready
3 // On document ready
4 //============================================================================
4 //============================================================================
5
5
6
6
7 $(document).ready(function () {
7 $(document).ready(function () {
8
8
9 MathJax.Hub.Config({
9 MathJax.Hub.Config({
10 tex2jax: {
10 tex2jax: {
11 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
11 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
12 displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
12 displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
13 },
13 },
14 displayAlign: 'left', // Change this to 'center' to center equations.
14 displayAlign: 'left', // Change this to 'center' to center equations.
15 "HTML-CSS": {
15 "HTML-CSS": {
16 styles: {'.MathJax_Display': {"margin": 0}}
16 styles: {'.MathJax_Display': {"margin": 0}}
17 }
17 }
18 });
18 });
19 IPython.markdown_converter = new Markdown.Converter();
19
20
20 $('div#header').addClass('border-box-sizing');
21 $('div#header').addClass('border-box-sizing');
21 $('div#main_app').addClass('border-box-sizing ui-widget ui-widget-content');
22 $('div#main_app').addClass('border-box-sizing ui-widget ui-widget-content');
22 $('div#notebook_panel').addClass('border-box-sizing ui-widget');
23 $('div#notebook_panel').addClass('border-box-sizing ui-widget');
23
24
24 IPython.layout_manager = new IPython.LayoutManager();
25 IPython.layout_manager = new IPython.LayoutManager();
25 IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter');
26 IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter');
26 IPython.left_panel = new IPython.LeftPanel('div#left_panel', 'div#left_panel_splitter');
27 IPython.left_panel = new IPython.LeftPanel('div#left_panel', 'div#left_panel_splitter');
27 IPython.save_widget = new IPython.SaveWidget('span#save_widget');
28 IPython.save_widget = new IPython.SaveWidget('span#save_widget');
28 IPython.notebook = new IPython.Notebook('div#notebook');
29 IPython.notebook = new IPython.Notebook('div#notebook');
29 IPython.kernel_status_widget = new IPython.KernelStatusWidget('#kernel_status');
30 IPython.kernel_status_widget = new IPython.KernelStatusWidget('#kernel_status');
30 IPython.kernel_status_widget.status_idle();
31 IPython.kernel_status_widget.status_idle();
31
32
32 IPython.layout_manager.do_resize();
33 IPython.layout_manager.do_resize();
33
34
34 // These have display: none in the css file and are made visible here to prevent FLOUC.
35 // These have display: none in the css file and are made visible here to prevent FLOUC.
35 $('div#header').css('display','block');
36 $('div#header').css('display','block');
36 $('div#main_app').css('display','block');
37 $('div#main_app').css('display','block');
37
38
38 // Perform these actions after the notebook has been loaded.
39 // Perform these actions after the notebook has been loaded.
39 // We wait 100 milliseconds because the notebook scrolls to the top after a load
40 // We wait 100 milliseconds because the notebook scrolls to the top after a load
40 // is completed and we need to wait for that to mostly finish.
41 // is completed and we need to wait for that to mostly finish.
41 IPython.notebook.load_notebook(function () {
42 IPython.notebook.load_notebook(function () {
42 setTimeout(function () {
43 setTimeout(function () {
43 IPython.save_widget.update_url();
44 IPython.save_widget.update_url();
44 IPython.layout_manager.do_resize();
45 IPython.layout_manager.do_resize();
45 IPython.pager.collapse();
46 IPython.pager.collapse();
46 },100);
47 },100);
47 });
48 });
48
49
49 });
50 });
50
51
@@ -1,235 +1,238 b''
1
1
2 //============================================================================
2 //============================================================================
3 // Cell
3 // Cell
4 //============================================================================
4 //============================================================================
5
5
6 var IPython = (function (IPython) {
6 var IPython = (function (IPython) {
7
7
8 var utils = IPython.utils;
8 var utils = IPython.utils;
9
9
10 // Base PanelSection class
10 // Base PanelSection class
11
11
12 var PanelSection = function (selector) {
12 var PanelSection = function (selector) {
13 this.selector = selector;
13 this.selector = selector;
14 if (this.selector !== undefined) {
14 if (this.selector !== undefined) {
15 this.element = $(selector);
15 this.element = $(selector);
16 this.header = this.element.find('h3.section_header');
16 this.header = this.element.find('h3.section_header');
17 this.content = this.element.find('div.section_content');
17 this.content = this.element.find('div.section_content');
18 this.style();
18 this.style();
19 this.bind_events();
19 this.bind_events();
20 }
20 }
21 this.expanded = true;
21 this.expanded = true;
22 };
22 };
23
23
24
24
25 PanelSection.prototype.style = function () {
25 PanelSection.prototype.style = function () {
26 this.header.addClass('ui-widget ui-state-default');
26 this.header.addClass('ui-widget ui-state-default');
27 this.content.addClass('ui-widget section_content');
27 this.content.addClass('ui-widget section_content');
28 };
28 };
29
29
30
30
31 PanelSection.prototype.bind_events = function () {
31 PanelSection.prototype.bind_events = function () {
32 var that = this;
32 var that = this;
33 this.header.click(function () {
33 this.header.click(function () {
34 that.toggle();
34 that.toggle();
35 });
35 });
36 this.header.hover(function () {
36 this.header.hover(function () {
37 that.header.toggleClass('ui-state-hover');
37 that.header.toggleClass('ui-state-hover');
38 });
38 });
39 };
39 };
40
40
41
41
42 PanelSection.prototype.expand = function () {
42 PanelSection.prototype.expand = function () {
43 if (!this.expanded) {
43 if (!this.expanded) {
44 this.content.slideDown('fast');
44 this.content.slideDown('fast');
45 this.expanded = true;
45 this.expanded = true;
46 };
46 };
47 };
47 };
48
48
49
49
50 PanelSection.prototype.collapse = function () {
50 PanelSection.prototype.collapse = function () {
51 if (this.expanded) {
51 if (this.expanded) {
52 this.content.slideUp('fast');
52 this.content.slideUp('fast');
53 this.expanded = false;
53 this.expanded = false;
54 };
54 };
55 };
55 };
56
56
57
57
58 PanelSection.prototype.toggle = function () {
58 PanelSection.prototype.toggle = function () {
59 if (this.expanded === true) {
59 if (this.expanded === true) {
60 this.collapse();
60 this.collapse();
61 } else {
61 } else {
62 this.expand();
62 this.expand();
63 };
63 };
64 };
64 };
65
65
66
66
67 PanelSection.prototype.create_children = function () {};
67 PanelSection.prototype.create_children = function () {};
68
68
69
69
70 // NotebookSection
70 // NotebookSection
71
71
72 var NotebookSection = function () {
72 var NotebookSection = function () {
73 PanelSection.apply(this, arguments);
73 PanelSection.apply(this, arguments);
74 };
74 };
75
75
76
76
77 NotebookSection.prototype = new PanelSection();
77 NotebookSection.prototype = new PanelSection();
78
78
79
79
80 NotebookSection.prototype.style = function () {
80 NotebookSection.prototype.style = function () {
81 PanelSection.prototype.style.apply(this);
81 PanelSection.prototype.style.apply(this);
82 this.content.addClass('ui-helper-clearfix');
82 this.content.addClass('ui-helper-clearfix');
83 this.content.find('div.section_row').addClass('ui-helper-clearfix');
83 this.content.find('div.section_row').addClass('ui-helper-clearfix');
84 this.content.find('#new_open').buttonset();
84 this.content.find('#new_open').buttonset();
85 this.content.find('#download_notebook').button();
85 this.content.find('#download_notebook').button();
86 this.content.find('#upload_notebook').button();
86 this.content.find('#upload_notebook').button();
87 this.content.find('#download_format').addClass('ui-widget ui-widget-content');
87 this.content.find('#download_format').addClass('ui-widget ui-widget-content');
88 this.content.find('#download_format option').addClass('ui-widget ui-widget-content');
88 this.content.find('#download_format option').addClass('ui-widget ui-widget-content');
89 };
89 };
90
90
91
91
92 NotebookSection.prototype.bind_events = function () {
92 NotebookSection.prototype.bind_events = function () {
93 PanelSection.prototype.bind_events.apply(this);
93 PanelSection.prototype.bind_events.apply(this);
94 var that = this;
94 var that = this;
95 this.content.find('#new_notebook').click(function () {
95 this.content.find('#new_notebook').click(function () {
96 window.open('/new');
96 window.open('/new');
97 });
97 });
98 this.content.find('#open_notebook').click(function () {
98 this.content.find('#open_notebook').click(function () {
99 window.open('/');
99 window.open('/');
100 });
100 });
101 this.content.find('#download_notebook').click(function () {
101 this.content.find('#download_notebook').click(function () {
102 var format = that.content.find('#download_format').val();
102 var format = that.content.find('#download_format').val();
103 var notebook_id = IPython.save_widget.get_notebook_id();
103 var notebook_id = IPython.save_widget.get_notebook_id();
104 var url = '/notebooks/' + notebook_id + '?format=' + format;
104 var url = '/notebooks/' + notebook_id + '?format=' + format;
105 window.open(url,'_newtab');
105 window.open(url,'_newtab');
106 });
106 });
107 };
107 };
108
108
109 // CellSection
109 // CellSection
110
110
111 var CellSection = function () {
111 var CellSection = function () {
112 PanelSection.apply(this, arguments);
112 PanelSection.apply(this, arguments);
113 };
113 };
114
114
115
115
116 CellSection.prototype = new PanelSection();
116 CellSection.prototype = new PanelSection();
117
117
118
118
119 CellSection.prototype.style = function () {
119 CellSection.prototype.style = function () {
120 PanelSection.prototype.style.apply(this);
120 PanelSection.prototype.style.apply(this);
121 this.content.addClass('ui-helper-clearfix');
121 this.content.addClass('ui-helper-clearfix');
122 this.content.find('div.section_row').addClass('ui-helper-clearfix');
122 this.content.find('div.section_row').addClass('ui-helper-clearfix');
123 this.content.find('#delete_cell').button();
123 this.content.find('#delete_cell').button();
124 this.content.find('#insert').buttonset();
124 this.content.find('#insert').buttonset();
125 this.content.find('#move').buttonset();
125 this.content.find('#move').buttonset();
126 this.content.find('#cell_type').buttonset();
126 this.content.find('#cell_type').buttonset();
127 this.content.find('#toggle_output').buttonset();
127 this.content.find('#toggle_output').buttonset();
128 this.content.find('#run_cells').buttonset();
128 this.content.find('#run_cells').buttonset();
129 };
129 };
130
130
131
131
132 CellSection.prototype.bind_events = function () {
132 CellSection.prototype.bind_events = function () {
133 PanelSection.prototype.bind_events.apply(this);
133 PanelSection.prototype.bind_events.apply(this);
134 this.content.find('#collapse_cell').click(function () {
134 this.content.find('#collapse_cell').click(function () {
135 IPython.notebook.collapse();
135 IPython.notebook.collapse();
136 });
136 });
137 this.content.find('#expand_cell').click(function () {
137 this.content.find('#expand_cell').click(function () {
138 IPython.notebook.expand();
138 IPython.notebook.expand();
139 });
139 });
140 this.content.find('#delete_cell').click(function () {
140 this.content.find('#delete_cell').click(function () {
141 IPython.notebook.delete_cell();
141 IPython.notebook.delete_cell();
142 });
142 });
143 this.content.find('#insert_cell_above').click(function () {
143 this.content.find('#insert_cell_above').click(function () {
144 IPython.notebook.insert_code_cell_before();
144 IPython.notebook.insert_code_cell_before();
145 });
145 });
146 this.content.find('#insert_cell_below').click(function () {
146 this.content.find('#insert_cell_below').click(function () {
147 IPython.notebook.insert_code_cell_after();
147 IPython.notebook.insert_code_cell_after();
148 });
148 });
149 this.content.find('#move_cell_up').click(function () {
149 this.content.find('#move_cell_up').click(function () {
150 IPython.notebook.move_cell_up();
150 IPython.notebook.move_cell_up();
151 });
151 });
152 this.content.find('#move_cell_down').click(function () {
152 this.content.find('#move_cell_down').click(function () {
153 IPython.notebook.move_cell_down();
153 IPython.notebook.move_cell_down();
154 });
154 });
155 this.content.find('#to_code').click(function () {
155 this.content.find('#to_code').click(function () {
156 IPython.notebook.html_to_code();
156 IPython.notebook.to_code();
157 });
157 });
158 this.content.find('#to_html').click(function () {
158 this.content.find('#to_html').click(function () {
159 IPython.notebook.code_to_html();
159 IPython.notebook.to_html();
160 });
161 this.content.find('#to_rst').click(function () {
162 IPython.notebook.to_rst();
160 });
163 });
161 this.content.find('#run_selected_cell').click(function () {
164 this.content.find('#run_selected_cell').click(function () {
162 IPython.notebook.execute_selected_cell();
165 IPython.notebook.execute_selected_cell();
163 });
166 });
164 this.content.find('#run_all_cells').click(function () {
167 this.content.find('#run_all_cells').click(function () {
165 IPython.notebook.execute_all_cells();
168 IPython.notebook.execute_all_cells();
166 });
169 });
167 };
170 };
168
171
169
172
170 // KernelSection
173 // KernelSection
171
174
172 var KernelSection = function () {
175 var KernelSection = function () {
173 PanelSection.apply(this, arguments);
176 PanelSection.apply(this, arguments);
174 };
177 };
175
178
176
179
177 KernelSection.prototype = new PanelSection();
180 KernelSection.prototype = new PanelSection();
178
181
179
182
180 KernelSection.prototype.style = function () {
183 KernelSection.prototype.style = function () {
181 PanelSection.prototype.style.apply(this);
184 PanelSection.prototype.style.apply(this);
182 this.content.addClass('ui-helper-clearfix');
185 this.content.addClass('ui-helper-clearfix');
183 this.content.find('div.section_row').addClass('ui-helper-clearfix');
186 this.content.find('div.section_row').addClass('ui-helper-clearfix');
184 this.content.find('#int_restart').buttonset();
187 this.content.find('#int_restart').buttonset();
185 };
188 };
186
189
187
190
188 KernelSection.prototype.bind_events = function () {
191 KernelSection.prototype.bind_events = function () {
189 PanelSection.prototype.bind_events.apply(this);
192 PanelSection.prototype.bind_events.apply(this);
190 this.content.find('#restart_kernel').click(function () {
193 this.content.find('#restart_kernel').click(function () {
191 IPython.notebook.kernel.restart();
194 IPython.notebook.kernel.restart();
192 });
195 });
193 this.content.find('#int_kernel').click(function () {
196 this.content.find('#int_kernel').click(function () {
194 IPython.notebook.kernel.interrupt();
197 IPython.notebook.kernel.interrupt();
195 });
198 });
196 };
199 };
197
200
198
201
199 // HelpSection
202 // HelpSection
200
203
201 var HelpSection = function () {
204 var HelpSection = function () {
202 PanelSection.apply(this, arguments);
205 PanelSection.apply(this, arguments);
203 };
206 };
204
207
205
208
206 HelpSection.prototype = new PanelSection();
209 HelpSection.prototype = new PanelSection();
207
210
208
211
209 HelpSection.prototype.style = function () {
212 HelpSection.prototype.style = function () {
210 PanelSection.prototype.style.apply(this);
213 PanelSection.prototype.style.apply(this);
211 PanelSection.prototype.style.apply(this);
214 PanelSection.prototype.style.apply(this);
212 this.content.addClass('ui-helper-clearfix');
215 this.content.addClass('ui-helper-clearfix');
213 this.content.find('div.section_row').addClass('ui-helper-clearfix');
216 this.content.find('div.section_row').addClass('ui-helper-clearfix');
214 this.content.find('#help_buttons0').buttonset();
217 this.content.find('#help_buttons0').buttonset();
215 this.content.find('#help_buttons1').buttonset();
218 this.content.find('#help_buttons1').buttonset();
216 };
219 };
217
220
218
221
219 HelpSection.prototype.bind_events = function () {
222 HelpSection.prototype.bind_events = function () {
220 PanelSection.prototype.bind_events.apply(this);
223 PanelSection.prototype.bind_events.apply(this);
221 };
224 };
222
225
223
226
224 // Set module variables
227 // Set module variables
225
228
226 IPython.PanelSection = PanelSection;
229 IPython.PanelSection = PanelSection;
227 IPython.NotebookSection = NotebookSection;
230 IPython.NotebookSection = NotebookSection;
228 IPython.CellSection = CellSection;
231 IPython.CellSection = CellSection;
229 IPython.KernelSection = KernelSection;
232 IPython.KernelSection = KernelSection;
230 IPython.HelpSection = HelpSection;
233 IPython.HelpSection = HelpSection;
231
234
232 return IPython;
235 return IPython;
233
236
234 }(IPython));
237 }(IPython));
235
238
@@ -1,201 +1,204 b''
1 <!DOCTYPE HTML>
1 <!DOCTYPE HTML>
2 <html>
2 <html>
3
3
4 <head>
4 <head>
5 <meta charset="utf-8">
5 <meta charset="utf-8">
6
6
7 <title>IPython Notebook</title>
7 <title>IPython Notebook</title>
8
8
9 <link rel="stylesheet" href="static/jquery/css/themes/aristo/jquery-wijmo.css" type="text/css" />
9 <link rel="stylesheet" href="static/jquery/css/themes/aristo/jquery-wijmo.css" type="text/css" />
10 <!-- <link rel="stylesheet" href="static/jquery/css/themes/rocket/jquery-wijmo.css" type="text/css" /> -->
10 <!-- <link rel="stylesheet" href="static/jquery/css/themes/rocket/jquery-wijmo.css" type="text/css" /> -->
11 <!-- <link rel="stylesheet" href="static/jquery/css/themes/smoothness/jquery-ui-1.8.14.custom.css" type="text/css" />-->
11 <!-- <link rel="stylesheet" href="static/jquery/css/themes/smoothness/jquery-ui-1.8.14.custom.css" type="text/css" />-->
12
12
13 <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML" charset="utf-8"></script>
13 <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML" charset="utf-8"></script>
14 <!-- <script type='text/javascript' src='static/mathjax/MathJax.js?config=TeX-AMS_HTML' charset='utf-8'></script> -->
14 <!-- <script type='text/javascript' src='static/mathjax/MathJax.js?config=TeX-AMS_HTML' charset='utf-8'></script> -->
15 <script type="text/javascript">
15 <script type="text/javascript">
16 if (typeof MathJax == 'undefined') {
16 if (typeof MathJax == 'undefined') {
17 console.log("Trying to load local copy of MathJax");
17 console.log("Trying to load local copy of MathJax");
18 document.write(unescape("%3Cscript type='text/javascript' src='static/mathjax/MathJax.js%3Fconfig=TeX-AMS_HTML' charset='utf-8'%3E%3C/script%3E"));
18 document.write(unescape("%3Cscript type='text/javascript' src='static/mathjax/MathJax.js%3Fconfig=TeX-AMS_HTML' charset='utf-8'%3E%3C/script%3E"));
19 }
19 }
20 </script>
20 </script>
21
21
22 <link rel="stylesheet" href="static/codemirror-2.12/lib/codemirror.css">
22 <link rel="stylesheet" href="static/codemirror-2.12/lib/codemirror.css">
23 <link rel="stylesheet" href="static/codemirror-2.12/mode/rst/rst.css">
23 <link rel="stylesheet" href="static/codemirror-2.12/mode/rst/rst.css">
24 <link rel="stylesheet" href="static/codemirror-2.12/theme/ipython.css">
24 <link rel="stylesheet" href="static/codemirror-2.12/theme/ipython.css">
25 <link rel="stylesheet" href="static/codemirror-2.12/theme/default.css">
25 <link rel="stylesheet" href="static/codemirror-2.12/theme/default.css">
26
26
27 <link rel="stylesheet" href="static/css/boilerplate.css" type="text/css" />
27 <link rel="stylesheet" href="static/css/boilerplate.css" type="text/css" />
28 <link rel="stylesheet" href="static/css/layout.css" type="text/css" />
28 <link rel="stylesheet" href="static/css/layout.css" type="text/css" />
29 <link rel="stylesheet" href="static/css/base.css" type="text/css" />
29 <link rel="stylesheet" href="static/css/base.css" type="text/css" />
30 <link rel="stylesheet" href="static/css/notebook.css" type="text/css" />
30 <link rel="stylesheet" href="static/css/notebook.css" type="text/css" />
31
31
32 </head>
32 </head>
33
33
34 <body>
34 <body>
35
35
36 <div id="header">
36 <div id="header">
37 <span id="ipython_notebook"><h1>IPython Notebook</h1></span>
37 <span id="ipython_notebook"><h1>IPython Notebook</h1></span>
38 <span id="save_widget">
38 <span id="save_widget">
39 <input type="text" id="notebook_name" size="20"></textarea>
39 <input type="text" id="notebook_name" size="20"></textarea>
40 <span id="notebook_id" style="display:none">{{notebook_id}}</span>
40 <span id="notebook_id" style="display:none">{{notebook_id}}</span>
41 <button id="save_notebook">Save</button>
41 <button id="save_notebook">Save</button>
42 </span>
42 </span>
43 <span id="kernel_status">Idle</span>
43 <span id="kernel_status">Idle</span>
44 </div>
44 </div>
45
45
46 <div id="main_app">
46 <div id="main_app">
47
47
48 <div id="left_panel">
48 <div id="left_panel">
49
49
50 <div id="notebook_section">
50 <div id="notebook_section">
51 <h3 class="section_header">Notebook</h3>
51 <h3 class="section_header">Notebook</h3>
52 <div class="section_content">
52 <div class="section_content">
53 <div class="section_row">
53 <div class="section_row">
54 <span id="new_open" class="section_row_buttons">
54 <span id="new_open" class="section_row_buttons">
55 <button id="new_notebook">New</button>
55 <button id="new_notebook">New</button>
56 <button id="open_notebook">Open</button>
56 <button id="open_notebook">Open</button>
57 </span>
57 </span>
58 <span class="section_row_header">Actions</span>
58 <span class="section_row_header">Actions</span>
59 </div>
59 </div>
60 <div class="section_row">
60 <div class="section_row">
61 <span class="section_row_buttons">
61 <span class="section_row_buttons">
62 <button id="download_notebook">Export</button>
62 <button id="download_notebook">Export</button>
63 </span>
63 </span>
64 <span>
64 <span>
65 <select id="download_format">
65 <select id="download_format">
66 <option value="xml">xml</option>
66 <option value="xml">xml</option>
67 <option value="json">json</option>
67 <option value="json">json</option>
68 <option value="py">py</option>
68 <option value="py">py</option>
69 </select>
69 </select>
70 </span>
70 </span>
71 </div>
71 </div>
72 </div>
72 </div>
73 </div>
73 </div>
74
74
75 <div id="cell_section">
75 <div id="cell_section">
76 <h3 class="section_header">Cell</h3>
76 <h3 class="section_header">Cell</h3>
77 <div class="section_content">
77 <div class="section_content">
78 <div class="section_row">
78 <div class="section_row">
79 <span class="section_row_buttons">
79 <span class="section_row_buttons">
80 <button id="delete_cell">Delete</button>
80 <button id="delete_cell">Delete</button>
81 </span>
81 </span>
82 <span class="section_row_header">Actions</span>
82 <span class="section_row_header">Actions</span>
83 </div>
83 </div>
84 <div class="section_row">
84 <div class="section_row">
85 <span id="insert" class="section_row_buttons">
85 <span id="insert" class="section_row_buttons">
86 <button id="insert_cell_above">Above</button>
86 <button id="insert_cell_above">Above</button>
87 <button id="insert_cell_below">Below</button>
87 <button id="insert_cell_below">Below</button>
88 </span>
88 </span>
89 <span class="button_label">Insert</span>
89 <span class="button_label">Insert</span>
90 </div>
90 </div>
91 <div class="section_row">
91 <div class="section_row">
92 <span id="move" class="section_row_buttons">
92 <span id="move" class="section_row_buttons">
93 <button id="move_cell_up">Up</button>
93 <button id="move_cell_up">Up</button>
94 <button id="move_cell_down">Down</button>
94 <button id="move_cell_down">Down</button>
95 </span>
95 </span>
96 <span class="button_label">Move</span>
96 <span class="button_label">Move</span>
97 </div>
97 </div>
98 <div class="section_row">
98 <div class="section_row">
99 <span id="cell_type" class="section_row_buttons">
99 <span id="cell_type" class="section_row_buttons">
100 <button id="to_code">Code</button>
100 <button id="to_code">Code</button>
101 <button id="to_html">HTML</button>
101 <button id="to_html">HTML</button>
102 <button id="to_rst">RST</button>
102 </span>
103 </span>
103 <span class="button_label">Cell Type</span>
104 <span class="button_label">Format</span>
104 </div>
105 </div>
105 <div class="section_row">
106 <div class="section_row">
106 <span id="toggle_output" class="section_row_buttons">
107 <span id="toggle_output" class="section_row_buttons">
107 <button id="collapse_cell">Collapse</button>
108 <button id="collapse_cell">Collapse</button>
108 <button id="expand_cell">Expand</button>
109 <button id="expand_cell">Expand</button>
109 </span>
110 </span>
110 <span class="button_label">Output</span>
111 <span class="button_label">Output</span>
111 </div>
112 </div>
112 <div class="section_row">
113 <div class="section_row">
113 <span id="run_cells" class="section_row_buttons">
114 <span id="run_cells" class="section_row_buttons">
114 <button id="run_selected_cell">Selected</button>
115 <button id="run_selected_cell">Selected</button>
115 <button id="run_all_cells">All</button>
116 <button id="run_all_cells">All</button>
116 </span>
117 </span>
117 <span class="button_label">Run</span>
118 <span class="button_label">Run</span>
118 </div>
119 </div>
119 </div>
120 </div>
120 </div>
121 </div>
121
122
122 <div id="kernel_section">
123 <div id="kernel_section">
123 <h3 class="section_header">Kernel</h3>
124 <h3 class="section_header">Kernel</h3>
124 <div class="section_content">
125 <div class="section_content">
125 <div class="section_row">
126 <div class="section_row">
126 <span id="int_restart" class="section_row_buttons">
127 <span id="int_restart" class="section_row_buttons">
127 <button id="int_kernel">Interrupt</button>
128 <button id="int_kernel">Interrupt</button>
128 <button id="restart_kernel">Restart</button>
129 <button id="restart_kernel">Restart</button>
129 </span>
130 </span>
130 <span class="section_row_header">Actions</span>
131 <span class="section_row_header">Actions</span>
131 </div>
132 </div>
132 <div class="section_row">
133 <div class="section_row">
133 <span id="kernel_persist">
134 <span id="kernel_persist">
134 <input type="checkbox" id="kill_kernel"></input>
135 <input type="checkbox" id="kill_kernel"></input>
135 </span>
136 </span>
136 <span class="checkbox_label">Kill kernel upon exit:</span>
137 <span class="checkbox_label">Kill kernel upon exit:</span>
137 </div>
138 </div>
138 </div>
139 </div>
139 </div>
140 </div>
140
141
141 <div id="help_section">
142 <div id="help_section">
142 <h3 class="section_header">Help</h3>
143 <h3 class="section_header">Help</h3>
143 <div class="section_content">
144 <div class="section_content">
144 <div class="section_row">
145 <div class="section_row">
145 <span id="help_buttons0" class="section_row_buttons">
146 <span id="help_buttons0" class="section_row_buttons">
146 <button id="python_help"><a href="http://docs.python.org" target="_blank">Python</a></button>
147 <button id="python_help"><a href="http://docs.python.org" target="_blank">Python</a></button>
147 <button id="ipython_help"><a href="http://ipython.org/documentation.html" target="_blank">IPython</a></button>
148 <button id="ipython_help"><a href="http://ipython.org/documentation.html" target="_blank">IPython</a></button>
148 <button id="numpy_help"><a href="http://docs.scipy.org/doc/numpy/reference/" target="_blank">NumPy</a></button>
149 <button id="numpy_help"><a href="http://docs.scipy.org/doc/numpy/reference/" target="_blank">NumPy</a></button>
149 </span>
150 </span>
150 <span class="section_row_header">Links</span>
151 <span class="section_row_header">Links</span>
151 </div>
152 </div>
152 <div class="section_row">
153 <div class="section_row">
153 <span id="help_buttons1" class="section_row_buttons">
154 <span id="help_buttons1" class="section_row_buttons">
154 <button id="matplotlib_help"><a href="http://matplotlib.sourceforge.net/" target="_blank">MPL</a></button>
155 <button id="matplotlib_help"><a href="http://matplotlib.sourceforge.net/" target="_blank">MPL</a></button>
155 <button id="scipy_help"><a href="http://docs.scipy.org/doc/scipy/reference/" target="_blank">SciPy</a></button>
156 <button id="scipy_help"><a href="http://docs.scipy.org/doc/scipy/reference/" target="_blank">SciPy</a></button>
156 <button id="sympy_help"><a href="http://docs.sympy.org/dev/index.html" target="_blank">SymPy</a></button>
157 <button id="sympy_help"><a href="http://docs.sympy.org/dev/index.html" target="_blank">SymPy</a></button>
157 </span>
158 </span>
158 </div>
159 </div>
159 </div>
160 </div>
160 </div>
161 </div>
161
162
162 </div>
163 </div>
163 <div id="left_panel_splitter"></div>
164 <div id="left_panel_splitter"></div>
164 <div id="notebook_panel">
165 <div id="notebook_panel">
165 <div id="notebook"></div>
166 <div id="notebook"></div>
166 <div id="pager_splitter"></div>
167 <div id="pager_splitter"></div>
167 <div id="pager"></div>
168 <div id="pager"></div>
168 </div>
169 </div>
169
170
170 </div>
171 </div>
171
172
172 <script src="static/jquery/js/jquery-1.6.2.min.js" type="text/javascript" charset="utf-8"></script>
173 <script src="static/jquery/js/jquery-1.6.2.min.js" type="text/javascript" charset="utf-8"></script>
173 <script src="static/jquery/js/jquery-ui-1.8.14.custom.min.js" type="text/javascript" charset="utf-8"></script>
174 <script src="static/jquery/js/jquery-ui-1.8.14.custom.min.js" type="text/javascript" charset="utf-8"></script>
174 <script src="static/jquery/js/jquery.autogrow.js" type="text/javascript" charset="utf-8"></script>
175 <script src="static/jquery/js/jquery.autogrow.js" type="text/javascript" charset="utf-8"></script>
175 <script src="static/js/namespace.js" type="text/javascript" charset="utf-8"></script>
176 <script src="static/js/namespace.js" type="text/javascript" charset="utf-8"></script>
176 <script src="static/js/utils.js" type="text/javascript" charset="utf-8"></script>
177 <script src="static/js/utils.js" type="text/javascript" charset="utf-8"></script>
177 <script src="static/js/cell.js" type="text/javascript" charset="utf-8"></script>
178 <script src="static/js/cell.js" type="text/javascript" charset="utf-8"></script>
178 <script src="static/js/codecell.js" type="text/javascript" charset="utf-8"></script>
179 <script src="static/js/codecell.js" type="text/javascript" charset="utf-8"></script>
179 <script src="static/js/htmlcell.js" type="text/javascript" charset="utf-8"></script>
180 <script src="static/js/htmlcell.js" type="text/javascript" charset="utf-8"></script>
181 <script src="static/js/rstcell.js" type="text/javascript" charset="utf-8"></script>
180 <script src="static/js/kernel.js" type="text/javascript" charset="utf-8"></script>
182 <script src="static/js/kernel.js" type="text/javascript" charset="utf-8"></script>
181 <script src="static/js/kernelstatus.js" type="text/javascript" charset="utf-8"></script>
183 <script src="static/js/kernelstatus.js" type="text/javascript" charset="utf-8"></script>
182 <script src="static/js/layout.js" type="text/javascript" charset="utf-8"></script>
184 <script src="static/js/layout.js" type="text/javascript" charset="utf-8"></script>
183 <script src="static/js/savewidget.js" type="text/javascript" charset="utf-8"></script>
185 <script src="static/js/savewidget.js" type="text/javascript" charset="utf-8"></script>
184 <script src="static/js/pager.js" type="text/javascript" charset="utf-8"></script>
186 <script src="static/js/pager.js" type="text/javascript" charset="utf-8"></script>
185 <script src="static/js/panelsection.js" type="text/javascript" charset="utf-8"></script>
187 <script src="static/js/panelsection.js" type="text/javascript" charset="utf-8"></script>
186 <script src="static/js/leftpanel.js" type="text/javascript" charset="utf-8"></script>
188 <script src="static/js/leftpanel.js" type="text/javascript" charset="utf-8"></script>
187 <script src="static/js/notebook.js" type="text/javascript" charset="utf-8"></script>
189 <script src="static/js/notebook.js" type="text/javascript" charset="utf-8"></script>
188 <script src="static/js/notebook_main.js" type="text/javascript" charset="utf-8"></script>
190 <script src="static/js/notebook_main.js" type="text/javascript" charset="utf-8"></script>
189 <script src="static/codemirror-2.12/lib/codemirror.js"></script>
191 <script src="static/codemirror-2.12/lib/codemirror.js" charset="utf-8"></script>
190 <script src="static/codemirror-2.12/mode/python/python.js"></script>
192 <script src="static/codemirror-2.12/mode/python/python.js" charset="utf-8"></script>
191 <script src="static/codemirror-2.12/mode/htmlmixed/htmlmixed.js"></script>
193 <script src="static/codemirror-2.12/mode/htmlmixed/htmlmixed.js" charset="utf-8"></script>
192 <script src="static/codemirror-2.12/mode/xml/xml.js"></script>
194 <script src="static/codemirror-2.12/mode/xml/xml.js" charset="utf-8"></script>
193 <script src="static/codemirror-2.12/mode/javascript/javascript.js"></script>
195 <script src="static/codemirror-2.12/mode/javascript/javascript.js" charset="utf-8"></script>
194 <script src="static/codemirror-2.12/mode/css/css.js"></script>
196 <script src="static/codemirror-2.12/mode/css/css.js" charset="utf-8"></script>
195 <script src="static/codemirror-2.12/mode/rst/rst.js"></script>
197 <script src="static/codemirror-2.12/mode/rst/rst.js" charset="utf-8"></script>
198 <script src="static/pagedown/Markdown.Converter.js" charset="utf-8"></script>
196
199
197 </body>
200 </body>
198
201
199 </html>
202 </html>
200
203
201
204
General Comments 0
You need to be logged in to leave comments. Login now