Skip to content

Commit

Permalink
Merge pull request #1630 from jasongrout/embed-amd
Browse files Browse the repository at this point in the history
Concat embed amd files together to have one file to include
  • Loading branch information
jasongrout authored Aug 15, 2017
2 parents 306480d + 8ecdc1f commit f832983
Show file tree
Hide file tree
Showing 9 changed files with 58 additions and 76 deletions.
37 changes: 18 additions & 19 deletions docs/source/embedding.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ Jupyter interactive widgets can be serialized and embedded into
- sphinx documentation
- html-converted notebooks on nbviewer

## RequireJS
Here, we discuss embedding widgets using the custom widget manager in the `@jupyter-widgets/html-manager` npm package. Two embedders are provided:

This page talks about embedding widgets using the custom widget manager in the `@jupyter-widgets/html-manager` npm package. This can be done in two basic ways:
1. A basic embedder that only embeds standard controls, but can be used on any web page
2. An embedder that uses RequireJS, and can embed standard and custom widgets.

1.

## Embedding Widgets in HTML Web Pages

Expand All @@ -28,27 +28,29 @@ The context menu provides three actions
### Embeddable HTML Snippet

The last option, `Embed widgets`, provides a dialog containing an HTML page
which embeds Jupyter interactive widgets.
which embeds Jupyter interactive widgets. In order to support custom widgets, this exposes the RequireJS embedder.

This HTML snippet is composed of multiple sections containing `<script>` tags:
This HTML snippet is composed of multiple `<script>` tags embedded into an HTML context:

- The first section loads a custom widget manager from the `unpkg` CDN. In order to accommodate custom widgets, RequireJS is first loaded on the page, and then a small bit of Javascript requires the appropriate Jupyter widgets module and renders the widgets on the page.
- The first script tag loads RequireJS from a CDN. If you already have RequireJS on the page, you can delete this script tag.

- The second section is a script tag with mime type
- The second script tag loads the RequireJS widget embedder. This defines appropriate modules and then sets up a function to render all of the widget views included on the page. If you are only embedding standard widgets and do not want to use RequireJS, you can replace these first two script tags with a script tag loading the standard embedder.

- The next script tag is a script tag with mime type
`application/vnd.jupyter.widget-state+json` that contains the state of all
the widget models currently in use. The JSON schema for the content of that
the widget models currently in use. The JSON schema for the content of this
script tag is found in the `@jupyter-widgets/schema` npm package.

- The next section has a number of script tags, each with mime type
- Then there are a number of script tags, each with mime type
`application/vnd.jupyter.widget-view+json`, corresponding to the views which
you want to display in the web page. These script tags must be in the body of
the page, and are replaced with the rendered widgets. The JSON schema for the
content of these script tags is found in the `@jupyter-widgets/schema` npm
package. The *Embed Widgets* action currently creates one of these script tags
for each view displayed in the notebook.
package.

If you want to lay out these script tags in a custom fashion or only keep some
of them, you can delete or include these view script tags as you wish.
The *Embed Widgets* action currently creates one of these script tags for each
view displayed in the notebook. If you'd like to lay out the views, or include
only some of them, you can delete or include these script tags as you wish.

### Widget State JSON

Expand Down Expand Up @@ -111,15 +113,12 @@ print(embed_snippet(
))
```

In `embed_snippet` and `embed_minimal_html` examples above, the `requirejs=True`
argument was given.

In `embed_snippet` and `embed_minimal_html` examples above, the `requirejs=True` gives the RequireJS embedder. To get the standard embedder, omit this option or give `requirejs=False`.

## Embedding Widgets in the Sphinx HTML Documentation

As of ipywidgets 6.0, Jupyter interactive widgets can be rendered and
interacted with in sphinx html documentation. Two means of achieving this are
provided:
As of ipywidgets 6.0, Jupyter interactive widgets can be rendered in Sphinx html
documentation. Two means of achieving this are provided:

### Using the Jupyter Sphinx Extension

Expand Down
22 changes: 8 additions & 14 deletions docs/source/migration_guides.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,27 +129,21 @@ If you are just embedding the standard widgets that come with ipywidgets, then y
<script src="https://unpkg.com/@jupyter-widgets/html-manager@*/dist/embed.js"></script>
```

