Skip to content

Commit

Permalink
Merge pull request #260 from Carreau/typeahead
Browse files Browse the repository at this point in the history
Command Palette on notebook.
  • Loading branch information
jdfreder committed Aug 14, 2015
2 parents 4f3c65d + 589dce3 commit 309dab2
Show file tree
Hide file tree
Showing 18 changed files with 329 additions and 52 deletions.
3 changes: 2 additions & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"requirejs": "~2.1",
"term.js": "chjj/term.js#~0.0.4",
"text-encoding": "~0.1",
"underscore": "components/underscore#~1.5"
"underscore": "components/underscore#~1.5",
"jquery-typeahead": "~2.0.0"
}
}
1 change: 0 additions & 1 deletion notebook/services/contents/filemanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ def _post_save_script(model, os_path, contents_manager, **kwargs):
log = contents_manager.log

base, ext = os.path.splitext(os_path)
py_fname = base + '.py'
script, resources = _script_exporter.from_filename(os_path)
script_fname = base + resources.get('output_extension', '.txt')
log.info("Saving script /%s", to_api_path(script_fname, contents_manager.root_dir))
Expand Down
25 changes: 18 additions & 7 deletions notebook/static/base/js/keyboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ define([

/**
* 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
Expand Down Expand Up @@ -48,12 +48,12 @@ define([

// These apply to Firefox and Opera
var _mozilla_keycodes = {
'; :': 59, '= +': 61, '- _': 173, 'meta': 224
'; :': 59, '= +': 61, '- _': 173, 'meta': 224, 'minus':173
};

// This apply to Webkit and IE
var _ie_keycodes = {
'; :': 186, '= +': 187, '- _': 189
'; :': 186, '= +': 187, '- _': 189, 'minus':189
};

var browser = utils.browser[0];
Expand Down Expand Up @@ -105,7 +105,7 @@ define([
}

shortcut = shortcut.toLowerCase().replace('cmd', 'meta');
shortcut = shortcut.replace(/-$/, '_'); // catch shortcuts using '-' key
shortcut = shortcut.replace(/-$/, 'minus'); // catch shortcuts using '-' key
shortcut = shortcut.replace(/,$/, 'comma'); // catch shortcuts using '-' key
if(shortcut.indexOf(',') !== -1){
var sht = shortcut.split(',');
Expand All @@ -130,7 +130,7 @@ define([
**/
type = type || 'keydown';
shortcut = normalize_shortcut(shortcut);
shortcut = shortcut.replace(/-$/, '_'); // catch shortcuts using '-' key
shortcut = shortcut.replace(/-$/, 'minus'); // catch shortcuts using '-' key
var values = shortcut.split("-");
var modifiers = values.slice(0,-1);
var key = values[values.length-1];
Expand All @@ -148,7 +148,7 @@ define([
* false otherwise
**/
var key = inv_keycodes[event.which];
return ((event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) &&
return ((event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) &&
(key === 'alt'|| key === 'ctrl'|| key === 'meta'|| key === 'shift'));

};
Expand Down Expand Up @@ -190,7 +190,7 @@ define([
/**
* 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);
Expand Down Expand Up @@ -225,6 +225,17 @@ define([
}
return dct;
};

ShortcutManager.prototype.get_action_shortcut = function(name){
var ftree = flatten_shorttree(this._shortcuts);
var res = {};
for (var sht in ftree ){
if(ftree[sht] === name){
return sht;
}
}
return undefined;
};

ShortcutManager.prototype.help = function () {
var help = [];
Expand Down
4 changes: 3 additions & 1 deletion notebook/static/base/less/variables.less
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
@border-radius-base: 2px;
@border-radius-large: 3px;
@grid-gutter-width: 0px;
@kbd-color: #888;
@kbd-bg: transparent;

@icon-font-path: "../components/bootstrap/fonts/";

// Disable modal slide-in from top animation.
Expand Down Expand Up @@ -57,4 +60,3 @@ label {
// preven container size to jump from 768px to 720px
// when window width go from 768 to 769+
@container-sm : @screen-sm-min;

11 changes: 10 additions & 1 deletion notebook/static/notebook/js/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

define(function(require){
"use strict";

var ActionHandler = function (env) {
this.env = env || {};
Object.seal(this);
Expand Down Expand Up @@ -329,10 +329,19 @@ define(function(require){
handler : function (env) {
env.pager.collapse();
}
},
'command-palette': {
help_index : 'aa',
help: 'open the command palette',
icon: 'fa-search',
handler : function(env){
env.notebook.show_command_palette();
}
}

};


/**
* A bunch of `Advance actions` for Jupyter.
* Cf `Simple Action` plus the following properties.
Expand Down
177 changes: 177 additions & 0 deletions notebook/static/notebook/js/commandpalette.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

define(function(require){
"use strict";

var QH = require("notebook/js/quickhelp");
var $ = require("jquery");

/**
* Humanize the action name to be consumed by user.
* internaly the actions anem are of the form
* <namespace>.<description-with-dashes>
* we drop <namesapce> and replace dashes for space.
*/
var 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.
**/
var get_mode_for_action_id = function(name, notebook) {
var shortcut = notebook.keyboard_manager.command_shortcuts.get_action_shortcut(name);
if (shortcut) {
return 'command-shortcut';
}
shortcut = notebook.keyboard_manager.edit_shortcuts.get_action_shortcut(name);
if (shortcut) {
return 'edit-shortcut';
}
return 'no-shortcut';
};

var CommandPalette = function(notebook) {
if(!notebook){
throw new Error("CommandPalette takes a notebook non-null mandatory arguement");
}

// typeahead lib need a specific layout with specific class names.
// the following just does that
var form = $('<form/>');
var container = $('<div/>').addClass('typeahead-container');
var field = $('<div/>').addClass('typeahead-field');
var input = $('<input/>').attr('type', 'search');

field
.append(
$('<span>').addClass('typeahead-query').append(
input
)
)
.append(
$('<span/>').addClass('typeahead-button').append(
$('<button/>').attr('type', 'submit').append(
$('<span/>').addClass('typeahead-search-icon')
)
)
);

container.append(field);
form.append(container);


var mod = $('<div/>').addClass('modal cmd-palette').append(
$('<div/>').addClass('modal-dialog')
.append(
$('<div/>').addClass('modal-content').append(
$('<div/>').addClass('modal-body')
.append(
form
)
)
)
)
// end setting up right layout
.modal({show: false, backdrop:true})
.on('shown.bs.modal', function () {
// click on button trigger de-focus on mouse up.
// or somethign like that.
setTimeout(function(){input.focus();}, 100);
})
.on("hide.bs.modal", before_close);

notebook.keyboard_manager.disable();

var before_close = function() {
// little trick to trigger early in onsubmit
// when the action called pop-up a dialog
// insure this function is only called once
if (before_close.ok) {
return;
}
var cell = notebook.get_selected_cell();
if (cell) {
cell.select();
}
if (notebook.keyboard_manager) {
notebook.keyboard_manager.enable();
notebook.keyboard_manager.command_mode();
}
before_close.ok = true; // avoid double call.
};

// will be trigger when user select action
var onSubmit = function(node, query, result, resultCount) {
if (actions.indexOf(result.key) >= 0) {
before_close();
notebook.keyboard_manager.actions.call(result.key);
} else {
console.warning("No command " + result.key);
}
mod.modal('hide');
};

// generate structure needed for typeahead layout and ability to search
var src = {};

var actions = Object.keys(notebook.keyboard_manager.actions._actions);

for (var i = 0; i < actions.length; i++) {
var action_id = actions[i];
var action = notebook.keyboard_manager.actions.get(action_id);
var group = action_id.split('.')[0];
if (group === 'ipython') {
group = 'built-in';
}

src[group] = src[group] || {
data: [],
display: 'display'
};

var short = notebook.keyboard_manager.command_shortcuts.get_action_shortcut(action_id) ||
notebook.keyboard_manager.edit_shortcuts.get_action_shortcut(action_id);
if (short) {
short = QH.humanize_sequence(short);
}

src[group].data.push({
display: humanize_action_id(action_id),
shortcut: short,
mode_shortcut: get_mode_for_action_id(action_id, notebook),
group: group,
icon: action.icon,
help: action.help,
key: action_id,
});
}

// now src is the right structure for typeahead


input.typeahead({
emptyTemplate: "No results found for <pre>{{query}}</pre>",
maxItem: 1e3,
minLength: 0,
hint: true,
group: ["group", "{{group}} extension"],
searchOnFocus: true,
mustSelectItem: true,
template: '<i class="fa fa-icon {{icon}}"></i>{{display}} <div class="pull-right {{mode_shortcut}}">{{shortcut}}</div>',
order: "asc",
source: src,
callback: {
onSubmit: onSubmit,
onClickAfter: onSubmit
},
debug: false,
});

mod.modal('show');
};
return {'CommandPalette': CommandPalette};
});
2 changes: 2 additions & 0 deletions notebook/static/notebook/js/keyboardmanager.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ define([

KeyboardManager.prototype.get_default_edit_shortcuts = function() {
return {
'cmdtrl-shift-p' : 'ipython.command-palette',
'esc' : 'ipython.go-to-command-mode',
'ctrl-m' : 'ipython.go-to-command-mode',
'up' : 'ipython.move-cursor-up-or-previous-cell',
Expand All @@ -84,6 +85,7 @@ define([

KeyboardManager.prototype.get_default_command_shortcuts = function() {
return {
'cmdtrl-shift-p': 'ipython.command-palette',
'shift-space': 'ipython.scroll-up',
'shift-v' : 'ipython.paste-cell-before',
'shift-m' : 'ipython.merge-selected-cells',
Expand Down
2 changes: 2 additions & 0 deletions notebook/static/notebook/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ require([
'notebook/js/kernelselector',
'codemirror/lib/codemirror',
'notebook/js/about',
'typeahead',
// only loaded, not used, please keep sure this is loaded last
'custom/custom'
], function(
Expand All @@ -45,6 +46,7 @@ require([
kernelselector,
CodeMirror,
about,
typeahead,
// please keep sure that even if not used, this is loaded last
custom
) {
Expand Down
3 changes: 2 additions & 1 deletion notebook/static/notebook/js/maintoolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ define([
],
'run_int'],
['<add_celltype_list>'],
['<add_celltoolbar_list>']
['<add_celltoolbar_list>'],
[['ipython.command-palette']]
];
this.construct(grps);
};
Expand Down
9 changes: 8 additions & 1 deletion notebook/static/notebook/js/notebook.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ define(function (require) {
var rawcell_celltoolbar = require('notebook/js/celltoolbarpresets/rawcell');
var slideshow_celltoolbar = require('notebook/js/celltoolbarpresets/slideshow');
var scrollmanager = require('notebook/js/scrollmanager');
var commandpalette = require('notebook/js/commandpalette');

/**
* Contains and manages cells.
Expand Down Expand Up @@ -170,7 +171,8 @@ define(function (require) {
// i) provide a margin between the last cell and the end of the notebook
// ii) to prevent the div from scrolling up when the last cell is being
// edited, but is too low on the page, which browsers will do automatically.
var end_space = $('<div/>').addClass('end_space');
var end_space = $('<div/>')
.addClass('end_space');
end_space.dblclick(function (e) {
var ncells = that.ncells();
that.insert_cell_below('code',ncells-1);
Expand Down Expand Up @@ -319,6 +321,11 @@ define(function (require) {
};
};


Notebook.prototype.show_command_palette = function() {
var x = new commandpalette.CommandPalette(this);
}

/**
* Trigger a warning dialog about missing functionality from newer minor versions
*/
Expand Down

0 comments on commit 309dab2

Please sign in to comment.