@grafloria/element 0.4.30 → 0.4.32
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.
- package/package.json +1 -1
- package/src/lib/dashboard-kit/dashboard.d.ts +16 -2
- package/src/lib/dashboard-kit/dashboard.js +502 -89
- package/src/lib/dashboard-kit/grid-binder.d.ts +91 -0
- package/src/lib/dashboard-kit/grid-binder.js +355 -42
- package/src/lib/dashboard-kit/split-binder.js +2 -0
- package/src/lib/dashboard-kit/styles.js +22 -0
- package/src/lib/dashboard-kit/tabs.d.ts +1 -1
- package/src/lib/dashboard-kit/tabs.js +1 -1
- package/src/lib/load.js +9 -1
|
@@ -156,6 +156,38 @@ export function pressOnDragHandle(sel, target, hostEl, clientX, clientY) {
|
|
|
156
156
|
export const CAPTION_BAND = 28;
|
|
157
157
|
/** A torn-out page never arrives shorter than this: a strip with no room under it is not a group. */
|
|
158
158
|
export const TEAR_OUT_MIN_ROWS = 2;
|
|
159
|
+
/**
|
|
160
|
+
* Steps that depend on each other's RESULT — create a group, then move a page
|
|
161
|
+
* into it, then place the group on the board; or remove a member and then the
|
|
162
|
+
* group it emptied — run as one history step. A batch checks every member's
|
|
163
|
+
* `canExecute` before running any of them and every member's `canUndo` before
|
|
164
|
+
* undoing any, and a membership command's precondition (its group exists) is
|
|
165
|
+
* exactly what a neighbouring step creates or removes. This runs the chain in
|
|
166
|
+
* order and reverses it on undo, judging nothing up front.
|
|
167
|
+
*/
|
|
168
|
+
export class SequenceCommand extends Command {
|
|
169
|
+
constructor(name, steps) {
|
|
170
|
+
super(name);
|
|
171
|
+
this.steps = steps;
|
|
172
|
+
}
|
|
173
|
+
execute(context) {
|
|
174
|
+
for (const c of this.steps)
|
|
175
|
+
c.execute(context);
|
|
176
|
+
}
|
|
177
|
+
undo(context) {
|
|
178
|
+
for (let i = this.steps.length - 1; i >= 0; i--)
|
|
179
|
+
this.steps[i].undo(context);
|
|
180
|
+
}
|
|
181
|
+
canExecute() {
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
canUndo() {
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
serialize() {
|
|
188
|
+
return { id: this.id, name: this.name, timestamp: this.timestamp, data: { steps: this.steps.map((c) => c.serialize()) } };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
159
191
|
/**
|
|
160
192
|
* Binders on the same canvas find each other here. A WeakMap: a canvas that
|
|
161
193
|
* is gone takes its (empty) peer set with it — the strong Map it replaced kept
|
|
@@ -1257,6 +1289,8 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1257
1289
|
return false;
|
|
1258
1290
|
};
|
|
1259
1291
|
let slabGesture = null;
|
|
1292
|
+
/** The slab gesture as it is NOW — read through a call so a guard's narrowing does not stick. */
|
|
1293
|
+
const currentSlab = () => slabGesture;
|
|
1260
1294
|
/** The PARENT running a resize of OUR section from a press this tool claimed. */
|
|
1261
1295
|
let forwardSlab = null;
|
|
1262
1296
|
const frameOfGroup = (grp) => ({ x: grp.position.x, y: grp.position.y, width: sizeOf(grp).width, height: sizeOf(grp).height });
|
|
@@ -1281,10 +1315,48 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1281
1315
|
dx: edges.e ? grp.position.x + sizeOf(grp).width - ev.world.x : edges.w ? grp.position.x - ev.world.x : 0,
|
|
1282
1316
|
dy: edges.s ? grp.position.y + sizeOf(grp).height - ev.world.y : edges.n ? grp.position.y - ev.world.y : 0,
|
|
1283
1317
|
},
|
|
1318
|
+
move: false,
|
|
1284
1319
|
};
|
|
1285
1320
|
capturePointer(slabGesture.pointerId);
|
|
1286
1321
|
api.container.style.cursor = cursorFor(edges);
|
|
1287
1322
|
};
|
|
1323
|
+
/**
|
|
1324
|
+
* MOVE a section by its caption band or its strip's empty space. A section
|
|
1325
|
+
* is a LOCKED tile so that nothing pushes it; for the gesture's duration the
|
|
1326
|
+
* tile is unlocked (it is the one moving), other sections stay locked and
|
|
1327
|
+
* still refuse it (E4b), and every unlocked tile gets pushed the way a
|
|
1328
|
+
* widget pushes it. Its children ride along: the frame moves, the nested
|
|
1329
|
+
* board re-projects.
|
|
1330
|
+
*/
|
|
1331
|
+
const beginSlabMove = (id, ev) => {
|
|
1332
|
+
const grp = diagram.getGroup(id);
|
|
1333
|
+
const it = engine.getItem(id);
|
|
1334
|
+
if (!grp || !it || gesture || slabGesture || isStatic)
|
|
1335
|
+
return;
|
|
1336
|
+
engine.beginGesture();
|
|
1337
|
+
const snap = snapshotAll();
|
|
1338
|
+
it.locked = false;
|
|
1339
|
+
slabGesture = {
|
|
1340
|
+
id,
|
|
1341
|
+
edges: NO_EDGES,
|
|
1342
|
+
pointerId: typeof PointerEvent !== 'undefined' && ev.source instanceof PointerEvent ? ev.source.pointerId : null,
|
|
1343
|
+
started: false,
|
|
1344
|
+
downScreen: { x: ev.screen.x, y: ev.screen.y },
|
|
1345
|
+
startCells: snap.cells,
|
|
1346
|
+
startGeom: snap.geoms,
|
|
1347
|
+
cellBefore: { x: it.x, y: it.y, w: it.w, h: it.h },
|
|
1348
|
+
frameBefore: frameOfGroup(grp),
|
|
1349
|
+
grab: { dx: grp.position.x - ev.world.x, dy: grp.position.y - ev.world.y },
|
|
1350
|
+
move: true,
|
|
1351
|
+
};
|
|
1352
|
+
capturePointer(slabGesture.pointerId);
|
|
1353
|
+
api.container.style.cursor = 'grabbing';
|
|
1354
|
+
};
|
|
1355
|
+
const relockSlab = (id) => {
|
|
1356
|
+
const it = engine.getItem(id);
|
|
1357
|
+
if (it)
|
|
1358
|
+
it.locked = true;
|
|
1359
|
+
};
|
|
1288
1360
|
const slabMove = (ev) => {
|
|
1289
1361
|
const g = slabGesture;
|
|
1290
1362
|
if (!g)
|
|
@@ -1300,6 +1372,14 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1300
1372
|
return;
|
|
1301
1373
|
const f = frame();
|
|
1302
1374
|
const gg = geom();
|
|
1375
|
+
if (g.move) {
|
|
1376
|
+
// The section's top-left follows the pointer by the offset it was grabbed at.
|
|
1377
|
+
const cell = pointToCell(ev.world.x + g.grab.dx, ev.world.y + g.grab.dy, f, gg, rows(), it.w);
|
|
1378
|
+
if ((cell.x !== it.x || cell.y !== it.y) && engine.moveCheck(g.id, cell.x, cell.y, { gate: false }).changed)
|
|
1379
|
+
project();
|
|
1380
|
+
syncPlaceholder();
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1303
1383
|
const cu = columnUnitFor(gg, f.width);
|
|
1304
1384
|
const rh = rowHeightFor(gg, rows());
|
|
1305
1385
|
// The grid line nearest the pointer, in cells (mirrored on RTL).
|
|
@@ -1346,6 +1426,8 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1346
1426
|
slabGesture = null;
|
|
1347
1427
|
releasePointer(g.pointerId);
|
|
1348
1428
|
api.container.style.cursor = '';
|
|
1429
|
+
if (g.move)
|
|
1430
|
+
relockSlab(g.id);
|
|
1349
1431
|
if (!g.started) {
|
|
1350
1432
|
engine.endGesture();
|
|
1351
1433
|
return;
|
|
@@ -1359,11 +1441,11 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1359
1441
|
if (it && grp && (b.x !== it.x || b.y !== it.y || b.w !== it.w || b.h !== it.h)) {
|
|
1360
1442
|
commands.push(new SetGroupCellCommand(g.id, b, { x: it.x, y: it.y, w: it.w, h: it.h }, g.frameBefore, frameOfGroup(grp)));
|
|
1361
1443
|
}
|
|
1362
|
-
const changed = execute('Resize section', commands);
|
|
1444
|
+
const changed = execute(g.move ? 'Move section' : 'Resize section', commands);
|
|
1363
1445
|
disarmGlideSoon();
|
|
1364
1446
|
syncHandles();
|
|
1365
1447
|
api.renderNow();
|
|
1366
|
-
(_a = options.onGesture) === null || _a === void 0 ? void 0 : _a.call(options, { type: 'commit', kind: 'resize', nodeId: g.id, changed });
|
|
1448
|
+
(_a = options.onGesture) === null || _a === void 0 ? void 0 : _a.call(options, { type: 'commit', kind: g.move ? 'move' : 'resize', nodeId: g.id, changed });
|
|
1367
1449
|
};
|
|
1368
1450
|
const slabCancel = () => {
|
|
1369
1451
|
var _a;
|
|
@@ -1373,6 +1455,8 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1373
1455
|
slabGesture = null;
|
|
1374
1456
|
releasePointer(g.pointerId);
|
|
1375
1457
|
api.container.style.cursor = '';
|
|
1458
|
+
if (g.move)
|
|
1459
|
+
relockSlab(g.id);
|
|
1376
1460
|
if (g.started)
|
|
1377
1461
|
engine.cancelGesture();
|
|
1378
1462
|
else
|
|
@@ -1487,9 +1571,13 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1487
1571
|
(_a = options.onGesture) === null || _a === void 0 ? void 0 : _a.call(options, { type: 'commit', kind: g.kind, nodeId: g.id, changed });
|
|
1488
1572
|
};
|
|
1489
1573
|
const cancelActiveGesture = (notify = true) => {
|
|
1490
|
-
var _a, _b, _c, _d;
|
|
1574
|
+
var _a, _b, _c, _d, _e;
|
|
1575
|
+
if (gesture === null || gesture === void 0 ? void 0 : gesture.strip) {
|
|
1576
|
+
(_a = options.tabDrop) === null || _a === void 0 ? void 0 : _a.markDrop(null, null);
|
|
1577
|
+
gesture.strip = null;
|
|
1578
|
+
}
|
|
1491
1579
|
if (forwardSlab) {
|
|
1492
|
-
(
|
|
1580
|
+
(_b = forwardSlab.slabCancel) === null || _b === void 0 ? void 0 : _b.call(forwardSlab);
|
|
1493
1581
|
forwardSlab = null;
|
|
1494
1582
|
}
|
|
1495
1583
|
if (slabGesture)
|
|
@@ -1514,7 +1602,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1514
1602
|
engine.endGesture();
|
|
1515
1603
|
const items = [];
|
|
1516
1604
|
for (const [id, c] of g.startCells) {
|
|
1517
|
-
const lockedNode = ((
|
|
1605
|
+
const lockedNode = ((_d = (_c = diagram.getNode(id)) === null || _c === void 0 ? void 0 : _c.state) === null || _d === void 0 ? void 0 : _d.locked) === true;
|
|
1518
1606
|
items.push(Object.assign(Object.assign({ id }, c), { locked: lockedNode || isGroupMember(id) }));
|
|
1519
1607
|
}
|
|
1520
1608
|
engine = engineFrom(items);
|
|
@@ -1562,7 +1650,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1562
1650
|
enforceBoardHeight();
|
|
1563
1651
|
api.renderNow();
|
|
1564
1652
|
if (notify) {
|
|
1565
|
-
(
|
|
1653
|
+
(_e = options.onGesture) === null || _e === void 0 ? void 0 : _e.call(options, { type: 'cancel', kind: g.kind, nodeId: g.id, changed: false });
|
|
1566
1654
|
}
|
|
1567
1655
|
};
|
|
1568
1656
|
/** Centre a w×h-span tile's top-left under the cursor, in world px. */
|
|
@@ -1577,7 +1665,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1577
1665
|
};
|
|
1578
1666
|
};
|
|
1579
1667
|
const onToolMove = (ev) => {
|
|
1580
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
1668
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
1581
1669
|
const g = gesture;
|
|
1582
1670
|
if (!g || g.kind === 'palette')
|
|
1583
1671
|
return;
|
|
@@ -1594,6 +1682,36 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1594
1682
|
ghostStyleFastPath(g, desired);
|
|
1595
1683
|
g.lastWorld = { x: ev.world.x, y: ev.world.y };
|
|
1596
1684
|
g.lastScreen = { x: ev.screen.x, y: ev.screen.y };
|
|
1685
|
+
// A TAB STRIP under the pointer wins over every board: the widget will
|
|
1686
|
+
// become a new tab there, so it leaves this board (survivors settle
|
|
1687
|
+
// home) and the strip marks the slot.
|
|
1688
|
+
if (options.tabDrop && !isStatic) {
|
|
1689
|
+
const crect = api.container.getBoundingClientRect();
|
|
1690
|
+
const hitStrip = options.tabDrop.stripAt(crect.left + ev.screen.x, crect.top + ev.screen.y);
|
|
1691
|
+
if (hitStrip) {
|
|
1692
|
+
if (g.leg) {
|
|
1693
|
+
g.leg.adopted.abort();
|
|
1694
|
+
g.leg = null;
|
|
1695
|
+
}
|
|
1696
|
+
if (!g.removedFromBoard) {
|
|
1697
|
+
g.removedFromBoard = true;
|
|
1698
|
+
engine.remove(g.id);
|
|
1699
|
+
project();
|
|
1700
|
+
}
|
|
1701
|
+
(_a = hostOf(g.id)) === null || _a === void 0 ? void 0 : _a.classList.remove('axdb-out');
|
|
1702
|
+
if (!g.strip || g.strip.containerId !== hitStrip.containerId || g.strip.index !== hitStrip.index) {
|
|
1703
|
+
options.tabDrop.markDrop(hitStrip.containerId, hitStrip.index);
|
|
1704
|
+
}
|
|
1705
|
+
g.strip = hitStrip;
|
|
1706
|
+
syncPlaceholder();
|
|
1707
|
+
api.render();
|
|
1708
|
+
return;
|
|
1709
|
+
}
|
|
1710
|
+
if (g.strip) {
|
|
1711
|
+
options.tabDrop.markDrop(null, null);
|
|
1712
|
+
g.strip = null;
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1597
1715
|
// Deepest board under the pointer wins: the nested KPI strip beats the
|
|
1598
1716
|
// tab that contains it; a foreign board beats "outside". Strict frames
|
|
1599
1717
|
// first; the one-row grace band below each board (gridstack's extra
|
|
@@ -1633,13 +1751,13 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1633
1751
|
height: g.node.size.height,
|
|
1634
1752
|
});
|
|
1635
1753
|
if (adopted) {
|
|
1636
|
-
(
|
|
1754
|
+
(_b = hostOf(g.id)) === null || _b === void 0 ? void 0 : _b.classList.remove('axdb-out');
|
|
1637
1755
|
g.leg = { peer, adopted };
|
|
1638
1756
|
g.leg.adopted.move(ev.world);
|
|
1639
1757
|
}
|
|
1640
1758
|
else {
|
|
1641
1759
|
// Bounded/full board refused the adoption: dim = will snap home.
|
|
1642
|
-
(
|
|
1760
|
+
(_c = hostOf(g.id)) === null || _c === void 0 ? void 0 : _c.classList.add('axdb-out');
|
|
1643
1761
|
}
|
|
1644
1762
|
}
|
|
1645
1763
|
}
|
|
@@ -1651,7 +1769,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1651
1769
|
}
|
|
1652
1770
|
if (g.removedFromBoard) {
|
|
1653
1771
|
g.removedFromBoard = false;
|
|
1654
|
-
(
|
|
1772
|
+
(_d = hostOf(g.id)) === null || _d === void 0 ? void 0 : _d.classList.remove('axdb-out');
|
|
1655
1773
|
const cell = pointToCell(desired.x, desired.y, frame(), geom(), rows(), g.spans.w);
|
|
1656
1774
|
// Re-enter at the bottom edge (collision-free), then take the cursor
|
|
1657
1775
|
// cell GATELESSLY — a first placement skips the anti-jitter gate.
|
|
@@ -1660,7 +1778,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1660
1778
|
project();
|
|
1661
1779
|
}
|
|
1662
1780
|
else {
|
|
1663
|
-
const spanW = (
|
|
1781
|
+
const spanW = (_f = (_e = engine.getItem(g.id)) === null || _e === void 0 ? void 0 : _e.w) !== null && _f !== void 0 ? _f : g.spans.w;
|
|
1664
1782
|
const cell = pointToCell(desired.x, desired.y, frame(), geom(), rows(), spanW);
|
|
1665
1783
|
if (engine.moveCheck(g.id, cell.x, cell.y).changed)
|
|
1666
1784
|
project();
|
|
@@ -1675,7 +1793,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1675
1793
|
if (!g.removedFromBoard) {
|
|
1676
1794
|
g.removedFromBoard = true;
|
|
1677
1795
|
engine.remove(g.id); // survivors settle home; cells minted nowhere
|
|
1678
|
-
(
|
|
1796
|
+
(_g = hostOf(g.id)) === null || _g === void 0 ? void 0 : _g.classList.add('axdb-out');
|
|
1679
1797
|
project();
|
|
1680
1798
|
}
|
|
1681
1799
|
}
|
|
@@ -1785,7 +1903,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1785
1903
|
maxRows = n;
|
|
1786
1904
|
engine.maxRows = n;
|
|
1787
1905
|
};
|
|
1788
|
-
const slabRows = (
|
|
1906
|
+
const slabRows = (_j = (_h = parent.memberCell(group.id)) === null || _h === void 0 ? void 0 : _h.h) !== null && _j !== void 0 ? _j : maxRows;
|
|
1789
1907
|
const inner = maxRows;
|
|
1790
1908
|
const rhNow = rowHeightFor(geom(), rows());
|
|
1791
1909
|
const rowPx = rhNow + gap;
|
|
@@ -1949,7 +2067,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1949
2067
|
const anchorBottom = liveRect ? liveRect.y + liveRect.height : bottom;
|
|
1950
2068
|
const px = E.w ? anchorRight - w : anchorLeft;
|
|
1951
2069
|
const py = E.n ? anchorBottom - h : anchorTop;
|
|
1952
|
-
g.node.setSize(w, h, (
|
|
2070
|
+
g.node.setSize(w, h, (_k = g.node.size.depth) !== null && _k !== void 0 ? _k : 0);
|
|
1953
2071
|
g.node.setPosition(px, py);
|
|
1954
2072
|
ghostStyleFastPath(g, { x: px, y: py, width: w, height: h });
|
|
1955
2073
|
const spanF = bound() !== undefined ? frame() : f;
|
|
@@ -1990,7 +2108,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1990
2108
|
syncPlaceholder();
|
|
1991
2109
|
};
|
|
1992
2110
|
const onToolUp = () => {
|
|
1993
|
-
var _a, _b, _c, _d, _e, _f;
|
|
2111
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
1994
2112
|
const g = gesture;
|
|
1995
2113
|
if (!g || g.kind === 'palette')
|
|
1996
2114
|
return;
|
|
@@ -1998,6 +2116,36 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1998
2116
|
gesture = null; // a plain click — the page's own click-to-focus handles it
|
|
1999
2117
|
return;
|
|
2000
2118
|
}
|
|
2119
|
+
if (g.strip && options.tabDrop) {
|
|
2120
|
+
// -- INTO A STRIP: the widget becomes a new tab of that container ------
|
|
2121
|
+
const target = g.strip;
|
|
2122
|
+
g.strip = null;
|
|
2123
|
+
options.tabDrop.markDrop(null, null);
|
|
2124
|
+
if (g.leg) {
|
|
2125
|
+
g.leg.adopted.abort();
|
|
2126
|
+
g.leg = null;
|
|
2127
|
+
}
|
|
2128
|
+
const displaced = buildCommitCommands(deltasSince(g.startCells, g.startGeom, g.id));
|
|
2129
|
+
const snap = g.startGeom.get(g.id);
|
|
2130
|
+
if (snap) {
|
|
2131
|
+
g.node.setPosition(snap.pos.x, snap.pos.y);
|
|
2132
|
+
g.node.setSize(snap.size.width, snap.size.height, (_a = snap.size.depth) !== null && _a !== void 0 ? _a : 0);
|
|
2133
|
+
}
|
|
2134
|
+
const cmds = options.tabDrop.dropIntoStrip(g.id, target.containerId, target.index, group.id, displaced);
|
|
2135
|
+
if (cmds.length === 0) {
|
|
2136
|
+
cancelActiveGesture();
|
|
2137
|
+
return;
|
|
2138
|
+
}
|
|
2139
|
+
engine.endGesture();
|
|
2140
|
+
cleanupGestureVisuals(g);
|
|
2141
|
+
gesture = null;
|
|
2142
|
+
execute('Move widget into a new tab', cmds);
|
|
2143
|
+
enforceBoardHeight();
|
|
2144
|
+
persistLayouts();
|
|
2145
|
+
api.renderNow();
|
|
2146
|
+
(_b = options.onGesture) === null || _b === void 0 ? void 0 : _b.call(options, { type: 'commit', kind: g.kind, nodeId: g.id, changed: true });
|
|
2147
|
+
return;
|
|
2148
|
+
}
|
|
2001
2149
|
if (g.leg) {
|
|
2002
2150
|
// -- CROSS-CONTAINER COMMIT: one batch across both boards -----------
|
|
2003
2151
|
const fin = g.leg.adopted.finalize();
|
|
@@ -2040,21 +2188,25 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2040
2188
|
isGroup: false,
|
|
2041
2189
|
cellBefore: before !== null && before !== void 0 ? before : fin.cell,
|
|
2042
2190
|
cellAfter: fin.cell,
|
|
2043
|
-
posBefore: (
|
|
2191
|
+
posBefore: (_c = geomBefore === null || geomBefore === void 0 ? void 0 : geomBefore.pos) !== null && _c !== void 0 ? _c : { x: fin.rect.x, y: fin.rect.y },
|
|
2044
2192
|
posAfter: { x: fin.rect.x, y: fin.rect.y },
|
|
2045
|
-
sizeBefore: (
|
|
2193
|
+
sizeBefore: (_d = geomBefore === null || geomBefore === void 0 ? void 0 : geomBefore.size) !== null && _d !== void 0 ? _d : { width: fin.rect.width, height: fin.rect.height },
|
|
2046
2194
|
sizeAfter: { width: fin.rect.width, height: fin.rect.height },
|
|
2047
2195
|
},
|
|
2048
2196
|
]),
|
|
2049
2197
|
];
|
|
2050
|
-
|
|
2198
|
+
// …and whatever follows a member out of this board: an emptied page
|
|
2199
|
+
// closes — in which case the membership commands ride INSIDE one
|
|
2200
|
+
// sequence with it, or the batch could never undo (its group is gone).
|
|
2201
|
+
const leaving = (_f = (_e = options.onMemberLeaving) === null || _e === void 0 ? void 0 : _e.call(options, g.id)) !== null && _f !== void 0 ? _f : [];
|
|
2202
|
+
execute('Move widget', leaving.length > 0 ? [new SequenceCommand('Move widget', [...crossing, ...leaving])] : crossing);
|
|
2051
2203
|
engine.endGesture();
|
|
2052
2204
|
cleanupGestureVisuals(g);
|
|
2053
2205
|
gesture = null;
|
|
2054
2206
|
enforceBoardHeight();
|
|
2055
2207
|
persistLayouts();
|
|
2056
2208
|
api.renderNow();
|
|
2057
|
-
(
|
|
2209
|
+
(_g = options.onGesture) === null || _g === void 0 ? void 0 : _g.call(options, { type: 'commit', kind: g.kind, nodeId: g.id, changed: true });
|
|
2058
2210
|
return;
|
|
2059
2211
|
}
|
|
2060
2212
|
if (g.removedFromBoard && dragOut === 'cancel') {
|
|
@@ -2085,15 +2237,15 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2085
2237
|
// Park the node on its start rect so the page's RemoveNodeCommand
|
|
2086
2238
|
// captures sane geometry for undo.
|
|
2087
2239
|
g.node.setPosition(snap.pos.x, snap.pos.y);
|
|
2088
|
-
g.node.setSize(snap.size.width, snap.size.height, (
|
|
2240
|
+
g.node.setSize(snap.size.width, snap.size.height, (_h = snap.size.depth) !== null && _h !== void 0 ? _h : 0);
|
|
2089
2241
|
}
|
|
2090
2242
|
engine.endGesture();
|
|
2091
2243
|
cleanupGestureVisuals(g);
|
|
2092
2244
|
gesture = null;
|
|
2093
2245
|
enforceBoardHeight();
|
|
2094
2246
|
api.renderNow();
|
|
2095
|
-
void ((
|
|
2096
|
-
(
|
|
2247
|
+
void ((_j = options.onRemoveRequest) === null || _j === void 0 ? void 0 : _j.call(options, g.id, displaced));
|
|
2248
|
+
(_k = options.onGesture) === null || _k === void 0 ? void 0 : _k.call(options, { type: 'remove', kind: g.kind, nodeId: g.id, changed: true });
|
|
2097
2249
|
return;
|
|
2098
2250
|
}
|
|
2099
2251
|
commitGesture(g);
|
|
@@ -2314,8 +2466,29 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2314
2466
|
project();
|
|
2315
2467
|
syncPlaceholder();
|
|
2316
2468
|
},
|
|
2469
|
+
leave: () => {
|
|
2470
|
+
if (!engine.getItem(node.id))
|
|
2471
|
+
return;
|
|
2472
|
+
engine.remove(node.id); // displaced tiles come home (gesture memory)
|
|
2473
|
+
lastWant = null;
|
|
2474
|
+
project();
|
|
2475
|
+
syncPlaceholder();
|
|
2476
|
+
},
|
|
2477
|
+
enter: (w) => {
|
|
2478
|
+
if (!engine.getItem(node.id) && !engine.add({ id: node.id, x: 0, y: engine.rows(), w: span.w, h: hNatural }))
|
|
2479
|
+
return;
|
|
2480
|
+
const item = engine.getItem(node.id);
|
|
2481
|
+
if (!item)
|
|
2482
|
+
return;
|
|
2483
|
+
const cell = wantedCell(w.x, w.y, item.w, opts.fit === 'shrink' ? hNatural : item.h);
|
|
2484
|
+
lastWant = cell;
|
|
2485
|
+
place(cell, item.w);
|
|
2486
|
+
project();
|
|
2487
|
+
syncPlaceholder();
|
|
2488
|
+
},
|
|
2317
2489
|
abort: () => {
|
|
2318
|
-
engine.
|
|
2490
|
+
if (engine.getItem(node.id))
|
|
2491
|
+
engine.remove(node.id);
|
|
2319
2492
|
engine.cancelGesture(); // pre-entry layout, memory cleared
|
|
2320
2493
|
adoptedGhostId = null;
|
|
2321
2494
|
disarmGlideSoon();
|
|
@@ -2367,6 +2540,56 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2367
2540
|
beginSlabResize(id, edges, ev);
|
|
2368
2541
|
return (slabGesture === null || slabGesture === void 0 ? void 0 : slabGesture.id) === id;
|
|
2369
2542
|
},
|
|
2543
|
+
beginSlabMove: (id, ev) => {
|
|
2544
|
+
if (isStatic)
|
|
2545
|
+
return false;
|
|
2546
|
+
beginSlabMove(id, ev);
|
|
2547
|
+
return (slabGesture === null || slabGesture === void 0 ? void 0 : slabGesture.id) === id;
|
|
2548
|
+
},
|
|
2549
|
+
dragMember: (id, ev) => {
|
|
2550
|
+
var _a;
|
|
2551
|
+
if (isStatic || disposed || !engine.getItem(id) || gesture || slabGesture)
|
|
2552
|
+
return false;
|
|
2553
|
+
const toTool = (e) => {
|
|
2554
|
+
var _a;
|
|
2555
|
+
const rect = api.container.getBoundingClientRect();
|
|
2556
|
+
const world = ((_a = api.viewport) === null || _a === void 0 ? void 0 : _a.clientToWorld) ? api.viewport.clientToWorld(e.clientX, e.clientY, rect) : { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
|
2557
|
+
return { world, screen: { x: e.clientX - rect.left, y: e.clientY - rect.top }, source: e };
|
|
2558
|
+
};
|
|
2559
|
+
beginSlabMove(id, toTool(ev));
|
|
2560
|
+
if (((_a = currentSlab()) === null || _a === void 0 ? void 0 : _a.id) !== id)
|
|
2561
|
+
return false;
|
|
2562
|
+
const detachAll = () => {
|
|
2563
|
+
window.removeEventListener('pointermove', onMove, true);
|
|
2564
|
+
window.removeEventListener('pointerup', onUp, true);
|
|
2565
|
+
window.removeEventListener('pointercancel', onCancel, true);
|
|
2566
|
+
window.removeEventListener('keydown', onKey, true);
|
|
2567
|
+
};
|
|
2568
|
+
const onMove = (e) => {
|
|
2569
|
+
var _a;
|
|
2570
|
+
if (disposed || ((_a = currentSlab()) === null || _a === void 0 ? void 0 : _a.id) !== id)
|
|
2571
|
+
return detachAll();
|
|
2572
|
+
slabMove(toTool(e));
|
|
2573
|
+
api.render();
|
|
2574
|
+
};
|
|
2575
|
+
const onUp = () => {
|
|
2576
|
+
detachAll();
|
|
2577
|
+
slabUp();
|
|
2578
|
+
};
|
|
2579
|
+
const onCancel = () => {
|
|
2580
|
+
detachAll();
|
|
2581
|
+
slabCancel();
|
|
2582
|
+
};
|
|
2583
|
+
const onKey = (e) => {
|
|
2584
|
+
if (e.key === 'Escape')
|
|
2585
|
+
onCancel();
|
|
2586
|
+
};
|
|
2587
|
+
window.addEventListener('pointermove', onMove, true);
|
|
2588
|
+
window.addEventListener('pointerup', onUp, true);
|
|
2589
|
+
window.addEventListener('pointercancel', onCancel, true);
|
|
2590
|
+
window.addEventListener('keydown', onKey, true);
|
|
2591
|
+
return true;
|
|
2592
|
+
},
|
|
2370
2593
|
slabMove: (ev) => slabMove(ev),
|
|
2371
2594
|
slabUp: () => slabUp(),
|
|
2372
2595
|
slabCancel: () => slabCancel(),
|
|
@@ -2473,7 +2696,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2473
2696
|
return insideMemberGroupFrame(ev.world.x, ev.world.y) || worldInsideBoard(ev.world.x, ev.world.y);
|
|
2474
2697
|
},
|
|
2475
2698
|
onPointerDown(ev, hit) {
|
|
2476
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
|
|
2699
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
|
|
2477
2700
|
if (gesture)
|
|
2478
2701
|
return; // mid-palette
|
|
2479
2702
|
const target = ((_b = (_a = ev.source) === null || _a === void 0 ? void 0 : _a.target) !== null && _b !== void 0 ? _b : null);
|
|
@@ -2511,6 +2734,10 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2511
2734
|
: slabEdgesNear(grp, ev.world.x, ev.world.y);
|
|
2512
2735
|
if (anyEdge(edges))
|
|
2513
2736
|
beginSlabResize(slabId, edges, ev);
|
|
2737
|
+
// The caption band is the section's handle: pressed and travelled,
|
|
2738
|
+
// it moves the whole section (its inner empty space only selects).
|
|
2739
|
+
else if (ownCaption)
|
|
2740
|
+
beginSlabMove(slabId, ev);
|
|
2514
2741
|
return;
|
|
2515
2742
|
}
|
|
2516
2743
|
// OUR OWN empty band, and we are a section of a parent board: the
|
|
@@ -2527,12 +2754,14 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2527
2754
|
: slabEdgesNear(group, ev.world.x, ev.world.y);
|
|
2528
2755
|
if (anyEdge(edges) && parent.beginSlabResize(group.id, edges, ev))
|
|
2529
2756
|
forwardSlab = parent;
|
|
2757
|
+
else if (!anyEdge(edges) && captionId === group.id && ((_r = parent.beginSlabMove) === null || _r === void 0 ? void 0 : _r.call(parent, group.id, ev)))
|
|
2758
|
+
forwardSlab = parent;
|
|
2530
2759
|
}
|
|
2531
2760
|
return;
|
|
2532
2761
|
}
|
|
2533
2762
|
// The board's own empty area: a void click. Nothing to drag, and the
|
|
2534
2763
|
// selection clears exactly as a click outside any board would.
|
|
2535
|
-
(
|
|
2764
|
+
(_t = (_s = diagram).clearSelection) === null || _t === void 0 ? void 0 : _t.call(_s);
|
|
2536
2765
|
selectWidget(undefined);
|
|
2537
2766
|
api.render();
|
|
2538
2767
|
return;
|
|
@@ -2541,17 +2770,17 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2541
2770
|
if (!node)
|
|
2542
2771
|
return;
|
|
2543
2772
|
selectWidget(node.id); // a press selects, whether or not it starts a gesture
|
|
2544
|
-
if (((
|
|
2773
|
+
if (((_u = node.state) === null || _u === void 0 ? void 0 : _u.locked) === true)
|
|
2545
2774
|
return; // pinned: refuse; click still focuses
|
|
2546
2775
|
if (isStatic)
|
|
2547
2776
|
return; // a static board: claimed and deadened, click still focuses
|
|
2548
2777
|
// Which edges did the press take? The corner handle names its own (s+e,
|
|
2549
2778
|
// or s+w on RTL); a bare press within EDGE_GRIP of the tile's border
|
|
2550
2779
|
// takes that border; anywhere else is a move. A grip press is a move.
|
|
2551
|
-
const onHandle = !!((
|
|
2780
|
+
const onHandle = !!((_v = target === null || target === void 0 ? void 0 : target.closest) === null || _v === void 0 ? void 0 : _v.call(target, '.axdb-rs'));
|
|
2552
2781
|
const hostEl = hostOf(node.id);
|
|
2553
|
-
const resizable = ((
|
|
2554
|
-
const movable = ((
|
|
2782
|
+
const resizable = ((_w = node.getMetadata) === null || _w === void 0 ? void 0 : _w.call(node, 'widgetResizable')) !== false;
|
|
2783
|
+
const movable = ((_x = node.getMetadata) === null || _x === void 0 ? void 0 : _x.call(node, 'widgetMovable')) !== false;
|
|
2555
2784
|
// `ev.screen` is ELEMENT-LOCAL px; host rects are in client px. Compare
|
|
2556
2785
|
// like with like — the source event's clientX/Y when there is one, else
|
|
2557
2786
|
// the container's origin plus the local offset.
|
|
@@ -2599,9 +2828,10 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2599
2828
|
startSize: { width: node.size.width, height: node.size.height },
|
|
2600
2829
|
startPos: { x: node.position.x, y: node.position.y },
|
|
2601
2830
|
edges,
|
|
2602
|
-
spans: { w: (
|
|
2831
|
+
spans: { w: (_y = it === null || it === void 0 ? void 0 : it.w) !== null && _y !== void 0 ? _y : 1, h: (_z = it === null || it === void 0 ? void 0 : it.h) !== null && _z !== void 0 ? _z : 1 },
|
|
2603
2832
|
removedFromBoard: false,
|
|
2604
2833
|
leg: null,
|
|
2834
|
+
strip: null,
|
|
2605
2835
|
lastWorld: null,
|
|
2606
2836
|
lastScreen: null,
|
|
2607
2837
|
hostEl: null,
|
|
@@ -2920,6 +3150,48 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2920
3150
|
chip.className = 'axdb-drag-chip axdb-tab-chip';
|
|
2921
3151
|
chip.textContent = plan.label;
|
|
2922
3152
|
doc.body.appendChild(chip);
|
|
3153
|
+
// Over ANOTHER tab container the page joins it instead of taking a cell:
|
|
3154
|
+
// the tile leaves the board (its displaced tiles come home), the target's
|
|
3155
|
+
// frame lights up and its strip marks where the tab will go.
|
|
3156
|
+
const layer = htmlLayer();
|
|
3157
|
+
const targets = plan.joinTargets
|
|
3158
|
+
.map((id) => diagram.getGroup(id))
|
|
3159
|
+
.filter((g) => !!g && g.id !== fromGroupId);
|
|
3160
|
+
const targetAt = (wx, wy) => { var _a; return (_a = targets.find((t) => worldInsideGroup(t, wx, wy))) !== null && _a !== void 0 ? _a : null; };
|
|
3161
|
+
let over = null;
|
|
3162
|
+
let joinEl = null;
|
|
3163
|
+
const showJoin = (g) => {
|
|
3164
|
+
if (!layer || g.id === fromGroupId)
|
|
3165
|
+
return; // reordering along its own strip: the mark is enough
|
|
3166
|
+
if (!joinEl) {
|
|
3167
|
+
joinEl = doc.createElement('div');
|
|
3168
|
+
joinEl.className = 'axdb-join';
|
|
3169
|
+
layer.prepend(joinEl);
|
|
3170
|
+
}
|
|
3171
|
+
const sz = sizeOf(g);
|
|
3172
|
+
joinEl.style.left = `${g.position.x}px`;
|
|
3173
|
+
joinEl.style.top = `${g.position.y}px`;
|
|
3174
|
+
joinEl.style.width = `${sz.width}px`;
|
|
3175
|
+
joinEl.style.height = `${sz.height}px`;
|
|
3176
|
+
};
|
|
3177
|
+
const hideJoin = () => {
|
|
3178
|
+
joinEl === null || joinEl === void 0 ? void 0 : joinEl.remove();
|
|
3179
|
+
joinEl = null;
|
|
3180
|
+
plan.markDrop(null, null);
|
|
3181
|
+
};
|
|
3182
|
+
const setOver = (g, world) => {
|
|
3183
|
+
if (g === over)
|
|
3184
|
+
return;
|
|
3185
|
+
over = g;
|
|
3186
|
+
if (g) {
|
|
3187
|
+
leg.leave();
|
|
3188
|
+
showJoin(g);
|
|
3189
|
+
}
|
|
3190
|
+
else {
|
|
3191
|
+
hideJoin();
|
|
3192
|
+
leg.enter(world);
|
|
3193
|
+
}
|
|
3194
|
+
};
|
|
2923
3195
|
const moveChip = (cx, cy) => {
|
|
2924
3196
|
chip.style.left = `${cx + 6}px`;
|
|
2925
3197
|
chip.style.top = `${cy + 6}px`;
|
|
@@ -2934,6 +3206,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2934
3206
|
window.removeEventListener('pointercancel', onCancel, true);
|
|
2935
3207
|
window.removeEventListener('keydown', onKey, true);
|
|
2936
3208
|
};
|
|
3209
|
+
let homeIndex = null;
|
|
2937
3210
|
const onMove = (e) => {
|
|
2938
3211
|
if (disposed)
|
|
2939
3212
|
return detach();
|
|
@@ -2941,27 +3214,60 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2941
3214
|
moveChip(e.clientX, e.clientY);
|
|
2942
3215
|
const world = toWorld(e.clientX, e.clientY);
|
|
2943
3216
|
const home = worldInsideGroup(from, world.x, world.y);
|
|
2944
|
-
// Over its
|
|
2945
|
-
//
|
|
2946
|
-
|
|
2947
|
-
|
|
3217
|
+
// Over its OWN strip the tab reorders: the strip marks the slot and the
|
|
3218
|
+
// tile leaves the board. Over its own body it goes home (a cancel).
|
|
3219
|
+
homeIndex = home ? plan.stripIndex(fromGroupId, e.clientX, e.clientY) : null;
|
|
3220
|
+
const target = home ? null : targetAt(world.x, world.y);
|
|
3221
|
+
setOver(target !== null && target !== void 0 ? target : (homeIndex !== null ? from : null), world);
|
|
3222
|
+
chip.classList.toggle('axdb-out', (home && homeIndex === null) || (!target && !home && !worldInsideBoardGrace(world.x, world.y)));
|
|
3223
|
+
if (target)
|
|
3224
|
+
plan.markDrop(target.id, plan.dropIndex(target.id, e.clientX, e.clientY));
|
|
3225
|
+
else if (homeIndex !== null)
|
|
3226
|
+
plan.markDrop(fromGroupId, homeIndex);
|
|
3227
|
+
else if (!home)
|
|
2948
3228
|
leg.move(world);
|
|
2949
3229
|
api.render();
|
|
2950
3230
|
};
|
|
2951
3231
|
const finish = (commit) => {
|
|
2952
|
-
var _a, _b;
|
|
3232
|
+
var _a, _b, _c, _d;
|
|
2953
3233
|
detach();
|
|
2954
3234
|
chip.remove();
|
|
3235
|
+
hideJoin();
|
|
2955
3236
|
tearing = null;
|
|
2956
3237
|
if (disposed)
|
|
2957
3238
|
return;
|
|
2958
3239
|
const world = toWorld(last.x, last.y);
|
|
2959
3240
|
const home = worldInsideGroup(from, world.x, world.y);
|
|
3241
|
+
if (commit && home && homeIndex !== null) {
|
|
3242
|
+
// REORDER along its own strip.
|
|
3243
|
+
leg.abort();
|
|
3244
|
+
const cmds = plan.reorder(homeIndex);
|
|
3245
|
+
const changed = cmds.length > 0 ? execute('Reorder tab', cmds) : false;
|
|
3246
|
+
disarmGlideSoon();
|
|
3247
|
+
api.renderNow();
|
|
3248
|
+
(_a = options.onGesture) === null || _a === void 0 ? void 0 : _a.call(options, { type: changed ? 'commit' : 'cancel', kind: 'move', nodeId: pageId, changed });
|
|
3249
|
+
return;
|
|
3250
|
+
}
|
|
3251
|
+
const target = commit && !home ? targetAt(world.x, world.y) : null;
|
|
3252
|
+
if (target) {
|
|
3253
|
+
// JOIN: no cell on this board — the leg is abandoned (its displaced
|
|
3254
|
+
// tiles are already home) and the page becomes the target's tab.
|
|
3255
|
+
const index = plan.dropIndex(target.id, last.x, last.y);
|
|
3256
|
+
leg.abort();
|
|
3257
|
+
const planned = plan.join(target.id, index, group.id);
|
|
3258
|
+
const changed = execute('Move tab', [...planned.move, ...planned.collapse]);
|
|
3259
|
+
disarmGlideSoon();
|
|
3260
|
+
enforceBoardHeight();
|
|
3261
|
+
persistLayouts();
|
|
3262
|
+
api.renderNow();
|
|
3263
|
+
(_b = options.onGesture) === null || _b === void 0 ? void 0 : _b.call(options, { type: 'commit', kind: 'move', nodeId: pageId, changed });
|
|
3264
|
+
return;
|
|
3265
|
+
}
|
|
2960
3266
|
if (!commit || home || !worldInsideBoardGrace(world.x, world.y)) {
|
|
2961
3267
|
leg.abort();
|
|
2962
3268
|
disarmGlideSoon();
|
|
2963
3269
|
api.renderNow();
|
|
2964
|
-
(
|
|
3270
|
+
(_c = options.onGesture) === null || _c === void 0 ? void 0 : _c.call(options, { type: 'cancel', kind: 'move', nodeId: pageId, changed: false });
|
|
2965
3271
|
return;
|
|
2966
3272
|
}
|
|
2967
3273
|
const fin = leg.finalize();
|
|
@@ -2972,15 +3278,13 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2972
3278
|
}
|
|
2973
3279
|
const planned = plan.commands(fin.cell, fin.rect, group.id);
|
|
2974
3280
|
// The container the page left may have been holding its last page: it
|
|
2975
|
-
// goes too
|
|
2976
|
-
|
|
2977
|
-
const collapse = planned.collapse.length > 0 ? [...planRemovalOf(fromGroupId), ...planned.collapse] : [];
|
|
2978
|
-
const changed = execute('Move tab out', [...fin.commands, ...planned.move, ...collapse]);
|
|
3281
|
+
// goes too (the plan carries the removal's settle).
|
|
3282
|
+
const changed = execute('Move tab out', [...fin.commands, ...planned.move, ...planned.collapse]);
|
|
2979
3283
|
disarmGlideSoon();
|
|
2980
3284
|
enforceBoardHeight();
|
|
2981
3285
|
persistLayouts();
|
|
2982
3286
|
api.renderNow();
|
|
2983
|
-
(
|
|
3287
|
+
(_d = options.onGesture) === null || _d === void 0 ? void 0 : _d.call(options, { type: 'commit', kind: 'move', nodeId: pageId, changed });
|
|
2984
3288
|
};
|
|
2985
3289
|
const onUp = () => finish(true);
|
|
2986
3290
|
const onCancel = () => finish(false);
|
|
@@ -3023,6 +3327,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
3023
3327
|
spans: { w: Math.max(1, spec.w), h: Math.max(1, spec.h) },
|
|
3024
3328
|
removedFromBoard: true,
|
|
3025
3329
|
leg: null,
|
|
3330
|
+
strip: null,
|
|
3026
3331
|
lastWorld: null,
|
|
3027
3332
|
lastScreen: null,
|
|
3028
3333
|
hostEl: null,
|
|
@@ -3136,7 +3441,15 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
3136
3441
|
return false;
|
|
3137
3442
|
engine.beginGesture();
|
|
3138
3443
|
const snap = snapshotAll();
|
|
3139
|
-
|
|
3444
|
+
// A section is a LOCKED tile; for ITS OWN move it is the one moving.
|
|
3445
|
+
const self = engine.getItem(id);
|
|
3446
|
+
const wasLocked = !!(self === null || self === void 0 ? void 0 : self.locked);
|
|
3447
|
+
if (self && isGroupMember(id))
|
|
3448
|
+
self.locked = false;
|
|
3449
|
+
const ok = op();
|
|
3450
|
+
if (self && isGroupMember(id))
|
|
3451
|
+
self.locked = wasLocked;
|
|
3452
|
+
if (!ok) {
|
|
3140
3453
|
engine.endGesture();
|
|
3141
3454
|
return false;
|
|
3142
3455
|
}
|