plain.htmx 0.10.2__tar.gz → 0.10.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/PKG-INFO +1 -1
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/CHANGELOG.md +10 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/templates.py +45 -30
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/views.py +12 -6
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/pyproject.toml +1 -1
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/.gitignore +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/LICENSE +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/README.md +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/deps.yml +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/package-lock.json +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/package.json +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/README.md +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/__init__.py +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/plainhtmx.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/idiomorph/idiomorph-ext.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/idiomorph/idiomorph-ext.min.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/idiomorph/idiomorph-htmx.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/idiomorph/idiomorph.amd.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/idiomorph/idiomorph.cjs.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/idiomorph/idiomorph.esm.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/idiomorph/idiomorph.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/idiomorph/idiomorph.min.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/README.md +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/ajax-header.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/alpine-morph.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/class-tools.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/client-side-templates.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/debug.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/disable-element.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/event-header.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/head-support.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/include-vals.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/json-enc.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/loading-states.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/method-override.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/morphdom-swap.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/multi-swap.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/path-deps.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/path-params.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/preload.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/rails-method.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/remove-me.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/response-targets.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/restored.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/sse.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/ws.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/htmx.amd.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/htmx.cjs.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/htmx.esm.d.ts +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/htmx.esm.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/htmx.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/htmx.min.js +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/htmx.min.js.gz +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/templates/htmx/js.html +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/tests/app/settings.py +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/tests/app/urls.py +0 -0
- {plain_htmx-0.10.2 → plain_htmx-0.10.3}/tests/test_views.py +0 -0
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# plain-htmx changelog
|
|
2
2
|
|
|
3
|
+
## [0.10.3](https://github.com/dropseed/plain/releases/plain-htmx@0.10.3) (2025-10-06)
|
|
4
|
+
|
|
5
|
+
### What's changed
|
|
6
|
+
|
|
7
|
+
- Added type annotations for improved IDE and type checker support ([8cdda13](https://github.com/dropseed/plain/commit/8cdda13a6c))
|
|
8
|
+
|
|
9
|
+
### Upgrade instructions
|
|
10
|
+
|
|
11
|
+
- No changes required
|
|
12
|
+
|
|
3
13
|
## [0.10.2](https://github.com/dropseed/plain/releases/plain-htmx@0.10.2) (2025-10-02)
|
|
4
14
|
|
|
5
15
|
### What's changed
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
1
5
|
import jinja2
|
|
2
6
|
from jinja2 import meta, nodes
|
|
3
7
|
from jinja2.ext import Extension
|
|
8
|
+
from jinja2.nodes import CallBlock, Node
|
|
9
|
+
from jinja2.parser import Parser
|
|
4
10
|
|
|
5
11
|
from plain.runtime import settings
|
|
6
12
|
from plain.templates import register_template_extension
|
|
@@ -12,7 +18,9 @@ class HTMXJSExtension(InclusionTagExtension):
|
|
|
12
18
|
tags = {"htmx_js"}
|
|
13
19
|
template_name = "htmx/js.html"
|
|
14
20
|
|
|
15
|
-
def get_context(
|
|
21
|
+
def get_context(
|
|
22
|
+
self, context: dict[str, Any], *args: Any, **kwargs: Any
|
|
23
|
+
) -> dict[str, Any]:
|
|
16
24
|
return {
|
|
17
25
|
"DEBUG": settings.DEBUG,
|
|
18
26
|
"extensions": kwargs.get("extensions", []),
|
|
@@ -23,11 +31,11 @@ class HTMXJSExtension(InclusionTagExtension):
|
|
|
23
31
|
class HTMXFragmentExtension(Extension):
|
|
24
32
|
tags = {"htmxfragment"}
|
|
25
33
|
|
|
26
|
-
def __init__(self, environment):
|
|
34
|
+
def __init__(self, environment: jinja2.Environment):
|
|
27
35
|
super().__init__(environment)
|
|
28
36
|
environment.extend(htmx_fragment_nodes={})
|
|
29
37
|
|
|
30
|
-
def parse(self, parser):
|
|
38
|
+
def parse(self, parser: Parser) -> Node:
|
|
31
39
|
lineno = next(parser.stream).lineno
|
|
32
40
|
|
|
33
41
|
fragment_name = parser.parse_expression()
|
|
@@ -42,25 +50,27 @@ class HTMXFragmentExtension(Extension):
|
|
|
42
50
|
value = parser.parse_expression()
|
|
43
51
|
kwargs.append(nodes.Keyword(key, value))
|
|
44
52
|
|
|
45
|
-
body = parser.parse_statements(
|
|
53
|
+
body = parser.parse_statements(("name:endhtmxfragment",), drop_needle=True)
|
|
46
54
|
|
|
47
55
|
call = self.call_method(
|
|
48
56
|
"_render_htmx_fragment",
|
|
49
|
-
args=[fragment_name,
|
|
57
|
+
args=[fragment_name, nodes.ContextReference()],
|
|
50
58
|
kwargs=kwargs,
|
|
51
59
|
)
|
|
52
60
|
|
|
53
|
-
node =
|
|
61
|
+
node = CallBlock(call, [], [], body).set_lineno(lineno)
|
|
54
62
|
|
|
55
63
|
# Store a reference to the node for later
|
|
56
|
-
self.environment.htmx_fragment_nodes.setdefault(parser.name, {})[
|
|
57
|
-
fragment_name.value
|
|
64
|
+
self.environment.htmx_fragment_nodes.setdefault(parser.name, {})[ # type: ignore[attr-defined]
|
|
65
|
+
fragment_name.value # type: ignore[attr-defined]
|
|
58
66
|
] = node
|
|
59
67
|
|
|
60
68
|
return node
|
|
61
69
|
|
|
62
|
-
def _render_htmx_fragment(
|
|
63
|
-
|
|
70
|
+
def _render_htmx_fragment(
|
|
71
|
+
self, fragment_name: str, context: dict[str, Any], caller: Any, **kwargs: Any
|
|
72
|
+
) -> str:
|
|
73
|
+
def attrs_to_str(attrs: dict[str, Any]) -> str:
|
|
64
74
|
parts = []
|
|
65
75
|
for k, v in attrs.items():
|
|
66
76
|
if v == "":
|
|
@@ -96,41 +106,46 @@ class HTMXFragmentExtension(Extension):
|
|
|
96
106
|
return f'<{as_element} plain-hx-fragment="{fragment_name}" {attrs_str}>{caller()}</{as_element}>'
|
|
97
107
|
|
|
98
108
|
|
|
99
|
-
def render_template_fragment(
|
|
109
|
+
def render_template_fragment(
|
|
110
|
+
*, template: jinja2.Template, fragment_name: str, context: dict[str, Any]
|
|
111
|
+
) -> str:
|
|
100
112
|
template = find_template_fragment(template, fragment_name)
|
|
101
113
|
return template.render(context)
|
|
102
114
|
|
|
103
115
|
|
|
104
|
-
def find_template_fragment(
|
|
116
|
+
def find_template_fragment(
|
|
117
|
+
template: jinja2.Template, fragment_name: str
|
|
118
|
+
) -> jinja2.Template:
|
|
105
119
|
# Look in this template for the fragment
|
|
106
|
-
callblock_node = template.environment.htmx_fragment_nodes.get(
|
|
120
|
+
callblock_node = template.environment.htmx_fragment_nodes.get( # type: ignore[attr-defined]
|
|
107
121
|
template.name, {}
|
|
108
122
|
).get(fragment_name)
|
|
109
123
|
|
|
110
124
|
if not callblock_node:
|
|
111
125
|
# Look in other templates for this fragment
|
|
112
126
|
matching_callblock_nodes = []
|
|
113
|
-
for fragments in template.environment.htmx_fragment_nodes.values():
|
|
127
|
+
for fragments in template.environment.htmx_fragment_nodes.values(): # type: ignore[attr-defined]
|
|
114
128
|
if fragment_name in fragments:
|
|
115
129
|
matching_callblock_nodes.append(fragments[fragment_name])
|
|
116
130
|
|
|
117
131
|
if len(matching_callblock_nodes) == 0:
|
|
118
132
|
# If we still haven't found anything, it's possible that we're
|
|
119
133
|
# in a different/new worker/process and haven't parsed the related templates yet
|
|
120
|
-
|
|
121
|
-
template.environment.
|
|
122
|
-
template.environment
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
+
if template.environment.loader and template.name:
|
|
135
|
+
ast = template.environment.parse(
|
|
136
|
+
template.environment.loader.get_source(
|
|
137
|
+
template.environment, template.name
|
|
138
|
+
)[0]
|
|
139
|
+
)
|
|
140
|
+
for ref in meta.find_referenced_templates(ast):
|
|
141
|
+
if ref not in template.environment.htmx_fragment_nodes: # type: ignore[attr-defined]
|
|
142
|
+
# Trigger them to parse
|
|
143
|
+
template.environment.get_template(ref)
|
|
144
|
+
|
|
145
|
+
# Now look again
|
|
146
|
+
for fragments in template.environment.htmx_fragment_nodes.values(): # type: ignore[attr-defined]
|
|
147
|
+
if fragment_name in fragments:
|
|
148
|
+
matching_callblock_nodes.append(fragments[fragment_name])
|
|
134
149
|
|
|
135
150
|
if len(matching_callblock_nodes) == 1:
|
|
136
151
|
callblock_node = matching_callblock_nodes[0]
|
|
@@ -149,5 +164,5 @@ def find_template_fragment(template: jinja2.Template, fragment_name: str):
|
|
|
149
164
|
)
|
|
150
165
|
|
|
151
166
|
# Create a new template from the node
|
|
152
|
-
template_node =
|
|
153
|
-
return template.environment.from_string(template_node)
|
|
167
|
+
template_node = nodes.Template(callblock_node.body) # type: ignore[attr-defined]
|
|
168
|
+
return template.environment.from_string(template_node) # type: ignore[arg-type]
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from plain.http import Response
|
|
1
7
|
from plain.utils.cache import patch_vary_headers
|
|
2
8
|
|
|
3
9
|
from .templates import render_template_fragment
|
|
4
10
|
|
|
5
11
|
|
|
6
12
|
class HTMXViewMixin:
|
|
7
|
-
def render_template(self):
|
|
13
|
+
def render_template(self) -> str:
|
|
8
14
|
template = self.get_template()
|
|
9
15
|
context = self.get_template_context()
|
|
10
16
|
|
|
@@ -17,7 +23,7 @@ class HTMXViewMixin:
|
|
|
17
23
|
|
|
18
24
|
return template.render(context)
|
|
19
25
|
|
|
20
|
-
def get_response(self):
|
|
26
|
+
def get_response(self) -> Response:
|
|
21
27
|
response = super().get_response()
|
|
22
28
|
# Tell browser caching to also consider the fragment header,
|
|
23
29
|
# not just the url/cookie.
|
|
@@ -26,7 +32,7 @@ class HTMXViewMixin:
|
|
|
26
32
|
)
|
|
27
33
|
return response
|
|
28
34
|
|
|
29
|
-
def get_request_handler(self):
|
|
35
|
+
def get_request_handler(self) -> Callable[..., Any]:
|
|
30
36
|
if self.is_htmx_request():
|
|
31
37
|
# You can use an htmx_{method} method on views
|
|
32
38
|
# (or htmx_{method}_{action} for specific actions)
|
|
@@ -45,12 +51,12 @@ class HTMXViewMixin:
|
|
|
45
51
|
|
|
46
52
|
return super().get_request_handler()
|
|
47
53
|
|
|
48
|
-
def is_htmx_request(self):
|
|
54
|
+
def is_htmx_request(self) -> bool:
|
|
49
55
|
return self.request.headers.get("HX-Request") == "true"
|
|
50
56
|
|
|
51
|
-
def get_htmx_fragment_name(self):
|
|
57
|
+
def get_htmx_fragment_name(self) -> str:
|
|
52
58
|
# A custom header that we pass with the {% htmxfragment %} tag
|
|
53
59
|
return self.request.headers.get("Plain-HX-Fragment", "")
|
|
54
60
|
|
|
55
|
-
def get_htmx_action_name(self):
|
|
61
|
+
def get_htmx_action_name(self) -> str:
|
|
56
62
|
return self.request.headers.get("Plain-HX-Action", "")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/idiomorph/idiomorph-ext.js
RENAMED
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/idiomorph/idiomorph-ext.min.js
RENAMED
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/idiomorph/idiomorph-htmx.js
RENAMED
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/idiomorph/idiomorph.amd.js
RENAMED
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/idiomorph/idiomorph.cjs.js
RENAMED
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/idiomorph/idiomorph.esm.js
RENAMED
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/idiomorph/idiomorph.js
RENAMED
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/idiomorph/idiomorph.min.js
RENAMED
|
File without changes
|
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/ajax-header.js
RENAMED
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/alpine-morph.js
RENAMED
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/class-tools.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/disable-element.js
RENAMED
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/event-header.js
RENAMED
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/head-support.js
RENAMED
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/include-vals.js
RENAMED
|
File without changes
|
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/loading-states.js
RENAMED
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/method-override.js
RENAMED
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/morphdom-swap.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/path-params.js
RENAMED
|
File without changes
|
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/rails-method.js
RENAMED
|
File without changes
|
|
File without changes
|
{plain_htmx-0.10.2 → plain_htmx-0.10.3}/plain/htmx/assets/htmx/vendor/src/ext/response-targets.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|