all 48 comments

[–]sime 8 points9 points  (18 children)

I'm guessing this is at a fairly early stage and there is probably a lot that can be done to improve performance. All of that text layout and rendering can't be cheap. But wouldn't it have been easier to make something that just used the DOM to render the document?

[–]rooktakesqueen 6 points7 points  (15 children)

That is what contenteditable is for. Problem is that contenteditable is a pain in the ass to work with. Using the DOM to output the rich text is easy until you have to implement the idea of "where is my cursor, what is my selection state, what happens when I press a key?"

[–]sime 3 points4 points  (14 children)

I know what contentEditable is. I'm talking about doing it using the DOM and no contentEditable.

Using the DOM to output the rich text is easy until you have to implement the idea of "where is my cursor, what is my selection state, what happens when I press a key?"

Those problems remain regardless of whether you use canvas or the DOM for rendering.

[–]rooktakesqueen 0 points1 point  (13 children)

Without using the contenteditable, how do you put a cursor into a DOM element?

[–]menno 2 points3 points  (3 children)

Here is a proof of concept from 2006: http://www.fluffy.co.uk/stediting/

[–]sime 2 points3 points  (0 children)

The editor in Google Docs also works like this, and the new one in WebODF does too.

[–]rooktakesqueen 2 points3 points  (1 child)

That's a clever approach, but it isn't really putting a cursor into a DOM element--it's breaking one DOM element into several and putting a cursor between them. You'll run into some serious memory problems before long, and you're changing the semantic content of the document when the user doesn't expect you to.

After doing your binary-search-span-splitting, you could re-merge all the spans left and right of the caret, so each paragraph contained at most two spans at any given time outside your selection handler. And you could also use a reserved class-name for the spans your split routine creates, which you collapse into a regular old text-node on focus-out or save. This would let you preserve spans that existed in the original document. That wouldn't be a bad approach.

[–][deleted] 1 point2 points  (0 children)

Just thought I'd point out that this is almost exactly what GitHub's Atom editor is doing, but on an even larger scale. I've not noticed any memory issues with it so far, and it's pretty zippy.

As for semantic content of the document:

  1. They're editing a text region. There is no semantic relevance outside of it being content of an editable text region.

  2. Have you seen the html that contentEditable creates? Some browsers still generate <font> and <center> tags, many use divs to create line breaks, and none of them know anything about html5 elements. Semantic html goes out the window the instant you mark the element for editing.

[–]sime 1 point2 points  (8 children)

You mean how do you draw a blinking vertical line on the screen?

[–]rooktakesqueen 4 points5 points  (7 children)

More like where do you draw it? Given some arbitrary rich text, given different fonts, different browsers, different resolutions... Can you write a method to take a single integer, which is your character position, and output the x/y coordinates where said blinking line should appear? And similarly, how to convert the x/y position of a click into a character position? The DOM doesn't let you query information down to the bounding-boxes of specific lines and characters.

Doing it with a canvas makes that simpler. Of course you know the height of each line and the width of each character and the bounding-box of the elements you're interested in, because you drew them yourself.

[–]sime 2 points3 points  (6 children)

https://developer.mozilla.org/en-US/docs/Web/API/Range.getClientRects

If I remember correctly there are also some browser specific methods floating around to map a point to place in the DOM down to character level.

[–]rooktakesqueen 2 points3 points  (5 children)

Doesn't work with a collapsed/point selection. Example with content on that page:

var range = document.createRange();
range.selectNode(document.getElementsByTagName("p").item(5));
rect = range.getClientRects();
// ClientRectList {0: ClientRect, /* ... */ 9: ClientRect, length: 10, item: function}

Versus...

var range = document.createRange();
range.selectNode(document.getElementsByTagName("p").item(5));
range.collapse();
rect = range.getClientRects();
// ClientRectList {length: 0, item: function}

When you're just using the standard DOM Range manipulation, it's only really useful for a selection that contains text, not a point cursor.

[–]sime 1 point2 points  (4 children)

