mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-21 17:11:08 -05:00
okay fine
This commit is contained in:
147
.venv/lib/python3.12/site-packages/django_htmx/http.py
Normal file
147
.venv/lib/python3.12/site-packages/django_htmx/http.py
Normal file
@@ -0,0 +1,147 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from typing import Any
|
||||
from typing import Literal
|
||||
from typing import TypeVar
|
||||
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
from django.http import HttpResponse
|
||||
from django.http.response import HttpResponseBase
|
||||
from django.http.response import HttpResponseRedirectBase
|
||||
|
||||
HTMX_STOP_POLLING = 286
|
||||
|
||||
|
||||
class HttpResponseStopPolling(HttpResponse):
|
||||
status_code = HTMX_STOP_POLLING
|
||||
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
self._reason_phrase = "Stop Polling"
|
||||
|
||||
|
||||
class HttpResponseClientRedirect(HttpResponseRedirectBase):
|
||||
status_code = 200
|
||||
|
||||
def __init__(self, redirect_to: str, *args: Any, **kwargs: Any) -> None:
|
||||
super().__init__(redirect_to, *args, **kwargs)
|
||||
self["HX-Redirect"] = self["Location"]
|
||||
del self["Location"]
|
||||
|
||||
@property
|
||||
def url(self) -> str:
|
||||
return self["HX-Redirect"]
|
||||
|
||||
|
||||
class HttpResponseClientRefresh(HttpResponse):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self["HX-Refresh"] = "true"
|
||||
|
||||
|
||||
class HttpResponseLocation(HttpResponseRedirectBase):
|
||||
status_code = 200
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
redirect_to: str,
|
||||
*args: Any,
|
||||
source: str | None = None,
|
||||
event: str | None = None,
|
||||
target: str | None = None,
|
||||
swap: Literal[
|
||||
"innerHTML",
|
||||
"outerHTML",
|
||||
"beforebegin",
|
||||
"afterbegin",
|
||||
"beforeend",
|
||||
"afterend",
|
||||
"delete",
|
||||
"none",
|
||||
None,
|
||||
] = None,
|
||||
select: str | None = None,
|
||||
values: dict[str, str] | None = None,
|
||||
headers: dict[str, str] | None = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
super().__init__(redirect_to, *args, **kwargs)
|
||||
spec: dict[str, str | dict[str, str]] = {
|
||||
"path": self["Location"],
|
||||
}
|
||||
del self["Location"]
|
||||
if source is not None:
|
||||
spec["source"] = source
|
||||
if event is not None:
|
||||
spec["event"] = event
|
||||
if target is not None:
|
||||
spec["target"] = target
|
||||
if swap is not None:
|
||||
spec["swap"] = swap
|
||||
if select is not None:
|
||||
spec["select"] = select
|
||||
if headers is not None:
|
||||
spec["headers"] = headers
|
||||
if values is not None:
|
||||
spec["values"] = values
|
||||
self["HX-Location"] = json.dumps(spec)
|
||||
|
||||
|
||||
_HttpResponse = TypeVar("_HttpResponse", bound=HttpResponseBase)
|
||||
|
||||
|
||||
def push_url(response: _HttpResponse, url: str | Literal[False]) -> _HttpResponse:
|
||||
response["HX-Push-Url"] = "false" if url is False else url
|
||||
return response
|
||||
|
||||
|
||||
def replace_url(response: _HttpResponse, url: str | Literal[False]) -> _HttpResponse:
|
||||
response["HX-Replace-Url"] = "false" if url is False else url
|
||||
return response
|
||||
|
||||
|
||||
def reswap(response: _HttpResponse, method: str) -> _HttpResponse:
|
||||
response["HX-Reswap"] = method
|
||||
return response
|
||||
|
||||
|
||||
def retarget(response: _HttpResponse, target: str) -> _HttpResponse:
|
||||
response["HX-Retarget"] = target
|
||||
return response
|
||||
|
||||
|
||||
def trigger_client_event(
|
||||
response: _HttpResponse,
|
||||
name: str,
|
||||
params: dict[str, Any] | None = None,
|
||||
*,
|
||||
after: Literal["receive", "settle", "swap"] = "receive",
|
||||
encoder: type[json.JSONEncoder] = DjangoJSONEncoder,
|
||||
) -> _HttpResponse:
|
||||
params = params or {}
|
||||
|
||||
if after == "receive":
|
||||
header = "HX-Trigger"
|
||||
elif after == "settle":
|
||||
header = "HX-Trigger-After-Settle"
|
||||
elif after == "swap":
|
||||
header = "HX-Trigger-After-Swap"
|
||||
else:
|
||||
raise ValueError(
|
||||
"Value for 'after' must be one of: 'receive', 'settle', or 'swap'."
|
||||
)
|
||||
|
||||
if header in response:
|
||||
value = response[header]
|
||||
try:
|
||||
data = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise ValueError(f"{header!r} value should be valid JSON.") from exc
|
||||
data[name] = params
|
||||
else:
|
||||
data = {name: params}
|
||||
|
||||
response[header] = json.dumps(data, cls=encoder)
|
||||
|
||||
return response
|
||||
17
.venv/lib/python3.12/site-packages/django_htmx/jinja.py
Normal file
17
.venv/lib/python3.12/site-packages/django_htmx/jinja.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from django.conf import settings
|
||||
from django.templatetags.static import static
|
||||
from django.utils.html import format_html
|
||||
|
||||
|
||||
def django_htmx_script() -> str:
|
||||
# Optimization: whilst the script has no behaviour outside of debug mode,
|
||||
# don't include it.
|
||||
if not settings.DEBUG:
|
||||
return ""
|
||||
return format_html(
|
||||
'<script src="{}" data-debug="{}" defer></script>',
|
||||
static("django-htmx.js"),
|
||||
str(bool(settings.DEBUG)),
|
||||
)
|
||||
114
.venv/lib/python3.12/site-packages/django_htmx/middleware.py
Normal file
114
.venv/lib/python3.12/site-packages/django_htmx/middleware.py
Normal file
@@ -0,0 +1,114 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from collections.abc import Awaitable
|
||||
from typing import Any
|
||||
from typing import Callable
|
||||
from urllib.parse import unquote
|
||||
from urllib.parse import urlsplit
|
||||
from urllib.parse import urlunsplit
|
||||
|
||||
from asgiref.sync import iscoroutinefunction
|
||||
from asgiref.sync import markcoroutinefunction
|
||||
from django.http import HttpRequest
|
||||
from django.http.response import HttpResponseBase
|
||||
from django.utils.functional import cached_property
|
||||
|
||||
|
||||
class HtmxMiddleware:
|
||||
sync_capable = True
|
||||
async_capable = True
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
get_response: (
|
||||
Callable[[HttpRequest], HttpResponseBase]
|
||||
| Callable[[HttpRequest], Awaitable[HttpResponseBase]]
|
||||
),
|
||||
) -> None:
|
||||
self.get_response = get_response
|
||||
self.async_mode = iscoroutinefunction(self.get_response)
|
||||
|
||||
if self.async_mode:
|
||||
# Mark the class as async-capable, but do the actual switch
|
||||
# inside __call__ to avoid swapping out dunder methods
|
||||
markcoroutinefunction(self)
|
||||
|
||||
def __call__(
|
||||
self, request: HttpRequest
|
||||
) -> HttpResponseBase | Awaitable[HttpResponseBase]:
|
||||
if self.async_mode:
|
||||
return self.__acall__(request)
|
||||
request.htmx = HtmxDetails(request) # type: ignore [attr-defined]
|
||||
return self.get_response(request)
|
||||
|
||||
async def __acall__(self, request: HttpRequest) -> HttpResponseBase:
|
||||
request.htmx = HtmxDetails(request) # type: ignore [attr-defined]
|
||||
return await self.get_response(request) # type: ignore [no-any-return, misc]
|
||||
|
||||
|
||||
class HtmxDetails:
|
||||
def __init__(self, request: HttpRequest) -> None:
|
||||
self.request = request
|
||||
|
||||
def _get_header_value(self, name: str) -> str | None:
|
||||
value = self.request.headers.get(name) or None
|
||||
if value:
|
||||
if self.request.headers.get(f"{name}-URI-AutoEncoded") == "true":
|
||||
value = unquote(value)
|
||||
return value
|
||||
|
||||
def __bool__(self) -> bool:
|
||||
return self._get_header_value("HX-Request") == "true"
|
||||
|
||||
@cached_property
|
||||
def boosted(self) -> bool:
|
||||
return self._get_header_value("HX-Boosted") == "true"
|
||||
|
||||
@cached_property
|
||||
def current_url(self) -> str | None:
|
||||
return self._get_header_value("HX-Current-URL")
|
||||
|
||||
@cached_property
|
||||
def current_url_abs_path(self) -> str | None:
|
||||
url = self.current_url
|
||||
if url is not None:
|
||||
split = urlsplit(url)
|
||||
if (
|
||||
split.scheme == self.request.scheme
|
||||
and split.netloc == self.request.get_host()
|
||||
):
|
||||
url = urlunsplit(split._replace(scheme="", netloc=""))
|
||||
else:
|
||||
url = None
|
||||
return url
|
||||
|
||||
@cached_property
|
||||
def history_restore_request(self) -> bool:
|
||||
return self._get_header_value("HX-History-Restore-Request") == "true"
|
||||
|
||||
@cached_property
|
||||
def prompt(self) -> str | None:
|
||||
return self._get_header_value("HX-Prompt")
|
||||
|
||||
@cached_property
|
||||
def target(self) -> str | None:
|
||||
return self._get_header_value("HX-Target")
|
||||
|
||||
@cached_property
|
||||
def trigger(self) -> str | None:
|
||||
return self._get_header_value("HX-Trigger")
|
||||
|
||||
@cached_property
|
||||
def trigger_name(self) -> str | None:
|
||||
return self._get_header_value("HX-Trigger-Name")
|
||||
|
||||
@cached_property
|
||||
def triggering_event(self) -> Any:
|
||||
value = self._get_header_value("Triggering-Event")
|
||||
if value is not None:
|
||||
try:
|
||||
value = json.loads(value)
|
||||
except json.JSONDecodeError:
|
||||
value = None
|
||||
return value
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
const data = document.currentScript.dataset;
|
||||
const isDebug = data.debug === "True";
|
||||
|
||||
if (isDebug) {
|
||||
document.addEventListener("htmx:beforeOnLoad", function (event) {
|
||||
const xhr = event.detail.xhr;
|
||||
if (xhr.status == 500 || xhr.status == 404) {
|
||||
// Tell htmx to stop processing this response
|
||||
event.stopPropagation();
|
||||
|
||||
document.children[0].innerHTML = xhr.response;
|
||||
|
||||
// Run Django’s inline script
|
||||
// (1, eval) wtf - see https://stackoverflow.com/questions/9107240/1-evalthis-vs-evalthis-in-javascript
|
||||
(1, eval)(document.scripts[0].innerText);
|
||||
// Need to directly call Django’s onload function since browser won’t
|
||||
window.onload();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from django import template
|
||||
|
||||
from django_htmx.jinja import django_htmx_script
|
||||
|
||||
register = template.Library()
|
||||
register.simple_tag(django_htmx_script)
|
||||
Reference in New Issue
Block a user