5 ms·
The "affinity cursor" is a really lovely innovation. Most HTML/DOM/contenteditable based rich text editors end up adding support for virtual cursors that enable
by samwillis 4y ago
The "affinity cursor" is a really lovely innovation. Most HTML/DOM/contenteditable based rich text editors end up adding support for virtual cursors that enable you to have the insertion cursor somewhere that the native browser cursor hasn't got support for (next to a floating image, end of a table row). Effectively this is what this is doing.
Internally the inline formatting will be marked as tags in a rage, exactly like html. Essentially there is a possible cursor position both inside and outside a formatting tag, but both appear as the same visual location on the screen. This is such a lovely way to indicate the difference.
So with this code:
Something <b>bold</b>
There are two cursor positions that are visually the same place:
Something |<b>|bold</b>
^ ^
Most editors "jump" over one of those positions to hide the implementation detail from users. This idea exposes it with a little tail on the cursor.
- felixfbecker 4y agoI really wish browsers would support this for `contenteditable` (even without the tail, just having some way to put the cursor in either position, maybe based on from what direction the cursor is coming from). Slack's message editor is `contenteditable`-based, and it means there is absolutely no way to put the cursor inside at the beginning of e.g. an inline code snippet. Despite the code snippet formatting having an outline border and some padding, meaning it should be possible to even click inside or outside the snippet unambiguously just with your mouse, Chrome will always place it in the same spot and you have to do the awkward trick of replacing the first character. This single behavior makes `contenteditable` so terrible
- samwillis 4y agoIt is possible via JS to place the cursor in that position. The issue is the a native browser cursor navigation skips over it. It would be quite possible to implement this on a contenteditable editor. That particular bug with slack would be possible to fix with JS. The particular difference about that style is there is a little bit of padding at the start of the style. Bowsers have no understanding of clicking on that padding to select inside the the beginning of the inline style.
- panzerboiler 4y ago> It is possible via JS to place the cursor in that position... How? No matter what I try, the insertion point is always before the bold element, and not inside it.
- jitl 4y agoThe behavior for inserting text varies by browser and/or OS, unfortunately. I made [sandbox] to test this. Click the button to set the selection to the first position inside the first <strong> tag in the contenteditable div. [sandbox]: https://codesandbox.io/s/gracious-dew-rx3xhz?file=/index.html https://codesandbox.io/s/gracious-dew-rx3xhz?file=/index.htm... On my Mac, Firefox 104.0.2 inserts new characters inside the <strong>, so they're bold. In Chrome, the browser API allows positioning the selection there, but during the input event, the selection ends up normalized to just before the strong tag, so the characters aren't inserted into the <strong> tag. In Safari, the browser API accepts the arguments to set the selection to the first position inside the strong tag, but normalizes during the API call, and the selection always ends up right before the strong tag. The variance of contentEditable is a huge impediment to using the API raw. If you want reliable, relatively low-level control of rich text input on the web, use ProseMirror. (I learned a lot about this stuff while working on Notion's rich-text editor, which is all custom.)
- panzerboiler 4y agoThank you for the example. I do mostly the same thing and as a Safari user there is no way to place the caret in "the right spot". What I found working (but I still have to test on other browsers and make my mind if it is really worth the hack) is to place a dummy marker with [contenteditable="false"] at the beginning and the end of the inline elements (the one on the end has to be skipped to avoid getting stuck in a limbo inside the parent element). This way the result is similar to the one in Bike, with the caret that stops on both sides of the element. Let's see if this thing goes somewhere...
- jitl 4y ago
- stabbles 4y agoI guess it won't work for rich editors that create tons of elements for every style applied, like `<b><span style=font:...><span style=...>...<i>...` it requires some sanity of the editor.
- samwillis 4y agoOlder content editable editors would do that. But modern ones have moved to not nesting inline styles, and separating internal data structure from the exported html. Full html isn't really that great for the internal data structure of a rich text editor. Think of them as having only a none nestable <span> tag with a style attribute.
- oneeyedpigeon 4y agoI'm hoping these modern editors you refer to at least replace those <span...> atrocities with the correct elements on save.
- samwillis 4y agoThey do, they separate the internal representation of the editor state from the saved html.
- jessegrosjean 4y agoI don't think it would matter, text affinity happens at texts "run" boundaries... so only where formatting changes. Doesn't matter how many attributes each run has. I think that is proper way to design the feature, but it does means it's maybe less flexible then you are thinking. You can pick left or right run... you can pick individual attributes within a run with text affinity.
- MForster 4y agoWhat if there are more than three cursor locations? Like a bold link?
- jessegrosjean 4y agoIt works on text "runs", so there will only ever be two choices. In the case you describe there's no way to choose only bold, or only link... you would need to revert to standard rich text dancing for that.
- munch117 4y agoYeah, looks really nice. The innovation is the visual indicator, the cursor tail. The rest is how WordPerfect worked 30 years ago. It is horrifying to think how much the Microsoft Word approach has hobbled rich text editing for all those years, and continues to do so.
- ComodoHacker 4y agoMicrosoft Word never had problems with inserting any formatting at any position in the text. It also has some visual style indicators via caret shape and size.
- munch117 4y agoMSWord doesn't have formatting codes, at least not for simple text styles. Instead, each individual character has formatting attributes. So the word italics is not a single italicized region, it's 7 separately italicized characters, that just happen to be next to one another. It's a radically different model from HTML/markdown/WordPerfect markup. Microsoft Word may never have problems inserting any formatting, but I have; when it comes to paragraph structure, indenting and such, I find it very hard to predict. For example, I'll look at sections of a document with basically the same structure, but in one place the spacing between a table and the paragraph that follows is much larger, and I have no idea why or how to make them the same.
- jamesfisher 4y agoIn https://tigyog.app https://tigyog.app I'm solving the same problem in a different way. Like Bike, the TigYog editor treats those two cursor locations as district. But TigYog shows which position you're at in a different way: when the cursor is inside a link, the link gets a "focus" outline.
- c-smile 4y agoMy Sciter [https://sciter.com https://sciter.com] uses that since 2012 : https://terrainformatica.com/2012/11/04/caret-positions-in-html/ https://terrainformatica.com/2012/11/04/caret-positions-in-h... The feature there is named "directional caret"...
- jessegrosjean 4y agoNice work on Sciter. When I came up with this feature in Bike I was pretty proud of the idea and it seemed original. Then a few weeks later I came across your post on StackExchange UX... everything already been invented I guess :) I'm curious how you came with idea? Also have you come across other editors that implement it? For me I new that something bothered me about rich text editing... always seemed more painful then required. I was also aware of the idea of split cursor from Humane Interface book. And also aware of affinity idea from text cursor position in wrapped text editor lines. Bike's typing affinity came from combining those ideas. Anyway would love to hear any related thoughts or ideas.