##// END OF EJS Templates
Merge pull request #5296 from ivanov/more-shortcuts...
Min RK -
r15839:07be9dbb merge
parent child Browse files
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.up && event.type === 'keydown') {
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 } else {
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 IPython.notebook.command_mode();
107 IPython.notebook.select_prev();
108 IPython.notebook.select_prev();
108 IPython.notebook.edit_mode();
109 IPython.notebook.edit_mode();
109 var cm = IPython.notebook.get_selected_cell().code_mirror;
110 return false;
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 if (index !== null && index !== (IPython.notebook.ncells()-1)) {
126 var cell = IPython.notebook.get_cell(index);
121 var cell = IPython.notebook.get_cell(index);
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 IPython.notebook.command_mode();
130 IPython.notebook.select_next();
125 IPython.notebook.select_next();
131 IPython.notebook.edit_mode();
126 IPython.notebook.edit_mode();
132 var cm = IPython.notebook.get_selected_cell().code_mirror;
127 return false;
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