mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-10 01:09:43 +02:00
Merge #432: pop a session, a file preview or a web tab out into a native wrapper's own window
# Conflicts: # src/web/public/app.js # src/web/public/settings-ui.js
This commit is contained in:
+57
-2
@@ -1164,6 +1164,8 @@ class CodemanApp {
|
||||
this._selectUrlSession();
|
||||
});
|
||||
}
|
||||
// mobile.css keeps the pop-out icon off phones unless a host can open windows.
|
||||
document.documentElement.classList.toggle('host-windows', this.hasHostWindows());
|
||||
// Initialize mobile handlers
|
||||
KeyboardHandler.init();
|
||||
SwipeHandler.init();
|
||||
@@ -1667,6 +1669,21 @@ class CodemanApp {
|
||||
// false only when we owned a now-closed window (re-dock + fall through to
|
||||
// genuinely re-open below).
|
||||
if (this.detachedSessions.has(id) && this._raiseDetached(id)) return;
|
||||
// A native wrapper (an Android WebView app) has no browser pop-ups, but can
|
||||
// open the solo URL in a window of its own, beside this one on a foldable or
|
||||
// a split screen. There is no WindowProxy to poll, so the tab is tracked the
|
||||
// way a dashboard reload tracks it: the solo window's channel announcements
|
||||
// plus the roll-call liveness check.
|
||||
const hosted = this.openInHostWindow(CodemanBase.url('/session/' + encodeURIComponent(id)));
|
||||
if (hosted !== null) {
|
||||
if (!hosted) {
|
||||
this.showToast?.('Could not open a new window for this session', 'error');
|
||||
return;
|
||||
}
|
||||
this._markDetached(id, true);
|
||||
this._postWindowMessage({ type: 'detached', id });
|
||||
return;
|
||||
}
|
||||
const features = 'width=960,height=680,menubar=no,toolbar=no,location=no,status=no';
|
||||
let win = null;
|
||||
try { win = window.open(CodemanBase.url('/session/' + encodeURIComponent(id)), 'codeman-session-' + id, features); } catch {}
|
||||
@@ -1681,6 +1698,32 @@ class CodemanApp {
|
||||
try { win.focus(); } catch {}
|
||||
}
|
||||
|
||||
/**
|
||||
* The embedding app's window opener, when there is one. A native wrapper
|
||||
* exposes `window.CodemanHost.openWindow(absoluteUrl)` (returning whether a
|
||||
* window opened) to say it can put a page in a window of its own; browsers
|
||||
* never define it.
|
||||
* @returns {boolean} whether a host window opener is present
|
||||
*/
|
||||
hasHostWindows() {
|
||||
try {
|
||||
return typeof window !== 'undefined' && typeof window.CodemanHost?.openWindow === 'function';
|
||||
} catch { return false; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a same-origin page in a host window.
|
||||
* @param {string} url absolute or base-relative URL
|
||||
* @returns {boolean|null} null when there is no host (use window.open),
|
||||
* otherwise whether the host opened a window
|
||||
*/
|
||||
openInHostWindow(url) {
|
||||
if (!this.hasHostWindows()) return null;
|
||||
try {
|
||||
return window.CodemanHost.openWindow(new URL(url, location.href).href) !== false;
|
||||
} catch { return false; }
|
||||
}
|
||||
|
||||
/** Raise the popup for an already-detached session. Returns true if the raise
|
||||
* was handled (caller should stop); false if we owned a now-closed window and
|
||||
* re-docked it (caller should fall through to inline / re-open). Unifies the
|
||||
@@ -1810,8 +1853,12 @@ class CodemanApp {
|
||||
// Roll-call has no id (broadcast to all) — answer before the id filter.
|
||||
if (msg.type === 'roll-call') { this._postWindowMessage({ type: 'detached', id: this.soloSessionId }); return; }
|
||||
if (msg.id !== this.soloSessionId) return;
|
||||
if (msg.type === 'close-request') { try { window.close(); } catch {} }
|
||||
else if (msg.type === 'focus-request') { try { window.focus(); } catch {} }
|
||||
// A host window ignores window.close()/focus() from script it did not
|
||||
// open by window.open, so ask the host when it offers the call.
|
||||
if (msg.type === 'close-request') { this._closeSoloWindow(); }
|
||||
else if (msg.type === 'focus-request') {
|
||||
try { if (typeof window.CodemanHost?.focusWindow === 'function') window.CodemanHost.focusWindow(); else window.focus(); } catch {}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Dashboard side.
|
||||
@@ -1863,6 +1910,14 @@ class CodemanApp {
|
||||
}, 1200);
|
||||
}
|
||||
|
||||
/** Solo window: close itself (the re-dock button and a dashboard close-request). */
|
||||
_closeSoloWindow() {
|
||||
try {
|
||||
if (typeof window.CodemanHost?.closeWindow === 'function') window.CodemanHost.closeWindow();
|
||||
else window.close();
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/** Solo window: select the target session and apply minimal single-session
|
||||
* chrome. Called from handleInit once the session list has loaded. */
|
||||
_applySoloMode() {
|
||||
|
||||
Reference in New Issue
Block a user