Commit 8809d3d8 authored by Serge S. Koval's avatar Serge S. Koval

Fixed #596. Menu items can now have CSS class(es) associated, as well as glyph and image icons

parent 65503372
......@@ -148,7 +148,8 @@ class BaseView(with_metaclass(AdminViewMeta, BaseViewClass)):
return args
def __init__(self, name=None, category=None, endpoint=None, url=None,
static_folder=None, static_url_path=None):
static_folder=None, static_url_path=None,
menu_class_name=None, menu_icon_type=None, menu_icon_value=None):
"""
Constructor.
......@@ -168,9 +169,16 @@ class BaseView(with_metaclass(AdminViewMeta, BaseViewClass)):
and '/admin/' prefix won't be applied.
:param static_url_path:
Static URL Path. If provided, this specifies the path to the static url directory.
:param debug:
Optional debug flag. If set to `True`, will rethrow exceptions in some cases, so Werkzeug
debugger can catch them.
:param menu_class_name:
Optional class name for the menu item.
:param menu_icon_type:
Optional icon. Possible icon types:
- `flask.ext.admin.consts.ICON_TYPE_GLYPH` - Bootstrap glyph icon
- `flask.ext.admin.consts.ICON_TYPE_IMAGE` - Image relative to Flask static directory
- `flask.ext.admin.consts.ICON_TYPE_IMAGE_URL` - Image with full URL
:param menu_icon_value:
Icon glyph name or URL, depending on `menu_icon_type` setting
"""
self.name = name
self.category = category
......@@ -178,6 +186,11 @@ class BaseView(with_metaclass(AdminViewMeta, BaseViewClass)):
self.url = url
self.static_folder = static_folder
self.static_url_path = static_url_path
self.menu = None
self.menu_class_name = menu_class_name
self.menu_icon_type = menu_icon_type
self.menu_icon_value = menu_icon_value
# Initialized from create_blueprint
self.admin = None
......@@ -483,6 +496,9 @@ class Admin(object):
def _add_view_to_menu(self, view):
self._add_menu_item(MenuView(view.name, view), view.category)
def get_category_menu_item(self, name):
return self._menu_categories.get(name)
def init_app(self, app):
"""
Register all views with the Flask application.
......
# bootstrap glyph icon
ICON_TYPE_GLYPH = 'glyph'
# image relative to Flask static folder
ICON_TYPE_IMAGE = 'image'
# external image
ICON_TYPE_IMAGE_URL = 'image-url'
......@@ -199,7 +199,8 @@ class ModelView(BaseModelView):
"""
def __init__(self, model, name=None,
category=None, endpoint=None, url=None):
category=None, endpoint=None, url=None,
menu_class_name=None, menu_icon_type=None, menu_icon_value=None):
"""
Constructor
......@@ -213,10 +214,24 @@ class ModelView(BaseModelView):
Endpoint
:param url:
Custom URL
:param menu_class_name:
Optional class name for the menu item.
:param menu_icon_type:
Optional icon. Possible icon types:
- `flask.ext.admin.consts.ICON_TYPE_GLYPH` - Bootstrap glyph icon
- `flask.ext.admin.consts.ICON_TYPE_IMAGE` - Image relative to Flask static directory
- `flask.ext.admin.consts.ICON_TYPE_IMAGE_URL` - Image with full URL
:param menu_icon_value:
Icon glyph name or URL, depending on `menu_icon_type` setting
"""
self._search_fields = []
super(ModelView, self).__init__(model, name, category, endpoint, url)
super(ModelView, self).__init__(model, name, category, endpoint, url,
menu_class_name=menu_class_name,
menu_icon_type=menu_icon_type,
menu_icon_value=menu_icon_value)
self._primary_key = self.scaffold_pk()
......
......@@ -132,10 +132,14 @@ class ModelView(BaseModelView):
"""
def __init__(self, model, name=None,
category=None, endpoint=None, url=None):
category=None, endpoint=None, url=None,
menu_class_name=None, menu_icon_type=None, menu_icon_value=None):
self._search_fields = []
super(ModelView, self).__init__(model, name, category, endpoint, url)
super(ModelView, self).__init__(model, name, category, endpoint, url,
menu_class_name=menu_class_name,
menu_icon_type=menu_icon_type,
menu_icon_value=menu_icon_value)
self._primary_key = self.scaffold_pk()
......
......@@ -39,7 +39,8 @@ class ModelView(BaseModelView):
"""
def __init__(self, coll,
name=None, category=None, endpoint=None, url=None):
name=None, category=None, endpoint=None, url=None,
menu_class_name=None, menu_icon_type=None, menu_icon_value=None):
"""
Constructor
......@@ -53,6 +54,16 @@ class ModelView(BaseModelView):
Endpoint
:param url:
Custom URL
:param menu_class_name:
Optional class name for the menu item.
:param menu_icon_type:
Optional icon. Possible icon types:
- `flask.ext.admin.consts.ICON_TYPE_GLYPH` - Bootstrap glyph icon
- `flask.ext.admin.consts.ICON_TYPE_IMAGE` - Image relative to Flask static directory
- `flask.ext.admin.consts.ICON_TYPE_IMAGE_URL` - Image with full URL
:param menu_icon_value:
Icon glyph name or URL, depending on `menu_icon_type` setting
"""
self._search_fields = []
......@@ -62,7 +73,10 @@ class ModelView(BaseModelView):
if endpoint is None:
endpoint = ('%sview' % coll.name).lower()
super(ModelView, self).__init__(None, name, category, endpoint, url)
super(ModelView, self).__init__(None, name, category, endpoint, url,
menu_class_name=menu_class_name,
menu_icon_type=menu_icon_type,
menu_icon_value=menu_icon_value)
self.coll = coll
......
......@@ -242,7 +242,8 @@ class ModelView(BaseModelView):
"""
def __init__(self, model, session,
name=None, category=None, endpoint=None, url=None):
name=None, category=None, endpoint=None, url=None,
menu_class_name=None, menu_icon_type=None, menu_icon_value=None):
"""
Constructor.
......@@ -258,6 +259,16 @@ class ModelView(BaseModelView):
Endpoint name. If not set, defaults to the model name
:param url:
Base URL. If not set, defaults to '/admin/' + endpoint
:param menu_class_name:
Optional class name for the menu item.
:param menu_icon_type:
Optional icon. Possible icon types:
- `flask.ext.admin.consts.ICON_TYPE_GLYPH` - Bootstrap glyph icon
- `flask.ext.admin.consts.ICON_TYPE_IMAGE` - Image relative to Flask static directory
- `flask.ext.admin.consts.ICON_TYPE_IMAGE_URL` - Image with full URL
:param menu_icon_value:
Icon glyph name or URL, depending on `menu_icon_type` setting
"""
self.session = session
......@@ -271,7 +282,10 @@ class ModelView(BaseModelView):
if self.form_choices is None:
self.form_choices = {}
super(ModelView, self).__init__(model, name, category, endpoint, url)
super(ModelView, self).__init__(model, name, category, endpoint, url,
menu_class_name=menu_class_name,
menu_icon_type=menu_icon_type,
menu_icon_value=menu_icon_value)
# Primary key
self._primary_key = self.scaffold_pk()
......
......@@ -5,11 +5,18 @@ class BaseMenu(object):
"""
Base menu item
"""
def __init__(self, name):
def __init__(self, name, class_name=None, icon_type=None, icon_value=None):
self.name = name
self.class_name = class_name
self.icon_type = icon_type
self.icon_value = icon_value
self.parent = None
self._children = []
def add_child(self, menu):
# TODO: Check if menu item is already assigned to some parent
menu.parent = self
self._children.append(menu)
def get_url(self):
......@@ -25,6 +32,15 @@ class BaseMenu(object):
return False
def get_class_name(self):
return self.class_name
def get_icon_type(self):
return self.icon_type
def get_icon_value(self):
return self.icon_value
def is_visible(self):
return True
......@@ -65,11 +81,16 @@ class MenuView(BaseMenu):
Admin view menu item
"""
def __init__(self, name, view=None):
super(MenuView, self).__init__(name)
super(MenuView, self).__init__(name,
class_name=view.menu_class_name,
icon_type=view.menu_icon_type,
icon_value=view.menu_icon_value)
self._view = view
self._cached_url = None
view.menu = self
def get_url(self):
if self._view is None:
return None
......
......@@ -484,7 +484,8 @@ class BaseModelView(BaseView, ActionsMixin):
"""
def __init__(self, model,
name=None, category=None, endpoint=None, url=None):
name=None, category=None, endpoint=None, url=None,
menu_class_name=None, menu_icon_type=None, menu_icon_value=None):
"""
Constructor.
......@@ -500,9 +501,16 @@ class BaseModelView(BaseView, ActionsMixin):
'userview'
:param url:
Base URL. If not provided, will use endpoint as a URL.
:param debug:
Enable debugging mode. Won't catch exceptions on model
save failures.
:param menu_class_name:
Optional class name for the menu item.
:param menu_icon_type:
Optional icon. Possible icon types:
- `flask.ext.admin.consts.ICON_TYPE_GLYPH` - Bootstrap glyph icon
- `flask.ext.admin.consts.ICON_TYPE_IMAGE` - Image relative to Flask static directory
- `flask.ext.admin.consts.ICON_TYPE_IMAGE_URL` - Image with full URL
:param menu_icon_value:
Icon glyph name or URL, depending on `menu_icon_type` setting
"""
# If name not provided, it is model name
......@@ -513,7 +521,10 @@ class BaseModelView(BaseView, ActionsMixin):
if endpoint is None:
endpoint = model.__name__.lower()
super(BaseModelView, self).__init__(name, category, endpoint, url)
super(BaseModelView, self).__init__(name, category, endpoint, url,
menu_class_name=menu_class_name,
menu_icon_type=menu_icon_type,
menu_icon_value=menu_icon_value)
self.model = model
......
{% macro menu_icon(item) -%}
{% set icon_type = item.get_icon_type() %}
{% if icon_type %}
{% set icon_value = item.get_icon_value() %}
{% if icon_type == 'glyph' %}
<i class="{{ icon_value }}"></i>
{% elif icon_type == 'image' %}
<img src="{{ url_for('static', filename=icon_value) }}" alt="menu image"></img>
{% elif icon_type == 'image-url' %}
<img src="item.icon_value" alt="menu image"></img>
{% endif %}
{% endif %}
{%- endmacro %}
{% macro menu() %}
{% for item in admin_view.admin.menu() %}
{% if item.is_category() %}
{% set children = item.get_children() %}
{% if children %}
{% if item.is_active(admin_view) %}<li class="active dropdown">{% else %}<li class="dropdown">{% endif %}
<a class="dropdown-toggle" data-toggle="dropdown" href="javascript:void(0)">{{ item.name }}<b class="caret"></b></a>
{% set class_name = item.get_class_name() %}
{% if item.is_active(admin_view) %}
<li class="active dropdown{% if class_name %} {{class_name}}{% endif %}">
{% else %}
<li class="dropdown{% if class_name %} {{class_name}}{% endif %}">
{% endif %}
<a class="dropdown-toggle" data-toggle="dropdown" href="javascript:void(0)">
{{ menu_icon(item) }}{{ item.name }}<b class="caret"></b>
</a>
<ul class="dropdown-menu">
{% for child in children %}
{% if child.is_active(admin_view) %}<li class="active">{% else %}<li>{% endif %}
<a href="{{ child.get_url() }}">{{ child.name }}</a>
{% set class_name = child.get_class_name() %}
{% if child.is_active(admin_view) %}
<li class="active{% if class_name %} {{class_name}}{% endif %}">
{% else %}
<li{% if class_name %} class="{{class_name}}"{% endif %}>
{% endif %}
<a href="{{ child.get_url() }}">{{ menu_icon(item) }}{{ child.name }}</a>
</li>
{% endfor %}
</ul>
......@@ -16,8 +42,13 @@
{% endif %}
{% else %}
{% if item.is_accessible() and item.is_visible() %}
{% if item.is_active(admin_view) %}<li class="active">{% else %}<li>{% endif %}
<a href="{{ item.get_url() }}">{{ item.name }}</a>
{% set class_name = item.get_class_name() %}
{% if item.is_active(admin_view) %}
<li class="active{% if class_name %} {{class_name}}{% endif %}">
{% else %}
<li{% if class_name %} class="{{class_name}}"{% endif %}>
{% endif %}
<a href="{{ item.get_url() }}">{{ menu_icon(item) }}{{ item.name }}</a>
</li>
{% endif %}
{% endif %}
......
{% macro menu_icon(item) -%}
{% set icon_type = item.get_icon_type() %}
{% if icon_type %}
{% set icon_value = item.get_icon_value() %}
{% if icon_type == 'glyph' %}
<i class="glyphicon {{ icon_value }}"></i>
{% elif icon_type == 'image' %}
<img src="{{ url_for('static', filename=icon_value) }}" alt="menu image"></img>
{% elif icon_type == 'image-url' %}
<img src="item.icon_value" alt="menu image"></img>
{% endif %}
{% endif %}
{%- endmacro %}
{% macro menu() %}
{% for item in admin_view.admin.menu() %}
{% if item.is_category() %}
{% set children = item.get_children() %}
{% if children %}
{% if item.is_active(admin_view) %}<li class="active dropdown">{% else %}<li class="dropdown">{% endif %}
<a class="dropdown-toggle" data-toggle="dropdown" href="javascript:void(0)">{{ item.name }}<b class="caret"></b></a>
{% if item.is_active(admin_view) %}
<li class="active dropdown{% if class_name %} {{class_name}}{% endif %}">
{% else %}
<li class="dropdown{% if class_name %} {{class_name}}{% endif %}">
{% endif %}
<a class="dropdown-toggle" data-toggle="dropdown" href="javascript:void(0)">aaas{{ menu_icon(item) }}{{ item.name }}<b class="caret"></b></a>
<ul class="dropdown-menu">
{% for child in children %}
{% if child.is_active(admin_view) %}<li class="active">{% else %}<li>{% endif %}
<a href="{{ child.get_url() }}">{{ child.name }}</a>
{% set class_name = child.get_class_name() %}
{% if child.is_active(admin_view) %}
<li class="active"{% if class_name %} {{class_name}}{% endif %}>
{% else %}
<li{% if class_name %} class="{{class_name}}"{% endif %}>
{% endif %}
<a href="{{ child.get_url() }}">asasdasd{{ menu_icon(item) }}{{ child.name }}</a>
</li>
{% endfor %}
</ul>
......@@ -16,8 +39,13 @@
{% endif %}
{% else %}
{% if item.is_accessible() and item.is_visible() %}
{% if item.is_active(admin_view) %}<li class="active">{% else %}<li>{% endif %}
<a href="{{ item.get_url() }}">{{ item.name }}</a>
{% set class_name = item.get_class_name() %}
{% if item.is_active(admin_view) %}
<li class="active"{% if class_name %} {{class_name}}{% endif %}>
{% else %}
<li{% if class_name %} class="{{class_name}}"{% endif %}>
{% endif %}
<a href="{{ item.get_url() }}">{{ menu_icon(item) }}{{ item.name }}</a>
</li>
{% endif %}
{% endif %}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment