Monday, April 12, 2021

Bookmarklets for Sharing

Android has Share intents, which are a way to send a string, frequently a URL, to another program.

The receiving program can even be a PWA. This means it is fairly easy to write a new target to share on Android, such as a note-taking website or a link aggregator.

On a desktop browser, the standard tools are less easy. There's no simple share command. Many apps, such as Pocket and Google Keep, implement this functionality with a browser extension. Browser extensions are much more involved to write than PWAs, and I find the buttons to activate extensions inconvenient to manage. In addition, you have to write a different extension for every browser you want to support.

I found a much better solution for my purposes: bookmarklets.

Bookmarklets are bookmarks that, instead of constaining a URL, have a snippet of JavaScript. When clicked, the bookmark's JavaScript executes in the current page.

Obviously, this has all the danger of running custom JavaScript on any page. Never run any you don't trust: it can trivially steal your cookies and other authentication, or perform any action you could on the page.

That being said, creating one yourself is very simple. You create a new bookmark (the "Add Page" option in Chrome), give it the title you want, and then write the JavaScript to execute, preceded by javascript:. The most inconvenient thing is that it all has to be on one line, so it's usually worth working the details out elsewhere, removing the newlines, and copying it in.

I have found two bookmarklets to be useful (the comment header is required by my employer, however, you will not be able to copy it into your bookmarklets).

Background Send

// Copyright 2021 Google LLC.
// SPDX-License-Identifier: Apache-2.0
javascript:const _u = new URL("https://example.com/save.cgi"); _u.searchParams.set("url", location.href); fetch(_u, {mode: "no-cors"});
This bookmarklet sends the current URL to a server for processing. I use this for link aggregators where the only relevant information is the URL itself. It uses the new fetch() API to send a GET request (it uses no-cors mode because the whole point is that the destination is a different server).

The server that receives the message just expects a URL in a GET parameter and handles it. Since no special page is seen by the user, this is most akin to the very lightweight share intents in Android like Pocket has, which do not interrupt the current screen.

Because this is GET, no real authentication is possible, so for a real use I would probably require HTTPS and include a unique key in another GET parameter that needs to match. This means it shouldn't be run on an untrusted browser, but that's already true for bookmarklets.

Sharing Window

// Copyright 2021 Google LLC.
// SPDX-License-Identifier: Apache-2.0
javascript:const _u = new URL("https://example.com/share.html"); _u.searchParams.set("text", location.href); const _a = document.createElement("a"); _a.setAttribute("target", "_blank"); _a.setAttribute("href", _u.toString()); _a.click()
The second useful bookmarklet creates an <a> tag, target=_blank, with an HREF that includes the current URL in a GET parameter, then clicks the link. This means that clicking the bookmarklet opens a new page with data that includes the previous page's URL. This is exactly like the experience of most Android apps when you share to them, in which selecting share takes you to a new page that you can use to make some choices on the data you included.

In fact, I was able to use this second form of bookmarklet to work with the exact same URL I had already written for share intents in a PWA.

Usage

To conserve space on my bookmarks bar, I'm giving these short names, just a character or two, or even an emoji (inspired by this article about using favicons alone for bookmark names, but bookmarklets don't support favicons.)

For the moment I am putting these directly on my bookmarks bar. If I make enough that even with short names I start to run out of space, I will probably put them all into a single folder, possibly named "Share". This will mimic the Android share button that when pressed reveals a list of possible applications (but will load much faster).

I hope this is useful for someone else!

Postscript

I discovered Use Bookmarklets on Chrome on Android, which points out that you can invoke bookmarklets by name if you are using Chrome and synced it to an Android device. I'm not sure whether this works for other mobile browsers, or for Chrome on iOS, and the original purpose here was to supplement a desktop computer with a mobile-inspired feature, but there might be some cool combinations possible with this.