##// END OF EJS Templates
smart kwarg completion...
Matthias BUSSONNIER -
Show More
@@ -1,392 +1,396 b''
1 1 /**
2 2 * Primary styles
3 3 *
4 4 * Author: IPython Development Team
5 5 */
6 6
7 7
8 8 body {
9 9 background-color: white;
10 10 /* This makes sure that the body covers the entire window and needs to
11 11 be in a different element than the display: box in wrapper below */
12 12 position: absolute;
13 13 left: 0px;
14 14 right: 0px;
15 15 top: 0px;
16 16 bottom: 0px;
17 17 overflow: hidden;
18 18 }
19 19
20 20 span#save_widget {
21 21 position: static;
22 22 left: 0px;
23 23 padding: 5px 0px;
24 24 margin: 0px 0px 0px 0px;
25 25 }
26 26
27 27 span#quick_help_area {
28 28 position: static;
29 29 padding: 5px 0px;
30 30 margin: 0px 0px 0px 0px;
31 31 }
32 32
33 33 input#notebook_name {
34 34 height: 1em;
35 35 line-height: 1em;
36 36 padding: 5px;
37 37 }
38 38
39 39 span#kernel_status {
40 40 position: absolute;
41 41 padding: 8px 5px 5px 5px;
42 42 right: 10px;
43 43 font-weight: bold;
44 44 }
45 45
46 46
47 47 .status_idle {
48 48 color: gray;
49 49 visibility: hidden;
50 50 }
51 51
52 52 .status_busy {
53 53 color: red;
54 54 }
55 55
56 56 .status_restarting {
57 57 color: black;
58 58 }
59 59
60 60 div#left_panel {
61 61 overflow-y: auto;
62 62 top: 0px;
63 63 left: 0px;
64 64 margin: 0px;
65 65 padding: 0px;
66 66 position: absolute;
67 67 }
68 68
69 69 div.section_header {
70 70 padding: 5px;
71 71 }
72 72
73 73 div.section_header h3 {
74 74 display: inline;
75 75 }
76 76
77 77 div.section_content {
78 78 padding: 5px;
79 79 }
80 80
81 81 span.section_row_buttons button {
82 82 width: 70px;
83 83 }
84 84
85 85 span.section_row_buttons a {
86 86 width: 70px;
87 87 }
88 88
89 89 .section_row {
90 90 margin: 5px 0px;
91 91 }
92 92
93 93 .section_row_buttons {
94 94 float: right;
95 95 }
96 96
97 97 #kernel_persist {
98 98 float: right;
99 99 }
100 100
101 101 .help_string {
102 102 float: right;
103 103 width: 170px;
104 104 padding: 0px 5px;
105 105 text-align: left;
106 106 font-size: 85%;
107 107 }
108 108
109 109 .help_string_label {
110 110 float: right;
111 111 font-size: 85%;
112 112 }
113 113
114 114 #autoindent_span {
115 115 float: right;
116 116 }
117 117
118 118 #tooltipontab_span {
119 119 float: right;
120 120 }
121 121
122 #smartcompleter_span {
123 float: right;
124 }
125
122 126 .checkbox_label {
123 127 font-size: 85%;
124 128 float: right;
125 129 padding: 0.3em;
126 130 }
127 131
128 132 .section_row_header {
129 133 float: left;
130 134 font-size: 85%;
131 135 padding: 0.4em 0em;
132 136 font-weight: bold;
133 137 }
134 138
135 139 span.button_label {
136 140 padding: 0.2em 1em;
137 141 font-size: 77%;
138 142 float: right;
139 143 }
140 144
141 145 /* This is needed because FF was adding a 2px margin top and bottom. */
142 146 .section_row .ui-button {
143 147 margin-top: 0px;
144 148 margin-bottom: 0px;
145 149 }
146 150
147 151 #download_format {
148 152 float: right;
149 153 font-size: 85%;
150 154 width: 62px;
151 155 margin: 1px 5px;
152 156 }
153 157
154 158 div#left_panel_splitter {
155 159 width: 8px;
156 160 top: 0px;
157 161 left: 202px;
158 162 margin: 0px;
159 163 padding: 0px;
160 164 position: absolute;
161 165 }
162 166
163 167 div#notebook_panel {
164 168 /* The L margin will be set in the Javascript code*/
165 169 margin: 0px 0px 0px 0px;
166 170 padding: 0px;
167 171 }
168 172
169 173 div#notebook {
170 174 overflow-y: scroll;
171 175 overflow-x: auto;
172 176 width: 100%;
173 177 /* This spaces the cell away from the edge of the notebook area */
174 178 padding: 5px 5px 15px 5px;
175 179 margin: 0px
176 180 background-color: white;
177 181 }
178 182
179 183 div#pager_splitter {
180 184 height: 8px;
181 185 }
182 186
183 187 div#pager {
184 188 padding: 15px;
185 189 overflow: auto;
186 190 }
187 191
188 192 div.cell {
189 193 width: 100%;
190 194 padding: 5px 5px 5px 0px;
191 195 /* This acts as a spacer between cells, that is outside the border */
192 196 margin: 2px 0px 2px 0px;
193 197 }
194 198
195 199 div.code_cell {
196 200 background-color: white;
197 201 }
198 202 /* any special styling for code cells that are currently running goes here */
199 203 div.code_cell.running {
200 204 }
201 205
202 206 div.prompt {
203 207 /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */
204 208 width: 11ex;
205 209 /* This 0.4em is tuned to match the padding on the CodeMirror editor. */
206 210 padding: 0.4em;
207 211 margin: 0px;
208 212 font-family: monospace;
209 213 text-align:right;
210 214 }
211 215
212 216 div.input {
213 217 page-break-inside: avoid;
214 218 }
215 219
216 220 /* input_area and input_prompt must match in top border and margin for alignment */
217 221 div.input_area {
218 222 color: black;
219 223 border: 1px solid #ddd;
220 224 border-radius: 3px;
221 225 background: #f7f7f7;
222 226 }
223 227
224 228 div.input_prompt {
225 229 color: navy;
226 230 border-top: 1px solid transparent;
227 231 }
228 232
229 233 div.output {
230 234 /* This is a spacer between the input and output of each cell */
231 235 margin-top: 5px;
232 236 }
233 237
234 238 div.output_prompt {
235 239 color: darkred;
236 240 }
237 241
238 242 /* This class is the outer container of all output sections. */
239 243 div.output_area {
240 244 padding: 0px;
241 245 page-break-inside: avoid;
242 246 }
243 247
244 248 /* This class is for the output subarea inside the output_area and after
245 249 the prompt div. */
246 250 div.output_subarea {
247 251 padding: 0.4em 6.1em 0.4em 0.4em;
248 252 }
249 253
250 254 /* The rest of the output_* classes are for special styling of the different
251 255 output types */
252 256
253 257 /* all text output has this class: */
254 258 div.output_text {
255 259 text-align: left;
256 260 color: black;
257 261 font-family: monospace;
258 262 }
259 263
260 264 /* stdout/stderr are 'text' as well as 'stream', but pyout/pyerr are *not* streams */
261 265 div.output_stream {
262 266 padding-top: 0.0em;
263 267 padding-bottom: 0.0em;
264 268 }
265 269 div.output_stdout {
266 270 }
267 271 div.output_stderr {
268 272 background: #fdd; /* very light red background for stderr */
269 273 }
270 274
271 275 div.output_latex {
272 276 text-align: left;
273 277 color: black;
274 278 }
275 279
276 280 div.output_html {
277 281 }
278 282
279 283 div.output_png {
280 284 }
281 285
282 286 div.output_jpeg {
283 287 }
284 288
285 289 div.text_cell {
286 290 background-color: white;
287 291 }
288 292
289 293 div.text_cell_input {
290 294 color: black;
291 295 }
292 296
293 297 div.text_cell_render {
294 298 font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
295 299 outline: none;
296 300 resize: none;
297 301 width: inherit;
298 302 border-style: none;
299 303 padding: 5px;
300 304 color: black;
301 305 }
302 306
303 307 .CodeMirror {
304 308 line-height: 1.231; /* Changed from 1em to our global default */
305 309 }
306 310
307 311 .CodeMirror-scroll {
308 312 height: auto; /* Changed to auto to autogrow */
309 313 /* The CodeMirror docs are a bit fuzzy on if overflow-y should be hidden or visible.*/
310 314 /* We have found that if it is visible, vertical scrollbars appear with font size changes.*/
311 315 overflow-y: hidden;
312 316 overflow-x: auto; /* Changed from auto to remove scrollbar */
313 317 }
314 318
315 319 /* CSS font colors for translated ANSI colors. */
316 320
317 321
318 322 .ansiblack {color: black;}
319 323 .ansired {color: darkred;}
320 324 .ansigreen {color: darkgreen;}
321 325 .ansiyellow {color: brown;}
322 326 .ansiblue {color: darkblue;}
323 327 .ansipurple {color: darkviolet;}
324 328 .ansicyan {color: steelblue;}
325 329 .ansigrey {color: grey;}
326 330 .ansibold {font-weight: bold;}
327 331
328 332 .completions , .tooltip{
329 333 position: absolute;
330 334 z-index: 10;
331 335 overflow: auto;
332 336 border: 1px solid black;
333 337 }
334 338
335 339 .completions select {
336 340 background: white;
337 341 outline: none;
338 342 border: none;
339 343 padding: 0px;
340 344 margin: 0px;
341 345 font-family: monospace;
342 346 }
343 347
344 348 @-moz-keyframes fadeIn {
345 349 from {opacity:0;}
346 350 to {opacity:1;}
347 351 }
348 352
349 353 @-webkit-keyframes fadeIn {
350 354 from {opacity:0;}
351 355 to {opacity:1;}
352 356 }
353 357
354 358 @keyframes fadeIn {
355 359 from {opacity:0;}
356 360 to {opacity:1;}
357 361 }
358 362
359 363
360 364 .tooltip{
361 365 border-radius: 0px 10px 10px 10px;
362 366 box-shadow: 3px 3px 5px #999;
363 367 -webkit-animation: fadeIn 200ms;
364 368 -moz-animation: fadeIn 200ms;
365 369 animation: fadeIn 200ms;
366 370 vertical-align: middle;
367 371 background: #FDFDD8;
368 372 outline: none;
369 373 padding: 3px;
370 374 margin: 0px;
371 375 font-family: monospace;
372 376 }
373 377
374 378 @media print {
375 379 body { overflow: visible !important; }
376 380 .ui-widget-content { border: 0px; }
377 381 }
378 382
379 383 .shortcut_key {
380 384 display: inline-block;
381 385 width: 13ex;
382 386 text-align: right;
383 387 font-family: monospace;
384 388 }
385 389
386 390 .shortcut_descr {
387 391 }
388 392
389 393 /* Word-wrap output correctly. This is the CSS3 spelling, though Firefox seems
390 394 to not honor it correctly. Webkit browsers (Chrome, rekonq, Safari) do.
391 395 */
392 396 pre, code, kbd, samp { white-space: pre-wrap; }
@@ -1,587 +1,600 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2008-2011 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // CodeCell
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13
14 14 var utils = IPython.utils;
15 15
16 16 var CodeCell = function (notebook) {
17 17 this.code_mirror = null;
18 18 this.input_prompt_number = ' ';
19 19 this.is_completing = false;
20 20 this.completion_cursor = null;
21 21 this.outputs = [];
22 22 this.collapsed = false;
23 23 IPython.Cell.apply(this, arguments);
24 24 };
25 25
26 26
27 27 CodeCell.prototype = new IPython.Cell();
28 28
29 29
30 30 CodeCell.prototype.create_element = function () {
31 31 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
32 32 cell.attr('tabindex','2');
33 33 var input = $('<div></div>').addClass('input hbox');
34 34 input.append($('<div/>').addClass('prompt input_prompt'));
35 35 var input_area = $('<div/>').addClass('input_area box-flex1');
36 36 this.code_mirror = CodeMirror(input_area.get(0), {
37 37 indentUnit : 4,
38 38 mode: 'python',
39 39 theme: 'ipython',
40 40 readOnly: this.read_only,
41 41 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
42 42 });
43 43 input.append(input_area);
44 44 var output = $('<div></div>').addClass('output vbox');
45 45 cell.append(input).append(output);
46 46 this.element = cell;
47 47 this.collapse()
48 48 };
49 49
50 50 //TODO, try to diminish the number of parameters.
51 51 CodeCell.prototype.request_tooltip_after_time = function (pre_cursor,time,that){
52 52 if (pre_cursor === "" || pre_cursor === "(" ) {
53 53 // don't do anything if line beggin with '(' or is empty
54 54 } else {
55 55 // Will set a timer to request tooltip in `time`
56 56 that.tooltip_timeout = setTimeout(function(){
57 57 IPython.notebook.request_tool_tip(that, pre_cursor)
58 58 },time);
59 59 }
60 60 };
61 61
62 62 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
63 63 // This method gets called in CodeMirror's onKeyDown/onKeyPress
64 64 // handlers and is used to provide custom key handling. Its return
65 65 // value is used to determine if CodeMirror should ignore the event:
66 66 // true = ignore, false = don't ignore.
67 67
68 68 // note that we are comparing and setting the time to wait at each key press.
69 69 // a better wqy might be to generate a new function on each time change and
70 70 // assign it to CodeCell.prototype.request_tooltip_after_time
71 71 tooltip_wait_time = this.notebook.time_before_tooltip;
72 72 tooltip_on_tab = this.notebook.tooltip_on_tab;
73 73 var that = this;
74 74
75 75 // whatever key is pressed, first, cancel the tooltip request before
76 76 // they are sent, and remove tooltip if any
77 77 if(event.type === 'keydown' && this.tooltip_timeout != null){
78 78 CodeCell.prototype.remove_and_cancell_tooltip(that.tooltip_timeout);
79 79 that.tooltip_timeout=null;
80 80 }
81 81
82 82 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
83 83 // Always ignore shift-enter in CodeMirror as we handle it.
84 84 return true;
85 85 }else if (event.keyCode === 53 && event.type === 'keydown' && tooltip_wait_time >= 0) {
86 86 // Pressing '(' , request tooltip, don't forget to reappend it
87 87 var cursor = editor.getCursor();
88 88 var pre_cursor = editor.getRange({line:cursor.line,ch:0},cursor).trim()+'(';
89 89 CodeCell.prototype.request_tooltip_after_time(pre_cursor,tooltip_wait_time,that);
90 90 } else if (event.keyCode === 9 && event.type == 'keydown') {
91 91 // Tab completion.
92 92 var cur = editor.getCursor();
93 93 //Do not trim here because of tooltip
94 94 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
95 95 if (pre_cursor.trim() === "") {
96 96 // Don't autocomplete if the part of the line before the cursor
97 97 // is empty. In this case, let CodeMirror handle indentation.
98 98 return false;
99 99 } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && tooltip_on_tab ) {
100 100 CodeCell.prototype.request_tooltip_after_time(pre_cursor,0,that);
101 101 } else {
102 102 pre_cursor.trim();
103 103 // Autocomplete the current line.
104 104 event.stop();
105 105 var line = editor.getLine(cur.line);
106 106 this.is_completing = true;
107 107 this.completion_cursor = cur;
108 108 IPython.notebook.complete_cell(this, line, cur.ch);
109 109 return true;
110 110 }
111 111 } else if (event.keyCode === 8 && event.type == 'keydown') {
112 112 // If backspace and the line ends with 4 spaces, remove them.
113 113 var cur = editor.getCursor();
114 114 var line = editor.getLine(cur.line);
115 115 var ending = line.slice(-4);
116 116 if (ending === ' ') {
117 117 editor.replaceRange('',
118 118 {line: cur.line, ch: cur.ch-4},
119 119 {line: cur.line, ch: cur.ch}
120 120 );
121 121 event.stop();
122 122 return true;
123 123 } else {
124 124 return false;
125 125 };
126 126 } else if (event.keyCode === 76 && event.ctrlKey && event.shiftKey
127 127 && event.type == 'keydown') {
128 128 // toggle line numbers with Ctrl-Shift-L
129 129 this.toggle_line_numbers();
130 130 }
131 131 else {
132 132 // keypress/keyup also trigger on TAB press, and we don't want to
133 133 // use those to disable tab completion.
134 134 if (this.is_completing && event.keyCode !== 9) {
135 135 var ed_cur = editor.getCursor();
136 136 var cc_cur = this.completion_cursor;
137 137 if (ed_cur.line !== cc_cur.line || ed_cur.ch !== cc_cur.ch) {
138 138 this.is_completing = false;
139 139 this.completion_cursor = null;
140 140 };
141 141 };
142 142 return false;
143 143 };
144 144 };
145 145
146 146 CodeCell.prototype.remove_and_cancell_tooltip = function(timeout)
147 147 {
148 148 // note that we don't handle closing directly inside the calltip
149 149 // as in the completer, because it is not focusable, so won't
150 150 // get the event.
151 151 clearTimeout(timeout);
152 152 $('#tooltip').remove();
153 153 }
154 154
155 155 CodeCell.prototype.finish_tooltip = function (defstring,docstring) {
156 156 shortened = function(string){
157 157 if(string.length > 200){
158 158 return string.trim().substring(0,197)+'...';
159 159 } else { return string.trim() }
160 160 }
161 161
162 162 var that = this;
163 163 var tooltip = $('<div/>').attr('id', 'tooltip').addClass('tooltip');
164 164 if(defstring){
165 165 defstring_html= $('<pre/>').html(utils.fixConsole(defstring));
166 166 tooltip.append(defstring_html);
167 167 }
168 168 tooltip.append($('<pre/>').html(utils.fixConsole(shortened(docstring))));
169 169 var pos = this.code_mirror.cursorCoords();
170 170 tooltip.css('left',pos.x+'px');
171 171 tooltip.css('top',pos.yBot+'px');
172 172 $('body').append(tooltip);
173 173
174 174 // issues with cross-closing if multiple tooltip in less than 5sec
175 175 // keep it comented for now
176 176 // setTimeout(CodeCell.prototype.remove_and_cancell_tooltip, 5000);
177 177 };
178 178
179 179
180 180 CodeCell.prototype.finish_completing = function (matched_text, matches) {
181 181 // console.log("Got matches", matched_text, matches);
182 var newm = new Array();
183 if(this.notebook.smart_completer)
184 {
185 kwargs = new Array();
186 other = new Array();
187 for(var i=0;i<matches.length; ++i){
188 if(matches[i].substr(-1) === '='){
189 kwargs.push(matches[i]);
190 }else{other.push(matches[i]);}
191 }
192 newm = kwargs.concat(other);
193 matches=newm;
194 }
182 195 if (!this.is_completing || matches.length === 0) {return;}
183 196
184 197 var that = this;
185 198 var cur = this.completion_cursor;
186 199
187 200 var insert = function (selected_text) {
188 201 that.code_mirror.replaceRange(
189 202 selected_text,
190 203 {line: cur.line, ch: (cur.ch-matched_text.length)},
191 204 {line: cur.line, ch: cur.ch}
192 205 );
193 206 };
194 207
195 208 if (matches.length === 1) {
196 209 insert(matches[0]);
197 210 setTimeout(function(){that.code_mirror.focus();}, 50);
198 211 return;
199 212 };
200 213
201 214 var complete = $('<div/>').addClass('completions');
202 215 var select = $('<select/>').attr('multiple','true');
203 216 for (var i=0; i<matches.length; ++i) {
204 217 select.append($('<option/>').text(matches[i]));
205 218 }
206 219 select.children().first().attr('selected','true');
207 220 select.attr('size',Math.min(10,matches.length));
208 221 var pos = this.code_mirror.cursorCoords();
209 222 complete.css('left',pos.x+'px');
210 223 complete.css('top',pos.yBot+'px');
211 224 complete.append(select);
212 225
213 226 $('body').append(complete);
214 227 var done = false;
215 228
216 229 var close = function () {
217 230 if (done) return;
218 231 done = true;
219 232 complete.remove();
220 233 that.is_completing = false;
221 234 that.completion_cursor = null;
222 235 };
223 236
224 237 var pick = function () {
225 238 insert(select.val()[0]);
226 239 close();
227 240 setTimeout(function(){that.code_mirror.focus();}, 50);
228 241 };
229 242
230 243 select.blur(close);
231 244 select.keydown(function (event) {
232 245 var code = event.which;
233 246 if (code === 13 || code === 32) {
234 247 // Pressing SPACE or ENTER will cause a pick
235 248 event.stopPropagation();
236 249 event.preventDefault();
237 250 pick();
238 251 } else if (code === 38 || code === 40) {
239 252 // We don't want the document keydown handler to handle UP/DOWN,
240 253 // but we want the default action.
241 254 event.stopPropagation();
242 255 } else {
243 256 // All other key presses exit completion.
244 257 event.stopPropagation();
245 258 event.preventDefault();
246 259 close();
247 260 that.code_mirror.focus();
248 261 }
249 262 });
250 263 // Double click also causes a pick.
251 264 select.dblclick(pick);
252 265 select.focus();
253 266 };
254 267
255 268 CodeCell.prototype.toggle_line_numbers = function () {
256 269 if (this.code_mirror.getOption('lineNumbers') == false) {
257 270 this.code_mirror.setOption('lineNumbers', true);
258 271 } else {
259 272 this.code_mirror.setOption('lineNumbers', false);
260 273 }
261 274 this.code_mirror.refresh()
262 275 };
263 276
264 277 CodeCell.prototype.select = function () {
265 278 IPython.Cell.prototype.select.apply(this);
266 279 // Todo: this dance is needed because as of CodeMirror 2.12, focus is
267 280 // not causing the cursor to blink if the editor is empty initially.
268 281 // While this seems to fix the issue, this should be fixed
269 282 // in CodeMirror proper.
270 283 var s = this.code_mirror.getValue();
271 284 this.code_mirror.focus();
272 285 if (s === '') this.code_mirror.setValue('');
273 286 };
274 287
275 288
276 289 CodeCell.prototype.select_all = function () {
277 290 var start = {line: 0, ch: 0};
278 291 var nlines = this.code_mirror.lineCount();
279 292 var last_line = this.code_mirror.getLine(nlines-1);
280 293 var end = {line: nlines-1, ch: last_line.length};
281 294 this.code_mirror.setSelection(start, end);
282 295 };
283 296
284 297
285 298 CodeCell.prototype.append_output = function (json) {
286 299 this.expand();
287 300 if (json.output_type === 'pyout') {
288 301 this.append_pyout(json);
289 302 } else if (json.output_type === 'pyerr') {
290 303 this.append_pyerr(json);
291 304 } else if (json.output_type === 'display_data') {
292 305 this.append_display_data(json);
293 306 } else if (json.output_type === 'stream') {
294 307 this.append_stream(json);
295 308 };
296 309 this.outputs.push(json);
297 310 };
298 311
299 312
300 313 CodeCell.prototype.create_output_area = function () {
301 314 var oa = $("<div/>").addClass("hbox output_area");
302 315 oa.append($('<div/>').addClass('prompt'));
303 316 return oa;
304 317 };
305 318
306 319
307 320 CodeCell.prototype.append_pyout = function (json) {
308 321 n = json.prompt_number || ' ';
309 322 var toinsert = this.create_output_area();
310 323 toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:');
311 324 this.append_mime_type(json, toinsert);
312 325 this.element.find('div.output').append(toinsert);
313 326 // If we just output latex, typeset it.
314 327 if ((json.latex !== undefined) || (json.html !== undefined)) {
315 328 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
316 329 };
317 330 };
318 331
319 332
320 333 CodeCell.prototype.append_pyerr = function (json) {
321 334 var tb = json.traceback;
322 335 if (tb !== undefined && tb.length > 0) {
323 336 var s = '';
324 337 var len = tb.length;
325 338 for (var i=0; i<len; i++) {
326 339 s = s + tb[i] + '\n';
327 340 }
328 341 s = s + '\n';
329 342 var toinsert = this.create_output_area();
330 343 this.append_text(s, toinsert);
331 344 this.element.find('div.output').append(toinsert);
332 345 };
333 346 };
334 347
335 348
336 349 CodeCell.prototype.append_stream = function (json) {
337 350 // temporary fix: if stream undefined (json file written prior to this patch),
338 351 // default to most likely stdout:
339 352 if (json.stream == undefined){
340 353 json.stream = 'stdout';
341 354 }
342 355 var subclass = "output_"+json.stream;
343 356 if (this.outputs.length > 0){
344 357 // have at least one output to consider
345 358 var last = this.outputs[this.outputs.length-1];
346 359 if (last.output_type == 'stream' && json.stream == last.stream){
347 360 // latest output was in the same stream,
348 361 // so append directly into its pre tag
349 362 this.element.find('div.'+subclass).last().find('pre').append(json.text);
350 363 return;
351 364 }
352 365 }
353 366
354 367 // If we got here, attach a new div
355 368 var toinsert = this.create_output_area();
356 369 this.append_text(json.text, toinsert, "output_stream "+subclass);
357 370 this.element.find('div.output').append(toinsert);
358 371 };
359 372
360 373
361 374 CodeCell.prototype.append_display_data = function (json) {
362 375 var toinsert = this.create_output_area();
363 376 this.append_mime_type(json, toinsert)
364 377 this.element.find('div.output').append(toinsert);
365 378 // If we just output latex, typeset it.
366 379 if ( (json.latex !== undefined) || (json.html !== undefined) ) {
367 380 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
368 381 };
369 382 };
370 383
371 384
372 385 CodeCell.prototype.append_mime_type = function (json, element) {
373 386 if (json.html !== undefined) {
374 387 this.append_html(json.html, element);
375 388 } else if (json.latex !== undefined) {
376 389 this.append_latex(json.latex, element);
377 390 } else if (json.svg !== undefined) {
378 391 this.append_svg(json.svg, element);
379 392 } else if (json.png !== undefined) {
380 393 this.append_png(json.png, element);
381 394 } else if (json.jpeg !== undefined) {
382 395 this.append_jpeg(json.jpeg, element);
383 396 } else if (json.text !== undefined) {
384 397 this.append_text(json.text, element);
385 398 };
386 399 };
387 400
388 401
389 402 CodeCell.prototype.append_html = function (html, element) {
390 403 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_html rendered_html");
391 404 toinsert.append(html);
392 405 element.append(toinsert);
393 406 }
394 407
395 408
396 409 CodeCell.prototype.append_text = function (data, element, extra_class) {
397 410 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_text");
398 411 if (extra_class){
399 412 toinsert.addClass(extra_class);
400 413 }
401 414 toinsert.append($("<pre/>").html(data));
402 415 element.append(toinsert);
403 416 };
404 417
405 418
406 419 CodeCell.prototype.append_svg = function (svg, element) {
407 420 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_svg");
408 421 toinsert.append(svg);
409 422 element.append(toinsert);
410 423 };
411 424
412 425
413 426 CodeCell.prototype.append_png = function (png, element) {
414 427 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_png");
415 428 toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png));
416 429 element.append(toinsert);
417 430 };
418 431
419 432
420 433 CodeCell.prototype.append_jpeg = function (jpeg, element) {
421 434 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_jpeg");
422 435 toinsert.append($("<img/>").attr('src','data:image/jpeg;base64,'+jpeg));
423 436 element.append(toinsert);
424 437 };
425 438
426 439
427 440 CodeCell.prototype.append_latex = function (latex, element) {
428 441 // This method cannot do the typesetting because the latex first has to
429 442 // be on the page.
430 443 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_latex");
431 444 toinsert.append(latex);
432 445 element.append(toinsert);
433 446 }
434 447
435 448
436 449 CodeCell.prototype.clear_output = function (stdout, stderr, other) {
437 450 var output_div = this.element.find("div.output");
438 451 if (stdout && stderr && other){
439 452 // clear all, no need for logic
440 453 output_div.html("");
441 454 this.outputs = [];
442 455 return;
443 456 }
444 457 // remove html output
445 458 // each output_subarea that has an identifying class is in an output_area
446 459 // which is the element to be removed.
447 460 if (stdout){
448 461 output_div.find("div.output_stdout").parent().remove();
449 462 }
450 463 if (stderr){
451 464 output_div.find("div.output_stderr").parent().remove();
452 465 }
453 466 if (other){
454 467 output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
455 468 }
456 469
457 470 // remove cleared outputs from JSON list:
458 471 for (var i = this.outputs.length - 1; i >= 0; i--){
459 472 var out = this.outputs[i];
460 473 var output_type = out.output_type;
461 474 if (output_type == "display_data" && other){
462 475 this.outputs.splice(i,1);
463 476 }else if (output_type == "stream"){
464 477 if (stdout && out.stream == "stdout"){
465 478 this.outputs.splice(i,1);
466 479 }else if (stderr && out.stream == "stderr"){
467 480 this.outputs.splice(i,1);
468 481 }
469 482 }
470 483 }
471 484 };
472 485
473 486
474 487 CodeCell.prototype.clear_input = function () {
475 488 this.code_mirror.setValue('');
476 489 };
477 490
478 491
479 492 CodeCell.prototype.collapse = function () {
480 493 if (!this.collapsed) {
481 494 this.element.find('div.output').hide();
482 495 this.collapsed = true;
483 496 };
484 497 };
485 498
486 499
487 500 CodeCell.prototype.expand = function () {
488 501 if (this.collapsed) {
489 502 this.element.find('div.output').show();
490 503 this.collapsed = false;
491 504 };
492 505 };
493 506
494 507
495 508 CodeCell.prototype.toggle_output = function () {
496 509 if (this.collapsed) {
497 510 this.expand();
498 511 } else {
499 512 this.collapse();
500 513 };
501 514 };
502 515
503 516 CodeCell.prototype.set_input_prompt = function (number) {
504 517 var n = number || ' ';
505 518 this.input_prompt_number = n
506 519 this.element.find('div.input_prompt').html('In&nbsp;[' + n + ']:');
507 520 };
508 521
509 522
510 523 CodeCell.prototype.get_code = function () {
511 524 return this.code_mirror.getValue();
512 525 };
513 526
514 527
515 528 CodeCell.prototype.set_code = function (code) {
516 529 return this.code_mirror.setValue(code);
517 530 };
518 531
519 532
520 533 CodeCell.prototype.at_top = function () {
521 534 var cursor = this.code_mirror.getCursor();
522 535 if (cursor.line === 0) {
523 536 return true;
524 537 } else {
525 538 return false;
526 539 }
527 540 };
528 541
529 542
530 543 CodeCell.prototype.at_bottom = function () {
531 544 var cursor = this.code_mirror.getCursor();
532 545 if (cursor.line === (this.code_mirror.lineCount()-1)) {
533 546 return true;
534 547 } else {
535 548 return false;
536 549 }
537 550 };
538 551
539 552
540 553 CodeCell.prototype.fromJSON = function (data) {
541 554 console.log('Import from JSON:', data);
542 555 if (data.cell_type === 'code') {
543 556 if (data.input !== undefined) {
544 557 this.set_code(data.input);
545 558 }
546 559 if (data.prompt_number !== undefined) {
547 560 this.set_input_prompt(data.prompt_number);
548 561 } else {
549 562 this.set_input_prompt();
550 563 };
551 564 var len = data.outputs.length;
552 565 for (var i=0; i<len; i++) {
553 566 this.append_output(data.outputs[i]);
554 567 };
555 568 if (data.collapsed !== undefined) {
556 569 if (data.collapsed) {
557 570 this.collapse();
558 571 };
559 572 };
560 573 };
561 574 };
562 575
563 576
564 577 CodeCell.prototype.toJSON = function () {
565 578 var data = {};
566 579 data.input = this.get_code();
567 580 data.cell_type = 'code';
568 581 if (this.input_prompt_number !== ' ') {
569 582 data.prompt_number = this.input_prompt_number
570 583 };
571 584 var outputs = [];
572 585 var len = this.outputs.length;
573 586 for (var i=0; i<len; i++) {
574 587 outputs[i] = this.outputs[i];
575 588 };
576 589 data.outputs = outputs;
577 590 data.language = 'python';
578 591 data.collapsed = this.collapsed;
579 592 // console.log('Export to JSON:',data);
580 593 return data;
581 594 };
582 595
583 596
584 597 IPython.CodeCell = CodeCell;
585 598
586 599 return IPython;
587 600 }(IPython));
@@ -1,1062 +1,1068 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2008-2011 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // Notebook
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13
14 14 var utils = IPython.utils;
15 15
16 16 var Notebook = function (selector) {
17 17 this.read_only = IPython.read_only;
18 18 this.element = $(selector);
19 19 this.element.scroll();
20 20 this.element.data("notebook", this);
21 21 this.next_prompt_number = 1;
22 22 this.kernel = null;
23 23 this.dirty = false;
24 24 this.msg_cell_map = {};
25 25 this.metadata = {};
26 26 this.control_key_active = false;
27 27 this.style();
28 28 this.create_elements();
29 29 this.bind_events();
30 30 this.set_tooltipontab(true);
31 this.set_smartcompleter(true);
31 32 this.set_timebeforetooltip(1200);
32 33 };
33 34
34 35
35 36 Notebook.prototype.style = function () {
36 37 $('div#notebook').addClass('border-box-sizing');
37 38 };
38 39
39 40
40 41 Notebook.prototype.create_elements = function () {
41 42 // We add this end_space div to the end of the notebook div to:
42 43 // i) provide a margin between the last cell and the end of the notebook
43 44 // ii) to prevent the div from scrolling up when the last cell is being
44 45 // edited, but is too low on the page, which browsers will do automatically.
45 46 var that = this;
46 47 var end_space = $('<div class="end_space"></div>').height(150);
47 48 end_space.dblclick(function (e) {
48 49 if (that.read_only) return;
49 50 var ncells = that.ncells();
50 51 that.insert_code_cell_below(ncells-1);
51 52 });
52 53 this.element.append(end_space);
53 54 $('div#notebook').addClass('border-box-sizing');
54 55 };
55 56
56 57
57 58 Notebook.prototype.bind_events = function () {
58 59 var that = this;
59 60 $(document).keydown(function (event) {
60 61 // console.log(event);
61 62 if (that.read_only) return;
62 63 if (event.which === 27) {
63 64 // Intercept escape at highest level to avoid closing
64 65 // websocket connection with firefox
65 66 event.preventDefault();
66 67 }
67 68 if (event.which === 38) {
68 69 var cell = that.selected_cell();
69 70 if (cell.at_top()) {
70 71 event.preventDefault();
71 72 that.select_prev();
72 73 };
73 74 } else if (event.which === 40) {
74 75 var cell = that.selected_cell();
75 76 if (cell.at_bottom()) {
76 77 event.preventDefault();
77 78 that.select_next();
78 79 };
79 80 } else if (event.which === 13 && event.shiftKey) {
80 81 that.execute_selected_cell();
81 82 return false;
82 83 } else if (event.which === 13 && event.ctrlKey) {
83 84 that.execute_selected_cell({terminal:true});
84 85 return false;
85 86 } else if (event.which === 77 && event.ctrlKey) {
86 87 that.control_key_active = true;
87 88 return false;
88 89 } else if (event.which === 68 && that.control_key_active) {
89 90 // Delete selected cell = d
90 91 that.delete_cell();
91 92 that.control_key_active = false;
92 93 return false;
93 94 } else if (event.which === 65 && that.control_key_active) {
94 95 // Insert code cell above selected = a
95 96 that.insert_code_cell_above();
96 97 that.control_key_active = false;
97 98 return false;
98 99 } else if (event.which === 66 && that.control_key_active) {
99 100 // Insert code cell below selected = b
100 101 that.insert_code_cell_below();
101 102 that.control_key_active = false;
102 103 return false;
103 104 } else if (event.which === 67 && that.control_key_active) {
104 105 // To code = c
105 106 that.to_code();
106 107 that.control_key_active = false;
107 108 return false;
108 109 } else if (event.which === 77 && that.control_key_active) {
109 110 // To markdown = m
110 111 that.to_markdown();
111 112 that.control_key_active = false;
112 113 return false;
113 114 } else if (event.which === 84 && that.control_key_active) {
114 115 // Toggle output = t
115 116 that.toggle_output();
116 117 that.control_key_active = false;
117 118 return false;
118 119 } else if (event.which === 83 && that.control_key_active) {
119 120 // Save notebook = s
120 121 IPython.save_widget.save_notebook();
121 122 that.control_key_active = false;
122 123 return false;
123 124 } else if (event.which === 74 && that.control_key_active) {
124 125 // Move cell down = j
125 126 that.move_cell_down();
126 127 that.control_key_active = false;
127 128 return false;
128 129 } else if (event.which === 75 && that.control_key_active) {
129 130 // Move cell up = k
130 131 that.move_cell_up();
131 132 that.control_key_active = false;
132 133 return false;
133 134 } else if (event.which === 80 && that.control_key_active) {
134 135 // Select previous = p
135 136 that.select_prev();
136 137 that.control_key_active = false;
137 138 return false;
138 139 } else if (event.which === 78 && that.control_key_active) {
139 140 // Select next = n
140 141 that.select_next();
141 142 that.control_key_active = false;
142 143 return false;
143 144 } else if (event.which === 76 && that.control_key_active) {
144 145 // Toggle line numbers = l
145 146 that.cell_toggle_line_numbers();
146 147 that.control_key_active = false;
147 148 return false;
148 149 } else if (event.which === 73 && that.control_key_active) {
149 150 // Interrupt kernel = i
150 151 IPython.notebook.kernel.interrupt();
151 152 that.control_key_active = false;
152 153 return false;
153 154 } else if (event.which === 190 && that.control_key_active) {
154 155 // Restart kernel = . # matches qt console
155 156 IPython.notebook.restart_kernel();
156 157 that.control_key_active = false;
157 158 return false;
158 159 } else if (event.which === 72 && that.control_key_active) {
159 160 // Show keyboard shortcuts = h
160 161 that.toggle_keyboard_shortcuts();
161 162 that.control_key_active = false;
162 163 return false;
163 164 } else if (that.control_key_active) {
164 165 that.control_key_active = false;
165 166 return true;
166 167 };
167 168 });
168 169
169 170 this.element.bind('collapse_pager', function () {
170 171 var app_height = $('div#main_app').height(); // content height
171 172 var splitter_height = $('div#pager_splitter').outerHeight(true);
172 173 var new_height = app_height - splitter_height;
173 174 that.element.animate({height : new_height + 'px'}, 'fast');
174 175 });
175 176
176 177 this.element.bind('expand_pager', function () {
177 178 var app_height = $('div#main_app').height(); // content height
178 179 var splitter_height = $('div#pager_splitter').outerHeight(true);
179 180 var pager_height = $('div#pager').outerHeight(true);
180 181 var new_height = app_height - pager_height - splitter_height;
181 182 that.element.animate({height : new_height + 'px'}, 'fast');
182 183 });
183 184
184 185 this.element.bind('collapse_left_panel', function () {
185 186 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
186 187 var new_margin = splitter_width;
187 188 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
188 189 });
189 190
190 191 this.element.bind('expand_left_panel', function () {
191 192 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
192 193 var left_panel_width = IPython.left_panel.width;
193 194 var new_margin = splitter_width + left_panel_width;
194 195 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
195 196 });
196 197
197 198 $(window).bind('beforeunload', function () {
198 199 var kill_kernel = $('#kill_kernel').prop('checked');
199 200 if (kill_kernel) {
200 201 that.kernel.kill();
201 202 }
202 203 if (that.dirty && ! that.read_only) {
203 204 return "You have unsaved changes that will be lost if you leave this page.";
204 205 };
205 206 });
206 207 };
207 208
208 209
209 210 Notebook.prototype.toggle_keyboard_shortcuts = function () {
210 211 // toggles display of keyboard shortcut dialog
211 212 var that = this;
212 213 if ( this.shortcut_dialog ){
213 214 // if dialog is already shown, close it
214 215 this.shortcut_dialog.dialog("close");
215 216 this.shortcut_dialog = null;
216 217 return;
217 218 }
218 219 var dialog = $('<div/>');
219 220 this.shortcut_dialog = dialog;
220 221 var shortcuts = [
221 222 {key: 'Shift-Enter', help: 'run cell'},
222 223 {key: 'Ctrl-Enter', help: 'run cell in-place'},
223 224 {key: 'Ctrl-m d', help: 'delete cell'},
224 225 {key: 'Ctrl-m a', help: 'insert cell above'},
225 226 {key: 'Ctrl-m b', help: 'insert cell below'},
226 227 {key: 'Ctrl-m t', help: 'toggle output'},
227 228 {key: 'Ctrl-m l', help: 'toggle line numbers'},
228 229 {key: 'Ctrl-m s', help: 'save notebook'},
229 230 {key: 'Ctrl-m j', help: 'move cell down'},
230 231 {key: 'Ctrl-m k', help: 'move cell up'},
231 232 {key: 'Ctrl-m c', help: 'code cell'},
232 233 {key: 'Ctrl-m m', help: 'markdown cell'},
233 234 {key: 'Ctrl-m p', help: 'select previous'},
234 235 {key: 'Ctrl-m n', help: 'select next'},
235 236 {key: 'Ctrl-m i', help: 'interrupt kernel'},
236 237 {key: 'Ctrl-m .', help: 'restart kernel'},
237 238 {key: 'Ctrl-m h', help: 'show keyboard shortcuts'}
238 239 ];
239 240 for (var i=0; i<shortcuts.length; i++) {
240 241 dialog.append($('<div>').
241 242 append($('<span/>').addClass('shortcut_key').html(shortcuts[i].key)).
242 243 append($('<span/>').addClass('shortcut_descr').html(' : ' + shortcuts[i].help))
243 244 );
244 245 };
245 246 dialog.bind('dialogclose', function(event) {
246 247 // dialog has been closed, allow it to be drawn again.
247 248 that.shortcut_dialog = null;
248 249 });
249 250 dialog.dialog({title: 'Keyboard shortcuts'});
250 251 };
251 252
252 253
253 254 Notebook.prototype.scroll_to_bottom = function () {
254 255 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
255 256 };
256 257
257 258
258 259 Notebook.prototype.scroll_to_top = function () {
259 260 this.element.animate({scrollTop:0}, 0);
260 261 };
261 262
262 263
263 264 // Cell indexing, retrieval, etc.
264 265
265 266
266 267 Notebook.prototype.cell_elements = function () {
267 268 return this.element.children("div.cell");
268 269 }
269 270
270 271
271 272 Notebook.prototype.ncells = function (cell) {
272 273 return this.cell_elements().length;
273 274 }
274 275
275 276
276 277 // TODO: we are often calling cells as cells()[i], which we should optimize
277 278 // to cells(i) or a new method.
278 279 Notebook.prototype.cells = function () {
279 280 return this.cell_elements().toArray().map(function (e) {
280 281 return $(e).data("cell");
281 282 });
282 283 }
283 284
284 285
285 286 Notebook.prototype.find_cell_index = function (cell) {
286 287 var result = null;
287 288 this.cell_elements().filter(function (index) {
288 289 if ($(this).data("cell") === cell) {
289 290 result = index;
290 291 };
291 292 });
292 293 return result;
293 294 };
294 295
295 296
296 297 Notebook.prototype.index_or_selected = function (index) {
297 298 return index || this.selected_index() || 0;
298 299 }
299 300
300 301
301 302 Notebook.prototype.select = function (index) {
302 303 if (index !== undefined && index >= 0 && index < this.ncells()) {
303 304 if (this.selected_index() !== null) {
304 305 this.selected_cell().unselect();
305 306 };
306 307 this.cells()[index].select();
307 308 };
308 309 return this;
309 310 };
310 311
311 312
312 313 Notebook.prototype.select_next = function () {
313 314 var index = this.selected_index();
314 315 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
315 316 this.select(index+1);
316 317 };
317 318 return this;
318 319 };
319 320
320 321
321 322 Notebook.prototype.select_prev = function () {
322 323 var index = this.selected_index();
323 324 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
324 325 this.select(index-1);
325 326 };
326 327 return this;
327 328 };
328 329
329 330
330 331 Notebook.prototype.selected_index = function () {
331 332 var result = null;
332 333 this.cell_elements().filter(function (index) {
333 334 if ($(this).data("cell").selected === true) {
334 335 result = index;
335 336 };
336 337 });
337 338 return result;
338 339 };
339 340
340 341
341 342 Notebook.prototype.cell_for_msg = function (msg_id) {
342 343 var cell_id = this.msg_cell_map[msg_id];
343 344 var result = null;
344 345 this.cell_elements().filter(function (index) {
345 346 cell = $(this).data("cell");
346 347 if (cell.cell_id === cell_id) {
347 348 result = cell;
348 349 };
349 350 });
350 351 return result;
351 352 };
352 353
353 354
354 355 Notebook.prototype.selected_cell = function () {
355 356 return this.cell_elements().eq(this.selected_index()).data("cell");
356 357 }
357 358
358 359
359 360 // Cell insertion, deletion and moving.
360 361
361 362
362 363 Notebook.prototype.delete_cell = function (index) {
363 364 var i = index || this.selected_index();
364 365 if (i !== null && i >= 0 && i < this.ncells()) {
365 366 this.cell_elements().eq(i).remove();
366 367 if (i === (this.ncells())) {
367 368 this.select(i-1);
368 369 } else {
369 370 this.select(i);
370 371 };
371 372 };
372 373 this.dirty = true;
373 374 return this;
374 375 };
375 376
376 377
377 378 Notebook.prototype.append_cell = function (cell) {
378 379 this.element.find('div.end_space').before(cell.element);
379 380 this.dirty = true;
380 381 return this;
381 382 };
382 383
383 384
384 385 Notebook.prototype.insert_cell_below = function (cell, index) {
385 386 var ncells = this.ncells();
386 387 if (ncells === 0) {
387 388 this.append_cell(cell);
388 389 return this;
389 390 };
390 391 if (index >= 0 && index < ncells) {
391 392 this.cell_elements().eq(index).after(cell.element);
392 393 };
393 394 this.dirty = true;
394 395 return this
395 396 };
396 397
397 398
398 399 Notebook.prototype.insert_cell_above = function (cell, index) {
399 400 var ncells = this.ncells();
400 401 if (ncells === 0) {
401 402 this.append_cell(cell);
402 403 return this;
403 404 };
404 405 if (index >= 0 && index < ncells) {
405 406 this.cell_elements().eq(index).before(cell.element);
406 407 };
407 408 this.dirty = true;
408 409 return this;
409 410 };
410 411
411 412
412 413 Notebook.prototype.move_cell_up = function (index) {
413 414 var i = index || this.selected_index();
414 415 if (i !== null && i < this.ncells() && i > 0) {
415 416 var pivot = this.cell_elements().eq(i-1);
416 417 var tomove = this.cell_elements().eq(i);
417 418 if (pivot !== null && tomove !== null) {
418 419 tomove.detach();
419 420 pivot.before(tomove);
420 421 this.select(i-1);
421 422 };
422 423 };
423 424 this.dirty = true;
424 425 return this;
425 426 }
426 427
427 428
428 429 Notebook.prototype.move_cell_down = function (index) {
429 430 var i = index || this.selected_index();
430 431 if (i !== null && i < (this.ncells()-1) && i >= 0) {
431 432 var pivot = this.cell_elements().eq(i+1)
432 433 var tomove = this.cell_elements().eq(i)
433 434 if (pivot !== null && tomove !== null) {
434 435 tomove.detach();
435 436 pivot.after(tomove);
436 437 this.select(i+1);
437 438 };
438 439 };
439 440 this.dirty = true;
440 441 return this;
441 442 }
442 443
443 444
444 445 Notebook.prototype.sort_cells = function () {
445 446 var ncells = this.ncells();
446 447 var sindex = this.selected_index();
447 448 var swapped;
448 449 do {
449 450 swapped = false
450 451 for (var i=1; i<ncells; i++) {
451 452 current = this.cell_elements().eq(i).data("cell");
452 453 previous = this.cell_elements().eq(i-1).data("cell");
453 454 if (previous.input_prompt_number > current.input_prompt_number) {
454 455 this.move_cell_up(i);
455 456 swapped = true;
456 457 };
457 458 };
458 459 } while (swapped);
459 460 this.select(sindex);
460 461 return this;
461 462 };
462 463
463 464
464 465 Notebook.prototype.insert_code_cell_above = function (index) {
465 466 // TODO: Bounds check for i
466 467 var i = this.index_or_selected(index);
467 468 var cell = new IPython.CodeCell(this);
468 469 cell.set_input_prompt();
469 470 this.insert_cell_above(cell, i);
470 471 this.select(this.find_cell_index(cell));
471 472 return cell;
472 473 }
473 474
474 475
475 476 Notebook.prototype.insert_code_cell_below = function (index) {
476 477 // TODO: Bounds check for i
477 478 var i = this.index_or_selected(index);
478 479 var cell = new IPython.CodeCell(this);
479 480 cell.set_input_prompt();
480 481 this.insert_cell_below(cell, i);
481 482 this.select(this.find_cell_index(cell));
482 483 return cell;
483 484 }
484 485
485 486
486 487 Notebook.prototype.insert_html_cell_above = function (index) {
487 488 // TODO: Bounds check for i
488 489 var i = this.index_or_selected(index);
489 490 var cell = new IPython.HTMLCell(this);
490 491 cell.config_mathjax();
491 492 this.insert_cell_above(cell, i);
492 493 this.select(this.find_cell_index(cell));
493 494 return cell;
494 495 }
495 496
496 497
497 498 Notebook.prototype.insert_html_cell_below = function (index) {
498 499 // TODO: Bounds check for i
499 500 var i = this.index_or_selected(index);
500 501 var cell = new IPython.HTMLCell(this);
501 502 cell.config_mathjax();
502 503 this.insert_cell_below(cell, i);
503 504 this.select(this.find_cell_index(cell));
504 505 return cell;
505 506 }
506 507
507 508
508 509 Notebook.prototype.insert_markdown_cell_above = function (index) {
509 510 // TODO: Bounds check for i
510 511 var i = this.index_or_selected(index);
511 512 var cell = new IPython.MarkdownCell(this);
512 513 cell.config_mathjax();
513 514 this.insert_cell_above(cell, i);
514 515 this.select(this.find_cell_index(cell));
515 516 return cell;
516 517 }
517 518
518 519
519 520 Notebook.prototype.insert_markdown_cell_below = function (index) {
520 521 // TODO: Bounds check for i
521 522 var i = this.index_or_selected(index);
522 523 var cell = new IPython.MarkdownCell(this);
523 524 cell.config_mathjax();
524 525 this.insert_cell_below(cell, i);
525 526 this.select(this.find_cell_index(cell));
526 527 return cell;
527 528 }
528 529
529 530
530 531 Notebook.prototype.to_code = function (index) {
531 532 // TODO: Bounds check for i
532 533 var i = this.index_or_selected(index);
533 534 var source_element = this.cell_elements().eq(i);
534 535 var source_cell = source_element.data("cell");
535 536 if (source_cell instanceof IPython.HTMLCell ||
536 537 source_cell instanceof IPython.MarkdownCell) {
537 538 this.insert_code_cell_below(i);
538 539 var target_cell = this.cells()[i+1];
539 540 target_cell.set_code(source_cell.get_source());
540 541 source_element.remove();
541 542 target_cell.select();
542 543 };
543 544 this.dirty = true;
544 545 };
545 546
546 547
547 548 Notebook.prototype.to_markdown = function (index) {
548 549 // TODO: Bounds check for i
549 550 var i = this.index_or_selected(index);
550 551 var source_element = this.cell_elements().eq(i);
551 552 var source_cell = source_element.data("cell");
552 553 var target_cell = null;
553 554 if (source_cell instanceof IPython.CodeCell) {
554 555 this.insert_markdown_cell_below(i);
555 556 var target_cell = this.cells()[i+1];
556 557 var text = source_cell.get_code();
557 558 } else if (source_cell instanceof IPython.HTMLCell) {
558 559 this.insert_markdown_cell_below(i);
559 560 var target_cell = this.cells()[i+1];
560 561 var text = source_cell.get_source();
561 562 if (text === source_cell.placeholder) {
562 563 text = target_cell.placeholder;
563 564 }
564 565 }
565 566 if (target_cell !== null) {
566 567 if (text === "") {text = target_cell.placeholder;};
567 568 target_cell.set_source(text);
568 569 source_element.remove();
569 570 target_cell.edit();
570 571 }
571 572 this.dirty = true;
572 573 };
573 574
574 575
575 576 Notebook.prototype.to_html = function (index) {
576 577 // TODO: Bounds check for i
577 578 var i = this.index_or_selected(index);
578 579 var source_element = this.cell_elements().eq(i);
579 580 var source_cell = source_element.data("cell");
580 581 var target_cell = null;
581 582 if (source_cell instanceof IPython.CodeCell) {
582 583 this.insert_html_cell_below(i);
583 584 var target_cell = this.cells()[i+1];
584 585 var text = source_cell.get_code();
585 586 } else if (source_cell instanceof IPython.MarkdownCell) {
586 587 this.insert_html_cell_below(i);
587 588 var target_cell = this.cells()[i+1];
588 589 var text = source_cell.get_source();
589 590 if (text === source_cell.placeholder) {
590 591 text = target_cell.placeholder;
591 592 }
592 593 }
593 594 if (target_cell !== null) {
594 595 if (text === "") {text = target_cell.placeholder;};
595 596 target_cell.set_source(text);
596 597 source_element.remove();
597 598 target_cell.edit();
598 599 }
599 600 this.dirty = true;
600 601 };
601 602
602 603
603 604 // Cell collapsing and output clearing
604 605
605 606 Notebook.prototype.collapse = function (index) {
606 607 var i = this.index_or_selected(index);
607 608 this.cells()[i].collapse();
608 609 this.dirty = true;
609 610 };
610 611
611 612
612 613 Notebook.prototype.expand = function (index) {
613 614 var i = this.index_or_selected(index);
614 615 this.cells()[i].expand();
615 616 this.dirty = true;
616 617 };
617 618
618 619
619 620 Notebook.prototype.toggle_output = function (index) {
620 621 var i = this.index_or_selected(index);
621 622 this.cells()[i].toggle_output();
622 623 this.dirty = true;
623 624 };
624 625
625 626
626 627 Notebook.prototype.set_timebeforetooltip = function (time) {
627 628 console.log("change time before tooltip to : "+time);
628 629 this.time_before_tooltip = time;
629 630 };
630 631
631 632 Notebook.prototype.set_tooltipontab = function (state) {
632 633 console.log("change tooltip on tab to : "+state);
633 634 this.tooltip_on_tab = state;
634 635 };
635 636
637 Notebook.prototype.set_smartcompleter = function (state) {
638 console.log("Smart completion (kwargs first) changed to to : "+state);
639 this.smart_completer = state;
640 };
641
636 642 Notebook.prototype.set_autoindent = function (state) {
637 643 var cells = this.cells();
638 644 len = cells.length;
639 645 for (var i=0; i<len; i++) {
640 646 cells[i].set_autoindent(state)
641 647 };
642 648 };
643 649
644 650
645 651 Notebook.prototype.clear_all_output = function () {
646 652 var ncells = this.ncells();
647 653 var cells = this.cells();
648 654 for (var i=0; i<ncells; i++) {
649 655 if (cells[i] instanceof IPython.CodeCell) {
650 656 cells[i].clear_output(true,true,true);
651 657 }
652 658 };
653 659 this.dirty = true;
654 660 };
655 661
656 662 // Other cell functions: line numbers, ...
657 663
658 664 Notebook.prototype.cell_toggle_line_numbers = function() {
659 665 this.selected_cell().toggle_line_numbers()
660 666 };
661 667
662 668 // Kernel related things
663 669
664 670 Notebook.prototype.start_kernel = function () {
665 671 this.kernel = new IPython.Kernel();
666 672 var notebook_id = IPython.save_widget.get_notebook_id();
667 673 this.kernel.start(notebook_id, $.proxy(this.kernel_started, this));
668 674 };
669 675
670 676
671 677 Notebook.prototype.restart_kernel = function () {
672 678 var that = this;
673 679 var notebook_id = IPython.save_widget.get_notebook_id();
674 680
675 681 var dialog = $('<div/>');
676 682 dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
677 683 $(document).append(dialog);
678 684 dialog.dialog({
679 685 resizable: false,
680 686 modal: true,
681 687 title: "Restart kernel or continue running?",
682 688 buttons : {
683 689 "Restart": function () {
684 690 that.kernel.restart($.proxy(that.kernel_started, that));
685 691 $(this).dialog('close');
686 692 },
687 693 "Continue running": function () {
688 694 $(this).dialog('close');
689 695 }
690 696 }
691 697 });
692 698 };
693 699
694 700
695 701 Notebook.prototype.kernel_started = function () {
696 702 console.log("Kernel started: ", this.kernel.kernel_id);
697 703 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
698 704 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
699 705 };
700 706
701 707
702 708 Notebook.prototype.handle_shell_reply = function (e) {
703 709 reply = $.parseJSON(e.data);
704 710 var header = reply.header;
705 711 var content = reply.content;
706 712 var msg_type = header.msg_type;
707 713 // console.log(reply);
708 714 var cell = this.cell_for_msg(reply.parent_header.msg_id);
709 715 if (msg_type === "execute_reply") {
710 716 cell.set_input_prompt(content.execution_count);
711 717 cell.element.removeClass("running");
712 718 this.dirty = true;
713 719 } else if (msg_type === "complete_reply") {
714 720 cell.finish_completing(content.matched_text, content.matches);
715 721 } else if (msg_type === "object_info_reply"){
716 722 //console.log('back from object_info_request : ')
717 723 rep = reply.content;
718 724 if(rep.found)
719 725 {
720 726 cell.finish_tooltip(rep.definition,rep.docstring);
721 727 }
722 728 } else {
723 729 //console.log("unknown reply:"+msg_type);
724 730 }
725 731 // when having a rely from object_info_reply,
726 732 // no payload so no nned to handle it
727 733 if(typeof(content.payload)!='undefined') {
728 734 var payload = content.payload || [];
729 735 this.handle_payload(cell, payload);
730 736 }
731 737 };
732 738
733 739
734 740 Notebook.prototype.handle_payload = function (cell, payload) {
735 741 var l = payload.length;
736 742 console.log(payload);
737 743 for (var i=0; i<l; i++) {
738 744 if (payload[i].source === 'IPython.zmq.page.page') {
739 745 if (payload[i].text.trim() !== '') {
740 746 IPython.pager.clear();
741 747 IPython.pager.expand();
742 748 IPython.pager.append_text(payload[i].text);
743 749 }
744 750 } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
745 751 var index = this.find_cell_index(cell);
746 752 var new_cell = this.insert_code_cell_below(index);
747 753 new_cell.set_code(payload[i].text);
748 754 this.dirty = true;
749 755 }
750 756 };
751 757 };
752 758
753 759
754 760 Notebook.prototype.handle_iopub_reply = function (e) {
755 761 reply = $.parseJSON(e.data);
756 762 var content = reply.content;
757 763 // console.log(reply);
758 764 var msg_type = reply.header.msg_type;
759 765 var cell = this.cell_for_msg(reply.parent_header.msg_id);
760 766 var output_types = ['stream','display_data','pyout','pyerr'];
761 767 if (output_types.indexOf(msg_type) >= 0) {
762 768 this.handle_output(cell, msg_type, content);
763 769 } else if (msg_type === 'status') {
764 770 if (content.execution_state === 'busy') {
765 771 IPython.kernel_status_widget.status_busy();
766 772 } else if (content.execution_state === 'idle') {
767 773 IPython.kernel_status_widget.status_idle();
768 774 } else if (content.execution_state === 'dead') {
769 775 this.handle_status_dead();
770 776 };
771 777 } else if (msg_type === 'clear_output') {
772 778 cell.clear_output(content.stdout, content.stderr, content.other);
773 779 };
774 780 };
775 781
776 782
777 783 Notebook.prototype.handle_status_dead = function () {
778 784 var that = this;
779 785 this.kernel.stop_channels();
780 786 var dialog = $('<div/>');
781 787 dialog.html('The kernel has died, would you like to restart it? If you do not restart the kernel, you will be able to save the notebook, but running code will not work until the notebook is reopened.');
782 788 $(document).append(dialog);
783 789 dialog.dialog({
784 790 resizable: false,
785 791 modal: true,
786 792 title: "Dead kernel",
787 793 buttons : {
788 794 "Restart": function () {
789 795 that.start_kernel();
790 796 $(this).dialog('close');
791 797 },
792 798 "Continue running": function () {
793 799 $(this).dialog('close');
794 800 }
795 801 }
796 802 });
797 803 };
798 804
799 805
800 806 Notebook.prototype.handle_output = function (cell, msg_type, content) {
801 807 var json = {};
802 808 json.output_type = msg_type;
803 809 if (msg_type === "stream") {
804 810 json.text = utils.fixConsole(content.data);
805 811 json.stream = content.name;
806 812 } else if (msg_type === "display_data") {
807 813 json = this.convert_mime_types(json, content.data);
808 814 } else if (msg_type === "pyout") {
809 815 json.prompt_number = content.execution_count;
810 816 json = this.convert_mime_types(json, content.data);
811 817 } else if (msg_type === "pyerr") {
812 818 json.ename = content.ename;
813 819 json.evalue = content.evalue;
814 820 var traceback = [];
815 821 for (var i=0; i<content.traceback.length; i++) {
816 822 traceback.push(utils.fixConsole(content.traceback[i]));
817 823 }
818 824 json.traceback = traceback;
819 825 };
820 826 cell.append_output(json);
821 827 this.dirty = true;
822 828 };
823 829
824 830
825 831 Notebook.prototype.convert_mime_types = function (json, data) {
826 832 if (data['text/plain'] !== undefined) {
827 833 json.text = utils.fixConsole(data['text/plain']);
828 834 };
829 835 if (data['text/html'] !== undefined) {
830 836 json.html = data['text/html'];
831 837 };
832 838 if (data['image/svg+xml'] !== undefined) {
833 839 json.svg = data['image/svg+xml'];
834 840 };
835 841 if (data['image/png'] !== undefined) {
836 842 json.png = data['image/png'];
837 843 };
838 844 if (data['image/jpeg'] !== undefined) {
839 845 json.jpeg = data['image/jpeg'];
840 846 };
841 847 if (data['text/latex'] !== undefined) {
842 848 json.latex = data['text/latex'];
843 849 };
844 850 if (data['application/json'] !== undefined) {
845 851 json.json = data['application/json'];
846 852 };
847 853 if (data['application/javascript'] !== undefined) {
848 854 json.javascript = data['application/javascript'];
849 855 }
850 856 return json;
851 857 };
852 858
853 859
854 860 Notebook.prototype.execute_selected_cell = function (options) {
855 861 // add_new: should a new cell be added if we are at the end of the nb
856 862 // terminal: execute in terminal mode, which stays in the current cell
857 863 default_options = {terminal: false, add_new: true}
858 864 $.extend(default_options, options)
859 865 var that = this;
860 866 var cell = that.selected_cell();
861 867 var cell_index = that.find_cell_index(cell);
862 868 if (cell instanceof IPython.CodeCell) {
863 869 cell.clear_output(true, true, true);
864 870 cell.set_input_prompt('*');
865 871 cell.element.addClass("running");
866 872 var code = cell.get_code();
867 873 var msg_id = that.kernel.execute(cell.get_code());
868 874 that.msg_cell_map[msg_id] = cell.cell_id;
869 875 } else if (cell instanceof IPython.HTMLCell) {
870 876 cell.render();
871 877 }
872 878 if (default_options.terminal) {
873 879 cell.select_all();
874 880 } else {
875 881 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
876 882 that.insert_code_cell_below();
877 883 // If we are adding a new cell at the end, scroll down to show it.
878 884 that.scroll_to_bottom();
879 885 } else {
880 886 that.select(cell_index+1);
881 887 };
882 888 };
883 889 this.dirty = true;
884 890 };
885 891
886 892
887 893 Notebook.prototype.execute_all_cells = function () {
888 894 var ncells = this.ncells();
889 895 for (var i=0; i<ncells; i++) {
890 896 this.select(i);
891 897 this.execute_selected_cell({add_new:false});
892 898 };
893 899 this.scroll_to_bottom();
894 900 };
895 901
896 902
897 903 Notebook.prototype.request_tool_tip = function (cell,func) {
898 904 // Feel free to shorten this logic if you are better
899 905 // than me in regEx
900 906 // basicaly you shoul be able to get xxx.xxx.xxx from
901 907 // something(range(10), kwarg=smth) ; xxx.xxx.xxx( firstarg, rand(234,23), kwarg1=2,
902 908 // remove everything between matchin bracket (need to iterate)
903 909 matchBracket = /\([^\(\)]+\)/g;
904 910 oldfunc = func;
905 911 func = func.replace(matchBracket,"");
906 912 while( oldfunc != func )
907 913 {
908 914 oldfunc = func;
909 915 func = func.replace(matchBracket,"");
910 916 }
911 917 // remove everythin after last open bracket
912 918 endBracket = /\([^\(]*$/g;
913 919 func = func.replace(endBracket,"");
914 920 var re = /[a-zA-Z._]+$/g;
915 921 var msg_id = this.kernel.object_info_request(re.exec(func));
916 922 this.msg_cell_map[msg_id] = cell.cell_id;
917 923 };
918 924
919 925 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
920 926 var msg_id = this.kernel.complete(line, cursor_pos);
921 927 this.msg_cell_map[msg_id] = cell.cell_id;
922 928 };
923 929
924 930 // Persistance and loading
925 931
926 932
927 933 Notebook.prototype.fromJSON = function (data) {
928 934 var ncells = this.ncells();
929 935 for (var i=0; i<ncells; i++) {
930 936 // Always delete cell 0 as they get renumbered as they are deleted.
931 937 this.delete_cell(0);
932 938 };
933 939 // Save the metadata
934 940 this.metadata = data.metadata;
935 941 // Only handle 1 worksheet for now.
936 942 var worksheet = data.worksheets[0];
937 943 if (worksheet !== undefined) {
938 944 var new_cells = worksheet.cells;
939 945 ncells = new_cells.length;
940 946 var cell_data = null;
941 947 var new_cell = null;
942 948 for (var i=0; i<ncells; i++) {
943 949 cell_data = new_cells[i];
944 950 if (cell_data.cell_type == 'code') {
945 951 new_cell = this.insert_code_cell_below();
946 952 new_cell.fromJSON(cell_data);
947 953 } else if (cell_data.cell_type === 'html') {
948 954 new_cell = this.insert_html_cell_below();
949 955 new_cell.fromJSON(cell_data);
950 956 } else if (cell_data.cell_type === 'markdown') {
951 957 new_cell = this.insert_markdown_cell_below();
952 958 new_cell.fromJSON(cell_data);
953 959 };
954 960 };
955 961 };
956 962 };
957 963
958 964
959 965 Notebook.prototype.toJSON = function () {
960 966 var cells = this.cells();
961 967 var ncells = cells.length;
962 968 cell_array = new Array(ncells);
963 969 for (var i=0; i<ncells; i++) {
964 970 cell_array[i] = cells[i].toJSON();
965 971 };
966 972 data = {
967 973 // Only handle 1 worksheet for now.
968 974 worksheets : [{cells:cell_array}],
969 975 metadata : this.metadata
970 976 }
971 977 return data
972 978 };
973 979
974 980 Notebook.prototype.save_notebook = function () {
975 981 if (IPython.save_widget.test_notebook_name()) {
976 982 var notebook_id = IPython.save_widget.get_notebook_id();
977 983 var nbname = IPython.save_widget.get_notebook_name();
978 984 // We may want to move the name/id/nbformat logic inside toJSON?
979 985 var data = this.toJSON();
980 986 data.metadata.name = nbname;
981 987 data.nbformat = 2;
982 988 // We do the call with settings so we can set cache to false.
983 989 var settings = {
984 990 processData : false,
985 991 cache : false,
986 992 type : "PUT",
987 993 data : JSON.stringify(data),
988 994 headers : {'Content-Type': 'application/json'},
989 995 success : $.proxy(this.notebook_saved,this),
990 996 error : $.proxy(this.notebook_save_failed,this)
991 997 };
992 998 IPython.save_widget.status_saving();
993 999 var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id
994 1000 $.ajax(url, settings);
995 1001 };
996 1002 };
997 1003
998 1004
999 1005 Notebook.prototype.notebook_saved = function (data, status, xhr) {
1000 1006 this.dirty = false;
1001 1007 IPython.save_widget.notebook_saved();
1002 1008 IPython.save_widget.status_save();
1003 1009 }
1004 1010
1005 1011
1006 1012 Notebook.prototype.notebook_save_failed = function (xhr, status, error_msg) {
1007 1013 // Notify the user and reset the save button
1008 1014 // TODO: Handle different types of errors (timeout etc.)
1009 1015 alert('An unexpected error occured while saving the notebook.');
1010 1016 IPython.save_widget.reset_status();
1011 1017 }
1012 1018
1013 1019
1014 1020 Notebook.prototype.load_notebook = function (callback) {
1015 1021 var that = this;
1016 1022 var notebook_id = IPython.save_widget.get_notebook_id();
1017 1023 // We do the call with settings so we can set cache to false.
1018 1024 var settings = {
1019 1025 processData : false,
1020 1026 cache : false,
1021 1027 type : "GET",
1022 1028 dataType : "json",
1023 1029 success : function (data, status, xhr) {
1024 1030 that.notebook_loaded(data, status, xhr);
1025 1031 if (callback !== undefined) {
1026 1032 callback();
1027 1033 };
1028 1034 }
1029 1035 };
1030 1036 IPython.save_widget.status_loading();
1031 1037 var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id
1032 1038 $.ajax(url, settings);
1033 1039 }
1034 1040
1035 1041
1036 1042 Notebook.prototype.notebook_loaded = function (data, status, xhr) {
1037 1043 var allowed = xhr.getResponseHeader('Allow');
1038 1044 this.fromJSON(data);
1039 1045 if (this.ncells() === 0) {
1040 1046 this.insert_code_cell_below();
1041 1047 };
1042 1048 IPython.save_widget.status_save();
1043 1049 IPython.save_widget.set_notebook_name(data.metadata.name);
1044 1050 this.dirty = false;
1045 1051 if (! this.read_only) {
1046 1052 this.start_kernel();
1047 1053 }
1048 1054 // fromJSON always selects the last cell inserted. We need to wait
1049 1055 // until that is done before scrolling to the top.
1050 1056 setTimeout(function () {
1051 1057 IPython.notebook.select(0);
1052 1058 IPython.notebook.scroll_to_top();
1053 1059 }, 50);
1054 1060 };
1055 1061
1056 1062 IPython.Notebook = Notebook;
1057 1063
1058 1064
1059 1065 return IPython;
1060 1066
1061 1067 }(IPython));
1062 1068
@@ -1,327 +1,333 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2008-2011 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // PanelSection
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13
14 14 var utils = IPython.utils;
15 15
16 16 // Base PanelSection class
17 17
18 18 var PanelSection = function (selector) {
19 19 this.selector = selector;
20 20 if (this.selector !== undefined) {
21 21 this.element = $(selector);
22 22 this.header = this.element.find('div.section_header');
23 23 this.content = this.element.find('div.section_content');
24 24 this.style();
25 25 this.bind_events();
26 26 }
27 27 this.expanded = true;
28 28 };
29 29
30 30
31 31 PanelSection.prototype.style = function () {
32 32 this.header.addClass('ui-widget ui-state-default ui-helper-clearfix');
33 33 this.header.attr('title', "Click to Show/Hide Section");
34 34 this.content.addClass('ui-widget section_content');
35 35 };
36 36
37 37
38 38 PanelSection.prototype.bind_events = function () {
39 39 var that = this;
40 40 this.header.click(function () {
41 41 that.toggle();
42 42 });
43 43 this.header.hover(function () {
44 44 that.header.toggleClass('ui-state-hover');
45 45 });
46 46 };
47 47
48 48
49 49 PanelSection.prototype.expand = function () {
50 50 if (!this.expanded) {
51 51 this.content.slideDown('fast');
52 52 this.expanded = true;
53 53 };
54 54 };
55 55
56 56
57 57 PanelSection.prototype.collapse = function () {
58 58 if (this.expanded) {
59 59 this.content.slideUp('fast');
60 60 this.expanded = false;
61 61 };
62 62 };
63 63
64 64
65 65 PanelSection.prototype.toggle = function () {
66 66 if (this.expanded === true) {
67 67 this.collapse();
68 68 } else {
69 69 this.expand();
70 70 };
71 71 };
72 72
73 73
74 74 PanelSection.prototype.create_children = function () {};
75 75
76 76
77 77 // NotebookSection
78 78
79 79 var NotebookSection = function () {
80 80 PanelSection.apply(this, arguments);
81 81 };
82 82
83 83
84 84 NotebookSection.prototype = new PanelSection();
85 85
86 86
87 87 NotebookSection.prototype.style = function () {
88 88 PanelSection.prototype.style.apply(this);
89 89 this.content.addClass('ui-helper-clearfix');
90 90 this.content.find('div.section_row').addClass('ui-helper-clearfix');
91 91 this.content.find('#new_open').buttonset();
92 92 this.content.find('#new_notebook').attr('title', "Create a new notebook");
93 93 this.content.find('#open_notebook').attr('title', "Open an existing notebook");
94 94 this.content.find('#download_notebook').button();
95 95 this.content.find('#download_notebook').attr('title',
96 96 "Download the notebook in the specified format," +
97 97 " either full ipynb notebook or as a Python script." +
98 98 " Make sure to save before downloading, to ensure the file is up to date."
99 99 );
100 100 // upload notebook doesn't exist:
101 101 this.content.find('#upload_notebook').button();
102 102 this.content.find('#download_format').addClass('ui-widget ui-widget-content');
103 103 this.content.find('#download_format option').addClass('ui-widget ui-widget-content');
104 104 };
105 105
106 106
107 107 NotebookSection.prototype.bind_events = function () {
108 108 PanelSection.prototype.bind_events.apply(this);
109 109 var that = this;
110 110 this.content.find('#new_notebook').click(function () {
111 111 window.open($('body').data('baseProjectUrl')+'new');
112 112 });
113 113 this.content.find('#open_notebook').click(function () {
114 114 window.open($('body').data('baseProjectUrl'));
115 115 });
116 116 this.content.find('#download_notebook').click(function () {
117 117 var format = that.content.find('#download_format').val();
118 118 var notebook_id = IPython.save_widget.get_notebook_id();
119 119 var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id + '?format=' + format;
120 120 window.open(url,'_newtab');
121 121 });
122 122 };
123 123
124 124 // ConfigSection
125 125
126 126 var ConfigSection = function () {
127 127 PanelSection.apply(this, arguments);
128 128 };
129 129
130 130 ConfigSection.prototype = new PanelSection();
131 131
132 132 ConfigSection.prototype.style = function () {
133 133 PanelSection.prototype.style.apply(this);
134 134 this.content.addClass('ui-helper-clearfix');
135 135 this.content.find('div.section_row').addClass('ui-helper-clearfix');
136 136
137 137 this.content.find('#tooltipontab').attr('title', 'Show tooltip if yuo press <Tab> after "(" or a white space');
138 138 this.content.find('#tooltipontab_label').attr('title', 'Show Tooltip when pressing Tab');
139 139
140 140 this.content.find('#timebeforetooltip').attr('title', 'Time before a tooltip auto-appear when "(" is pressed (negative value supress tooltip)');
141 141 this.content.find('#timebeforetooltip_label').attr('title', 'Time before a tooltip auto-appear when "(" is pressed (negative value supress tooltip)');
142 142
143 this.content.find('#smartcompleter').attr('title', 'When inside function call, completer try to propose kwargs first');
144 this.content.find('#smartcompleter_label').attr('title', 'When inside function call, completer try to propose kwargs first');
143 145 };
144 146
145 147
146 148 ConfigSection.prototype.bind_events = function () {
147 149 PanelSection.prototype.bind_events.apply(this);
148 150 this.content.find('#tooltipontab').change(function () {
149 151 var state = $('#tooltipontab').prop('checked');
150 152 IPython.notebook.set_tooltipontab(state);
151 153 });
152 154 this.content.find('#timebeforetooltip').change(function () {
153 155 var state = $('#timebeforetooltip').prop('value');
154 156 IPython.notebook.set_timebeforetooltip(state);
155 157 });
158 this.content.find('#smartcompleter').change(function () {
159 var state = $('#smartcompleter').prop('checked');
160 IPython.notebook.set_smartcompleter(state);
161 });
156 162 };
157 163
158 164 // CellSection
159 165
160 166 var CellSection = function () {
161 167 PanelSection.apply(this, arguments);
162 168 };
163 169
164 170 CellSection.prototype = new PanelSection();
165 171
166 172
167 173 CellSection.prototype.style = function () {
168 174 PanelSection.prototype.style.apply(this);
169 175 this.content.addClass('ui-helper-clearfix');
170 176 this.content.find('div.section_row').addClass('ui-helper-clearfix');
171 177 this.content.find('#delete_cell').button();
172 178 this.content.find('#delete_cell').attr('title', "Delete the selected cell");
173 179
174 180 this.content.find('#insert').buttonset();
175 181 this.content.find('#insert_cell_above').attr('title', "Insert new cell above selected");
176 182 this.content.find('#insert_cell_below').attr('title', "Insert new cell below selected");
177 183
178 184 this.content.find('#move').buttonset();
179 185 this.content.find('#move_cell_up').attr('title', "Move selected cell up one in the Notebook");
180 186 this.content.find('#move_cell_down').attr('title', "Move selected cell down one in the Notebook");
181 187
182 188 this.content.find('#cell_type').buttonset();
183 189 this.content.find('#to_markdown').attr('title', 'Change selected cell to markdown (for text)')
184 190 this.content.find('#to_code').attr('title', 'Change selected cell to code (for execution)')
185 191
186 192 this.content.find('#cell_output').buttonset();
187 193 this.content.find('#toggle_output').attr('title', 'Toggle visibility of the output of code cells')
188 194 this.content.find('#clear_all_output').attr('title', 'Clear output of all code cells (actually removes the data, unlike toggle)')
189 195
190 196 this.content.find('#run_cells').buttonset();
191 197 this.content.find('#run_selected_cell').attr('title', 'Submit the selected cell for execution')
192 198 this.content.find('#run_all_cells').attr('title', 'Run *all* code cells in the notebook in order')
193 199 this.content.find('#autoindent').attr('title', 'Autoindent code as-you-type')
194 200 this.content.find('#autoindent_label').attr('title', 'Autoindent code as-you-type')
195 201 };
196 202
197 203
198 204 CellSection.prototype.bind_events = function () {
199 205 PanelSection.prototype.bind_events.apply(this);
200 206 this.content.find('#toggle_output').click(function () {
201 207 IPython.notebook.toggle_output();
202 208 });
203 209 this.content.find('#clear_all_output').click(function () {
204 210 IPython.notebook.clear_all_output();
205 211 });
206 212 this.content.find('#delete_cell').click(function () {
207 213 IPython.notebook.delete_cell();
208 214 });
209 215 this.content.find('#insert_cell_above').click(function () {
210 216 IPython.notebook.insert_code_cell_above();
211 217 });
212 218 this.content.find('#insert_cell_below').click(function () {
213 219 IPython.notebook.insert_code_cell_below();
214 220 });
215 221 this.content.find('#move_cell_up').click(function () {
216 222 IPython.notebook.move_cell_up();
217 223 });
218 224 this.content.find('#move_cell_down').click(function () {
219 225 IPython.notebook.move_cell_down();
220 226 });
221 227 this.content.find('#to_code').click(function () {
222 228 IPython.notebook.to_code();
223 229 });
224 230 this.content.find('#to_markdown').click(function () {
225 231 IPython.notebook.to_markdown();
226 232 });
227 233 this.content.find('#run_selected_cell').click(function () {
228 234 IPython.notebook.execute_selected_cell();
229 235 });
230 236 this.content.find('#run_all_cells').click(function () {
231 237 IPython.notebook.execute_all_cells();
232 238 });
233 239 this.content.find('#autoindent').change(function () {
234 240 var state = $('#autoindent').prop('checked');
235 241 IPython.notebook.set_autoindent(state);
236 242 });
237 243 this.content.find('#tooltipontab').change(function () {
238 244 var state = $('#tooltipontab').prop('checked');
239 245 IPython.notebook.set_tooltipontab(state);
240 246 });
241 247 };
242 248
243 249
244 250 // KernelSection
245 251
246 252 var KernelSection = function () {
247 253 PanelSection.apply(this, arguments);
248 254 };
249 255
250 256
251 257 KernelSection.prototype = new PanelSection();
252 258
253 259
254 260 KernelSection.prototype.style = function () {
255 261 PanelSection.prototype.style.apply(this);
256 262 this.content.addClass('ui-helper-clearfix');
257 263 this.content.find('div.section_row').addClass('ui-helper-clearfix');
258 264 this.content.find('#int_restart').buttonset();
259 265 this.content.find("#int_kernel").attr('title', "Interrupt the kernel with SIGINT/Ctrl-C");
260 266 this.content.find("#restart_kernel").attr('title',
261 267 "Restart the kernel. This will shutdown the current kernel," +
262 268 " and start a new, clean kernel in its place, connected to this Notebook." +
263 269 " This may break the connection of other clients connected to this kernel." );
264 270 var kill_tip = "Kill the kernel on exit. If unchecked, the kernel will remain" +
265 271 " active after closing the session, allowing you to reconnect and resume later.";
266 272 this.content.find('#kill_kernel').attr('title', kill_tip);
267 273 this.content.find('#kill_kernel_label').attr('title', kill_tip);
268 274
269 275 };
270 276
271 277
272 278 KernelSection.prototype.bind_events = function () {
273 279 PanelSection.prototype.bind_events.apply(this);
274 280 this.content.find('#restart_kernel').click(function () {
275 281 IPython.notebook.restart_kernel();
276 282 });
277 283 this.content.find('#int_kernel').click(function () {
278 284 IPython.notebook.kernel.interrupt();
279 285 });
280 286 };
281 287
282 288
283 289 // HelpSection
284 290
285 291 var HelpSection = function () {
286 292 PanelSection.apply(this, arguments);
287 293 };
288 294
289 295
290 296 HelpSection.prototype = new PanelSection();
291 297
292 298
293 299 HelpSection.prototype.style = function () {
294 300 PanelSection.prototype.style.apply(this);
295 301 PanelSection.prototype.style.apply(this);
296 302 this.content.addClass('ui-helper-clearfix');
297 303 this.content.find('div.section_row').addClass('ui-helper-clearfix');
298 304 this.content.find('#help_buttons0').buttonset();
299 305 this.content.find('#help_buttons1').buttonset();
300 306 this.content.find('#help_buttons2').buttonset();
301 307 this.content.find('#python_help').attr('title', "Open the online Python documentation in a new tab")
302 308 this.content.find('#ipython_help').attr('title', "Open the online IPython documentation in a new tab")
303 309 this.content.find('#numpy_help').attr('title', "Open the online NumPy documentation in a new tab")
304 310 this.content.find('#scipy_help').attr('title', "Open the online SciPy documentation in a new tab")
305 311 this.content.find('#matplotlib_help').attr('title', "Open the online Matplotlib documentation in a new tab")
306 312 this.content.find('#sympy_help').attr('title', "Open the online SymPy documentation in a new tab")
307 313 };
308 314
309 315
310 316 HelpSection.prototype.bind_events = function () {
311 317 PanelSection.prototype.bind_events.apply(this);
312 318 };
313 319
314 320
315 321 // Set module variables
316 322
317 323 IPython.PanelSection = PanelSection;
318 324 IPython.NotebookSection = NotebookSection;
319 325 IPython.CellSection = CellSection;
320 326 IPython.ConfigSection = ConfigSection;
321 327 IPython.KernelSection = KernelSection;
322 328 IPython.HelpSection = HelpSection;
323 329
324 330 return IPython;
325 331
326 332 }(IPython));
327 333
@@ -1,321 +1,327 b''
1 1 <!DOCTYPE HTML>
2 2 <html>
3 3
4 4 <head>
5 5 <meta charset="utf-8">
6 6
7 7 <title>IPython Notebook</title>
8 8
9 9 <!-- <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML" charset="utf-8"></script> -->
10 10 <script type='text/javascript' src='static/mathjax/MathJax.js?config=TeX-AMS_HTML' charset='utf-8'></script>
11 11 <script type="text/javascript">
12 12 function CheckMathJax(){
13 13 var div=document.getElementById("MathJaxFetchingWarning")
14 14 if(window.MathJax){
15 15 document.body.removeChild(div)
16 16 }
17 17 else{
18 18 div.style.display = "block";
19 19 }
20 20 }
21 21 if (typeof MathJax == 'undefined') {
22 22 console.log("No local MathJax, loading from CDN");
23 23 document.write(unescape("%3Cscript type='text/javascript' src='http://cdn.mathjax.org/mathjax/latest/MathJax.js%3Fconfig=TeX-AMS_HTML' charset='utf-8'%3E%3C/script%3E"));
24 24 }else{
25 25 console.log("Using local MathJax");
26 26 }
27 27 </script>
28 28
29 29 <link rel="stylesheet" href="static/jquery/css/themes/aristo/jquery-wijmo.css" type="text/css" />
30 30 <link rel="stylesheet" href="static/codemirror/lib/codemirror.css">
31 31 <link rel="stylesheet" href="static/codemirror/mode/markdown/markdown.css">
32 32 <link rel="stylesheet" href="static/codemirror/mode/rst/rst.css">
33 33 <link rel="stylesheet" href="static/codemirror/theme/ipython.css">
34 34 <link rel="stylesheet" href="static/codemirror/theme/default.css">
35 35
36 36 <link rel="stylesheet" href="static/prettify/prettify.css"/>
37 37
38 38 <link rel="stylesheet" href="static/css/boilerplate.css" type="text/css" />
39 39 <link rel="stylesheet" href="static/css/layout.css" type="text/css" />
40 40 <link rel="stylesheet" href="static/css/base.css" type="text/css" />
41 41 <link rel="stylesheet" href="static/css/notebook.css" type="text/css" />
42 42 <link rel="stylesheet" href="static/css/renderedhtml.css" type="text/css" />
43 43
44 44 <meta name="read_only" content="{{read_only}}"/>
45 45
46 46 </head>
47 47
48 48 <body onload='CheckMathJax();'
49 49 data-project={{project}} data-notebook-id={{notebook_id}}
50 50 data-base-project-url={{base_project_url}} data-base-kernel-url={{base_kernel_url}}
51 51 >
52 52
53 53 <div id="header">
54 54 <span id="ipython_notebook"><h1>IPython Notebook</h1></span>
55 55 <span id="save_widget">
56 56 <input type="text" id="notebook_name" size="20"></textarea>
57 57 <button id="save_notebook"><u>S</u>ave</button>
58 58 </span>
59 59 <span id="quick_help_area">
60 60 <button id="quick_help">Quick<u>H</u>elp</button>
61 61 </span>
62 62
63 63 <span id="login_widget">
64 64 {% comment This is a temporary workaround to hide the logout button %}
65 65 {% comment when appropriate until notebook.html is templated %}
66 66 {% if current_user and current_user != 'anonymous' %}
67 67 <button id="logout">Logout</button>
68 68 {% end %}
69 69 </span>
70 70
71 71 <span id="kernel_status">Idle</span>
72 72 </div>
73 73
74 74 <div id="MathJaxFetchingWarning"
75 75 style="width:80%; margin:auto;padding-top:20%;text-align: justify; display:none">
76 76 <p style="font-size:26px;">There was an issue trying to fetch MathJax.js
77 77 from the internet.</p>
78 78
79 79 <p style="padding:0.2em"> With a working internet connection, you can run
80 80 the following at a Python or IPython prompt, which will install a local
81 81 copy of MathJax:</p>
82 82
83 83 <pre style="background-color:lightblue;border:thin silver solid;padding:0.4em">
84 84 from IPython.external import mathjax; mathjax.install_mathjax()
85 85 </pre>
86 86 This will try to install MathJax into the directory where you installed
87 87 IPython. If you installed IPython to a location that requires
88 88 administrative privileges to write, you will need to make this call as
89 89 an administrator. On OSX/Linux/Unix, this can be done at the
90 90 command-line via:
91 91 <pre style="background-color:lightblue;border:thin silver solid;padding:0.4em">
92 92 sudo python -c "from IPython.external import mathjax; mathjax.install_mathjax()"
93 93 </pre>
94 94 </p>
95 95 </div>
96 96
97 97 <div id="main_app">
98 98
99 99 <div id="left_panel">
100 100
101 101 <div id="notebook_section">
102 102 <div class="section_header">
103 103 <h3>Notebook</h3>
104 104 </div>
105 105 <div class="section_content">
106 106 <div class="section_row">
107 107 <span id="new_open" class="section_row_buttons">
108 108 <button id="new_notebook">New</button>
109 109 <button id="open_notebook">Open</button>
110 110 </span>
111 111 <span class="section_row_header">Actions</span>
112 112 </div>
113 113 <div class="section_row">
114 114 <span>
115 115 <select id="download_format">
116 116 <option value="json">ipynb</option>
117 117 <option value="py">py</option>
118 118 </select>
119 119 </span>
120 120 <span class="section_row_buttons">
121 121 <button id="download_notebook">Download</button>
122 122 </span>
123 123 </div>
124 124 <div class="section_row">
125 125 <span class="section_row_buttons">
126 126 <span id="print_widget">
127 127 <button id="print_notebook">Print</button>
128 128 </span>
129 129 </span>
130 130 </div>
131 131 </div>
132 132 </div>
133 133
134 134 <div id="cell_section">
135 135 <div class="section_header">
136 136 <h3>Cell</h3>
137 137 </div>
138 138 <div class="section_content">
139 139 <div class="section_row">
140 140 <span class="section_row_buttons">
141 141 <button id="delete_cell"><u>D</u>elete</button>
142 142 </span>
143 143 <span class="section_row_header">Actions</span>
144 144 </div>
145 145 <div class="section_row">
146 146 <span id="cell_type" class="section_row_buttons">
147 147 <button id="to_code"><u>C</u>ode</button>
148 148 <!-- <button id="to_html">HTML</button>-->
149 149 <button id="to_markdown"><u>M</u>arkdown</button>
150 150 </span>
151 151 <span class="button_label">Format</span>
152 152 </div>
153 153 <div class="section_row">
154 154 <span id="cell_output" class="section_row_buttons">
155 155 <button id="toggle_output"><u>T</u>oggle</button>
156 156 <button id="clear_all_output">ClearAll</button>
157 157 </span>
158 158 <span class="button_label">Output</span>
159 159 </div>
160 160 <div class="section_row">
161 161 <span id="insert" class="section_row_buttons">
162 162 <button id="insert_cell_above"><u>A</u>bove</button>
163 163 <button id="insert_cell_below"><u>B</u>elow</button>
164 164 </span>
165 165 <span class="button_label">Insert</span>
166 166 </div>
167 167 <div class="section_row">
168 168 <span id="move" class="section_row_buttons">
169 169 <button id="move_cell_up">Up</button>
170 170 <button id="move_cell_down">Down</button>
171 171 </span>
172 172 <span class="button_label">Move</span>
173 173 </div>
174 174 <div class="section_row">
175 175 <span id="run_cells" class="section_row_buttons">
176 176 <button id="run_selected_cell">Selected</button>
177 177 <button id="run_all_cells">All</button>
178 178 </span>
179 179 <span class="button_label">Run</span>
180 180 </div>
181 181 <div class="section_row">
182 182 <span id="autoindent_span">
183 183 <input type="checkbox" id="autoindent" checked="true"></input>
184 184 </span>
185 185 <span class="checkbox_label" id="autoindent_label">Autoindent:</span>
186 186 </div>
187 187 </div>
188 188 </div>
189 189
190 190 <div id="kernel_section">
191 191 <div class="section_header">
192 192 <h3>Kernel</h3>
193 193 </div>
194 194 <div class="section_content">
195 195 <div class="section_row">
196 196 <span id="int_restart" class="section_row_buttons">
197 197 <button id="int_kernel"><u>I</u>nterrupt</button>
198 198 <button id="restart_kernel">Restart</button>
199 199 </span>
200 200 <span class="section_row_header">Actions</span>
201 201 </div>
202 202 <div class="section_row">
203 203 <span id="kernel_persist">
204 204 {% if kill_kernel %}
205 205 <input type="checkbox" id="kill_kernel" checked="true"></input>
206 206 {% else %}
207 207 <input type="checkbox" id="kill_kernel"></input>
208 208 {% end %}
209 209 </span>
210 210 <span class="checkbox_label" id="kill_kernel_label">Kill kernel upon exit:</span>
211 211 </div>
212 212 </div>
213 213 </div>
214 214
215 215 <div id="help_section">
216 216 <div class="section_header">
217 217 <h3>Help</h3>
218 218 </div>
219 219 <div class="section_content">
220 220 <div class="section_row">
221 221 <span id="help_buttons0" class="section_row_buttons">
222 222 <a id="python_help" href="http://docs.python.org" target="_blank">Python</a>
223 223 <a id="ipython_help" href="http://ipython.org/documentation.html" target="_blank">IPython</a>
224 224 </span>
225 225 <span class="section_row_header">Links</span>
226 226 </div>
227 227 <div class="section_row">
228 228 <span id="help_buttons1" class="section_row_buttons">
229 229 <a id="numpy_help" href="http://docs.scipy.org/doc/numpy/reference/" target="_blank">NumPy</a>
230 230 <a id="scipy_help" href="http://docs.scipy.org/doc/scipy/reference/" target="_blank">SciPy</a>
231 231 </span>
232 232 </div>
233 233 <div class="section_row">
234 234 <span id="help_buttons2" class="section_row_buttons">
235 235 <a id="matplotlib_help" href="http://matplotlib.sourceforge.net/" target="_blank">MPL</a>
236 236 <a id="sympy_help" href="http://docs.sympy.org/dev/index.html" target="_blank">SymPy</a>
237 237 </span>
238 238 </div>
239 239 <div class="section_row">
240 240 <span class="help_string">run selected cell</span>
241 241 <span class="help_string_label">Shift-Enter :</span>
242 242 </div>
243 243 <div class="section_row">
244 244 <span class="help_string">run selected cell in-place</span>
245 245 <span class="help_string_label">Ctrl-Enter :</span>
246 246 </div>
247 247 <div class="section_row">
248 248 <span class="help_string">show keyboard shortcuts</span>
249 249 <span class="help_string_label">Ctrl-m h :</span>
250 250 </div>
251 251 </div>
252 252 </div>
253 253
254 254 <div id="config_section">
255 255 <div class="section_header">
256 256 <h3>Config</h3>
257 257 </div>
258 258 <div class="section_content">
259 259 <div class="section_row">
260 260 <span id="tooltipontab_span">
261 261 <input type="checkbox" id="tooltipontab" checked="true"></input>
262 262 </span>
263 263 <span class="checkbox_label" id="tooltipontab_label">Tooltip on tab:</span>
264 264 </div>
265 265 <div class="section_row">
266 <span id="smartcompleter_span">
267 <input type="checkbox" id="smartcompleter" checked="true"></input>
268 </span>
269 <span class="checkbox_label" id="smartcompleter_label">Smart completer:</span>
270 </div>
271 <div class="section_row">
266 272 <span id="tooltipontab_span">
267 273 <input type="text" id="timebeforetooltip" value="1200"></input>
268 274 </span>
269 275 <span class="numeric_input_label" id="timebeforetooltip_label">Time before tooltip : </span>
270 276 </div>
271 277 </div>
272 278 </div>
273 279
274 280 </div>
275 281 <div id="left_panel_splitter"></div>
276 282 <div id="notebook_panel">
277 283 <div id="notebook"></div>
278 284 <div id="pager_splitter"></div>
279 285 <div id="pager"></div>
280 286 </div>
281 287
282 288 </div>
283 289
284 290 <script src="static/jquery/js/jquery-1.6.2.min.js" type="text/javascript" charset="utf-8"></script>
285 291 <script src="static/jquery/js/jquery-ui-1.8.14.custom.min.js" type="text/javascript" charset="utf-8"></script>
286 292 <script src="static/jquery/js/jquery.autogrow.js" type="text/javascript" charset="utf-8"></script>
287 293
288 294 <script src="static/codemirror/lib/codemirror.js" charset="utf-8"></script>
289 295 <script src="static/codemirror/mode/python/python.js" charset="utf-8"></script>
290 296 <script src="static/codemirror/mode/htmlmixed/htmlmixed.js" charset="utf-8"></script>
291 297 <script src="static/codemirror/mode/xml/xml.js" charset="utf-8"></script>
292 298 <script src="static/codemirror/mode/javascript/javascript.js" charset="utf-8"></script>
293 299 <script src="static/codemirror/mode/css/css.js" charset="utf-8"></script>
294 300 <script src="static/codemirror/mode/rst/rst.js" charset="utf-8"></script>
295 301 <script src="static/codemirror/mode/markdown/markdown.js" charset="utf-8"></script>
296 302
297 303 <script src="static/pagedown/Markdown.Converter.js" charset="utf-8"></script>
298 304
299 305 <script src="static/prettify/prettify.js" charset="utf-8"></script>
300 306
301 307 <script src="static/js/namespace.js" type="text/javascript" charset="utf-8"></script>
302 308 <script src="static/js/utils.js" type="text/javascript" charset="utf-8"></script>
303 309 <script src="static/js/cell.js" type="text/javascript" charset="utf-8"></script>
304 310 <script src="static/js/codecell.js" type="text/javascript" charset="utf-8"></script>
305 311 <script src="static/js/textcell.js" type="text/javascript" charset="utf-8"></script>
306 312 <script src="static/js/kernel.js" type="text/javascript" charset="utf-8"></script>
307 313 <script src="static/js/kernelstatus.js" type="text/javascript" charset="utf-8"></script>
308 314 <script src="static/js/layout.js" type="text/javascript" charset="utf-8"></script>
309 315 <script src="static/js/savewidget.js" type="text/javascript" charset="utf-8"></script>
310 316 <script src="static/js/quickhelp.js" type="text/javascript" charset="utf-8"></script>
311 317 <script src="static/js/loginwidget.js" type="text/javascript" charset="utf-8"></script>
312 318 <script src="static/js/pager.js" type="text/javascript" charset="utf-8"></script>
313 319 <script src="static/js/panelsection.js" type="text/javascript" charset="utf-8"></script>
314 320 <script src="static/js/printwidget.js" type="text/javascript" charset="utf-8"></script>
315 321 <script src="static/js/leftpanel.js" type="text/javascript" charset="utf-8"></script>
316 322 <script src="static/js/notebook.js" type="text/javascript" charset="utf-8"></script>
317 323 <script src="static/js/notebookmain.js" type="text/javascript" charset="utf-8"></script>
318 324
319 325 </body>
320 326
321 327 </html>
General Comments 0
You need to be logged in to leave comments. Login now