diff --git a/IPython/html/static/base/js/dialog.js b/IPython/html/static/base/js/dialog.js index 7fbcd7c..4ec8ec0 100644 --- a/IPython/html/static/base/js/dialog.js +++ b/IPython/html/static/base/js/dialog.js @@ -65,13 +65,16 @@ IPython.dialog = (function (IPython) { dialog.remove(); }); } - if (options.reselect_cell !== false) { - dialog.on("hidden", function () { - if (IPython.notebook) { - var cell = IPython.notebook.get_selected_cell(); - if (cell) cell.select(); - } - }); + dialog.on("hidden", function () { + if (IPython.notebook) { + var cell = IPython.notebook.get_selected_cell(); + if (cell) cell.select(); + IPython.keyboard_manager.command_mode(); + } + }); + + if (IPython.keyboard_manager) { + IPython.keyboard_manager.null_mode(); } return dialog.modal(options); diff --git a/IPython/html/static/notebook/js/codecell.js b/IPython/html/static/notebook/js/codecell.js index 164c72d..335e1ef 100644 --- a/IPython/html/static/notebook/js/codecell.js +++ b/IPython/html/static/notebook/js/codecell.js @@ -160,7 +160,7 @@ var IPython = (function (IPython) { var that = this; if (this.mode === 'command') { - return false + return true; } else if (this.mode === 'edit') { // whatever key is pressed, first, cancel the tooltip request before // they are sent, and remove tooltip if any, except for tab again diff --git a/IPython/html/static/notebook/js/completer.js b/IPython/html/static/notebook/js/completer.js index cfb2e90..c6dcba0 100644 --- a/IPython/html/static/notebook/js/completer.js +++ b/IPython/html/static/notebook/js/completer.js @@ -244,21 +244,28 @@ var IPython = (function (IPython) { //build the container var that = this; - this.sel.dblclick(function () { - that.pick(); - }); - this.sel.blur(this.close); - this.sel.keydown(function (event) { - that.keydown(event); - }); + // this.sel.dblclick(function () { + // that.pick(); + // }); + // this.sel.blur(this.close); + // this.sel.keydown(function (event) { + // that.keydown(event); + // }); this.build_gui_list(this.raw_result); - this.sel.focus(); - // Opera sometimes ignores focusing a freshly created node - if (window.opera) setTimeout(function () { - if (!this.done) this.sel.focus(); + setTimeout(function () { + console.log('doing it'); + that.sel.focus(); }, 100); + // this.sel.focus(); + // This needs to be after the focus() call because that puts the notebook into + // command mode. + // IPython.keyboard_manager.null_mode(); + // Opera sometimes ignores focusing a freshly created node + // if (window.opera) setTimeout(function () { + // if (!this.done) this.sel.focus(); + // }, 100); return true; } @@ -279,6 +286,8 @@ var IPython = (function (IPython) { if (this.done) return; this.done = true; $('.completions').remove(); + console.log('closing...') + IPython.keyboard_manager.edit_mode(); } Completer.prototype.pick = function () { @@ -292,6 +301,7 @@ var IPython = (function (IPython) { Completer.prototype.keydown = function (event) { + console.log('keydown', event.keyCode); var code = event.keyCode; var that = this; var special_key = false; diff --git a/IPython/html/static/notebook/js/keyboardmanager.js b/IPython/html/static/notebook/js/keyboardmanager.js new file mode 100644 index 0000000..4f54426 --- /dev/null +++ b/IPython/html/static/notebook/js/keyboardmanager.js @@ -0,0 +1,280 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2011 The IPython Development Team +// +// Distributed under the terms of the BSD License. The full license is in +// the file COPYING, distributed as part of this software. +//---------------------------------------------------------------------------- + +//============================================================================ +// Keyboard management +//============================================================================ + +var IPython = (function (IPython) { + "use strict"; + + var key = IPython.utils.keycodes; + + var KeyboardManager = function () { + this.mode = 'null'; + this.last_mode = 'null'; + this.bind_events(); + }; + + KeyboardManager.prototype.bind_events = function () { + var that = this; + $(document).keydown(function (event) { + return that.handle_keydown(event); + }); + }; + + KeyboardManager.prototype.handle_keydown = function (event) { + var notebook = IPython.notebook; + + console.log('keyboard_manager', this.mode, event); + + if (event.which === key.ESC) { + // Intercept escape at highest level to avoid closing + // websocket connection with firefox + event.preventDefault(); + } + + if (this.mode === 'null') { + return this.handle_edit_mode(event); + } + + // Event handlers for both command and edit mode + if ((event.ctrlKey || event.metaKey) && event.keyCode==83) { + // Save (CTRL+S) or (Command+S on Mac) + notebook.save_checkpoint(); + event.preventDefault(); + return false; + } else if (event.which === key.ESC) { + // Intercept escape at highest level to avoid closing + // websocket connection with firefox + event.preventDefault(); + // Don't return yet to allow edit/command modes to handle + } else if (event.which === key.SHIFT) { + // ignore shift keydown + return true; + } else if (event.which === key.ENTER && event.shiftKey) { + notebook.execute_selected_cell('shift'); + return false; + } else if (event.which === key.ENTER && event.altKey) { + // Execute code cell, and insert new in place + notebook.execute_selected_cell('alt'); + return false; + } else if (event.which === key.ENTER && event.ctrlKey) { + notebook.execute_selected_cell('ctrl'); + return false; + } + + if (this.mode === 'edit') { + return this.handle_edit_mode(event); + } else if (this.mode === 'command' && !(event.ctrlKey || event.altKey || event.metaKey)) { + return this.handle_command_mode(event); + } + } + + KeyboardManager.prototype.handle_null_mode = function (event) { + return true; + } + + + KeyboardManager.prototype.handle_edit_mode = function (event) { + var notebook = IPython.notebook; + + if (event.which === key.ESC) { + // ESC + notebook.command_mode(); + return false; + } else if (event.which === 77 && event.ctrlKey) { + // Ctrl-m + notebook.command_mode(); + return false; + } else if (event.which === key.UPARROW && !event.shiftKey) { + var cell = notebook.get_selected_cell(); + if (cell && cell.at_top()) { + event.preventDefault(); + notebook.command_mode() + notebook.select_prev(); + notebook.edit_mode(); + return false; + }; + } else if (event.which === key.DOWNARROW && !event.shiftKey) { + var cell = notebook.get_selected_cell(); + if (cell && cell.at_bottom()) { + event.preventDefault(); + notebook.command_mode() + notebook.select_next(); + notebook.edit_mode(); + return false; + }; + }; + return true; + } + + KeyboardManager.prototype.handle_command_mode = function (event) { + var notebook = IPython.notebook; + + if (event.which === key.ENTER && !(event.ctrlKey || event.altKey || event.shiftKey)) { + // Enter edit mode = ENTER alone + notebook.edit_mode(); + return false; + } else if (event.which === key.UPARROW && !event.shiftKey) { + var index = notebook.get_selected_index(); + if (index !== 0 && index !== null) { + notebook.select_prev(); + var cell = notebook.get_selected_cell(); + cell.focus_cell(); + }; + return false; + } else if (event.which === key.DOWNARROW && !event.shiftKey) { + var index = notebook.get_selected_index(); + if (index !== (notebook.ncells()-1) && index !== null) { + notebook.select_next(); + var cell = notebook.get_selected_cell(); + cell.focus_cell(); + }; + return false; + } else if (event.which === 88) { + // Cut selected cell = x + notebook.cut_cell(); + return false; + } else if (event.which === 67) { + // Copy selected cell = c + notebook.copy_cell(); + return false; + } else if (event.which === 86) { + // Paste below selected cell = v + notebook.paste_cell_below(); + return false; + } else if (event.which === 68) { + // Delete selected cell = d + notebook.delete_cell(); + return false; + } else if (event.which === 65) { + // Insert code cell above selected = a + notebook.insert_cell_above('code'); + notebook.select_prev(); + return false; + } else if (event.which === 66) { + // Insert code cell below selected = b + notebook.insert_cell_below('code'); + notebook.select_next(); + return false; + } else if (event.which === 89) { + // To code = y + notebook.to_code(); + return false; + } else if (event.which === 77) { + // To markdown = m + notebook.to_markdown(); + return false; + } else if (event.which === 84) { + // To Raw = t + notebook.to_raw(); + return false; + } else if (event.which === 49) { + // To Heading 1 = 1 + notebook.to_heading(undefined, 1); + return false; + } else if (event.which === 50) { + // To Heading 2 = 2 + notebook.to_heading(undefined, 2); + return false; + } else if (event.which === 51) { + // To Heading 3 = 3 + notebook.to_heading(undefined, 3); + return false; + } else if (event.which === 52) { + // To Heading 4 = 4 + notebook.to_heading(undefined, 4); + return false; + } else if (event.which === 53) { + // To Heading 5 = 5 + notebook.to_heading(undefined, 5); + return false; + } else if (event.which === 54) { + // To Heading 6 = 6 + notebook.to_heading(undefined, 6); + return false; + } else if (event.which === 79) { + // Toggle output = o + if (event.shiftKey) { + notebook.toggle_output_scroll(); + } else { + notebook.toggle_output(); + }; + return false; + } else if (event.which === 83) { + // Save notebook = s + notebook.save_checkpoint(); + return false; + } else if (event.which === 74) { + // Move cell down = j + notebook.move_cell_down(); + return false; + } else if (event.which === 75) { + // Move cell up = k + notebook.move_cell_up(); + return false; + } else if (event.which === 80) { + // Select previous = p + notebook.select_prev(); + return false; + } else if (event.which === 78) { + // Select next = n + notebook.select_next(); + return false; + } else if (event.which === 76) { + // Toggle line numbers = l + notebook.cell_toggle_line_numbers(); + return false; + } else if (event.which === 73) { + // Interrupt kernel = i + notebook.kernel.interrupt(); + return false; + } else if (event.which === 190) { + // Restart kernel = . # matches qt console + notebook.restart_kernel(); + return false; + } else if (event.which === 72) { + // Show keyboard shortcuts = h + IPython.quick_help.show_keyboard_shortcuts(); + return false; + } else if (event.which === 90) { + // Undo last cell delete = z + notebook.undelete(); + return false; + }; + // If we havn't handled it, let someone else. + return true; + }; + + KeyboardManager.prototype.edit_mode = function () { + this.last_mode = this.mode; + this.mode = 'edit'; + } + + KeyboardManager.prototype.command_mode = function () { + this.last_mode = this.mode; + this.mode = 'command'; + } + + KeyboardManager.prototype.null_mode = function () { + this.last_mode = this.mode; + this.mode = 'null'; + } + + KeyboardManager.prototype.last_mode = function () { + var lm = this.last_mode; + this.last_mode = this.mode; + this.mode = lm; + } + + + IPython.KeyboardManager = KeyboardManager; + + return IPython; + +}(IPython)); diff --git a/IPython/html/static/notebook/js/main.js b/IPython/html/static/notebook/js/main.js index e0ac198..0caeaec 100644 --- a/IPython/html/static/notebook/js/main.js +++ b/IPython/html/static/notebook/js/main.js @@ -62,6 +62,7 @@ function (marked) { IPython.quick_help = new IPython.QuickHelp(); IPython.login_widget = new IPython.LoginWidget('span#login_widget',{baseProjectUrl:baseProjectUrl}); IPython.notebook = new IPython.Notebook('div#notebook',{baseProjectUrl:baseProjectUrl, notebookPath:notebookPath, notebookName:notebookName}); + IPython.keyboard_manager = new IPython.KeyboardManager(); IPython.save_widget = new IPython.SaveWidget('span#save_widget'); IPython.menubar = new IPython.MenuBar('#menubar',{baseProjectUrl:baseProjectUrl, notebookPath: notebookPath}) IPython.toolbar = new IPython.MainToolBar('#maintoolbar-container') diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index 70aa2e9..8b4aa3f 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -13,7 +13,6 @@ var IPython = (function (IPython) { "use strict"; var utils = IPython.utils; - var key = IPython.utils.keycodes; /** * A notebook contains and manages cells. @@ -51,7 +50,6 @@ var IPython = (function (IPython) { this.minimum_autosave_interval = 120000; // single worksheet for now this.worksheet_metadata = {}; - this.control_key_active = false; this.notebook_name_blacklist_re = /[\/\\:]/; this.nbformat = 3 // Increment this when changing the nbformat this.nbformat_minor = 0 // Increment this when changing the nbformat @@ -94,7 +92,6 @@ var IPython = (function (IPython) { */ Notebook.prototype.create_elements = function () { var that = this; - // We need the notebook div to be focusable so it can watch for keyboard events. this.element.attr('tabindex','-1'); this.container = $("
").addClass("container").attr("id", "notebook-container"); // We add this end_space div to the end of the notebook div to: @@ -156,210 +153,6 @@ var IPython = (function (IPython) { }); }); - $(document).keydown(function (event) { - if (event.which === key.ESC) { - // Intercept escape at highest level to avoid closing - // websocket connection with firefox - event.preventDefault(); - } - }); - - this.element.keydown(function (event) { - // console.log(event); - - // Event handlers for both command and edit mode - if ((event.ctrlKey || event.metaKey) && event.keyCode==83) { - // Save (CTRL+S) or (Command+S on Mac) - that.save_checkpoint(); - event.preventDefault(); - return false; - } else if (event.which === key.ESC) { - // Intercept escape at highest level to avoid closing - // websocket connection with firefox - event.preventDefault(); - // Don't return yet to allow edit/command modes to handle - } else if (event.which === key.SHIFT) { - // ignore shift keydown - return true; - } else if (event.which === key.ENTER && event.shiftKey) { - that.execute_selected_cell('shift'); - return false; - } else if (event.which === key.ENTER && event.altKey) { - // Execute code cell, and insert new in place - that.execute_selected_cell('alt'); - return false; - } else if (event.which === key.ENTER && event.ctrlKey) { - that.execute_selected_cell('ctrl'); - return false; - } - - // Event handlers for edit mode - if (that.mode === 'edit') { - if (event.which === key.ESC) { - // ESC - that.command_mode(); - return false; - } else if (event.which === 77 && event.ctrlKey) { - // Ctrl-m - that.command_mode(); - return false; - } else if (event.which === key.UPARROW && !event.shiftKey) { - var cell = that.get_selected_cell(); - if (cell && cell.at_top()) { - event.preventDefault(); - that.command_mode() - that.select_prev(); - that.edit_mode(); - return false; - }; - } else if (event.which === key.DOWNARROW && !event.shiftKey) { - var cell = that.get_selected_cell(); - if (cell && cell.at_bottom()) { - event.preventDefault(); - that.command_mode() - that.select_next(); - that.edit_mode(); - return false; - }; - }; - // Event handlers for command mode - } else if (that.mode === 'command' && !(event.ctrlKey || event.altKey || event.metaKey)) { - if (event.which === key.ENTER && !(event.ctrlKey || event.altKey || event.shiftKey)) { - // Enter edit mode = ENTER alone - that.edit_mode(); - return false; - } else if (event.which === key.UPARROW && !event.shiftKey) { - var index = that.get_selected_index(); - if (index !== 0 && index !== null) { - that.select_prev(); - var cell = that.get_selected_cell(); - cell.focus_cell(); - }; - return false; - } else if (event.which === key.DOWNARROW && !event.shiftKey) { - var index = that.get_selected_index(); - if (index !== (that.ncells()-1) && index !== null) { - that.select_next(); - var cell = that.get_selected_cell(); - cell.focus_cell(); - }; - return false; - } else if (event.which === 88) { - // Cut selected cell = x - that.cut_cell(); - return false; - } else if (event.which === 67) { - // Copy selected cell = c - that.copy_cell(); - return false; - } else if (event.which === 86) { - // Paste below selected cell = v - that.paste_cell_below(); - return false; - } else if (event.which === 68) { - // Delete selected cell = d - that.delete_cell(); - return false; - } else if (event.which === 65) { - // Insert code cell above selected = a - that.insert_cell_above('code'); - that.select_prev(); - return false; - } else if (event.which === 66) { - // Insert code cell below selected = b - that.insert_cell_below('code'); - that.select_next(); - return false; - } else if (event.which === 89) { - // To code = y - that.to_code(); - return false; - } else if (event.which === 77) { - // To markdown = m - that.to_markdown(); - return false; - } else if (event.which === 84) { - // To Raw = t - that.to_raw(); - return false; - } else if (event.which === 49) { - // To Heading 1 = 1 - that.to_heading(undefined, 1); - return false; - } else if (event.which === 50) { - // To Heading 2 = 2 - that.to_heading(undefined, 2); - return false; - } else if (event.which === 51) { - // To Heading 3 = 3 - that.to_heading(undefined, 3); - return false; - } else if (event.which === 52) { - // To Heading 4 = 4 - that.to_heading(undefined, 4); - return false; - } else if (event.which === 53) { - // To Heading 5 = 5 - that.to_heading(undefined, 5); - return false; - } else if (event.which === 54) { - // To Heading 6 = 6 - that.to_heading(undefined, 6); - return false; - } else if (event.which === 79) { - // Toggle output = o - if (event.shiftKey) { - that.toggle_output_scroll(); - } else { - that.toggle_output(); - }; - return false; - } else if (event.which === 83) { - // Save notebook = s - that.save_checkpoint(); - return false; - } else if (event.which === 74) { - // Move cell down = j - that.move_cell_down(); - return false; - } else if (event.which === 75) { - // Move cell up = k - that.move_cell_up(); - return false; - } else if (event.which === 80) { - // Select previous = p - that.select_prev(); - return false; - } else if (event.which === 78) { - // Select next = n - that.select_next(); - return false; - } else if (event.which === 76) { - // Toggle line numbers = l - that.cell_toggle_line_numbers(); - return false; - } else if (event.which === 73) { - // Interrupt kernel = i - that.kernel.interrupt(); - return false; - } else if (event.which === 190) { - // Restart kernel = . # matches qt console - that.restart_kernel(); - return false; - } else if (event.which === 72) { - // Show keyboard shortcuts = h - IPython.quick_help.show_keyboard_shortcuts(); - return false; - } else if (event.which === 90) { - // Undo last cell delete = z - that.undelete(); - return false; - }; - }; - // If we havn't handled it, let someone else. - return true; - }); - var collapse_time = function (time) { var app_height = $('#ipython-main-app').height(); // content height var splitter_height = $('div#pager_splitter').outerHeight(true); @@ -735,6 +528,7 @@ var IPython = (function (IPython) { this.mode = 'command'; }; }; + IPython.keyboard_manager.command_mode(); }; Notebook.prototype.edit_mode = function () { @@ -747,6 +541,7 @@ var IPython = (function (IPython) { cell.edit_mode(); this.mode = 'edit'; }; + IPython.keyboard_manager.edit_mode(); }; }; diff --git a/IPython/html/templates/notebook.html b/IPython/html/templates/notebook.html index 84e8c37..8270856 100644 --- a/IPython/html/templates/notebook.html +++ b/IPython/html/templates/notebook.html @@ -291,6 +291,7 @@ class="notebook_app" +