Creating an editable page

K, so, here's the deal:

This is a text, and the idea is that we can put a cursor in here, even if some content has additional markup, whether that's single-level nested or multiple levels down and then just edit content in place with a button bar and/or hotkeys, WYSIWYG style. This relies on the contenteditable HTML attribute, which lets us do a bunch of "where is the caret ("cursor") right now?" checks (in a way that works on both desktop and mobile) so we can then "do stuff" like wrapping text in tags, or removing tags, or changing tags, etc.

And of course, secretly that functionality isn't tied to "these fancy boxes with a border", it works everywhere on this page. You click a thing, it's editable, even if the HTML source code didn't say it was.

But wait: there's more! You can also use ctrl-/ or cmd-/ to toggle a block from being editable HTML to being editable markdown text and back, so you can do your precision edits in markdown, then come back to plain WYSIWYG editing.

Some obvious instructions

I get hotkeys?

Yeah, there's a bunch of ctrl (on linux/windows) or cmd (on mac) key combinations to speed up your writing, just like a regular WYSIWYG editing experience. Just use ctrl/cmd + ...:

Additionally, there are the cosmetic combos:

And then the two special combinations:

What about tables?

Those should work, provided the table is fully specified, i.e. it has a thead with th header cells, as well as a tbody with regular tr rows containing td cells. Note that a thead element is not optional, tables without labels would make no sense, and so aren't allowed in (most flavours of) markdown.

value 2 3 5 7
2 1 0 0 0
3 0 1 0 0
4 2 0 0 0
5 0 0 1 0
6 0 2 0 0
7 0 0 0 1
8 0 1 1 0
9 0 3 0 0
10 0 1 0 1

How does all this work?

Three core concepts: contenteditable, the Selection object, and Ranges. "Content Editable" elements basically let you live-edit your HTML, with the caret and text-selections being tracked by the global Selection object. This lets you fairly easily not just find out where the cursor is at any given time, but also lets you do things like select whatever word the cursor is in, as well as which HTML elements that position is associated with, so that you can do things like "find the cursor, then select the entire word it's in, then wrap that text in <em>".

The only tricky bit is making sure that the cursor ends up in the right place after a change, which is generally a matter of "clearing the selection, building a range, and saying which element and text offset it represents, then making that the new selection". It's quite a powerful API!

Bug! I can't click on links!

True, but that's because the document is currently editable. Remove the contenteditable attribute on the body (or set the JS .contendEditable property to false), and it's a normal page again. Imagine this being an option you can toggle.

(The best part is that its still just HTML so you can just right click or long-press and open the link in a new tab that way)

More bug! I can't hot key to the URL bar!

Yeah, kind of a consequence of ctrl/cmd-L being the hotkey for links. Because going to the URL bar while you're editing a document makes no sense, "what's a URL? We're document editing". If you have to change the URL in the browser, for as long as this is an in-browser PoC, just click/tap the URL bar. Once this gets wrapped up as an electron-or-similar application, There won't even be a URL bar, so don't worry: not a bug.

What's left?

There's a bunch of "this probably doesn't need to be in a PoC" like full blown Markdown to HTML and HTML to Markdown converters (they're hilariously simplistic at the moment!), but there's a few things that should probably still be added before this is a complete enough PoC:

I have ideas

I expected as much. https://github.com/Pomax/editable-document-poc/issues is ready for you to post any ideation you have.

Pomax, 05/25