Show More
@@ -237,6 +237,12 b' IPython.keyboard = (function (IPython) {' | |||||
237 | return true; |
|
237 | return true; | |
238 | } |
|
238 | } | |
239 |
|
239 | |||
|
240 | ShortcutManager.prototype.handles = function (event) { | |||
|
241 | var shortcut = event_to_shortcut(event); | |||
|
242 | var data = this._shortcuts[shortcut]; | |||
|
243 | return !( data === undefined ) | |||
|
244 | } | |||
|
245 | ||||
240 | return { |
|
246 | return { | |
241 | keycodes : keycodes, |
|
247 | keycodes : keycodes, | |
242 | inv_keycodes : inv_keycodes, |
|
248 | inv_keycodes : inv_keycodes, |
@@ -19,6 +19,7 b' var IPython = (function (IPython) {' | |||||
19 | "use strict"; |
|
19 | "use strict"; | |
20 |
|
20 | |||
21 | var utils = IPython.utils; |
|
21 | var utils = IPython.utils; | |
|
22 | var keycodes = IPython.keyboard.keycodes; | |||
22 |
|
23 | |||
23 | /** |
|
24 | /** | |
24 | * The Base `Cell` class from which to inherit |
|
25 | * The Base `Cell` class from which to inherit | |
@@ -153,6 +154,30 b' var IPython = (function (IPython) {' | |||||
153 | }); |
|
154 | }); | |
154 | } |
|
155 | } | |
155 | }; |
|
156 | }; | |
|
157 | ||||
|
158 | /** | |||
|
159 | * This method gets called in CodeMirror's onKeyDown/onKeyPress | |||
|
160 | * handlers and is used to provide custom key handling. | |||
|
161 | * | |||
|
162 | * To have custom handling, subclasses should override this method, but still call it | |||
|
163 | * in order to process the Edit mode keyboard shortcuts. | |||
|
164 | * | |||
|
165 | * @method handle_codemirror_keyevent | |||
|
166 | * @param {CodeMirror} editor - The codemirror instance bound to the cell | |||
|
167 | * @param {event} event - key press event which either should or should not be handled by CodeMirror | |||
|
168 | * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise | |||
|
169 | */ | |||
|
170 | Cell.prototype.handle_codemirror_keyevent = function (editor, event) { | |||
|
171 | var that = this; | |||
|
172 | var shortcuts = IPython.keyboard_manager.edit_shortcuts; | |||
|
173 | ||||
|
174 | // if this is an edit_shortcuts shortcut, the global keyboard/shortcut | |||
|
175 | // manager will handle it | |||
|
176 | if (shortcuts.handles(event)) { return true; } | |||
|
177 | ||||
|
178 | return false; | |||
|
179 | }; | |||
|
180 | ||||
156 |
|
181 | |||
157 | /** |
|
182 | /** | |
158 | * Triger typsetting of math by mathjax on current cell element |
|
183 | * Triger typsetting of math by mathjax on current cell element | |
@@ -230,6 +255,52 b' var IPython = (function (IPython) {' | |||||
230 | }; |
|
255 | }; | |
231 |
|
256 | |||
232 | /** |
|
257 | /** | |
|
258 | * Delegates keyboard shortcut handling to either IPython keyboard | |||
|
259 | * manager when in command mode, or CodeMirror when in edit mode | |||
|
260 | * | |||
|
261 | * @method handle_keyevent | |||
|
262 | * @param {CodeMirror} editor - The codemirror instance bound to the cell | |||
|
263 | * @param {event} - key event to be handled | |||
|
264 | * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise | |||
|
265 | */ | |||
|
266 | Cell.prototype.handle_keyevent = function (editor, event) { | |||
|
267 | ||||
|
268 | // console.log('CM', this.mode, event.which, event.type) | |||
|
269 | ||||
|
270 | if (this.mode === 'command') { | |||
|
271 | return true; | |||
|
272 | } else if (this.mode === 'edit') { | |||
|
273 | return this.handle_codemirror_keyevent(editor, event); | |||
|
274 | } | |||
|
275 | }; | |||
|
276 | ||||
|
277 | /** | |||
|
278 | * @method at_top | |||
|
279 | * @return {Boolean} | |||
|
280 | */ | |||
|
281 | Cell.prototype.at_top = function () { | |||
|
282 | var cm = this.code_mirror; | |||
|
283 | var cursor = cm.getCursor(); | |||
|
284 | if (cursor.line === 0 && cursor.ch === 0) { | |||
|
285 | return true; | |||
|
286 | } | |||
|
287 | return false; | |||
|
288 | }; | |||
|
289 | ||||
|
290 | /** | |||
|
291 | * @method at_bottom | |||
|
292 | * @return {Boolean} | |||
|
293 | * */ | |||
|
294 | Cell.prototype.at_bottom = function () { | |||
|
295 | var cm = this.code_mirror; | |||
|
296 | var cursor = cm.getCursor(); | |||
|
297 | if (cursor.line === (cm.lineCount()-1) && cursor.ch === cm.getLine(cursor.line).length) { | |||
|
298 | return true; | |||
|
299 | } | |||
|
300 | return false; | |||
|
301 | }; | |||
|
302 | ||||
|
303 | /** | |||
233 | * enter the command mode for the cell |
|
304 | * enter the command mode for the cell | |
234 | * @method command_mode |
|
305 | * @method command_mode | |
235 | * @return is the action being taken |
|
306 | * @return is the action being taken |
@@ -171,16 +171,6 b' var IPython = (function (IPython) {' | |||||
171 | ); |
|
171 | ); | |
172 | }; |
|
172 | }; | |
173 |
|
173 | |||
174 | CodeCell.prototype.handle_keyevent = function (editor, event) { |
|
|||
175 |
|
||||
176 | // console.log('CM', this.mode, event.which, event.type) |
|
|||
177 |
|
||||
178 | if (this.mode === 'command') { |
|
|||
179 | return true; |
|
|||
180 | } else if (this.mode === 'edit') { |
|
|||
181 | return this.handle_codemirror_keyevent(editor, event); |
|
|||
182 | } |
|
|||
183 | }; |
|
|||
184 |
|
174 | |||
185 | /** |
|
175 | /** | |
186 | * This method gets called in CodeMirror's onKeyDown/onKeyPress |
|
176 | * This method gets called in CodeMirror's onKeyDown/onKeyPress | |
@@ -204,60 +194,26 b' var IPython = (function (IPython) {' | |||||
204 | this.auto_highlight(); |
|
194 | this.auto_highlight(); | |
205 | } |
|
195 | } | |
206 |
|
196 | |||
207 | if (event.keyCode === keycodes.enter && (event.shiftKey || event.ctrlKey || event.altKey)) { |
|
197 | if (event.which === keycodes.down && event.type === 'keypress' && IPython.tooltip.time_before_tooltip >= 0) { | |
208 | // Always ignore shift-enter in CodeMirror as we handle it. |
|
|||
209 | return true; |
|
|||
210 | } else if (event.which === 40 && event.type === 'keypress' && IPython.tooltip.time_before_tooltip >= 0) { |
|
|||
211 | // triger on keypress (!) otherwise inconsistent event.which depending on plateform |
|
198 | // triger on keypress (!) otherwise inconsistent event.which depending on plateform | |
212 | // browser and keyboard layout ! |
|
199 | // browser and keyboard layout ! | |
213 | // Pressing '(' , request tooltip, don't forget to reappend it |
|
200 | // Pressing '(' , request tooltip, don't forget to reappend it | |
214 | // The second argument says to hide the tooltip if the docstring |
|
201 | // The second argument says to hide the tooltip if the docstring | |
215 | // is actually empty |
|
202 | // is actually empty | |
216 | IPython.tooltip.pending(that, true); |
|
203 | IPython.tooltip.pending(that, true); | |
217 |
} else if (event.which === keycodes. |
|
204 | } else if ( tooltip_closed && event.which === keycodes.esc && event.type === 'keydown') { | |
218 | // If we are not at the top, let CM handle the up arrow and |
|
205 | // If tooltip is active, cancel it. The call to | |
219 | // prevent the global keydown handler from handling it. |
|
206 | // remove_and_cancel_tooltip above doesn't pass, force=true. | |
220 | if (!that.at_top()) { |
|
207 | // Because of this it won't actually close the tooltip | |
221 | event.stop(); |
|
208 | // if it is in sticky mode. Thus, we have to check again if it is open | |
222 | return false; |
|
209 | // and close it with force=true. | |
223 | } else { |
|
210 | if (!IPython.tooltip._hidden) { | |
224 | return true; |
|
211 | IPython.tooltip.remove_and_cancel_tooltip(true); | |
225 | } |
|
|||
226 | } else if (event.which === keycodes.esc && event.type === 'keydown') { |
|
|||
227 | // First see if the tooltip is active and if so cancel it. |
|
|||
228 | if (tooltip_closed) { |
|
|||
229 | // The call to remove_and_cancel_tooltip above in L177 doesn't pass |
|
|||
230 | // force=true. Because of this it won't actually close the tooltip |
|
|||
231 | // if it is in sticky mode. Thus, we have to check again if it is open |
|
|||
232 | // and close it with force=true. |
|
|||
233 | if (!IPython.tooltip._hidden) { |
|
|||
234 | IPython.tooltip.remove_and_cancel_tooltip(true); |
|
|||
235 | } |
|
|||
236 | // If we closed the tooltip, don't let CM or the global handlers |
|
|||
237 | // handle this event. |
|
|||
238 | event.stop(); |
|
|||
239 | return true; |
|
|||
240 | } |
|
|||
241 | if (that.code_mirror.options.keyMap === "vim-insert") { |
|
|||
242 | // vim keyMap is active and in insert mode. In this case we leave vim |
|
|||
243 | // insert mode, but remain in notebook edit mode. |
|
|||
244 | // Let' CM handle this event and prevent global handling. |
|
|||
245 | event.stop(); |
|
|||
246 | return false; |
|
|||
247 | } else { |
|
|||
248 | // vim keyMap is not active. Leave notebook edit mode. |
|
|||
249 | // Don't let CM handle the event, defer to global handling. |
|
|||
250 | return true; |
|
|||
251 | } |
|
|||
252 | } else if (event.which === keycodes.down && event.type === 'keydown') { |
|
|||
253 | // If we are not at the bottom, let CM handle the down arrow and |
|
|||
254 | // prevent the global keydown handler from handling it. |
|
|||
255 | if (!that.at_bottom()) { |
|
|||
256 | event.stop(); |
|
|||
257 | return false; |
|
|||
258 | } else { |
|
|||
259 | return true; |
|
|||
260 | } |
|
212 | } | |
|
213 | // If we closed the tooltip, don't let CM or the global handlers | |||
|
214 | // handle this event. | |||
|
215 | event.stop(); | |||
|
216 | return true; | |||
261 | } else if (event.keyCode === keycodes.tab && event.type === 'keydown' && event.shiftKey) { |
|
217 | } else if (event.keyCode === keycodes.tab && event.type === 'keydown' && event.shiftKey) { | |
262 | if (editor.somethingSelected()){ |
|
218 | if (editor.somethingSelected()){ | |
263 | var anchor = editor.getCursor("anchor"); |
|
219 | var anchor = editor.getCursor("anchor"); | |
@@ -285,12 +241,11 b' var IPython = (function (IPython) {' | |||||
285 | this.completer.startCompletion(); |
|
241 | this.completer.startCompletion(); | |
286 | return true; |
|
242 | return true; | |
287 | } |
|
243 | } | |
288 |
} |
|
244 | } | |
289 | // keypress/keyup also trigger on TAB press, and we don't want to |
|
245 | ||
290 | // use those to disable tab completion. |
|
246 | // keyboard event wasn't one of those unique to code cells, let's see | |
291 | return false; |
|
247 | // if it's one of the generic ones (i.e. check edit mode shortcuts) | |
292 | } |
|
248 | return IPython.Cell.prototype.handle_codemirror_keyevent.apply(this, [editor, event]); | |
293 | return false; |
|
|||
294 | }; |
|
249 | }; | |
295 |
|
250 | |||
296 | // Kernel related calls. |
|
251 | // Kernel related calls. | |
@@ -455,7 +410,7 b' var IPython = (function (IPython) {' | |||||
455 |
|
410 | |||
456 | CodeCell.input_prompt_classical = function (prompt_value, lines_number) { |
|
411 | CodeCell.input_prompt_classical = function (prompt_value, lines_number) { | |
457 | var ns; |
|
412 | var ns; | |
458 | if (prompt_value == undefined) { |
|
413 | if (prompt_value === undefined) { | |
459 | ns = " "; |
|
414 | ns = " "; | |
460 | } else { |
|
415 | } else { | |
461 | ns = encodeURIComponent(prompt_value); |
|
416 | ns = encodeURIComponent(prompt_value); | |
@@ -501,26 +456,6 b' var IPython = (function (IPython) {' | |||||
501 | }; |
|
456 | }; | |
502 |
|
457 | |||
503 |
|
458 | |||
504 | CodeCell.prototype.at_top = function () { |
|
|||
505 | var cursor = this.code_mirror.getCursor(); |
|
|||
506 | if (cursor.line === 0 && cursor.ch === 0) { |
|
|||
507 | return true; |
|
|||
508 | } else { |
|
|||
509 | return false; |
|
|||
510 | } |
|
|||
511 | }; |
|
|||
512 |
|
||||
513 |
|
||||
514 | CodeCell.prototype.at_bottom = function () { |
|
|||
515 | var cursor = this.code_mirror.getCursor(); |
|
|||
516 | if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) { |
|
|||
517 | return true; |
|
|||
518 | } else { |
|
|||
519 | return false; |
|
|||
520 | } |
|
|||
521 | }; |
|
|||
522 |
|
||||
523 |
|
||||
524 | CodeCell.prototype.clear_output = function (wait) { |
|
459 | CodeCell.prototype.clear_output = function (wait) { | |
525 | this.output_area.clear_output(wait); |
|
460 | this.output_area.clear_output(wait); | |
526 | this.set_input_prompt(); |
|
461 | this.set_input_prompt(); |
@@ -100,15 +100,21 b' var IPython = (function (IPython) {' | |||||
100 | help_index : '', |
|
100 | help_index : '', | |
101 | handler : function (event) { |
|
101 | handler : function (event) { | |
102 | var index = IPython.notebook.get_selected_index(); |
|
102 | var index = IPython.notebook.get_selected_index(); | |
103 | if (index !== null && index !== 0) { |
|
103 | var cell = IPython.notebook.get_cell(index); | |
104 | var cell = IPython.notebook.get_cell(index); |
|
104 | if (cell && cell.at_top() && index !== 0) { | |
105 | if (cell && cell.at_top()) { |
|
105 | event.preventDefault(); | |
106 | event.preventDefault(); |
|
106 | IPython.notebook.command_mode(); | |
107 |
|
|
107 | IPython.notebook.select_prev(); | |
108 |
|
|
108 | IPython.notebook.edit_mode(); | |
109 |
|
|
109 | var cm = IPython.notebook.get_selected_cell().code_mirror; | |
110 |
|
|
110 | cm.setCursor(cm.lastLine(), 0); | |
111 |
|
|
111 | return false; | |
|
112 | } else if (cell) { | |||
|
113 | var cm = cell.code_mirror; | |||
|
114 | var cursor = cm.getCursor(); | |||
|
115 | cursor.line -= 1; | |||
|
116 | cm.setCursor(cursor); | |||
|
117 | return false; | |||
112 | } |
|
118 | } | |
113 | } |
|
119 | } | |
114 | }, |
|
120 | }, | |
@@ -117,15 +123,21 b' var IPython = (function (IPython) {' | |||||
117 | help_index : '', |
|
123 | help_index : '', | |
118 | handler : function (event) { |
|
124 | handler : function (event) { | |
119 | var index = IPython.notebook.get_selected_index(); |
|
125 | var index = IPython.notebook.get_selected_index(); | |
120 |
|
|
126 | var cell = IPython.notebook.get_cell(index); | |
121 |
|
|
127 | if (cell.at_bottom() && index !== (IPython.notebook.ncells()-1)) { | |
122 | if (cell && cell.at_bottom()) { |
|
128 | event.preventDefault(); | |
123 | event.preventDefault(); |
|
129 | IPython.notebook.command_mode(); | |
124 |
|
|
130 | IPython.notebook.select_next(); | |
125 |
|
|
131 | IPython.notebook.edit_mode(); | |
126 |
|
|
132 | var cm = IPython.notebook.get_selected_cell().code_mirror; | |
127 |
|
|
133 | cm.setCursor(0, 0); | |
128 |
|
|
134 | return false; | |
|
135 | } else { | |||
|
136 | var cm = cell.code_mirror; | |||
|
137 | var cursor = cm.getCursor(); | |||
|
138 | cursor.line += 1; | |||
|
139 | cm.setCursor(cursor); | |||
|
140 | return false; | |||
129 | } |
|
141 | } | |
130 | } |
|
142 | } | |
131 | }, |
|
143 | }, |
@@ -113,68 +113,6 b' var IPython = (function (IPython) {' | |||||
113 | }); |
|
113 | }); | |
114 | }; |
|
114 | }; | |
115 |
|
115 | |||
116 | TextCell.prototype.handle_keyevent = function (editor, event) { |
|
|||
117 |
|
||||
118 | // console.log('CM', this.mode, event.which, event.type) |
|
|||
119 |
|
||||
120 | if (this.mode === 'command') { |
|
|||
121 | return true; |
|
|||
122 | } else if (this.mode === 'edit') { |
|
|||
123 | return this.handle_codemirror_keyevent(editor, event); |
|
|||
124 | } |
|
|||
125 | }; |
|
|||
126 |
|
||||
127 | /** |
|
|||
128 | * This method gets called in CodeMirror's onKeyDown/onKeyPress |
|
|||
129 | * handlers and is used to provide custom key handling. |
|
|||
130 | * |
|
|||
131 | * Subclass should override this method to have custom handeling |
|
|||
132 | * |
|
|||
133 | * @method handle_codemirror_keyevent |
|
|||
134 | * @param {CodeMirror} editor - The codemirror instance bound to the cell |
|
|||
135 | * @param {event} event - |
|
|||
136 | * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise |
|
|||
137 | */ |
|
|||
138 | TextCell.prototype.handle_codemirror_keyevent = function (editor, event) { |
|
|||
139 | var that = this; |
|
|||
140 |
|
||||
141 | if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey || event.altKey)) { |
|
|||
142 | // Always ignore shift-enter in CodeMirror as we handle it. |
|
|||
143 | return true; |
|
|||
144 | } else if (event.which === keycodes.up && event.type === 'keydown') { |
|
|||
145 | // If we are not at the top, let CM handle the up arrow and |
|
|||
146 | // prevent the global keydown handler from handling it. |
|
|||
147 | if (!that.at_top()) { |
|
|||
148 | event.stop(); |
|
|||
149 | return false; |
|
|||
150 | } else { |
|
|||
151 | return true; |
|
|||
152 | }; |
|
|||
153 | } else if (event.which === keycodes.down && event.type === 'keydown') { |
|
|||
154 | // If we are not at the bottom, let CM handle the down arrow and |
|
|||
155 | // prevent the global keydown handler from handling it. |
|
|||
156 | if (!that.at_bottom()) { |
|
|||
157 | event.stop(); |
|
|||
158 | return false; |
|
|||
159 | } else { |
|
|||
160 | return true; |
|
|||
161 | }; |
|
|||
162 | } else if (event.which === keycodes.esc && event.type === 'keydown') { |
|
|||
163 | if (that.code_mirror.options.keyMap === "vim-insert") { |
|
|||
164 | // vim keyMap is active and in insert mode. In this case we leave vim |
|
|||
165 | // insert mode, but remain in notebook edit mode. |
|
|||
166 | // Let' CM handle this event and prevent global handling. |
|
|||
167 | event.stop(); |
|
|||
168 | return false; |
|
|||
169 | } else { |
|
|||
170 | // vim keyMap is not active. Leave notebook edit mode. |
|
|||
171 | // Don't let CM handle the event, defer to global handling. |
|
|||
172 | return true; |
|
|||
173 | } |
|
|||
174 | } |
|
|||
175 | return false; |
|
|||
176 | }; |
|
|||
177 |
|
||||
178 | // Cell level actions |
|
116 | // Cell level actions | |
179 |
|
117 | |||
180 | TextCell.prototype.select = function () { |
|
118 | TextCell.prototype.select = function () { | |
@@ -242,39 +180,6 b' var IPython = (function (IPython) {' | |||||
242 | this.element.find('div.text_cell_render').html(text); |
|
180 | this.element.find('div.text_cell_render').html(text); | |
243 | }; |
|
181 | }; | |
244 |
|
182 | |||
245 | /** |
|
|||
246 | * @method at_top |
|
|||
247 | * @return {Boolean} |
|
|||
248 | */ |
|
|||
249 | TextCell.prototype.at_top = function () { |
|
|||
250 | if (this.rendered) { |
|
|||
251 | return true; |
|
|||
252 | } else { |
|
|||
253 | var cursor = this.code_mirror.getCursor(); |
|
|||
254 | if (cursor.line === 0 && cursor.ch === 0) { |
|
|||
255 | return true; |
|
|||
256 | } else { |
|
|||
257 | return false; |
|
|||
258 | } |
|
|||
259 | } |
|
|||
260 | }; |
|
|||
261 |
|
||||
262 | /** |
|
|||
263 | * @method at_bottom |
|
|||
264 | * @return {Boolean} |
|
|||
265 | * */ |
|
|||
266 | TextCell.prototype.at_bottom = function () { |
|
|||
267 | if (this.rendered) { |
|
|||
268 | return true; |
|
|||
269 | } else { |
|
|||
270 | var cursor = this.code_mirror.getCursor(); |
|
|||
271 | if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) { |
|
|||
272 | return true; |
|
|||
273 | } else { |
|
|||
274 | return false; |
|
|||
275 | } |
|
|||
276 | } |
|
|||
277 | }; |
|
|||
278 |
|
183 | |||
279 | /** |
|
184 | /** | |
280 | * Create Text cell from JSON |
|
185 | * Create Text cell from JSON |
General Comments 0
You need to be logged in to leave comments.
Login now