pywebview-htmx 0.2.0__tar.gz → 0.2.1__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.
- {pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/PKG-INFO +1 -1
- {pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/pyproject.toml +1 -1
- {pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/src/pywebview_htmx/runtime.py +4 -1
- {pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/src/pywebview_htmx/static/runtime.js +10 -2
- {pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/tests/test_js_contract_request_and_swap.py +17 -2
- {pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/tests/test_python_injection.py +7 -0
- {pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/LICENSE +0 -0
- {pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/README.md +0 -0
- {pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/src/pywebview_htmx/__init__.py +0 -0
- {pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/src/pywebview_htmx/static/themes/aurora.css +0 -0
- {pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/src/pywebview_htmx/static/themes/base.css +0 -0
- {pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/src/pywebview_htmx/static/themes/cybermind.css +0 -0
- {pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/src/pywebview_htmx/static/themes/paper.css +0 -0
- {pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/tests/conftest.py +0 -0
- {pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/tests/test_js_contract_config_and_binding.py +0 -0
- {pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/tests/test_python_create_window.py +0 -0
- {pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/tests/test_python_script_loading.py +0 -0
- {pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/tests/test_python_themes.py +0 -0
|
@@ -6,7 +6,10 @@ from typing import Any
|
|
|
6
6
|
|
|
7
7
|
import webview
|
|
8
8
|
|
|
9
|
-
_SCRIPT_TAG_RE = re.compile(
|
|
9
|
+
_SCRIPT_TAG_RE = re.compile(
|
|
10
|
+
r"<script[^>]*\bdata-pywebview-htmx\s*=\s*(?:[\"']true[\"']|true\b)",
|
|
11
|
+
re.IGNORECASE,
|
|
12
|
+
)
|
|
10
13
|
_THEME_TAG_RE = re.compile(
|
|
11
14
|
r"<style[^>]*\bdata-pywebview-theme\s*=\s*[\"'](?P<name>[^\"']+)[\"'][^>]*>.*?</style>",
|
|
12
15
|
re.IGNORECASE | re.DOTALL,
|
|
@@ -94,6 +94,10 @@
|
|
|
94
94
|
return state;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
function shouldPreventDefault(eventName) {
|
|
98
|
+
return eventName === "submit";
|
|
99
|
+
}
|
|
100
|
+
|
|
97
101
|
function processPyWebviewHtmxNodes(root = document) {
|
|
98
102
|
if (!root || typeof root.querySelectorAll !== "function") {
|
|
99
103
|
return;
|
|
@@ -119,7 +123,7 @@
|
|
|
119
123
|
}
|
|
120
124
|
|
|
121
125
|
element.addEventListener(eventName, async (event) => {
|
|
122
|
-
if (event.cancelable) {
|
|
126
|
+
if (shouldPreventDefault(eventName) && event.cancelable) {
|
|
123
127
|
event.preventDefault();
|
|
124
128
|
}
|
|
125
129
|
|
|
@@ -163,7 +167,11 @@
|
|
|
163
167
|
}
|
|
164
168
|
|
|
165
169
|
const processRoot = pySwap(target, response, swapStyle);
|
|
166
|
-
|
|
170
|
+
const afterSwapTarget =
|
|
171
|
+
swapStyle === "outerHTML"
|
|
172
|
+
? (targetSelector ? $(targetSelector) || processRoot : processRoot)
|
|
173
|
+
: target;
|
|
174
|
+
triggerEvent(afterSwapTarget, "py:afterSwap", { response, requestId });
|
|
167
175
|
processPyWebviewHtmxNodes(processRoot);
|
|
168
176
|
|
|
169
177
|
if (config.settleDelay > 0) {
|
|
@@ -11,7 +11,15 @@ def _assert_fragments_present(js_compact: str, fragments: tuple[str, ...]) -> No
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
JS_BEHAVIOR_FRAGMENTS: list[tuple[int, tuple[str, ...]]] = [
|
|
14
|
-
(
|
|
14
|
+
(
|
|
15
|
+
73,
|
|
16
|
+
(
|
|
17
|
+
'function shouldPreventDefault(eventName)',
|
|
18
|
+
'return eventName === "submit";',
|
|
19
|
+
"if (shouldPreventDefault(eventName) && event.cancelable)",
|
|
20
|
+
"event.preventDefault();",
|
|
21
|
+
),
|
|
22
|
+
),
|
|
15
23
|
(74, ("let state = requestState.get(element);", "if (!state) {")),
|
|
16
24
|
(75, ("lastIssued: 0", "state.lastIssued = requestId;")),
|
|
17
25
|
(76, ("inFlightCount: 0", "state.inFlightCount += 1;")),
|
|
@@ -27,7 +35,14 @@ JS_BEHAVIOR_FRAGMENTS: list[tuple[int, tuple[str, ...]]] = [
|
|
|
27
35
|
(86, ("if (requestId !== state.lastIssued) { return; }",)),
|
|
28
36
|
(87, ("const processRoot = pySwap(target, response, swapStyle);",)),
|
|
29
37
|
(88, ("processPyWebviewHtmxNodes(processRoot);",)),
|
|
30
|
-
(
|
|
38
|
+
(
|
|
39
|
+
89,
|
|
40
|
+
(
|
|
41
|
+
"const afterSwapTarget =",
|
|
42
|
+
'swapStyle === "outerHTML"',
|
|
43
|
+
'triggerEvent(afterSwapTarget, "py:afterSwap"',
|
|
44
|
+
),
|
|
45
|
+
),
|
|
31
46
|
(90, ("if (config.settleDelay > 0)", "await delay(config.settleDelay);")),
|
|
32
47
|
(91, ('triggerEvent(element, "py:error"', "requestId")),
|
|
33
48
|
(92, ("state.inFlightCount = Math.max(0, state.inFlightCount - 1);",)),
|
|
@@ -90,6 +90,13 @@ def test_non_script_data_marker_does_not_block_injection() -> None:
|
|
|
90
90
|
assert result.count(SCRIPT_MARKER) == 1
|
|
91
91
|
|
|
92
92
|
|
|
93
|
+
def test_script_with_false_marker_does_not_block_injection() -> None:
|
|
94
|
+
html = '<html><body><script data-pywebview-htmx="false"></script></body></html>'
|
|
95
|
+
result = inject_runtime(html)
|
|
96
|
+
assert result != html
|
|
97
|
+
assert result.count(SCRIPT_MARKER) == 1
|
|
98
|
+
|
|
99
|
+
|
|
93
100
|
def test_empty_html_input_gets_injected_script() -> None:
|
|
94
101
|
result = inject_runtime("")
|
|
95
102
|
assert MARKER in result
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pywebview_htmx-0.2.0 → pywebview_htmx-0.2.1}/src/pywebview_htmx/static/themes/cybermind.css
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|