What is Quink?
It allows developers to add rich input and self-edited areas into web pages and web apps.
You can find it on www.quink.mobi and github.
Why did it get built?
The trigger was that I could not find a good solution for editing rich content on mobile, specifically on the iPad platform – at least not one that hit all the key points I was aiming for. We (IMD Business School) have had an iPad app in production for supporting our course participants since June 2010, and I wanted to move beyond plain text annotations on PDFs, notes and plain text discussion forums with file attachments. I wanted participants in our courses to be able to create richer content for themselves, for sharing with fellow participants, and for feedback to and from the professors.
Once started down that road, there are a host of decisions to make, top of the list being:
- data / file format
- editing capabilities
- separate app or in-app component
- openness to variety of use cases, or focus on a tight scope
There is more detail on these points below, but after initial consideration, I was looking for
- an HTML editor that works within the browser
- with a good UI/UX for basic rich text editing,
- that could be embedded in our app, and
- which had a good API and plug-in architecture to allow great flexibility.
So I started looking for solutions. While there are many things that fulfill some of the requirements, I simply could not find one that would work well on the iPad, the primary target. In the end it seemed to come down to a choice between doing significant work on somebody else’s architecture, all of which were designed for the desktop browser, or starting from scratch and focusing primarily on the mobile environment and our own needs. Even that decision is not a no-brainer. But the end result was that we followed the path that led to Quink.
I won’t go into all the alternatives considered here, but for me the decisions were reasonably clear:
Data format: HTML
For me, HTML is the only rational solution for the base format. It is the most versatile and widely used document format, has a really excellent track record of backward compatibility, and is free of proprietary control. If it seems a little strange, I guess that is just because people don’t think of it as a document format in the same category as pdf, word docs, and so on. The only thing it is really tricky to do is precise and locked-down control of presentation and layout. But in the multi-device world, I see that less as a critical feature than as a lurking problem. I would argue that the natural tendency of HTML to flow is more valuable, though more difficult to work with.
Separate app or in-app component.
The easy option would be to break out into specialist apps / editors. That makes extensibility simple, but it provides a really horrible user experience for many use cases and is simply unusable for some core requirements. Using 3rd party apps also creates all kinds of problems about cross-platform requirements, compatibility, and data management. For something as core as document creation and viewing, we needed something we could build into our app and our web portals, and be sure it would just work.
The minimum requirement was easy creation of ‘rich text’: some basic formatting for headings, lists, emphasis. The ability to include images. That’s really the core requirement, and covers 80% of immediate uses. But there is always the remaining 20%…
Tight focus or broad applicability
Beyond the basic capabilities, I knew from the start that there are a million things that will be required at some point: tables, graphs, vector graphics, video, audio, and just about anything you can imagine. When each of these will become important or critical is unknown – so the key requirement is to have something that is extensible in response to new demands and use cases. HTML and the web stack provide a good framework for allowing this, and for using components developed by others – both proprietary or open source. So our goal was to create an architecture where we could employ specialist content editors developed by others, out of the box. I always strive to create architectures that put as few limits as possible on the future without incurring unreasonable current costs – and I think we have achieved that.
Design – What is special?
Content divs and tagging
Probably the most significant thing about Quink is the approach to extensibility and plugins. The idea is that a page is made up of units, for each of which you may need a specialist editor. Quink exploits the HTML structure where a page is made up of a set of divs and elements. Divs provide clean boundaries for content. Some divs may be tagged to identify the editor functionality that is appropriate for editing them. If the user wishes to edit such tagged content, then the specialist editor is loaded, passed the content that it needs to edit, and the Quink core steps back to let it do its job. When it is finished, the modified content is updated in the HTML.
The base implementation of this was designed to allow the use of editors that have no knowledge of Quink. There are very, very few requirements that an editor must satisfy to allow it to be used as a plugin, and the system uses adapters so that the requirements on the underlying component are functional capabilities, not any specific API. To be eligible as a plugin, some editor need only:
- Be loadable in a web page
- To have some method of delivering the edited content to the Quink core so that it can be dropped into a page – ie renderable HTML.
- In order to be re-editable, it also needs a means of having the HTML sent to it.
Being loadable includes being hosted on different servers. Quink defaults to opening plugins in iFrames, and only loading them when asked for by the user. They don’t have to be part of the root site, so you dont actually need access to source, or to own the editor component. Of course, when setting up a plugin you should trust the provider and code enough to give them access to an iframe in your page!
The mechanisms for transferring the data can include all kinds of back-end tricks if needed, though we haven’t gone down that road ourselves yet. Quink supplies the user with a button to save and exit, or simply quit the plugin – which calls a function on to the plugin’s adapter, so the plugin editor itself does not need to know it is operating inside Quink or to emit any events.
If an editor is not capable of re-editing existing content it will not break anything either, though of course it may not meet user expectations.
Adding Quink to a page & configuration
Quink bootstraps from a small script which exists mainly to set up the urls to load from and kick Require.js into action. The default bootstrap script will do the job for most installations; the target page then only needs to have a one-line inclusion of the bootstrap script, and to declare one or more divs to be contenteditable; Quink is enabled as the editor for all of them by default.
Various aspects of Quink are easily configurable. A configuration can be set up by adjusting JSON files: the plugins, toolbars, and the keymap for keyboard-driven edit functions. One of the items on the roadmap is to allow these configuration structures to be cleanly manipulated after loading.
There are also a number of things which we have found it useful to allow Quink to pull from the page query parameters: the autosave frequency and destination, the destination for an explicit POST of the content as an alternate save mechanism, whether the toolbar should pop up on page load. This approach allows referring links to change aspects of the configuration which turn out to change more frequently than it is practical to change code, and seems to be a useful pattern. In future I think this will be extended and also made more generic – and capable of being disabled.
One of the other things which is a little unusual in WYSIWYG HTML editors, that we have included in Quink is keyboard commands. This was also driven by frustration as fairly heavy iOS users with the touch-based cursor positioning and selection. In my view this is one area where the Android UI is just miles better; but even then, trying to position the cursor and select text to replace, delete or format is slow and relatively tricky, because fine positioning is just inherently more difficult with a touch interface than with a mouse – and I am speaking as someone who has quite steady hands. From my past in mobile surveying and mapping, I know that quite a high percentage of the population have really quite shaky hands and find fine positioning on touch screens REALLY hard.
So we added an approach to allowing keyboard commands: the minimal target was simply keyboard-based navigation and selection, but the architecture delivered the ability to map a key sequence to any of the toolbar or internal commands. Because of the limitations of on-screen keyboards, we had to deliver this without control keys, and the best solution seemed to be to use a standard QWERTY key in some way. Following that line led pretty inevitably to requiring a command mode and an insert mode like Vi. This is really deeply ironic since I grew up as an emacs fan, and avoided Vi as much as I could, and now found myself forced to implement and learn vi-like sequences to achieve what I wanted.
Where we have ended up is with two ‘q’ keys in quick succession to enter command mode, and a single ‘q’ to return to normal, or ‘insert’ mode. The default map is not the same as vi, because of course many commands are more about formatting than rapid editing of plain text, but diehards can adjust to suit their tastes! To handle the limited set of keys, it is possible to set up command groups with ‘prefix’ keys, so for example we use ‘f’ for font formatting, so ‘fb’ means ‘format:toggle-bold’ and ‘fbi’ means ‘format:(toggle-bold, toggle-italic)’.
I have a long list of to-do’s.
Some should be relatively simple, such as adding a few more plug-ins; I particularly fancy the image editor Muro, not only because it seems really good, but because it is a hosted component that has the required functions, so it is also an interesting test case for the plugin architecture. After that, the next class of plugin to work on is grid/table support.
Good support of Android devices is certainly high on the list.
After that, there is some significant work to be done on div and css style management. Right now, Quink just exposes the browser behaviour for these areas, which is limited and often rather flaky. In principle this is all do-able, but doing it well with a clean architecture is an interesting challenge.
We have some other cool ideas, but they are in a phase of stealth mode experimentation just now.
We have released Quink under the Gnu Lesser GPL. The aim is to find a good balance between maximising the usefulness and user base around Quink (by being relatively liberal), and to get help and input from the community on improvements. Our current understanding of the lesser GPL with regard to Quink is that it allows people to use Quink in their apps and sites, or write add-ons and plugins without being obliged to open source everything – thereby maximising its usefulness. However, if there are bug fixes or compatibility fixes that people find and make to the core, it is the least they can do to publish them. It would be great if people become proactive and contribute/publish plugins, plugin adapters or other significant enhancements, but that is entirely voluntary.
Prior to joining IMD in 2008, Iain has worked in a variety of industries, but always at the forefront of technology development and disruptive change. In the early 90s, Iain co-founded a software start-up focused on mobile pen computing and geospatial solutions. The solution that he created enabled Ordnance Survey to be the world’s first mapping agency to use a 100% digital map collection and production system, and helped revolutionise the industry of creating and consuming geographic information.