Laverna Webclipper, the story of a WebExtension
Yesterday I’ve spent my afternoon on a very small side-project related to Laverna.
Laverna is an offline-first, no-backend Web application that allows you to write notes directly from your browser, classify them in notebooks, with a live-preview Markdown editor and a powerful yet simple tagging system. Besides being offline-first, it also allows you to sync between different devices, using Dropbox as a backend or your own instance of a RemoteStorage server. All of this makes it a powerful free and open-source alternative to software like Evernote or even Microsoft OneNote.
A WebClipper for Laverna
There was already an official webclipper, but when I’ve tried it, it didn’t work. Looking at the code and the last commit date, it seemed a bit deprecated; so I made my own that uses WebExtensions (since I really wanted to learn a bit more about these), that you can find here on Github.
The idea behind a web clipper is very simple: you go on a Web page that contains some interesting content and you would like to keep it for later (for example, to read it later, or to keep it as reference). So the addon introduces a new click button in the browser bar that opens a new Laverna tab and prefills the field with the parsed content, one-click away from being saved. This is useful because some read-it-later services can’t have access to content behind paid-walls, for instance.
If you’re interested in getting this addon, you can go on the official addons for Firefox website (as of the day of this writing, the addon has not been validated yet).
The Implementation
This project is using Readability.js for retrieving the “interesting content” of a page, and then renders it to Markdown (since Laverna uses this format) thanks to html.md. The rest is plumbing :)
WebExtensions are a new safe and portable way to write addons for Web browsers. Heavily inspired from Chrome’s Addons APIs, the main thrust is that WebExtensions should Just Work© on any Web browser supporting them (any Chromium-based, Edge and Firefox, as of today).
This is fantastic news! … when all the browsers will support it. As of today, this addon will only work on Firefox, and here is why.
First, programming a WebExtension is hard. I mean really hard; debugging
it may quickly become a nightmare, because debug messages can appear in the
developer console (for the content script, which is the “client” part of your
addon), or in a specific addon debugger console (for background scripts), or
even in the stdout
logs of your browser. Some issues, like parsing errors in
your JavaScript files, may be really hard to find in this context.
Second, at some point in the addon’s workflow, you need to inject the Markdown
content into the Laverna’s text editor. Laverna uses
CodeMirror for their rich text editor, so dumping the
content is not just as simple as setting the value
property of the target
textarea
. You need to retrieve the CodeMirror instance somehow and call one of its
methods. The instance is fortunately saved in the
.CodeMirror
property of the textarea, so you could retrieve it, if you really
were on the client page. But browsers don’t
allow
that,
unless modifying the observed page itself, which I didn’t know about when writing this addon.
That being said, Firefox gives you a (hacky) way to do so (through
wrappedJSObject
), so you can indeed access the original JS DOM object of the
observed page and retrieve the CodeMirror instance, then call its setValue
method. Pfew! Chrome doesn’t have this hack, which is merely the reason why it
doesn’t work there.
Unrelated to these issues: whenever one clicks on the clipper button, the page is parsed, which has the unfortunate side-effect of clearing the parsed content (that’s how Readability works). One can clone the entire DOM to prevent this issue, but this API is not (yet?) available in WebExtensions, at least under Firefox. To work around this, the page is reloaded in the background after you’ve clicked the button. Filthy, right?
Get in touch!
If you have any remarks or suggestions, don’t hesitate to ping me on twitter or diaspora; I love any kind of feedback, since this is usually the only way to get better and understand what matters. If you’re interested in contributing to this addon, let’s get in touch!