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