"""Default template variables."""
# Standard Library
import datetime
import logging
# Pyramid
from pyramid.events import BeforeRender
# TODO: We expose this as a global for documentation. Migrate to non-global map in the future.
from pyramid.path import AssetResolver # noQA
from pyramid.path import DottedNameResolver
# Websauna
from websauna.utils.time import now
logger = logging.getLogger(__name__)
_template_variables = {}
[docs]def var(name):
"""Decorator to mark template variables for documentation."""
def _inner(func):
_template_variables[name] = func
return func
return _inner
[docs]@var("site_name")
def site_name(request, registry, settings):
"""Expose website name from ``websauna.site_name`` config variable to templates.
Example:
.. code-block:: html+jinja
<div class="jumbotron text-center">
<h1>{{ site_name }}</h1>
<p class="lead text-center">
{{ site_tag_line }}
</p>
</div>
"""
return settings["websauna.site_name"]
[docs]@var("site_title")
def site_title(request, registry, settings):
"""Expose website name from ``websauna.site_title`` config variable to templates.
This is the default ``<title>`` tag.
Example:
.. code-block:: html+jinja
<meta>
<title>My page - {{ site_title }}</title>
</meta>
"""
# Use .get() for BBB
return settings.get("websauna.site_title", "")
[docs]@var("site_url")
def site_url(request, registry, settings):
"""Expose website URL from ``websauna.site_url`` config variable to templates.
.. note ::
You should not use this variable in web page templates. This variable is intended for cases where one needs templating without running a web server.
The correct way to get the home URL of your website is:
.. code-block:: html+jinja
<a href="{{ request.route_url('home') }}">Home</a>
"""
return settings["websauna.site_url"]
[docs]@var("site_author")
def site_author(request, registry, settings):
"""Expose website URL from ``websauna.site_author`` config variable to templates.
This is used in footer to display the site owner.
"""
return settings["websauna.site_author"]
[docs]@var("site_tag_line")
def site_tag_line(request, registry, settings):
"""Expose website URL from ``websauna.site_tag_line`` config variable to templates.
This is used on the default front page to catch the attention of audience.
"""
return settings["websauna.site_tag_line"]
[docs]@var("site_email_prefix")
def site_email_prefix(request, registry, settings):
"""Expose website URL from ``websauna.site_email_prefix`` config variable to templates.
This is used as the subject prefix in outgoing email. E.g. if the value is ``SuperSite`` you'll email subjects::
[SuperSite] Welcome to www.supersite.com
"""
return settings["websauna.site_email_prefix"]
[docs]@var("site_time_zone")
def site_time_zone(request, registry, settings):
"""Expose website URL from ``websauna.site_time_zone`` config variable to templates.
By best practices, all dates and times should be stored in the database using :term:`UTC` time. This setting allows quickly convert dates and times to your local time.
Example:
.. code-block:: html+jinja
<p>
<strong>Bar opens</strong>:
{{ opening_at|friendly_time(timezone=site_time_zone) }}
</p>
Default value is ``UTC``.
See `timezone abbreviation list <https://en.wikipedia.org/wiki/List_of_time_zone_abbreviations>`_.
"""
return settings.get("websauna.site_timezone", "UTC")
[docs]@var("js_in_head")
def js_in_head(request, registry, settings):
"""Should ``<script>`` tags be placed in ``<head>`` or end of ``<body>``.
"""
on_demand_resource_renderer = getattr(request, "on_demand_resource_renderer", None)
if on_demand_resource_renderer and on_demand_resource_renderer.is_js_in_head(request):
return True
else:
return False
[docs]@var("on_demand_resource_renderer")
def on_demand_resource_renderer(request, registry, settings):
"""Active instance of :py:class:`websauna.system.core.render.OnDemandResourceRenderer` managing dynamic CSS and JS. May be None."""
on_demand_resource_renderer = getattr(request, "on_demand_resource_renderer", None)
return on_demand_resource_renderer
@var("now")
def _now(request, registry, settings):
"""Get the current time as :term:`UTC`.
:py:func:`websauna.utils.time.now` function.
Example:
.. code-block: html+jinja
<footer class="footer">
<div class="container-fluid">
<p class="copyright pull-right">
© {{ now().year }} {{ site_author }}
</p>
</div>
</footer>
"""
return now
@var("timedelta")
def _timedelta(request, registry, settings):
"""Expose Python timedelta class to templates, so you can do relative time calculations.
For more information see :py:class:`datetime.timedelta`.
Example:
.. code-block: html+jinja
<div class="panel panel-default panel-admin">
<div class="panel-body">
<h2>
Current power generation
(as generated {{ (now() - timedelta(days=14))|arrow_format("YYYY-MM-DD")}}*)
</h2>
<div id="super-nice-graph"></div>
<p>* Incoming data delayed two weeks</p>
</div>
</div>
"""
return datetime.timedelta
[docs]@var("debug")
def debug(request, registry, settings):
"""Invoke pdb breakpoint from a template.
Example:
.. code-block:: html+jinja
<h1>{{ site_name }}</h1>
{{ debug() }}
This will invoke function from :ref:`websauna.template_debugger` setting. The debugger is turned on only on :ref:`development.ini`. If there is no debugger configured, a warning is given.
"""
def _dummy():
logger.warning("{{ debug() }} invoked, but websauna.template_debugger not set")
return ""
template_debugger = settings.get("websauna.template_debugger")
if not template_debugger:
debugger = _dummy
else:
r = DottedNameResolver()
debugger = r.resolve(template_debugger)
def _inner():
debugger()
return ""
return _inner
[docs]def includeme(config):
def on_before_render(event):
# Augment Pyramid template renderers with these extra variables and deal with JS placement
request = event["request"]
for name, func in _template_variables.items():
event[name] = func(request, request.registry, request.registry.settings)
config.add_subscriber(on_before_render, BeforeRender)