Source code for websauna.system.core.render

"""Rendering helpers."""
# Websauna
from websauna.utils.orderedset import OrderedSet


[docs]class OnDemandResourceRenderer: """A JS and CSS resource registry which helps to allow widgets and such add JS and CSS files dynamically on the page. Usually instance of this class is available as ``request.on_demand_resource_renderer``. The best practice is to place all JavaScript files before the closing ``</body>`` tag, so that they do not block the the page rendering and decrease the page response time. However, out there exist a lot of badly written JavaScript code which does not honour this - they have ``<script>`` tags in the middle of ``<body>`` and even worse assume you have loaded dependencies, like jQuery, in the ``<head>``. Namely, Deform 2 form library does this. ``BodyRelocatableResourceRegistry`` contains the logic to determine if ``<script>`` tags should go to the end of the page (preferred) or to ``<head>`` (in case some javascript makes assumptions of this). If any widget requires resources assume JS must go to head. See also :py:attr`deform.widget.default_resources` which includes the list of default resources activated for any form on the page. More information * https://developers.google.com/speed/docs/insights/BlockingJS * https://developers.google.com/web/fundamentals/performance/critical-rendering-path/adding-interactivity-with-javascript#parser-blocking-vs-asynchronous-javascript """ def __init__(self): self.resources = { "js": OrderedSet(), "css": OrderedSet(), } self.js_requires_head = False
[docs] def request_resource(self, kind: str, resource_url: str, js_requires_head: bool = False): """A widget or something wants to place a CSS or JS file on the page rendering. :param kind: "js" or "css" :param resource_path: Resolved full URL to this resource :param js_requires_head: Move all JavaScript to <head> instead of </body> end. I.e. you have <script> tags in the middle of HTML. """ self.resources[kind].add(resource_url) # If one JS wants to go head then everybody goes self.js_requires_head |= js_requires_head
[docs] def is_js_in_head(self, request) -> bool: return self.js_requires_head
[docs] def get_resources(self, kind) -> OrderedSet: """Get list of resource URLs to render. :param kind: "js" or "css" """ return self.resources[kind]
[docs]def get_on_demand_resource_renderer(request): """Reify method for configuration.""" return OnDemandResourceRenderer()