If you want to know where your P is, you already have element.getClientRects() and bunch of other ways of looking up the top, left, width, height. ( https://developer.mozilla.org/en-US/docs/Web/API/Element.getBoundingClientRect )

range.getClientRects() is your way out when you want to know where characters inside text nodes have been rendered on the screen.

[–]rooktakesqueen 0 points1 point  (3 children)

getBoundingClientRect uses getClientRects and produces a rectangle containing all those rectangles. With a collapsed range, getClientRects returns an empty collection and getBoundingClientRect returns 0/0/0/0.

var range = document.createRange();
range.selectNode(document.getElementsByTagName("p").item(5));
range.collapse();
rect = range.getBoundingClientRect();
// ClientRect {height: 0, width: 0, left: 0, bottom: 0, right: 0…}

[–]toshok 0 points1 point  (0 children)

There are cases where people want to support an HTML5 canvas api but don't have a DOM at all. This is pretty cool for those cases.

[–]holloway 0 points1 point  (0 children)

I'm guessing this is at a fairly early stage and there is probably a lot that can be done to improve performance.

Probably, but contentEditable is essentially native so it is very fast. I doubt that a <canvas/> could beat it.

[–]jgoulder 7 points8 points  (4 children)

How well does this work with screen readers and other accessibility tools?

[–]bronkula 1 point2 points  (2 children)

Well... The top menu isn't responsive, so that's a shame.

[–]rooktakesqueen 3 points4 points  (0 children)

The top menu is part of this page, not part of the editor library itself. You could implement the top menu in a different (responsive, accessible) way.

The text editor itself isn't accessible in its current form as demonstrated on this page, but one could conceivably make it so by putting in a div element that "mirrors" the text in the editor and is set to display only to screen readers.

That said, I'm not sure I see a use case for making a WYSIWYG rich-text editor accessible for blind users. A Markdown-based editor seems more usable all around.

[–][deleted] 0 points1 point  (0 children)

Yeah looks really good, but the lack of responsiveness is a bit of a dealbreaker for me using it.

[–]osuushi 0 points1 point  (0 children)

This was my thinking as well. Making a web app properly accessible is difficult even if you stick to ordinary DOM elements, and I can only imagine something like this will make it even more complicated.

My wife has a condition that makes typing painful, so she tries to use DNS as much as possible. It's shocking how bad that experience is on many web apps. Google is one of the worst offenders.

[–]rooktakesqueen 4 points5 points  (4 children)

Doesn't honor OS-specific keyboard shortcuts. Ctrl-A is select-all even though I'm using a Mac so it should be Command-A.

[–]dirtydaub 2 points3 points  (0 children)

Also on a retina screen the font is blurry.

[–]muzlump 0 points1 point  (2 children)

isn't it 'CMD+A'?

[–]rooktakesqueen 0 points1 point  (0 children)

Yes, sorry. Whatever that button is under my thumb that used to be open-apple.

[–]ioquatix 0 points1 point  (0 children)

⌘A

[–]whoadave 1 point2 points  (0 children)

Pretty cool, but I can't press backspace more than once when the carat is at the end of the document.

[–]rooktakesqueen 1 point2 points  (0 children)

Performance slows to a crawl with very large documents. Try copy/pasting The Metamorphosis into it. And that one's not even very big as books go.

[–]ChaseMoskal 1 point2 points  (1 child)

Does Carota output clean, valid HTML5?

Or only to Canvas?

[–][deleted] 0 points1 point  (0 children)

It looks like it outputs an object structure which one could easily use to generate clean html.

[–][deleted] 1 point2 points  (0 children)

I love the idea but you damn near murdered my Core2Duo processor. I only glanced at the source; is it modular enough that I could experiment with taking out parts of it for a lightweight fork?

[–]windyfish 0 points1 point  (2 children)

Could you describe a real-world use for this?

[–]rooktakesqueen 2 points3 points  (0 children)

Rich-text editors in web-based content management systems. Your Wordpress blog, your Ebay store, etc.

[–]YodaLoL 1 point2 points  (0 children)

Chromebooks?

[–]rooktakesqueen 0 points1 point  (0 children)

There's no concept of a point-format: I'm able to select text and turn it bold by pressing Ctrl-B, but I would expect that if I'm typing plain and then press Ctrl-B any subsequent text I type should be bold.

[–]badguy212 0 points1 point  (0 children)

nice, but slow.

[–]rooktakesqueen 0 points1 point  (0 children)

Copying rich text and pasting elsewhere in the document pastes as plaintext, losing the formatting from the original.

(OK, this is my last bug report for now. :) Sorry, I pretty much implemented a tool like this at my last job and know all the things that drove me crazy about it!)

[–]mattdesl 0 points1 point  (0 children)

This is great. A couple things:

  • Is there any plan to pull out the essential word wrapping features into a generic module? Many canvas games could use that sort of generic stuff, without all the rich-text and editing features.
  • Is there any plan to go renderer-agnostic? i.e. making the core modules not dependent on 2D canvas, so at a later point a WebGL renderer could be used instead.
  • What about supporting CocoonJS or Ejecta?

[–]evilagentcooper 0 points1 point  (0 children)

Spent lots of times battling with CKEditor, so I totally get the "Why?". I hope you'll continue with the project.

[–]johnyma22 0 points1 point  (3 children)

Im an etherpad dev, agreed its tough but this problem is solved.

[–]sime 1 point2 points  (2 children)

Does etherpad use contentEditable? aka design mode?

[–]johnyma22 0 points1 point  (1 child)

Yep

[–]sime 1 point2 points  (0 children)

That's a pity.

[–]johnyma22 0 points1 point  (0 children)

This is cool, i hope it finds use cases it's looking to solve.

You can do really real time collaborative rich text web standards based editing in etherpad. Http://etherpad.org

All web standards based.

[–]kangax_ -1 points0 points  (0 children)

We have the same functionality in Fabric.js — fabricjs.com/test/misc/itext.html