Notebook javascript API

There is a 'pythonic' javascript API in the notebook. From this API you can access code mirror configuration, you can add buttons to the toolbar, enable or disable some code cells,...

Some examples


Add line numbers on each cell

Add line number to new cells:

IPython.Cell.options_default.cm_config.lineNumbers = true;

or only to new code cells:

IPython.CodeCell.options_default.cm_config.lineNumbers = true;
In [ ]:
%%javascript
IPython.CodeCell.options_default.cm_config.lineNumbers = false;

Cursor blink (extracted from http://pirsquared.org/blog/notebook-blink.html)

In [ ]:
%%javascript
var rate = 530; // default in codemirror is 530ms
// apply setting to  all current CodeMirror instances
IPython.notebook.get_cells().map(
    function(c) {  return c.code_mirror.options.cursorBlinkRate=rate;  }
);

// make sure new CodeMirror instance also use this setting
CodeMirror.defaults.cursorBlinkRate = rate;

Listening the content of cells using a shortcut and the new HTML5 SpeechAPI

This functionality has been tested only on modern Chrome versions. I think the latest Firefox nightly build (2014/11/08) allows you to use this API but I didn't find the time to test it on firefox.

You can easily add new shortcuts to include new functionality using the js IPython API.

In [ ]:
%%javascript
IPython.keyboard_manager.command_shortcuts.add_shortcut("Ctrl-Shift-Alt-h", {
    help : 'Talking cells',
    help_index : 'zzz',
    handler : function() { 
        var input = IPython.notebook.get_selected_cell().get_text();
        var msg = new SpeechSynthesisUtterance();
        msg.text = input;
        msg.lang = "es-ES";
        msg.voiceURI = 'native';
        msg.volume = 1; // 0 to 1
        msg.rate = 0.5; // 0.1 to 10
        msg.pitch = 2; //0 to 2
        window.speechSynthesis.speak(msg);
        return false;
    }}
);

To disable the recently created shortcut:

In [ ]:
%%javascript
IPython.keyboard_manager.command_shortcuts.remove_shortcut('Ctrl-Shift-Alt-h');

A shortcut for simple things

Lets add a shortcut to clear all outputs so we don't have to use the top menus

In [ ]:
%%javascript
IPython.keyboard_manager.command_shortcuts.add_shortcut("Ctrl-Shift-Alt-h", {
    help : 'Clear all output',
    help_index : 'zzz',
    handler : function() { 
        // to clear all the outputs
        IPython.notebook.clear_all_output();         
        return false;
    }}
);
In [ ]:
%%javascript
IPython.keyboard_manager.command_shortcuts.remove_shortcut('Ctrl-Shift-Alt-h');

You can change the content inside the function with other stuff:

// see http://codemirror.net/mode/ to change the syntax higlighting/codecompletion
IPython.notebook.set_codemirror_mode('ipython');

// Scroll to top
IPython.notebook.scroll_to_top();

// Scroll to bottom
IPython.notebook.scroll_to_bottom();

// To know the number of cells used in the notebook and display it on a pop-up window:
number = IPython.notebook.ncells();
alert(number);

// Execute all the cells
IPython.notebook.execute_all_cells();

...
In the notebook you have two modes: ***edit*** and ***command***. You can add shortcuts when you are in a mode or in the other so if the shortcut is created to work only in a mode while you are in the other mode the shortcut will not work.
In [ ]:
%%javascript

IPython.keyboard_manager.command_shortcuts.add_shortcut('Ctrl-Alt-c', {
    help : 'clear all outputs',
    help_index : 'zzz',
    handler : function (event) {
        IPython.notebook.clear_all_output();    
        return false;
    }}
);
IPython.keyboard_manager.edit_shortcuts.add_shortcut('Ctrl-Alt-c', {
    help : 'clear all outputs',
    help_index : 'zzz',
    handler : function (event) {
        IPython.notebook.clear_all_output();    
        return false;
    }}
);
In [ ]:
%%javascript

IPython.keyboard_manager.command_shortcuts.remove_shortcut('Ctrl-Alt-c');
IPython.keyboard_manager.edit_shortcuts.remove_shortcut('Ctrl-Alt-c');

Go deeper with shortcuts


Custom.js and Custom.css

If you want that some of the modifications you made will be available when a notebook is opened you can use the file custom.js available on each profile. Also, if you want to modify the look you can use the file custom.css

We can add the ruler option to the custom.js file of the created pycones14 profile in previous notebooks.

In [ ]:
profile_dir = !ipython locate profile pycones14
profile_dir = profile_dir[0]
profile_dir

We will load the custom.js file of the pycones14 profile, the loaded code will be saved using %%writefile magic and with the updated custom.js file we will open a new notebook for that profile to see how the changes are applied.

In [ ]:
%load $profile_dir/static/custom/custom.js
In [ ]:
%%writefile $profile_dir/static/custom/custom.js
// leave at least 2 line with only a star on it below, or doc generation fails
/**
 *
 *
 * Placeholder for custom user javascript
 * mainly to be overridden in profile/static/custom/custom.js
 * This will always be an empty file in IPython
 *
 * User could add any javascript in the `profile/static/custom/custom.js` file
 * (and should create it if it does not exist).
 * It will be executed by the ipython notebook at load time.
 *
 * Same thing with `profile/static/custom/custom.css` to inject custom css into the notebook.
 * 
 * Classes and functions are available at load time and may be accessed plainly: 
 * 
 *     IPython.Cell.options_default.cm_config.extraKeys['Home'] = 'goLineLeft';
 *     IPython.Cell.options_default.cm_config.extraKeys['End'] = 'goLineRight';
 * 
 * Instances are created later however and must be accessed using events:
 * 
 *     $([IPython.events]).on("app_initialized.NotebookApp", function () {
 *         IPython.keyboard_manager....
 *     });
 *
 * __Example 1:__
 *
 * Create a custom button in toolbar that execute `%qtconsole` in kernel
 * and hence open a qtconsole attached to the same kernel as the current notebook
 *
 *    IPython.events.on('app_initialized.NotebookApp', function(){
 *        IPython.toolbar.add_buttons_group([
 *            {
 *                 'label'   : 'run qtconsole',
 *                 'icon'    : 'icon-terminal', // select your icon from http://fortawesome.github.io/Font-Awesome/icons
 *                 'callback': function () {
 *                     IPython.notebook.kernel.execute('%qtconsole')
 *                 }
 *            }
 *            // add more button here if needed.
 *            ]);
 *    });
 *
 * __Example 2:__
 *
 * At the completion of the dashboard loading, load an unofficial javascript extension
 * that is installed in profile/static/custom/ 
 *
 *    IPython.events.on('app_initialized.DashboardApp', function(){
 *        require(['custom/unofficial_extension.js'])
 *    });
 *
 * __Example 3:__
 *
 *  Use `jQuery.getScript(url [, success(script, textStatus, jqXHR)] );`
 *  to load custom script into the notebook.
 *
 *    // to load the metadata ui extension example.
 *    $.getScript('/static/notebook/js/celltoolbarpresets/example.js');
 *    // or
 *    // to load the metadata ui extension to control slideshow mode / reveal js for nbconvert
 *    $.getScript('/static/notebook/js/celltoolbarpresets/slideshow.js');
 *
 *
 * @module IPython
 * @namespace IPython
 * @class customjs
 * @static
 */

$([IPython.events]).on("app_initialized.NotebookApp", function () {    
        
    var colors = [["Red", "PaleVioletRed"],
                  ["Orange", "DarkOrange"], 
                  ["Green", "LightGreen"], 
                  ["None", "#F7F7F7"]];
        
    var cell_flag_init = IPython.CellToolbar.utils.select_ui_generator(
 
        // List
        colors, 
        // Setter, called when the select state has been changed.  
        // Sets the color of the cell background
        // add the color value in the cell's metadata.
        function(cell, value){
            if (cell.metadata.bgcolor == undefined){
                cell.metadata.bgcolor = {};
            }
            cell.metadata.bgcolor = value;
            var prompt = cell.element.find('div.input_area');
            prompt.css("background-color", value);
        },
 
        // Getter, called when the control is rendered.  Determines the initial
        // state of the checkbox.  If the flag doesn't in the metadata, default
        // to false.
        function(cell){
            if (cell.metadata.bgcolor === undefined || cell.metadata.bgcolor == false) {
                return "default";
            } else {
                return cell.metadata.bgcolor;
            }
        },
        // Label
        "Choose bg color"
    );

    IPython.CellToolbar.register_callback("choose_bg_color", cell_flag_init);
 
    // Create and register the toolbar with IPython.
    IPython.CellToolbar.register_preset('Choose bg color', ["choose_bg_color"]);
    console.log("Background colors modifications loaded")
        
});

$([IPython.events]).on('notebook_loaded.Notebook', function(){
        
    var cells = IPython.notebook.get_cells();
    for(var i in cells){
        var cell = cells[i];
        if (cell.metadata.bgcolor){
            var prompt = cell.element.find('div.input_area');
            prompt.css("background-color", cell.metadata.bgcolor);
        }
    }
        
});

... things happened in the live talk ...

More