mirror of
https://github.com/jupyter/notebook.git
synced 2025-03-19 13:20:36 +08:00
Merge pull request #6668 from Carreau/actions
Add notion of action to keyboard manager.
This commit is contained in:
commit
5db4b7a8ee
@ -12,18 +12,22 @@ define([
|
||||
'base/js/namespace',
|
||||
'jquery',
|
||||
'base/js/utils',
|
||||
], function(IPython, $, utils) {
|
||||
'underscore',
|
||||
], function(IPython, $, utils, _) {
|
||||
"use strict";
|
||||
|
||||
|
||||
// Setup global keycodes and inverse keycodes.
|
||||
/**
|
||||
* Setup global keycodes and inverse keycodes.
|
||||
*
|
||||
* See http://unixpapa.com/js/key.html for a complete description. The short of
|
||||
* it is that there are different keycode sets. Firefox uses the "Mozilla keycodes"
|
||||
* and Webkit/IE use the "IE keycodes". These keycode sets are mostly the same
|
||||
* but have minor differences.
|
||||
**/
|
||||
|
||||
// See http://unixpapa.com/js/key.html for a complete description. The short of
|
||||
// it is that there are different keycode sets. Firefox uses the "Mozilla keycodes"
|
||||
// and Webkit/IE use the "IE keycodes". These keycode sets are mostly the same
|
||||
// but have minor differences.
|
||||
|
||||
// These apply to Firefox, (Webkit and IE)
|
||||
// These apply to Firefox, (Webkit and IE)
|
||||
// This does work **only** on US keyboard.
|
||||
var _keycodes = {
|
||||
'a': 65, 'b': 66, 'c': 67, 'd': 68, 'e': 69, 'f': 70, 'g': 71, 'h': 72, 'i': 73,
|
||||
'j': 74, 'k': 75, 'l': 76, 'm': 77, 'n': 78, 'o': 79, 'p': 80, 'q': 81, 'r': 82,
|
||||
@ -84,13 +88,32 @@ define([
|
||||
};
|
||||
|
||||
var normalize_shortcut = function (shortcut) {
|
||||
// Put a shortcut into normalized form:
|
||||
// 1. Make lowercase
|
||||
// 2. Replace cmd by meta
|
||||
// 3. Sort '-' separated modifiers into the order alt-ctrl-meta-shift
|
||||
// 4. Normalize keys
|
||||
/**
|
||||
* @function _normalize_shortcut
|
||||
* @private
|
||||
* return a dict containing the normalized shortcut and the number of time it should be pressed:
|
||||
*
|
||||
* Put a shortcut into normalized form:
|
||||
* 1. Make lowercase
|
||||
* 2. Replace cmd by meta
|
||||
* 3. Sort '-' separated modifiers into the order alt-ctrl-meta-shift
|
||||
* 4. Normalize keys
|
||||
**/
|
||||
if (platform === 'MacOS') {
|
||||
shortcut = shortcut.toLowerCase().replace('cmdtrl-', 'cmd-');
|
||||
} else {
|
||||
shortcut = shortcut.toLowerCase().replace('cmdtrl-', 'ctrl-');
|
||||
}
|
||||
|
||||
shortcut = shortcut.toLowerCase().replace('cmd', 'meta');
|
||||
shortcut = shortcut.replace(/-$/, '_'); // catch shortcuts using '-' key
|
||||
shortcut = shortcut.replace(/,$/, 'comma'); // catch shortcuts using '-' key
|
||||
if(shortcut.indexOf(',') !== -1){
|
||||
var sht = shortcut.split(',');
|
||||
sht = _.map(sht, normalize_shortcut);
|
||||
return shortcut;
|
||||
}
|
||||
shortcut = shortcut.replace(/comma/g, ','); // catch shortcuts using '-' key
|
||||
var values = shortcut.split("-");
|
||||
if (values.length === 1) {
|
||||
return normalize_key(values[0]);
|
||||
@ -103,7 +126,9 @@ define([
|
||||
};
|
||||
|
||||
var shortcut_to_event = function (shortcut, type) {
|
||||
// Convert a shortcut (shift-r) to a jQuery Event object
|
||||
/**
|
||||
* Convert a shortcut (shift-r) to a jQuery Event object
|
||||
**/
|
||||
type = type || 'keydown';
|
||||
shortcut = normalize_shortcut(shortcut);
|
||||
shortcut = shortcut.replace(/-$/, '_'); // catch shortcuts using '-' key
|
||||
@ -118,8 +143,21 @@ define([
|
||||
return $.Event(type, opts);
|
||||
};
|
||||
|
||||
var only_modifier_event = function(event){
|
||||
/**
|
||||
* Return `true` if the event only contains modifiers keys.
|
||||
* false otherwise
|
||||
**/
|
||||
var key = inv_keycodes[event.which];
|
||||
return ((event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) &&
|
||||
(key === 'alt'|| key === 'ctrl'|| key === 'meta'|| key === 'shift'));
|
||||
|
||||
};
|
||||
|
||||
var event_to_shortcut = function (event) {
|
||||
// Convert a jQuery Event object to a shortcut (shift-r)
|
||||
/**
|
||||
* Convert a jQuery Event object to a normalized shortcut string (shift-r)
|
||||
**/
|
||||
var shortcut = '';
|
||||
var key = inv_keycodes[event.which];
|
||||
if (event.altKey && key !== 'alt') {shortcut += 'alt-';}
|
||||
@ -132,7 +170,7 @@ define([
|
||||
|
||||
// Shortcut manager class
|
||||
|
||||
var ShortcutManager = function (delay, events) {
|
||||
var ShortcutManager = function (delay, events, actions, env) {
|
||||
/**
|
||||
* A class to deal with keyboard event and shortcut
|
||||
*
|
||||
@ -140,33 +178,78 @@ define([
|
||||
* @constructor
|
||||
*/
|
||||
this._shortcuts = {};
|
||||
this._counts = {};
|
||||
this._timers = {};
|
||||
this.delay = delay || 800; // delay in milliseconds
|
||||
this.events = events;
|
||||
this.actions = actions;
|
||||
this.actions.extend_env(env);
|
||||
this._queue = [];
|
||||
this._cleartimeout = null;
|
||||
Object.seal(this);
|
||||
};
|
||||
|
||||
ShortcutManager.prototype.clearsoon = function(){
|
||||
/**
|
||||
* Clear the pending shortcut soon, and cancel previous clearing
|
||||
* that might be registered.
|
||||
**/
|
||||
var that = this;
|
||||
clearTimeout(this._cleartimeout);
|
||||
this._cleartimeout = setTimeout(function(){that.clearqueue();}, this.delay);
|
||||
};
|
||||
|
||||
|
||||
ShortcutManager.prototype.clearqueue = function(){
|
||||
/**
|
||||
* clear the pending shortcut sequence now.
|
||||
**/
|
||||
this._queue = [];
|
||||
clearTimeout(this._cleartimeout);
|
||||
};
|
||||
|
||||
|
||||
var flatten_shorttree = function(tree){
|
||||
/**
|
||||
* Flatten a tree of shortcut sequences.
|
||||
* use full to iterate over all the key/values of available shortcuts.
|
||||
**/
|
||||
var dct = {};
|
||||
for(var key in tree){
|
||||
var value = tree[key];
|
||||
if(typeof(value) === 'string'){
|
||||
dct[key] = value;
|
||||
} else {
|
||||
var ftree=flatten_shorttree(value);
|
||||
for(var subkey in ftree){
|
||||
dct[key+','+subkey] = ftree[subkey];
|
||||
}
|
||||
}
|
||||
}
|
||||
return dct;
|
||||
};
|
||||
|
||||
ShortcutManager.prototype.help = function () {
|
||||
var help = [];
|
||||
for (var shortcut in this._shortcuts) {
|
||||
var help_string = this._shortcuts[shortcut].help;
|
||||
var help_index = this._shortcuts[shortcut].help_index;
|
||||
var ftree = flatten_shorttree(this._shortcuts);
|
||||
for (var shortcut in ftree) {
|
||||
var action = this.actions.get(ftree[shortcut]);
|
||||
var help_string = action.help||'== no help ==';
|
||||
var help_index = action.help_index;
|
||||
if (help_string) {
|
||||
if (platform === 'MacOS') {
|
||||
shortcut = shortcut.replace('meta', 'cmd');
|
||||
}
|
||||
var shortstring = (action.shortstring||shortcut);
|
||||
help.push({
|
||||
shortcut: shortcut,
|
||||
shortcut: shortstring,
|
||||
help: help_string,
|
||||
help_index: help_index}
|
||||
);
|
||||
}
|
||||
}
|
||||
help.sort(function (a, b) {
|
||||
if (a.help_index > b.help_index)
|
||||
if (a.help_index > b.help_index){
|
||||
return 1;
|
||||
if (a.help_index < b.help_index)
|
||||
}
|
||||
if (a.help_index < b.help_index){
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
return help;
|
||||
@ -176,19 +259,105 @@ define([
|
||||
this._shortcuts = {};
|
||||
};
|
||||
|
||||
ShortcutManager.prototype.get_shortcut = function (shortcut){
|
||||
/**
|
||||
* return a node of the shortcut tree which an action name (string) if leaf,
|
||||
* and an object with `object.subtree===true`
|
||||
**/
|
||||
if(typeof(shortcut) === 'string'){
|
||||
shortcut = shortcut.split(',');
|
||||
}
|
||||
|
||||
return this._get_leaf(shortcut, this._shortcuts);
|
||||
};
|
||||
|
||||
|
||||
ShortcutManager.prototype._get_leaf = function(shortcut_array, tree){
|
||||
/**
|
||||
* @private
|
||||
* find a leaf/node in a subtree of the keyboard shortcut
|
||||
*
|
||||
**/
|
||||
if(shortcut_array.length === 1){
|
||||
return tree[shortcut_array[0]];
|
||||
} else if( typeof(tree[shortcut_array[0]]) !== 'string'){
|
||||
return this._get_leaf(shortcut_array.slice(1), tree[shortcut_array[0]]);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
ShortcutManager.prototype.set_shortcut = function( shortcut, action_name){
|
||||
if( typeof(action_name) !== 'string'){ throw('action is not a string', action_name);}
|
||||
if( typeof(shortcut) === 'string'){
|
||||
shortcut = shortcut.split(',');
|
||||
}
|
||||
return this._set_leaf(shortcut, action_name, this._shortcuts);
|
||||
};
|
||||
|
||||
ShortcutManager.prototype._is_leaf = function(shortcut_array, tree){
|
||||
if(shortcut_array.length === 1){
|
||||
return(typeof(tree[shortcut_array[0]]) === 'string');
|
||||
} else {
|
||||
var subtree = tree[shortcut_array[0]];
|
||||
return this._is_leaf(shortcut_array.slice(1), subtree );
|
||||
}
|
||||
};
|
||||
|
||||
ShortcutManager.prototype._remove_leaf = function(shortcut_array, tree, allow_node){
|
||||
if(shortcut_array.length === 1){
|
||||
var current_node = tree[shortcut_array[0]];
|
||||
if(typeof(current_node) === 'string'){
|
||||
delete tree[shortcut_array[0]];
|
||||
} else {
|
||||
throw('try to delete non-leaf');
|
||||
}
|
||||
} else {
|
||||
this._remove_leaf(shortcut_array.slice(1), tree[shortcut_array[0]], allow_node);
|
||||
if(_.keys(tree[shortcut_array[0]]).length === 0){
|
||||
delete tree[shortcut_array[0]];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ShortcutManager.prototype._set_leaf = function(shortcut_array, action_name, tree){
|
||||
var current_node = tree[shortcut_array[0]];
|
||||
if(shortcut_array.length === 1){
|
||||
if(current_node !== undefined && typeof(current_node) !== 'string'){
|
||||
console.warn('[warning], you are overriting a long shortcut with a shorter one');
|
||||
}
|
||||
tree[shortcut_array[0]] = action_name;
|
||||
return true;
|
||||
} else {
|
||||
if(typeof(current_node) === 'string'){
|
||||
console.warn('you are trying to set a shortcut that will be shadowed'+
|
||||
'by a more specific one. Aborting for :', action_name, 'the follwing '+
|
||||
'will take precedence', current_node);
|
||||
return false;
|
||||
} else {
|
||||
tree[shortcut_array[0]] = tree[shortcut_array[0]]||{};
|
||||
}
|
||||
this._set_leaf(shortcut_array.slice(1), action_name, tree[shortcut_array[0]]);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
ShortcutManager.prototype.add_shortcut = function (shortcut, data, suppress_help_update) {
|
||||
if (typeof(data) === 'function') {
|
||||
data = {help: '', help_index: '', handler: data};
|
||||
}
|
||||
data.help_index = data.help_index || '';
|
||||
data.help = data.help || '';
|
||||
data.count = data.count || 1;
|
||||
if (data.help_index === '') {
|
||||
data.help_index = 'zz';
|
||||
/**
|
||||
* Add a action to be handled by shortcut manager.
|
||||
*
|
||||
* - `shortcut` should be a `Shortcut Sequence` of the for `Ctrl-Alt-C,Meta-X`...
|
||||
* - `data` could be an `action name`, an `action` or a `function`.
|
||||
* if a `function` is passed it will be converted to an anonymous `action`.
|
||||
*
|
||||
**/
|
||||
var action_name = this.actions.get_name(data);
|
||||
if (! action_name){
|
||||
throw('does nto know how to deal with ', data);
|
||||
}
|
||||
|
||||
shortcut = normalize_shortcut(shortcut);
|
||||
this._counts[shortcut] = 0;
|
||||
this._shortcuts[shortcut] = data;
|
||||
this.set_shortcut(shortcut, action_name);
|
||||
|
||||
if (!suppress_help_update) {
|
||||
// update the keyboard shortcuts notebook help
|
||||
this.events.trigger('rebuild.QuickHelp');
|
||||
@ -196,6 +365,11 @@ define([
|
||||
};
|
||||
|
||||
ShortcutManager.prototype.add_shortcuts = function (data) {
|
||||
/**
|
||||
* Convenient methods to call `add_shortcut(key, value)` on several items
|
||||
*
|
||||
* data : Dict of the form {key:value, ...}
|
||||
**/
|
||||
for (var shortcut in data) {
|
||||
this.add_shortcut(shortcut, data[shortcut], true);
|
||||
}
|
||||
@ -204,44 +378,22 @@ define([
|
||||
};
|
||||
|
||||
ShortcutManager.prototype.remove_shortcut = function (shortcut, suppress_help_update) {
|
||||
/**
|
||||
* Remove the binding of shortcut `sortcut` with its action.
|
||||
* throw an error if trying to remove a non-exiting shortcut
|
||||
**/
|
||||
shortcut = normalize_shortcut(shortcut);
|
||||
delete this._counts[shortcut];
|
||||
delete this._shortcuts[shortcut];
|
||||
if( typeof(shortcut) === 'string'){
|
||||
shortcut = shortcut.split(',');
|
||||
}
|
||||
this._remove_leaf(shortcut, this._shortcuts);
|
||||
if (!suppress_help_update) {
|
||||
// update the keyboard shortcuts notebook help
|
||||
this.events.trigger('rebuild.QuickHelp');
|
||||
}
|
||||
};
|
||||
|
||||
ShortcutManager.prototype.count_handler = function (shortcut, event, data) {
|
||||
/**
|
||||
* Seem to allow to call an handler only after several key press.
|
||||
* like, I suppose `dd` that delete the current cell only after
|
||||
* `d` has been pressed twice..
|
||||
* @method count_handler
|
||||
* @return {Boolean} `true|false`, whether or not the event has been handled.
|
||||
* @param shortcut {shortcut}
|
||||
* @param event {event}
|
||||
* @param data {data}
|
||||
*/
|
||||
var that = this;
|
||||
var c = this._counts;
|
||||
var t = this._timers;
|
||||
var timer = null;
|
||||
if (c[shortcut] === data.count-1) {
|
||||
c[shortcut] = 0;
|
||||
timer = t[shortcut];
|
||||
if (timer) {clearTimeout(timer); delete t[shortcut];}
|
||||
return data.handler(event);
|
||||
} else {
|
||||
c[shortcut] = c[shortcut] + 1;
|
||||
timer = setTimeout(function () {
|
||||
c[shortcut] = 0;
|
||||
}, that.delay);
|
||||
t[shortcut] = timer;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
ShortcutManager.prototype.call_handler = function (event) {
|
||||
/**
|
||||
@ -249,26 +401,40 @@ define([
|
||||
* @method call_handler
|
||||
* @return {Boolean} `true|false`, `false` if no handler was found, otherwise the value return by the handler.
|
||||
* @param event {event}
|
||||
*/
|
||||
var shortcut = event_to_shortcut(event);
|
||||
var data = this._shortcuts[shortcut];
|
||||
if (data) {
|
||||
var handler = data.handler;
|
||||
if (handler) {
|
||||
if (data.count === 1) {
|
||||
return handler(event);
|
||||
} else if (data.count > 1) {
|
||||
return this.count_handler(shortcut, event, data);
|
||||
}
|
||||
}
|
||||
*
|
||||
* given an event, call the corresponding shortcut.
|
||||
* return false is event wan handled, true otherwise
|
||||
* in any case returning false stop event propagation
|
||||
**/
|
||||
|
||||
|
||||
this.clearsoon();
|
||||
if(only_modifier_event(event)){
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
var shortcut = event_to_shortcut(event);
|
||||
this._queue.push(shortcut);
|
||||
var action_name = this.get_shortcut(this._queue);
|
||||
|
||||
if (typeof(action_name) === 'undefined'|| action_name === null){
|
||||
this.clearqueue();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.actions.exists(action_name)) {
|
||||
event.preventDefault();
|
||||
this.clearqueue();
|
||||
return this.actions.call(action_name, event);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
ShortcutManager.prototype.handles = function (event) {
|
||||
var shortcut = event_to_shortcut(event);
|
||||
var data = this._shortcuts[shortcut];
|
||||
return !( data === undefined || data.handler === undefined );
|
||||
var action_name = this.get_shortcut(this._queue.concat(shortcut));
|
||||
return (typeof(action_name) !== 'undefined');
|
||||
};
|
||||
|
||||
var keyboard = {
|
||||
@ -278,7 +444,7 @@ define([
|
||||
normalize_key : normalize_key,
|
||||
normalize_shortcut : normalize_shortcut,
|
||||
shortcut_to_event : shortcut_to_event,
|
||||
event_to_shortcut : event_to_shortcut
|
||||
event_to_shortcut : event_to_shortcut,
|
||||
};
|
||||
|
||||
// For backwards compatibility.
|
||||
|
503
IPython/html/static/notebook/js/actions.js
Normal file
503
IPython/html/static/notebook/js/actions.js
Normal file
@ -0,0 +1,503 @@
|
||||
// Copyright (c) IPython Development Team.
|
||||
// Distributed under the terms of the Modified BSD License.
|
||||
|
||||
define(['require'
|
||||
], function(require) {
|
||||
"use strict";
|
||||
|
||||
var ActionHandler = function (env) {
|
||||
this.env = env || {};
|
||||
Object.seal(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* A bunch of predefined `Simple Actions` used by IPython.
|
||||
* `Simple Actions` have the following keys:
|
||||
* help (optional): a short string the describe the action.
|
||||
* will be used in various context, like as menu name, tool tips on buttons,
|
||||
* and short description in help menu.
|
||||
* help_index (optional): a string used to sort action in help menu.
|
||||
* icon (optional): a short string that represent the icon that have to be used with this
|
||||
* action. this should mainly correspond to a Font_awesome class.
|
||||
* handler : a function which is called when the action is activated. It will receive at first parameter
|
||||
* a dictionary containing various handle to element of the notebook.
|
||||
*
|
||||
* action need to be registered with a **name** that can be use to refer to this action.
|
||||
*
|
||||
*
|
||||
* if `help` is not provided it will be derived by replacing any dash by space
|
||||
* in the **name** of the action. It is advised to provide a prefix to action name to
|
||||
* avoid conflict the prefix should be all lowercase and end with a dot `.`
|
||||
* in the absence of a prefix the behavior of the action is undefined.
|
||||
*
|
||||
* All action provided by IPython are prefixed with `ipython.`.
|
||||
*
|
||||
* One can register extra actions or replace an existing action with another one is possible
|
||||
* but is considered undefined behavior.
|
||||
*
|
||||
**/
|
||||
var _action = {
|
||||
'run-select-next': {
|
||||
icon: 'fa-play',
|
||||
help : 'run cell, select below',
|
||||
help_index : 'ba',
|
||||
handler : function (env) {
|
||||
env.notebook.execute_cell_and_select_below();
|
||||
}
|
||||
},
|
||||
'execute-in-place':{
|
||||
help : 'run cell',
|
||||
help_index : 'bb',
|
||||
handler : function (env) {
|
||||
env.notebook.execute_cell();
|
||||
}
|
||||
},
|
||||
'execute-and-insert-after':{
|
||||
help : 'run cell, insert below',
|
||||
help_index : 'bc',
|
||||
handler : function (env) {
|
||||
env.notebook.execute_cell_and_insert_below();
|
||||
}
|
||||
},
|
||||
'go-to-command-mode': {
|
||||
help : 'command mode',
|
||||
help_index : 'aa',
|
||||
handler : function (env) {
|
||||
env.notebook.command_mode();
|
||||
}
|
||||
},
|
||||
'split-cell-at-cursor': {
|
||||
help : 'split cell',
|
||||
help_index : 'ea',
|
||||
handler : function (env) {
|
||||
env.notebook.split_cell();
|
||||
}
|
||||
},
|
||||
'enter-edit-mode' : {
|
||||
help_index : 'aa',
|
||||
handler : function (env) {
|
||||
env.notebook.edit_mode();
|
||||
}
|
||||
},
|
||||
'select-previous-cell' : {
|
||||
help_index : 'da',
|
||||
handler : function (env) {
|
||||
var index = env.notebook.get_selected_index();
|
||||
if (index !== 0 && index !== null) {
|
||||
env.notebook.select_prev();
|
||||
env.notebook.focus_cell();
|
||||
}
|
||||
}
|
||||
},
|
||||
'select-next-cell' : {
|
||||
help_index : 'db',
|
||||
handler : function (env) {
|
||||
var index = env.notebook.get_selected_index();
|
||||
if (index !== (env.notebook.ncells()-1) && index !== null) {
|
||||
env.notebook.select_next();
|
||||
env.notebook.focus_cell();
|
||||
}
|
||||
}
|
||||
},
|
||||
'cut-selected-cell' : {
|
||||
icon: 'fa-cut',
|
||||
help_index : 'ee',
|
||||
handler : function (env) {
|
||||
env.notebook.cut_cell();
|
||||
}
|
||||
},
|
||||
'copy-selected-cell' : {
|
||||
icon: 'fa-copy',
|
||||
help_index : 'ef',
|
||||
handler : function (env) {
|
||||
env.notebook.copy_cell();
|
||||
}
|
||||
},
|
||||
'paste-cell-before' : {
|
||||
help_index : 'eg',
|
||||
handler : function (env) {
|
||||
env.notebook.paste_cell_above();
|
||||
}
|
||||
},
|
||||
'paste-cell-after' : {
|
||||
icon: 'fa-paste',
|
||||
help_index : 'eh',
|
||||
handler : function (env) {
|
||||
env.notebook.paste_cell_below();
|
||||
}
|
||||
},
|
||||
'insert-cell-before' : {
|
||||
help_index : 'ec',
|
||||
handler : function (env) {
|
||||
env.notebook.insert_cell_above();
|
||||
env.notebook.select_prev();
|
||||
env.notebook.focus_cell();
|
||||
}
|
||||
},
|
||||
'insert-cell-after' : {
|
||||
icon : 'fa-plus',
|
||||
help_index : 'ed',
|
||||
handler : function (env) {
|
||||
env.notebook.insert_cell_below();
|
||||
env.notebook.select_next();
|
||||
env.notebook.focus_cell();
|
||||
}
|
||||
},
|
||||
'change-selected-cell-to-code-cell' : {
|
||||
help : 'to code',
|
||||
help_index : 'ca',
|
||||
handler : function (env) {
|
||||
env.notebook.to_code();
|
||||
}
|
||||
},
|
||||
'change-selected-cell-to-markdown-cell' : {
|
||||
help : 'to markdown',
|
||||
help_index : 'cb',
|
||||
handler : function (env) {
|
||||
env.notebook.to_markdown();
|
||||
}
|
||||
},
|
||||
'change-selected-cell-to-raw-cell' : {
|
||||
help : 'to raw',
|
||||
help_index : 'cc',
|
||||
handler : function (env) {
|
||||
env.notebook.to_raw();
|
||||
}
|
||||
},
|
||||
'change-selected-cell-to-heading-1' : {
|
||||
help : 'to heading 1',
|
||||
help_index : 'cd',
|
||||
handler : function (env) {
|
||||
env.notebook.to_heading(undefined, 1);
|
||||
}
|
||||
},
|
||||
'change-selected-cell-to-heading-2' : {
|
||||
help : 'to heading 2',
|
||||
help_index : 'ce',
|
||||
handler : function (env) {
|
||||
env.notebook.to_heading(undefined, 2);
|
||||
}
|
||||
},
|
||||
'change-selected-cell-to-heading-3' : {
|
||||
help : 'to heading 3',
|
||||
help_index : 'cf',
|
||||
handler : function (env) {
|
||||
env.notebook.to_heading(undefined, 3);
|
||||
}
|
||||
},
|
||||
'change-selected-cell-to-heading-4' : {
|
||||
help : 'to heading 4',
|
||||
help_index : 'cg',
|
||||
handler : function (env) {
|
||||
env.notebook.to_heading(undefined, 4);
|
||||
}
|
||||
},
|
||||
'change-selected-cell-to-heading-5' : {
|
||||
help : 'to heading 5',
|
||||
help_index : 'ch',
|
||||
handler : function (env) {
|
||||
env.notebook.to_heading(undefined, 5);
|
||||
}
|
||||
},
|
||||
'change-selected-cell-to-heading-6' : {
|
||||
help : 'to heading 6',
|
||||
help_index : 'ci',
|
||||
handler : function (env) {
|
||||
env.notebook.to_heading(undefined, 6);
|
||||
}
|
||||
},
|
||||
'toggle-output-visibility-selected-cell' : {
|
||||
help : 'toggle output',
|
||||
help_index : 'gb',
|
||||
handler : function (env) {
|
||||
env.notebook.toggle_output();
|
||||
}
|
||||
},
|
||||
'toggle-output-scrolling-selected-cell' : {
|
||||
help : 'toggle output scrolling',
|
||||
help_index : 'gc',
|
||||
handler : function (env) {
|
||||
env.notebook.toggle_output_scroll();
|
||||
}
|
||||
},
|
||||
'move-selected-cell-down' : {
|
||||
icon: 'fa-arrow-down',
|
||||
help_index : 'eb',
|
||||
handler : function (env) {
|
||||
env.notebook.move_cell_down();
|
||||
}
|
||||
},
|
||||
'move-selected-cell-up' : {
|
||||
icon: 'fa-arrow-up',
|
||||
help_index : 'ea',
|
||||
handler : function (env) {
|
||||
env.notebook.move_cell_up();
|
||||
}
|
||||
},
|
||||
'toggle-line-number-selected-cell' : {
|
||||
help : 'toggle line numbers',
|
||||
help_index : 'ga',
|
||||
handler : function (env) {
|
||||
env.notebook.cell_toggle_line_numbers();
|
||||
}
|
||||
},
|
||||
'show-keyboard-shortcut-help-dialog' : {
|
||||
help_index : 'ge',
|
||||
handler : function (env) {
|
||||
env.quick_help.show_keyboard_shortcuts();
|
||||
}
|
||||
},
|
||||
'delete-cell': {
|
||||
help_index : 'ej',
|
||||
handler : function (env) {
|
||||
env.notebook.delete_cell();
|
||||
}
|
||||
},
|
||||
'interrupt-kernel':{
|
||||
icon: 'fa-stop',
|
||||
help_index : 'ha',
|
||||
handler : function (env) {
|
||||
env.notebook.kernel.interrupt();
|
||||
}
|
||||
},
|
||||
'restart-kernel':{
|
||||
icon: 'fa-repeat',
|
||||
help_index : 'hb',
|
||||
handler : function (env) {
|
||||
env.notebook.restart_kernel();
|
||||
}
|
||||
},
|
||||
'undo-last-cell-deletion' : {
|
||||
help_index : 'ei',
|
||||
handler : function (env) {
|
||||
env.notebook.undelete_cell();
|
||||
}
|
||||
},
|
||||
'merge-selected-cell-with-cell-after' : {
|
||||
help : 'merge cell below',
|
||||
help_index : 'ek',
|
||||
handler : function (env) {
|
||||
env.notebook.merge_cell_below();
|
||||
}
|
||||
},
|
||||
'close-pager' : {
|
||||
help_index : 'gd',
|
||||
handler : function (env) {
|
||||
env.pager.collapse();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* A bunch of `Advance actions` for IPython.
|
||||
* Cf `Simple Action` plus the following properties.
|
||||
*
|
||||
* handler: first argument of the handler is the event that triggerd the action
|
||||
* (typically keypress). The handler is responsible for any modification of the
|
||||
* event and event propagation.
|
||||
* Is also responsible for returning false if the event have to be further ignored,
|
||||
* true, to tell keyboard manager that it ignored the event.
|
||||
*
|
||||
* the second parameter of the handler is the environemnt passed to Simple Actions
|
||||
*
|
||||
**/
|
||||
var custom_ignore = {
|
||||
'ignore':{
|
||||
handler : function () {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
'move-cursor-up-or-previous-cell':{
|
||||
handler : function (env, event) {
|
||||
var index = env.notebook.get_selected_index();
|
||||
var cell = env.notebook.get_cell(index);
|
||||
var cm = env.notebook.get_selected_cell().code_mirror;
|
||||
var cur = cm.getCursor();
|
||||
if (cell && cell.at_top() && index !== 0 && cur.ch === 0) {
|
||||
if(event){
|
||||
event.preventDefault();
|
||||
}
|
||||
env.notebook.command_mode();
|
||||
env.notebook.select_prev();
|
||||
env.notebook.edit_mode();
|
||||
cm = env.notebook.get_selected_cell().code_mirror;
|
||||
cm.setCursor(cm.lastLine(), 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'move-cursor-down-or-next-cell':{
|
||||
handler : function (env, event) {
|
||||
var index = env.notebook.get_selected_index();
|
||||
var cell = env.notebook.get_cell(index);
|
||||
if (cell.at_bottom() && index !== (env.notebook.ncells()-1)) {
|
||||
if(event){
|
||||
event.preventDefault();
|
||||
}
|
||||
env.notebook.command_mode();
|
||||
env.notebook.select_next();
|
||||
env.notebook.edit_mode();
|
||||
var cm = env.notebook.get_selected_cell().code_mirror;
|
||||
cm.setCursor(0, 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'scroll-down': {
|
||||
handler: function(env, event) {
|
||||
if(event){
|
||||
event.preventDefault();
|
||||
}
|
||||
return env.notebook.scroll_manager.scroll(1);
|
||||
},
|
||||
},
|
||||
'scroll-up': {
|
||||
handler: function(env, event) {
|
||||
if(event){
|
||||
event.preventDefault();
|
||||
}
|
||||
return env.notebook.scroll_manager.scroll(-1);
|
||||
},
|
||||
},
|
||||
'save-notebook':{
|
||||
help: "Save and Checkpoint",
|
||||
help_index : 'fb',
|
||||
icon: 'fa-save',
|
||||
handler : function (env, event) {
|
||||
env.notebook.save_checkpoint();
|
||||
if(event){
|
||||
event.preventDefault();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// private stuff that prepend `.ipython` to actions names
|
||||
// and uniformize/fill in missing pieces in of an action.
|
||||
var _prepare_handler = function(registry, subkey, source){
|
||||
registry['ipython.'+subkey] = {};
|
||||
registry['ipython.'+subkey].help = source[subkey].help||subkey.replace(/-/g,' ');
|
||||
registry['ipython.'+subkey].help_index = source[subkey].help_index;
|
||||
registry['ipython.'+subkey].icon = source[subkey].icon;
|
||||
return source[subkey].handler;
|
||||
};
|
||||
|
||||
// Will actually generate/register all the IPython actions
|
||||
var fun = function(){
|
||||
var final_actions = {};
|
||||
for(var k in _action){
|
||||
// Js closure are function level not block level need to wrap in a IIFE
|
||||
// and append ipython to event name these things do intercept event so are wrapped
|
||||
// in a function that return false.
|
||||
var handler = _prepare_handler(final_actions, k, _action);
|
||||
(function(key, handler){
|
||||
final_actions['ipython.'+key].handler = function(env, event){
|
||||
handler(env);
|
||||
if(event){
|
||||
event.preventDefault();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
})(k, handler);
|
||||
}
|
||||
|
||||
for(var k in custom_ignore){
|
||||
// Js closure are function level not block level need to wrap in a IIFE
|
||||
// same as above, but decide for themselves wether or not they intercept events.
|
||||
var handler = _prepare_handler(final_actions, k, custom_ignore);
|
||||
(function(key, handler){
|
||||
final_actions['ipython.'+key].handler = function(env, event){
|
||||
return handler(env, event);
|
||||
};
|
||||
})(k, handler);
|
||||
}
|
||||
|
||||
return final_actions;
|
||||
};
|
||||
ActionHandler.prototype._actions = fun();
|
||||
|
||||
|
||||
/**
|
||||
* extend the environment variable that will be pass to handlers
|
||||
**/
|
||||
ActionHandler.prototype.extend_env = function(env){
|
||||
for(var k in env){
|
||||
this.env[k] = env[k];
|
||||
}
|
||||
};
|
||||
|
||||
ActionHandler.prototype.register = function(action, name, prefix){
|
||||
/**
|
||||
* Register an `action` with an optional name and prefix.
|
||||
*
|
||||
* if name and prefix are not given they will be determined automatically.
|
||||
* if action if just a `function` it will be wrapped in an anonymous action.
|
||||
*
|
||||
* @return the full name to access this action .
|
||||
**/
|
||||
action = this.normalise(action);
|
||||
if( !name ){
|
||||
name = 'autogenerated-'+String(action.handler);
|
||||
}
|
||||
prefix = prefix || 'auto';
|
||||
var full_name = prefix+'.'+name;
|
||||
this._actions[full_name] = action;
|
||||
return full_name;
|
||||
|
||||
};
|
||||
|
||||
|
||||
ActionHandler.prototype.normalise = function(data){
|
||||
/**
|
||||
* given an `action` or `function`, return a normalised `action`
|
||||
* by setting all known attributes and removing unknown attributes;
|
||||
**/
|
||||
if(typeof(data) === 'function'){
|
||||
data = {handler:data};
|
||||
}
|
||||
if(typeof(data.handler) !== 'function'){
|
||||
throw('unknown datatype, cannot register');
|
||||
}
|
||||
var _data = data;
|
||||
data = {};
|
||||
data.handler = _data.handler;
|
||||
data.help = data.help || '';
|
||||
data.icon = data.icon || '';
|
||||
data.help_index = data.help_index || '';
|
||||
return data;
|
||||
};
|
||||
|
||||
ActionHandler.prototype.get_name = function(name_or_data){
|
||||
/**
|
||||
* given an `action` or `name` of a action, return the name attached to this action.
|
||||
* if given the name of and corresponding actions does not exist in registry, return `null`.
|
||||
**/
|
||||
|
||||
if(typeof(name_or_data) === 'string'){
|
||||
if(this.exists(name_or_data)){
|
||||
return name_or_data;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return this.register(name_or_data);
|
||||
}
|
||||
};
|
||||
|
||||
ActionHandler.prototype.get = function(name){
|
||||
return this._actions[name];
|
||||
};
|
||||
|
||||
ActionHandler.prototype.call = function(name, event, env){
|
||||
return this._actions[name].handler(env|| this.env, event);
|
||||
};
|
||||
|
||||
ActionHandler.prototype.exists = function(name){
|
||||
return (typeof(this._actions[name]) !== 'undefined');
|
||||
};
|
||||
|
||||
return {init:ActionHandler};
|
||||
|
||||
});
|
@ -16,9 +16,6 @@ define([
|
||||
], function(IPython, $, utils, keyboard) {
|
||||
"use strict";
|
||||
|
||||
var browser = utils.browser[0];
|
||||
var platform = utils.platform;
|
||||
|
||||
// Main keyboard manager for the notebook
|
||||
var keycodes = keyboard.keycodes;
|
||||
|
||||
@ -37,487 +34,119 @@ define([
|
||||
this.pager = options.pager;
|
||||
this.quick_help = undefined;
|
||||
this.notebook = undefined;
|
||||
this.last_mode = undefined;
|
||||
this.bind_events();
|
||||
this.command_shortcuts = new keyboard.ShortcutManager(undefined, options.events);
|
||||
this.env = {pager:this.pager};
|
||||
this.actions = options.actions;
|
||||
this.command_shortcuts = new keyboard.ShortcutManager(undefined, options.events, this.actions, this.env );
|
||||
this.command_shortcuts.add_shortcuts(this.get_default_common_shortcuts());
|
||||
this.command_shortcuts.add_shortcuts(this.get_default_command_shortcuts());
|
||||
this.edit_shortcuts = new keyboard.ShortcutManager(undefined, options.events);
|
||||
this.edit_shortcuts = new keyboard.ShortcutManager(undefined, options.events, this.actions, this.env);
|
||||
this.edit_shortcuts.add_shortcuts(this.get_default_common_shortcuts());
|
||||
this.edit_shortcuts.add_shortcuts(this.get_default_edit_shortcuts());
|
||||
Object.seal(this);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return a dict of common shortcut
|
||||
* @method get_default_common_shortcuts
|
||||
*
|
||||
* @example Example of returned shortcut
|
||||
* ```
|
||||
* 'shortcut-key': // a string representing the shortcut as dash separated value.
|
||||
* // e.g. 'shift' , 'shift-enter', 'cmd-t'
|
||||
* {
|
||||
* help: String // user facing help string
|
||||
* help_index: String // string used internally to order the shortcut on the quickhelp
|
||||
* handler: function(event){return true|false} // function that takes an even as first and only parameter
|
||||
* // and return a boolean indicating whether or not the event should been handled further.
|
||||
* }
|
||||
* 'shortcut-key': 'action-name'
|
||||
* // a string representing the shortcut as dash separated value.
|
||||
* // e.g. 'shift' , 'shift-enter', 'cmd-t'
|
||||
*```
|
||||
*/
|
||||
KeyboardManager.prototype.get_default_common_shortcuts = function() {
|
||||
var that = this;
|
||||
var shortcuts = {
|
||||
'shift' : {
|
||||
help : '',
|
||||
help_index : '',
|
||||
handler : function (event) {
|
||||
// ignore shift keydown
|
||||
return true;
|
||||
}
|
||||
},
|
||||
'shift-enter' : {
|
||||
help : 'run cell, select below',
|
||||
help_index : 'ba',
|
||||
handler : function (event) {
|
||||
that.notebook.execute_cell_and_select_below();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'ctrl-enter' : {
|
||||
help : 'run cell',
|
||||
help_index : 'bb',
|
||||
handler : function (event) {
|
||||
that.notebook.execute_cell();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'alt-enter' : {
|
||||
help : 'run cell, insert below',
|
||||
help_index : 'bc',
|
||||
handler : function (event) {
|
||||
that.notebook.execute_cell_and_insert_below();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return {
|
||||
'shift' : 'ipython.ignore',
|
||||
'shift-enter' : 'ipython.run-select-next',
|
||||
'ctrl-enter' : 'ipython.execute-in-place',
|
||||
'alt-enter' : 'ipython.execute-and-insert-after',
|
||||
// cmd on mac, ctrl otherwise
|
||||
'cmdtrl-s' : 'ipython.save-notebook',
|
||||
};
|
||||
|
||||
if (platform === 'MacOS') {
|
||||
shortcuts['cmd-s'] =
|
||||
{
|
||||
help : 'save notebook',
|
||||
help_index : 'fb',
|
||||
handler : function (event) {
|
||||
that.notebook.save_checkpoint();
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
shortcuts['ctrl-s'] =
|
||||
{
|
||||
help : 'save notebook',
|
||||
help_index : 'fb',
|
||||
handler : function (event) {
|
||||
that.notebook.save_checkpoint();
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
return shortcuts;
|
||||
};
|
||||
|
||||
KeyboardManager.prototype.get_default_edit_shortcuts = function() {
|
||||
var that = this;
|
||||
return {
|
||||
'esc' : {
|
||||
help : 'command mode',
|
||||
help_index : 'aa',
|
||||
handler : function (event) {
|
||||
that.notebook.command_mode();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'ctrl-m' : {
|
||||
help : 'command mode',
|
||||
help_index : 'ab',
|
||||
handler : function (event) {
|
||||
that.notebook.command_mode();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'up' : {
|
||||
help : '',
|
||||
help_index : '',
|
||||
handler : function (event) {
|
||||
var index = that.notebook.get_selected_index();
|
||||
var cell = that.notebook.get_cell(index);
|
||||
var cm = that.notebook.get_selected_cell().code_mirror;
|
||||
var cur = cm.getCursor()
|
||||
if (cell && cell.at_top() && index !== 0 && cur.ch === 0) {
|
||||
event.preventDefault();
|
||||
that.notebook.command_mode();
|
||||
that.notebook.select_prev();
|
||||
that.notebook.edit_mode();
|
||||
var cm = that.notebook.get_selected_cell().code_mirror;
|
||||
cm.setCursor(cm.lastLine(), 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'down' : {
|
||||
help : '',
|
||||
help_index : '',
|
||||
handler : function (event) {
|
||||
var index = that.notebook.get_selected_index();
|
||||
var cell = that.notebook.get_cell(index);
|
||||
if (cell.at_bottom() && index !== (that.notebook.ncells()-1)) {
|
||||
event.preventDefault();
|
||||
that.notebook.command_mode();
|
||||
that.notebook.select_next();
|
||||
that.notebook.edit_mode();
|
||||
var cm = that.notebook.get_selected_cell().code_mirror;
|
||||
cm.setCursor(0, 0);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'ctrl-shift--' : {
|
||||
help : 'split cell',
|
||||
help_index : 'ea',
|
||||
handler : function (event) {
|
||||
that.notebook.split_cell();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'ctrl-shift-subtract' : {
|
||||
help : '',
|
||||
help_index : 'eb',
|
||||
handler : function (event) {
|
||||
that.notebook.split_cell();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'esc' : 'ipython.go-to-command-mode',
|
||||
'ctrl-m' : 'ipython.go-to-command-mode',
|
||||
'up' : 'ipython.move-cursor-up-or-previous-cell',
|
||||
'down' : 'ipython.move-cursor-down-or-next-cell',
|
||||
'ctrl-shift--' : 'ipython.split-cell-at-cursor',
|
||||
'ctrl-shift-subtract' : 'ipython.split-cell-at-cursor'
|
||||
};
|
||||
};
|
||||
|
||||
KeyboardManager.prototype.get_default_command_shortcuts = function() {
|
||||
var that = this;
|
||||
return {
|
||||
'space': {
|
||||
help: "Scroll down",
|
||||
handler: function(event) {
|
||||
return that.notebook.scroll_manager.scroll(1);
|
||||
},
|
||||
},
|
||||
'shift-space': {
|
||||
help: "Scroll up",
|
||||
handler: function(event) {
|
||||
return that.notebook.scroll_manager.scroll(-1);
|
||||
},
|
||||
},
|
||||
'enter' : {
|
||||
help : 'edit mode',
|
||||
help_index : 'aa',
|
||||
handler : function (event) {
|
||||
that.notebook.edit_mode();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'up' : {
|
||||
help : 'select previous cell',
|
||||
help_index : 'da',
|
||||
handler : function (event) {
|
||||
var index = that.notebook.get_selected_index();
|
||||
if (index !== 0 && index !== null) {
|
||||
that.notebook.select_prev();
|
||||
that.notebook.focus_cell();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'down' : {
|
||||
help : 'select next cell',
|
||||
help_index : 'db',
|
||||
handler : function (event) {
|
||||
var index = that.notebook.get_selected_index();
|
||||
if (index !== (that.notebook.ncells()-1) && index !== null) {
|
||||
that.notebook.select_next();
|
||||
that.notebook.focus_cell();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'k' : {
|
||||
help : 'select previous cell',
|
||||
help_index : 'dc',
|
||||
handler : function (event) {
|
||||
var index = that.notebook.get_selected_index();
|
||||
if (index !== 0 && index !== null) {
|
||||
that.notebook.select_prev();
|
||||
that.notebook.focus_cell();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'j' : {
|
||||
help : 'select next cell',
|
||||
help_index : 'dd',
|
||||
handler : function (event) {
|
||||
var index = that.notebook.get_selected_index();
|
||||
if (index !== (that.notebook.ncells()-1) && index !== null) {
|
||||
that.notebook.select_next();
|
||||
that.notebook.focus_cell();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'x' : {
|
||||
help : 'cut cell',
|
||||
help_index : 'ee',
|
||||
handler : function (event) {
|
||||
that.notebook.cut_cell();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'c' : {
|
||||
help : 'copy cell',
|
||||
help_index : 'ef',
|
||||
handler : function (event) {
|
||||
that.notebook.copy_cell();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'shift-v' : {
|
||||
help : 'paste cell above',
|
||||
help_index : 'eg',
|
||||
handler : function (event) {
|
||||
that.notebook.paste_cell_above();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'v' : {
|
||||
help : 'paste cell below',
|
||||
help_index : 'eh',
|
||||
handler : function (event) {
|
||||
that.notebook.paste_cell_below();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'd' : {
|
||||
help : 'delete cell (press twice)',
|
||||
help_index : 'ej',
|
||||
count: 2,
|
||||
handler : function (event) {
|
||||
that.notebook.delete_cell();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'a' : {
|
||||
help : 'insert cell above',
|
||||
help_index : 'ec',
|
||||
handler : function (event) {
|
||||
that.notebook.insert_cell_above();
|
||||
that.notebook.select_prev();
|
||||
that.notebook.focus_cell();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'b' : {
|
||||
help : 'insert cell below',
|
||||
help_index : 'ed',
|
||||
handler : function (event) {
|
||||
that.notebook.insert_cell_below();
|
||||
that.notebook.select_next();
|
||||
that.notebook.focus_cell();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'y' : {
|
||||
help : 'to code',
|
||||
help_index : 'ca',
|
||||
handler : function (event) {
|
||||
that.notebook.to_code();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'm' : {
|
||||
help : 'to markdown',
|
||||
help_index : 'cb',
|
||||
handler : function (event) {
|
||||
that.notebook.to_markdown();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'r' : {
|
||||
help : 'to raw',
|
||||
help_index : 'cc',
|
||||
handler : function (event) {
|
||||
that.notebook.to_raw();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'1' : {
|
||||
help : 'to heading 1',
|
||||
help_index : 'cd',
|
||||
handler : function (event) {
|
||||
that.notebook.to_heading(undefined, 1);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'2' : {
|
||||
help : 'to heading 2',
|
||||
help_index : 'ce',
|
||||
handler : function (event) {
|
||||
that.notebook.to_heading(undefined, 2);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'3' : {
|
||||
help : 'to heading 3',
|
||||
help_index : 'cf',
|
||||
handler : function (event) {
|
||||
that.notebook.to_heading(undefined, 3);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'4' : {
|
||||
help : 'to heading 4',
|
||||
help_index : 'cg',
|
||||
handler : function (event) {
|
||||
that.notebook.to_heading(undefined, 4);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'5' : {
|
||||
help : 'to heading 5',
|
||||
help_index : 'ch',
|
||||
handler : function (event) {
|
||||
that.notebook.to_heading(undefined, 5);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'6' : {
|
||||
help : 'to heading 6',
|
||||
help_index : 'ci',
|
||||
handler : function (event) {
|
||||
that.notebook.to_heading(undefined, 6);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'o' : {
|
||||
help : 'toggle output',
|
||||
help_index : 'gb',
|
||||
handler : function (event) {
|
||||
that.notebook.toggle_output();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'shift-o' : {
|
||||
help : 'toggle output scrolling',
|
||||
help_index : 'gc',
|
||||
handler : function (event) {
|
||||
that.notebook.toggle_output_scroll();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
's' : {
|
||||
help : 'save notebook',
|
||||
help_index : 'fa',
|
||||
handler : function (event) {
|
||||
that.notebook.save_checkpoint();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'ctrl-j' : {
|
||||
help : 'move cell down',
|
||||
help_index : 'eb',
|
||||
handler : function (event) {
|
||||
that.notebook.move_cell_down();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'ctrl-k' : {
|
||||
help : 'move cell up',
|
||||
help_index : 'ea',
|
||||
handler : function (event) {
|
||||
that.notebook.move_cell_up();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'l' : {
|
||||
help : 'toggle line numbers',
|
||||
help_index : 'ga',
|
||||
handler : function (event) {
|
||||
that.notebook.cell_toggle_line_numbers();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'i' : {
|
||||
help : 'interrupt kernel (press twice)',
|
||||
help_index : 'ha',
|
||||
count: 2,
|
||||
handler : function (event) {
|
||||
that.notebook.kernel.interrupt();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'0' : {
|
||||
help : 'restart kernel (press twice)',
|
||||
help_index : 'hb',
|
||||
count: 2,
|
||||
handler : function (event) {
|
||||
that.notebook.restart_kernel();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'h' : {
|
||||
help : 'keyboard shortcuts',
|
||||
help_index : 'ge',
|
||||
handler : function (event) {
|
||||
that.quick_help.show_keyboard_shortcuts();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'z' : {
|
||||
help : 'undo last delete',
|
||||
help_index : 'ei',
|
||||
handler : function (event) {
|
||||
that.notebook.undelete_cell();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'shift-m' : {
|
||||
help : 'merge cell below',
|
||||
help_index : 'ek',
|
||||
handler : function (event) {
|
||||
that.notebook.merge_cell_below();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'q' : {
|
||||
help : 'close pager',
|
||||
help_index : 'gd',
|
||||
handler : function (event) {
|
||||
that.pager.collapse();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
'shift-space': 'ipython.scroll-up',
|
||||
'shift-v' : 'ipython.paste-cell-before',
|
||||
'shift-m' : 'ipython.merge-selected-cell-with-cell-after',
|
||||
'shift-o' : 'ipython.toggle-output-scrolling-selected-cell',
|
||||
'ctrl-j' : 'ipython.move-selected-cell-down',
|
||||
'ctrl-k' : 'ipython.move-selected-cell-up',
|
||||
'enter' : 'ipython.enter-edit-mode',
|
||||
'space' : 'ipython.scroll-down',
|
||||
'down' : 'ipython.select-next-cell',
|
||||
'i,i' : 'ipython.interrupt-kernel',
|
||||
'0,0' : 'ipython.restart-kernel',
|
||||
'd,d' : 'ipython.delete-cell',
|
||||
'up' : 'ipython.select-previous-cell',
|
||||
'k' : 'ipython.select-previous-cell',
|
||||
'j' : 'ipython.select-next-cell',
|
||||
'x' : 'ipython.cut-selected-cell',
|
||||
'c' : 'ipython.copy-selected-cell',
|
||||
'v' : 'ipython.paste-cell-after',
|
||||
'a' : 'ipython.insert-cell-before',
|
||||
'b' : 'ipython.insert-cell-after',
|
||||
'y' : 'ipython.change-selected-cell-to-code-cell',
|
||||
'm' : 'ipython.change-selected-cell-to-markdown-cell',
|
||||
'r' : 'ipython.change-selected-cell-to-raw-cell',
|
||||
'1' : 'ipython.change-selected-cell-to-heading-1',
|
||||
'2' : 'ipython.change-selected-cell-to-heading-2',
|
||||
'3' : 'ipython.change-selected-cell-to-heading-3',
|
||||
'4' : 'ipython.change-selected-cell-to-heading-4',
|
||||
'5' : 'ipython.change-selected-cell-to-heading-5',
|
||||
'6' : 'ipython.change-selected-cell-to-heading-6',
|
||||
'o' : 'ipython.toggle-output-visibility-selected-cell',
|
||||
's' : 'ipython.save-notebook',
|
||||
'l' : 'ipython.toggle-line-number-selected-cell',
|
||||
'h' : 'ipython.show-keyboard-shortcut-help-dialog',
|
||||
'z' : 'ipython.undo-last-cell-deletion',
|
||||
'q' : 'ipython.close-pager',
|
||||
};
|
||||
};
|
||||
|
||||
KeyboardManager.prototype.bind_events = function () {
|
||||
var that = this;
|
||||
$(document).keydown(function (event) {
|
||||
|
||||
if(event._ipkmIgnore==true||(event.originalEvent||{})._ipkmIgnore==true){
|
||||
if(event._ipkmIgnore===true||(event.originalEvent||{})._ipkmIgnore===true){
|
||||
return false;
|
||||
}
|
||||
return that.handle_keydown(event);
|
||||
});
|
||||
};
|
||||
|
||||
KeyboardManager.prototype.set_notebook = function (notebook) {
|
||||
this.notebook = notebook;
|
||||
this.actions.extend_env({notebook:notebook});
|
||||
};
|
||||
|
||||
KeyboardManager.prototype.set_quickhelp = function (notebook) {
|
||||
this.actions.extend_env({quick_help:notebook});
|
||||
};
|
||||
|
||||
|
||||
KeyboardManager.prototype.handle_keydown = function (event) {
|
||||
var notebook = this.notebook;
|
||||
/**
|
||||
* returning false from this will stop event propagation
|
||||
**/
|
||||
|
||||
if (event.which === keycodes.esc) {
|
||||
// Intercept escape at highest level to avoid closing
|
||||
@ -527,8 +156,7 @@ define([
|
||||
|
||||
if (!this.enabled) {
|
||||
if (event.which === keycodes.esc) {
|
||||
// ESC
|
||||
notebook.command_mode();
|
||||
this.notebook.command_mode();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -595,7 +223,8 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
// For backwards compatability.
|
||||
|
||||
// For backwards compatibility.
|
||||
IPython.KeyboardManager = KeyboardManager;
|
||||
|
||||
return {'KeyboardManager': KeyboardManager};
|
||||
|
@ -17,6 +17,7 @@ require([
|
||||
'notebook/js/menubar',
|
||||
'notebook/js/notificationarea',
|
||||
'notebook/js/savewidget',
|
||||
'notebook/js/actions',
|
||||
'notebook/js/keyboardmanager',
|
||||
'notebook/js/config',
|
||||
'notebook/js/kernelselector',
|
||||
@ -39,7 +40,8 @@ require([
|
||||
quickhelp,
|
||||
menubar,
|
||||
notificationarea,
|
||||
savewidget,
|
||||
savewidget,
|
||||
actions,
|
||||
keyboardmanager,
|
||||
config,
|
||||
kernelselector,
|
||||
@ -66,9 +68,11 @@ require([
|
||||
var pager = new pager.Pager('div#pager', 'div#pager_splitter', {
|
||||
layout_manager: layout_manager,
|
||||
events: events});
|
||||
var acts = new actions.init();
|
||||
var keyboard_manager = new keyboardmanager.KeyboardManager({
|
||||
pager: pager,
|
||||
events: events});
|
||||
events: events,
|
||||
actions: acts });
|
||||
var save_widget = new savewidget.SaveWidget('span#save_widget', {
|
||||
events: events,
|
||||
keyboard_manager: keyboard_manager});
|
||||
@ -85,11 +89,14 @@ require([
|
||||
var login_widget = new loginwidget.LoginWidget('span#login_widget', common_options);
|
||||
var toolbar = new maintoolbar.MainToolBar('#maintoolbar-container', {
|
||||
notebook: notebook,
|
||||
events: events});
|
||||
events: events,
|
||||
actions: acts});
|
||||
var quick_help = new quickhelp.QuickHelp({
|
||||
keyboard_manager: keyboard_manager,
|
||||
events: events,
|
||||
notebook: notebook});
|
||||
keyboard_manager.set_notebook(notebook);
|
||||
keyboard_manager.set_quickhelp(quick_help);
|
||||
var menubar = new menubar.MenuBar('#menubar', $.extend({
|
||||
notebook: notebook,
|
||||
contents: contents,
|
||||
|
@ -34,10 +34,10 @@ define([
|
||||
platform_specific = [
|
||||
{ shortcut: "Cmd-Up", help:"go to cell start" },
|
||||
{ shortcut: "Cmd-Down", help:"go to cell end" },
|
||||
{ shortcut: "Opt-Left", help:"go one word left" },
|
||||
{ shortcut: "Opt-Right", help:"go one word right" },
|
||||
{ shortcut: "Opt-Backspace", help:"del word before" },
|
||||
{ shortcut: "Opt-Delete", help:"del word after" },
|
||||
{ shortcut: "Alt-Left", help:"go one word left" },
|
||||
{ shortcut: "Alt-Right", help:"go one word right" },
|
||||
{ shortcut: "Alt-Backspace", help:"del word before" },
|
||||
{ shortcut: "Alt-Delete", help:"del word after" },
|
||||
];
|
||||
} else {
|
||||
// PC specific
|
||||
@ -65,10 +65,6 @@ define([
|
||||
].concat( platform_specific );
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
QuickHelp.prototype.show_keyboard_shortcuts = function () {
|
||||
// toggles display of keyboard shortcut dialog
|
||||
var that = this;
|
||||
@ -139,7 +135,9 @@ define([
|
||||
keys[i] = "<code><strong>" + k + "</strong></code>";
|
||||
continue; // leave individual keys lower-cased
|
||||
}
|
||||
keys[i] = ( special_case[k] ? special_case[k] : k.charAt(0).toUpperCase() + k.slice(1) );
|
||||
if (k.indexOf(',') === -1){
|
||||
keys[i] = ( special_case[k] ? special_case[k] : k.charAt(0).toUpperCase() + k.slice(1) );
|
||||
}
|
||||
keys[i] = "<code><strong>" + keys[i] + "</strong></code>";
|
||||
}
|
||||
return keys.join('-');
|
||||
|
@ -11,7 +11,7 @@ define([
|
||||
* A generic toolbar on which one can add button
|
||||
* @class ToolBar
|
||||
* @constructor
|
||||
* @param {Dom_object} selector
|
||||
* @param {Dom object} selector
|
||||
*/
|
||||
var ToolBar = function (selector, layout_manager) {
|
||||
this.selector = selector;
|
||||
|
@ -13,7 +13,9 @@ var to_normalize = [
|
||||
var unshifted = "` 1 2 3 4 5 6 7 8 9 0 - = q w e r t y u i o p [ ] \\ a s d f g h j k l ; ' z x c v b n m , . /";
|
||||
// shifted = '~ ! @ # $ % ^ & * ( ) _ + Q W E R T Y U I O P { } | A S D F G H J K L : " Z X C V B N M < > ?';
|
||||
|
||||
|
||||
casper.notebook_test(function () {
|
||||
var that = this;
|
||||
|
||||
this.then(function () {
|
||||
this.each(unshifted.split(' '), function (self, item) {
|
||||
@ -46,4 +48,37 @@ casper.notebook_test(function () {
|
||||
});
|
||||
});
|
||||
|
||||
this.then(function(){
|
||||
|
||||
var shortcuts_test = {
|
||||
'i,e,e,e,e,e' : '[[5E]]',
|
||||
'i,d,d,q,d' : '[[TEST1]]',
|
||||
'i,d,d' : '[[TEST1 WILL BE SHADOWED]]',
|
||||
'i,d,k' : '[[SHOULD SHADOW TEST2]]',
|
||||
'i,d,k,r,q' : '[[TEST2 NOT SHADOWED]]',
|
||||
';,up,down,up,down,left,right,left,right,b,a' : '[[KONAMI]]',
|
||||
'ctrl-x,meta-c,meta-b,u,t,t,e,r,f,l,y' : '[[XKCD]]'
|
||||
|
||||
};
|
||||
|
||||
that.msgs = [];
|
||||
that.on('remote.message', function(msg) {
|
||||
that.msgs.push(msg);
|
||||
})
|
||||
that.evaluate(function (obj) {
|
||||
for(var k in obj){
|
||||
IPython.keyboard_manager.command_shortcuts.add_shortcut(k, function(){console.log(obj[k])});
|
||||
}
|
||||
}, shortcuts_test);
|
||||
|
||||
var longer_first = false;
|
||||
var longer_last = false;
|
||||
for(var m in that.msgs){
|
||||
longer_first = longer_first||(that.msgs[m].match(/you are overriting/)!= null);
|
||||
longer_last = longer_last ||(that.msgs[m].match(/will be shadowed/) != null);
|
||||
}
|
||||
this.test.assert(longer_first, 'no warnign if registering shorter shortut');
|
||||
this.test.assert(longer_last , 'no warnign if registering longer shortut');
|
||||
})
|
||||
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user