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
- clicking places the cursor
- arrow keys move the cursor
- typing (unsurprisingly) inserts text
- backspace removes to the left of the cursor
- delete removes to the right of the cursor
- cmd/ctrl-A selects all text in the current element
- clicking buttons in the button bar does things
- You get hotkeys!
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 + ...:
- "1" through "4" to set the current block to a heading
- "p" to make the current block a paragraph
- "o" to make the current block am ordered list
- "u" to make the current block an unordered list
- "e" to make the current block a "pre" text block
Additionally, there are the cosmetic combos:
-
"b" will mark text as "bold", but not really. Bold is a CSS thing, it
marks up the content as "strong".
-
"i" will mark text as "italic", but again, not really. It actually marks
it as "em" for emphasis
-
"s" will mark text as "strike-through", but you guessed it, no it doesn't,
it's "del" for "consider this deleted"
- up arrow will toggle text superscript
- down arrow will toggle text subscript
And then the two special combinations:
-
"/" toggles between HTML and markdown edit modes on a per-block basis.
-
"a" is the "select all" combination, except it doesn't, it selects
everything only in the current block because the number of times
you want to select the entire document are zero, with rounding.
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:
- toolbar UI for working with images
- proper code blocks
-
"raw" HTML support, so you can put divs, custom elements, scripts, etc. in
your document.
-
improved UI for links (e.g. some way to get from text to the URL field,
and enter on the URL field taking you back to the text)
- Loading markdown files, because the idea is to build an editor.
- Change tracking through OT/CRDT
-
Related to which, using a custom edit history because the browser's
contenteditable history (unlike the History object) does not allow you to
slip in your own edits.
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