Skip to content

Commit

Permalink
Improved handling of ReactiveHTML resources (#2397)
Browse files Browse the repository at this point in the history
* Improved handling of ReactiveHTML resources

* Fix flakes
  • Loading branch information
philippjfr committed Jun 16, 2021
1 parent 483d000 commit 8b8a7e8
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 8 deletions.
59 changes: 58 additions & 1 deletion examples/user_guide/Custom_Components.ipynb
Expand Up @@ -9,7 +9,15 @@
"import param\n",
"import panel as pn\n",
"\n",
"pn.extension()"
"js_files = {\n",
" 'mdc': 'https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js'\n",
"}\n",
" \n",
"css_files = [\n",
" 'https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css'\n",
"]\n",
"\n",
"pn.extension(js_files=js_files, css_files=css_files)"
]
},
{
Expand Down Expand Up @@ -411,6 +419,55 @@
"3. `'line_width'` and `'color'` are invoked when the parameters change (i.e. when a widget is updated)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## External dependencies\n",
"\n",
"Often you will want to wrap a component with some external Javascript or CSS dependencies. To make this possible `ReactiveHTML` components may declare `__javascript__`, `__javascript_modules__` and `__css__` attributes, specifying the external dependencies to load. Note that in a notebook the component must be declared before `pn.extension` is called, otherwise the libraries won't be loaded (in this case we explicitly loaded them above).\n",
"\n",
"Below we will create a Material UI text field and declare the Javascript and CSS components to load:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class MaterialTextField(ReactiveHTML):\n",
" \n",
" value = param.String(default='')\n",
" \n",
" _template = \"\"\"\n",
" <label id=\"text-field\" class=\"mdc-text-field mdc-text-field--filled\">\n",
" <span class=\"mdc-text-field__ripple\"></span>\n",
" <span class=\"mdc-floating-label\">Label</span>\n",
" <input id=\"text-input\" type=\"text\" class=\"mdc-text-field__input\" aria-labelledby=\"my-label\" value=\"${value}\"></input>\n",
" <span class=\"mdc-line-ripple\"></span>\n",
" </label>\n",
" \"\"\"\n",
" \n",
" _dom_events = {'text-input': ['change']}\n",
" \n",
" _scripts = {\n",
" 'render': \"mdc.textField.MDCTextField.attachTo(text_field);\"\n",
" }\n",
" \n",
" __javascript__ = [\n",
" 'https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js'\n",
" ]\n",
" \n",
" __css__ = [\n",
" 'https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css'\n",
" ]\n",
" \n",
"text_field = MaterialTextField()\n",
"\n",
"text_field"
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand Down
35 changes: 28 additions & 7 deletions panel/io/resources.py
Expand Up @@ -117,7 +117,12 @@ def bundle_resources(resources):
if ext is not None:
js_raw.append(ext)

return Bundle.of(js_files, js_raw, css_files, css_raw, js_resources.hashes if js_resources else {})
hashes = js_resources.hashes if js_resources else {}

return Bundle(
js_files=js_files, js_raw=js_raw, css_files=css_files,
css_raw=css_raw, hashes=hashes
)


class Resources(BkResources):
Expand Down Expand Up @@ -167,7 +172,9 @@ def js_files(self):

for model in param.concrete_descendents(ReactiveHTML).values():
if hasattr(model, '__javascript__'):
files += model.__javascript__
for jsfile in model.__javascript__:
if jsfile not in files:
files.append(jsfile)

js_files = []
for js_file in files:
Expand Down Expand Up @@ -200,7 +207,14 @@ def js_files(self):
@property
def js_modules(self):
from ..config import config
return list(config.js_modules.values())
from ..reactive import ReactiveHTML
modules = list(config.js_modules.values())
for model in param.concrete_descendents(ReactiveHTML).values():
if hasattr(model, '__javascript_modules__'):
for jsmodule in model.__javascript_modules__:
if jsmodule not in modules:
modules.append(jsmodule)
return modules

@property
def css_files(self):
Expand All @@ -211,7 +225,9 @@ def css_files(self):

for model in param.concrete_descendents(ReactiveHTML).values():
if hasattr(model, '__css__'):
files += model.__css__
for css_file in model.__css__:
if css_file not in files:
files.append(css_file)

for cssf in config.css_files:
if os.path.isfile(cssf) or cssf in files:
Expand Down Expand Up @@ -242,15 +258,20 @@ class Bundle(BkBundle):

def __init__(self, **kwargs):
from ..config import config
self.js_modules = kwargs.pop("js_modules", list(config.js_modules.values()))
from ..reactive import ReactiveHTML
js_modules = list(config.js_modules.values())
for model in param.concrete_descendents(ReactiveHTML).values():
if hasattr(model, '__javascript_modules__'):
for js_module in model.__javascript_modules__:
if js_module not in js_modules:
js_modules.append(js_module)
self.js_modules = kwargs.pop("js_modules", js_modules)
super().__init__(**kwargs)

@classmethod
def from_bokeh(cls, bk_bundle):
from ..config import config
return cls(
js_files=bk_bundle.js_files,
js_modules=list(config.js_modules.values()),
js_raw=bk_bundle.js_raw,
css_files=bk_bundle.css_files,
css_raw=bk_bundle.css_raw,
Expand Down
2 changes: 2 additions & 0 deletions panel/models/reactive_html.ts
Expand Up @@ -190,6 +190,8 @@ export class ReactiveHTMLView extends PanelHTMLBoxView {
}

resize_layout(): void {
if (this.layout == null)
this.update_layout()
super.resize_layout()
if (this._parent != null && this._parent !== this)
this._parent.resize_layout()
Expand Down

0 comments on commit 8b8a7e8

Please sign in to comment.