mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-19 18:27:29 -05:00
Allow nodes in shadow roots to be addressed via Element (#1454)
This commit is contained in:
committed by
GitHub
parent
82e5b64bad
commit
d3bcd87cfa
13
pyscriptjs/package-lock.json
generated
13
pyscriptjs/package-lock.json
generated
@@ -8,7 +8,8 @@
|
||||
"name": "pyscript",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"basic-devtools": "^0.1.6"
|
||||
"basic-devtools": "^0.1.6",
|
||||
"not-so-weak": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@codemirror/commands": "^6.2.2",
|
||||
@@ -4802,6 +4803,11 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/not-so-weak": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/not-so-weak/-/not-so-weak-1.0.0.tgz",
|
||||
"integrity": "sha512-kgpM6y09QLyfQXfA0AAupX8ZUqKn4caDxQTMVNsyKK02IQ+9P9ylcL1ioQem4qciUCy3IitESXQfMBfnGuGNOQ=="
|
||||
},
|
||||
"node_modules/npm-run-path": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
|
||||
@@ -9610,6 +9616,11 @@
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true
|
||||
},
|
||||
"not-so-weak": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/not-so-weak/-/not-so-weak-1.0.0.tgz",
|
||||
"integrity": "sha512-kgpM6y09QLyfQXfA0AAupX8ZUqKn4caDxQTMVNsyKK02IQ+9P9ylcL1ioQem4qciUCy3IitESXQfMBfnGuGNOQ=="
|
||||
},
|
||||
"npm-run-path": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
"typescript": "5.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"basic-devtools": "^0.1.6"
|
||||
"basic-devtools": "^0.1.6",
|
||||
"not-so-weak": "^1.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { $$, $x } from 'basic-devtools';
|
||||
|
||||
import { shadowRoots } from '../shadow_roots';
|
||||
import { ltrim, htmlDecode, ensureUniqueId, createDeprecationWarning } from '../utils';
|
||||
import { getLogger } from '../logger';
|
||||
import { pyExec, displayPyException } from '../pyexec';
|
||||
@@ -174,7 +175,9 @@ export function make_PyScript(interpreter: InterpreterClient, app: PyScriptApp)
|
||||
const { attachShadow } = Element.prototype;
|
||||
Object.assign(Element.prototype, {
|
||||
attachShadow(init: ShadowRootInit) {
|
||||
return observe(attachShadow.call(this as Element, init));
|
||||
const shadowRoot = observe(attachShadow.call(this as Element, init));
|
||||
shadowRoots.add(shadowRoot);
|
||||
return shadowRoot;
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import time
|
||||
from textwrap import dedent
|
||||
|
||||
import js
|
||||
from _pyscript_js import deepQuerySelector
|
||||
|
||||
from . import _internal
|
||||
from ._mime import format_mime as _format_mime
|
||||
@@ -55,7 +56,7 @@ class Element:
|
||||
def element(self):
|
||||
"""Return the dom element"""
|
||||
if not self._element:
|
||||
self._element = js.document.querySelector(f"#{self._id}")
|
||||
self._element = deepQuerySelector(f"#{self._id}")
|
||||
return self._element
|
||||
|
||||
@property
|
||||
|
||||
@@ -9,6 +9,7 @@ import type { ProxyMarked } from 'synclink';
|
||||
import * as Synclink from 'synclink';
|
||||
import { showWarning } from './utils';
|
||||
import { define_custom_element } from './plugin';
|
||||
import { deepQuerySelector } from './shadow_roots';
|
||||
|
||||
import { python_package } from './python_package';
|
||||
|
||||
@@ -100,7 +101,7 @@ export class RemoteInterpreter extends Object {
|
||||
*/
|
||||
async loadInterpreter(config: AppConfig, stdio: Synclink.Remote<Stdio & ProxyMarked>): Promise<void> {
|
||||
// TODO: move this to "main thread"!
|
||||
const _pyscript_js_main = { define_custom_element, showWarning };
|
||||
const _pyscript_js_main = { define_custom_element, showWarning, deepQuerySelector };
|
||||
|
||||
this.interface = Synclink.proxy(
|
||||
await loadPyodide({
|
||||
|
||||
18
pyscriptjs/src/shadow_roots.ts
Normal file
18
pyscriptjs/src/shadow_roots.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { $ } from 'basic-devtools';
|
||||
import { WSet } from 'not-so-weak';
|
||||
|
||||
// weakly retain shadow root nodes in an iterable way
|
||||
// so that it's possible to query these and find elements by ID
|
||||
export const shadowRoots: WSet<ShadowRoot> = new WSet();
|
||||
|
||||
// returns an element by ID if present within any of the live shadow roots
|
||||
const findInShadowRoots = (selector: string): Element | null => {
|
||||
for (const shadowRoot of shadowRoots) {
|
||||
const element = $(selector, shadowRoot);
|
||||
if (element) return element;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// find an element by ID either via document or via any live shadow root
|
||||
export const deepQuerySelector = (selector: string) => $(selector, document) || findInShadowRoots(selector);
|
||||
30
pyscriptjs/tests/integration/test_shadow_root.py
Normal file
30
pyscriptjs/tests/integration/test_shadow_root.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from .support import PyScriptTest, skip_worker
|
||||
|
||||
|
||||
class TestShadowRoot(PyScriptTest):
|
||||
@skip_worker("FIXME: js.document")
|
||||
def test_reachable_shadow_root(self):
|
||||
self.pyscript_run(
|
||||
r"""
|
||||
<script>
|
||||
// reason to wait for py-script is that it's the entry point for
|
||||
// all patches and the MutationObserver, otherwise being this a synchronous
|
||||
// script the constructor gets instantly invoked at the node before
|
||||
// py-script gets a chance to initialize itself.
|
||||
customElements.whenDefined('py-script').then(() => {
|
||||
customElements.define('s-r', class extends HTMLElement {
|
||||
constructor() {
|
||||
super().attachShadow({mode: 'closed'}).innerHTML =
|
||||
'<div id="shadowed">OK</div>';
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<s-r></s-r>
|
||||
<py-script>
|
||||
import js
|
||||
js.console.log(Element("shadowed").innerHtml)
|
||||
</py-script>
|
||||
"""
|
||||
)
|
||||
assert self.console.log.lines[-1] == "OK"
|
||||
@@ -1,4 +1,10 @@
|
||||
from unittest.mock import Mock
|
||||
|
||||
import js
|
||||
|
||||
showWarning = Mock()
|
||||
define_custom_element = Mock()
|
||||
|
||||
|
||||
def deepQuerySelector(selector):
|
||||
return js.document.querySelector(selector)
|
||||
|
||||
Reference in New Issue
Block a user