Dec 8: Squire: FastMail's rich text editor

Post categories

Profile picture for Neil Jenkins

Chief Product Officer

This blog post is part of the FastMail 2014 Advent Calendar.

The previous post on 7th December was about automated installation. The following post on 9th December is on email authentication.

Technical level: low-medium.

We’re going to take a break from talking about our backend infrastructure in this post and switch over to discussing our webmail.

In the beginning, there was text. And really, it was pretty good. You could *emphasise* things, SHOUT AT PEOPLE, and generally convey the nuance of what you had to say. But then came HTML email. Now you could make big bold statements, or small
interesting asides. Your paragraphs were no longer hard-wrapped, but instead flowed according to the size of your screen. Despite some grumblings from a dedicated band of luddites (including a few of the FastMail team :-)), most people decided that this was, in fact, better.

To support rich text editing in our previous interface, we used CKEditor. While not a bad choice, like most other editors out there it was designed for creating websites, not writing emails. As such, simply inserting an image by default presented a dialog with three tabs and more options than you could believe possible. Meanwhile, support for quoting, crucial in email, was severely limited. It also came with its own UI toolkit and framework, which we would have had to heavily customise to fit in with the rest of the new UI we were building; a pain to maintain.

With our focus on speed and performance, we were also concerned about the code size. The version of CKEditor we use for our previous (classic) UI, which only includes the plugins we need, is a 159 KB download (when gzipped; uncompressed it’s 441 KB). That’s just the code, excluding styles and images. To put this in perspective, in the current interface the combined code weight required to load the whole compose screen, including our awesome base library (more on that in a future post…), the mail/contacts model code and all the UI code to render the entire screen comes to only 149.4 KB (459.7 KB uncompressed).

After considering various options, we therefore decided to strike out on our own and wrote Squire.

Making a rich text editor is notoriously difficult due to the fact that different browsers are extremely inconsistent in this area. The APIs were all introduced by Microsoft back in the IE heyday, and were then copied by the other vendors in various incompatible ways. The result of applying document.execCommand to simply bold the selected text is likely to be different in every browser you try.

To deal with this, most rich text editors execute a command, then try to clean up the mess the browser created. With Squire, we neatly bypass this by simply not using the browser’s built-in commands. Instead, we manipulate the DOM directly, only using the selection and range APIs. This turns out to be easier and require less code than letting the browser do any of the work!

For example, to bold some text, we use the following simple algorithm (actually, this more generally applies to any inline style, such as setting a font or colour too):

  1. Iterate through the text nodes in the DOM that are part of the
    current selection.
  2. For each text node, check if it’s already got a parent <b> tag. If
    it does, there’s nothing to do. If not, create a new <b> element
    and wrap the text node in it. If the text node was only partially in
    the selection, split it first so only the selected part gets
    wrapped.

I’d like to give a quick shout out to the under-appreciated TreeWalker API for iterating through the DOM. True story: when first developing Squire, I came across a bug in Opera’s TreeWalker implementation. The first comment on my report from the Presto developer team (this was pre-WebKit days at Opera) was, and I quote verbatim, “First TreeWalker bug ever. First TreeWalker usage ever? :)”. Sadly, due to the lack of common use, other browsers have also had the occasional bug with this API too, so to be on the safe side I just reimplemented the bits of the API I needed in JavaScript. The idea is sound though.

Squire also completely takes over certain keys that are handled badly by default, such as enter and delete. This lets us get a consistent result, and allows us to add the features we want, such as breaking nested quotes if you hit enter on a blank line. And of course we’ve added our own keyboard shortcuts too for actions like changing quote level or starting a bullet list.

At only 11.5 KB of JavaScript after minification and gzip (34.7 KB uncompressed) and with no dependencies, Squire is extremely lightweight. If you’re building your own webmail client, or something else that needs to be able to edit rich text, give it a go! Squire is MIT licensed and available on GitHub.

Profile picture for Neil Jenkins

Chief Product Officer