1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Closes #14736: Enable HTMX navigation globally (#15158)

* Enable HTMX boosting

* Refactor HTMX properties for tables

* Fix dashboard object list widget

* Disable scrolling to page content

* Fix initialization of TomSelect dropdowns after HTMX loading

* Replace formaction properties with hx-post

* Fix quick search field on object list view

* Reinitialize copy-to-clipboard buttons upon HTMX load

* Disable scrolling effect for intra-page navigation

* Introduce user preference for toggling HTMX navigation

* Enable HTMX navigation only when selected by user

* Pass htmx_navigation context

* Fix display of confirmation form when deleting an object

* Disable HTMX boosting for rack elevation SVG downloads

* Fix dyanmic form rendering

* Introduce htmx_boost template tag; enable HTMX for user menu

* Use out-of-band sap to update footer stamp

* Fix display of toasts after form submission

* Fix user preference selection

* Misc cleanup

* Rename render_partial() to htmx_partial()

* Add docstring to htmx_boost template tag

* Disable HTMX for user preferences form to force a full page refresh on changes
This commit is contained in:
Jeremy Stretch
2024-03-28 11:51:38 -04:00
committed by GitHub
parent 04d8db7c52
commit 744be59a4d
54 changed files with 213 additions and 160 deletions

13
netbox/utilities/htmx.py Normal file
View File

@@ -0,0 +1,13 @@
__all__ = (
'htmx_partial',
)
PAGE_CONTAINER_ID = 'page-content'
def htmx_partial(request):
"""
Determines whether to render partial (versus complete) HTML content
in response to an HTMX request, based on the target element.
"""
return request.htmx and request.htmx.target != PAGE_CONTAINER_ID

View File

@@ -1,4 +1,5 @@
<div class="card-body htmx-container table-responsive p-0"
hx-get="{% url viewname %}{% if url_params %}?{{ url_params.urlencode }}{% endif %}"
hx-trigger="load"
hx-target="this"
hx-trigger="load" hx-select="table" hx-swap="innerHTML"
></div>

View File

@@ -1,6 +1,6 @@
{% load i18n %}
{% if url %}
<button type="submit" name="_delete" formaction="{{ url }}" class="btn btn-red">
<button type="submit" name="_delete" {% formaction %}="{{ url }}" class="btn btn-red">
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete Selected" %}
</button>
{% endif %}

View File

@@ -1,6 +1,6 @@
{% load i18n %}
{% if url %}
<button type="submit" name="_edit" formaction="{{ url }}" class="btn btn-yellow">
<button type="submit" name="_edit" {% formaction %}="{{ url }}" class="btn btn-yellow">
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit Selected" %}
</button>
{% endif %}

View File

@@ -2,6 +2,8 @@
<a href="#"
hx-get="{{ url }}"
hx-target="#htmx-modal-content"
hx-swap="innerHTML"
hx-select="form"
class="btn btn-red"
data-bs-toggle="modal"
data-bs-target="#htmx-modal"

View File

@@ -1,6 +1,7 @@
{% load helpers %}
{% load navigation %}
<ul class="navbar-nav pt-lg-2">
<ul class="navbar-nav pt-lg-2" {% htmx_boost %}>
{% for menu, groups in nav_items %}
<li class="nav-item dropdown">

View File

@@ -8,6 +8,7 @@ __all__ = (
'checkmark',
'copy_content',
'customfield_value',
'formaction',
'tag',
)
@@ -113,3 +114,14 @@ def htmx_table(context, viewname, return_url=None, **kwargs):
'viewname': viewname,
'url_params': url_params,
}
@register.simple_tag(takes_context=True)
def formaction(context):
"""
Replace the 'formaction' attribute on an HTML element with the appropriate HTMX attributes
if HTMX navigation is enabled (per the user's preferences).
"""
if context.get('htmx_navigation', False):
return 'hx-push-url="true" hx-post'
return 'formaction'

View File

@@ -1,11 +1,11 @@
from typing import Dict
from django import template
from django.template import Context
from django.utils.safestring import mark_safe
from netbox.navigation.menu import MENUS
__all__ = (
'nav',
'htmx_boost',
)
@@ -13,7 +13,7 @@ register = template.Library()
@register.inclusion_tag("navigation/menu.html", takes_context=True)
def nav(context: Context) -> Dict:
def nav(context):
"""
Render the navigation menu.
"""
@@ -40,6 +40,31 @@ def nav(context: Context) -> Dict:
nav_items.append((menu, groups))
return {
"nav_items": nav_items,
"request": context["request"]
'nav_items': nav_items,
'htmx_navigation': context['htmx_navigation']
}
@register.simple_tag(takes_context=True)
def htmx_boost(context, target='#page-content', select='#page-content'):
"""
Renders the HTML attributes needed to effect HTMX boosting within an element if
HTMX navigation is enabled for the request. The target and select parameters are
rendered as `hx-target` and `hx-select`, respectively. For example:
<div id="page-content" {% htmx_boost %}>
If HTMX navigation is not enabled, the tag renders no content.
"""
if not context.get('htmx_navigation', False):
return ''
hx_params = {
'hx-boost': 'true',
'hx-target': target,
'hx-select': select,
'hx-swap': 'outerHTML show:window:top',
}
htmx_params = ' '.join([
f'{k}="{v}"' for k, v in hx_params.items()
])
return mark_safe(htmx_params)