##// END OF EJS Templates
Adding keyboard manager logic....
Brian E. Granger -
Show More
@@ -0,0 +1,280 b''
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2011 The IPython Development Team
3 //
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
7
8 //============================================================================
9 // Keyboard management
10 //============================================================================
11
12 var IPython = (function (IPython) {
13 "use strict";
14
15 var key = IPython.utils.keycodes;
16
17 var KeyboardManager = function () {
18 this.mode = 'null';
19 this.last_mode = 'null';
20 this.bind_events();
21 };
22
23 KeyboardManager.prototype.bind_events = function () {
24 var that = this;
25 $(document).keydown(function (event) {
26 return that.handle_keydown(event);
27 });
28 };
29
30 KeyboardManager.prototype.handle_keydown = function (event) {
31 var notebook = IPython.notebook;
32
33 console.log('keyboard_manager', this.mode, event);
34
35 if (event.which === key.ESC) {
36 // Intercept escape at highest level to avoid closing
37 // websocket connection with firefox
38 event.preventDefault();
39 }
40
41 if (this.mode === 'null') {
42 return this.handle_edit_mode(event);
43 }
44
45 // Event handlers for both command and edit mode
46 if ((event.ctrlKey || event.metaKey) && event.keyCode==83) {
47 // Save (CTRL+S) or (Command+S on Mac)
48 notebook.save_checkpoint();
49 event.preventDefault();
50 return false;
51 } else if (event.which === key.ESC) {
52 // Intercept escape at highest level to avoid closing
53 // websocket connection with firefox
54 event.preventDefault();
55 // Don't return yet to allow edit/command modes to handle
56 } else if (event.which === key.SHIFT) {
57 // ignore shift keydown
58 return true;
59 } else if (event.which === key.ENTER && event.shiftKey) {
60 notebook.execute_selected_cell('shift');
61 return false;
62 } else if (event.which === key.ENTER && event.altKey) {
63 // Execute code cell, and insert new in place
64 notebook.execute_selected_cell('alt');
65 return false;
66 } else if (event.which === key.ENTER && event.ctrlKey) {
67 notebook.execute_selected_cell('ctrl');
68 return false;
69 }
70
71 if (this.mode === 'edit') {
72 return this.handle_edit_mode(event);
73 } else if (this.mode === 'command' && !(event.ctrlKey || event.altKey || event.metaKey)) {
74 return this.handle_command_mode(event);
75 }
76 }
77
78 KeyboardManager.prototype.handle_null_mode = function (event) {
79 return true;
80 }
81
82
83 KeyboardManager.prototype.handle_edit_mode = function (event) {
84 var notebook = IPython.notebook;
85
86 if (event.which === key.ESC) {
87 // ESC
88 notebook.command_mode();
89 return false;
90 } else if (event.which === 77 && event.ctrlKey) {
91 // Ctrl-m
92 notebook.command_mode();
93 return false;
94 } else if (event.which === key.UPARROW && !event.shiftKey) {
95 var cell = notebook.get_selected_cell();
96 if (cell && cell.at_top()) {
97 event.preventDefault();
98 notebook.command_mode()
99 notebook.select_prev();
100 notebook.edit_mode();
101 return false;
102 };
103 } else if (event.which === key.DOWNARROW && !event.shiftKey) {
104 var cell = notebook.get_selected_cell();
105 if (cell && cell.at_bottom()) {
106 event.preventDefault();
107 notebook.command_mode()
108 notebook.select_next();
109 notebook.edit_mode();
110 return false;
111 };
112 };
113 return true;
114 }
115
116 KeyboardManager.prototype.handle_command_mode = function (event) {
117 var notebook = IPython.notebook;
118
119 if (event.which === key.ENTER && !(event.ctrlKey || event.altKey || event.shiftKey)) {
120 // Enter edit mode = ENTER alone
121 notebook.edit_mode();
122 return false;
123 } else if (event.which === key.UPARROW && !event.shiftKey) {
124 var index = notebook.get_selected_index();
125 if (index !== 0 && index !== null) {
126 notebook.select_prev();
127 var cell = notebook.get_selected_cell();
128 cell.focus_cell();
129 };
130 return false;
131 } else if (event.which === key.DOWNARROW && !event.shiftKey) {
132 var index = notebook.get_selected_index();
133 if (index !== (notebook.ncells()-1) && index !== null) {
134 notebook.select_next();
135 var cell = notebook.get_selected_cell();
136 cell.focus_cell();
137 };
138 return false;
139 } else if (event.which === 88) {
140 // Cut selected cell = x
141 notebook.cut_cell();
142 return false;
143 } else if (event.which === 67) {
144 // Copy selected cell = c
145 notebook.copy_cell();
146 return false;
147 } else if (event.which === 86) {
148 // Paste below selected cell = v
149 notebook.paste_cell_below();
150 return false;
151 } else if (event.which === 68) {
152 // Delete selected cell = d
153 notebook.delete_cell();
154 return false;
155 } else if (event.which === 65) {
156 // Insert code cell above selected = a
157 notebook.insert_cell_above('code');
158 notebook.select_prev();
159 return false;
160 } else if (event.which === 66) {
161 // Insert code cell below selected = b
162 notebook.insert_cell_below('code');
163 notebook.select_next();
164 return false;
165 } else if (event.which === 89) {
166 // To code = y
167 notebook.to_code();
168 return false;
169 } else if (event.which === 77) {
170 // To markdown = m
171 notebook.to_markdown();
172 return false;
173 } else if (event.which === 84) {
174 // To Raw = t
175 notebook.to_raw();
176 return false;
177 } else if (event.which === 49) {
178 // To Heading 1 = 1
179 notebook.to_heading(undefined, 1);
180 return false;
181 } else if (event.which === 50) {
182 // To Heading 2 = 2
183 notebook.to_heading(undefined, 2);
184 return false;
185 } else if (event.which === 51) {
186 // To Heading 3 = 3
187 notebook.to_heading(undefined, 3);
188 return false;
189 } else if (event.which === 52) {
190 // To Heading 4 = 4
191 notebook.to_heading(undefined, 4);
192 return false;
193 } else if (event.which === 53) {
194 // To Heading 5 = 5
195 notebook.to_heading(undefined, 5);
196 return false;
197 } else if (event.which === 54) {
198 // To Heading 6 = 6
199 notebook.to_heading(undefined, 6);
200 return false;
201 } else if (event.which === 79) {
202 // Toggle output = o
203 if (event.shiftKey) {
204 notebook.toggle_output_scroll();
205 } else {
206 notebook.toggle_output();
207 };
208 return false;
209 } else if (event.which === 83) {
210 // Save notebook = s
211 notebook.save_checkpoint();
212 return false;
213 } else if (event.which === 74) {
214 // Move cell down = j
215 notebook.move_cell_down();
216 return false;
217 } else if (event.which === 75) {
218 // Move cell up = k
219 notebook.move_cell_up();
220 return false;
221 } else if (event.which === 80) {
222 // Select previous = p
223 notebook.select_prev();
224 return false;
225 } else if (event.which === 78) {
226 // Select next = n
227 notebook.select_next();
228 return false;
229 } else if (event.which === 76) {
230 // Toggle line numbers = l
231 notebook.cell_toggle_line_numbers();
232 return false;
233 } else if (event.which === 73) {
234 // Interrupt kernel = i
235 notebook.kernel.interrupt();
236 return false;
237 } else if (event.which === 190) {
238 // Restart kernel = . # matches qt console
239 notebook.restart_kernel();
240 return false;
241 } else if (event.which === 72) {
242 // Show keyboard shortcuts = h
243 IPython.quick_help.show_keyboard_shortcuts();
244 return false;
245 } else if (event.which === 90) {
246 // Undo last cell delete = z
247 notebook.undelete();
248 return false;
249 };
250 // If we havn't handled it, let someone else.
251 return true;
252 };
253
254 KeyboardManager.prototype.edit_mode = function () {
255 this.last_mode = this.mode;
256 this.mode = 'edit';
257 }
258
259 KeyboardManager.prototype.command_mode = function () {
260 this.last_mode = this.mode;
261 this.mode = 'command';
262 }
263
264 KeyboardManager.prototype.null_mode = function () {
265 this.last_mode = this.mode;
266 this.mode = 'null';
267 }
268
269 KeyboardManager.prototype.last_mode = function () {
270 var lm = this.last_mode;
271 this.last_mode = this.mode;
272 this.mode = lm;
273 }
274
275
276 IPython.KeyboardManager = KeyboardManager;
277
278 return IPython;
279
280 }(IPython));
@@ -65,13 +65,16 b' IPython.dialog = (function (IPython) {'
65 dialog.remove();
65 dialog.remove();
66 });
66 });
67 }
67 }
68 if (options.reselect_cell !== false) {
68 dialog.on("hidden", function () {
69 dialog.on("hidden", function () {
69 if (IPython.notebook) {
70 if (IPython.notebook) {
70 var cell = IPython.notebook.get_selected_cell();
71 var cell = IPython.notebook.get_selected_cell();
71 if (cell) cell.select();
72 if (cell) cell.select();
72 IPython.keyboard_manager.command_mode();
73 }
73 }
74 });
74 });
75
76 if (IPython.keyboard_manager) {
77 IPython.keyboard_manager.null_mode();
75 }
78 }
76
79
77 return dialog.modal(options);
80 return dialog.modal(options);
@@ -160,7 +160,7 b' var IPython = (function (IPython) {'
160 var that = this;
160 var that = this;
161
161
162 if (this.mode === 'command') {
162 if (this.mode === 'command') {
163 return false
163 return true;
164 } else if (this.mode === 'edit') {
164 } else if (this.mode === 'edit') {
165 // whatever key is pressed, first, cancel the tooltip request before
165 // whatever key is pressed, first, cancel the tooltip request before
166 // they are sent, and remove tooltip if any, except for tab again
166 // they are sent, and remove tooltip if any, except for tab again
@@ -244,21 +244,28 b' var IPython = (function (IPython) {'
244
244
245 //build the container
245 //build the container
246 var that = this;
246 var that = this;
247 this.sel.dblclick(function () {
247 // this.sel.dblclick(function () {
248 that.pick();
248 // that.pick();
249 });
249 // });
250 this.sel.blur(this.close);
250 // this.sel.blur(this.close);
251 this.sel.keydown(function (event) {
251 // this.sel.keydown(function (event) {
252 that.keydown(event);
252 // that.keydown(event);
253 });
253 // });
254
254
255 this.build_gui_list(this.raw_result);
255 this.build_gui_list(this.raw_result);
256
256
257 this.sel.focus();
257 setTimeout(function () {
258 // Opera sometimes ignores focusing a freshly created node
258 console.log('doing it');
259 if (window.opera) setTimeout(function () {
259 that.sel.focus();
260 if (!this.done) this.sel.focus();
261 }, 100);
260 }, 100);
261 // this.sel.focus();
262 // This needs to be after the focus() call because that puts the notebook into
263 // command mode.
264 // IPython.keyboard_manager.null_mode();
265 // Opera sometimes ignores focusing a freshly created node
266 // if (window.opera) setTimeout(function () {
267 // if (!this.done) this.sel.focus();
268 // }, 100);
262 return true;
269 return true;
263 }
270 }
264
271
@@ -279,6 +286,8 b' var IPython = (function (IPython) {'
279 if (this.done) return;
286 if (this.done) return;
280 this.done = true;
287 this.done = true;
281 $('.completions').remove();
288 $('.completions').remove();
289 console.log('closing...')
290 IPython.keyboard_manager.edit_mode();
282 }
291 }
283
292
284 Completer.prototype.pick = function () {
293 Completer.prototype.pick = function () {
@@ -292,6 +301,7 b' var IPython = (function (IPython) {'
292
301
293
302
294 Completer.prototype.keydown = function (event) {
303 Completer.prototype.keydown = function (event) {
304 console.log('keydown', event.keyCode);
295 var code = event.keyCode;
305 var code = event.keyCode;
296 var that = this;
306 var that = this;
297 var special_key = false;
307 var special_key = false;
@@ -62,6 +62,7 b' function (marked) {'
62 IPython.quick_help = new IPython.QuickHelp();
62 IPython.quick_help = new IPython.QuickHelp();
63 IPython.login_widget = new IPython.LoginWidget('span#login_widget',{baseProjectUrl:baseProjectUrl});
63 IPython.login_widget = new IPython.LoginWidget('span#login_widget',{baseProjectUrl:baseProjectUrl});
64 IPython.notebook = new IPython.Notebook('div#notebook',{baseProjectUrl:baseProjectUrl, notebookPath:notebookPath, notebookName:notebookName});
64 IPython.notebook = new IPython.Notebook('div#notebook',{baseProjectUrl:baseProjectUrl, notebookPath:notebookPath, notebookName:notebookName});
65 IPython.keyboard_manager = new IPython.KeyboardManager();
65 IPython.save_widget = new IPython.SaveWidget('span#save_widget');
66 IPython.save_widget = new IPython.SaveWidget('span#save_widget');
66 IPython.menubar = new IPython.MenuBar('#menubar',{baseProjectUrl:baseProjectUrl, notebookPath: notebookPath})
67 IPython.menubar = new IPython.MenuBar('#menubar',{baseProjectUrl:baseProjectUrl, notebookPath: notebookPath})
67 IPython.toolbar = new IPython.MainToolBar('#maintoolbar-container')
68 IPython.toolbar = new IPython.MainToolBar('#maintoolbar-container')
@@ -13,7 +13,6 b' var IPython = (function (IPython) {'
13 "use strict";
13 "use strict";
14
14
15 var utils = IPython.utils;
15 var utils = IPython.utils;
16 var key = IPython.utils.keycodes;
17
16
18 /**
17 /**
19 * A notebook contains and manages cells.
18 * A notebook contains and manages cells.
@@ -51,7 +50,6 b' var IPython = (function (IPython) {'
51 this.minimum_autosave_interval = 120000;
50 this.minimum_autosave_interval = 120000;
52 // single worksheet for now
51 // single worksheet for now
53 this.worksheet_metadata = {};
52 this.worksheet_metadata = {};
54 this.control_key_active = false;
55 this.notebook_name_blacklist_re = /[\/\\:]/;
53 this.notebook_name_blacklist_re = /[\/\\:]/;
56 this.nbformat = 3 // Increment this when changing the nbformat
54 this.nbformat = 3 // Increment this when changing the nbformat
57 this.nbformat_minor = 0 // Increment this when changing the nbformat
55 this.nbformat_minor = 0 // Increment this when changing the nbformat
@@ -94,7 +92,6 b' var IPython = (function (IPython) {'
94 */
92 */
95 Notebook.prototype.create_elements = function () {
93 Notebook.prototype.create_elements = function () {
96 var that = this;
94 var that = this;
97 // We need the notebook div to be focusable so it can watch for keyboard events.
98 this.element.attr('tabindex','-1');
95 this.element.attr('tabindex','-1');
99 this.container = $("<div/>").addClass("container").attr("id", "notebook-container");
96 this.container = $("<div/>").addClass("container").attr("id", "notebook-container");
100 // We add this end_space div to the end of the notebook div to:
97 // We add this end_space div to the end of the notebook div to:
@@ -156,210 +153,6 b' var IPython = (function (IPython) {'
156 });
153 });
157 });
154 });
158
155
159 $(document).keydown(function (event) {
160 if (event.which === key.ESC) {
161 // Intercept escape at highest level to avoid closing
162 // websocket connection with firefox
163 event.preventDefault();
164 }
165 });
166
167 this.element.keydown(function (event) {
168 // console.log(event);
169
170 // Event handlers for both command and edit mode
171 if ((event.ctrlKey || event.metaKey) && event.keyCode==83) {
172 // Save (CTRL+S) or (Command+S on Mac)
173 that.save_checkpoint();
174 event.preventDefault();
175 return false;
176 } else if (event.which === key.ESC) {
177 // Intercept escape at highest level to avoid closing
178 // websocket connection with firefox
179 event.preventDefault();
180 // Don't return yet to allow edit/command modes to handle
181 } else if (event.which === key.SHIFT) {
182 // ignore shift keydown
183 return true;
184 } else if (event.which === key.ENTER && event.shiftKey) {
185 that.execute_selected_cell('shift');
186 return false;
187 } else if (event.which === key.ENTER && event.altKey) {
188 // Execute code cell, and insert new in place
189 that.execute_selected_cell('alt');
190 return false;
191 } else if (event.which === key.ENTER && event.ctrlKey) {
192 that.execute_selected_cell('ctrl');
193 return false;
194 }
195
196 // Event handlers for edit mode
197 if (that.mode === 'edit') {
198 if (event.which === key.ESC) {
199 // ESC
200 that.command_mode();
201 return false;
202 } else if (event.which === 77 && event.ctrlKey) {
203 // Ctrl-m
204 that.command_mode();
205 return false;
206 } else if (event.which === key.UPARROW && !event.shiftKey) {
207 var cell = that.get_selected_cell();
208 if (cell && cell.at_top()) {
209 event.preventDefault();
210 that.command_mode()
211 that.select_prev();
212 that.edit_mode();
213 return false;
214 };
215 } else if (event.which === key.DOWNARROW && !event.shiftKey) {
216 var cell = that.get_selected_cell();
217 if (cell && cell.at_bottom()) {
218 event.preventDefault();
219 that.command_mode()
220 that.select_next();
221 that.edit_mode();
222 return false;
223 };
224 };
225 // Event handlers for command mode
226 } else if (that.mode === 'command' && !(event.ctrlKey || event.altKey || event.metaKey)) {
227 if (event.which === key.ENTER && !(event.ctrlKey || event.altKey || event.shiftKey)) {
228 // Enter edit mode = ENTER alone
229 that.edit_mode();
230 return false;
231 } else if (event.which === key.UPARROW && !event.shiftKey) {
232 var index = that.get_selected_index();
233 if (index !== 0 && index !== null) {
234 that.select_prev();
235 var cell = that.get_selected_cell();
236 cell.focus_cell();
237 };
238 return false;
239 } else if (event.which === key.DOWNARROW && !event.shiftKey) {
240 var index = that.get_selected_index();
241 if (index !== (that.ncells()-1) && index !== null) {
242 that.select_next();
243 var cell = that.get_selected_cell();
244 cell.focus_cell();
245 };
246 return false;
247 } else if (event.which === 88) {
248 // Cut selected cell = x
249 that.cut_cell();
250 return false;
251 } else if (event.which === 67) {
252 // Copy selected cell = c
253 that.copy_cell();
254 return false;
255 } else if (event.which === 86) {
256 // Paste below selected cell = v
257 that.paste_cell_below();
258 return false;
259 } else if (event.which === 68) {
260 // Delete selected cell = d
261 that.delete_cell();
262 return false;
263 } else if (event.which === 65) {
264 // Insert code cell above selected = a
265 that.insert_cell_above('code');
266 that.select_prev();
267 return false;
268 } else if (event.which === 66) {
269 // Insert code cell below selected = b
270 that.insert_cell_below('code');
271 that.select_next();
272 return false;
273 } else if (event.which === 89) {
274 // To code = y
275 that.to_code();
276 return false;
277 } else if (event.which === 77) {
278 // To markdown = m
279 that.to_markdown();
280 return false;
281 } else if (event.which === 84) {
282 // To Raw = t
283 that.to_raw();
284 return false;
285 } else if (event.which === 49) {
286 // To Heading 1 = 1
287 that.to_heading(undefined, 1);
288 return false;
289 } else if (event.which === 50) {
290 // To Heading 2 = 2
291 that.to_heading(undefined, 2);
292 return false;
293 } else if (event.which === 51) {
294 // To Heading 3 = 3
295 that.to_heading(undefined, 3);
296 return false;
297 } else if (event.which === 52) {
298 // To Heading 4 = 4
299 that.to_heading(undefined, 4);
300 return false;
301 } else if (event.which === 53) {
302 // To Heading 5 = 5
303 that.to_heading(undefined, 5);
304 return false;
305 } else if (event.which === 54) {
306 // To Heading 6 = 6
307 that.to_heading(undefined, 6);
308 return false;
309 } else if (event.which === 79) {
310 // Toggle output = o
311 if (event.shiftKey) {
312 that.toggle_output_scroll();
313 } else {
314 that.toggle_output();
315 };
316 return false;
317 } else if (event.which === 83) {
318 // Save notebook = s
319 that.save_checkpoint();
320 return false;
321 } else if (event.which === 74) {
322 // Move cell down = j
323 that.move_cell_down();
324 return false;
325 } else if (event.which === 75) {
326 // Move cell up = k
327 that.move_cell_up();
328 return false;
329 } else if (event.which === 80) {
330 // Select previous = p
331 that.select_prev();
332 return false;
333 } else if (event.which === 78) {
334 // Select next = n
335 that.select_next();
336 return false;
337 } else if (event.which === 76) {
338 // Toggle line numbers = l
339 that.cell_toggle_line_numbers();
340 return false;
341 } else if (event.which === 73) {
342 // Interrupt kernel = i
343 that.kernel.interrupt();
344 return false;
345 } else if (event.which === 190) {
346 // Restart kernel = . # matches qt console
347 that.restart_kernel();
348 return false;
349 } else if (event.which === 72) {
350 // Show keyboard shortcuts = h
351 IPython.quick_help.show_keyboard_shortcuts();
352 return false;
353 } else if (event.which === 90) {
354 // Undo last cell delete = z
355 that.undelete();
356 return false;
357 };
358 };
359 // If we havn't handled it, let someone else.
360 return true;
361 });
362
363 var collapse_time = function (time) {
156 var collapse_time = function (time) {
364 var app_height = $('#ipython-main-app').height(); // content height
157 var app_height = $('#ipython-main-app').height(); // content height
365 var splitter_height = $('div#pager_splitter').outerHeight(true);
158 var splitter_height = $('div#pager_splitter').outerHeight(true);
@@ -735,6 +528,7 b' var IPython = (function (IPython) {'
735 this.mode = 'command';
528 this.mode = 'command';
736 };
529 };
737 };
530 };
531 IPython.keyboard_manager.command_mode();
738 };
532 };
739
533
740 Notebook.prototype.edit_mode = function () {
534 Notebook.prototype.edit_mode = function () {
@@ -747,6 +541,7 b' var IPython = (function (IPython) {'
747 cell.edit_mode();
541 cell.edit_mode();
748 this.mode = 'edit';
542 this.mode = 'edit';
749 };
543 };
544 IPython.keyboard_manager.edit_mode();
750 };
545 };
751 };
546 };
752
547
@@ -291,6 +291,7 b' class="notebook_app"'
291 <script src="{{ static_url("notebook/js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
291 <script src="{{ static_url("notebook/js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
292 <script src="{{ static_url("notebook/js/maintoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
292 <script src="{{ static_url("notebook/js/maintoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
293 <script src="{{ static_url("notebook/js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
293 <script src="{{ static_url("notebook/js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
294 <script src="{{ static_url("notebook/js/keyboardmanager.js") }}" type="text/javascript" charset="utf-8"></script>
294 <script src="{{ static_url("notebook/js/notificationwidget.js") }}" type="text/javascript" charset="utf-8"></script>
295 <script src="{{ static_url("notebook/js/notificationwidget.js") }}" type="text/javascript" charset="utf-8"></script>
295 <script src="{{ static_url("notebook/js/notificationarea.js") }}" type="text/javascript" charset="utf-8"></script>
296 <script src="{{ static_url("notebook/js/notificationarea.js") }}" type="text/javascript" charset="utf-8"></script>
296 <script src="{{ static_url("notebook/js/tooltip.js") }}" type="text/javascript" charset="utf-8"></script>
297 <script src="{{ static_url("notebook/js/tooltip.js") }}" type="text/javascript" charset="utf-8"></script>
General Comments 0
You need to be logged in to leave comments. Login now