openvibers/openvibe.shared Commits
Dock: keep "in a window" to the page (#202)
Changes
@@@ -6,6 +6,11 @@ A release is the git tag `vX.Y.Z`; consumers pin the tag's tarball (see README).## Unreleased++- **The Dock keeps "in a window" to the page.** The pop-out window belongs to one page in one browser, closes with it,++ and no other device can open it again (the browser wants a click), so the Dock no longer sends `popped` to the++ Network. That also ends the refused PUT and its retry that 4.54.0 made on every pop-out, since the Network's++ `network.dock-state@1` contract has no such key.++## 4.54.0 — 2026-10-30- **The Dock pops out into a window of its own** (Dock plan K-D4). On a desktop browser that can (Chromium's Document@@@ -78,13 +78,7 @@const body = pending; pending = {};if (!Object.keys(body).length) return;try {-- let r = await call('/api/v1/me/dock', { method: 'PUT', body: JSON.stringify(body) });-- // A Network whose state contract does not know "popped" yet refuses the whole body; ask again without it,-- // so the Dock's place and its tab still reach the Network.-- if (!r && 'popped' in body) {-- const rest = { ...body }; delete rest.popped;-- r = await call('/api/v1/me/dock', { method: 'PUT', body: JSON.stringify(rest) });-- }++ const r = await call('/api/v1/me/dock', { method: 'PUT', body: JSON.stringify(body) });if (r && r.state && !Object.keys(pending).length) { doc = { ...doc, state: r.state, counts: r.counts || counts() }; notify(); badges(); }} catch { /* offline, or no route yet: the copy stands and the next change tries again */ }}@@@ -725,7 +719,9 @@win.document.body.appendChild(el);win.addEventListener('pagehide', () => { if (popped && !pipClosing) backToPage(); });paintPop();-- save({ open: true, popped: true });++ // Whether the Dock is in a window stays with this page: the window belongs to one page in one browser, closes++ // with it, and no other device could open it again (the browser wants a click), so the Network is not told.++ save({ open: true });paintPill();}@@@ -741,7 +737,6 @@el.hidden = false;layout();paintPop();-- save({ popped: false });paintPill();}@@@ -777,7 +772,7 @@document.documentElement.classList.remove('ovdk-sheet-open');clear(0);clearTimeout(chats.timer); clearTimeout(chats.unreadT);-- save(wasPopped ? { open: false, popped: false } : { open: false });++ save({ open: false });if (inside) {const back = pill && !pill.hidden ? pill : (lastFocus && lastFocus.isConnected ? lastFocus : null);try { if (back) back.focus({ preventScroll: true }); } catch { /* */ }@@@ -304,13 +304,14 @@ async function drag(p, from, to) {const inWindow = await until(p, PILL, 'the pill stays');assert.strictEqual(inWindow.text, 'In a window', 'the page keeps the pill, and it says where the Dock went');await wait(900);-- assert.ok(puts.some((b) => b.popped === true && b.open === true), `the Network is told the Dock is in a window (${JSON.stringify(puts)})`);++ assert.ok(puts.some((b) => b.open === true), `the Network is told the Dock is open (${JSON.stringify(puts)})`);++ assert.ok(!puts.some((b) => 'popped' in b), `and never where its window is: that stays with this page (${JSON.stringify(puts)})`);// The window is closed: the panel comes back to the page.await p.evaluate("window.__pip.close()");await until(p, "!!document.querySelector('.ovdk')", 'the panel back on the page');assert.strictEqual(await p.evaluate("!!window.__pip.win.document.querySelector('.ovdk')"), false, 'and out of the window');await wait(900);-- assert.ok(puts.some((b) => b.popped === false), `and told it is back (${JSON.stringify(puts)})`);++ assert.ok(!puts.some((b) => 'popped' in b), `nor that it is back (${JSON.stringify(puts)})`);await p.close();}
@@ -6,6 +6,11 @@ A release is the git tag `vX.Y.Z`; consumers pin the tag's tarball (see README).
@@ -6,6 +6,11 @@ A release is the git tag `vX.Y.Z`; consumers pin the tag's tarball (see README).
## Unreleased
## Unreleased
+- **The Dock keeps "in a window" to the page.** The pop-out window belongs to one page in one browser, closes with it,
+ and no other device can open it again (the browser wants a click), so the Dock no longer sends `popped` to the
+ Network. That also ends the refused PUT and its retry that 4.54.0 made on every pop-out, since the Network's
+ `network.dock-state@1` contract has no such key.
+
## 4.54.0 — 2026-10-30
## 4.54.0 — 2026-10-30
- **The Dock pops out into a window of its own** (Dock plan K-D4). On a desktop browser that can (Chromium's Document
- **The Dock pops out into a window of its own** (Dock plan K-D4). On a desktop browser that can (Chromium's Document
@@ -78,13 +78,7 @@
@@ -78,13 +78,7 @@
const body = pending; pending = {};
const body = pending; pending = {};
if (!Object.keys(body).length) return;
if (!Object.keys(body).length) return;
try {
try {
- let r = await call('/api/v1/me/dock', { method: 'PUT', body: JSON.stringify(body) });
- // A Network whose state contract does not know "popped" yet refuses the whole body; ask again without it,
- // so the Dock's place and its tab still reach the Network.
- if (!r && 'popped' in body) {
- const rest = { ...body }; delete rest.popped;
- r = await call('/api/v1/me/dock', { method: 'PUT', body: JSON.stringify(rest) });
- }
+ const r = await call('/api/v1/me/dock', { method: 'PUT', body: JSON.stringify(body) });
if (r && r.state && !Object.keys(pending).length) { doc = { ...doc, state: r.state, counts: r.counts || counts() }; notify(); badges(); }
if (r && r.state && !Object.keys(pending).length) { doc = { ...doc, state: r.state, counts: r.counts || counts() }; notify(); badges(); }
} catch { /* offline, or no route yet: the copy stands and the next change tries again */ }
} catch { /* offline, or no route yet: the copy stands and the next change tries again */ }
}
}
@@ -725,7 +719,9 @@
@@ -725,7 +719,9 @@
win.document.body.appendChild(el);
win.document.body.appendChild(el);
win.addEventListener('pagehide', () => { if (popped && !pipClosing) backToPage(); });
win.addEventListener('pagehide', () => { if (popped && !pipClosing) backToPage(); });
paintPop();
paintPop();
- save({ open: true, popped: true });
+ // Whether the Dock is in a window stays with this page: the window belongs to one page in one browser, closes
+ // with it, and no other device could open it again (the browser wants a click), so the Network is not told.
+ save({ open: true });
paintPill();
paintPill();
}
}
@@ -741,7 +737,6 @@
@@ -741,7 +737,6 @@
el.hidden = false;
el.hidden = false;
layout();
layout();
paintPop();
paintPop();
- save({ popped: false });
paintPill();
paintPill();
}
}
@@ -777,7 +772,7 @@
@@ -777,7 +772,7 @@
document.documentElement.classList.remove('ovdk-sheet-open');
document.documentElement.classList.remove('ovdk-sheet-open');
clear(0);
clear(0);
clearTimeout(chats.timer); clearTimeout(chats.unreadT);
clearTimeout(chats.timer); clearTimeout(chats.unreadT);
- save(wasPopped ? { open: false, popped: false } : { open: false });
+ save({ open: false });
if (inside) {
if (inside) {
const back = pill && !pill.hidden ? pill : (lastFocus && lastFocus.isConnected ? lastFocus : null);
const back = pill && !pill.hidden ? pill : (lastFocus && lastFocus.isConnected ? lastFocus : null);
try { if (back) back.focus({ preventScroll: true }); } catch { /* */ }
try { if (back) back.focus({ preventScroll: true }); } catch { /* */ }
@@ -304,13 +304,14 @@ async function drag(p, from, to) {
@@ -304,13 +304,14 @@ async function drag(p, from, to) {
const inWindow = await until(p, PILL, 'the pill stays');
const inWindow = await until(p, PILL, 'the pill stays');
assert.strictEqual(inWindow.text, 'In a window', 'the page keeps the pill, and it says where the Dock went');
assert.strictEqual(inWindow.text, 'In a window', 'the page keeps the pill, and it says where the Dock went');
await wait(900);
await wait(900);
- assert.ok(puts.some((b) => b.popped === true && b.open === true), `the Network is told the Dock is in a window (${JSON.stringify(puts)})`);
+ assert.ok(puts.some((b) => b.open === true), `the Network is told the Dock is open (${JSON.stringify(puts)})`);
+ assert.ok(!puts.some((b) => 'popped' in b), `and never where its window is: that stays with this page (${JSON.stringify(puts)})`);
// The window is closed: the panel comes back to the page.
// The window is closed: the panel comes back to the page.
await p.evaluate("window.__pip.close()");
await p.evaluate("window.__pip.close()");
await until(p, "!!document.querySelector('.ovdk')", 'the panel back on the page');
await until(p, "!!document.querySelector('.ovdk')", 'the panel back on the page');
assert.strictEqual(await p.evaluate("!!window.__pip.win.document.querySelector('.ovdk')"), false, 'and out of the window');
assert.strictEqual(await p.evaluate("!!window.__pip.win.document.querySelector('.ovdk')"), false, 'and out of the window');
await wait(900);
await wait(900);
- assert.ok(puts.some((b) => b.popped === false), `and told it is back (${JSON.stringify(puts)})`);
+ assert.ok(!puts.some((b) => 'popped' in b), `nor that it is back (${JSON.stringify(puts)})`);
await p.close();
await p.close();
}
}