and replace dashes for space.
+ */
+ const humanize_action_id = function(str) {
+ return str.split(':')[1].replace(/-/g, ' ').replace(/_/g, '-');
+ };
+
+ /**
+ * given an action id return 'command-shortcut', 'edit-shortcut' or 'no-shortcut'
+ * for the action. This allows us to tag UI in order to visually distinguish
+ * Wether an action have a keybinding or not.
+ **/
+
+ const KeyBinding = React.createClass({
+ displayName: 'KeyBindings',
+ getInitialState: function() {
+ return {shrt:''};
+ },
+ handleShrtChange: function (element){
+ this.setState({shrt:element.target.value});
+ },
+ render: function(){
+ const that = this;
+ const av = this.props.available(this.state.shrt);
+ const empty = this.state.shrt === '';
+ return React.createElement('div',{style:{borderBottom: '1px solid gray'}, className:'jupyter-keybindings'},
+ this.props.shortcut?
+ React.createElement('i', {className: "pull-right fa fa-times", alt: 'remove title'+this.props.shortcut,
+ onClick:()=>{
+ that.props.unbind(this.props.rawshrt);
+ }}):
+ React.createElement('i', {className: "pull-right fa fa-plus", alt: 'add-keyboard-shortcut',
+ onClick:()=>{
+ av?that.props.onAddBindings(that.state.shrt, that.props.ckey):null;
+ }
+ }),
+ this.props.shortcut? null:
+ React.createElement('input', {
+ type:'text',
+ placeholder:'add shortcut',
+ className:'pull-right'+((av||empty)?'':' alert alert-danger'),
+ value:this.state.shrt,
+ onChange:this.handleShrtChange
+ }),
+ this.props.shortcut? React.createElement('span', {className: 'pull-right'}, React.createElement('kbd', {}, this.props.shortcut)): null,
+ React.createElement('div', {title: '(' +this.props.ckey + ')' , className:'jupyter-keybindings-text'}, this.props.display )
+ );
+ }
+ });
+
+ const KeyBindingList = React.createClass({
+ displayName: 'KeyBindingList',
+ getInitialState: function(){
+ return {data:[]};
+ },
+ componentDidMount: function(){
+ this.setState({data:this.props.callback()});
+ },
+ render: function() {
+ const childrens = this.state.data.map((binding)=>{
+ return React.createElement(KeyBinding, Object.assign({}, binding, {onAddBindings:(shortcut, action)=>{
+ this.props.bind(shortcut, action);
+ this.setState({data:this.props.callback()});
+ },
+ available:this.props.available,
+ unbind: (shortcut) => {
+ this.props.unbind(shortcut);
+ this.setState({data:this.props.callback()});
+ }
+ }));
+ });
+
+ childrens.unshift(React.createElement('div', {className:'alert alert-info', key:'disclamer'},
+ "This dialog shoudl allow you to modify your keymap, and persist the changes."+
+ "This functionality is not feature complete, and will likely not function in all the cases."+
+ "You can define many type of shorctuts or sequence of keys. Here are various valid shortcuts sequences: a,a"+
+ "-- Shift-A,Shift-B -- Shift-A,a -- "+
+ "Casing will have no effect, you need to explicitelty write the `Shift` modifier,"+
+ " `Cmd`, `Ctrl`, `Meta`, `Cmdtrl` are various valid modifier. Refer to developper docs for their signification depending on teh platform"));
+ return React.createElement('div',{}, childrens);
+ }
+ });
+
+ const get_shortcuts_data = function(notebook) {
+ const actions = Object.keys(notebook.keyboard_manager.actions._actions);
+ const src = [];
+
+ for (let i = 0; i < actions.length; i++) {
+ const action_id = actions[i];
+ const action = notebook.keyboard_manager.actions.get(action_id);
+
+ let shortcut = notebook.keyboard_manager.command_shortcuts.get_action_shortcut(action_id);
+ let hshortcut;
+ if (shortcut) {
+ hshortcut = QH._humanize_sequence(shortcut);
+ }
+
+ src.push({
+ display: humanize_action_id(action_id),
+ shortcut: hshortcut,
+ rawshrt: shortcut,
+ key:action_id, // react specific thing
+ ckey: action_id
+ });
+ }
+ return src;
+ };
+
+
+ const ShortcutEditor = function(notebook) {
+
+ if(!notebook){
+ throw new Error("CommandPalette takes a notebook non-null mandatory arguement");
+ }
+
+ const body = $('');
+ const mod = dialog.modal({
+ notebook: notebook,
+ keyboard_manager: notebook.keyboard_manager,
+ title : "Edit Command mode Shortcuts",
+ body : body,
+ buttons : {
+ OK : {}
+ }
+ });
+
+ const src = get_shortcuts_data(notebook);
+
+ mod.addClass("modal_stretch");
+
+ mod.modal('show');
+ ReactDom.render(
+ React.createElement(KeyBindingList, {
+ callback:()=>{ return get_shortcuts_data(notebook);},
+ bind: (shortcut, command) => {
+ return notebook.keyboard_manager.command_shortcuts._persist_shortcut(shortcut, command);
+ },
+ unbind: (shortcut) => {
+ return notebook.keyboard_manager.command_shortcuts._persist_remove_shortcut(shortcut);
+ },
+ available: (shrt) => { return notebook.keyboard_manager.command_shortcuts.is_available_shortcut(shrt);}
+ }),
+ body.get(0)
+ );
+ };
+ return {'ShortcutEditor': ShortcutEditor};
+});
diff --git a/notebook/static/notebook/less/notebook.less b/notebook/static/notebook/less/notebook.less
index 2c3e8e6a3f..90c7a57b24 100644
--- a/notebook/static/notebook/less/notebook.less
+++ b/notebook/static/notebook/less/notebook.less
@@ -99,3 +99,18 @@ kbd {
padding-top: 1px;
padding-bottom: 1px;
}
+
+.jupyter-keybindings {
+ padding: 0px;
+ line-height: 24px;
+}
+
+.jupyter-keybindings input {
+ margin: 0;
+ padding: 0;
+ border: none;
+}
+
+.jupyter-keybindings i {
+ padding: 6px;
+}
diff --git a/package.json b/package.json
index 2ba8b0f5f6..f2816fd246 100644
--- a/package.json
+++ b/package.json
@@ -15,15 +15,20 @@
"build:css": "python setup.py css",
"build:css:watch": "echo Not implemented yet...",
"build:js": "webpack",
- "build:js:watch": "npm run build:js -- --watch"
+ "build:js:watch": "npm run build:js -- --watch --progress --color"
},
"devDependencies": {
+ "babel-core": "^6.7.4",
+ "babel-loader": "^6.2.4",
+ "babel-preset-es2015": "^6.6.0",
"bower": "*",
"concurrently": "^1.0.0",
"less": "~2",
"requirejs": "^2.1.17",
"underscore": "^1.8.3",
- "webpack": "^1.12.13"
+ "webpack": "^1.12.13",
+ "react": "^0.14.7",
+ "react-dom": "^0.14.7"
},
"dependencies": {
"moment": "^2.8.4"
diff --git a/webpack.config.js b/webpack.config.js
index 1c6fa8e28b..56e0f53a08 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -14,6 +14,7 @@ var commonConfig = {
},
module: {
loaders: [
+ { test: /\.js$/, exclude: /node_modules|\/notebook\/static\/component/, loader: "babel-loader"},
{ test: /\.css$/, loader: "style-loader!css-loader" },
{ test: /\.json$/, loader: "json-loader" },
// jquery-ui loads some images