If you want to use a specific version of the embedder, you replace the `@*` with a semver range, such as `@^0.7.0`
If you want to use a specific version of the embedder, you replace the `@*` with a semver range, such as `@^0.9.0`

#### Embedding with require.js and third-party widgets
#### Embedding custom widgets with RequireJS

In order to embed third-party widgets, you can use the require.js-based embedding. First, make sure that require.js is loaded on the page, for example:
In order to embed third-party widgets, you can use the RequireJS-based embedding. First, make sure that RequireJS is loaded on the page, for example:

```html
<!-- Load require.js. Delete this if your page already loads require.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js" integrity="sha256-Ae2Vz/4ePdIu6ZyI/5ZGsYnb+m0JlOmKPjt6XZ9JJkA=" crossorigin="anonymous"></script>
```

Then require the embedder and run the `renderWidgets` function:
Then define the embedding libraries and run the rendering function by including the following scripts
```html
<script>
window.require(['https://unpkg.com/@jupyter-widgets/html-manager@*/dist/embed-requirejs'], function(embed) {
if (document.readyState === "complete") {
embed.renderWidgets();
} else {
window.addEventListener('load', function() {embed.renderWidgets();});
}
});
</script>
<script src="https://unpkg.com/@jupyter-widgets/html-manager@*/dist/embed-amd.js"></script>
```
If you want to use a specific version of the embedder, you replace the `@*` with a semver range, such as `@^0.7.0`
If you want to use a specific version of the embedder, you replace the `@*` with a semver range, such as `@^0.9.0`

If you need to embed custom widgets without using RequireJS, you'll need to compile your own embedding javascript that includes the third-party libraries.
14 changes: 2 additions & 12 deletions ipywidgets/embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,7 @@
load_requirejs_template = u"""
<!-- Load require.js. Delete this if your page already loads require.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js" integrity="sha256-Ae2Vz/4ePdIu6ZyI/5ZGsYnb+m0JlOmKPjt6XZ9JJkA=" crossorigin="anonymous"></script>
<script>
window.require(["{embed_url}"], function(embed) {{
if (document.readyState === "complete") {{
embed.renderWidgets();
}} else {{
window.addEventListener('load', function() {{embed.renderWidgets();}});
}}
}});
</script>
<script src="{embed_url}"></script>
"""

requirejs_snippet_template = u"""
Expand Down Expand Up @@ -67,7 +57,7 @@
</script>"""

DEFAULT_EMBED_SCRIPT_URL = u'https://unpkg.com/@jupyter-widgets/html-manager@%s/dist/embed.js'%__html_manager_version__
DEFAULT_EMBED_REQUIREJS_URL = u'https://unpkg.com/@jupyter-widgets/html-manager@%s/dist/embed-requirejs'%__html_manager_version__
DEFAULT_EMBED_REQUIREJS_URL = u'https://unpkg.com/@jupyter-widgets/html-manager@%s/dist/embed-amd'%__html_manager_version__

