fix(techdemo): rebootstrap inserted islands
Keep opaque island widgets live when slhx swaps or later DOM insertion adds a new island, and tear down the listener when an island leaves the document. req: interop/001 req: examples/001
This commit is contained in:
@@ -80,12 +80,18 @@
|
||||
const state = { frame: 0, snapshot: parseSnapshot(island.getAttribute("data-island-snapshot")) };
|
||||
roots.set(island, state);
|
||||
|
||||
rootOf(island).addEventListener("slhx:island-orbit", (event) => {
|
||||
const root = rootOf(island);
|
||||
const update = (event) => {
|
||||
state.snapshot = parseSnapshot(event.detail);
|
||||
island.setAttribute("data-island-snapshot", event.detail);
|
||||
});
|
||||
};
|
||||
root.addEventListener("slhx:island-orbit", update);
|
||||
|
||||
function tick() {
|
||||
if (!document.contains(island)) {
|
||||
root.removeEventListener("slhx:island-orbit", update);
|
||||
return;
|
||||
}
|
||||
state.frame += 1;
|
||||
render(canvas, readout, state);
|
||||
requestAnimationFrame(tick);
|
||||
@@ -99,6 +105,18 @@
|
||||
});
|
||||
}
|
||||
|
||||
function bootAddedIslands(records) {
|
||||
for (const record of records) {
|
||||
for (const node of record.addedNodes) {
|
||||
if (node.nodeType === 1) {
|
||||
scan();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", scan);
|
||||
else scan();
|
||||
if (typeof MutationObserver !== "undefined") new MutationObserver(bootAddedIslands).observe(document.documentElement, { childList: true, subtree: true });
|
||||
})();
|
||||
|
||||
@@ -52,6 +52,8 @@ async fn browser_drives_typed_product_end_to_end() -> WebDriverResult<()> {
|
||||
assert_text(&driver, "No selectors. Generated resources address every target.").await?;
|
||||
assert_text(&driver, "Opaque island bridge").await?;
|
||||
wait_for_runtime(&driver).await?;
|
||||
insert_probe_island(&driver).await?;
|
||||
wait_for_text(&driver, "#probe-island [data-island-readout]", "probe live").await?;
|
||||
|
||||
driver
|
||||
.find(By::Css(&handle_selector(ui::control_center::handles::simulate_push)))
|
||||
@@ -97,6 +99,7 @@ async fn browser_drives_typed_product_end_to_end() -> WebDriverResult<()> {
|
||||
|
||||
driver.find(By::Css("a[href='/architecture']")).await?.click().await?;
|
||||
wait_for_text(&driver, &slot_selector(ui::control_center::slots::inspector), "Page swap").await?;
|
||||
wait_for_text(&driver, "[data-island-readout]", "activity rows").await?;
|
||||
assert!(driver.current_url().await?.as_str().ends_with("/architecture"));
|
||||
|
||||
driver.goto(&format!("http://{APP_ADDR}/")).await?;
|
||||
@@ -133,6 +136,27 @@ fn card_button_selector(handle_id: impl std::fmt::Display, work_id: u64) -> Stri
|
||||
format!(r#"[data-hid="{handle_id}"][data-work-id="{work_id}"]"#)
|
||||
}
|
||||
|
||||
async fn insert_probe_island(driver: &WebDriver) -> WebDriverResult<()> {
|
||||
driver
|
||||
.execute(
|
||||
r#"
|
||||
document.querySelector('[data-slhx-root]').insertAdjacentHTML('beforeend', `
|
||||
<article id="probe-island" data-slhx-island="orbit" data-island-snapshot="1|1|1|probe waiting">
|
||||
<canvas width="32" height="16"></canvas>
|
||||
<p data-island-readout="">waiting</p>
|
||||
</article>
|
||||
`);
|
||||
setTimeout(() => {
|
||||
document.querySelector('[data-slhx-root]').dispatchEvent(new CustomEvent('slhx:island-orbit', { bubbles: true, detail: '7|2|8|probe live' }));
|
||||
}, 25);
|
||||
return true;
|
||||
"#,
|
||||
Vec::new(),
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn drag_card_to_lane(driver: &WebDriver, work_id: u64, lane: &str) -> WebDriverResult<()> {
|
||||
driver
|
||||
.execute(
|
||||
|
||||
@@ -71,6 +71,8 @@ fn product_is_e2e_working_over_http() {
|
||||
assert!(island.header("content-type").contains("javascript"));
|
||||
assert!(island.text().contains("slhx:island-orbit"));
|
||||
assert!(island.text().contains("data-slhx-island"));
|
||||
assert!(island.text().contains("MutationObserver"));
|
||||
assert!(island.text().contains("removeEventListener"));
|
||||
|
||||
let architecture = request("GET", "/architecture", &[("X-SLHX-Partial", "1")], "");
|
||||
assert_eq!(architecture.status, 200);
|
||||
|
||||
Reference in New Issue
Block a user