home / tils / til

Menu
  • GraphQL API

til: electron_electron-external-links-system-browser.md

This data as json

path topic title url body html shot created created_utc updated updated_utc shot_hash slug
electron_electron-external-links-system-browser.md electron Open external links in an Electron app using the system browser https://github.com/simonw/til/blob/main/electron/electron-external-links-system-browser.md For [Datasette.app](https://github.com/simonw/datasette-app) I wanted to ensure that links to external URLs would [open in the system browser](https://github.com/simonw/datasette-app/issues/34). This recipe works: ```javascript function postConfigure(window) { window.webContents.on("will-navigate", function (event, reqUrl) { let requestedHost = new URL(reqUrl).host; let currentHost = new URL(window.webContents.getURL()).host; if (requestedHost && requestedHost != currentHost) { event.preventDefault(); shell.openExternal(reqUrl); } }); } ``` The `will-navigate` event fires before any in-browser navigations, which means they can be intercepted and cancelled if necessary. I use the `URL()` class to extract the `.host` so I can check if the host being navigated to differs from the host that the application is running against (which is probably `localhost:$port`). Initially I was using `require('url').URL` for this but that doesn't appear to be necessary - Node.js ships with `URL` as a top-level class these days. `event.preventDefault()` cancels the navigation and `shell.openExternal(reqUrl)` opens the URL using the system default browsner. I call this function on any new window I create using `new BrowserWindow` - for example: ```javascript mainWindow = new BrowserWindow({ width: 800, height: 600, show: false, }); mainWindow.loadFile("loading.html"); mainWindow.once("ready-to-show", () => { mainWindow.show(); }); postConfigure(mainWindow); ``` <p>For <a href="https://github.com/simonw/datasette-app">Datasette.app</a> I wanted to ensure that links to external URLs would <a href="https://github.com/simonw/datasette-app/issues/34">open in the system browser</a>.</p> <p>This recipe works:</p> <div class="highlight highlight-source-js"><pre><span class="pl-k">function</span> <span class="pl-en">postConfigure</span><span class="pl-kos">(</span><span class="pl-s1">window</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-s1">window</span><span class="pl-kos">.</span><span class="pl-c1">webContents</span><span class="pl-kos">.</span><span class="pl-en">on</span><span class="pl-kos">(</span><span class="pl-s">"will-navigate"</span><span class="pl-kos">,</span> <span class="pl-k">function</span> <span class="pl-kos">(</span><span class="pl-s1">event</span><span class="pl-kos">,</span> <span class="pl-s1">reqUrl</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">let</span> <span class="pl-s1">requestedHost</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-c1">URL</span><span class="pl-kos">(</span><span class="pl-s1">reqUrl</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-c1">host</span><span class="pl-kos">;</span> <span class="pl-k">let</span> <span class="pl-s1">currentHost</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-c1">URL</span><span class="pl-kos">(</span><span class="pl-s1">window</span><span class="pl-kos">.</span><span class="pl-c1">webContents</span><span class="pl-kos">.</span><span class="pl-en">getURL</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-c1">host</span><span class="pl-kos">;</span> <span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-s1">requestedHost</span> <span class="pl-c1">&amp;&amp;</span> <span class="pl-s1">requestedHost</span> <span class="pl-c1">!=</span> <span class="pl-s1">currentHost</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-s1">event</span><span class="pl-kos">.</span><span class="pl-en">preventDefault</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-s1">shell</span><span class="pl-kos">.</span><span class="pl-en">openExternal</span><span class="pl-kos">(</span><span class="pl-s1">reqUrl</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span></pre></div> <p>The <code>will-navigate</code> event fires before any in-browser navigations, which means they can be intercepted and cancelled if necessary.</p> <p>I use the <code>URL()</code> class to extract the <code>.host</code> so I can check if the host being navigated to differs from the host that the application is running against (which is probably <code>localhost:$port</code>).</p> <p>Initially I was using <code>require('url').URL</code> for this but that doesn't appear to be necessary - Node.js ships with <code>URL</code> as a top-level class these days.</p> <p><code>event.preventDefault()</code> cancels the navigation and <code>shell.openExternal(reqUrl)</code> opens the URL using the system default browsner.</p> <p>I call this function on any new window I create using <code>new BrowserWindow</code> - for example:</p> <div class="highlight highlight-source-js"><pre><span class="pl-s1">mainWindow</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-v">BrowserWindow</span><span class="pl-kos">(</span><span class="pl-kos">{</span> <span class="pl-c1">width</span>: <span class="pl-c1">800</span><span class="pl-kos">,</span> <span class="pl-c1">height</span>: <span class="pl-c1">600</span><span class="pl-kos">,</span> <span class="pl-c1">show</span>: <span class="pl-c1">false</span><span class="pl-kos">,</span> <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-s1">mainWindow</span><span class="pl-kos">.</span><span class="pl-en">loadFile</span><span class="pl-kos">(</span><span class="pl-s">"loading.html"</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-s1">mainWindow</span><span class="pl-kos">.</span><span class="pl-en">once</span><span class="pl-kos">(</span><span class="pl-s">"ready-to-show"</span><span class="pl-kos">,</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span> <span class="pl-s1">mainWindow</span><span class="pl-kos">.</span><span class="pl-en">show</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-en">postConfigure</span><span class="pl-kos">(</span><span class="pl-s1">mainWindow</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div> <Binary: 63,282 bytes> 2021-09-02T14:15:19-07:00 2021-09-02T21:15:19+00:00 2021-09-02T14:15:19-07:00 2021-09-02T21:15:19+00:00 5d14045ddef5563541eefa461db1f283 electron-external-links-system-browser
Powered by Datasette · How this site works · Code of conduct