Skip to content

Commit

Permalink
Fix loading indicator CSS (#4490)
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr authored Mar 2, 2023
1 parent 62fe471 commit ecd08bd
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 56 deletions.
11 changes: 5 additions & 6 deletions panel/dist/css/loading.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
.bk.pn-loading {
:host(.pn-loading) {
overflow: hidden;
}
.bk.pn-loading:before {

:host(.pn-loading):before {
position: absolute;
height: 100%;
width: 100%;
Expand All @@ -15,10 +16,8 @@
border-width: 1px;
cursor: progress;
}
.bk.pn-loading.arcs:hover:before {
cursor: progress;
}
.bk.pn-loading .pn-loading-msg {

:host(.pn-loading) .pn-loading-msg {
position: absolute;
top: 72%;
font-size: 2em;
Expand Down
4 changes: 4 additions & 0 deletions panel/io/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
if TYPE_CHECKING:
from concurrent.futures import Future

from bokeh.document.models import ImportedStyleSheet
from bokeh.model import Model
from bokeh.server.contexts import BokehSessionContext
from bokeh.server.server import Server
Expand Down Expand Up @@ -192,6 +193,9 @@ class _state(param.Parameterized):
# Endpoints
_rest_endpoints = {}

# Style cache
_stylesheets: ClassVar[WeakKeyDictionary[Document, Dict[str, ImportedStyleSheet]]] = WeakKeyDictionary()

# Locks
_cache_locks: ClassVar[Dict[str, threading.Lock]] = {'main': threading.Lock()}

Expand Down
31 changes: 22 additions & 9 deletions panel/reactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,9 @@ def _process_param_change(self, msg: Dict[str, Any]) -> Dict[str, Any]:
if 'height' in properties and self.sizing_mode is None:
properties['min_height'] = properties['height']
if 'stylesheets' in properties:
base_stylesheets = self._stylesheets+['css/loading.css']
stylesheets = [loading_css()] + [
ImportedStyleSheet(url=stylesheet) for stylesheet in self._stylesheets
ImportedStyleSheet(url=stylesheet) for stylesheet in base_stylesheets
]
for stylesheet in properties['stylesheets']:
if isinstance(stylesheet, str) and stylesheet.endswith('.css'):
Expand Down Expand Up @@ -529,14 +530,26 @@ def _get_properties(self, doc: Document) -> Dict[str, Any]:
elif k not in params or self.param[k].default is not v:
params[k] = v
properties = self._process_param_change(params)
if 'stylesheets' in properties:
if doc and 'dist_url' in doc._template_variables:
dist_url = doc._template_variables['dist_url']
else:
dist_url = CDN_DIST
for stylesheet in properties['stylesheets']:
if isinstance(stylesheet, ImportedStyleSheet):
patch_stylesheet(stylesheet, dist_url)
if 'stylesheets' not in properties:
return properties
if doc:
state._stylesheets[doc] = cache = state._stylesheets.get(doc, {})
else:
cache = {}
if doc and 'dist_url' in doc._template_variables:
dist_url = doc._template_variables['dist_url']
else:
dist_url = CDN_DIST
stylesheets = []
for stylesheet in properties['stylesheets']:
if isinstance(stylesheet, ImportedStyleSheet):
if stylesheet.url in cache:
stylesheet = cache[stylesheet.url]
else:
cache[stylesheet.url] = stylesheet
patch_stylesheet(stylesheet, dist_url)
stylesheets.append(stylesheet)
properties['stylesheets'] = stylesheets
return properties

def _update_properties(self, *events: param.parameterized.Event, doc: Document) -> Dict[str, Any]:
Expand Down
2 changes: 1 addition & 1 deletion panel/tests/io/test_save.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def test_save_cdn_resources():
alert.save(sio, resources='cdn')
sio.seek(0)
html = sio.read()
assert re.findall('https://cdn.holoviz.org/panel/(.*)/dist/css/alerts.css', html)
assert re.findall('https://cdn.holoviz.org/panel/(.*)/dist/panel.min.js', html)


@hv_available
Expand Down
70 changes: 42 additions & 28 deletions panel/tests/theme/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,16 @@ def test_design_apply(document, comm):

DesignTest().apply(widget, model)

assert len(model.stylesheets) == 3
s1, s2, s3 = model.stylesheets
assert len(model.stylesheets) == 4
s1, s2, s3, s4 = model.stylesheets
assert isinstance(s1, str)
assert 'pn-loading' in s1
assert isinstance(s2, ImportedStyleSheet)
assert s2.url.endswith('/dist/bundled/defaulttheme/default.css')
assert s2.url.endswith('/dist/css/loading.css')
assert isinstance(s3, ImportedStyleSheet)
assert s3.url.endswith('/dist/bundled/designtest/foo.css')
assert s3.url.endswith('/dist/bundled/defaulttheme/default.css')
assert isinstance(s4, ImportedStyleSheet)
assert s4.url.endswith('/dist/bundled/designtest/foo.css')

assert model.styles == {'color': 'green'}

Expand All @@ -91,12 +93,14 @@ def test_design_apply_not_isolated(document, comm):

DesignTest().apply(widget, model, isolated=False)

assert len(model.stylesheets) == 2
s1, s2 = model.stylesheets
assert len(model.stylesheets) == 3
s1, s2, s3 = model.stylesheets
assert isinstance(s1, str)
assert 'pn-loading' in s1
assert isinstance(s2, ImportedStyleSheet)
assert s2.url.endswith('/dist/bundled/designtest/foo.css')
assert s2.url.endswith('/dist/css/loading.css')
assert isinstance(s3, ImportedStyleSheet)
assert s3.url.endswith('/dist/bundled/designtest/foo.css')

assert model.styles == {'color': 'green'}

Expand All @@ -106,16 +110,18 @@ def test_design_apply_inherited(document, comm):

DesignTest().apply(widget, model)

assert len(model.stylesheets) == 4
s1, s2, s3, s4 = model.stylesheets
assert len(model.stylesheets) == 5
s1, s2, s3, s4, s5 = model.stylesheets
assert isinstance(s1, str)
assert 'pn-loading' in s1
assert isinstance(s2, ImportedStyleSheet)
assert s2.url.endswith('/dist/bundled/defaulttheme/default.css')
assert s2.url.endswith('/dist/css/loading.css')
assert isinstance(s3, ImportedStyleSheet)
assert s3.url.endswith('/dist/bundled/designtest/foo.css')
assert s3.url.endswith('/dist/bundled/defaulttheme/default.css')
assert isinstance(s4, ImportedStyleSheet)
assert s4.url.endswith('/dist/bundled/designtest/bar.css')
assert s4.url.endswith('/dist/bundled/designtest/foo.css')
assert isinstance(s5, ImportedStyleSheet)
assert s5.url.endswith('/dist/bundled/designtest/bar.css')

assert model.styles == {'color': 'red'}

Expand All @@ -125,16 +131,18 @@ def test_design_apply_url_inherited(document, comm):

DesignTest().apply(widget, model)

assert len(model.stylesheets) == 4
s1, s2, s3, s4 = model.stylesheets
assert len(model.stylesheets) == 5
s1, s2, s3, s4, s5 = model.stylesheets
assert isinstance(s1, str)
assert 'pn-loading' in s1
assert isinstance(s2, ImportedStyleSheet)
assert s2.url.endswith('/dist/bundled/defaulttheme/default.css')
assert s2.url.endswith('/dist/css/loading.css')
assert isinstance(s3, ImportedStyleSheet)
assert s3.url.endswith('/dist/bundled/designtest/foo.css')
assert s3.url.endswith('/dist/bundled/defaulttheme/default.css')
assert isinstance(s4, ImportedStyleSheet)
assert s4.url == 'http://example.com/baz.css'
assert s4.url.endswith('/dist/bundled/designtest/foo.css')
assert isinstance(s5, ImportedStyleSheet)
assert s5.url == 'http://example.com/baz.css'

def test_design_apply_with_dark_theme(document, comm):
widget = TextInput()
Expand All @@ -143,14 +151,16 @@ def test_design_apply_with_dark_theme(document, comm):

DesignTest(theme='dark').apply(widget, model)

assert len(model.stylesheets) == 3
s1, s2, s3 = model.stylesheets
assert len(model.stylesheets) == 4
s1, s2, s3, s4 = model.stylesheets
assert isinstance(s1, str)
assert 'pn-loading' in s1
assert isinstance(s2, ImportedStyleSheet)
assert s2.url.endswith('/dist/bundled/darktheme/dark.css')
assert s2.url.endswith('/dist/css/loading.css')
assert isinstance(s3, ImportedStyleSheet)
assert s3.url.endswith('/dist/bundled/designtest/foo.css')
assert s3.url.endswith('/dist/bundled/darktheme/dark.css')
assert isinstance(s4, ImportedStyleSheet)
assert s4.url.endswith('/dist/bundled/designtest/foo.css')

assert document.theme._json == BOKEH_DARK

Expand All @@ -161,12 +171,14 @@ def test_design_apply_with_dark_theme_not_isolated(document, comm):

DesignTest(theme='dark').apply(widget, model, isolated=False)

assert len(model.stylesheets) == 2
s1, s2 = model.stylesheets
assert len(model.stylesheets) == 3
s1, s2, s3 = model.stylesheets
assert isinstance(s1, str)
assert 'pn-loading' in s1
assert isinstance(s2, ImportedStyleSheet)
assert s2.url.endswith('/dist/bundled/designtest/foo.css')
assert s2.url.endswith('/dist/css/loading.css')
assert isinstance(s3, ImportedStyleSheet)
assert s3.url.endswith('/dist/bundled/designtest/foo.css')

assert document.theme._json == BOKEH_DARK

Expand All @@ -178,14 +190,16 @@ def test_design_apply_with_dist_url(document, comm):

DesignTest().apply(widget, model)

assert len(model.stylesheets) == 3
s1, s2, s3 = model.stylesheets
assert len(model.stylesheets) == 4
s1, s2, s3, s4 = model.stylesheets
assert isinstance(s1, str)
assert 'pn-loading' in s1
assert isinstance(s2, ImportedStyleSheet)
assert s2.url == 'https://mock.holoviz.org/bundled/defaulttheme/default.css'
assert s2.url.endswith('https://mock.holoviz.org/css/loading.css')
assert isinstance(s3, ImportedStyleSheet)
assert s3.url == 'https://mock.holoviz.org/bundled/designtest/foo.css'
assert s3.url == 'https://mock.holoviz.org/bundled/defaulttheme/default.css'
assert isinstance(s4, ImportedStyleSheet)
assert s4.url == 'https://mock.holoviz.org/bundled/designtest/foo.css'

assert model.styles == {'color': 'green'}

Expand Down
24 changes: 12 additions & 12 deletions panel/theme/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from typing import (
TYPE_CHECKING, Any, ClassVar, Dict, Tuple, Type,
)
from weakref import WeakKeyDictionary

import param

Expand Down Expand Up @@ -98,8 +97,6 @@ class Design(param.Parameterized):
'dark': DarkTheme
}

_caches: ClassVar[WeakKeyDictionary[Document, Dict[str, ImportedStyleSheet]]] = WeakKeyDictionary()

def __init__(self, theme=None, **params):
if isinstance(theme, type) and issubclass(theme, Theme):
theme = theme._name
Expand All @@ -116,10 +113,11 @@ def _reapply(self, viewable: Viewable, root: Model, isolated: bool=True, cache=N
self._apply_modifiers(o, ref, self.theme, isolated, cache)

def _apply_hooks(self, viewable: Viewable, root: Model) -> None:
if root.document in self._caches:
cache = self._caches[root.document]
from ..io.state import state
if root.document in state._stylesheets:
cache = state._stylesheets[root.document]
else:
self._caches[root.document] = cache = {}
state._stylesheets[root.document] = cache = {}
with root.document.models.freeze():
self._reapply(viewable, root, isolated=False, cache=cache)

Expand Down Expand Up @@ -276,10 +274,11 @@ def apply(self, viewable: Viewable, root: Model, isolated: bool=True):
self._reapply(viewable, root, isolated=isolated)
return

if doc in self._caches:
cache = self._caches[doc]
from ..io.state import state
if doc in state._stylesheets:
cache = state._stylesheets[doc]
else:
self._caches[doc] = cache = {}
state._stylesheets[doc] = cache = {}
with doc.models.freeze():
self._reapply(viewable, root, isolated=isolated, cache=cache)
if self.theme and self.theme.bokeh_theme and doc:
Expand Down Expand Up @@ -327,12 +326,13 @@ def params(
Dictionary of parameter values to apply to the children
of the Viewable.
"""
from ..io.state import state
if doc is None:
cache = {}
elif doc in self._caches:
cache = self._caches[doc]
elif doc in state._stylesheets:
cache = state._stylesheets[doc]
else:
self._caches[doc] = cache = {}
state._stylesheets[doc] = cache = {}
modifiers, child_modifiers = self._get_modifiers(viewable, theme=self.theme)
self._patch_modifiers(doc, modifiers, cache)
return modifiers, child_modifiers
Expand Down

0 comments on commit ecd08bd

Please sign in to comment.