From 01c25e467fac9417481951620fad689592d1c6b2 Mon Sep 17 00:00:00 2001 From: Mark Gibbs Date: Mon, 6 Aug 2018 10:24:13 -0700 Subject: [PATCH 1/5] Added generic html properties function to dash wrapper class and template that uses it --- django_plotly_dash/dash_wrapper.py | 11 ++++++++++- .../templates/django_plotly_dash/plotly_app.html | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/django_plotly_dash/dash_wrapper.py b/django_plotly_dash/dash_wrapper.py index 002a80bb..81bfe2aa 100644 --- a/django_plotly_dash/dash_wrapper.py +++ b/django_plotly_dash/dash_wrapper.py @@ -302,7 +302,7 @@ def flask_app(self): return self._flask_app def base_url(self): - 'Base url of this omponent' + 'Base url of this component' return self._base_pathname def app_context(self, *args, **kwargs): @@ -412,3 +412,12 @@ def dispatch_with_args(self, body, argMap): da.update_current_state(output['id'], output['property'], value) return res + + def extra_html_properties(self): + ''' + Return extra html properties to allow individual apps to be styled separately. + + The content returned from this function is injected unescaped into templates. + ''' + + return 'class="django-plotly-dash django-plotly-dash-iframe"' diff --git a/django_plotly_dash/templates/django_plotly_dash/plotly_app.html b/django_plotly_dash/templates/django_plotly_dash/plotly_app.html index bbe22d2c..32580973 100644 --- a/django_plotly_dash/templates/django_plotly_dash/plotly_app.html +++ b/django_plotly_dash/templates/django_plotly_dash/plotly_app.html @@ -1,3 +1,3 @@ -
+
From c290b435ee7eb96862a11522284abcd1dfc0e1bd Mon Sep 17 00:00:00 2001 From: Mark Gibbs Date: Mon, 6 Aug 2018 10:39:39 -0700 Subject: [PATCH 2/5] First cut, with css classes based on app name --- django_plotly_dash/dash_wrapper.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/django_plotly_dash/dash_wrapper.py b/django_plotly_dash/dash_wrapper.py index 81bfe2aa..f03a265d 100644 --- a/django_plotly_dash/dash_wrapper.py +++ b/django_plotly_dash/dash_wrapper.py @@ -1,4 +1,5 @@ -'''dash_wrapper +''' +dash_wrapper This module provides a DjangoDash class that can be used to expose a Plotly Dasb application through a Django server @@ -420,4 +421,7 @@ def extra_html_properties(self): The content returned from this function is injected unescaped into templates. ''' - return 'class="django-plotly-dash django-plotly-dash-iframe"' + pre_slugified_id = self._uid + slugified_id = slugify(pre_slugified_id) + + return 'class="django-plotly-dash django-plotly-dash-iframe django-plotly-dash-app-%s"' % slugified_id From 9c702c7f0f34acf174967f8f2bbd9a0f4066d7e4 Mon Sep 17 00:00:00 2001 From: Mark Gibbs Date: Tue, 7 Aug 2018 08:44:50 -0700 Subject: [PATCH 3/5] More work around class and identifier generation for html tags --- django_plotly_dash/dash_wrapper.py | 20 +++++-- .../django_plotly_dash/plotly_app.html | 2 +- .../templatetags/plotly_dash.py | 33 +++++++++++ docs/template_tags.rst | 56 +++++++++++++++++++ 4 files changed, 106 insertions(+), 5 deletions(-) diff --git a/django_plotly_dash/dash_wrapper.py b/django_plotly_dash/dash_wrapper.py index f03a265d..79b5da37 100644 --- a/django_plotly_dash/dash_wrapper.py +++ b/django_plotly_dash/dash_wrapper.py @@ -414,14 +414,26 @@ def dispatch_with_args(self, body, argMap): return res - def extra_html_properties(self): + def slugified_id(self): + pre_slugified_id = self._uid + return slugify(pre_slugified_id) + + def extra_html_properties(self, prefix=None, posfix=None, template_type=None): ''' Return extra html properties to allow individual apps to be styled separately. The content returned from this function is injected unescaped into templates. ''' - pre_slugified_id = self._uid - slugified_id = slugify(pre_slugified_id) + prefix = prefix if prefix else "django-plotly-dash" + + post_part = "-%s" % posfix if posfix else "" + template_type = template_type if template_type else "iframe" + + slugified_id = self.slugified_id() - return 'class="django-plotly-dash django-plotly-dash-iframe django-plotly-dash-app-%s"' % slugified_id + return "%(prefix)s %(prefix)s-%(template_type)s %(prefix)s-app-%(slugified_id)s%(post_part)s" % {'slugified_id':slugified_id, + 'post_part':post_part, + 'template_type':template_type, + 'prefix':prefix, + } diff --git a/django_plotly_dash/templates/django_plotly_dash/plotly_app.html b/django_plotly_dash/templates/django_plotly_dash/plotly_app.html index 32580973..bbe22d2c 100644 --- a/django_plotly_dash/templates/django_plotly_dash/plotly_app.html +++ b/django_plotly_dash/templates/django_plotly_dash/plotly_app.html @@ -1,3 +1,3 @@ -
+
diff --git a/django_plotly_dash/templatetags/plotly_dash.py b/django_plotly_dash/templatetags/plotly_dash.py index b1b331d3..c8dbd169 100644 --- a/django_plotly_dash/templatetags/plotly_dash.py +++ b/django_plotly_dash/templatetags/plotly_dash.py @@ -72,3 +72,36 @@ def plotly_message_pipe(context, url=None): 'Insert script for providing background websocket connection' url = url if url else ws_default_url return locals() + +@register.simple_tag() +def plotly_app_identifier(name=None, slug=None, da=None, postfix=None): + if name is not None: + da, app = DashApp.locate_item(name, stateless=True) + + if slug is not None: + da, app = DashApp.locate_item(slug, stateless=False) + + if not app: + app = da.as_dash_instance() + + slugified_id = app.slugified_id() + + if postfix: + return "%s-%s" %(slugified_id, postfix) + return slugified_id + +@register.simple_tag() +def plotly_class(name=None, slug=None, da=None, prefix=None, postfix=None, template_type=None): + + if name is not None: + da, app = DashApp.locate_item(name, stateless=True) + + if slug is not None: + da, app = DashApp.locate_item(slug, stateless=False) + + if not app: + app = da.as_dash_instance() + + return app.extra_html_properties(prefix=prefix, + postfix=postfix, + template_type=template_type) diff --git a/docs/template_tags.rst b/docs/template_tags.rst index ce8a14c0..91811fd6 100644 --- a/docs/template_tags.rst +++ b/docs/template_tags.rst @@ -54,3 +54,59 @@ on the page, and its ordering relative to the ``Dash`` instances using updating the page footer - to avoid delaying the main page load - along with other scripts is generally advisable. +The ``plotly_app_identifier`` template tag +----------------------------------------- + +This tag provides an identifier for an app, in a form that is suitable for use as a classname or identifier +in HTML: + +.. code-block:: jinja + + {%load plotly_dash%} + + {%plotly_app_identifier name="SimpleExample"%} + + {%plotly_app_identifier slug="liveoutput-2" postfix="A"%} + +The identifier, if the tag is not passed a ``slug``, is the result of passing the identifier of the app through +the ``django.utils.text.slugify`` function. + +The tag arguments are: + +:name = None: The name of the application, as passed to a ``DjangoDash`` constructor. +:slug = None: The slug of an existing ``DashApp`` instance. +:da = None: An existing ``django_plotly_dash.models.DashApp`` model instance. +:postfix = None: An optional string; if specified it is appended to the identifier with a hyphen. + +The validity rules for these arguments are the same as those for the ``plotly_app`` template tag. + +The ``plotly_class`` template tag +----------------------------------------- + +Generate a string of class names, suitable for a ``div`` or other element that wraps around ``django-plotly-dash`` template content. + +.. code-block:: jinja + + {%load plotly_dash%} + +
+ {%plotly_app slug="liveoutput-2" ratio="0.5" %} +
+ +The identifier, if the tag is not passed a ``slug``, is the result of passing the identifier of the app through +the ``django.utils.text.slugify`` function. + +The tag arguments are: + +:name = None: The name of the application, as passed to a ``DjangoDash`` constructor. +:slug = None: The slug of an existing ``DashApp`` instance. +:da = None: An existing ``django_plotly_dash.models.DashApp`` model instance. +:prefix = None: Optional prefix to use in place of the text ``django-plotly-dash`` in each class name +:postfix = None: An optional string; if specified it is appended to the app-specific identifier with a hyphen. +:template_type = None: Optional text to use in place of ``iframe`` in the template-specific class name + +The tag inserts a string with three class names in it. One is just the ``prefix`` argument, one +has the ``template_type`` appended, and the final one has the app identifier (as generated +by the ``plotly_app_identifier`` tag) and any ``postfix`` appended. + +The validity rules for these arguments are the same as those for the ``plotly_app`` template tag. From 736d9d5756c60644effbb192244b690fe08cd310 Mon Sep 17 00:00:00 2001 From: Mark Gibbs Date: Tue, 7 Aug 2018 09:25:13 -0700 Subject: [PATCH 4/5] Tidy up documentation, and update code following advice from linter --- django_plotly_dash/dash_wrapper.py | 5 +++-- django_plotly_dash/templatetags/plotly_dash.py | 2 ++ docs/template_tags.rst | 8 ++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/django_plotly_dash/dash_wrapper.py b/django_plotly_dash/dash_wrapper.py index 79b5da37..6fc53ba8 100644 --- a/django_plotly_dash/dash_wrapper.py +++ b/django_plotly_dash/dash_wrapper.py @@ -197,7 +197,7 @@ def before_first_request(self, *args, **kwargs): pass def run(self, *args, **kwargs): pass - def register_blueprint(*args, **kwargs): + def register_blueprint(self, *args, **kwargs): pass class WrappedDash(Dash): @@ -415,6 +415,7 @@ def dispatch_with_args(self, body, argMap): return res def slugified_id(self): + 'Return the app id in a slug-friendly form' pre_slugified_id = self._uid return slugify(pre_slugified_id) @@ -436,4 +437,4 @@ def extra_html_properties(self, prefix=None, posfix=None, template_type=None): 'post_part':post_part, 'template_type':template_type, 'prefix':prefix, - } + } diff --git a/django_plotly_dash/templatetags/plotly_dash.py b/django_plotly_dash/templatetags/plotly_dash.py index c8dbd169..047797b2 100644 --- a/django_plotly_dash/templatetags/plotly_dash.py +++ b/django_plotly_dash/templatetags/plotly_dash.py @@ -75,6 +75,7 @@ def plotly_message_pipe(context, url=None): @register.simple_tag() def plotly_app_identifier(name=None, slug=None, da=None, postfix=None): + 'Return a slug-friendly identifier' if name is not None: da, app = DashApp.locate_item(name, stateless=True) @@ -92,6 +93,7 @@ def plotly_app_identifier(name=None, slug=None, da=None, postfix=None): @register.simple_tag() def plotly_class(name=None, slug=None, da=None, prefix=None, postfix=None, template_type=None): + 'Return a string of space-separated class names' if name is not None: da, app = DashApp.locate_item(name, stateless=True) diff --git a/docs/template_tags.rst b/docs/template_tags.rst index 91811fd6..4e175cc6 100644 --- a/docs/template_tags.rst +++ b/docs/template_tags.rst @@ -78,7 +78,9 @@ The tag arguments are: :da = None: An existing ``django_plotly_dash.models.DashApp`` model instance. :postfix = None: An optional string; if specified it is appended to the identifier with a hyphen. -The validity rules for these arguments are the same as those for the ``plotly_app`` template tag. +The validity rules for these arguments are the same as those for the ``plotly_app`` template tag. If +supplied, the ``postfix`` argument +should already be in a slug-friendly form, as no processing is performed on it. The ``plotly_class`` template tag ----------------------------------------- @@ -109,4 +111,6 @@ The tag inserts a string with three class names in it. One is just the ``prefix` has the ``template_type`` appended, and the final one has the app identifier (as generated by the ``plotly_app_identifier`` tag) and any ``postfix`` appended. -The validity rules for these arguments are the same as those for the ``plotly_app`` template tag. +The validity rules for these arguments are the same as those for the ``plotly_app`` and ``plotly_app_identifier`` template tags. Note +that none of the ``prefix``, ``postfix`` and ``template_type`` arguments are modified and they should +already be in a slug-friendly form, or otherwise fit for their intended purpose. From 670daf9e82b2c64d81f6e372464766397b2e2bc1 Mon Sep 17 00:00:00 2001 From: Mark Gibbs Date: Tue, 7 Aug 2018 09:36:12 -0700 Subject: [PATCH 5/5] Added class generating tag to first demo page --- demo/demo/templates/demo_one.html | 13 +++++++++++-- django_plotly_dash/dash_wrapper.py | 4 ++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/demo/demo/templates/demo_one.html b/demo/demo/templates/demo_one.html index b91b4fa8..568daf0e 100644 --- a/demo/demo/templates/demo_one.html +++ b/demo/demo/templates/demo_one.html @@ -10,16 +10,25 @@

Simple App Embedding

the plotly_app template tag with the name of a dash application represents the simplest use of the django_plotly_dash framework.

+

+ The plotly_class tag is also used to wrap the application in css class names based on the + application (django-plotly-dash), the + type of the embedding (iframe), and the slugified version of the app name (simpleexample). +

{% load plotly_dash %}

-

{% plotly_app name="SimpleExample" %}

+

<div class="{% plotly_class name="SimpleExample"%}"> +

{% plotly_app name="SimpleExample" %}

+

<\div>

- {%plotly_app name="SimpleExample"%} +
+ {%plotly_app name="SimpleExample"%} +
{%endblock%} diff --git a/django_plotly_dash/dash_wrapper.py b/django_plotly_dash/dash_wrapper.py index 6fc53ba8..a61ba9e8 100644 --- a/django_plotly_dash/dash_wrapper.py +++ b/django_plotly_dash/dash_wrapper.py @@ -419,7 +419,7 @@ def slugified_id(self): pre_slugified_id = self._uid return slugify(pre_slugified_id) - def extra_html_properties(self, prefix=None, posfix=None, template_type=None): + def extra_html_properties(self, prefix=None, postfix=None, template_type=None): ''' Return extra html properties to allow individual apps to be styled separately. @@ -428,7 +428,7 @@ def extra_html_properties(self, prefix=None, posfix=None, template_type=None): prefix = prefix if prefix else "django-plotly-dash" - post_part = "-%s" % posfix if posfix else "" + post_part = "-%s" % postfix if postfix else "" template_type = template_type if template_type else "iframe" slugified_id = self.slugified_id()