Extending nbpresent

The nbpresent JavaScript runtime application (both the presenter and the authoring application) is built on:

  • d3
  • baobab
  • the Jupyter notebook!
  • webfontloader

Let's look at what each provides.

the Notebook

The notebook is a:

  • source of underlying truth
  • storage layer (in notebook and cell metadata)
  • convenient API for common things like keyboard shortcuts

baobab

The data for a presentation is, at runtime, stored in a Baobab tree. Baobab lets your UI rendering subscribe to subsets of your data, as well as embed data-only mutations as monkeys.

For hacking purposes, you can access the nbpresent tree from window.global. However, when writing "real code", use requirejs and a Promise


In [3]:
%%javascript
console.log(nbpresent.mode.tree.get());
require(["nbextensions/nbpresent/js/nbpresent.min"], function(nbpresent){
    nbpresent.initialized().then(function(nbp){
        console.log(nbp.tree.get());
    })
});


d3

d3 is what usually moves the actual DOM around on the page, and handles whether new elements should be created, updated or removed.

hammer

Making a new Theme

An easy way to add new content to nbpresent, both the Authoring environment and the presentation itself, is by working with the Baobab tree.

app.theme-manager.themes

If defined in the tree, whenever the theme manager shows the Community Themes, your theme will be displayed and available for copying into a presentation for modification.


In [4]:
%%javascript
nbpresent.mode.tree.set(
    ["app", "theme-manager", "themes", "my-theme"], 
    {
    palette: {
        "my-blue": {
            id: "my-blue",
            rgb: [0, 0, 255]
        },
        "my-black": {
            id: "my-black",
            rgb: [0, 0, 0]
        }
    },
    backgrounds: {
        "my-background": {
            "background-color": "my-black"
        }
    },
    "text-base": {
        "font-family": "Anonymous Pro",
        "font-size": 5
    },
    rules: {
        h1: {
            "font-size": 7,
            color: "my-blue"
        }
    }
});


If you want to do this at start-up time, you can listen for when nbpresent has initialized, a la custom.js.


In [5]:
%%javascript
require(["nbextensions/nbpresent/js/nbpresent.min"], function(nbpresent){
    nbpresent.initialized().then(function(nbpresent){
        // then do your thing
    });
});


Or in an nbextension that you plan to jupyter nbextension enable:


In [6]:
%%javascript
define(["nbextensions/nbpresent/js/nbpresent.min"], function(nbpresent){
    return {
        load_ipython_extension: function(){
            nbpresent.initialized().then(function(nbpresent){
                // then do your thing
            });
        }
    }
});


Importing themes from other notebooks


In [7]:
%%javascript
require([
    "underscore", "nbextensions/nbpresent/js/nbpresent.min"
], function(_, nbpresent){
    var base = Jupyter.notebook.base_url + "api/contents";

    $.get(base)
        .done(function(contents){
            nbpresent.initialized().then(function(nbpresent){
                var themes = nbpresent.mode.tree.select(["app", "theme-manager", "themes"]);
                
                if(!(themes.exists())){
                    themes.set({});
                }
                
                _.chain(contents.content)
                    .where({type: "notebook"})
                    .map(function(nb){
                        $.get(base + "/" + nb.path)
                            .done(function(ipynb){
                                var md = ipynb.content.metadata.nbpresent;
                                md = md && md.themes && md.themes.theme;
                                console.log(md);

                                md && themes.deepMerge(md);
                            })
                     });
            });
        });
});