##// END OF EJS Templates
Better way of saving through CodeMirror...
Better way of saving through CodeMirror This should support whatever keyboard shortcuts are configured for the 'save' command.

File last commit:

r18280:80b3c9ff
r19020:0e93c51c
Show More
keyboard.js
288 lines | 10.3 KiB | application/javascript | JavascriptLexer
Jonathan Frederic
Almost done!...
r17198 // Copyright (c) IPython Development Team.
// Distributed under the terms of the Modified BSD License.
Matthias BUSSONNIER
Update to codemirror 4...
r18280 /**
*
*
* @module keyboard
* @namespace keyboard
* @class ShortcutManager
*/
Jonathan Frederic
Almost done!...
r17198
define([
'base/js/namespace',
Jonathan Frederic
MWE,...
r17200 'jquery',
Jonathan Frederic
Almost done!...
r17198 'base/js/utils',
], function(IPython, $, utils) {
Brian E. Granger
Creating new base/js/keyboard.js
r15615 "use strict";
Jonathan Frederic
Almost done!...
r17198
Brian E. Granger
Creating new base/js/keyboard.js
r15615 // 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.
// These apply to Firefox, (Webkit and IE)
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,
's': 83, 't': 84, 'u': 85, 'v': 86, 'w': 87, 'x': 88, 'y': 89, 'z': 90,
'1 !': 49, '2 @': 50, '3 #': 51, '4 $': 52, '5 %': 53, '6 ^': 54,
'7 &': 55, '8 *': 56, '9 (': 57, '0 )': 48,
'[ {': 219, '] }': 221, '` ~': 192, ', <': 188, '. >': 190, '/ ?': 191,
'\\ |': 220, '\' "': 222,
'numpad0': 96, 'numpad1': 97, 'numpad2': 98, 'numpad3': 99, 'numpad4': 100,
'numpad5': 101, 'numpad6': 102, 'numpad7': 103, 'numpad8': 104, 'numpad9': 105,
'multiply': 106, 'add': 107, 'subtract': 109, 'decimal': 110, 'divide': 111,
'f1': 112, 'f2': 113, 'f3': 114, 'f4': 115, 'f5': 116, 'f6': 117, 'f7': 118,
'f8': 119, 'f9': 120, 'f11': 122, 'f12': 123, 'f13': 124, 'f14': 125, 'f15': 126,
'backspace': 8, 'tab': 9, 'enter': 13, 'shift': 16, 'ctrl': 17, 'alt': 18,
'meta': 91, 'capslock': 20, 'esc': 27, 'space': 32, 'pageup': 33, 'pagedown': 34,
'end': 35, 'home': 36, 'left': 37, 'up': 38, 'right': 39, 'down': 40,
'insert': 45, 'delete': 46, 'numlock': 144,
};
// These apply to Firefox and Opera
var _mozilla_keycodes = {
'; :': 59, '= +': 61, '- _': 173, 'meta': 224
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 };
Brian E. Granger
Creating new base/js/keyboard.js
r15615
// This apply to Webkit and IE
var _ie_keycodes = {
Paul Ivanov
really fix the '-' key shortcuts now
r15877 '; :': 186, '= +': 187, '- _': 189
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 };
Brian E. Granger
Creating new base/js/keyboard.js
r15615
Jonathan Frederic
Almost done!...
r17198 var browser = utils.browser[0];
var platform = utils.platform;
Brian E. Granger
Creating new base/js/keyboard.js
r15615
Jonathan Frederic
Fix Gecko (Netscape) keyboard handling
r15875 if (browser === 'Firefox' || browser === 'Opera' || browser === 'Netscape') {
Brian E. Granger
Creating new base/js/keyboard.js
r15615 $.extend(_keycodes, _mozilla_keycodes);
} else if (browser === 'Safari' || browser === 'Chrome' || browser === 'MSIE') {
$.extend(_keycodes, _ie_keycodes);
}
var keycodes = {};
var inv_keycodes = {};
for (var name in _keycodes) {
var names = name.split(' ');
if (names.length === 1) {
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 var n = names[0];
keycodes[n] = _keycodes[n];
inv_keycodes[_keycodes[n]] = n;
Brian E. Granger
Creating new base/js/keyboard.js
r15615 } else {
var primary = names[0];
var secondary = names[1];
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 keycodes[primary] = _keycodes[name];
keycodes[secondary] = _keycodes[name];
inv_keycodes[_keycodes[name]] = primary;
Brian E. Granger
Creating new base/js/keyboard.js
r15615 }
}
Brian E. Granger
Adding utility functions.
r15616 var normalize_key = function (key) {
return inv_keycodes[keycodes[key]];
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 };
Brian E. Granger
Adding utility functions.
r15616
var normalize_shortcut = function (shortcut) {
// Put a shortcut into normalized form:
// 1. Make lowercase
// 2. Replace cmd by meta
Paul Ivanov
use - for shortcut separators
r15873 // 3. Sort '-' separated modifiers into the order alt-ctrl-meta-shift
Brian E. Granger
Adding utility functions.
r15616 // 4. Normalize keys
shortcut = shortcut.toLowerCase().replace('cmd', 'meta');
Paul Ivanov
really fix the '-' key shortcuts now
r15877 shortcut = shortcut.replace(/-$/, '_'); // catch shortcuts using '-' key
Paul Ivanov
use - for shortcut separators
r15873 var values = shortcut.split("-");
Brian E. Granger
Adding utility functions.
r15616 if (values.length === 1) {
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 return normalize_key(values[0]);
Brian E. Granger
Adding utility functions.
r15616 } else {
var modifiers = values.slice(0,-1);
var key = normalize_key(values[values.length-1]);
modifiers.sort();
Paul Ivanov
use - for shortcut separators
r15873 return modifiers.join('-') + '-' + key;
Brian E. Granger
Adding utility functions.
r15616 }
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 };
Brian E. Granger
Adding utility functions.
r15616
var shortcut_to_event = function (shortcut, type) {
Paul Ivanov
use - for shortcut separators
r15873 // Convert a shortcut (shift-r) to a jQuery Event object
Brian E. Granger
Adding utility functions.
r15616 type = type || 'keydown';
shortcut = normalize_shortcut(shortcut);
Paul Ivanov
really fix the '-' key shortcuts now
r15877 shortcut = shortcut.replace(/-$/, '_'); // catch shortcuts using '-' key
Paul Ivanov
use - for shortcut separators
r15873 var values = shortcut.split("-");
Brian E. Granger
Adding utility functions.
r15616 var modifiers = values.slice(0,-1);
var key = values[values.length-1];
var opts = {which: keycodes[key]};
if (modifiers.indexOf('alt') !== -1) {opts.altKey = true;}
if (modifiers.indexOf('ctrl') !== -1) {opts.ctrlKey = true;}
if (modifiers.indexOf('meta') !== -1) {opts.metaKey = true;}
if (modifiers.indexOf('shift') !== -1) {opts.shiftKey = true;}
return $.Event(type, opts);
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 };
Brian E. Granger
Adding utility functions.
r15616
var event_to_shortcut = function (event) {
Paul Ivanov
use - for shortcut separators
r15873 // Convert a jQuery Event object to a shortcut (shift-r)
Brian E. Granger
Adding utility functions.
r15616 var shortcut = '';
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 var key = inv_keycodes[event.which];
Paul Ivanov
use - for shortcut separators
r15873 if (event.altKey && key !== 'alt') {shortcut += 'alt-';}
if (event.ctrlKey && key !== 'ctrl') {shortcut += 'ctrl-';}
if (event.metaKey && key !== 'meta') {shortcut += 'meta-';}
if (event.shiftKey && key !== 'shift') {shortcut += 'shift-';}
Brian E. Granger
Adding utility functions.
r15616 shortcut += key;
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 return shortcut;
};
Brian E. Granger
Adding utility functions.
r15616
Brian E. Granger
Creating new base/js/keyboard.js
r15615 // Shortcut manager class
Jonathan Frederic
Almost done!...
r17198 var ShortcutManager = function (delay, events) {
Matthias BUSSONNIER
Update to codemirror 4...
r18280 /**
* A class to deal with keyboard event and shortcut
*
* @class ShortcutManager
* @constructor
*/
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 this._shortcuts = {};
this._counts = {};
this._timers = {};
Brian E. Granger
Creating new base/js/keyboard.js
r15615 this.delay = delay || 800; // delay in milliseconds
Jonathan Frederic
Almost done!...
r17198 this.events = events;
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 };
Brian E. Granger
Creating new base/js/keyboard.js
r15615
ShortcutManager.prototype.help = function () {
var help = [];
for (var shortcut in this._shortcuts) {
Jonathan Frederic
Almost done!...
r17198 var help_string = this._shortcuts[shortcut].help;
var help_index = this._shortcuts[shortcut].help_index;
Brian E. Granger
Creating new base/js/keyboard.js
r15615 if (help_string) {
if (platform === 'MacOS') {
shortcut = shortcut.replace('meta', 'cmd');
}
help.push({
shortcut: shortcut,
help: help_string,
help_index: help_index}
);
}
}
help.sort(function (a, b) {
if (a.help_index > b.help_index)
return 1;
if (a.help_index < b.help_index)
return -1;
return 0;
});
return help;
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 };
Brian E. Granger
Creating new base/js/keyboard.js
r15615
ShortcutManager.prototype.clear_shortcuts = function () {
this._shortcuts = {};
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 };
Brian E. Granger
Creating new base/js/keyboard.js
r15615
Paul Ivanov
update notebook quickhelp on new shortcuts
r15769 ShortcutManager.prototype.add_shortcut = function (shortcut, data, suppress_help_update) {
Brian E. Granger
Creating new base/js/keyboard.js
r15615 if (typeof(data) === 'function') {
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 data = {help: '', help_index: '', handler: data};
Brian E. Granger
Creating new base/js/keyboard.js
r15615 }
data.help_index = data.help_index || '';
data.help = data.help || '';
data.count = data.count || 1;
if (data.help_index === '') {
data.help_index = 'zz';
}
Brian E. Granger
Adding utility functions.
r15616 shortcut = normalize_shortcut(shortcut);
Brian E. Granger
Creating new base/js/keyboard.js
r15615 this._counts[shortcut] = 0;
this._shortcuts[shortcut] = data;
Paul Ivanov
update notebook quickhelp on new shortcuts
r15769 if (!suppress_help_update) {
// update the keyboard shortcuts notebook help
Jonathan Frederic
Almost done!...
r17198 this.events.trigger('rebuild.QuickHelp');
Paul Ivanov
update notebook quickhelp on new shortcuts
r15769 }
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 };
Brian E. Granger
Creating new base/js/keyboard.js
r15615
ShortcutManager.prototype.add_shortcuts = function (data) {
for (var shortcut in data) {
Paul Ivanov
removing keyboard shortcuts should also update help
r15770 this.add_shortcut(shortcut, data[shortcut], true);
Brian E. Granger
Creating new base/js/keyboard.js
r15615 }
Paul Ivanov
update notebook quickhelp on new shortcuts
r15769 // update the keyboard shortcuts notebook help
Jonathan Frederic
Almost done!...
r17198 this.events.trigger('rebuild.QuickHelp');
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 };
Brian E. Granger
Creating new base/js/keyboard.js
r15615
Paul Ivanov
removing keyboard shortcuts should also update help
r15770 ShortcutManager.prototype.remove_shortcut = function (shortcut, suppress_help_update) {
Brian E. Granger
Adding utility functions.
r15616 shortcut = normalize_shortcut(shortcut);
Brian E. Granger
Creating new base/js/keyboard.js
r15615 delete this._counts[shortcut];
delete this._shortcuts[shortcut];
Paul Ivanov
removing keyboard shortcuts should also update help
r15770 if (!suppress_help_update) {
// update the keyboard shortcuts notebook help
Jonathan Frederic
Almost done!...
r17198 this.events.trigger('rebuild.QuickHelp');
Paul Ivanov
removing keyboard shortcuts should also update help
r15770 }
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 };
Brian E. Granger
Creating new base/js/keyboard.js
r15615
ShortcutManager.prototype.count_handler = function (shortcut, event, data) {
Matthias BUSSONNIER
Update to codemirror 4...
r18280 /**
* 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}
*/
Brian E. Granger
Creating new base/js/keyboard.js
r15615 var that = this;
var c = this._counts;
var t = this._timers;
var timer = null;
if (c[shortcut] === data.count-1) {
c[shortcut] = 0;
Jonathan Frederic
Almost done!...
r17198 timer = t[shortcut];
Brian E. Granger
Creating new base/js/keyboard.js
r15615 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;
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 };
Brian E. Granger
Creating new base/js/keyboard.js
r15615
ShortcutManager.prototype.call_handler = function (event) {
Matthias BUSSONNIER
Update to codemirror 4...
r18280 /**
* Call the corresponding shortcut handler for a keyboard event
* @method call_handler
* @return {Boolean} `true|false`, `false` if no handler was found, otherwise the value return by the handler.
* @param event {event}
*/
Brian E. Granger
Adding utility functions.
r15616 var shortcut = event_to_shortcut(event);
Brian E. Granger
Creating new base/js/keyboard.js
r15615 var data = this._shortcuts[shortcut];
if (data) {
Jonathan Frederic
Almost done!...
r17198 var handler = data.handler;
Brian E. Granger
Creating new base/js/keyboard.js
r15615 if (handler) {
if (data.count === 1) {
return handler(event);
} else if (data.count > 1) {
return this.count_handler(shortcut, event, data);
}
}
}
return true;
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 };
Brian E. Granger
Creating new base/js/keyboard.js
r15615
Paul Ivanov
renamed 'use_shortcut' method to 'handles'
r15823 ShortcutManager.prototype.handles = function (event) {
Paul Ivanov
added new use_shortcut method to shortcuts...
r15758 var shortcut = event_to_shortcut(event);
var data = this._shortcuts[shortcut];
Jonathan Frederic
Almost done!...
r17198 return !( data === undefined || data.handler === undefined );
};
Paul Ivanov
added new use_shortcut method to shortcuts...
r15758
Jonathan Frederic
More review changes
r17214 var keyboard = {
Brian E. Granger
Creating new base/js/keyboard.js
r15615 keycodes : keycodes,
inv_keycodes : inv_keycodes,
Brian E. Granger
Adding utility functions.
r15616 ShortcutManager : ShortcutManager,
normalize_key : normalize_key,
normalize_shortcut : normalize_shortcut,
shortcut_to_event : shortcut_to_event,
Jonathan Frederic
Partial fix of problems b/c keydown move
r15940 event_to_shortcut : event_to_shortcut
Paul Ivanov
semicolon fixes buttress half of my js commits
r15840 };
Jonathan Frederic
More review changes
r17214
Matthias BUSSONNIER
Update to codemirror 4...
r18280 // For backwards compatibility.
Jonathan Frederic
More review changes
r17214 IPython.keyboard = keyboard;
return keyboard;
Jonathan Frederic
Almost done!...
r17198 });