Reorganize repository
@@ -5,7 +5,7 @@
|
||||
IPython-contrib is licensed under the terms of the Modified BSD License (also
|
||||
known as New or Revised or 3-Clause BSD), as follows:
|
||||
|
||||
- Copyright (c) 2013-2014, IPython-contrib Developers
|
||||
- Copyright (c) 2013-2015, IPython-contrib Developers
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
||||
@@ -20,19 +20,19 @@ IPython/Jupyter version support
|
||||
There are different branches of the notebook extensions in this repository.
|
||||
Please make sure you use the branch corresponding to your IPython/Jupyter version.
|
||||
|
||||
Overview
|
||||
===========================
|
||||
The repository is organized in different categories:
|
||||
|
||||
| Name | Description |
|
||||
|------------|-------------|
|
||||
| [usability](https://github.com/ipython-contrib/IPython-notebook-extensions/wiki#usability) | Additional functionality for the notebook |
|
||||
| [publishing](https://github.com/ipython-contrib/IPython-notebook-extensions/wiki#publishing) | Getting your notebooks out in the wild |
|
||||
| [styling](https://github.com/ipython-contrib/IPython-notebook-extensions/wiki#styling) | Styling schemes for different looks of the notebook |
|
||||
| [slidemode](https://github.com/ipython-contrib/IPython-notebook-extensions/wiki#slidemode) | Slideshow creation |
|
||||
| [testing](https://github.com/ipython-contrib/IPython-notebook-extensions/wiki#testing) | Extensions in a early stage |
|
||||
|
||||
Documentation
|
||||
=============
|
||||
The extensions are documented in the Wiki. Please take a look [here](https://github.com/ipython-contrib/IPython-notebook-extensions/wiki)
|
||||
Some extensions are not documented. We encourage you to add documentation for them.
|
||||
|
||||
All extensions that are maintained and active have a markdown readme file for documentation and a yaml file to
|
||||
allow them being configured using the 'nbextensions' server extension.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
The simple case: You want to install the extensions as local user. Then, simply run `setup.py` or build
|
||||
a conda package by running `conda build`, and then do a `conda install nbextensions`.
|
||||
|
||||
For more complex installation scenarios, please look up the documentation at the Jupyter homepage http://www.jupyter.org
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ipython install.py
|
||||
@@ -0,0 +1,81 @@
|
||||
# Install notebook extensions
|
||||
|
||||
from jupyter_core.paths import jupyter_config_dir, jupyter_data_dir, jupyter_runtime_dir
|
||||
from traitlets.config.loader import Config, JSONFileConfigLoader
|
||||
import IPython.extensions
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import json
|
||||
|
||||
# http://stackoverflow.com/questions/12683834/how-to-copy-directory-recursively-in-python-and-overwrite-all
|
||||
def recursive_overwrite(src, dest, ignore=None):
|
||||
if os.path.isdir(src):
|
||||
if not os.path.isdir(dest):
|
||||
os.makedirs(dest)
|
||||
files = os.listdir(src)
|
||||
if ignore is not None:
|
||||
ignored = ignore(src, files)
|
||||
else:
|
||||
ignored = set()
|
||||
for f in files:
|
||||
if f not in ignored:
|
||||
recursive_overwrite(os.path.join(src, f),
|
||||
os.path.join(dest, f),
|
||||
ignore)
|
||||
else:
|
||||
shutil.copyfile(src, dest)
|
||||
|
||||
#
|
||||
# Install files
|
||||
#
|
||||
|
||||
# copy extensions to IPython extensions directory
|
||||
extensions = os.path.dirname(IPython.extensions.__file__)
|
||||
src = os.path.join('src','extensions')
|
||||
print("Install extensions to %s" % extensions)
|
||||
recursive_overwrite(src, extensions)
|
||||
|
||||
# Install templates
|
||||
templates = os.path.join(jupyter_data_dir(), 'templates')
|
||||
src = os.path.join('src','templates')
|
||||
print("Install templates to %s" % templates)
|
||||
recursive_overwrite(src, templates)
|
||||
|
||||
# Install nbextensions
|
||||
nbextensions = os.path.join(jupyter_data_dir(), 'nbextensions')
|
||||
src = os.path.join('src','nbextensions')
|
||||
print("Install notebook extensions to %s" % nbextensions)
|
||||
recursive_overwrite(src, nbextensions)
|
||||
|
||||
#
|
||||
# Update nbconvert configuration
|
||||
#
|
||||
fname = os.path.join(jupyter_config_dir(), 'jupyter_nbconvert_config.json')
|
||||
cl = JSONFileConfigLoader(fname)
|
||||
config = cl.load_config()
|
||||
newconfig=Config()
|
||||
# Set template path, pre- and postprocessors of notebook extensions
|
||||
newconfig.Exporter.template_path = [os.path.join(jupyter_data_dir(),'templates') ]
|
||||
newconfig.Exporter.preprocessors = ["codefolding.CodeFoldingPreprocessor", "pymdpreprocessor.PyMarkdownPreprocessor" ]
|
||||
newconfig.NbConvertApp.postprocessor_class = 'embed.EmbedPostProcessor'
|
||||
config.merge(newconfig)
|
||||
config.version = 1
|
||||
s=json.dumps(config, indent=2, separators=(',', ': '), sort_keys=True)
|
||||
with open(fname, 'w') as f:
|
||||
f.write(s)
|
||||
|
||||
#
|
||||
# Update notebook configuration
|
||||
#
|
||||
fname = os.path.join(jupyter_config_dir(), 'jupyter_notebook_config.json')
|
||||
cl = JSONFileConfigLoader(fname, log=log)
|
||||
config = cl.load_config()
|
||||
newconfig=Config()
|
||||
# Add server extension of /nbextension/ configuration tool
|
||||
newconfig.NotebookApp.server_extensions = [ "nbextensions" ]
|
||||
config.merge(newconfig)
|
||||
config.version = 1
|
||||
s=json.dumps(config, indent=2, separators=(',', ': '), sort_keys=True)
|
||||
with open(fname, 'w') as f:
|
||||
f.write(s)
|
||||
@@ -0,0 +1,36 @@
|
||||
package:
|
||||
name: nbextensions
|
||||
version: !!str 0.3
|
||||
|
||||
source:
|
||||
path: ./src
|
||||
|
||||
build:
|
||||
script: ipython install.py
|
||||
|
||||
requirements:
|
||||
build:
|
||||
- python
|
||||
- jupyter-client
|
||||
- jupyter-core
|
||||
- jupyter-notebook
|
||||
- nbconvert
|
||||
- nbformat
|
||||
- traitlets
|
||||
- ipython >=4
|
||||
|
||||
run:
|
||||
- python
|
||||
- jupyter-client
|
||||
- jupyter-core
|
||||
- jupyter-notebook
|
||||
- nbconvert
|
||||
- nbformat
|
||||
- traitlets
|
||||
- ipython >=4
|
||||
|
||||
about:
|
||||
home: https://github.com/ipython-contrib/IPython-notebook-extensions/wiki
|
||||
license: Modified BSD License
|
||||
summary: 'Notebook extensions for the IPython notebook'
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
# Configuration file for ipython-notebook.
|
||||
|
||||
from IPython.utils.path import get_ipython_dir
|
||||
import os
|
||||
import sys
|
||||
|
||||
ipythondir = get_ipython_dir()
|
||||
extensions = os.path.join(ipythondir,'extensions')
|
||||
sys.path.append( extensions )
|
||||
|
||||
c = get_config()
|
||||
c.NotebookApp.open_browser = False
|
||||
#c.IPKernelApp.ip = '127.0.0.1'
|
||||
#c.FileNotebookManager.notebook_dir = 'i:\\notebook'
|
||||
|
||||
c.NotebookApp.server_extensions = [ 'nbextensions' ]
|
||||
c.NotebookApp.extra_template_paths = [os.path.join(ipythondir,'templates') ]
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
.nbextension-row {
|
||||
border-bottom: 2px solid #888;
|
||||
padding-left: 20px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
// Copyright (c) IPython-Contrib Team.
|
||||
// Distributed under the terms of the Modified BSD License.
|
||||
|
||||
// Show notebook extension configuration
|
||||
|
||||
require([
|
||||
'base/js/namespace',
|
||||
'base/js/utils',
|
||||
'base/js/page',
|
||||
'base/js/events',
|
||||
'jquery',
|
||||
'require',
|
||||
'contents',
|
||||
'services/config'
|
||||
], function(
|
||||
IPython,
|
||||
utils,
|
||||
page,
|
||||
events,
|
||||
$, require,
|
||||
contents,
|
||||
configmod
|
||||
){
|
||||
page = new page.Page();
|
||||
|
||||
var base_url = utils.get_body_data('baseUrl');
|
||||
var extension_list = $('body').data('extension-list');
|
||||
|
||||
/* build html body listing all extensions */
|
||||
var html = "";
|
||||
for(var i=0; i < extension_list.length; i++) {
|
||||
var extension = extension_list[i];
|
||||
var url = base_url + extension['url'];
|
||||
var icon = url + '/' + extension['Icon'];
|
||||
var id = extension['Name'].replace(/\s+/g, '');
|
||||
|
||||
html += '<div class="row">\n'
|
||||
+' <div class="row nbextension-row" >\n';
|
||||
|
||||
html += ' <div class="col-xs-4 col-sm-6">'
|
||||
+' <div class="col-sm-9">'
|
||||
+' <h3>' + extension['Name'] + '</h3></div>';
|
||||
|
||||
html += '<div class="col-sm-9">' + extension['Description'] +
|
||||
' <a href="' + extension['Link'] + '">more...</a></div><br>';
|
||||
html += '<div class="col-sm-9">'
|
||||
+'<button type="button" class="btn btn-primary" id="'
|
||||
+ id + '-on" >Activate</button>'
|
||||
+'<button type="button" class="btn btn-default" disabled="disabled" id="'
|
||||
+ id + '-off" >Deactivate</button></div><br>';
|
||||
|
||||
if (extension['Parameter'] != undefined) {
|
||||
/* add an input element to configure extension parameters */
|
||||
var inputid = 'input_' + extension['Parameter'];
|
||||
var description = 'Parameter: ' + extension['Parameter'];
|
||||
console.log(extension.hasOwnProperty('ParameterDescription'))
|
||||
if (extension.hasOwnProperty('ParameterDescription') === true) description += '<br>'+extension['ParameterDescription'];
|
||||
html += '<div class="col-xs-12" style="height:10px;"></div><div class="col-sm-9">'
|
||||
+ description + '<input id="'+inputid+'" type="text" class="form-control searchbar_input">'
|
||||
+ '</div>';
|
||||
}
|
||||
html += '</div>'
|
||||
+' <div class="col-xs-8 col-sm-6">\n';
|
||||
html += ' <img src="' + icon + '" height="120px" /></div>'
|
||||
+'</div></div>'
|
||||
|
||||
}
|
||||
$("#nbextensions-container").html(html);
|
||||
|
||||
/**
|
||||
* Update config in json config file on server to reflect changed activate/deactivate stae
|
||||
*/
|
||||
var changeConfig = function(id,state) {
|
||||
for(var i=0; i < extension_list.length; i++) {
|
||||
var extension = extension_list[i];
|
||||
var url = base_url + extension['url'] + '/' + extension['Main'];
|
||||
url = url.split('.js')[0];
|
||||
url = url.split('nbextensions/')[1] ;
|
||||
var extid = extension['Name'].replace(/\s+/g, '');
|
||||
if (extid === id) {
|
||||
var ext = {};
|
||||
|
||||
if (state === true) {
|
||||
console.log("Turn extension " + extension['Name'] + ' on');
|
||||
ext[url] = true;
|
||||
config.update({"load_extensions": ext })
|
||||
} else {
|
||||
console.log("Turn extension " + extension['Name'] + ' off');
|
||||
ext[url] = null;
|
||||
config.update({"load_extensions": ext })
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle button click event to activate/deactivate extension
|
||||
*/
|
||||
var clickEvent = function(e) {
|
||||
|
||||
var id = this.id.replace(/-on|-off/,'');
|
||||
var state = this.id.search(/-on/) >= 0;
|
||||
if (state === true) {
|
||||
set_buttons(id,false);
|
||||
changeConfig(id,true)
|
||||
} else {
|
||||
set_buttons(id,true);
|
||||
changeConfig(id,false)
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* install click handler for buttons
|
||||
*/
|
||||
for(var i=0; i < extension_list.length; i++) {
|
||||
var extension = extension_list[i];
|
||||
var id = extension['Name'].replace(/\s+/g, '');
|
||||
console.log("Found extension:",id);
|
||||
$(document.getElementById(id+'-on')).on('click', clickEvent );
|
||||
$(document.getElementById(id+'-off')).on('click', clickEvent );
|
||||
}
|
||||
|
||||
var set_buttons = function(id, state) {
|
||||
var on = $(document.getElementById(id+'-on'));
|
||||
var off = $(document.getElementById(id+'-off'));
|
||||
if (state === true) {
|
||||
off = $(document.getElementById(id+'-on'));
|
||||
on = $(document.getElementById(id+'-off'));
|
||||
}
|
||||
|
||||
on.prop('disabled', true);
|
||||
on.removeClass('btn-primary');
|
||||
on.addClass('btn-default');
|
||||
off.prop('disabled', false);
|
||||
off.addClass('btn-primary');
|
||||
off.removeClass('btn-default')
|
||||
};
|
||||
|
||||
/**
|
||||
* handle input form for extension parameters, update parameter in json config file on server
|
||||
*/
|
||||
var handle_input = function(event, configkey)
|
||||
{
|
||||
var form = event.target.id;
|
||||
var input = $(document.getElementById(form));
|
||||
var c = {};
|
||||
c[configkey] = input.val();
|
||||
config.update(c)
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Get configuration from json config file on server
|
||||
*/
|
||||
var config = new configmod.ConfigSection('notebook', {base_url: base_url});
|
||||
config.load();
|
||||
|
||||
/* set activate/deactivate buttons and populate parameter input once config is loaded */
|
||||
config.loaded.then(function() {
|
||||
if (config.data.load_extensions) {
|
||||
var nbextension_paths = Object.getOwnPropertyNames(
|
||||
config.data.load_extensions);
|
||||
for(var i=0; i < extension_list.length; i++) {
|
||||
var extension = extension_list[i];
|
||||
var parameter = extension['Parameter'];
|
||||
if ( parameter != undefined) {
|
||||
if (config.data.hasOwnProperty(parameter)) {
|
||||
var input = $(document.getElementById('input_'+parameter));
|
||||
var configkey = parameter;
|
||||
input.val(config.data[parameter]);
|
||||
input.on('keyup', function(event) { handle_input(event, configkey);});
|
||||
}
|
||||
}
|
||||
var url = base_url + extension['url'] + '/' + extension['Main'];
|
||||
url = url.split('.js')[0];
|
||||
url = url.split('nbextensions/')[1];
|
||||
if ( config.data.load_extensions[url] === true) {
|
||||
var id = extension['Name'].replace(/\s+/g, '');
|
||||
set_buttons(id,false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Add CSS file
|
||||
*
|
||||
* @param name filename
|
||||
*/
|
||||
var load_css = function (name) {
|
||||
var link = document.createElement("link");
|
||||
link.type = "text/css";
|
||||
link.rel = "stylesheet";
|
||||
link.href = require.toUrl(name);
|
||||
document.getElementsByTagName("head")[0].appendChild(link);
|
||||
};
|
||||
load_css('/nbextensions/config/main.css');
|
||||
page.show();
|
||||
|
||||
});
|
||||
@@ -1,58 +0,0 @@
|
||||
// Example for custom.js
|
||||
|
||||
// we want strict javascript that fails on ambiguous syntax
|
||||
"use strict";
|
||||
|
||||
// activate extensions only after Notebook is initialized
|
||||
require(["base/js/events"], function (events) {
|
||||
events.on("app_initialized.NotebookApp", function () {
|
||||
/*
|
||||
* all exentensions from IPython-notebook-extensions, uncomment to activate
|
||||
*/
|
||||
|
||||
// PUBLISHING
|
||||
// IPython.load_extensions('publishing/nbviewer_theme/main')
|
||||
// IPython.load_extensions('publishing/gist_it')
|
||||
// IPython.load_extensions('publishing/nbconvert_button')
|
||||
// IPython.load_extensions('publishing/printview/main')
|
||||
// IPython.load_extensions('publishing/printviewmenu_button')
|
||||
|
||||
// SLIDEMODE
|
||||
// IPython.load_extensions('slidemode/main')
|
||||
|
||||
|
||||
// STYLING
|
||||
// IPython.load_extensions('styling/css_selector/main')
|
||||
|
||||
// TESTING
|
||||
// IPython.load_extensions('testing/hierarchical_collapse/main')
|
||||
|
||||
// USABILITY
|
||||
// IPython.load_extensions('usability/aspell/ipy-aspell')
|
||||
// IPython.load_extensions('usability/codefolding/main')
|
||||
// IPython.load_extensions('usability/dragdrop/drag-and-drop')
|
||||
// IPython.load_extensions('usability/runtools/main')
|
||||
// IPython.load_extensions('usability/chrome_clipboard/main')
|
||||
// IPython.load_extensions('usability/navigation-hotkeys/main')
|
||||
// IPython.load_extensions('usability/toggle_all_line_number')
|
||||
// IPython.load_extensions('usability/help_panel/help_panel')
|
||||
// IPython.load_extensions('usability/hide_input/main')
|
||||
// IPython.load_extensions('usability/split-combine')
|
||||
// IPython.load_extensions('usability/read-only')
|
||||
// IPython.load_extensions('usability/init_cell/main')
|
||||
// IPython.load_extensions('usability/limit_output/main')
|
||||
// IPython.load_extensions('usability/autosavetime')
|
||||
// IPython.load_extensions('usability/autoscroll')
|
||||
// IPython.load_extensions('usability/breakpoints')
|
||||
// IPython.load_extensions('usability/clean_start')
|
||||
// IPython.load_extensions('usability/comment-uncomment')
|
||||
// IPython.load_extensions('usability/linenumbers')
|
||||
// IPython.load_extensions('usability/no_exec_dunder')
|
||||
// IPython.load_extensions('usability/noscroll')
|
||||
// IPython.load_extensions('usability/hide_io_selected')
|
||||
// IPython.load_extensions('usability/execute_time/ExecuteTime')
|
||||
// IPython.load_extensions('usability/python-markdown/main')
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""PostProcessor for embedding markdown images in HTML files."""
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import re
|
||||
import base64
|
||||
import requests
|
||||
|
||||
from traitlets import Bool, Unicode, Int
|
||||
from nbconvert.postprocessors.base import PostProcessorBase
|
||||
|
||||
|
||||
class EmbedPostProcessor(PostProcessorBase):
|
||||
""" Post processor designed to embed images in markdown cells as base64 encoded blob in HTML file """
|
||||
|
||||
def replfunc(self, match):
|
||||
""" replace source url or file link with base64 encoded blob """
|
||||
url = match.group(1)
|
||||
imgformat = url.split('.')[-1]
|
||||
if url.startswith('http'):
|
||||
data = request.get(url)
|
||||
elif url.startswith('data'):
|
||||
img = '<img src="' + url + '" '+ match.group(2) + ' />'
|
||||
return img
|
||||
else:
|
||||
with open(url, 'rb') as f:
|
||||
data = f.read()
|
||||
|
||||
self.log.info("embedding url: %s, format: %s" % (url, imgformat))
|
||||
b64_data=base64.b64encode(data).decode("utf-8")
|
||||
if imgformat == "svg":
|
||||
img = '<img src="data:image/svg+xml;base64,' + b64_data + '" ' + match.group(2) + '/>'
|
||||
elif imgformat == "pdf":
|
||||
img = '<img src="data:application/pdf;base64,' + b64_data + '" ' + match.group(2) + '/>'
|
||||
else:
|
||||
img = '<img src="data:image/'+imgformat+';base64,' + b64_data + '" '+ match.group(2) + ' />'
|
||||
return img
|
||||
|
||||
def postprocess(self, input):
|
||||
regex = re.compile('<img\s+src="(\S+)"\s*(\S*)\s*/>')
|
||||
ext = input.split('.')[-1]
|
||||
output=input[0:-(len(ext)+1)] + '-embedded.' + ext
|
||||
with open(input) as fin, open(output,'w') as fout:
|
||||
for line in fin:
|
||||
fout.write(regex.sub(self.replfunc,line))
|
||||
fin.close()
|
||||
fout.close()
|
||||
@@ -12,14 +12,14 @@ import os
|
||||
import yaml
|
||||
import json
|
||||
|
||||
jupyterdir = jupyter_data_dir()
|
||||
nbextensions = (get_nbext_dir(), os.path.join(jupyterdir,'nbextensions'))
|
||||
exclude = [ 'mathjax' ]
|
||||
|
||||
class NBExtensionHandler(IPythonHandler):
|
||||
"""Render the notebook extension configuration interface."""
|
||||
@web.authenticated
|
||||
def get(self):
|
||||
jupyterdir = jupyter_data_dir()
|
||||
nbextensions = (get_nbext_dir(), os.path.join(jupyterdir,'nbextensions'))
|
||||
exclude = [ 'mathjax' ]
|
||||
yaml_list = []
|
||||
# Traverse through nbextension subdirectories to find all yaml files
|
||||
for root, dirs, files in chain.from_iterable(os.walk(root) for root in nbextensions):
|
||||
@@ -55,16 +55,56 @@ class NBExtensionHandler(IPythonHandler):
|
||||
self.log.info("Found extension %s" % extension['Name'])
|
||||
stream.close()
|
||||
json_list = json.dumps(extension_list)
|
||||
# find where the Javascript code and the readme file are
|
||||
config_js = None
|
||||
config_md = None
|
||||
for root, dirs, files in chain.from_iterable(os.walk(root) for root in nbextensions):
|
||||
dirs[:] = [d for d in dirs if d not in exclude]
|
||||
for f in files:
|
||||
if root.endswith('nbconfig') and f =='main.js':
|
||||
config_js = os.path.join(root, f)
|
||||
if root.endswith('nbconfig') and f =='readme.md':
|
||||
config_md = os.path.join(root, f)
|
||||
if config_js is None: raise FileNotFoundError('Could not find nbconfig Javascript')
|
||||
idx_js=config_js.find('nbextensions')
|
||||
idx_md=config_js.find('nbextensions')
|
||||
self.write(self.render_template('nbextensions.html',
|
||||
base_url = self.base_url,
|
||||
extension_list = json_list,
|
||||
page_title="Notebook Extension Configuration"
|
||||
page_title="Notebook Extension Configuration",
|
||||
config_js = self.base_url + config_js[idx_js::].replace('\\', '/'),
|
||||
config_md = self.base_url + 'rendermd/' + config_md[idx_md::].replace('\\', '/')
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
class RenderExtensionHandler(IPythonHandler):
|
||||
"""Render given markdown file"""
|
||||
@web.authenticated
|
||||
def get(self, path):
|
||||
render_js = None
|
||||
for root, dirs, files in chain.from_iterable(os.walk(root) for root in nbextensions):
|
||||
dirs[:] = [d for d in dirs if d not in exclude]
|
||||
for f in files:
|
||||
if root.endswith('nbconfig') and f =='render.js':
|
||||
render_js = os.path.join(root, f)
|
||||
if render_js is None: raise FileNotFoundError('Could not find nbconfig Javascript')
|
||||
idx_js=render_js.find('nbextensions')
|
||||
self.write(self.render_template('rendermd.html',
|
||||
base_url = self.base_url,
|
||||
render_url = path,
|
||||
page_title = path,
|
||||
render_js = self.base_url + render_js[idx_js::].replace('\\', '/'),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def load_jupyter_server_extension(nbapp):
|
||||
webapp = nbapp.web_app
|
||||
base_url = webapp.settings['base_url']
|
||||
mdregex = r'([^"\'>]+.md)'
|
||||
webapp.add_handlers(".*$", [
|
||||
(ujoin(base_url, r"/rendermd/%s" % mdregex), RenderExtensionHandler),
|
||||
(ujoin(base_url, r"/nbextensions"), NBExtensionHandler),
|
||||
(ujoin(base_url, r"/nbextensions/"), NBExtensionHandler)
|
||||
])
|
||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 291 KiB After Width: | Height: | Size: 291 KiB |
|
Before Width: | Height: | Size: 424 KiB After Width: | Height: | Size: 424 KiB |
|
Before Width: | Height: | Size: 325 KiB After Width: | Height: | Size: 325 KiB |
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 185 KiB |
|
Before Width: | Height: | Size: 311 KiB After Width: | Height: | Size: 311 KiB |
|
Before Width: | Height: | Size: 252 KiB After Width: | Height: | Size: 252 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 210 KiB After Width: | Height: | Size: 210 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |