mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2026-02-11 01:26:22 +01:00
BS5 Theme
This commit is contained in:
0
allianceauth/menu/__init__.py
Normal file
0
allianceauth/menu/__init__.py
Normal file
9
allianceauth/menu/admin.py
Normal file
9
allianceauth/menu/admin.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from . import models
|
||||
|
||||
|
||||
@admin.register(models.MenuItem)
|
||||
class MenuItemAdmin(admin.ModelAdmin):
|
||||
list_display = ['text', 'hide', 'parent', 'url', 'icon_classes', 'rank']
|
||||
ordering = ('rank',)
|
||||
19
allianceauth/menu/apps.py
Normal file
19
allianceauth/menu/apps.py
Normal file
@@ -0,0 +1,19 @@
|
||||
import logging
|
||||
|
||||
from django.apps import AppConfig
|
||||
from django.db.utils import ProgrammingError, OperationalError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MenuConfig(AppConfig):
|
||||
name = "allianceauth.menu"
|
||||
label = "menu"
|
||||
|
||||
def ready(self):
|
||||
try:
|
||||
logger.debug("Syncing MenuItem Hooks")
|
||||
from allianceauth.menu.providers import MenuItem
|
||||
MenuItem.sync_hook_models()
|
||||
except (ProgrammingError, OperationalError):
|
||||
logger.warning("Migrations not completed for MenuItems")
|
||||
42
allianceauth/menu/hooks.py
Normal file
42
allianceauth/menu/hooks.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
class MenuItemHook:
|
||||
"""
|
||||
Auth Hook for generating Side Menu Items
|
||||
"""
|
||||
def __init__(self, text: str, classes: List[str], url_name: str, order: Optional[int] = None, navactive: List = list([])):
|
||||
"""
|
||||
:param text: The text shown as menu item, e.g. usually the name of the app.
|
||||
:type text: str
|
||||
:param classes: The classes that should be applied to the menu item icon
|
||||
:type classes: List[str]
|
||||
:param url_name: The name of the Django URL to use
|
||||
:type url_name: str
|
||||
:param order: An integer which specifies the order of the menu item, lowest to highest. Community apps are free to use any order above `1000`. Numbers below are served for Auth.
|
||||
:type order: Optional[int], optional
|
||||
:param navactive: A list of views or namespaces the link should be highlighted on. See [django-navhelper](https://github.com/geelweb/django-navhelper#navactive) for usage. Defaults to the supplied `url_name`.
|
||||
:type navactive: List, optional
|
||||
"""
|
||||
|
||||
self.text = text
|
||||
self.classes = classes
|
||||
self.url_name = url_name
|
||||
self.template = 'public/menuitem.html'
|
||||
self.order = order if order is not None else 9999
|
||||
|
||||
# count is an integer shown next to the menu item as badge when count != None
|
||||
# apps need to set the count in their child class, e.g. in render() method
|
||||
self.count = None
|
||||
|
||||
navactive = navactive or []
|
||||
navactive.append(url_name)
|
||||
self.navactive = navactive
|
||||
|
||||
def render(self, request):
|
||||
return render_to_string(self.template,
|
||||
{'item': self},
|
||||
request=request)
|
||||
28
allianceauth/menu/migrations/0001_initial.py
Normal file
28
allianceauth/menu/migrations/0001_initial.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# Generated by Django 4.0.2 on 2022-08-28 14:00
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='MenuItem',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('hook_function', models.CharField(max_length=500)),
|
||||
('icon_classes', models.CharField(max_length=150)),
|
||||
('text', models.CharField(max_length=150)),
|
||||
('url', models.CharField(blank=True, default=None, max_length=2048, null=True)),
|
||||
('rank', models.IntegerField(default=1000)),
|
||||
('hide', models.BooleanField(default=False)),
|
||||
('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='menu.menuitem')),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,28 @@
|
||||
# Generated by Django 4.0.2 on 2022-08-28 14:10
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('menu', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='menuitem',
|
||||
name='hook_function',
|
||||
field=models.CharField(blank=True, default=None, max_length=500, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='menuitem',
|
||||
name='icon_classes',
|
||||
field=models.CharField(blank=True, default=None, max_length=150, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='menuitem',
|
||||
name='text',
|
||||
field=models.CharField(blank=True, default=None, max_length=150, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,17 @@
|
||||
# Generated by Django 4.0.8 on 2023-02-05 07:34
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('menu', '0002_alter_menuitem_hook_function_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddIndex(
|
||||
model_name='menuitem',
|
||||
index=models.Index(fields=['rank'], name='menu_menuit_rank_e880ab_idx'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,39 @@
|
||||
# Generated by Django 4.0.10 on 2023-07-16 11:41
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('menu', '0003_menuitem_menu_menuit_rank_e880ab_idx'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='menuitem',
|
||||
name='hide',
|
||||
field=models.BooleanField(default=False, help_text='Hide this menu item. If this item is a header all items under it will be hidden too.'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='menuitem',
|
||||
name='icon_classes',
|
||||
field=models.CharField(blank=True, default=None, help_text='Font Awesome classes to show as icon on menu', max_length=150, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='menuitem',
|
||||
name='parent',
|
||||
field=models.ForeignKey(blank=True, help_text='Parent Header. (Optional)', null=True, on_delete=django.db.models.deletion.SET_NULL, to='menu.menuitem'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='menuitem',
|
||||
name='rank',
|
||||
field=models.IntegerField(default=1000, help_text='Order of the menu. Lowest First.'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='menuitem',
|
||||
name='text',
|
||||
field=models.CharField(blank=True, default=None, help_text='Text to show on menu', max_length=150, null=True),
|
||||
),
|
||||
]
|
||||
0
allianceauth/menu/migrations/__init__.py
Normal file
0
allianceauth/menu/migrations/__init__.py
Normal file
174
allianceauth/menu/models.py
Normal file
174
allianceauth/menu/models.py
Normal file
@@ -0,0 +1,174 @@
|
||||
import logging
|
||||
from allianceauth.hooks import get_hooks
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MenuItem(models.Model):
|
||||
# Auto Generated model from an auth_hook
|
||||
hook_function = models.CharField(
|
||||
max_length=500, default=None, null=True, blank=True)
|
||||
|
||||
# User Made Model
|
||||
icon_classes = models.CharField(
|
||||
max_length=150, default=None, null=True, blank=True, help_text="Font Awesome classes to show as icon on menu")
|
||||
text = models.CharField(
|
||||
max_length=150, default=None, null=True, blank=True, help_text="Text to show on menu")
|
||||
url = models.CharField(max_length=2048, default=None,
|
||||
null=True, blank=True)
|
||||
|
||||
# Put it under a header?
|
||||
parent = models.ForeignKey(
|
||||
'self', on_delete=models.SET_NULL, null=True, blank=True, help_text="Parent Header. (Optional)")
|
||||
|
||||
# Put it where? lowest first
|
||||
rank = models.IntegerField(default=1000, help_text="Order of the menu. Lowest First.")
|
||||
|
||||
# Hide it fully? Hiding a parent will hide all it's children
|
||||
hide = models.BooleanField(default=False, help_text="Hide this menu item. If this item is a header all items under it will be hidden too.")
|
||||
|
||||
class Meta:
|
||||
indexes = [
|
||||
models.Index(fields=['rank', ]),
|
||||
]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.text
|
||||
|
||||
@property
|
||||
def classes(self): # Helper function to make this model closer to the hook functions
|
||||
return self.icon_classes
|
||||
|
||||
@staticmethod
|
||||
def hook_to_name(mh):
|
||||
return f"{mh.__class__.__module__}.{mh.__class__.__name__}"
|
||||
|
||||
@staticmethod
|
||||
def sync_hook_models():
|
||||
# TODO define aa way for hooks to predefine a "parent" to create a sub menu from modules
|
||||
menu_hooks = get_hooks('menu_item_hook')
|
||||
hook_functions = []
|
||||
for hook in menu_hooks:
|
||||
mh = hook()
|
||||
cls = MenuItem.hook_to_name(mh)
|
||||
try:
|
||||
# if it exists update the text only
|
||||
# Users can adjust ranks so lets not change it if they have.
|
||||
mi = MenuItem.objects.get(hook_function=cls)
|
||||
mi.text = getattr(mh, "text", mh.__class__.__name__)
|
||||
mi.save()
|
||||
except MenuItem.DoesNotExist:
|
||||
# This is a new hook, Make the database model.
|
||||
MenuItem.objects.create(
|
||||
hook_function=cls,
|
||||
rank=getattr(mh, "order", 500),
|
||||
text=getattr(mh, "text", mh.__class__.__name__)
|
||||
)
|
||||
hook_functions.append(cls)
|
||||
|
||||
# Get rid of any legacy hooks from modules removed
|
||||
MenuItem.objects.filter(hook_function__isnull=False).exclude(
|
||||
hook_function__in=hook_functions).delete()
|
||||
|
||||
@classmethod
|
||||
def filter_items(cls, menu_item: dict):
|
||||
"""
|
||||
filter any items with no valid children from a menu
|
||||
"""
|
||||
count_items = len(menu_item['items'])
|
||||
if count_items: # if we have children confirm we can see them
|
||||
for i in menu_item['items']:
|
||||
if len(i['render']) == 0:
|
||||
count_items -= 1
|
||||
if count_items == 0: # no children left dont render header
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def render_menu(cls, request):
|
||||
"""
|
||||
Return the sorted side menu items with any items the user can't see removed.
|
||||
"""
|
||||
# Override all the items to the bs5 theme
|
||||
template = "menu/menu-item-bs5.html"
|
||||
# TODO discuss permissions for user defined links
|
||||
|
||||
# Turn all the hooks into functions
|
||||
menu_hooks = get_hooks('menu_item_hook')
|
||||
items = {}
|
||||
for fn in menu_hooks:
|
||||
f = fn()
|
||||
items[cls.hook_to_name(f)] = f
|
||||
|
||||
menu_items = MenuItem.objects.all().order_by("rank")
|
||||
|
||||
menu = {}
|
||||
for mi in menu_items:
|
||||
if mi.hide:
|
||||
# hidden item, skip it completely
|
||||
continue
|
||||
try:
|
||||
_cnt = 0
|
||||
_render = None
|
||||
if mi.hook_function:
|
||||
# This is a module hook, so we need to render it as the developer intended
|
||||
# TODO add a new attribute for apps that want to override it in the new theme
|
||||
items[mi.hook_function].template = template
|
||||
_render = items[mi.hook_function].render(request)
|
||||
_cnt = items[mi.hook_function].count
|
||||
else:
|
||||
# This is a user defined menu item so we render it with defaults.
|
||||
_render = render_to_string(template,
|
||||
{'item': mi},
|
||||
request=request)
|
||||
|
||||
parent = mi.id
|
||||
if mi.parent_id: # Set it if present
|
||||
parent = mi.parent_id
|
||||
|
||||
if parent not in menu: # this will cause the menu headers to be out of order
|
||||
menu[parent] = {"items": [],
|
||||
"count": 0,
|
||||
"render": None,
|
||||
"text": "None",
|
||||
"rank": 9999,
|
||||
}
|
||||
_mi = {
|
||||
"count": _cnt,
|
||||
"render": _render,
|
||||
"text": mi.text,
|
||||
"rank": mi.rank,
|
||||
"classes": (mi.icon_classes if mi.icon_classes != "" else "fas fa-folder"),
|
||||
"hide": mi.hide
|
||||
}
|
||||
|
||||
if parent != mi.id:
|
||||
# this is a sub item
|
||||
menu[parent]["items"].append(_mi)
|
||||
if _cnt:
|
||||
#add its count to the header count
|
||||
menu[parent]["count"] += _cnt
|
||||
else:
|
||||
if len(menu[parent]["items"]):
|
||||
# this is a top folder dont update the count.
|
||||
del(_mi["count"])
|
||||
menu[parent].update(_mi)
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
|
||||
# reset to list
|
||||
menu = list(menu.values())
|
||||
|
||||
# sort the menu list as the parents may be out of order.
|
||||
menu.sort(key=lambda i: i['rank'])
|
||||
|
||||
# ensure no empty groups
|
||||
menu = filter(cls.filter_items, menu)
|
||||
|
||||
return menu
|
||||
10
allianceauth/menu/providers.py
Normal file
10
allianceauth/menu/providers.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
from allianceauth.hooks import get_hooks
|
||||
|
||||
from .models import MenuItem
|
||||
|
||||
|
||||
class MenuProvider():
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
7
allianceauth/menu/templates/menu/menu-block.html
Normal file
7
allianceauth/menu/templates/menu/menu-block.html
Normal file
@@ -0,0 +1,7 @@
|
||||
{% for data in menu_items %}
|
||||
{% if data.items|length > 0 %}
|
||||
{% include "menu/menu-item-bs5.html" with item=data %}
|
||||
{% else %}
|
||||
{{ data.render }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
32
allianceauth/menu/templates/menu/menu-item-bs5.html
Normal file
32
allianceauth/menu/templates/menu/menu-item-bs5.html
Normal file
@@ -0,0 +1,32 @@
|
||||
{% load i18n %}
|
||||
{% load navactive %}
|
||||
{% if not item.hide %}
|
||||
<li class="d-flex flex-wrap m-2 p-2 pt-0 pb-0 mt-0 mb-0 me-0 pe-0">
|
||||
<i class="nav-link {{ item.classes }} fa-fw align-self-center me-3 {% if item.navactive %}{% navactive request item.navactive|join:' ' %}{% endif %}" {% if item.items|length %} type="button" data-bs-toggle="collapse" data-bs-target="#id-{{ item.text|slugify }}" aria-expanded="false" aria-controls="" {% endif %}></i>
|
||||
<a class="nav-link flex-fill align-self-center" {% if item.items|length %} type="button" data-bs-toggle="collapse" data-bs-target="#id-{{ item.text|slugify }}" aria-expanded="false" aria-controls="" {% endif %}
|
||||
href="{% if item.url_name %}{% url item.url_name %}{% else %}{{ item.url }}{% endif %}">
|
||||
{% translate item.text %}
|
||||
</a>
|
||||
{% if item.count >= 1 %}
|
||||
<span class="badge bg-primary rounded-pill m-2 align-self-center {% if item.items|length == 0 %}me-4{% endif %}">
|
||||
{{ item.count }}
|
||||
</span>
|
||||
{% elif item.url %}
|
||||
<span class="pill m-2 me-4 align-self-center fas fa-external-link-alt"></span>
|
||||
{% endif %}
|
||||
{% if item.items|length > 0 %}
|
||||
<span class="pill m-2 me-4 align-self-center fas fa-solid fa-chevron-down"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#id-{{ item.text|slugify }}"
|
||||
aria-expanded="false"
|
||||
aria-controls=""></span>
|
||||
<!--<hr class="m-0 w-100">-->
|
||||
<ul class="collapse ps-1 w-100 border-start rounded-start border-light border-3" id="id-{{ item.text|slugify }}">
|
||||
{% for sub_item in item.items %}
|
||||
{{ sub_item.render }}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
@@ -0,0 +1,19 @@
|
||||
{% load i18n %}
|
||||
{% load navactive %}
|
||||
{% load auth_notifications %}
|
||||
<li class="nav-item {% navactive request 'notifications:' %}"
|
||||
id="menu_item_notifications">
|
||||
<a class="nav-link"
|
||||
href="{% url 'notifications:list' %}">
|
||||
<span class="fa">
|
||||
{% with unread_count=request.user|user_unread_notification_count %}
|
||||
<i
|
||||
class="fas fa-bell{% if unread_count %} text-danger{% endif %}"
|
||||
></i>
|
||||
{% endwith %}
|
||||
</span>
|
||||
<span class="d-lg-none d-md-inline m-2">
|
||||
{% translate "Notifications" %}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
51
allianceauth/menu/templates/menu/menu-user.html
Normal file
51
allianceauth/menu/templates/menu/menu-user.html
Normal file
@@ -0,0 +1,51 @@
|
||||
{% load i18n %}
|
||||
{% load evelinks %}
|
||||
{% load theme_tags %}
|
||||
<div style="z-index:5;" class="w100 d-flex flex-column justify-content-center align-items-center text-center pb-2">
|
||||
|
||||
{% if request.user.profile.main_character %}
|
||||
{% with request.user.profile.main_character as main %}
|
||||
<div class="p-2 position-relative m-2">
|
||||
<img class="rounded-circle" src="{{ main.character_id|character_portrait_url:64 }}" alt="{{ main.character_name }}"/>
|
||||
<img class="rounded-circle position-absolute bottom-0 start-0" src="{{ main.corporation_logo_url_32 }}" alt="{{ main.corporation_name }}"/>
|
||||
{% if main.alliance_id %}
|
||||
<img class="rounded-circle position-absolute bottom-0 end-0" src="{{ main.alliance_logo_url_32 }}" alt="{{ main.alliance_name }}"/>
|
||||
{% elif main.faction_id %}
|
||||
<img class="rounded-circle position-absolute bottom-0 end-0" src="{{ main.faction_logo_url_32 }}" alt="{{ main.faction_name }}"/>
|
||||
{% endif %}
|
||||
</div>
|
||||
<h5>{{ main.character_name }}</h5>
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
<img class="rounded-circle m-2" src="{{ 1|character_portrait_url:32 }}" alt="{% translate 'No Main Character!' %}"/>
|
||||
<h5>{% translate "No Main Character!" %}</h5>
|
||||
{% endif %}
|
||||
{% if user.is_authenticated %}
|
||||
{% theme_select %}
|
||||
{% endif %}
|
||||
<div class="btn-group m-2">
|
||||
<button type="button" class="btn btn-secondary p-1">
|
||||
{% include "public/lang_select.html" %}
|
||||
</button>
|
||||
{% if user.is_superuser %}
|
||||
<a role="button" class="btn btn btn-secondary d-flex"
|
||||
href="{% url 'admin:index' %}"
|
||||
bs-data-toggle="button">
|
||||
<span class="align-self-center">{% translate "Admin" %}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="btn-group m-2">
|
||||
<a role="button" class="btn btn-info" href="{% url 'authentication:token_management' %}" alt="Token Management"><i class="fa-solid fa-user-lock fa-fw"></i></a>
|
||||
{% if user.is_superuser %}
|
||||
<a role="button" class="btn btn-info" href="https://allianceauth.readthedocs.io/" alt="Alliance Auth Documentation"><i class="fa-solid fa-book fa-fw"></i></a>
|
||||
<a role="button" class="btn btn-info" href="https://discord.gg/fjnHAmk" alt="Alliance Auth Discord"><i class="fa-brands fa-discord fa-fw"></i></a>
|
||||
<a role="button" class="btn btn-info" href="https://gitlab.com/allianceauth/allianceauth" alt="Alliance Auth Git"><i class="fa-brands fa-gitlab fa-fw"></i></a>
|
||||
{% endif %}
|
||||
{% if user.is_authenticated %}
|
||||
<a role="button" class="btn btn-danger" href="{% url 'logout' %}" alt="{% translate 'Sign Out' %}"><i class="fa-solid fa-right-from-bracket fa-fw"></i></a>
|
||||
{% else %}
|
||||
<a role="button" class="btn btn-success" href="{% url 'authentication:login' %}" alt="{% translate 'Sign In' %}"> <i class="fa-solid fa-right-to-bracket fa-fw"></i></a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
21
allianceauth/menu/templates/menu/sortable-side-menu.html
Normal file
21
allianceauth/menu/templates/menu/sortable-side-menu.html
Normal file
@@ -0,0 +1,21 @@
|
||||
{% load i18n %}
|
||||
{% load navactive %}
|
||||
{% load menu_items %}
|
||||
<div class="col-auto px-0 " >
|
||||
<div class="collapse collapse-horizontal" tabindex="-1" id="sidebar" >
|
||||
<div style="width: 350px;">
|
||||
<div class="nav-padding navbar-dark bg-dark text-light px-0 d-flex flex-column overflow-hidden vh-100 auth-logo" >
|
||||
<ul style="z-index:5;" id="sidebar-menu" class="navbar-nav flex-column mb-auto overflow-auto pt-2">
|
||||
<li class="d-flex flex-wrap m-2 p-2 pt-0 pb-0 mt-0 mb-0 me-0 pe-0">
|
||||
<i class="nav-link fas fa-tachometer-alt fa-fw align-self-center me-3 {% navactive request 'authentication:dashboard' %}"></i>
|
||||
<a class="nav-link flex-fill align-self-center" href="{% url 'authentication:dashboard' %}">
|
||||
{% translate "Dashboard" %}
|
||||
</a>
|
||||
</li>
|
||||
{% sorted_menu_items %}
|
||||
</ul>
|
||||
{% include 'menu/menu-user.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
0
allianceauth/menu/templatetags/__init__.py
Normal file
0
allianceauth/menu/templatetags/__init__.py
Normal file
35
allianceauth/menu/templatetags/menu_items.py
Normal file
35
allianceauth/menu/templatetags/menu_items.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from django import template
|
||||
|
||||
from allianceauth.hooks import get_hooks
|
||||
from allianceauth.menu.models import MenuItem
|
||||
|
||||
from ..providers import MenuProvider
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
def process_menu_items(hooks, request):
|
||||
_menu_items = list()
|
||||
items = [fn() for fn in hooks]
|
||||
items.sort(key=lambda i: i.order)
|
||||
for item in items:
|
||||
_menu_items.append(item.render(request))
|
||||
return _menu_items
|
||||
|
||||
|
||||
@register.inclusion_tag('public/menublock.html', takes_context=True)
|
||||
def menu_items(context):
|
||||
request = context['request']
|
||||
|
||||
return {
|
||||
'menu_items': process_menu_items(get_hooks('menu_item_hook'), request),
|
||||
}
|
||||
|
||||
|
||||
@register.inclusion_tag('menu/menu-block.html', takes_context=True)
|
||||
def sorted_menu_items(context):
|
||||
request = context['request']
|
||||
manu_items = MenuItem.render_menu(request)
|
||||
return {
|
||||
'menu_items':manu_items
|
||||
}
|
||||
Reference in New Issue
Block a user