CI / Typecheck, test, build (pull_request) Successful in 26s
The plain address is the one thing that button must not offer -- followed in the browser the rewrite rules are installed in, it comes straight back here -- so there is nothing to show until there is a browser to hand it to. The copy button and the selectable URL were always the part carrying the weight; the open link now ships hidden and the script reveals it along with the scheme. That also settles what the button should say. It went back to "Open on <platform>": the browser's name was there to explain a tap that went nowhere, and a button that is not shown until it works needs no such explanation. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01KF5YF3iZVKbezwALap8LYd
65 lines
2.8 KiB
JavaScript
65 lines
2.8 KiB
JavaScript
// The rewrite rules that send a shared link here catch the original link on
|
|
// the way back out too, so in Safari "Open on <platform>" lands back on this
|
|
// page. Handing the address to a different browser is the way out, and the
|
|
// only way to do that from a web page is that browser's own URL scheme --
|
|
// which every one of them spells differently. Some swap the scheme, some
|
|
// prefix it, some take the whole address as a query parameter.
|
|
|
|
/** http -> googlechrome://, https -> googlechromes:// */
|
|
const chrome = (url) => url.replace(/^http(s?):/, 'googlechrome$1:');
|
|
|
|
// Edge keeps the original scheme either way, but on macOS it stays in the
|
|
// address and the scheme is prefixed, while on iOS it is folded into the
|
|
// scheme itself.
|
|
const edgeMacos = (url) => `microsoft-edge:${url}`;
|
|
const edgeIos = (url) => url.replace(/^http(s?):/, 'microsoft-edge-http$1:');
|
|
|
|
/** Firefox and Orion take the address as a parameter instead. */
|
|
const openUrl = (scheme) => (url) => `${scheme}://open-url?url=${encodeURIComponent(url)}`;
|
|
|
|
// `null` means the browser is there but ships no scheme to reach it on that
|
|
// system, so there is nothing to offer beyond the plain link.
|
|
export const BROWSERS = [
|
|
{ id: 'default', label: 'Default browser', macos: null, ios: null },
|
|
{ id: 'chrome', label: 'Chrome', macos: chrome, ios: chrome },
|
|
{ id: 'edge', label: 'Edge', macos: edgeMacos, ios: edgeIos },
|
|
{ id: 'firefox', label: 'Firefox', macos: null, ios: openUrl('firefox') },
|
|
{ id: 'orion', label: 'Orion', macos: openUrl('orion'), ios: openUrl('orion') },
|
|
];
|
|
|
|
/**
|
|
* iPadOS calls itself MacIntel, so the platform string alone cannot tell the
|
|
* two apart; the touch points can. Everything else gets the desktop table --
|
|
* the only desktop this is ever opened on is a Mac.
|
|
*
|
|
* @param {{ platform?: string, maxTouchPoints?: number }} [nav]
|
|
*/
|
|
export function detectOs(nav = globalThis.navigator) {
|
|
const platform = nav?.platform ?? '';
|
|
if (/^iP(hone|ad|od)/.test(platform)) return 'ios';
|
|
if (platform === 'MacIntel' && (nav?.maxTouchPoints ?? 0) > 1) return 'ios';
|
|
return 'macos';
|
|
}
|
|
|
|
/** The browsers worth offering here: the default, plus the ones this system
|
|
* actually has a scheme for. */
|
|
export function browsersFor(os) {
|
|
return BROWSERS.filter((browser) => browser.id === 'default' || browser[os]);
|
|
}
|
|
|
|
function browserById(id) {
|
|
return BROWSERS.find((browser) => browser.id === id);
|
|
}
|
|
|
|
/**
|
|
* The address to open. A browser with no scheme on this system, an unknown
|
|
* id, or anything that is not an ordinary web link is handed back untouched:
|
|
* a dead custom scheme opens nothing at all, which is worse than the plain
|
|
* link opening in the wrong browser.
|
|
*/
|
|
export function openUrlFor(url, browserId, os) {
|
|
const rewrite = browserById(browserId)?.[os];
|
|
if (!rewrite || !/^https?:\/\//i.test(url)) return url;
|
|
return rewrite(url);
|
|
}
|