143 lines
4.4 KiB
Python
143 lines
4.4 KiB
Python
|
|
from django.forms import Media, MediaDefiningClass
|
||
|
|
from django.forms.utils import flatatt
|
||
|
|
from django.template.loader import render_to_string
|
||
|
|
from django.utils.functional import cached_property
|
||
|
|
from django.utils.safestring import mark_safe
|
||
|
|
from django.utils.text import slugify
|
||
|
|
|
||
|
|
from wagtail import hooks
|
||
|
|
from wagtail.admin.forms.search import SearchForm
|
||
|
|
|
||
|
|
|
||
|
|
class SearchArea(metaclass=MediaDefiningClass):
|
||
|
|
template = "wagtailadmin/shared/search_area.html"
|
||
|
|
|
||
|
|
def __init__(
|
||
|
|
self,
|
||
|
|
label,
|
||
|
|
url,
|
||
|
|
name=None,
|
||
|
|
classname="",
|
||
|
|
icon_name="",
|
||
|
|
attrs=None,
|
||
|
|
order=1000,
|
||
|
|
):
|
||
|
|
self.label = label
|
||
|
|
self.url = url
|
||
|
|
self.classname = classname
|
||
|
|
self.icon_name = icon_name
|
||
|
|
self.name = name or slugify(str(label))
|
||
|
|
self.order = order
|
||
|
|
|
||
|
|
if attrs:
|
||
|
|
self.attr_string = flatatt(attrs)
|
||
|
|
else:
|
||
|
|
self.attr_string = ""
|
||
|
|
|
||
|
|
def __lt__(self, other):
|
||
|
|
if not isinstance(other, SearchArea):
|
||
|
|
return NotImplemented
|
||
|
|
return (self.order, self.label) < (other.order, other.label)
|
||
|
|
|
||
|
|
def __le__(self, other):
|
||
|
|
if not isinstance(other, SearchArea):
|
||
|
|
return NotImplemented
|
||
|
|
return (self.order, self.label) <= (other.order, other.label)
|
||
|
|
|
||
|
|
def __gt__(self, other):
|
||
|
|
if not isinstance(other, SearchArea):
|
||
|
|
return NotImplemented
|
||
|
|
return (self.order, self.label) > (other.order, other.label)
|
||
|
|
|
||
|
|
def __ge__(self, other):
|
||
|
|
if not isinstance(other, SearchArea):
|
||
|
|
return NotImplemented
|
||
|
|
return (self.order, self.label) >= (other.order, other.label)
|
||
|
|
|
||
|
|
def __eq__(self, other):
|
||
|
|
if not isinstance(other, SearchArea):
|
||
|
|
return NotImplemented
|
||
|
|
return (self.order, self.label) == (other.order, other.label)
|
||
|
|
|
||
|
|
def is_shown(self, request):
|
||
|
|
"""
|
||
|
|
Whether this search area should be shown for the given request; permission
|
||
|
|
checks etc should go here. By default, search areas are shown all the time
|
||
|
|
"""
|
||
|
|
return True
|
||
|
|
|
||
|
|
def is_active(self, request, current=None):
|
||
|
|
if current is None:
|
||
|
|
return request.path.startswith(self.url)
|
||
|
|
else:
|
||
|
|
return self.name == current
|
||
|
|
|
||
|
|
def render_html(self, request, query, current=None):
|
||
|
|
return render_to_string(
|
||
|
|
self.template,
|
||
|
|
{
|
||
|
|
"name": self.name,
|
||
|
|
"url": self.url,
|
||
|
|
"classname": self.classname,
|
||
|
|
"icon_name": self.icon_name,
|
||
|
|
"attr_string": self.attr_string,
|
||
|
|
"label": self.label,
|
||
|
|
"active": self.is_active(request, current),
|
||
|
|
"query_string": query,
|
||
|
|
},
|
||
|
|
request=request,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
class Search:
|
||
|
|
def __init__(self, register_hook_name, construct_hook_name=None):
|
||
|
|
self.register_hook_name = register_hook_name
|
||
|
|
self.construct_hook_name = construct_hook_name
|
||
|
|
|
||
|
|
@cached_property
|
||
|
|
def registered_search_areas(self):
|
||
|
|
return sorted([fn() for fn in hooks.get_hooks(self.register_hook_name)])
|
||
|
|
|
||
|
|
def search_items_for_request(self, request):
|
||
|
|
return [item for item in self.registered_search_areas if item.is_shown(request)]
|
||
|
|
|
||
|
|
def active_search(self, request, current=None):
|
||
|
|
return [
|
||
|
|
item
|
||
|
|
for item in self.search_items_for_request(request)
|
||
|
|
if item.is_active(request, current)
|
||
|
|
]
|
||
|
|
|
||
|
|
@property
|
||
|
|
def media(self):
|
||
|
|
media = Media()
|
||
|
|
for item in self.registered_search_areas:
|
||
|
|
media += item.media
|
||
|
|
return media
|
||
|
|
|
||
|
|
def render_html(self, request, current=None):
|
||
|
|
search_areas = self.search_items_for_request(request)
|
||
|
|
|
||
|
|
# Get query parameter
|
||
|
|
form = SearchForm(request.GET)
|
||
|
|
query = ""
|
||
|
|
if form.is_valid():
|
||
|
|
query = form.cleaned_data["q"]
|
||
|
|
|
||
|
|
# provide a hook for modifying the search area, if construct_hook_name has been set
|
||
|
|
if self.construct_hook_name:
|
||
|
|
for fn in hooks.get_hooks(self.construct_hook_name):
|
||
|
|
fn(request, search_areas)
|
||
|
|
|
||
|
|
rendered_search_areas = []
|
||
|
|
for item in search_areas:
|
||
|
|
rendered_search_areas.append(item.render_html(request, query, current))
|
||
|
|
|
||
|
|
return mark_safe("".join(rendered_search_areas))
|
||
|
|
|
||
|
|
|
||
|
|
admin_search_areas = Search(
|
||
|
|
register_hook_name="register_admin_search_area",
|
||
|
|
construct_hook_name="construct_search",
|
||
|
|
)
|