diff options
author | Diana Whitten <hurgleburgler@gmail.com> | 2015-10-08 12:22:08 -0700 |
---|---|---|
committer | Diana Whitten <hurgleburgler@gmail.com> | 2015-12-03 16:07:00 +0000 |
commit | 053b5f30d7b2c4b5ba6d885dc28723744e5b22db (patch) | |
tree | 627e08e9deae4f4ca183d508b34dbb6e1848f289 /horizon | |
parent | eae45b143cb7be538c11b1b1b51aa7dd4be2e23d (diff) | |
download | horizon-053b5f30d7b2c4b5ba6d885dc28723744e5b22db.tar.gz |
Horizon Dropdown now inherits from Bootstrap Theme
Horizon dropdowns now use proper Bootstrap markup to allow for theme
inheritance. It was noticed during this effort that Horizon was
using a mixture of <a> and <button> elements within dropdowns, and
having to override CSS so that their styles were shared. This
created unnecessary complexity in the CSS:
http://getbootstrap.com/components/#dropdowns
It was also noted that we were passing Bootstrap classes defined in
the Python code to the templates through a static string that was
concatenated within all the other needed attributes. This makes
overriding the templates with custom classes difficult. New logic was
added to allow classes to be separate. This more granular approach
was added to the table drop down templates.
Partially-Implements: blueprint horizon-theme-css-reorg
Partially-Implements: blueprint bootstrap-html-standards
Partial-bug: #1490207
Change-Id: Id82999e5db37035968d39361ba9be4ff87c26f66
Diffstat (limited to 'horizon')
-rw-r--r-- | horizon/tables/actions.py | 2 | ||||
-rw-r--r-- | horizon/templates/horizon/common/_data_table_action.html | 42 | ||||
-rw-r--r-- | horizon/templates/horizon/common/_data_table_row_action_dropdown.html | 5 | ||||
-rw-r--r-- | horizon/templates/horizon/common/_data_table_row_actions_dropdown.html | 25 | ||||
-rw-r--r-- | horizon/templates/horizon/common/_data_table_table_action.html | 11 | ||||
-rw-r--r-- | horizon/templates/horizon/common/_data_table_table_actions.html | 16 | ||||
-rw-r--r-- | horizon/templatetags/horizon.py | 37 | ||||
-rw-r--r-- | horizon/utils/html.py | 15 |
8 files changed, 118 insertions, 35 deletions
diff --git a/horizon/tables/actions.py b/horizon/tables/actions.py index 00e78ec5f..fda32de06 100644 --- a/horizon/tables/actions.py +++ b/horizon/tables/actions.py @@ -37,7 +37,7 @@ from horizon.utils import html LOG = logging.getLogger(__name__) # For Bootstrap integration; can be overridden in settings. -ACTION_CSS_CLASSES = ("btn", "btn-default") +ACTION_CSS_CLASSES = () STRING_SEPARATOR = "__" diff --git a/horizon/templates/horizon/common/_data_table_action.html b/horizon/templates/horizon/common/_data_table_action.html new file mode 100644 index 000000000..3fe51eb18 --- /dev/null +++ b/horizon/templates/horizon/common/_data_table_action.html @@ -0,0 +1,42 @@ +{% load horizon %} + +{% minifyspace %} + {% if action.method != "GET" %} + <button {{ action.attr_string_nc|safe }} + class="{% if is_single %}btn btn-default {% endif %}{% if is_small %}btn-sm {% endif %}{{ action.get_final_css|safe }}" + name="action" + {% if action.help_text %} + help_text="{{ action.help_text }}" + {% endif %} + type="submit" + {% if is_table_action %} + value="{{ action.get_param_name }}"> + {% if action.icon != None %} + <span class="fa fa-{{ action.icon }}"></span> + {% endif %} + {% if action.handles_multiple %} + {{ action.verbose_name_plural }} + {% else %} + {{ action.verbose_name }} + {% endif %} + {% else %} + value="{{ action.table.name }}__{{ action.name }}__{{ row_id }}"> + {{ action.verbose_name }} + {% endif %} + </button> + {% else %} + <a {{ action.attr_string_nc|safe }} + class="{% if is_single %}btn btn-default {% endif %}{% if is_small %}btn-sm {% endif %}{{ action.get_final_css|safe }}" + {% if is_table_action %} + href="{{ action.get_link_url }}" + title="{{ action.verbose_name }}"> + {% if action.icon != None %} + <span class="fa fa-{{ action.icon }}"></span> + {% endif %} + {% else %} + href="{{ action.bound_url }}"> + {% endif %} + {{ action.verbose_name }} + </a> + {% endif %} +{% endminifyspace %} diff --git a/horizon/templates/horizon/common/_data_table_row_action_dropdown.html b/horizon/templates/horizon/common/_data_table_row_action_dropdown.html deleted file mode 100644 index aee336f6b..000000000 --- a/horizon/templates/horizon/common/_data_table_row_action_dropdown.html +++ /dev/null @@ -1,5 +0,0 @@ -{% if action.method != "GET" %} - <button {{ action.attr_string|safe }} {% if action.help_text %}help_text="{{ action.help_text }}"{% endif %} name="action" value="{{ action.table.name }}__{{ action.name }}__{{ row_id }}" type="submit">{{ action.verbose_name }}</button> -{% else %} - <a href='{{ action.bound_url }}' {{ action.attr_string|safe }}>{{ action.verbose_name }}</a> -{% endif %} diff --git a/horizon/templates/horizon/common/_data_table_row_actions_dropdown.html b/horizon/templates/horizon/common/_data_table_row_actions_dropdown.html index 37afa0ff0..9b62e9dd2 100644 --- a/horizon/templates/horizon/common/_data_table_row_actions_dropdown.html +++ b/horizon/templates/horizon/common/_data_table_row_actions_dropdown.html @@ -1,27 +1,28 @@ {% load horizon i18n %} {% spaceless %} {# This makes sure whitespace doesn't affect positioning for dropdown. #} -{% if row_actions|length > 1 %} -<div class="btn-group {% if pull_right %}pull-right{% endif %}"> - {% for action in row_actions %} + + {% if row_actions|length == 1 %} + {% include "horizon/common/_data_table_action.html" with action=row_actions.0 is_single=1 %} + {% elif row_actions|length > 1 %} + <div class="btn-group {% if pull_right %}pull-right{% endif %}"> + {% for action in row_actions %} {% if forloop.first %} - {% include "horizon/common/_data_table_row_action_dropdown.html" %} + {% include "horizon/common/_data_table_action.html" with is_small=1 is_single=1 %} <a class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" href="#"> <span class="fa fa-caret-down"></span> </a> - <ul class="dropdown-menu row_actions dropdown-menu-right"> + <ul class="dropdown-menu dropdown-menu-right row_actions"> {% else %} <li> - {% include "horizon/common/_data_table_row_action_dropdown.html" %} + {% include "horizon/common/_data_table_action.html" %} </li> {% endif %} {% if forloop.last %} </ul> {% endif %} - {% endfor %} -</div> -{% endif %} -{% if row_actions|length == 1 %} - {% include "horizon/common/_data_table_row_action_dropdown.html" with action=row_actions.0 %} -{% endif %} + {% endfor %} + </div> + {% endif %} + {% endspaceless %} diff --git a/horizon/templates/horizon/common/_data_table_table_action.html b/horizon/templates/horizon/common/_data_table_table_action.html deleted file mode 100644 index b0e819e2e..000000000 --- a/horizon/templates/horizon/common/_data_table_table_action.html +++ /dev/null @@ -1,11 +0,0 @@ -{% if action.method != "GET" %} - <button {{ action.attr_string|safe }} name="action" value="{{ action.get_param_name }}" {% if action.help_text %}help_text="{{ action.help_text }}"{% endif %} type="submit"> - {% if action.icon != None %}<span class="fa fa-{{ action.icon }}"></span> {% endif %} - {% if action.handles_multiple %}{{ action.verbose_name_plural }}{% else %}{{ action.verbose_name }}{% endif %} - </button> -{% else %} - <a href='{{ action.get_link_url }}' title='{{ action.verbose_name }}' {{ action.attr_string|safe }}> - {% if action.icon != None %}<span class="fa fa-{{ action.icon }}"></span> {% endif %} - {{ action.verbose_name }} - </a> -{% endif %} diff --git a/horizon/templates/horizon/common/_data_table_table_actions.html b/horizon/templates/horizon/common/_data_table_table_actions.html index bd3f79d50..40cb31cdc 100644 --- a/horizon/templates/horizon/common/_data_table_table_actions.html +++ b/horizon/templates/horizon/common/_data_table_table_actions.html @@ -30,14 +30,23 @@ {% endfor %} </select> <input class="form-control" value="{{ filter.filter_string|default:'' }}" type="text" name="{{ filter.get_param_name }}" /> - <button type="submit" {{ filter.attr_string|safe }}>{% trans "Filter" %}</button> + <button type="submit" class="btn btn-default {{ filter.get_final_css|safe }}" {{ filter.attr_string_nc|safe }}>{% trans "Filter" %}</button> </div> {% endif %} {% endblock table_filter %} + {% block table_actions %} + + {% comment %} + For each single action in the Table Actions area + {% endcomment %} {% for action in table_actions_buttons %} - {% include "horizon/common/_data_table_table_action.html" %} + {% include "horizon/common/_data_table_action.html" with is_table_action=1 is_single=1 %} {% endfor %} + + {% comment %} + If additional actions are defined, scoop them into the actions dropdown menu + {% endcomment %} {% if table_actions_menu|length > 0 %} <div class="btn-group table_actions_menu"> <a class="btn btn-default dropdown-toggle" data-toggle="dropdown" href="#"> @@ -51,11 +60,12 @@ <ul class="dropdown-menu dropdown-menu-right"> {% for action in table_actions_menu %} <li> - {% include "horizon/common/_data_table_table_action.html" %} + {% include "horizon/common/_data_table_action.html" with is_table_action=1 %} </li> {% endfor %} </ul> </div> {% endif %} {% endblock table_actions %} + </div> diff --git a/horizon/templatetags/horizon.py b/horizon/templatetags/horizon.py index c8ef4f112..bca67bd45 100644 --- a/horizon/templatetags/horizon.py +++ b/horizon/templatetags/horizon.py @@ -19,6 +19,7 @@ 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 _ @@ -26,10 +27,19 @@ from django.utils.translation import ugettext_lazy as _ from horizon.base import Horizon # noqa 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() + ) + + @register.filter def has_permissions(user, component): """Checks if the given user meets the permissions requirements for @@ -198,3 +208,28 @@ def datepicker_locale(): locale_mapping = getattr(settings, 'DATEPICKER_LOCALES', bootstrap_datepicker.LOCALE_MAPPING) return locale_mapping.get(translation.get_language(), 'en') + + +@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) diff --git a/horizon/utils/html.py b/horizon/utils/html.py index fe5c3c60b..e936bb89c 100644 --- a/horizon/utils/html.py +++ b/horizon/utils/html.py @@ -33,13 +33,17 @@ class HTMLElement(object): """ return {} - def get_final_attrs(self): + def get_final_attrs(self, classes=True): """Returns a dict containing the final attributes of this element which will be rendered. """ final_attrs = copy.copy(self.get_default_attrs()) final_attrs.update(self.attrs) - final_attrs['class'] = self.get_final_css() + if classes: + final_attrs['class'] = self.get_final_css() + else: + final_attrs.pop('class', None) + return final_attrs def get_final_css(self): @@ -59,6 +63,13 @@ class HTMLElement(object): return flatatt(self.get_final_attrs()) @property + def attr_string_nc(self): + """Returns a flattened string of HTML attributes based on the + ``attrs`` dict provided to the class. + """ + return flatatt(self.get_final_attrs(False)) + + @property def class_string(self): """Returns a list of class name of HTML Element in string.""" classes_str = " ".join(self.classes) |