Utils
These are an assortment of tools in the same vein of django-extensions:
Theme helpers
Instead of placing the javascript file in its proper place within the base, I opt to place it at the top before the html tag even loads. This allows me to insert a themeHTML()
command to get the user preference for theme and place it in localStorage, or use an existing theme, if localStorage is already populated.
doSelect(id-of-container-node) | |
---|---|
So even before the <html>
loads the following script gets executed:
<script>
// document.documentElement = <html> tag
// if local storage set, use it; check user pref; if still unset: light mode
if (localStorage.getItem("theme") === "dark") {
document.documentElement.classList.add("dark");
} else if (localStorage.getItem("theme") === "light") {
document.documentElement.classList.add("light");
} else if (window.matchMedia("(prefers-color-scheme: dark)")) {
document.documentElement.classList.add("dark");
localStorage.setItem("theme", "dark");
} else {
document.documentElement.classList.add("light");
localStorage.setItem("theme", "light");
}
</script>
themeHTML()
Will populate <html>
with class=light
or class=dark
depending on localStorage and/or media preference.
toggleTheme()
Will toggle the existing <html class=?>
with light
or dark
.
{% toggle_icons %}
Implements two sibling icon fragments, surrounded by a <button>
that, when clicked, calls toggleTheme()
.
Toggle icons. Returns an HTML fragment implementing two {% icon %}
's surrounded by a single button which,
when clicked, implements the toggleTheme() functionality from doTheme.js
Parameters:
Name | Type | Description | Default |
---|---|---|---|
btn_kls |
str | None
|
description. Defaults to "theme-toggler". |
'theme-toggler'
|
aria_label |
str | None
|
description. Defaults to "Toggle mode". |
'Toggle mode'
|
Returns:
Name | Type | Description |
---|---|---|
SafeText |
SafeText
|
HTML fragment button |
Source code in django_fragments/templatetags/fragments.py
htmx
These are just convenience fragments for oft-repeated idioms of + htmx. For a more comprehensive library, see django-htmx.
{% htmx_csrf %}
Just a tiny fragment to signify htmx-compatible requests that will include the csrf_token.
Source code in django_fragments/templatetags/helpers.py
Python | |
---|---|
is_htmx
Checks if a request contains the HTTP_HX_REQUEST
Header:
Determines whether or not the request should be handled differently
because of the presence of the HTTP_HX_REQUEST
header.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
request |
HttpRequest
|
The Django request object received from the view |
required |
Returns:
Name | Type | Description |
---|---|---|
bool |
bool
|
Whether or not |
Source code in django_fragments/utils.py
Whitespaceless
Remove whitespace from template tag via a Stackover flow answer from one Will Gordon. See answer:
Filter Attributes
Filter k
, v
from d
based on keys prefixed with <key>_
. Based on this result, rename or replace the key,
depending on the unprefix
flag.
This enables a shortcut for gathering all <key>-
* attributes found in the dict d
and parse them properly
before inserting them into html tags.
Examples:
>>> res = filter_attrs(key="aria", d={"aria_hidden":"true"})
>>> res['aria-hidden'] == "true"
True
>>> res_hx = filter_attrs(key="hx", d={"hx_get":"https://test.html", "hx_target":"body"})
>>> res_hx['hx-get'] == "https://test.html"
True
>>> res_hx['hx-target'] == "body"
True
>>> res_dt = filter_attrs(key="data", d={"data_site_good":"https://test.html"})
>>> res_dt['data-site-good'] == "https://test.html"
True
>>> parent_res = filter_attrs(key="parent", d={"non-a-parent": "test", "parent_class":"flex items-center", "parent_title": "I should be centered"}, unprefix=True)
>>> "parent_class" in parent_res
False
>>> "class" in parent_res
True
>>> "title" in parent_res
True
>>> "non-a-parent" in parent_res
False
>>> pre_res = filter_attrs(key="pre", d={"pre_class":"sr-only"}, unprefix=True)
>>> "class" in pre_res
True
>>> res_btn = filter_attrs(key="btn", d={"btn_name":"i-am-button", "btn_id": "btn-1"}, unprefix=True)
>>> res_btn["name"] == "i-am-button"
True
>>> res_btn["id"] == "btn-1"
True
>>> res_a= filter_attrs(key="a", d={"a_href":"#", "a_target": "_self"}, unprefix=True)
>>> res_a["href"] == "#"
True
>>> res_a["target"] == "_self"
True
Parameters:
Name | Type | Description | Default |
---|---|---|---|
d |
dict
|
Values from a template tag. |
required |
Returns:
Type | Description |
---|---|
dict[str, str]
|
dict[str, str]: dict to be used for a html tag's aria-* attributes. |
Source code in django_fragments/templatetags/utils/filter_attrs.py
Wrap Icon
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5">
<path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" />
</svg>
<span class="sr-only">Close menu</span>
<svg aria-hidden="true" class="w-6 h-6" fill="none" stroke="currentColor" stroke-width="1.5" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M6 18L18 6M6 6l12 12" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
Supplement html fragment of <svg>
icon with css classes and attributes, include parent/sibling <span>
s when parameters dictate.
The following kwargs: pre_
, post_
, and parent_
args are respected.
So pre_text
+ pre_class
will add:
<!-- pre_ implies before the icon, with special rule for pre_text -->
<span class='the-value-of-pre_class'>the-value-of-pre_text</span><svg></svg>
post_text
+ post_class
will add:
<!-- post_ implies after the icon, with special rule for post_text -->
<svg></svg><span class='the-value-of-post_class'>the-value-of-post_text</span>
parent_class
+ parent_title
will add:
<!-- parent_ implies a wrapper over the icon,
'parent_text' will not have same effect.
-->
<span class='the-value-of-parent_class' title='the-value-of-parent_title'><svg></svg></span>
Examples:
>>> markup = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5"><path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" /></svg>'
>>> res = wrap_svg(html_markup=markup, pre_text="Close menu", pre_class="sr-only", aria_hidden="true")
>>> len(res.contents) == 2
True
>>> res.contents[0]
<span class="sr-only">Close menu</span>
>>> res.contents[1].attrs == {'xmlns': 'http://www.w3.org/2000/svg', 'viewbox': '0 0 20 20', 'fill': 'currentColor', 'class': ['w-5', 'h-5'], 'aria-hidden': 'true'}
True
>>> parented = wrap_svg(html_markup=markup, parent_tag="button", pre_text="Close menu", pre_class="sr-only", aria_hidden="true")
>>> elements = list(parented.children)
>>> elements[0].name == 'button'
True
>>> list(elements[0].children)
[<span class="sr-only">Close menu</span>, <svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewbox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"></path></svg>]
Parameters:
Name | Type | Description | Default |
---|---|---|---|
html_markup |
str
|
The template that contains the |
required |
css |
str
|
Previously defined CSS to add to the |
None
|
Returns:
Name | Type | Description |
---|---|---|
SafeString |
BeautifulSoup
|
Small HTML fragment visually representing an svg icon. |