Jekyll Micro extension for Jupyter Notebooks

3 minute read | Updated:

I got tired of cleaning up my Jupyter-created HTML to go into my Jekyll blog, so I created a custom JavaScript function to do it for me.
I put the following code in my `~/.jupyter/custom/custom.js` file that gets run at the start of each notebook.
First, define a function that will initialize the download prompt:

I got tired of cleaning up my Jupyter-created HTML to go into my Jekyll blog, so I created a custom JavaScript function to do it for me.

I put the following code in my ~/.jupyter/custom/custom.js file that gets run at the start of each notebook.

First, define a function that will initialize the download prompt:

In [2]:
function download(data, filename, type) {
    var a = document.createElement("a"),
        file = new Blob([data], {type: type});
    if (window.navigator.msSaveOrOpenBlob) // IE10+
        window.navigator.msSaveOrOpenBlob(file, filename);
    else { // Others
        var url = URL.createObjectURL(file);
        a.href = url;
        a.download = filename;
        document.body.appendChild(a);
        a.click();
        setTimeout(function() {
            document.body.removeChild(a);
            window.URL.revokeObjectURL(url);  
        }, 0); 
    }
}
Then you'll append a `btn-group` to `#maintoolbar-container`:

Then you'll append a btn-group to #maintoolbar-container:

In [3]:
$([IPython.events]).on('app_initialized.NotebookApp', function(){
    // append your btn-group
    $('#maintoolbar-container')
        .append('<div id="jekyllExport" class="btn-group">'
                + '<a class="btn btn-default btn-md" title="Export as Jekyll blog post">eJekt</a>'
                + '</div>');
    $('#jekyllExport')
        .on('click', function(){
            var notebook = $('#notebook-container'); 
            // clean up your HTML
            notebook.find('.ctb_hideshow').remove();
            notebook.find('.CodeMirror-hscrollbar').remove();
            notebook.find('.CodeMirror-cursor').remove();
            notebook.find('.CodeMirror-scroll').each(function(index){
                $(this).children().eq(1).remove();
            });
            var HTMLString = '<link rel="stylesheet" type="text/css" href="/assets/css/ipython.css">'
                             + notebook[0].innerHTML
                                .replace(/out_prompt_overlay/g, '')
                                .replace(/output_scroll/g, '')
                                .replace(/selected/g, '')
                                .replace(/tabindex/g, 'tabs');
        
            var currentDate = new Date(),
                year = currentDate.getFullYear(),
                month = currentDate.getMonth(),
                day = currentDate.getDay();
            var titleDate = String(year) + '-' 
                + String(month) + '-' + String(day) 
                + '-JekyllPost.html';
            download(HTMLString, titleDate, 'html');
        }
    );
});
Notice the `$('#maintoolbar-container').append` is in an `app_initialized.NotebookApp` event. This is one of many JavaScript events that you can tap into. Others can be found [here](http://jupyter.readthedocs.io/en/latest/development_guide/js_events.html).
Enjoy!

Notice the $('#maintoolbar-container').append is in an app_initialized.NotebookApp event. This is one of many JavaScript events that you can tap into. Others can be found here.

Enjoy!

# Update

Update

xxxxxxxxxx
Now you can put post-specific, custom CSS in your Jupyter notebook, as well as the front matter details, that will then be injected into your blog post. 
First, put these lines of code in your original `IPython.events` function:

Now you can put post-specific, custom CSS in your Jupyter notebook, as well as the front matter details, that will then be injected into your blog post.

First, put these lines of code in your original IPython.events function:

In [9]:
// new lines of code
var notebookHTML = notebook[0].innerHTML;
if (notebookHTML.match(/__FRONT_MATTER__/)){
    var customFrontMatterDiv = $('div.cell:contains("__FRONT_MATTER__")');
    customFrontMatterString = customFrontMatterDiv[0].innerText
                                .replace(/__FRONT_MATTER__/g, '')
                                .replace(/^\s+/, '');
    notebook.find('div.cell:contains("__FRONT_MATTER__")').remove();
}
if (notebookHTML.match(/__CUSTOM_CSS__/)) {
    var customCSSDiv = $('div.cell:contains("__CUSTOM_CSS__")');
    customCSSString = '<style>' + customCSSDiv[0].innerText.replace(/__CUSTOM_CSS__/g, '') + '</style>';
    notebook.find('div.cell:contains("__CUSTOM_CSS__")').remove();
}
notebookHTML = notebook[0].innerHTML; // end new lines of code
xxxxxxxxxx
Like this:

Like this:

In [5]:
$([IPython.events]).on('app_initialized.NotebookApp', function(){
    // append your btn-group
    $('#maintoolbar-container')
        .append('<div id="jekyllExport" class="btn-group">'
                + '<a class="btn btn-default btn-md" title="Export as Jekyll blog post">eJekt</a>'
                + '</div>');
    $('#jekyllExport')
        .on('click', function(){
            var notebook = $('#notebook-container'); 
            // clean up your HTML
            notebook.find('.ctb_hideshow').remove();
            notebook.find('.CodeMirror-hscrollbar').remove();
            notebook.find('.CodeMirror-cursor').remove();
            notebook.find('.CodeMirror-scroll').each(function(index){
                $(this).children().eq(1).remove();
            });
            
            // new lines of code
            var notebookHTML = notebook[0].innerHTML;
            if (notebookHTML.match(/__FRONT_MATTER__/)){
                var customFrontMatterDiv = $('div.cell:contains("__FRONT_MATTER__")');
                customFrontMatterString = customFrontMatterDiv[0].innerText
                                            .replace(/__FRONT_MATTER__/g, '')
                                            .replace(/^\s+/, '');
                notebook.find('div.cell:contains("__FRONT_MATTER__")').remove();
            }
            if (notebookHTML.match(/__CUSTOM_CSS__/)) {
                var customCSSDiv = $('div.cell:contains("__CUSTOM_CSS__")');
                customCSSString = '<style>' + customCSSDiv[0].innerText.replace(/__CUSTOM_CSS__/g, '') + '</style>';
                notebook.find('div.cell:contains("__CUSTOM_CSS__")').remove();
            }
            notebookHTML = notebook[0].innerHTML; // end new lines of code
            var HTMLString = '<link rel="stylesheet" type="text/css" href="/assets/css/ipython.css">'
                             + notebook[0].innerHTML
                                .replace(/out_prompt_overlay/g, '')
                                .replace(/output_scroll/g, '')
                                .replace(/selected/g, '')
                                .replace(/tabindex/g, 'tabs');
        
            var currentDate = new Date(),
                year = currentDate.getFullYear(),
                month = currentDate.getMonth(),
                day = currentDate.getDay();
            var titleDate = String(year) + '-' 
                + String(month) + '-' + String(day) 
                + '-JekyllPost.html';
            download(HTMLString, titleDate, 'html');
        }
    );
});
xxxxxxxxxx
Now, just use the following syntax to inject your custom CSS and front matter details. I plan to add custom JavaScript soon.

Now, just use the following syntax to inject your custom CSS and front matter details. I plan to add custom JavaScript soon.

__CUSTOM_CSS__
div.output_area {
    max-height: 400px;
}
div.input_area {
    margin: 5px;
}
__FRONT_MATTER__
---
title: Jekyll Micro extension for Jupyter Notebooks
author_profile: true
author: Tim Dobbins
excerpt: I got tired of cleaning up my Jupyter-created HTML to go into my Jekyll blog, so I created a custom JavaScript function to do it for me.
categories: [tools]
tags: [jekyll, python, jupyter-notebook]
---