Adding keyboard manager logic.

This is currently very broken.
This commit is contained in:
Brian E. Granger 2013-12-05 13:22:12 -08:00
parent c775800714
commit caffba142e
7 changed files with 316 additions and 226 deletions

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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));

View File

@ -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')

View File

@ -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 = $("<div/>").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();
};
};

View File

@ -291,6 +291,7 @@ class="notebook_app"
<script src="{{ static_url("notebook/js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("notebook/js/maintoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("notebook/js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("notebook/js/keyboardmanager.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("notebook/js/notificationwidget.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("notebook/js/notificationarea.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("notebook/js/tooltip.js") }}" type="text/javascript" charset="utf-8"></script>