def _find_widget_refs_by_state(widget, state):
"""Find references to other widgets in a widget's state"""
Expand Down
3 changes: 2 additions & 1 deletion packages/html-manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@
"scripts": {
"clean": "rimraf lib && rimraf dist",
"build:src": "tsc --project src",
"build:embed-amd": "node scripts/concat-amd-build.js && rimraf dist/amd",
"build:test": "tsc --project test/src && webpack --config test/webpack.conf.js",
"build": "npm run build:src && webpack",
"build": "npm run build:src && webpack && npm run build:embed-amd",
"test": "npm run test:unit",
"test:unit": "npm run test:unit:firefox && npm run test:unit:chrome",
"test:unit:default": "npm run build:test && karma start test/karma.conf.js --log-level debug --browsers=Firefox",
Expand Down
19 changes: 19 additions & 0 deletions packages/html-manager/scripts/concat-amd-build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

var fs = require('fs');

// Make a script file that defines all of the relevant AMD modules
var files = ['base.js', 'controls.js', 'index.js', 'libembed-amd.js'];
var output = files.map((f)=>{
return fs.readFileSync('./dist/amd/'+f).toString();
}).join(';\n\n');
fs.writeFileSync('./dist/libembed-amd.js', output)

// Make a script that has all of the above AMD modules and runs a function which
// renders all of the widgets on page load automatically.
files = ['base.js', 'controls.js', 'index.js', 'libembed-amd.js', 'embed-amd-render.js'];
var output = files.map((f)=>{
return fs.readFileSync('./dist/amd/'+f).toString();
}).join(';\n\n');
fs.writeFileSync('./dist/embed-amd.js', output)
File renamed without changes.
7 changes: 0 additions & 7 deletions packages/html-manager/src/libembed-amd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,6 @@

import * as libembed from './libembed';

// Populate the requirejs cache with local versions of @jupyter-widgets/base,
// @jupyter-widgets/controls, @jupyter-widgets/html-manager. These are externals
// when compiled with webpack.
require('./base');
require('./controls');
require('./index');

/**
* Load a package using requirejs and return a promise
*
Expand Down
22 changes: 8 additions & 14 deletions packages/html-manager/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,12 @@ module.exports = [
postcss: postcssHandler
},
{// script that renders widgets using the amd embedding and can render third-party custom widgets
entry: './lib/embed-amd.js',
entry: './lib/embed-amd-render.js',
output: {
filename : 'embed-amd.js',
path: './dist',
filename : 'embed-amd-render.js',
path: './dist/amd',
publicPath: publicPath,
},
devtool: 'source-map',
module: { loaders: loaders },
postcss: postcssHandler
},
Expand All @@ -69,25 +68,22 @@ module.exports = [
output: {
library: '@jupyter-widgets/html-manager/dist/libembed-amd',
filename : 'libembed-amd.js',
path: './dist',
path: './dist/amd',
publicPath: publicPath,
libraryTarget: 'amd'
},
devtool: 'source-map',
module: { loaders: loaders },
postcss: postcssHandler,
externals: ['./base', './controls', './index']
postcss: postcssHandler
},
{// @jupyter-widgets/html-manager
entry: './lib/index.js',
output: {
library: '@jupyter-widgets/html-manager',
filename : 'index.js',
path: './dist',
path: './dist/amd',
publicPath: publicPath,
libraryTarget: 'amd',
},
devtool: 'source-map',
module: { loaders: loaders },
postcss: postcssHandler,
externals: ['@jupyter-widgets/base', '@jupyter-widgets/controls']
Expand All @@ -97,11 +93,10 @@ module.exports = [
output: {
library: '@jupyter-widgets/base',
filename : 'base.js',
path: './dist',
path: './dist/amd',
publicPath: publicPath,
libraryTarget: 'amd',
},
devtool: 'source-map',
module: { loaders: loaders },
postcss: postcssHandler
},
Expand All @@ -110,11 +105,10 @@ module.exports = [
output: {
library: '@jupyter-widgets/controls',
filename : 'controls.js',
path: './dist',
path: './dist/amd',
publicPath: publicPath,
libraryTarget: 'amd'
},
devtool: 'source-map',
module: { loaders: loaders },
postcss: postcssHandler,
externals: ['@jupyter-widgets/base']
Expand Down
10 changes: 1 addition & 9 deletions widgetsnbextension/src/embed_widgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,7 @@ var embed_widgets = function() {
'',
'<!-- Load require.js. Delete this if your page already loads require.js -->',
'<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js" integrity="sha256-Ae2Vz/4ePdIu6ZyI/5ZGsYnb+m0JlOmKPjt6XZ9JJkA=" crossorigin="anonymous"></script>',
'<script>',
' window.require(["https://unpkg.com/@jupyter-widgets/html-manager@^'+htmlManagerVersion+'/dist/embed-requirejs"], function(embed) {',
' if (document.readyState === "complete") {',
' embed.renderWidgets();',
' } else {',
' window.addEventListener("load", function() {embed.renderWidgets();});',
' }',
' });',
'</script>',
'<script src="https://unpkg.com/@jupyter-widgets/html-manager@*/dist/embed-amd.js" crossorigin="anonymous"></script>',
'<script type="application/vnd.jupyter.widget-state+json">',
data,
'</script>',
Expand Down

0 comments on commit f832983

Please sign in to comment.