##// END OF EJS Templates
Merge pull request #1825 from minrk/elide2...
Min RK -
r7614:ef57f6e2 merge
parent child Browse files
Show More
@@ -1,345 +1,383 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 overflow: hidden;
10 10 }
11 11
12 12 span#save_widget {
13 13 padding: 5px;
14 14 margin: 0px 0px 0px 300px;
15 15 display:inline-block;
16 16 }
17 17
18 18 span#notebook_name {
19 19 height: 1em;
20 20 line-height: 1em;
21 21 padding: 3px;
22 22 border: none;
23 23 font-size: 146.5%;
24 24 }
25 25
26 26 .ui-menubar-item .ui-button .ui-button-text {
27 27 padding: 0.4em 1.0em;
28 28 font-size: 100%;
29 29 }
30 30
31 31 .ui-menu {
32 32 -moz-box-shadow: 0px 6px 10px -1px #adadad;
33 33 -webkit-box-shadow: 0px 6px 10px -1px #adadad;
34 34 box-shadow: 0px 6px 10px -1px #adadad;
35 35 }
36 36
37 37 .ui-menu .ui-menu-item a {
38 38 border: 1px solid transparent;
39 39 padding: 2px 1.6em;
40 40 }
41 41
42 42 .ui-menu .ui-menu-item a.ui-state-focus {
43 43 margin: 0;
44 44 }
45 45
46 46 .ui-menu hr {
47 47 margin: 0.3em 0;
48 48 }
49 49
50 50 #menubar_container {
51 51 position: relative;
52 52 }
53 53
54 54 #notification {
55 55 position: absolute;
56 56 right: 3px;
57 57 top: 3px;
58 58 height: 25px;
59 59 padding: 3px 6px;
60 60 z-index: 10;
61 61 }
62 62
63 63 #toolbar {
64 64 padding: 3px 15px;
65 65 }
66 66
67 67 #cell_type {
68 68 font-size: 85%;
69 69 }
70 70
71 71
72 72 div#main_app {
73 73 width: 100%;
74 74 position: relative;
75 75 }
76 76
77 77 span#quick_help_area {
78 78 position: static;
79 79 padding: 5px 0px;
80 80 margin: 0px 0px 0px 0px;
81 81 }
82 82
83 83 .help_string {
84 84 float: right;
85 85 width: 170px;
86 86 padding: 0px 5px;
87 87 text-align: left;
88 88 font-size: 85%;
89 89 }
90 90
91 91 .help_string_label {
92 92 float: right;
93 93 font-size: 85%;
94 94 }
95 95
96 96 div#notebook_panel {
97 97 margin: 0px 0px 0px 0px;
98 98 padding: 0px;
99 99 }
100 100
101 101 div#notebook {
102 102 overflow-y: scroll;
103 103 overflow-x: auto;
104 104 width: 100%;
105 105 /* This spaces the cell away from the edge of the notebook area */
106 106 padding: 5px 5px 15px 5px;
107 margin: 0px
107 margin: 0px;
108 108 background-color: white;
109 109 }
110 110
111 111 div#pager_splitter {
112 112 height: 8px;
113 113 }
114 114
115 115 div#pager {
116 116 padding: 15px;
117 117 overflow: auto;
118 118 display: none;
119 119 }
120 120
121 121 div.ui-widget-content {
122 122 border: 1px solid #aaa;
123 123 outline: none;
124 124 }
125 125
126 126 .cell {
127 127 border: 1px solid transparent;
128 128 }
129 129
130 130 div.cell {
131 131 width: 100%;
132 132 padding: 5px 5px 5px 0px;
133 133 /* This acts as a spacer between cells, that is outside the border */
134 134 margin: 2px 0px 2px 0px;
135 135 }
136 136
137 137 div.code_cell {
138 138 background-color: white;
139 139 }
140
140 141 /* any special styling for code cells that are currently running goes here */
141 142 div.code_cell.running {
142 143 }
143 144
144 145 div.prompt {
145 146 /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */
146 147 width: 11ex;
147 148 /* This 0.4em is tuned to match the padding on the CodeMirror editor. */
148 149 padding: 0.4em;
149 150 margin: 0px;
150 151 font-family: monospace;
151 152 text-align:right;
152 153 }
153 154
154 155 div.input {
155 156 page-break-inside: avoid;
156 157 }
157 158
158 159 /* input_area and input_prompt must match in top border and margin for alignment */
159 160 div.input_area {
160 161 color: black;
161 162 border: 1px solid #ddd;
162 163 border-radius: 3px;
163 164 background: #f7f7f7;
164 165 }
165 166
166 167 div.input_prompt {
167 168 color: navy;
168 169 border-top: 1px solid transparent;
169 170 }
170 171
171 div.output {
172 div.output_wrapper {
172 173 /* This is a spacer between the input and output of each cell */
173 174 margin-top: 5px;
175 margin-left: 5px;
176 /* FF needs explicit width to stretch */
177 width: 100%;
178 /* this position must be relative to enable descendents to be absolute within it */
179 position: relative;
180 }
181
182 /* class for the output area when it should be height-limited */
183 div.output_scroll {
184 /* ideally, this would be max-height, but FF barfs all over that */
185 height: 24em;
186 /* FF needs this *and the wrapper* to specify full width, or it will shrinkwrap */
187 width: 100%;
188
189 overflow: auto;
190 border-radius: 3px;
191 box-shadow: inset 0 2px 8px rgba(0, 0, 0, .8);
192 }
193
194 /* output div while it is collapsed */
195 div.output_collapsed {
196 margin-right: 5px;
197 }
198
199 div.out_prompt_overlay {
200 height: 100%;
201 padding: 0px;
202 position: absolute;
203 border-radius: 3px;
204 }
205
206 div.out_prompt_overlay:hover {
207 /* use inner shadow to get border that is computed the same on WebKit/FF */
208 box-shadow: inset 0 0 1px #000;
209 background: rgba(240, 240, 240, 0.5);
174 210 }
175 211
176 212 div.output_prompt {
177 213 color: darkred;
214 /* 5px right shift to account for margin in parent container */
215 margin: 0 5px 0 -5px;
178 216 }
179 217
180 218 /* This class is the outer container of all output sections. */
181 219 div.output_area {
182 220 padding: 0px;
183 221 page-break-inside: avoid;
184 222 }
185 223
186 224 /* This class is for the output subarea inside the output_area and after
187 225 the prompt div. */
188 226 div.output_subarea {
189 227 padding: 0.4em 0.4em 0.4em 0.4em;
190 228 }
191 229
192 230 /* The rest of the output_* classes are for special styling of the different
193 231 output types */
194 232
195 233 /* all text output has this class: */
196 234 div.output_text {
197 235 text-align: left;
198 236 color: black;
199 237 font-family: monospace;
200 238 }
201 239
202 240 /* stdout/stderr are 'text' as well as 'stream', but pyout/pyerr are *not* streams */
203 241 div.output_stream {
204 242 padding-top: 0.0em;
205 243 padding-bottom: 0.0em;
206 244 }
207 245 div.output_stdout {
208 246 }
209 247 div.output_stderr {
210 248 background: #fdd; /* very light red background for stderr */
211 249 }
212 250
213 251 div.output_latex {
214 252 text-align: left;
215 253 color: black;
216 254 }
217 255
218 256 div.output_html {
219 257 }
220 258
221 259 div.output_png {
222 260 }
223 261
224 262 div.output_jpeg {
225 263 }
226 264
227 265 div.text_cell {
228 266 background-color: white;
229 267 padding: 5px 5px 5px 5px;
230 268 }
231 269
232 270 div.text_cell_input {
233 271 color: black;
234 272 border: 1px solid #ddd;
235 273 border-radius: 3px;
236 274 background: #f7f7f7;
237 275 }
238 276
239 277 div.text_cell_render {
240 278 font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
241 279 outline: none;
242 280 resize: none;
243 281 width: inherit;
244 282 border-style: none;
245 283 padding: 5px;
246 284 color: black;
247 285 }
248 286
249 287 .CodeMirror span {
250 288 vertical-align: bottom;
251 289 }
252 290
253 291 .CodeMirror {
254 292 line-height: 1.231; /* Changed from 1em to our global default */
255 293 }
256 294
257 295 .CodeMirror-scroll {
258 296 height: auto; /* Changed to auto to autogrow */
259 297 /* The CodeMirror docs are a bit fuzzy on if overflow-y should be hidden or visible.*/
260 298 /* We have found that if it is visible, vertical scrollbars appear with font size changes.*/
261 299 overflow-y: hidden;
262 300 overflow-x: auto; /* Changed from auto to remove scrollbar */
263 301 }
264 302
265 303 /* CSS font colors for translated ANSI colors. */
266 304
267 305
268 306 .ansiblack {color: black;}
269 307 .ansired {color: darkred;}
270 308 .ansigreen {color: darkgreen;}
271 309 .ansiyellow {color: brown;}
272 310 .ansiblue {color: darkblue;}
273 311 .ansipurple {color: darkviolet;}
274 312 .ansicyan {color: steelblue;}
275 313 .ansigrey {color: grey;}
276 314 .ansibold {font-weight: bold;}
277 315
278 316 .completions {
279 317 position: absolute;
280 318 z-index: 10;
281 319 overflow: hidden;
282 320 border: 1px solid grey;
283 321 }
284 322
285 323 .completions select {
286 324 background: white;
287 325 outline: none;
288 326 border: none;
289 327 padding: 0px;
290 328 margin: 0px;
291 329 overflow: auto;
292 330 font-family: monospace;
293 331 }
294 332
295 333 option.context {
296 334 background-color: #DEF7FF;
297 335 }
298 336 option.introspection {
299 337 background-color: #EBF4EB;
300 338 }
301 339
302 340 /*fixed part of the completion*/
303 341 .completions p b {
304 342 font-weight:bold;
305 343 }
306 344
307 345 .completions p {
308 346 background: #DDF;
309 347 /*outline: none;
310 348 padding: 0px;*/
311 349 border-bottom: black solid 1px;
312 350 padding: 1px;
313 351 font-family: monospace;
314 352 }
315 353
316 354 pre.dialog {
317 355 background-color: #f7f7f7;
318 356 border: 1px solid #ddd;
319 357 border-radius: 3px;
320 358 padding: 0.4em;
321 359 padding-left: 2em;
322 360 }
323 361
324 362 p.dialog {
325 363 padding : 0.2em;
326 364 }
327 365
328 366 .shortcut_key {
329 367 display: inline-block;
330 368 width: 15ex;
331 369 text-align: right;
332 370 font-family: monospace;
333 371 }
334 372
335 373 .shortcut_descr {
336 374 }
337 375
338 376 /* Word-wrap output correctly. This is the CSS3 spelling, though Firefox seems
339 377 to not honor it correctly. Webkit browsers (Chrome, rekonq, Safari) do.
340 378 */
341 379 pre, code, kbd, samp { white-space: pre-wrap; }
342 380
343 381 #fonttest {
344 382 font-family: monospace;
345 383 }
@@ -1,314 +1,319 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 "use strict";
14 14
15 15 var utils = IPython.utils;
16 16 var key = IPython.utils.keycodes;
17 17
18 18 var CodeCell = function (kernel) {
19 19 // The kernel doesn't have to be set at creation time, in that case
20 20 // it will be null and set_kernel has to be called later.
21 21 this.kernel = kernel || null;
22 22 this.code_mirror = null;
23 23 this.input_prompt_number = null;
24 24 this.tooltip_on_tab = true;
25 25 this.collapsed = false;
26 26 IPython.Cell.apply(this, arguments);
27 27 };
28 28
29 29
30 30 CodeCell.prototype = new IPython.Cell();
31 31
32 32
33 33 CodeCell.prototype.create_element = function () {
34 34 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
35 35 cell.attr('tabindex','2');
36 36 var input = $('<div></div>').addClass('input hbox');
37 37 input.append($('<div/>').addClass('prompt input_prompt'));
38 38 var input_area = $('<div/>').addClass('input_area box-flex1');
39 39 this.code_mirror = CodeMirror(input_area.get(0), {
40 40 indentUnit : 4,
41 41 mode: 'python',
42 42 theme: 'ipython',
43 43 readOnly: this.read_only,
44 44 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
45 45 });
46 46 input.append(input_area);
47 47 var output = $('<div></div>');
48 48 cell.append(input).append(output);
49 49 this.element = cell;
50 50 this.output_area = new IPython.OutputArea(output, true);
51 51
52 52 // construct a completer only if class exist
53 53 // otherwise no print view
54 54 if (IPython.Completer !== undefined)
55 55 {
56 56 this.completer = new IPython.Completer(this);
57 57 }
58 58 };
59 59
60 60 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
61 61 // This method gets called in CodeMirror's onKeyDown/onKeyPress
62 62 // handlers and is used to provide custom key handling. Its return
63 63 // value is used to determine if CodeMirror should ignore the event:
64 64 // true = ignore, false = don't ignore.
65 65
66 66 if (this.read_only){
67 67 return false;
68 68 }
69 69
70 70 var that = this;
71 71 // whatever key is pressed, first, cancel the tooltip request before
72 72 // they are sent, and remove tooltip if any, except for tab again
73 73 if (event.type === 'keydown' && event.which != key.TAB ) {
74 74 IPython.tooltip.remove_and_cancel_tooltip();
75 75 };
76 76
77 77 var cur = editor.getCursor();
78 78
79 79 if (event.keyCode === key.ENTER && (event.shiftKey || event.ctrlKey)) {
80 80 // Always ignore shift-enter in CodeMirror as we handle it.
81 81 return true;
82 82 } else if (event.which === 40 && event.type === 'keypress' && IPython.tooltip.time_before_tooltip >= 0) {
83 83 // triger on keypress (!) otherwise inconsistent event.which depending on plateform
84 84 // browser and keyboard layout !
85 85 // Pressing '(' , request tooltip, don't forget to reappend it
86 86 IPython.tooltip.pending(that);
87 87 } else if (event.which === key.UPARROW && event.type === 'keydown') {
88 88 // If we are not at the top, let CM handle the up arrow and
89 89 // prevent the global keydown handler from handling it.
90 90 if (!that.at_top()) {
91 91 event.stop();
92 92 return false;
93 93 } else {
94 94 return true;
95 95 };
96 96 } else if (event.which === key.ESC) {
97 97 IPython.tooltip.remove_and_cancel_tooltip(true);
98 98 return true;
99 99 } else if (event.which === key.DOWNARROW && event.type === 'keydown') {
100 100 // If we are not at the bottom, let CM handle the down arrow and
101 101 // prevent the global keydown handler from handling it.
102 102 if (!that.at_bottom()) {
103 103 event.stop();
104 104 return false;
105 105 } else {
106 106 return true;
107 107 };
108 108 } else if (event.keyCode === key.TAB && event.type == 'keydown') {
109 109 // Tab completion.
110 110 //Do not trim here because of tooltip
111 111 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
112 112 if (pre_cursor.trim() === "") {
113 113 // Don't autocomplete if the part of the line before the cursor
114 114 // is empty. In this case, let CodeMirror handle indentation.
115 115 return false;
116 116 } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && that.tooltip_on_tab ) {
117 117 IPython.tooltip.request(that);
118 118 // Prevent the event from bubbling up.
119 119 event.stop();
120 120 // Prevent CodeMirror from handling the tab.
121 121 return true;
122 122 } else {
123 123 event.stop();
124 124 this.completer.startCompletion();
125 125 return true;
126 126 };
127 127 } else if (event.keyCode === key.BACKSPACE && event.type == 'keydown') {
128 128 // If backspace and the line ends with 4 spaces, remove them.
129 129 var line = editor.getLine(cur.line);
130 130 var ending = line.slice(-4);
131 131 if (ending === ' ') {
132 132 editor.replaceRange('',
133 133 {line: cur.line, ch: cur.ch-4},
134 134 {line: cur.line, ch: cur.ch}
135 135 );
136 136 event.stop();
137 137 return true;
138 138 } else {
139 139 return false;
140 140 };
141 141 } else {
142 142 // keypress/keyup also trigger on TAB press, and we don't want to
143 143 // use those to disable tab completion.
144 144 return false;
145 145 };
146 146 return false;
147 147 };
148 148
149 149
150 150 // Kernel related calls.
151 151
152 152 CodeCell.prototype.set_kernel = function (kernel) {
153 153 this.kernel = kernel;
154 154 }
155 155
156 156
157 157 CodeCell.prototype.execute = function () {
158 158 this.output_area.clear_output(true, true, true);
159 159 this.set_input_prompt('*');
160 160 this.element.addClass("running");
161 161 var callbacks = {
162 162 'execute_reply': $.proxy(this._handle_execute_reply, this),
163 163 'output': $.proxy(this.output_area.handle_output, this.output_area),
164 164 'clear_output': $.proxy(this.output_area.handle_clear_output, this.output_area),
165 165 'set_next_input': $.proxy(this._handle_set_next_input, this)
166 166 };
167 167 var msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false});
168 168 };
169 169
170 170
171 171 CodeCell.prototype._handle_execute_reply = function (content) {
172 172 this.set_input_prompt(content.execution_count);
173 173 this.element.removeClass("running");
174 174 $([IPython.events]).trigger('set_dirty.Notebook', {'value': true});
175 175 }
176 176
177 177 CodeCell.prototype._handle_set_next_input = function (text) {
178 178 var data = {'cell': this, 'text': text}
179 179 $([IPython.events]).trigger('set_next_input.Notebook', data);
180 180 }
181 181
182 182 // Basic cell manipulation.
183 183
184 184 CodeCell.prototype.select = function () {
185 185 IPython.Cell.prototype.select.apply(this);
186 186 this.code_mirror.refresh();
187 187 this.code_mirror.focus();
188 188 // We used to need an additional refresh() after the focus, but
189 189 // it appears that this has been fixed in CM. This bug would show
190 190 // up on FF when a newly loaded markdown cell was edited.
191 191 };
192 192
193 193
194 194 CodeCell.prototype.select_all = function () {
195 195 var start = {line: 0, ch: 0};
196 196 var nlines = this.code_mirror.lineCount();
197 197 var last_line = this.code_mirror.getLine(nlines-1);
198 198 var end = {line: nlines-1, ch: last_line.length};
199 199 this.code_mirror.setSelection(start, end);
200 200 };
201 201
202 202
203 203 CodeCell.prototype.collapse = function () {
204 204 this.collapsed = true;
205 205 this.output_area.collapse();
206 206 };
207 207
208 208
209 209 CodeCell.prototype.expand = function () {
210 210 this.collapsed = false;
211 211 this.output_area.expand();
212 212 };
213 213
214 214
215 215 CodeCell.prototype.toggle_output = function () {
216 216 this.collapsed = Boolean(1 - this.collapsed);
217 217 this.output_area.toggle_output();
218 218 };
219 219
220 220
221 CodeCell.prototype.toggle_output_scroll = function () {
222 this.output_area.toggle_scroll();
223 };
224
225
221 226 CodeCell.prototype.set_input_prompt = function (number) {
222 227 this.input_prompt_number = number;
223 228 var ns = number || "&nbsp;";
224 229 this.element.find('div.input_prompt').html('In&nbsp;[' + ns + ']:');
225 230 };
226 231
227 232
228 233 CodeCell.prototype.clear_input = function () {
229 234 this.code_mirror.setValue('');
230 235 };
231 236
232 237
233 238 CodeCell.prototype.get_text = function () {
234 239 return this.code_mirror.getValue();
235 240 };
236 241
237 242
238 243 CodeCell.prototype.set_text = function (code) {
239 244 return this.code_mirror.setValue(code);
240 245 };
241 246
242 247
243 248 CodeCell.prototype.at_top = function () {
244 249 var cursor = this.code_mirror.getCursor();
245 250 if (cursor.line === 0) {
246 251 return true;
247 252 } else {
248 253 return false;
249 254 }
250 255 };
251 256
252 257
253 258 CodeCell.prototype.at_bottom = function () {
254 259 var cursor = this.code_mirror.getCursor();
255 260 if (cursor.line === (this.code_mirror.lineCount()-1)) {
256 261 return true;
257 262 } else {
258 263 return false;
259 264 }
260 265 };
261 266
262 267
263 268 CodeCell.prototype.clear_output = function (stdout, stderr, other) {
264 269 this.output_area.clear_output(stdout, stderr, other);
265 270 };
266 271
267 272
268 273 // JSON serialization
269 274
270 275 CodeCell.prototype.fromJSON = function (data) {
271 276 IPython.Cell.prototype.fromJSON.apply(this, arguments);
272 277 if (data.cell_type === 'code') {
273 278 if (data.input !== undefined) {
274 279 this.set_text(data.input);
275 280 // make this value the starting point, so that we can only undo
276 281 // to this state, instead of a blank cell
277 282 this.code_mirror.clearHistory();
278 283 }
279 284 if (data.prompt_number !== undefined) {
280 285 this.set_input_prompt(data.prompt_number);
281 286 } else {
282 287 this.set_input_prompt();
283 288 };
284 289 this.output_area.fromJSON(data.outputs);
285 290 if (data.collapsed !== undefined) {
286 291 if (data.collapsed) {
287 292 this.collapse();
288 293 } else {
289 294 this.expand();
290 295 };
291 296 };
292 297 };
293 298 };
294 299
295 300
296 301 CodeCell.prototype.toJSON = function () {
297 302 var data = IPython.Cell.prototype.toJSON.apply(this);
298 303 data.input = this.get_text();
299 304 data.cell_type = 'code';
300 305 if (this.input_prompt_number) {
301 306 data.prompt_number = this.input_prompt_number;
302 307 };
303 308 var outputs = this.output_area.toJSON();
304 309 data.outputs = outputs;
305 310 data.language = 'python';
306 311 data.collapsed = this.collapsed;
307 312 return data;
308 313 };
309 314
310 315
311 316 IPython.CodeCell = CodeCell;
312 317
313 318 return IPython;
314 319 }(IPython));
@@ -1,182 +1,191 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 // MenuBar
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13
14 14 var MenuBar = function (selector) {
15 15 this.selector = selector;
16 16 if (this.selector !== undefined) {
17 17 this.element = $(selector);
18 18 this.style();
19 19 this.bind_events();
20 20 }
21 21 };
22 22
23 23
24 24 MenuBar.prototype.style = function () {
25 25 this.element.addClass('border-box-sizing');
26 26 $('ul#menus').menubar({
27 27 select : function (event, ui) {
28 28 // The selected cell loses focus when the menu is entered, so we
29 29 // re-select it upon selection.
30 30 var i = IPython.notebook.get_selected_index();
31 31 IPython.notebook.select(i);
32 32 }
33 33 });
34 34 };
35 35
36 36
37 37 MenuBar.prototype.bind_events = function () {
38 38 // File
39 39 this.element.find('#new_notebook').click(function () {
40 40 window.open($('body').data('baseProjectUrl')+'new');
41 41 });
42 42 this.element.find('#open_notebook').click(function () {
43 43 window.open($('body').data('baseProjectUrl'));
44 44 });
45 45 this.element.find('#rename_notebook').click(function () {
46 46 IPython.save_widget.rename_notebook();
47 47 });
48 48 this.element.find('#copy_notebook').click(function () {
49 49 var notebook_id = IPython.notebook.get_notebook_id();
50 50 var url = $('body').data('baseProjectUrl') + notebook_id + '/copy';
51 51 window.open(url,'_newtab');
52 52 });
53 53 this.element.find('#save_notebook').click(function () {
54 54 IPython.notebook.save_notebook();
55 55 });
56 56 this.element.find('#download_ipynb').click(function () {
57 57 var notebook_id = IPython.notebook.get_notebook_id();
58 58 var url = $('body').data('baseProjectUrl') + 'notebooks/' +
59 59 notebook_id + '?format=json';
60 60 window.open(url,'_newtab');
61 61 });
62 62 this.element.find('#download_py').click(function () {
63 63 var notebook_id = IPython.notebook.get_notebook_id();
64 64 var url = $('body').data('baseProjectUrl') + 'notebooks/' +
65 65 notebook_id + '?format=py';
66 66 window.open(url,'_newtab');
67 67 });
68 68 this.element.find('button#print_notebook').click(function () {
69 69 IPython.print_widget.print_notebook();
70 70 });
71 71 this.element.find('#kill_and_exit').click(function () {
72 72 IPython.notebook.kernel.kill();
73 73 setTimeout(function(){window.close();}, 200);
74 74 });
75 75 // Edit
76 76 this.element.find('#cut_cell').click(function () {
77 77 IPython.notebook.cut_cell();
78 78 });
79 79 this.element.find('#copy_cell').click(function () {
80 80 IPython.notebook.copy_cell();
81 81 });
82 82 this.element.find('#delete_cell').click(function () {
83 83 IPython.notebook.delete_cell();
84 84 });
85 85 this.element.find('#split_cell').click(function () {
86 86 IPython.notebook.split_cell();
87 87 });
88 88 this.element.find('#merge_cell_above').click(function () {
89 89 IPython.notebook.merge_cell_above();
90 90 });
91 91 this.element.find('#merge_cell_below').click(function () {
92 92 IPython.notebook.merge_cell_below();
93 93 });
94 94 this.element.find('#move_cell_up').click(function () {
95 95 IPython.notebook.move_cell_up();
96 96 });
97 97 this.element.find('#move_cell_down').click(function () {
98 98 IPython.notebook.move_cell_down();
99 99 });
100 100 this.element.find('#select_previous').click(function () {
101 101 IPython.notebook.select_prev();
102 102 });
103 103 this.element.find('#select_next').click(function () {
104 104 IPython.notebook.select_next();
105 105 });
106 106 // View
107 107 this.element.find('#toggle_header').click(function () {
108 108 $('div#header').toggle();
109 109 IPython.layout_manager.do_resize();
110 110 });
111 111 this.element.find('#toggle_toolbar').click(function () {
112 112 IPython.toolbar.toggle();
113 113 });
114 114 // Insert
115 115 this.element.find('#insert_cell_above').click(function () {
116 116 IPython.notebook.insert_cell_above('code');
117 117 });
118 118 this.element.find('#insert_cell_below').click(function () {
119 119 IPython.notebook.insert_cell_below('code');
120 120 });
121 121 // Cell
122 122 this.element.find('#run_cell').click(function () {
123 123 IPython.notebook.execute_selected_cell();
124 124 });
125 125 this.element.find('#run_cell_in_place').click(function () {
126 126 IPython.notebook.execute_selected_cell({terminal:true});
127 127 });
128 128 this.element.find('#run_all_cells').click(function () {
129 129 IPython.notebook.execute_all_cells();
130 130 });
131 131 this.element.find('#to_code').click(function () {
132 132 IPython.notebook.to_code();
133 133 });
134 134 this.element.find('#to_markdown').click(function () {
135 135 IPython.notebook.to_markdown();
136 136 });
137 137 this.element.find('#to_raw').click(function () {
138 138 IPython.notebook.to_raw();
139 139 });
140 140 this.element.find('#to_heading1').click(function () {
141 141 IPython.notebook.to_heading(undefined, 1);
142 142 });
143 143 this.element.find('#to_heading2').click(function () {
144 144 IPython.notebook.to_heading(undefined, 2);
145 145 });
146 146 this.element.find('#to_heading3').click(function () {
147 147 IPython.notebook.to_heading(undefined, 3);
148 148 });
149 149 this.element.find('#to_heading4').click(function () {
150 150 IPython.notebook.to_heading(undefined, 4);
151 151 });
152 152 this.element.find('#to_heading5').click(function () {
153 153 IPython.notebook.to_heading(undefined, 5);
154 154 });
155 155 this.element.find('#to_heading6').click(function () {
156 156 IPython.notebook.to_heading(undefined, 6);
157 157 });
158 158 this.element.find('#toggle_output').click(function () {
159 159 IPython.notebook.toggle_output();
160 160 });
161 this.element.find('#collapse_all_output').click(function () {
162 IPython.notebook.collapse_all_output();
163 });
164 this.element.find('#scroll_all_output').click(function () {
165 IPython.notebook.scroll_all_output();
166 });
167 this.element.find('#expand_all_output').click(function () {
168 IPython.notebook.expand_all_output();
169 });
161 170 this.element.find('#clear_all_output').click(function () {
162 171 IPython.notebook.clear_all_output();
163 172 });
164 173 // Kernel
165 174 this.element.find('#int_kernel').click(function () {
166 175 IPython.notebook.kernel.interrupt();
167 176 });
168 177 this.element.find('#restart_kernel').click(function () {
169 178 IPython.notebook.restart_kernel();
170 179 });
171 180 // Help
172 181 this.element.find('#keyboard_shortcuts').click(function () {
173 182 IPython.quick_help.show_keyboard_shortcuts();
174 183 });
175 184 };
176 185
177 186
178 187 IPython.MenuBar = MenuBar;
179 188
180 189 return IPython;
181 190
182 191 }(IPython));
@@ -1,1233 +1,1284 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 var key = IPython.utils.keycodes;
16 16
17 17 var Notebook = function (selector) {
18 18 this.read_only = IPython.read_only;
19 19 this.element = $(selector);
20 20 this.element.scroll();
21 21 this.element.data("notebook", this);
22 22 this.next_prompt_number = 1;
23 23 this.kernel = null;
24 24 this.clipboard = null;
25 25 this.paste_enabled = false;
26 26 this.dirty = false;
27 27 this.metadata = {};
28 28 // single worksheet for now
29 29 this.worksheet_metadata = {};
30 30 this.control_key_active = false;
31 31 this.notebook_id = null;
32 32 this.notebook_name = null;
33 33 this.notebook_name_blacklist_re = /[\/\\:]/;
34 34 this.nbformat = 3 // Increment this when changing the nbformat
35 35 this.nbformat_minor = 0 // Increment this when changing the nbformat
36 36 this.style();
37 37 this.create_elements();
38 38 this.bind_events();
39 39 };
40 40
41 41
42 42 Notebook.prototype.style = function () {
43 43 $('div#notebook').addClass('border-box-sizing');
44 44 };
45 45
46 46
47 47 Notebook.prototype.create_elements = function () {
48 48 // We add this end_space div to the end of the notebook div to:
49 49 // i) provide a margin between the last cell and the end of the notebook
50 50 // ii) to prevent the div from scrolling up when the last cell is being
51 51 // edited, but is too low on the page, which browsers will do automatically.
52 52 var that = this;
53 53 var end_space = $('<div/>').addClass('end_space').height("30%");
54 54 end_space.dblclick(function (e) {
55 55 if (that.read_only) return;
56 56 var ncells = that.ncells();
57 57 that.insert_cell_below('code',ncells-1);
58 58 });
59 59 this.element.append(end_space);
60 60 $('div#notebook').addClass('border-box-sizing');
61 61 };
62 62
63 63
64 64 Notebook.prototype.bind_events = function () {
65 65 var that = this;
66 66
67 67 $([IPython.events]).on('set_next_input.Notebook', function (event, data) {
68 68 var index = that.find_cell_index(data.cell);
69 69 var new_cell = that.insert_cell_below('code',index);
70 70 new_cell.set_text(data.text);
71 71 that.dirty = true;
72 72 });
73 73
74 74 $([IPython.events]).on('set_dirty.Notebook', function (event, data) {
75 75 that.dirty = data.value;
76 76 });
77 77
78 78 $([IPython.events]).on('select.Cell', function (event, data) {
79 79 var index = that.find_cell_index(data.cell);
80 80 that.select(index);
81 81 });
82 82
83 83
84 84 $(document).keydown(function (event) {
85 85 // console.log(event);
86 86 if (that.read_only) return true;
87 87
88 88 // Save (CTRL+S) or (AppleKey+S)
89 89 //metaKey = applekey on mac
90 90 if ((event.ctrlKey || event.metaKey) && event.keyCode==83) {
91 91 that.save_notebook();
92 92 event.preventDefault();
93 93 return false;
94 94 } else if (event.which === key.ESC) {
95 95 // Intercept escape at highest level to avoid closing
96 96 // websocket connection with firefox
97 97 event.preventDefault();
98 98 }
99 99 if (event.which === key.UPARROW && !event.shiftKey) {
100 100 var cell = that.get_selected_cell();
101 101 if (cell.at_top()) {
102 102 event.preventDefault();
103 103 that.select_prev();
104 104 };
105 105 } else if (event.which === key.DOWNARROW && !event.shiftKey) {
106 106 var cell = that.get_selected_cell();
107 107 if (cell.at_bottom()) {
108 108 event.preventDefault();
109 109 that.select_next();
110 110 };
111 111 } else if (event.which === key.ENTER && event.shiftKey) {
112 112 that.execute_selected_cell();
113 113 return false;
114 114 } else if (event.which === key.ENTER && event.ctrlKey) {
115 115 that.execute_selected_cell({terminal:true});
116 116 return false;
117 117 } else if (event.which === 77 && event.ctrlKey && that.control_key_active == false) {
118 118 that.control_key_active = true;
119 119 return false;
120 120 } else if (event.which === 88 && that.control_key_active) {
121 121 // Cut selected cell = x
122 122 that.cut_cell();
123 123 that.control_key_active = false;
124 124 return false;
125 125 } else if (event.which === 67 && that.control_key_active) {
126 126 // Copy selected cell = c
127 127 that.copy_cell();
128 128 that.control_key_active = false;
129 129 return false;
130 130 } else if (event.which === 86 && that.control_key_active) {
131 131 // Paste selected cell = v
132 132 that.paste_cell();
133 133 that.control_key_active = false;
134 134 return false;
135 135 } else if (event.which === 68 && that.control_key_active) {
136 136 // Delete selected cell = d
137 137 that.delete_cell();
138 138 that.control_key_active = false;
139 139 return false;
140 140 } else if (event.which === 65 && that.control_key_active) {
141 141 // Insert code cell above selected = a
142 142 that.insert_cell_above('code');
143 143 that.control_key_active = false;
144 144 return false;
145 145 } else if (event.which === 66 && that.control_key_active) {
146 146 // Insert code cell below selected = b
147 147 that.insert_cell_below('code');
148 148 that.control_key_active = false;
149 149 return false;
150 150 } else if (event.which === 89 && that.control_key_active) {
151 151 // To code = y
152 152 that.to_code();
153 153 that.control_key_active = false;
154 154 return false;
155 155 } else if (event.which === 77 && that.control_key_active) {
156 156 // To markdown = m
157 157 that.to_markdown();
158 158 that.control_key_active = false;
159 159 return false;
160 160 } else if (event.which === 84 && that.control_key_active) {
161 161 // To Raw = t
162 162 that.to_raw();
163 163 that.control_key_active = false;
164 164 return false;
165 165 } else if (event.which === 49 && that.control_key_active) {
166 166 // To Heading 1 = 1
167 167 that.to_heading(undefined, 1);
168 168 that.control_key_active = false;
169 169 return false;
170 170 } else if (event.which === 50 && that.control_key_active) {
171 171 // To Heading 2 = 2
172 172 that.to_heading(undefined, 2);
173 173 that.control_key_active = false;
174 174 return false;
175 175 } else if (event.which === 51 && that.control_key_active) {
176 176 // To Heading 3 = 3
177 177 that.to_heading(undefined, 3);
178 178 that.control_key_active = false;
179 179 return false;
180 180 } else if (event.which === 52 && that.control_key_active) {
181 181 // To Heading 4 = 4
182 182 that.to_heading(undefined, 4);
183 183 that.control_key_active = false;
184 184 return false;
185 185 } else if (event.which === 53 && that.control_key_active) {
186 186 // To Heading 5 = 5
187 187 that.to_heading(undefined, 5);
188 188 that.control_key_active = false;
189 189 return false;
190 190 } else if (event.which === 54 && that.control_key_active) {
191 191 // To Heading 6 = 6
192 192 that.to_heading(undefined, 6);
193 193 that.control_key_active = false;
194 194 return false;
195 195 } else if (event.which === 79 && that.control_key_active) {
196 196 // Toggle output = o
197 that.toggle_output();
197 if (event.shiftKey){
198 that.toggle_output_scroll();
199 } else {
200 that.toggle_output();
201 }
198 202 that.control_key_active = false;
199 203 return false;
200 204 } else if (event.which === 83 && that.control_key_active) {
201 205 // Save notebook = s
202 206 that.save_notebook();
203 207 that.control_key_active = false;
204 208 return false;
205 209 } else if (event.which === 74 && that.control_key_active) {
206 210 // Move cell down = j
207 211 that.move_cell_down();
208 212 that.control_key_active = false;
209 213 return false;
210 214 } else if (event.which === 75 && that.control_key_active) {
211 215 // Move cell up = k
212 216 that.move_cell_up();
213 217 that.control_key_active = false;
214 218 return false;
215 219 } else if (event.which === 80 && that.control_key_active) {
216 220 // Select previous = p
217 221 that.select_prev();
218 222 that.control_key_active = false;
219 223 return false;
220 224 } else if (event.which === 78 && that.control_key_active) {
221 225 // Select next = n
222 226 that.select_next();
223 227 that.control_key_active = false;
224 228 return false;
225 229 } else if (event.which === 76 && that.control_key_active) {
226 230 // Toggle line numbers = l
227 231 that.cell_toggle_line_numbers();
228 232 that.control_key_active = false;
229 233 return false;
230 234 } else if (event.which === 73 && that.control_key_active) {
231 235 // Interrupt kernel = i
232 236 that.kernel.interrupt();
233 237 that.control_key_active = false;
234 238 return false;
235 239 } else if (event.which === 190 && that.control_key_active) {
236 240 // Restart kernel = . # matches qt console
237 241 that.restart_kernel();
238 242 that.control_key_active = false;
239 243 return false;
240 244 } else if (event.which === 72 && that.control_key_active) {
241 245 // Show keyboard shortcuts = h
242 246 IPython.quick_help.show_keyboard_shortcuts();
243 247 that.control_key_active = false;
244 248 return false;
245 249 } else if (that.control_key_active) {
246 250 that.control_key_active = false;
247 251 return true;
248 252 };
249 253 return true;
250 254 });
251 255
252 256 var collapse_time = function(time){
253 257 var app_height = $('div#main_app').height(); // content height
254 258 var splitter_height = $('div#pager_splitter').outerHeight(true);
255 259 var new_height = app_height - splitter_height;
256 260 that.element.animate({height : new_height + 'px'}, time);
257 261 }
258 262
259 263 this.element.bind('collapse_pager', function (event,extrap) {
260 264 time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast';
261 265 collapse_time(time);
262 266 });
263 267
264 268 var expand_time = function(time) {
265 269 var app_height = $('div#main_app').height(); // content height
266 270 var splitter_height = $('div#pager_splitter').outerHeight(true);
267 271 var pager_height = $('div#pager').outerHeight(true);
268 272 var new_height = app_height - pager_height - splitter_height;
269 273 that.element.animate({height : new_height + 'px'}, time);
270 274 }
271 275
272 276 this.element.bind('expand_pager', function (event, extrap) {
273 277 time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast';
274 278 expand_time(time);
275 279 });
276 280
277 281 $(window).bind('beforeunload', function () {
278 282 // TODO: Make killing the kernel configurable.
279 283 var kill_kernel = false;
280 284 if (kill_kernel) {
281 285 that.kernel.kill();
282 286 }
283 287 if (that.dirty && ! that.read_only) {
284 288 return "You have unsaved changes that will be lost if you leave this page.";
285 289 };
286 290 // Null is the *only* return value that will make the browser not
287 291 // pop up the "don't leave" dialog.
288 292 return null;
289 293 });
290 294 };
291 295
292 296
293 297 Notebook.prototype.scroll_to_bottom = function () {
294 298 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
295 299 };
296 300
297 301
298 302 Notebook.prototype.scroll_to_top = function () {
299 303 this.element.animate({scrollTop:0}, 0);
300 304 };
301 305
302 306
303 307 // Cell indexing, retrieval, etc.
304 308
305 309 Notebook.prototype.get_cell_elements = function () {
306 310 return this.element.children("div.cell");
307 311 };
308 312
309 313
310 314 Notebook.prototype.get_cell_element = function (index) {
311 315 var result = null;
312 316 var e = this.get_cell_elements().eq(index);
313 317 if (e.length !== 0) {
314 318 result = e;
315 319 }
316 320 return result;
317 321 };
318 322
319 323
320 324 Notebook.prototype.ncells = function (cell) {
321 325 return this.get_cell_elements().length;
322 326 };
323 327
324 328
325 329 // TODO: we are often calling cells as cells()[i], which we should optimize
326 330 // to cells(i) or a new method.
327 331 Notebook.prototype.get_cells = function () {
328 332 return this.get_cell_elements().toArray().map(function (e) {
329 333 return $(e).data("cell");
330 334 });
331 335 };
332 336
333 337
334 338 Notebook.prototype.get_cell = function (index) {
335 339 var result = null;
336 340 var ce = this.get_cell_element(index);
337 341 if (ce !== null) {
338 342 result = ce.data('cell');
339 343 }
340 344 return result;
341 345 }
342 346
343 347
344 348 Notebook.prototype.get_next_cell = function (cell) {
345 349 var result = null;
346 350 var index = this.find_cell_index(cell);
347 351 if (index !== null && index < this.ncells()) {
348 352 result = this.get_cell(index+1);
349 353 }
350 354 return result;
351 355 }
352 356
353 357
354 358 Notebook.prototype.get_prev_cell = function (cell) {
355 359 var result = null;
356 360 var index = this.find_cell_index(cell);
357 361 if (index !== null && index > 1) {
358 362 result = this.get_cell(index-1);
359 363 }
360 364 return result;
361 365 }
362 366
363 367 Notebook.prototype.find_cell_index = function (cell) {
364 368 var result = null;
365 369 this.get_cell_elements().filter(function (index) {
366 370 if ($(this).data("cell") === cell) {
367 371 result = index;
368 372 };
369 373 });
370 374 return result;
371 375 };
372 376
373 377
374 378 Notebook.prototype.index_or_selected = function (index) {
375 379 var i;
376 380 if (index === undefined || index === null) {
377 381 i = this.get_selected_index();
378 382 if (i === null) {
379 383 i = 0;
380 384 }
381 385 } else {
382 386 i = index;
383 387 }
384 388 return i;
385 389 };
386 390
387 391
388 392 Notebook.prototype.get_selected_cell = function () {
389 393 var index = this.get_selected_index();
390 394 return this.get_cell(index);
391 395 };
392 396
393 397
394 398 Notebook.prototype.is_valid_cell_index = function (index) {
395 399 if (index !== null && index >= 0 && index < this.ncells()) {
396 400 return true;
397 401 } else {
398 402 return false;
399 403 };
400 404 }
401 405
402 406 Notebook.prototype.get_selected_index = function () {
403 407 var result = null;
404 408 this.get_cell_elements().filter(function (index) {
405 409 if ($(this).data("cell").selected === true) {
406 410 result = index;
407 411 };
408 412 });
409 413 return result;
410 414 };
411 415
412 416
413 417 // Cell selection.
414 418
415 419 Notebook.prototype.select = function (index) {
416 420 if (index !== undefined && index >= 0 && index < this.ncells()) {
417 421 sindex = this.get_selected_index()
418 422 if (sindex !== null && index !== sindex) {
419 423 this.get_cell(sindex).unselect();
420 424 };
421 425 var cell = this.get_cell(index)
422 426 cell.select();
423 427 if (cell.cell_type === 'heading') {
424 428 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
425 429 {'cell_type':cell.cell_type,level:cell.level}
426 430 );
427 431 } else {
428 432 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
429 433 {'cell_type':cell.cell_type}
430 434 );
431 435 };
432 436 };
433 437 return this;
434 438 };
435 439
436 440
437 441 Notebook.prototype.select_next = function () {
438 442 var index = this.get_selected_index();
439 443 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
440 444 this.select(index+1);
441 445 };
442 446 return this;
443 447 };
444 448
445 449
446 450 Notebook.prototype.select_prev = function () {
447 451 var index = this.get_selected_index();
448 452 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
449 453 this.select(index-1);
450 454 };
451 455 return this;
452 456 };
453 457
454 458
455 459 // Cell movement
456 460
457 461 Notebook.prototype.move_cell_up = function (index) {
458 462 var i = this.index_or_selected();
459 463 if (i !== null && i < this.ncells() && i > 0) {
460 464 var pivot = this.get_cell_element(i-1);
461 465 var tomove = this.get_cell_element(i);
462 466 if (pivot !== null && tomove !== null) {
463 467 tomove.detach();
464 468 pivot.before(tomove);
465 469 this.select(i-1);
466 470 };
467 471 };
468 472 this.dirty = true;
469 473 return this;
470 474 };
471 475
472 476
473 477 Notebook.prototype.move_cell_down = function (index) {
474 478 var i = this.index_or_selected();
475 479 if (i !== null && i < (this.ncells()-1) && i >= 0) {
476 480 var pivot = this.get_cell_element(i+1);
477 481 var tomove = this.get_cell_element(i);
478 482 if (pivot !== null && tomove !== null) {
479 483 tomove.detach();
480 484 pivot.after(tomove);
481 485 this.select(i+1);
482 486 };
483 487 };
484 488 this.dirty = true;
485 489 return this;
486 490 };
487 491
488 492
489 493 Notebook.prototype.sort_cells = function () {
490 494 // This is not working right now. Calling this will actually crash
491 495 // the browser. I think there is an infinite loop in here...
492 496 var ncells = this.ncells();
493 497 var sindex = this.get_selected_index();
494 498 var swapped;
495 499 do {
496 500 swapped = false;
497 501 for (var i=1; i<ncells; i++) {
498 502 current = this.get_cell(i);
499 503 previous = this.get_cell(i-1);
500 504 if (previous.input_prompt_number > current.input_prompt_number) {
501 505 this.move_cell_up(i);
502 506 swapped = true;
503 507 };
504 508 };
505 509 } while (swapped);
506 510 this.select(sindex);
507 511 return this;
508 512 };
509 513
510 514 // Insertion, deletion.
511 515
512 516 Notebook.prototype.delete_cell = function (index) {
513 517 var i = this.index_or_selected(index);
514 518 if (this.is_valid_cell_index(i)) {
515 519 var ce = this.get_cell_element(i);
516 520 ce.remove();
517 521 if (i === (this.ncells())) {
518 522 this.select(i-1);
519 523 } else {
520 524 this.select(i);
521 525 };
522 526 this.dirty = true;
523 527 };
524 528 return this;
525 529 };
526 530
527 531
528 532 Notebook.prototype.insert_cell_below = function (type, index) {
529 533 // type = ('code','html','markdown')
530 534 // index = cell index or undefined to insert below selected
531 535 index = this.index_or_selected(index);
532 536 var cell = null;
533 537 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
534 538 if (type === 'code') {
535 539 cell = new IPython.CodeCell(this.kernel);
536 540 cell.set_input_prompt();
537 541 } else if (type === 'markdown') {
538 542 cell = new IPython.MarkdownCell();
539 543 } else if (type === 'html') {
540 544 cell = new IPython.HTMLCell();
541 545 } else if (type === 'raw') {
542 546 cell = new IPython.RawCell();
543 547 } else if (type === 'heading') {
544 548 cell = new IPython.HeadingCell();
545 549 };
546 550 if (cell !== null) {
547 551 if (this.ncells() === 0) {
548 552 this.element.find('div.end_space').before(cell.element);
549 553 } else if (this.is_valid_cell_index(index)) {
550 554 this.get_cell_element(index).after(cell.element);
551 555 };
552 556 cell.render();
553 557 this.select(this.find_cell_index(cell));
554 558 this.dirty = true;
555 559 return cell;
556 560 };
557 561 };
558 562 return cell;
559 563 };
560 564
561 565
562 566 Notebook.prototype.insert_cell_above = function (type, index) {
563 567 // type = ('code','html','markdown')
564 568 // index = cell index or undefined to insert above selected
565 569 index = this.index_or_selected(index);
566 570 var cell = null;
567 571 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
568 572 if (type === 'code') {
569 573 cell = new IPython.CodeCell(this.kernel);
570 574 cell.set_input_prompt();
571 575 } else if (type === 'markdown') {
572 576 cell = new IPython.MarkdownCell();
573 577 } else if (type === 'html') {
574 578 cell = new IPython.HTMLCell();
575 579 } else if (type === 'raw') {
576 580 cell = new IPython.RawCell();
577 581 } else if (type === 'heading') {
578 582 cell = new IPython.HeadingCell();
579 583 };
580 584 if (cell !== null) {
581 585 if (this.ncells() === 0) {
582 586 this.element.find('div.end_space').before(cell.element);
583 587 } else if (this.is_valid_cell_index(index)) {
584 588 this.get_cell_element(index).before(cell.element);
585 589 };
586 590 cell.render();
587 591 this.select(this.find_cell_index(cell));
588 592 this.dirty = true;
589 593 return cell;
590 594 };
591 595 };
592 596 return cell;
593 597 };
594 598
595 599
596 600 Notebook.prototype.to_code = function (index) {
597 601 var i = this.index_or_selected(index);
598 602 if (this.is_valid_cell_index(i)) {
599 603 var source_element = this.get_cell_element(i);
600 604 var source_cell = source_element.data("cell");
601 605 if (!(source_cell instanceof IPython.CodeCell)) {
602 606 target_cell = this.insert_cell_below('code',i);
603 607 var text = source_cell.get_text();
604 608 if (text === source_cell.placeholder) {
605 609 text = '';
606 610 }
607 611 target_cell.set_text(text);
608 612 // make this value the starting point, so that we can only undo
609 613 // to this state, instead of a blank cell
610 614 target_cell.code_mirror.clearHistory();
611 615 source_element.remove();
612 616 this.dirty = true;
613 617 };
614 618 };
615 619 };
616 620
617 621
618 622 Notebook.prototype.to_markdown = function (index) {
619 623 var i = this.index_or_selected(index);
620 624 if (this.is_valid_cell_index(i)) {
621 625 var source_element = this.get_cell_element(i);
622 626 var source_cell = source_element.data("cell");
623 627 if (!(source_cell instanceof IPython.MarkdownCell)) {
624 628 target_cell = this.insert_cell_below('markdown',i);
625 629 var text = source_cell.get_text();
626 630 if (text === source_cell.placeholder) {
627 631 text = '';
628 632 };
629 633 // The edit must come before the set_text.
630 634 target_cell.edit();
631 635 target_cell.set_text(text);
632 636 // make this value the starting point, so that we can only undo
633 637 // to this state, instead of a blank cell
634 638 target_cell.code_mirror.clearHistory();
635 639 source_element.remove();
636 640 this.dirty = true;
637 641 };
638 642 };
639 643 };
640 644
641 645
642 646 Notebook.prototype.to_html = function (index) {
643 647 var i = this.index_or_selected(index);
644 648 if (this.is_valid_cell_index(i)) {
645 649 var source_element = this.get_cell_element(i);
646 650 var source_cell = source_element.data("cell");
647 651 var target_cell = null;
648 652 if (!(source_cell instanceof IPython.HTMLCell)) {
649 653 target_cell = this.insert_cell_below('html',i);
650 654 var text = source_cell.get_text();
651 655 if (text === source_cell.placeholder) {
652 656 text = '';
653 657 };
654 658 // The edit must come before the set_text.
655 659 target_cell.edit();
656 660 target_cell.set_text(text);
657 661 // make this value the starting point, so that we can only undo
658 662 // to this state, instead of a blank cell
659 663 target_cell.code_mirror.clearHistory();
660 664 source_element.remove();
661 665 this.dirty = true;
662 666 };
663 667 };
664 668 };
665 669
666 670
667 671 Notebook.prototype.to_raw = function (index) {
668 672 var i = this.index_or_selected(index);
669 673 if (this.is_valid_cell_index(i)) {
670 674 var source_element = this.get_cell_element(i);
671 675 var source_cell = source_element.data("cell");
672 676 var target_cell = null;
673 677 if (!(source_cell instanceof IPython.RawCell)) {
674 678 target_cell = this.insert_cell_below('raw',i);
675 679 var text = source_cell.get_text();
676 680 if (text === source_cell.placeholder) {
677 681 text = '';
678 682 };
679 683 // The edit must come before the set_text.
680 684 target_cell.edit();
681 685 target_cell.set_text(text);
682 686 // make this value the starting point, so that we can only undo
683 687 // to this state, instead of a blank cell
684 688 target_cell.code_mirror.clearHistory();
685 689 source_element.remove();
686 690 this.dirty = true;
687 691 };
688 692 };
689 693 };
690 694
691 695
692 696 Notebook.prototype.to_heading = function (index, level) {
693 697 level = level || 1;
694 698 var i = this.index_or_selected(index);
695 699 if (this.is_valid_cell_index(i)) {
696 700 var source_element = this.get_cell_element(i);
697 701 var source_cell = source_element.data("cell");
698 702 var target_cell = null;
699 703 if (source_cell instanceof IPython.HeadingCell) {
700 704 source_cell.set_level(level);
701 705 } else {
702 706 target_cell = this.insert_cell_below('heading',i);
703 707 var text = source_cell.get_text();
704 708 if (text === source_cell.placeholder) {
705 709 text = '';
706 710 };
707 711 // The edit must come before the set_text.
708 712 target_cell.set_level(level);
709 713 target_cell.edit();
710 714 target_cell.set_text(text);
711 715 // make this value the starting point, so that we can only undo
712 716 // to this state, instead of a blank cell
713 717 target_cell.code_mirror.clearHistory();
714 718 source_element.remove();
715 719 this.dirty = true;
716 720 };
717 721 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
718 722 {'cell_type':'heading',level:level}
719 723 );
720 724 };
721 725 };
722 726
723 727
724 728 // Cut/Copy/Paste
725 729
726 730 Notebook.prototype.enable_paste = function () {
727 731 var that = this;
728 732 if (!this.paste_enabled) {
729 733 $('#paste_cell').removeClass('ui-state-disabled')
730 734 .on('click', function () {that.paste_cell();});
731 735 $('#paste_cell_above').removeClass('ui-state-disabled')
732 736 .on('click', function () {that.paste_cell_above();});
733 737 $('#paste_cell_below').removeClass('ui-state-disabled')
734 738 .on('click', function () {that.paste_cell_below();});
735 739 this.paste_enabled = true;
736 740 };
737 741 };
738 742
739 743
740 744 Notebook.prototype.disable_paste = function () {
741 745 if (this.paste_enabled) {
742 746 $('#paste_cell').addClass('ui-state-disabled').off('click');
743 747 $('#paste_cell_above').addClass('ui-state-disabled').off('click');
744 748 $('#paste_cell_below').addClass('ui-state-disabled').off('click');
745 749 this.paste_enabled = false;
746 750 };
747 751 };
748 752
749 753
750 754 Notebook.prototype.cut_cell = function () {
751 755 this.copy_cell();
752 756 this.delete_cell();
753 757 }
754 758
755 759 Notebook.prototype.copy_cell = function () {
756 760 var cell = this.get_selected_cell();
757 761 this.clipboard = cell.toJSON();
758 762 this.enable_paste();
759 763 };
760 764
761 765
762 766 Notebook.prototype.paste_cell = function () {
763 767 if (this.clipboard !== null && this.paste_enabled) {
764 768 var cell_data = this.clipboard;
765 769 var new_cell = this.insert_cell_above(cell_data.cell_type);
766 770 new_cell.fromJSON(cell_data);
767 771 old_cell = this.get_next_cell(new_cell);
768 772 this.delete_cell(this.find_cell_index(old_cell));
769 773 this.select(this.find_cell_index(new_cell));
770 774 };
771 775 };
772 776
773 777
774 778 Notebook.prototype.paste_cell_above = function () {
775 779 if (this.clipboard !== null && this.paste_enabled) {
776 780 var cell_data = this.clipboard;
777 781 var new_cell = this.insert_cell_above(cell_data.cell_type);
778 782 new_cell.fromJSON(cell_data);
779 783 };
780 784 };
781 785
782 786
783 787 Notebook.prototype.paste_cell_below = function () {
784 788 if (this.clipboard !== null && this.paste_enabled) {
785 789 var cell_data = this.clipboard;
786 790 var new_cell = this.insert_cell_below(cell_data.cell_type);
787 791 new_cell.fromJSON(cell_data);
788 792 };
789 793 };
790 794
791 795
792 796 // Split/merge
793 797
794 798 Notebook.prototype.split_cell = function () {
795 799 // Todo: implement spliting for other cell types.
796 800 var cell = this.get_selected_cell();
797 801 if (cell.is_splittable()) {
798 802 texta = cell.get_pre_cursor();
799 803 textb = cell.get_post_cursor();
800 804 if (cell instanceof IPython.CodeCell) {
801 805 cell.set_text(texta);
802 806 var new_cell = this.insert_cell_below('code');
803 807 new_cell.set_text(textb);
804 808 } else if (cell instanceof IPython.MarkdownCell) {
805 809 cell.set_text(texta);
806 810 cell.render();
807 811 var new_cell = this.insert_cell_below('markdown');
808 812 new_cell.edit(); // editor must be visible to call set_text
809 813 new_cell.set_text(textb);
810 814 new_cell.render();
811 815 } else if (cell instanceof IPython.HTMLCell) {
812 816 cell.set_text(texta);
813 817 cell.render();
814 818 var new_cell = this.insert_cell_below('html');
815 819 new_cell.edit(); // editor must be visible to call set_text
816 820 new_cell.set_text(textb);
817 821 new_cell.render();
818 822 };
819 823 };
820 824 };
821 825
822 826
823 827 Notebook.prototype.merge_cell_above = function () {
824 828 var index = this.get_selected_index();
825 829 var cell = this.get_cell(index);
826 830 if (index > 0) {
827 831 upper_cell = this.get_cell(index-1);
828 832 upper_text = upper_cell.get_text();
829 833 text = cell.get_text();
830 834 if (cell instanceof IPython.CodeCell) {
831 835 cell.set_text(upper_text+'\n'+text);
832 836 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
833 837 cell.edit();
834 838 cell.set_text(upper_text+'\n'+text);
835 839 cell.render();
836 840 };
837 841 this.delete_cell(index-1);
838 842 this.select(this.find_cell_index(cell));
839 843 };
840 844 };
841 845
842 846
843 847 Notebook.prototype.merge_cell_below = function () {
844 848 var index = this.get_selected_index();
845 849 var cell = this.get_cell(index);
846 850 if (index < this.ncells()-1) {
847 851 lower_cell = this.get_cell(index+1);
848 852 lower_text = lower_cell.get_text();
849 853 text = cell.get_text();
850 854 if (cell instanceof IPython.CodeCell) {
851 855 cell.set_text(text+'\n'+lower_text);
852 856 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
853 857 cell.edit();
854 858 cell.set_text(text+'\n'+lower_text);
855 859 cell.render();
856 860 };
857 861 this.delete_cell(index+1);
858 862 this.select(this.find_cell_index(cell));
859 863 };
860 864 };
861 865
862 866
863 867 // Cell collapsing and output clearing
864 868
865 869 Notebook.prototype.collapse = function (index) {
866 870 var i = this.index_or_selected(index);
867 871 this.get_cell(i).collapse();
868 872 this.dirty = true;
869 873 };
870 874
871 875
872 876 Notebook.prototype.expand = function (index) {
873 877 var i = this.index_or_selected(index);
874 878 this.get_cell(i).expand();
875 879 this.dirty = true;
876 880 };
877 881
878 882
879 883 Notebook.prototype.toggle_output = function (index) {
880 884 var i = this.index_or_selected(index);
881 885 this.get_cell(i).toggle_output();
882 886 this.dirty = true;
883 887 };
884 888
885 889
890 Notebook.prototype.toggle_output_scroll = function (index) {
891 var i = this.index_or_selected(index);
892 this.get_cell(i).toggle_output_scroll();
893 };
894
895
896 Notebook.prototype.collapse_all_output = function () {
897 var ncells = this.ncells();
898 var cells = this.get_cells();
899 for (var i=0; i<ncells; i++) {
900 if (cells[i] instanceof IPython.CodeCell) {
901 cells[i].output_area.collapse();
902 }
903 };
904 // this should not be set if the `collapse` key is removed from nbformat
905 this.dirty = true;
906 };
907
908
909 Notebook.prototype.scroll_all_output = function () {
910 var ncells = this.ncells();
911 var cells = this.get_cells();
912 for (var i=0; i<ncells; i++) {
913 if (cells[i] instanceof IPython.CodeCell) {
914 cells[i].output_area.expand();
915 cells[i].output_area.scroll_if_long(20);
916 }
917 };
918 // this should not be set if the `collapse` key is removed from nbformat
919 this.dirty = true;
920 };
921
922
923 Notebook.prototype.expand_all_output = function () {
924 var ncells = this.ncells();
925 var cells = this.get_cells();
926 for (var i=0; i<ncells; i++) {
927 if (cells[i] instanceof IPython.CodeCell) {
928 cells[i].output_area.expand();
929 cells[i].output_area.unscroll_area();
930 }
931 };
932 // this should not be set if the `collapse` key is removed from nbformat
933 this.dirty = true;
934 };
935
936
886 937 Notebook.prototype.clear_all_output = function () {
887 938 var ncells = this.ncells();
888 939 var cells = this.get_cells();
889 940 for (var i=0; i<ncells; i++) {
890 941 if (cells[i] instanceof IPython.CodeCell) {
891 942 cells[i].clear_output(true,true,true);
892 943 // Make all In[] prompts blank, as well
893 944 // TODO: make this configurable (via checkbox?)
894 945 cells[i].set_input_prompt();
895 946 }
896 947 };
897 948 this.dirty = true;
898 949 };
899 950
900 951
901 952 // Other cell functions: line numbers, ...
902 953
903 954 Notebook.prototype.cell_toggle_line_numbers = function() {
904 955 this.get_selected_cell().toggle_line_numbers();
905 956 };
906 957
907 958 // Kernel related things
908 959
909 960 Notebook.prototype.start_kernel = function () {
910 961 var base_url = $('body').data('baseKernelUrl') + "kernels";
911 962 this.kernel = new IPython.Kernel(base_url);
912 963 this.kernel.start(this.notebook_id);
913 964 // Now that the kernel has been created, tell the CodeCells about it.
914 965 var ncells = this.ncells();
915 966 for (var i=0; i<ncells; i++) {
916 967 var cell = this.get_cell(i);
917 968 if (cell instanceof IPython.CodeCell) {
918 969 cell.set_kernel(this.kernel)
919 970 };
920 971 };
921 972 };
922 973
923 974
924 975 Notebook.prototype.restart_kernel = function () {
925 976 var that = this;
926 977 var dialog = $('<div/>');
927 978 dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
928 979 $(document).append(dialog);
929 980 dialog.dialog({
930 981 resizable: false,
931 982 modal: true,
932 983 title: "Restart kernel or continue running?",
933 984 closeText: '',
934 985 buttons : {
935 986 "Restart": function () {
936 987 that.kernel.restart();
937 988 $(this).dialog('close');
938 989 },
939 990 "Continue running": function () {
940 991 $(this).dialog('close');
941 992 }
942 993 }
943 994 });
944 995 };
945 996
946 997
947 998 Notebook.prototype.execute_selected_cell = function (options) {
948 999 // add_new: should a new cell be added if we are at the end of the nb
949 1000 // terminal: execute in terminal mode, which stays in the current cell
950 1001 default_options = {terminal: false, add_new: true};
951 1002 $.extend(default_options, options);
952 1003 var that = this;
953 1004 var cell = that.get_selected_cell();
954 1005 var cell_index = that.find_cell_index(cell);
955 1006 if (cell instanceof IPython.CodeCell) {
956 1007 cell.execute();
957 1008 } else if (cell instanceof IPython.HTMLCell) {
958 1009 cell.render();
959 1010 }
960 1011 if (default_options.terminal) {
961 1012 cell.select_all();
962 1013 } else {
963 1014 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
964 1015 that.insert_cell_below('code');
965 1016 // If we are adding a new cell at the end, scroll down to show it.
966 1017 that.scroll_to_bottom();
967 1018 } else {
968 1019 that.select(cell_index+1);
969 1020 };
970 1021 };
971 1022 this.dirty = true;
972 1023 };
973 1024
974 1025
975 1026 Notebook.prototype.execute_all_cells = function () {
976 1027 var ncells = this.ncells();
977 1028 for (var i=0; i<ncells; i++) {
978 1029 this.select(i);
979 1030 this.execute_selected_cell({add_new:false});
980 1031 };
981 1032 this.scroll_to_bottom();
982 1033 };
983 1034
984 1035 // Persistance and loading
985 1036
986 1037 Notebook.prototype.get_notebook_id = function () {
987 1038 return this.notebook_id;
988 1039 };
989 1040
990 1041
991 1042 Notebook.prototype.get_notebook_name = function () {
992 1043 return this.notebook_name;
993 1044 };
994 1045
995 1046
996 1047 Notebook.prototype.set_notebook_name = function (name) {
997 1048 this.notebook_name = name;
998 1049 };
999 1050
1000 1051
1001 1052 Notebook.prototype.test_notebook_name = function (nbname) {
1002 1053 nbname = nbname || '';
1003 1054 if (this.notebook_name_blacklist_re.test(nbname) == false && nbname.length>0) {
1004 1055 return true;
1005 1056 } else {
1006 1057 return false;
1007 1058 };
1008 1059 };
1009 1060
1010 1061
1011 1062 Notebook.prototype.fromJSON = function (data) {
1012 1063 var ncells = this.ncells();
1013 1064 var i;
1014 1065 for (i=0; i<ncells; i++) {
1015 1066 // Always delete cell 0 as they get renumbered as they are deleted.
1016 1067 this.delete_cell(0);
1017 1068 };
1018 1069 // Save the metadata and name.
1019 1070 this.metadata = data.metadata;
1020 1071 this.notebook_name = data.metadata.name;
1021 1072 // Only handle 1 worksheet for now.
1022 1073 var worksheet = data.worksheets[0];
1023 1074 if (worksheet !== undefined) {
1024 1075 if (worksheet.metadata) {
1025 1076 this.worksheet_metadata = worksheet.metadata;
1026 1077 }
1027 1078 var new_cells = worksheet.cells;
1028 1079 ncells = new_cells.length;
1029 1080 var cell_data = null;
1030 1081 var new_cell = null;
1031 1082 for (i=0; i<ncells; i++) {
1032 1083 cell_data = new_cells[i];
1033 1084 // VERSIONHACK: plaintext -> raw
1034 1085 // handle never-released plaintext name for raw cells
1035 1086 if (cell_data.cell_type === 'plaintext'){
1036 1087 cell_data.cell_type = 'raw';
1037 1088 }
1038 1089
1039 1090 new_cell = this.insert_cell_below(cell_data.cell_type);
1040 1091 new_cell.fromJSON(cell_data);
1041 1092 };
1042 1093 };
1043 1094 if (data.worksheets.length > 1) {
1044 1095 var dialog = $('<div/>');
1045 1096 dialog.html("This notebook has " + data.worksheets.length + " worksheets, " +
1046 1097 "but this version of IPython can only handle the first. " +
1047 1098 "If you save this notebook, worksheets after the first will be lost."
1048 1099 );
1049 1100 this.element.append(dialog);
1050 1101 dialog.dialog({
1051 1102 resizable: false,
1052 1103 modal: true,
1053 1104 title: "Multiple worksheets",
1054 1105 closeText: "",
1055 1106 close: function(event, ui) {$(this).dialog('destroy').remove();},
1056 1107 buttons : {
1057 1108 "OK": function () {
1058 1109 $(this).dialog('close');
1059 1110 }
1060 1111 },
1061 1112 width: 400
1062 1113 });
1063 1114 }
1064 1115 };
1065 1116
1066 1117
1067 1118 Notebook.prototype.toJSON = function () {
1068 1119 var cells = this.get_cells();
1069 1120 var ncells = cells.length;
1070 1121 var cell_array = new Array(ncells);
1071 1122 for (var i=0; i<ncells; i++) {
1072 1123 cell_array[i] = cells[i].toJSON();
1073 1124 };
1074 1125 var data = {
1075 1126 // Only handle 1 worksheet for now.
1076 1127 worksheets : [{
1077 1128 cells: cell_array,
1078 1129 metadata: this.worksheet_metadata
1079 1130 }],
1080 1131 metadata : this.metadata
1081 1132 };
1082 1133 return data;
1083 1134 };
1084 1135
1085 1136 Notebook.prototype.save_notebook = function () {
1086 1137 // We may want to move the name/id/nbformat logic inside toJSON?
1087 1138 var data = this.toJSON();
1088 1139 data.metadata.name = this.notebook_name;
1089 1140 data.nbformat = this.nbformat;
1090 1141 data.nbformat_minor = this.nbformat_minor;
1091 1142 // We do the call with settings so we can set cache to false.
1092 1143 var settings = {
1093 1144 processData : false,
1094 1145 cache : false,
1095 1146 type : "PUT",
1096 1147 data : JSON.stringify(data),
1097 1148 headers : {'Content-Type': 'application/json'},
1098 1149 success : $.proxy(this.save_notebook_success,this),
1099 1150 error : $.proxy(this.save_notebook_error,this)
1100 1151 };
1101 1152 $([IPython.events]).trigger('notebook_saving.Notebook');
1102 1153 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1103 1154 $.ajax(url, settings);
1104 1155 };
1105 1156
1106 1157
1107 1158 Notebook.prototype.save_notebook_success = function (data, status, xhr) {
1108 1159 this.dirty = false;
1109 1160 $([IPython.events]).trigger('notebook_saved.Notebook');
1110 1161 };
1111 1162
1112 1163
1113 1164 Notebook.prototype.save_notebook_error = function (xhr, status, error_msg) {
1114 1165 $([IPython.events]).trigger('notebook_save_failed.Notebook');
1115 1166 };
1116 1167
1117 1168
1118 1169 Notebook.prototype.load_notebook = function (notebook_id) {
1119 1170 var that = this;
1120 1171 this.notebook_id = notebook_id;
1121 1172 // We do the call with settings so we can set cache to false.
1122 1173 var settings = {
1123 1174 processData : false,
1124 1175 cache : false,
1125 1176 type : "GET",
1126 1177 dataType : "json",
1127 1178 success : $.proxy(this.load_notebook_success,this),
1128 1179 error : $.proxy(this.load_notebook_error,this),
1129 1180 };
1130 1181 $([IPython.events]).trigger('notebook_loading.Notebook');
1131 1182 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1132 1183 $.ajax(url, settings);
1133 1184 };
1134 1185
1135 1186
1136 1187 Notebook.prototype.load_notebook_success = function (data, status, xhr) {
1137 1188 this.fromJSON(data);
1138 1189 if (this.ncells() === 0) {
1139 1190 this.insert_cell_below('code');
1140 1191 };
1141 1192 this.dirty = false;
1142 1193 this.select(0);
1143 1194 this.scroll_to_top();
1144 1195 if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) {
1145 1196 msg = "This notebook has been converted from an older " +
1146 1197 "notebook format (v"+data.orig_nbformat+") to the current notebook " +
1147 1198 "format (v"+data.nbformat+"). The next time you save this notebook, the " +
1148 1199 "newer notebook format will be used and older verions of IPython " +
1149 1200 "may not be able to read it. To keep the older version, close the " +
1150 1201 "notebook without saving it.";
1151 1202 var dialog = $('<div/>');
1152 1203 dialog.html(msg);
1153 1204 this.element.append(dialog);
1154 1205 dialog.dialog({
1155 1206 resizable: false,
1156 1207 modal: true,
1157 1208 title: "Notebook converted",
1158 1209 closeText: "",
1159 1210 close: function(event, ui) {$(this).dialog('destroy').remove();},
1160 1211 buttons : {
1161 1212 "OK": function () {
1162 1213 $(this).dialog('close');
1163 1214 }
1164 1215 },
1165 1216 width: 400
1166 1217 });
1167 1218 } else if (data.orig_nbformat_minor !== undefined && data.nbformat_minor !== data.orig_nbformat_minor) {
1168 1219 var that = this;
1169 1220 var orig_vs = 'v' + data.nbformat + '.' + data.orig_nbformat_minor;
1170 1221 var this_vs = 'v' + data.nbformat + '.' + this.nbformat_minor;
1171 1222 msg = "This notebook is version " + orig_vs + ", but we only fully support up to " +
1172 1223 this_vs + ". You can still work with this notebook, but some features " +
1173 1224 "introduced in later notebook versions may not be available."
1174 1225
1175 1226 var dialog = $('<div/>');
1176 1227 dialog.html(msg);
1177 1228 this.element.append(dialog);
1178 1229 dialog.dialog({
1179 1230 resizable: false,
1180 1231 modal: true,
1181 1232 title: "Newer Notebook",
1182 1233 closeText: "",
1183 1234 close: function(event, ui) {$(this).dialog('destroy').remove();},
1184 1235 buttons : {
1185 1236 "OK": function () {
1186 1237 $(this).dialog('close');
1187 1238 }
1188 1239 },
1189 1240 width: 400
1190 1241 });
1191 1242
1192 1243 }
1193 1244 // Create the kernel after the notebook is completely loaded to prevent
1194 1245 // code execution upon loading, which is a security risk.
1195 1246 if (! this.read_only) {
1196 1247 this.start_kernel();
1197 1248 }
1198 1249 $([IPython.events]).trigger('notebook_loaded.Notebook');
1199 1250 };
1200 1251
1201 1252
1202 1253 Notebook.prototype.load_notebook_error = function (xhr, textStatus, errorThrow) {
1203 1254 if (xhr.status === 500) {
1204 1255 msg = "An error occurred while loading this notebook. Most likely " +
1205 1256 "this notebook is in a newer format than is supported by this " +
1206 1257 "version of IPython. This version can load notebook formats " +
1207 1258 "v"+this.nbformat+" or earlier.";
1208 1259 var dialog = $('<div/>');
1209 1260 dialog.html(msg);
1210 1261 this.element.append(dialog);
1211 1262 dialog.dialog({
1212 1263 resizable: false,
1213 1264 modal: true,
1214 1265 title: "Error loading notebook",
1215 1266 closeText: "",
1216 1267 close: function(event, ui) {$(this).dialog('destroy').remove();},
1217 1268 buttons : {
1218 1269 "OK": function () {
1219 1270 $(this).dialog('close');
1220 1271 }
1221 1272 },
1222 1273 width: 400
1223 1274 });
1224 1275 }
1225 1276 }
1226 1277
1227 1278 IPython.Notebook = Notebook;
1228 1279
1229 1280
1230 1281 return IPython;
1231 1282
1232 1283 }(IPython));
1233 1284
@@ -1,416 +1,518 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 // OutputArea
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13 "use strict";
14 14
15 15 var utils = IPython.utils;
16 16
17 17 var OutputArea = function (selector, prompt_area) {
18 18 this.selector = selector;
19 this.element = $(selector);
19 this.wrapper = $(selector);
20 20 this.outputs = [];
21 21 this.collapsed = false;
22 this.scrolled = false;
22 23 this.clear_out_timeout = null;
23 24 if (prompt_area === undefined) {
24 25 this.prompt_area = true;
25 26 } else {
26 27 this.prompt_area = prompt_area;
27 28 };
29 this.create_elements();
28 30 this.style();
31 this.bind_events();
32 };
33
34 OutputArea.prototype.create_elements = function () {
35 this.element = $("<div/>");
36 this.collapse_button = $("<div/>");
37 this.prompt_overlay = $("<div/>");
38 this.wrapper.append(this.prompt_overlay);
39 this.wrapper.append(this.element);
40 this.wrapper.append(this.collapse_button);
29 41 };
30 42
31 43
32 44 OutputArea.prototype.style = function () {
45 this.collapse_button.hide();
46 this.prompt_overlay.hide();
47
48 this.wrapper.addClass('output_wrapper');
33 49 this.element.addClass('output vbox');
50
51 this.collapse_button.button();
52 this.collapse_button.addClass('output_collapsed vbox');
53 this.collapse_button.attr('title', 'click to expand outout');
54 this.collapse_button.html('. . .');
55
56 this.prompt_overlay.addClass('out_prompt_overlay prompt');
57 this.prompt_overlay.attr('title', 'click to expand outout; double click to hide output');
58
34 59 this.collapse();
35 60 };
36 61
37 62
63 OutputArea.prototype._should_scroll = function (lines) {
64 if (!lines) {
65 lines = 50;
66 }
67 // line-height from http://stackoverflow.com/questions/1185151
68 var fontSize = this.element.css('font-size');
69 var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
70
71 return (this.element.height() > lines * lineHeight);
72 };
73
74
75 OutputArea.prototype.bind_events = function () {
76 var that = this;
77 this.prompt_overlay.dblclick(function () { that.toggle_output(); });
78 this.prompt_overlay.click(function () { that.toggle_scroll(); });
79
80 this.element.resize(function () {
81 // maybe scroll output,
82 // if it's grown large enough and hasn't already been scrolled.
83 if ( !that.scrolled && that._should_scroll()) {
84 that.scroll_area();
85 }
86 });
87 this.collapse_button.click(function () {
88 that.expand();
89 });
90 this.collapse_button.hover(function () {
91 $(this).addClass("ui-state-hover");
92 }, function () {
93 $(this).removeClass("ui-state-hover");
94 });
95 };
96
97
38 98 OutputArea.prototype.collapse = function () {
39 99 if (!this.collapsed) {
40 100 this.element.hide();
101 this.prompt_overlay.hide();
102 if (this.element.html()){
103 this.collapse_button.show();
104 }
41 105 this.collapsed = true;
42 106 };
43 107 };
44 108
45 109
46 110 OutputArea.prototype.expand = function () {
47 111 if (this.collapsed) {
112 this.collapse_button.hide();
48 113 this.element.show();
114 this.prompt_overlay.show();
49 115 this.collapsed = false;
50 116 };
51 117 };
52 118
53 119
54 120 OutputArea.prototype.toggle_output = function () {
55 121 if (this.collapsed) {
56 122 this.expand();
57 123 } else {
58 124 this.collapse();
59 125 };
60 126 };
61 127
62 128
129 OutputArea.prototype.scroll_area = function () {
130 this.element.addClass('output_scroll');
131 this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide');
132 this.scrolled = true;
133 };
134
135
136 OutputArea.prototype.unscroll_area = function () {
137 this.element.removeClass('output_scroll');
138 this.prompt_overlay.attr('title', 'click to scroll output; double click to hide');
139 this.scrolled = false;
140 };
141
142
143 OutputArea.prototype.scroll_if_long = function (lines) {
144 if (this._should_scroll(lines)) {
145 // only allow scrolling long-enough output
146 this.scroll_area();
147 };
148 };
149
150
151 OutputArea.prototype.toggle_scroll = function () {
152 if (this.scrolled) {
153 this.unscroll_area();
154 } else {
155 // only allow scrolling long-enough output
156 this.scroll_if_long(20);
157 };
158 };
159
160
63 161 // typeset with MathJax if MathJax is available
64 162 OutputArea.prototype.typeset = function () {
65 163 if (window.MathJax){
66 164 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
67 165 }
68 166 };
69 167
70 168
71 169 OutputArea.prototype.handle_output = function (msg_type, content) {
72 170 var json = {};
73 171 json.output_type = msg_type;
74 172 if (msg_type === "stream") {
75 173 json.text = content.data;
76 174 json.stream = content.name;
77 175 } else if (msg_type === "display_data") {
78 176 json = this.convert_mime_types(json, content.data);
79 177 } else if (msg_type === "pyout") {
80 178 json.prompt_number = content.execution_count;
81 179 json = this.convert_mime_types(json, content.data);
82 180 } else if (msg_type === "pyerr") {
83 181 json.ename = content.ename;
84 182 json.evalue = content.evalue;
85 183 json.traceback = content.traceback;
86 184 };
87 185 // append with dynamic=true
88 186 this.append_output(json, true);
89 187 };
90 188
91 189
92 190 OutputArea.prototype.convert_mime_types = function (json, data) {
93 191 if (data['text/plain'] !== undefined) {
94 192 json.text = data['text/plain'];
95 193 };
96 194 if (data['text/html'] !== undefined) {
97 195 json.html = data['text/html'];
98 196 };
99 197 if (data['image/svg+xml'] !== undefined) {
100 198 json.svg = data['image/svg+xml'];
101 199 };
102 200 if (data['image/png'] !== undefined) {
103 201 json.png = data['image/png'];
104 202 };
105 203 if (data['image/jpeg'] !== undefined) {
106 204 json.jpeg = data['image/jpeg'];
107 205 };
108 206 if (data['text/latex'] !== undefined) {
109 207 json.latex = data['text/latex'];
110 208 };
111 209 if (data['application/json'] !== undefined) {
112 210 json.json = data['application/json'];
113 211 };
114 212 if (data['application/javascript'] !== undefined) {
115 213 json.javascript = data['application/javascript'];
116 214 }
117 215 return json;
118 216 };
119 217
120 218
121 219 OutputArea.prototype.append_output = function (json, dynamic) {
122 220 // If dynamic is true, javascript output will be eval'd.
123 221 this.expand();
124 222 this.flush_clear_timeout();
125 223 if (json.output_type === 'pyout') {
126 224 this.append_pyout(json, dynamic);
127 225 } else if (json.output_type === 'pyerr') {
128 226 this.append_pyerr(json);
129 227 } else if (json.output_type === 'display_data') {
130 228 this.append_display_data(json, dynamic);
131 229 } else if (json.output_type === 'stream') {
132 230 this.append_stream(json);
133 231 };
134 232 this.outputs.push(json);
233 var that = this;
234 setTimeout(function(){that.element.trigger('resize');}, 100);
135 235 };
136 236
137 237
138 238 OutputArea.prototype.create_output_area = function () {
139 239 var oa = $("<div/>").addClass("hbox output_area");
140 240 if (this.prompt_area) {
141 241 oa.append($('<div/>').addClass('prompt'));
142 242 }
143 243 return oa;
144 244 };
145 245
146 246
147 247 OutputArea.prototype.append_pyout = function (json, dynamic) {
148 248 var n = json.prompt_number || ' ';
149 249 var toinsert = this.create_output_area();
150 250 if (this.prompt_area) {
151 251 toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:');
152 252 }
153 253 this.append_mime_type(json, toinsert, dynamic);
154 254 this.element.append(toinsert);
155 255 // If we just output latex, typeset it.
156 256 if ((json.latex !== undefined) || (json.html !== undefined)) {
157 257 this.typeset();
158 258 };
159 259 };
160 260
161 261
162 262 OutputArea.prototype.append_pyerr = function (json) {
163 263 var tb = json.traceback;
164 264 if (tb !== undefined && tb.length > 0) {
165 265 var s = '';
166 266 var len = tb.length;
167 267 for (var i=0; i<len; i++) {
168 268 s = s + tb[i] + '\n';
169 269 }
170 270 s = s + '\n';
171 271 var toinsert = this.create_output_area();
172 272 this.append_text(s, toinsert);
173 273 this.element.append(toinsert);
174 274 };
175 275 };
176 276
177 277
178 278 OutputArea.prototype.append_stream = function (json) {
179 279 // temporary fix: if stream undefined (json file written prior to this patch),
180 280 // default to most likely stdout:
181 281 if (json.stream == undefined){
182 282 json.stream = 'stdout';
183 283 }
184 284 var text = json.text;
185 285 var subclass = "output_"+json.stream;
186 286 if (this.outputs.length > 0){
187 287 // have at least one output to consider
188 288 var last = this.outputs[this.outputs.length-1];
189 289 if (last.output_type == 'stream' && json.stream == last.stream){
190 290 // latest output was in the same stream,
191 291 // so append directly into its pre tag
192 292 // escape ANSI & HTML specials:
193 293 var pre = this.element.find('div.'+subclass).last().find('pre');
194 294 var html = utils.fixCarriageReturn(
195 295 pre.html() + utils.fixConsole(text));
196 296 pre.html(html);
197 297 return;
198 298 }
199 299 }
200 300
201 301 if (!text.replace("\r", "")) {
202 302 // text is nothing (empty string, \r, etc.)
203 303 // so don't append any elements, which might add undesirable space
204 304 return;
205 305 }
206 306
207 307 // If we got here, attach a new div
208 308 var toinsert = this.create_output_area();
209 309 this.append_text(text, toinsert, "output_stream "+subclass);
210 310 this.element.append(toinsert);
211 311 };
212 312
213 313
214 314 OutputArea.prototype.append_display_data = function (json, dynamic) {
215 315 var toinsert = this.create_output_area();
216 316 this.append_mime_type(json, toinsert, dynamic);
217 317 this.element.append(toinsert);
218 318 // If we just output latex, typeset it.
219 319 if ( (json.latex !== undefined) || (json.html !== undefined) ) {
220 320 this.typeset();
221 321 };
222 322 };
223 323
224 324
225 325 OutputArea.prototype.append_mime_type = function (json, element, dynamic) {
226 326 if (json.javascript !== undefined && dynamic) {
227 327 this.append_javascript(json.javascript, element, dynamic);
228 328 } else if (json.html !== undefined) {
229 329 this.append_html(json.html, element);
230 330 } else if (json.latex !== undefined) {
231 331 this.append_latex(json.latex, element);
232 332 } else if (json.svg !== undefined) {
233 333 this.append_svg(json.svg, element);
234 334 } else if (json.png !== undefined) {
235 335 this.append_png(json.png, element);
236 336 } else if (json.jpeg !== undefined) {
237 337 this.append_jpeg(json.jpeg, element);
238 338 } else if (json.text !== undefined) {
239 339 this.append_text(json.text, element);
240 340 };
241 341 };
242 342
243 343
244 344 OutputArea.prototype.append_html = function (html, element) {
245 345 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_html rendered_html");
246 346 toinsert.append(html);
247 347 element.append(toinsert);
248 348 };
249 349
250 350
251 351 OutputArea.prototype.append_javascript = function (js, container) {
252 352 // We just eval the JS code, element appears in the local scope.
253 353 var element = $("<div/>").addClass("box-flex1 output_subarea");
254 354 container.append(element);
255 355 // Div for js shouldn't be drawn, as it will add empty height to the area.
256 356 container.hide();
257 357 // If the Javascript appends content to `element` that should be drawn, then
258 358 // it must also call `container.show()`.
259 359 eval(js);
260 360 }
261 361
262 362
263 363 OutputArea.prototype.append_text = function (data, element, extra_class) {
264 364 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_text");
265 365 // escape ANSI & HTML specials in plaintext:
266 366 data = utils.fixConsole(data);
267 367 data = utils.fixCarriageReturn(data);
268 368 if (extra_class){
269 369 toinsert.addClass(extra_class);
270 370 }
271 371 toinsert.append($("<pre/>").html(data));
272 372 element.append(toinsert);
273 373 };
274 374
275 375
276 376 OutputArea.prototype.append_svg = function (svg, element) {
277 377 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_svg");
278 378 toinsert.append(svg);
279 379 element.append(toinsert);
280 380 };
281 381
282 382
283 383 OutputArea.prototype.append_png = function (png, element) {
284 384 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_png");
285 385 var img = $("<img/>").attr('src','data:image/png;base64,'+png);
286 386 img.load(function () {
287 387 $(this).resizable({'aspectRatio': true, 'autoHide': true})
288 388 });
289 389 toinsert.append(img);
290 390 element.append(toinsert);
291 391 };
292 392
293 393
294 394 OutputArea.prototype.append_jpeg = function (jpeg, element) {
295 395 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_jpeg");
296 396 var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg);
297 397 img.load(function () {
298 398 $(this).resizable({'aspectRatio': true, 'autoHide': true})
299 399 });
300 400 toinsert.append(img);
301 401 element.append(toinsert);
302 402 };
303 403
304 404
305 405 OutputArea.prototype.append_latex = function (latex, element) {
306 406 // This method cannot do the typesetting because the latex first has to
307 407 // be on the page.
308 408 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_latex");
309 409 toinsert.append(latex);
310 410 element.append(toinsert);
311 411 };
312 412
313 413
314 414 OutputArea.prototype.handle_clear_output = function (content) {
315 415 this.clear_output(content.stdout, content.stderr, content.other);
316 416 }
317 417
318 418
319 419 OutputArea.prototype.clear_output = function (stdout, stderr, other) {
320 420 var that = this;
321 421 if (this.clear_out_timeout != null){
322 422 // fire previous pending clear *immediately*
323 423 clearTimeout(this.clear_out_timeout);
324 424 this.clear_out_timeout = null;
325 425 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
326 426 }
327 427 // store flags for flushing the timeout
328 428 this._clear_stdout = stdout;
329 429 this._clear_stderr = stderr;
330 430 this._clear_other = other;
331 431 this.clear_out_timeout = setTimeout(function() {
332 432 // really clear timeout only after a short delay
333 433 // this reduces flicker in 'clear_output; print' cases
334 434 that.clear_out_timeout = null;
335 435 that._clear_stdout = that._clear_stderr = that._clear_other = null;
336 436 that.clear_output_callback(stdout, stderr, other);
337 437 }, 500
338 438 );
339 439 };
340 440
341 441
342 442 OutputArea.prototype.clear_output_callback = function (stdout, stderr, other) {
343 443 var output_div = this.element;
344 444
345 445 if (stdout && stderr && other){
346 446 // clear all, no need for logic
347 447 output_div.html("");
348 448 this.outputs = [];
449 this.unscroll_area();
349 450 return;
350 451 }
351 452 // remove html output
352 453 // each output_subarea that has an identifying class is in an output_area
353 454 // which is the element to be removed.
354 455 if (stdout) {
355 456 output_div.find("div.output_stdout").parent().remove();
356 457 }
357 458 if (stderr) {
358 459 output_div.find("div.output_stderr").parent().remove();
359 460 }
360 461 if (other) {
361 462 output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
362 463 }
363
464 this.unscroll_area();
465
364 466 // remove cleared outputs from JSON list:
365 467 for (var i = this.outputs.length - 1; i >= 0; i--) {
366 468 var out = this.outputs[i];
367 469 var output_type = out.output_type;
368 470 if (output_type == "display_data" && other) {
369 471 this.outputs.splice(i,1);
370 472 } else if (output_type == "stream") {
371 473 if (stdout && out.stream == "stdout") {
372 474 this.outputs.splice(i,1);
373 475 } else if (stderr && out.stream == "stderr") {
374 476 this.outputs.splice(i,1);
375 477 }
376 478 }
377 479 }
378 480 };
379 481
380 482
381 483 OutputArea.prototype.flush_clear_timeout = function() {
382 484 var output_div = this.element;
383 485 if (this.clear_out_timeout){
384 486 clearTimeout(this.clear_out_timeout);
385 487 this.clear_out_timeout = null;
386 488 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
387 489 };
388 490 }
389 491
390 492
391 493 // JSON serialization
392 494
393 495 OutputArea.prototype.fromJSON = function (outputs) {
394 496 var len = outputs.length;
395 497 for (var i=0; i<len; i++) {
396 498 // append with dynamic=false.
397 499 this.append_output(outputs[i], false);
398 500 };
399 501 };
400 502
401 503
402 504 OutputArea.prototype.toJSON = function () {
403 505 var outputs = [];
404 506 var len = this.outputs.length;
405 507 for (var i=0; i<len; i++) {
406 508 outputs[i] = this.outputs[i];
407 509 };
408 510 return outputs;
409 511 };
410 512
411 513
412 514 IPython.OutputArea = OutputArea;
413 515
414 516 return IPython;
415 517
416 518 }(IPython));
@@ -1,70 +1,71 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 // QuickHelp button
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13
14 14 var QuickHelp = function (selector) {
15 15 };
16 16
17 17 QuickHelp.prototype.show_keyboard_shortcuts = function () {
18 18 // toggles display of keyboard shortcut dialog
19 19 var that = this;
20 20 if ( this.shortcut_dialog ){
21 21 // if dialog is already shown, close it
22 22 this.shortcut_dialog.dialog("close");
23 23 this.shortcut_dialog = null;
24 24 return;
25 25 }
26 26 var dialog = $('<div/>');
27 27 this.shortcut_dialog = dialog;
28 28 var shortcuts = [
29 29 {key: 'Shift-Enter', help: 'run cell'},
30 30 {key: 'Ctrl-Enter', help: 'run cell in-place'},
31 31 {key: 'Ctrl-m x', help: 'cut cell'},
32 32 {key: 'Ctrl-m c', help: 'copy cell'},
33 33 {key: 'Ctrl-m v', help: 'paste cell'},
34 34 {key: 'Ctrl-m d', help: 'delete cell'},
35 35 {key: 'Ctrl-m a', help: 'insert cell above'},
36 36 {key: 'Ctrl-m b', help: 'insert cell below'},
37 37 {key: 'Ctrl-m o', help: 'toggle output'},
38 {key: 'Ctrl-m O', help: 'toggle output scroll'},
38 39 {key: 'Ctrl-m l', help: 'toggle line numbers'},
39 40 {key: 'Ctrl-m s', help: 'save notebook'},
40 41 {key: 'Ctrl-m j', help: 'move cell down'},
41 42 {key: 'Ctrl-m k', help: 'move cell up'},
42 43 {key: 'Ctrl-m y', help: 'code cell'},
43 44 {key: 'Ctrl-m m', help: 'markdown cell'},
44 45 {key: 'Ctrl-m t', help: 'raw cell'},
45 46 {key: 'Ctrl-m 1-6', help: 'heading 1-6 cell'},
46 47 {key: 'Ctrl-m p', help: 'select previous'},
47 48 {key: 'Ctrl-m n', help: 'select next'},
48 49 {key: 'Ctrl-m i', help: 'interrupt kernel'},
49 50 {key: 'Ctrl-m .', help: 'restart kernel'},
50 51 {key: 'Ctrl-m h', help: 'show keyboard shortcuts'}
51 52 ];
52 53 for (var i=0; i<shortcuts.length; i++) {
53 54 dialog.append($('<div>').
54 55 append($('<span/>').addClass('shortcut_key').html(shortcuts[i].key)).
55 56 append($('<span/>').addClass('shortcut_descr').html(' : ' + shortcuts[i].help))
56 57 );
57 58 };
58 59 dialog.bind('dialogclose', function(event) {
59 60 // dialog has been closed, allow it to be drawn again.
60 61 that.shortcut_dialog = null;
61 62 });
62 63 dialog.dialog({title: 'Keyboard shortcuts', closeText: ''});
63 64 };
64 65
65 66 // Set module variables
66 67 IPython.QuickHelp = QuickHelp;
67 68
68 69 return IPython;
69 70
70 71 }(IPython));
@@ -1,241 +1,248 b''
1 1 {% extends page.html %}
2 2 {% block stylesheet %}
3 3
4 4 {% if mathjax_url %}
5 5 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML" charset="utf-8"></script>
6 6 {% end %}
7 7 <script type="text/javascript">
8 8 // MathJax disabled, set as null to distingish from *missing* MathJax,
9 9 // where it will be undefined, and should prompt a dialog later.
10 10 window.mathjax_url = "{{mathjax_url}}";
11 11 </script>
12 12
13 13 <link rel="stylesheet" href="{{ static_url("codemirror/lib/codemirror.css") }}">
14 14 <link rel="stylesheet" href="{{ static_url("codemirror/theme/ipython.css") }}">
15 15
16 16 <link rel="stylesheet" href="{{ static_url("prettify/prettify.css") }}"/>
17 17
18 18 <link rel="stylesheet" href="{{ static_url("css/notebook.css") }}" type="text/css" />
19 19 <link rel="stylesheet" href="{{ static_url("css/tooltip.css") }}" type="text/css" />
20 20 <link rel="stylesheet" href="{{ static_url("css/renderedhtml.css") }}" type="text/css" />
21 21
22 22 {% end %}
23 23
24 24
25 25 {% block params %}
26 26
27 27 data-project={{project}}
28 28 data-base-project-url={{base_project_url}}
29 29 data-base-kernel-url={{base_kernel_url}}
30 30 data-read-only={{read_only and not logged_in}}
31 31 data-notebook-id={{notebook_id}}
32 32
33 33 {% end %}
34 34
35 35
36 36 {% block header %}
37 37
38 38 <span id="save_widget">
39 39 <span id="notebook_name"></span>
40 40 <span id="save_status"></span>
41 41 </span>
42 42
43 43 {% end %}
44 44
45 45
46 46 {% block site %}
47 47
48 48 <div id="menubar_container">
49 49 <div id="menubar">
50 50 <ul id="menus">
51 51 <li><a href="#">File</a>
52 52 <ul>
53 53 <li id="new_notebook"><a href="#">New</a></li>
54 54 <li id="open_notebook"><a href="#">Open...</a></li>
55 55 <hr/>
56 56 <li id="copy_notebook"><a href="#">Make a Copy...</a></li>
57 57 <li id="rename_notebook"><a href="#">Rename...</a></li>
58 58 <li id="save_notebook"><a href="#">Save</a></li>
59 59 <hr/>
60 60 <li><a href="#">Download as</a>
61 61 <ul>
62 62 <li id="download_ipynb"><a href="#">IPython (.ipynb)</a></li>
63 63 <li id="download_py"><a href="#">Python (.py)</a></li>
64 64 </ul>
65 65 </li>
66 66 <hr/>
67 67 <li id="print_notebook"><a href="/{{notebook_id}}/print" target="_blank">Print View</a></li>
68 68 <hr/>
69 69 <li id="kill_and_exit"><a href="#" >Close and halt</a></li>
70 70 </ul>
71 71 </li>
72 72 <li><a href="#">Edit</a>
73 73 <ul>
74 74 <li id="cut_cell"><a href="#">Cut Cell</a></li>
75 75 <li id="copy_cell"><a href="#">Copy Cell</a></li>
76 76 <li id="paste_cell" class="ui-state-disabled"><a href="#">Paste Cell</a></li>
77 77 <li id="paste_cell_above" class="ui-state-disabled"><a href="#">Paste Cell Above</a></li>
78 78 <li id="paste_cell_below" class="ui-state-disabled"><a href="#">Paste Cell Below</a></li>
79 79 <li id="delete_cell"><a href="#">Delete</a></li>
80 80 <hr/>
81 81 <li id="split_cell"><a href="#">Split Cell</a></li>
82 82 <li id="merge_cell_above"><a href="#">Merge Cell Above</a></li>
83 83 <li id="merge_cell_below"><a href="#">Merge Cell Below</a></li>
84 84 <hr/>
85 85 <li id="move_cell_up"><a href="#">Move Cell Up</a></li>
86 86 <li id="move_cell_down"><a href="#">Move Cell Down</a></li>
87 87 <hr/>
88 88 <li id="select_previous"><a href="#">Select Previous Cell</a></li>
89 89 <li id="select_next"><a href="#">Select Next Cell</a></li>
90 90 </ul>
91 91 </li>
92 92 <li><a href="#">View</a>
93 93 <ul>
94 94 <li id="toggle_header"><a href="#">Toggle Header</a></li>
95 95 <li id="toggle_toolbar"><a href="#">Toggle Toolbar</a></li>
96 96 </ul>
97 97 </li>
98 98 <li><a href="#">Insert</a>
99 99 <ul>
100 100 <li id="insert_cell_above"><a href="#">Insert Cell Above</a></li>
101 101 <li id="insert_cell_below"><a href="#">Insert Cell Below</a></li>
102 102 </ul>
103 103 </li>
104 104 <li><a href="#">Cell</a>
105 105 <ul>
106 106 <li id="run_cell"><a href="#">Run</a></li>
107 107 <li id="run_cell_in_place"><a href="#">Run in Place</a></li>
108 108 <li id="run_all_cells"><a href="#">Run All</a></li>
109 109 <hr/>
110 110 <li id="to_code"><a href="#">Code</a></li>
111 111 <li id="to_markdown"><a href="#">Markdown </a></li>
112 112 <li id="to_raw"><a href="#">Raw Text</a></li>
113 113 <li id="to_heading1"><a href="#">Heading 1</a></li>
114 114 <li id="to_heading2"><a href="#">Heading 2</a></li>
115 115 <li id="to_heading3"><a href="#">Heading 3</a></li>
116 116 <li id="to_heading4"><a href="#">Heading 4</a></li>
117 117 <li id="to_heading5"><a href="#">Heading 5</a></li>
118 118 <li id="to_heading6"><a href="#">Heading 6</a></li>
119 119 <hr/>
120 <li id="toggle_output"><a href="#">Toggle Output</a></li>
121 <li id="clear_all_output"><a href="#">Clear All Output</a></li>
120 <li id="toggle_output"><a href="#">Toggle Current Output</a></li>
121 <li id="all_outputs"><a href="#">All Output</a>
122 <ul>
123 <li id="expand_all_output"><a href="#">Expand</a></li>
124 <li id="scroll_all_output"><a href="#">Scroll Long</a></li>
125 <li id="collapse_all_output"><a href="#">Collapse</a></li>
126 <li id="clear_all_output"><a href="#">Clear</a></li>
127 </ul>
128 </li>
122 129 </ul>
123 130 </li>
124 131 <li><a href="#">Kernel</a>
125 132 <ul>
126 133 <li id="int_kernel"><a href="#">Interrupt</a></li>
127 134 <li id="restart_kernel"><a href="#">Restart</a></li>
128 135 </ul>
129 136 </li>
130 137 <li><a href="#">Help</a>
131 138 <ul>
132 139 <li><a href="http://ipython.org/documentation.html" target="_blank">IPython Help</a></li>
133 140 <li><a href="http://ipython.org/ipython-doc/stable/interactive/htmlnotebook.html" target="_blank">Notebook Help</a></li>
134 141 <li id="keyboard_shortcuts"><a href="#">Keyboard Shortcuts</a></li>
135 142 <hr/>
136 143 <li><a href="http://docs.python.org" target="_blank">Python</a></li>
137 144 <li><a href="http://docs.scipy.org/doc/numpy/reference/" target="_blank">NumPy</a></li>
138 145 <li><a href="http://docs.scipy.org/doc/scipy/reference/" target="_blank">SciPy</a></li>
139 146 <li><a href="http://docs.sympy.org/dev/index.html" target="_blank">SymPy</a></li>
140 147 <li><a href="http://matplotlib.sourceforge.net/" target="_blank">Matplotlib</a></li>
141 148 </ul>
142 149 </li>
143 150 </ul>
144 151
145 152 </div>
146 153 <div id="notification"></div>
147 154 </div>
148 155
149 156
150 157 <div id="toolbar">
151 158
152 159 <span>
153 160 <button id="save_b">Save</button>
154 161 </span>
155 162 <span id="cut_copy_paste">
156 163 <button id="cut_b" title="Cut Cell">Cut Cell</button>
157 164 <button id="copy_b" title="Copy Cell">Copy Cell</button>
158 165 <button id="paste_b" title="Paste Cell">Paste Cell</button>
159 166 </span>
160 167 <span id="move_up_down">
161 168 <button id="move_up_b" title="Move Cell Up">Move Cell Up</button>
162 169 <button id="move_down_b" title="Move Cell Down">Move Down</button>
163 170 </span>
164 171 <span id="insert_above_below">
165 172 <button id="insert_above_b" title="Insert Cell Above">Insert Cell Above</button>
166 173 <button id="insert_below_b" title="Insert Cell Below">Insert Cell Below</button>
167 174 </span>
168 175 <span id="run_int">
169 176 <button id="run_b" title="Run Cell">Run Cell</button>
170 177 <button id="interrupt_b" title="Interrupt">Interrupt</button>
171 178 </span>
172 179 <span>
173 180 <select id="cell_type">
174 181 <option value="code">Code</option>
175 182 <option value="markdown">Markdown</option>
176 183 <option value="raw">Raw Text</option>
177 184 <option value="heading1">Heading 1</option>
178 185 <option value="heading2">Heading 2</option>
179 186 <option value="heading3">Heading 3</option>
180 187 <option value="heading4">Heading 4</option>
181 188 <option value="heading5">Heading 5</option>
182 189 <option value="heading6">Heading 6</option>
183 190 </select>
184 191 </span>
185 192
186 193 </div>
187 194
188 195 <div id="main_app">
189 196
190 197 <div id="notebook_panel">
191 198 <div id="notebook"></div>
192 199 <div id="pager_splitter"></div>
193 200 <div id="pager"></div>
194 201 </div>
195 202
196 203 </div>
197 204 <div id='tooltip' class='tooltip ui-corner-all' style='display:none'></div>
198 205
199 206
200 207 {% end %}
201 208
202 209
203 210 {% block script %}
204 211
205 212 <script src="{{ static_url("codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
206 213 <script src="{{ static_url("codemirror/mode/python/python.js") }}" charset="utf-8"></script>
207 214 <script src="{{ static_url("codemirror/mode/htmlmixed/htmlmixed.js") }}" charset="utf-8"></script>
208 215 <script src="{{ static_url("codemirror/mode/xml/xml.js") }}" charset="utf-8"></script>
209 216 <script src="{{ static_url("codemirror/mode/javascript/javascript.js") }}" charset="utf-8"></script>
210 217 <script src="{{ static_url("codemirror/mode/css/css.js") }}" charset="utf-8"></script>
211 218 <script src="{{ static_url("codemirror/mode/rst/rst.js") }}" charset="utf-8"></script>
212 219 <script src="{{ static_url("codemirror/mode/markdown/markdown.js") }}" charset="utf-8"></script>
213 220
214 221 <script src="{{ static_url("pagedown/Markdown.Converter.js") }}" charset="utf-8"></script>
215 222
216 223 <script src="{{ static_url("prettify/prettify.js") }}" charset="utf-8"></script>
217 224 <script src="{{ static_url("dateformat/date.format.js") }}" charset="utf-8"></script>
218 225
219 226 <script src="{{ static_url("js/events.js") }}" type="text/javascript" charset="utf-8"></script>
220 227 <script src="{{ static_url("js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
221 228 <script src="{{ static_url("js/layoutmanager.js") }}" type="text/javascript" charset="utf-8"></script>
222 229 <script src="{{ static_url("js/initmathjax.js") }}" type="text/javascript" charset="utf-8"></script>
223 230 <script src="{{ static_url("js/outputarea.js") }}" type="text/javascript" charset="utf-8"></script>
224 231 <script src="{{ static_url("js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
225 232 <script src="{{ static_url("js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
226 233 <script src="{{ static_url("js/completer.js") }}" type="text/javascript" charset="utf-8"></script>
227 234 <script src="{{ static_url("js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
228 235 <script src="{{ static_url("js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
229 236 <script src="{{ static_url("js/savewidget.js") }}" type="text/javascript" charset="utf-8"></script>
230 237 <script src="{{ static_url("js/quickhelp.js") }}" type="text/javascript" charset="utf-8"></script>
231 238 <script src="{{ static_url("js/pager.js") }}" type="text/javascript" charset="utf-8"></script>
232 239 <script src="{{ static_url("js/menubar.js") }}" type="text/javascript" charset="utf-8"></script>
233 240 <script src="{{ static_url("js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
234 241 <script src="{{ static_url("js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
235 242 <script src="{{ static_url("js/notificationwidget.js") }}" type="text/javascript" charset="utf-8"></script>
236 243 <script src="{{ static_url("js/tooltip.js") }}" type="text/javascript" charset="utf-8"></script>
237 244 <script src="{{ static_url("js/notebookmain.js") }}" type="text/javascript" charset="utf-8"></script>
238 245
239 246 <script src="{{ static_url("js/contexthint.js") }} charset="utf-8"></script>
240 247
241 248 {% end %}
General Comments 0
You need to be logged in to leave comments. Login now