mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-01 12:18:51 +00:00
fix: end a tab drag when the card is disconnected
Validate / docs (push) Failing after 31s
Validate / provenance (push) Successful in 1m7s
Validate / process-gate (push) Failing after 1m11s
Validate / changes (push) Successful in 57s
Validate / hacs (push) Skipped
Validate / hassfest (push) Skipped
Validate / reuse (push) Successful in 1m30s
Validate / backend (push) Skipped
Validate / frontend (push) Successful in 12m25s
Validate / golden (push) Failing after 12m39s
Validate / performance_smoke (push) Failing after 11m36s
Validate / smoke (push) Failing after 27m40s
Validate / docs (push) Failing after 31s
Validate / provenance (push) Successful in 1m7s
Validate / process-gate (push) Failing after 1m11s
Validate / changes (push) Successful in 57s
Validate / hacs (push) Skipped
Validate / hassfest (push) Skipped
Validate / reuse (push) Successful in 1m30s
Validate / backend (push) Skipped
Validate / frontend (push) Successful in 12m25s
Validate / golden (push) Failing after 12m39s
Validate / performance_smoke (push) Failing after 11m36s
Validate / smoke (push) Failing after 27m40s
Review CODE-REVIEW-220-r2/r3, F1. The M1 fix installs window listeners for the length of the gesture, and disconnectedCallback — which takes down everything else, down to the other local gesture — did not take those down. Losing the card mid-drag (Lovelace rebuilding its tree, the user leaving the view with the button still down) left them alive: the closure holds the instance and its config, and the next pointerup anywhere on the page would have an invisible card write its order. The smoke now holds a tab, removes the card, and checks that the release it should no longer hear changes nothing. Registered as a mutant too. Issue: #220 User-Visible: no
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -180,6 +180,43 @@ const res = await page.evaluate(async () => {
|
||||
await settle();
|
||||
out.panelStillSwitchesAfterStrayRelease = c._space === strayTarget;
|
||||
|
||||
// --- review r2/r3 F1: the card is destroyed mid-drag -----------------------
|
||||
//
|
||||
// Lovelace rebuilds its tree, or the user leaves the view with the button
|
||||
// still down. The window listeners the gesture installed must not outlive
|
||||
// the card: they hold the instance alive and would let an invisible card
|
||||
// write its order on the next pointerup anywhere on the page.
|
||||
c._mode = 'plan';
|
||||
c.requestUpdate();
|
||||
await settle();
|
||||
const orderBeforeDetach = ids();
|
||||
const detachTabs = tabs();
|
||||
const held = detachTabs[detachTabs.length - 1];
|
||||
const heldRect = held.getBoundingClientRect();
|
||||
const heldEvent = (type, x, y) => held.dispatchEvent(new PointerEvent(type, {
|
||||
pointerId: 13, pointerType: 'mouse', clientX: x, clientY: y,
|
||||
bubbles: true, composed: true,
|
||||
}));
|
||||
heldEvent('pointerdown', heldRect.x + heldRect.width / 2, heldRect.y + heldRect.height / 2);
|
||||
heldEvent('pointermove', heldRect.x + heldRect.width / 2 + 40, heldRect.y + heldRect.height / 2);
|
||||
out.dragWasActiveBeforeDetach = c._tabDrag !== null && c._tabDrag.moved === true;
|
||||
|
||||
const parent = c.parentNode;
|
||||
const next = c.nextSibling;
|
||||
const writesBeforeDetach = writes.length;
|
||||
c.remove();
|
||||
await new Promise((r) => setTimeout(r, 50));
|
||||
out.detachEndedTheDrag = c._tabDrag === null;
|
||||
// the release the detached card must no longer hear
|
||||
window.dispatchEvent(new PointerEvent('pointerup', {
|
||||
pointerId: 13, pointerType: 'mouse', bubbles: true, composed: true,
|
||||
}));
|
||||
await new Promise((r) => setTimeout(r, 700));
|
||||
out.detachedCardDidNotWrite = writes.length === writesBeforeDetach;
|
||||
parent.insertBefore(c, next);
|
||||
await settle();
|
||||
out.orderSurvivedDetach = JSON.stringify(ids()) === JSON.stringify(orderBeforeDetach);
|
||||
|
||||
c._writeConfig = realWrite;
|
||||
return out;
|
||||
});
|
||||
|
||||
File diff suppressed because one or more lines are too long
Vendored
+2
-2
File diff suppressed because one or more lines are too long
@@ -762,6 +762,18 @@ export const MUTANTS = [
|
||||
replace: ' void 0;',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'tab-drag-outlives-the-card',
|
||||
guard: 'node demo/smoke_space_tab_reorder.mjs',
|
||||
because: 'слушатели жеста, пережившие disconnectedCallback, держат инстанс карточки '
|
||||
+ 'и дают невидимой карточке записать порядок по следующему pointerup на странице '
|
||||
+ '(ревью r2/r3, F1)',
|
||||
patches: [{
|
||||
file: 'src/houseplan-card.ts',
|
||||
find: ' this._endTabDrag();\n clearInterval(this._cycleTimer);',
|
||||
replace: ' clearInterval(this._cycleTimer);',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'tab-reorder-eats-click',
|
||||
guard: 'node --test --test-name-pattern="issue 220" test/space-order.test.mjs',
|
||||
|
||||
@@ -2236,6 +2236,13 @@ class HouseplanCard extends LitElement {
|
||||
this._bootSettling = false;
|
||||
for (const rt of this._activityRt.values()) clearTimeout(rt.timer); // pending activity-window repaints
|
||||
window.removeEventListener('keydown', this._keyHandler);
|
||||
// A tab drag holds window listeners for the length of the gesture. Losing
|
||||
// the card mid-drag — Lovelace rebuilding its tree, the user leaving the
|
||||
// view with the button still down — would leave them alive: the closure
|
||||
// keeps this instance (and its config) from being collected, and the next
|
||||
// pointerup anywhere on the page would make an invisible card write its
|
||||
// order (review CODE-REVIEW-220-r2/r3, F1).
|
||||
this._endTabDrag();
|
||||
clearInterval(this._cycleTimer);
|
||||
clearTimeout(this._kioskDotsTimer);
|
||||
clearTimeout(this._kioskHoldTimer);
|
||||
|
||||
Reference in New Issue
Block a user