mirror of
https://github.com/Matysh/houseplan-card
synced 2026-07-31 08:28:31 +00:00
fix v1.31.1: room card interactions no longer feed the active markup tool
- _markupClick ignores clicks originating from .roomlabel/.rlhandle (composedPath) and anything during an active drag/resize - smoke_card_tool_conflict.mjs (draw/delroom/handle/during-resize + normal stage click still works); TESTING/CHANGELOG same-commit
This commit is contained in:
@@ -11,7 +11,7 @@ PLANS_DIR = "houseplan/plans" # relative to the HA configuration directory
|
|||||||
FILES_URL = "/houseplan_files/files"
|
FILES_URL = "/houseplan_files/files"
|
||||||
FILES_DIR = "houseplan/files"
|
FILES_DIR = "houseplan/files"
|
||||||
CONF_ADMIN_ONLY = "admin_only"
|
CONF_ADMIN_ONLY = "admin_only"
|
||||||
VERSION = "1.31.0"
|
VERSION = "1.31.1"
|
||||||
|
|
||||||
DEFAULT_CONFIG: dict = {
|
DEFAULT_CONFIG: dict = {
|
||||||
"spaces": [],
|
"spaces": [],
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -16,5 +16,5 @@
|
|||||||
"issue_tracker": "https://github.com/Matysh/houseplan-card/issues",
|
"issue_tracker": "https://github.com/Matysh/houseplan-card/issues",
|
||||||
"requirements": [],
|
"requirements": [],
|
||||||
"single_config_entry": true,
|
"single_config_entry": true,
|
||||||
"version": "1.31.0"
|
"version": "1.31.1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { launch } from './serve.mjs';
|
||||||
|
const { page, browser } = await launch();
|
||||||
|
const res = await page.evaluate(async () => {
|
||||||
|
const out = {};
|
||||||
|
const c = window.__card;
|
||||||
|
const sr = () => c.shadowRoot || c.renderRoot;
|
||||||
|
c._setMode('plan'); await c.updateComplete;
|
||||||
|
const stage = sr().querySelector('.stage');
|
||||||
|
const label = sr().querySelector('.roomlabel');
|
||||||
|
out.hasLabel = !!label;
|
||||||
|
// 1) draw: клик по карточке не добавляет точку
|
||||||
|
c._tool = 'draw'; c._path = []; await c.updateComplete;
|
||||||
|
label.dispatchEvent(new MouseEvent('click', { bubbles: true, composed: true, clientX: 10, clientY: 10 }));
|
||||||
|
await c.updateComplete;
|
||||||
|
out.drawIgnored = c._path.length === 0;
|
||||||
|
// 2) клик по угловой метке тоже не считается кликом инструмента
|
||||||
|
const handle = label.querySelector('.rlhandle');
|
||||||
|
handle.dispatchEvent(new MouseEvent('click', { bubbles: true, composed: true, clientX: 10, clientY: 10 }));
|
||||||
|
await c.updateComplete;
|
||||||
|
out.handleIgnored = c._path.length === 0;
|
||||||
|
// 3) во время резайза клики по сцене игнорируются
|
||||||
|
const room = c._spaceModel().rooms.find((r) => r.name);
|
||||||
|
c._rlResize = { id: 'rl_' + room.id, space: c._space, k0: 1, cx: 0, cy: 0, d0: 50 };
|
||||||
|
const before = c._path.length;
|
||||||
|
c._markupClick(new MouseEvent('click', { bubbles: true, clientX: 200, clientY: 200 }));
|
||||||
|
out.duringResizeIgnored = c._path.length === before;
|
||||||
|
c._rlResize = null;
|
||||||
|
// 4) обычный клик по сцене (мимо карточки) по-прежнему работает — точка ставится
|
||||||
|
const r = stage.getBoundingClientRect();
|
||||||
|
// найти долю экрана, попадающую в свободное место (не внутри комнаты)
|
||||||
|
let fx = 0.4, fy = 0.4;
|
||||||
|
outer: for (let ix = 1; ix < 20; ix++) for (let iy = 1; iy < 20; iy++) {
|
||||||
|
const ev = new MouseEvent('click', { clientX: r.left + r.width * ix / 20, clientY: r.top + r.height * iy / 20 });
|
||||||
|
const raw = c._svgPoint(ev);
|
||||||
|
if (!c._roomAt(c._snap(raw))) { fx = ix / 20; fy = iy / 20; break outer; }
|
||||||
|
}
|
||||||
|
stage.dispatchEvent(new MouseEvent('click', { bubbles: true, composed: true,
|
||||||
|
clientX: r.left + r.width * fx, clientY: r.top + r.height * fy }));
|
||||||
|
await c.updateComplete;
|
||||||
|
out.normalClickWorks = c._path.length === 1;
|
||||||
|
// 5) delroom: клик по карточке не зовёт confirm (переопределим)
|
||||||
|
let confirmCalled = false;
|
||||||
|
window.confirm = () => { confirmCalled = true; return false; };
|
||||||
|
c._tool = 'delroom'; c._path = []; await c.updateComplete;
|
||||||
|
label.dispatchEvent(new MouseEvent('click', { bubbles: true, composed: true, clientX: 10, clientY: 10 }));
|
||||||
|
await c.updateComplete;
|
||||||
|
out.delroomIgnored = !confirmCalled;
|
||||||
|
return out;
|
||||||
|
});
|
||||||
|
console.log(JSON.stringify(res, null, 1));
|
||||||
|
await browser.close();
|
||||||
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
@@ -1,5 +1,11 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v1.31.1 — 2026-07-22
|
||||||
|
- Plan editor: interacting with a room card (drag, corner-resize or a plain
|
||||||
|
click) no longer leaks into the active markup tool — previously the click
|
||||||
|
after a resize could add an outline point, pick a merge/split room or even
|
||||||
|
prompt to delete the room under the card.
|
||||||
|
|
||||||
## v1.31.0 — 2026-07-22 (room cards)
|
## v1.31.0 — 2026-07-22 (room cards)
|
||||||
- Room labels grew into **room cards**: the name on top, and an optional
|
- Room labels grew into **room cards**: the name on top, and an optional
|
||||||
smaller metrics line below — temperature, humidity, average Zigbee signal
|
smaller metrics line below — temperature, humidity, average Zigbee signal
|
||||||
|
|||||||
@@ -140,6 +140,9 @@ Run the *core flows* (marked ★ below) in each environment at least once per mi
|
|||||||
(explicit ripple color still wins); off/white lights unchanged [auto]
|
(explicit ripple color still wins); off/white lights unchanged [auto]
|
||||||
- [ ] Alarm pulse (v1.27.0): leak/smoke/gas/CO/siren in 'on' pulse a red ring over any
|
- [ ] Alarm pulse (v1.27.0): leak/smoke/gas/CO/siren in 'on' pulse a red ring over any
|
||||||
display mode; clears on 'off'; unavailable never alarms [auto]; reduced-motion static
|
display mode; clears on 'off'; unavailable never alarms [auto]; reduced-motion static
|
||||||
|
- [ ] Card vs tool conflict (v1.31.1): in the Plan editor, dragging/resizing or
|
||||||
|
clicking a room card never feeds the active tool (no draw point, no
|
||||||
|
delete-room confirm, no merge/split pick); clicks past the card work [auto]
|
||||||
- [ ] Room cards (v1.31.0): with metrics enabled in space settings (4
|
- [ ] Room cards (v1.31.0): with metrics enabled in space settings (4
|
||||||
checkboxes: temperature, humidity, avg Zigbee, lights) the room name gets
|
checkboxes: temperature, humidity, avg Zigbee, lights) the room name gets
|
||||||
a smaller metrics line under it; lights show On/Off or "1 of 3" when
|
a smaller metrics line under it; lights show On/Off or "1 of 3" when
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "houseplan-card",
|
"name": "houseplan-card",
|
||||||
"version": "1.31.0",
|
"version": "1.31.1",
|
||||||
"description": "Interactive house plan Lovelace card for Home Assistant",
|
"description": "Interactive house plan Lovelace card for Home Assistant",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import './space-card';
|
|||||||
import { cardStyles } from './styles';
|
import { cardStyles } from './styles';
|
||||||
import { langOf, t, type I18nKey } from './i18n';
|
import { langOf, t, type I18nKey } from './i18n';
|
||||||
|
|
||||||
const CARD_VERSION = '1.31.0';
|
const CARD_VERSION = '1.31.1';
|
||||||
const LS_KEY = 'houseplan_card_layout_v1';
|
const LS_KEY = 'houseplan_card_layout_v1';
|
||||||
const LS_CFG = 'houseplan_card_cfg_v1'; // cache of the server config+layout for instant rendering
|
const LS_CFG = 'houseplan_card_cfg_v1'; // cache of the server config+layout for instant rendering
|
||||||
const LS_ZOOM = 'houseplan_card_zoom_v1';
|
const LS_ZOOM = 'houseplan_card_zoom_v1';
|
||||||
@@ -1171,6 +1171,13 @@ class HouseplanCard extends LitElement {
|
|||||||
|
|
||||||
private _markupClick(ev: MouseEvent): void {
|
private _markupClick(ev: MouseEvent): void {
|
||||||
if (!this._markup) return;
|
if (!this._markup) return;
|
||||||
|
// Room cards swallow markup clicks: dragging, resizing or just clicking a
|
||||||
|
// card must not feed the active tool (draw point, delete room, merge/split
|
||||||
|
// pick, opening placement). The drag itself already stops pointer events,
|
||||||
|
// but the synthesized `click` afterwards still bubbles to the stage.
|
||||||
|
if (this._drag || this._rlResize) return;
|
||||||
|
const path = (ev.composedPath?.() || []) as any[];
|
||||||
|
if (path.some((n) => n?.classList?.contains?.('roomlabel') || n?.classList?.contains?.('rlhandle'))) return;
|
||||||
const raw = this._svgPoint(ev);
|
const raw = this._svgPoint(ev);
|
||||||
if (this._tool === 'delroom') {
|
if (this._tool === 'delroom') {
|
||||||
const space = this._spaceModel();
|
const space = this._spaceModel();
|
||||||
|
|||||||
Reference in New Issue
Block a user