Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow defining external JS and CSS resources via config #330

Merged
merged 2 commits into from
Mar 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions examples/user_guide/Deploy_and_Export.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,24 @@
"\n",
" jupyter labextension install @pyviz/jupyterlab_pyviz\n",
" \n",
"Note that to use certain components such as Vega, LaTeX and Plotly plots in a notebook the models must be loaded using the extension, e.g.:\n",
"\n",
" pn.extension('vega', 'katex')\n",
" \n",
"will ensure that the Vega and LaTeX JS dependencies are loaded. Additionally any external ``css_files``, ``js_files`` and ``raw_css`` should be declared in the extension. The ``js_files`` should be declared as a dictionary mapping from the exported JS module name to the URL containing the JS components, while the ``css_files`` can be defined as a list:\n",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is already merged, but while it's still fresh in your mind, it would be good to clarify the situations where one would need external CSS or JS files.

"\n",
" pn.extension(js_files={'deck': https://unpkg.com/deck.gl@~5.2.0/deckgl.min.js},\n",
" css_files=['https://api.tiles.mapbox.com/mapbox-gl-js/v0.44.1/mapbox-gl.css'])\n",
"\n",
"Meanwhile ``raw_css`` can be defined as a list of CSS strings. Providing keyword arguments via the ``extension`` is the same as setting them on ``pn.config``, which is the preferred approach outside the notebook, e.g. ``js_files`` and ``css_files`` may be set as follows:\n",
"\n",
" pn.config.js_files = {'deck': https://unpkg.com/deck.gl@~5.2.0/deckgl.min.js}\n",
" pn.config.css_files = ['https://api.tiles.mapbox.com/mapbox-gl-js/v0.44.1/mapbox-gl.css']\n",
"\n",
"\n",
"#### The repr\n",
" \n",
"Once these conditions are met a panel will display itself:"
"Once the extension is loaded panel objects will display themselves if placed at the end of cell:"
]
},
{
Expand Down Expand Up @@ -192,25 +207,15 @@
"\n",
"## Exporting\n",
"\n",
"In case you don't need an actual server or simply want to export a static snapshot of a panel app you can use the ``save`` method which allows exporting the app to a standalone HTML or PNG file."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In case you don't need an actual server or simply want to export a static snapshot of a panel app you can use the ``save`` method which allows exporting the app to a standalone HTML or PNG file.\n",
"\n",
"By default, the HTML file generated will depend on loading JavaScript code for BokehJS from the online ``CDN`` repository, to reduce the file size. If you need to work in an airgapped or no-network environment, you can declare that ``INLINE`` resources should be used instead of ``CDN``:\n",
"\n",
"```python\n",
"from bokeh.resources import INLINE\n",
"panel.save('test.html', resources=INLINE)\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```\n",
"\n",
"Finally, if a 'png' file extension is specified, the exported plot will be rendered as a PNG, which currently requires Selenium and PhantomJS to be installed:\n",
"\n",
"```python\n",
Expand Down
18 changes: 15 additions & 3 deletions panel/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,23 @@ def require_components():
Returns JS snippet to load the required dependencies in the classic
notebook using REQUIRE JS.
"""
from .config import config

configs, requirements, exports = [], [], []
for model in CUSTOM_MODELS.values():
if not hasattr(model, '__js_require__'):
js_requires = list(CUSTOM_MODELS.values())

for export, js in config.js_files.items():
name = js.split('/')[-1].replace('.min', '').split('.')[-2]
conf = {'paths': {name: js[:-3]}, 'exports': {name: export}}
js_requires.append(conf)

for model in js_requires:
if not (hasattr(model, '__js_require__') or isinstance(model, dict)):
continue
model_require = model.__js_require__
if isinstance(model, dict):
model_require = model
else:
model_require = model.__js_require__
model_exports = model_require.pop('exports', {})
configs.append(model_require)
for req in model_require.get('paths', []):
Expand Down
10 changes: 10 additions & 0 deletions panel/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ class _config(param.Parameterized):
os.environ['PANEL_EMBED'] = 'True'
"""

css_files = param.List(default=[], doc="""
External CSS files to load as part of the template.""")

js_files = param.Dict(default={}, doc="""
External JS files to load as part of the template. Dictionary
should map from exported name to the URL of the JS file.""")

raw_css = param.List(default=[], doc="""
List of raw CSS strings to add to the template.""")

_embed = param.Boolean(default=False, allow_None=True, doc="""
Whether plot data will be embedded.""")

Expand Down
1 change: 1 addition & 0 deletions panel/io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
from .embed import embed_state # noqa
from .state import state # noqa
from .model import add_to_doc, remove_root, diff # noqa
from .resources import Resources # noqa
from .server import get_server # noqa
from .notebook import block_comm, load_notebook, push # noqa
26 changes: 26 additions & 0 deletions panel/io/resources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""
Patches bokeh resources to make it easy to add external JS and CSS
resources via the panel.config object.
"""
from __future__ import absolute_import, division, unicode_literals

from bokeh.resources import Resources

def css_raw(self):
from ..config import config
raw = super(Resources, self).css_raw
return raw + config.raw_css

def js_files(self):
from ..config import config
files = super(Resources, self).js_files
return files + list(config.js_files.values())

def css_files(self):
from ..config import config
files = super(Resources, self).css_files
return files + config.css_files

Resources.css_raw = property(css_raw)
Resources.js_files = property(js_files)
Resources.css_files = property(css_files)