horizon/horizon/templatetags/horizon.py

244 lines
7.8 KiB
Python

# Copyright 2012 Nebula, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import absolute_import
from collections import OrderedDict
from horizon.contrib import bootstrap_datepicker
from django.conf import settings
from django import template
from django.template import Node
from django.utils.encoding import force_text
from django.utils import translation
from django.utils.translation import ugettext_lazy as _
from horizon.base import Horizon
from horizon import conf
register = template.Library()
class MinifiedNode(Node):
def __init__(self, nodelist):
self.nodelist = nodelist
def render(self, context):
return ' '.join(
force_text(self.nodelist.render(context).strip()).split()
).replace(' > ', '>').replace(' <', '<')
@register.filter
def has_permissions(user, component):
"""Checks if the given user meets the permissions requirements for
the component.
"""
return user.has_perms(getattr(component, 'permissions', set()))
@register.filter
def has_permissions_on_list(components, user):
return [component for component
in components if has_permissions(user, component)]
@register.inclusion_tag('horizon/_sidebar.html', takes_context=True)
def horizon_nav(context):
if 'request' not in context:
return {}
current_dashboard = context['request'].horizon.get('dashboard', None)
current_panel_group = None
current_panel = context['request'].horizon.get('panel', None)
dashboards = []
for dash in Horizon.get_dashboards():
panel_groups = dash.get_panel_groups()
non_empty_groups = []
for group in panel_groups.values():
allowed_panels = []
for panel in group:
if (callable(panel.nav) and panel.nav(context) and
panel.can_access(context)):
allowed_panels.append(panel)
elif (not callable(panel.nav) and panel.nav and
panel.can_access(context)):
allowed_panels.append(panel)
if panel == current_panel:
current_panel_group = group.slug
if allowed_panels:
non_empty_groups.append((group, allowed_panels))
if (callable(dash.nav) and dash.nav(context) and
dash.can_access(context)):
dashboards.append((dash, OrderedDict(non_empty_groups)))
elif (not callable(dash.nav) and dash.nav and
dash.can_access(context)):
dashboards.append((dash, OrderedDict(non_empty_groups)))
return {'components': dashboards,
'user': context['request'].user,
'current': current_dashboard,
'current_panel_group': current_panel_group,
'current_panel': current_panel.slug if current_panel else '',
'request': context['request']}
@register.inclusion_tag('horizon/_nav_list.html', takes_context=True)
def horizon_main_nav(context):
"""Generates top-level dashboard navigation entries."""
if 'request' not in context:
return {}
current_dashboard = context['request'].horizon.get('dashboard', None)
dashboards = []
for dash in Horizon.get_dashboards():
if dash.can_access(context):
if callable(dash.nav) and dash.nav(context):
dashboards.append(dash)
elif dash.nav:
dashboards.append(dash)
return {'components': dashboards,
'user': context['request'].user,
'current': current_dashboard,
'request': context['request']}
@register.inclusion_tag('horizon/_subnav_list.html', takes_context=True)
def horizon_dashboard_nav(context):
"""Generates sub-navigation entries for the current dashboard."""
if 'request' not in context:
return {}
dashboard = context['request'].horizon['dashboard']
panel_groups = dashboard.get_panel_groups()
non_empty_groups = []
for group in panel_groups.values():
allowed_panels = []
for panel in group:
if (callable(panel.nav) and panel.nav(context) and
panel.can_access(context)):
allowed_panels.append(panel)
elif (not callable(panel.nav) and panel.nav and
panel.can_access(context)):
allowed_panels.append(panel)
if allowed_panels:
if group.name is None:
non_empty_groups.append((dashboard.name, allowed_panels))
else:
non_empty_groups.append((group.name, allowed_panels))
return {'components': OrderedDict(non_empty_groups),
'user': context['request'].user,
'current': context['request'].horizon['panel'].slug,
'request': context['request']}
@register.filter
def quota(val, units=None):
if val == float("inf"):
return _("(No Limit)")
elif units is not None:
return "%s %s %s" % (val, force_text(units),
force_text(_("Available")))
else:
return "%s %s" % (val, force_text(_("Available")))
@register.filter
def quotainf(val, units=None):
if val == float("inf"):
return '-1'
elif units is not None:
return "%s %s" % (val, units)
else:
return val
@register.simple_tag
def quotapercent(used, limit):
if used >= limit or limit == 0:
return 100
elif limit == float("inf"):
return '[%s, true]' % used
else:
return round((float(used) / float(limit)) * 100)
class JSTemplateNode(template.Node):
"""Helper node for the ``jstemplate`` template tag."""
def __init__(self, nodelist):
self.nodelist = nodelist
def render(self, context,):
output = self.nodelist.render(context)
output = output.replace('[[[', '{{{').replace(']]]', '}}}')
output = output.replace('[[', '{{').replace(']]', '}}')
output = output.replace('[%', '{%').replace('%]', '%}')
return output
@register.tag
def jstemplate(parser, token):
"""Replaces ``[[[`` and ``]]]`` with ``{{{`` and ``}}}``,
``[[`` and ``]]`` with ``{{`` and ``}}`` and
``[%`` and ``%]`` with ``{%`` and ``%}`` to avoid conflicts
with Django's template engine when using any of the Mustache-based
templating libraries.
"""
nodelist = parser.parse(('endjstemplate',))
parser.delete_first_token()
return JSTemplateNode(nodelist)
@register.assignment_tag
def load_config():
return conf
@register.assignment_tag
def datepicker_locale():
locale_mapping = getattr(settings, 'DATEPICKER_LOCALES',
bootstrap_datepicker.LOCALE_MAPPING)
return locale_mapping.get(translation.get_language(), 'en')
@register.assignment_tag
def template_cache_age():
return getattr(settings, 'NG_TEMPLATE_CACHE_AGE', 0)
@register.tag
def minifyspace(parser, token):
"""Removes whitespace including tab and newline characters.
Do not use this if you are using a <pre> tag.
Example usage::
{% minifyspace %}
<p>
<a title="foo"
href="foo/">
Foo
</a>
</p>
{% endminifyspace %}
This example would return this HTML::
<p><a title="foo" href="foo/">Foo</a></p>
"""
nodelist = parser.parse(('endminifyspace',))
parser.delete_first_token()
return MinifiedNode(nodelist)