Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should the caret move by default, and should we define this behavior? #58

Closed
johanneswilm opened this issue Jun 3, 2015 · 46 comments
Closed

Comments

@johanneswilm
Copy link
Contributor

Options mentioned so far:

A) Don't move the caret by default and don't define default behavior.

B) Move the caret by default and define the default behavior in a spec.

C) Move the caret by default and define some of the default behavior and leave the rest to be decided by UA/platform (for example: let UA decide on line block direction movement, but define inline movement in spec).

D) Move the caret by default, but do not spec this behavior. Instead, let the UA/platform decide what that behavior will look like.

This is the default inline movement we initially had in the spec before it was removed:

           <h3>Default caret movement pattern</h3>

            <section>
                <h4>Caret movement within <a>CE Typing Node</a></h4>

                <p>Each key press event in the `inline direction` or in the
                direction opposite to the `inline directions` triggers the
                movement of the caret of one position within the current
                <a>CE Typing Node</a>.</p>
            </section>

            <section>
                <h4>Caret movement at the end of a <a>CE Typing
                Node</a></h4>If the caret is at the end of a <a>CE Typing
                Node</a> before the movement takes place, and the requested
                movement would cause it to go beyond the end of the <a>CE
                Typing Node</a>, the caret is moved into the start of the
                next following <a>CE Typing Node</a> that is part of the
                same <a>CE Typing Container</a>. If this movement did not
                cause it to move by at least 1px, the caret is moved one
                additional position.

                <p></p>

                <p>If there is no following <a>CE Typing Node</a> to which
                the caret could be moved, it is not moved.</p>
            </section>

            <section>
                <h4>Caret movement at the start of a <a>CE Typing
                Node</a></h4>If the caret is at the start of a <a>CE Typing
                Node</a> before the movement takes place, and the requested
                movement would cause it to go beyond the start of the <a>CE
                Typing Node</a>, the caret is moved into the start of the
                last preceding <a>CE Typing Node</a> that is part of the
                same <a>CE Typing Container</a>. If this movement did not
                cause it to move by at least 1px, the caret is moved one
                additional position.

                <p>If there is no previous <a>CE Typing Node</a> to which
                the caret could be moved, it is not moved.</p>
            </section>
@fredck
Copy link

fredck commented Jun 3, 2015

I think that "B" is mandatory.

This is one of the messiest parts in cE right now and a quality spec is needed so the behavior is predictable. Also, a js implementation for it would be big, so passing this responsibility to the browser would be welcome, leaving js developers with the option to override the behavior when needed.

It could go as part of "typing" (or by default whenever editing is enabled). The other options is making it an additional editing module, namely contenteditable="caretcontrol" (or "selectioncontrol" or "selection" or anything else... a better name is needed, surely).

@johanneswilm
Copy link
Contributor Author

Putting it into another module certainly would be a clean division, I think. If it's really to be useful, it may end up being rather complex though, so it would probably be good if we could start. Also, it should be possible to override the behavior in the JS, so all the parts needed for that should be present (such as precise position info of caret, etc.).

@kojiishi
Copy link

kojiishi commented Jun 3, 2015

Hard to comment without knowing the diff between B and C. I think you're already aware of, but UAs might want some of inline movements such as related with RTL vary by platforms.

So if you could start from "which platform differences are troubling editor developers" and try to spec them out, that'd be good, but I don't imagine we can define every details. Actually, doing so i18n-wise correctly is really really hard...

@johanneswilm
Copy link
Contributor Author

@kojiishi Could you specify what parts of inline movement you want the UA to control? It is true that moving the caret is really hard, and that's editors either need full control or fully spec'ed movement or preferably both. Else one has to revert to tricks to get 4+ inconsistent browsers to do the same thing.

@rniwa
Copy link
Contributor

rniwa commented Jun 3, 2015

In WebKit, there are many caret movement behaviors that are platform specific. While both Gecko and Trident/Edge tend to match Windows' caret behavior, WebKit tends to match OS X's. So I don't really think we can agree on single caret behavior since that would cause a significant UX regression for many of our users.

Like I stated in another issue, the key here is to come up with a good abstraction to allow Web devs not to worry about platform-specific behaviors. If anything, they can cancel the default action and implement their own caret behavior.

@johanneswilm
Copy link
Contributor Author

Like I stated in another issue, the key here is to come up with a good abstraction to allow Web devs not to worry about platform-specific behaviors.

Yes, but this is kind of what contentEditable is trying today, right? And it's precisely because that is not working that we are at this point. The implementations have been fixed to work around the issues Gmail and some similar editors had in the past, but it doesn't work for all the editors made by non-browser-vendors, which all heavily override the default behavior.

If anything, they can cancel the default action and implement their own caret behavior.

Ok, if this is as far as you can go, then I think we should concentrate on making this work. It should be enough to allow to make custom editors. But for that we need some minimal information about actual current placement of caret, etc. .

@rniwa
Copy link
Contributor

rniwa commented Jun 3, 2015

I don't buy the argument that the difference in selection behavior is what forced editors to override the default behavior. Gmail, for example, doesn't override selection/caret behavior as far as I can tell. What they override is undo/redo and other editing actions such as bolding of text.

Anyway, we need to come up with a list of concrete use cases (e.g. building a collaborative editor) and associated requirements in order to talk about this. It's not really productive to talk about what we need to do without understanding what problem we're solving.

@johanneswilm
Copy link
Contributor Author

@rniwa

Gmail, for example, doesn't override selection/caret behavior as far as I can tell.

As mentioned, Gmail was successful in getting contentEditable fixed in browsers so it would work for them. That's great for Gmail. The editor in Gmail is quite simple when it comes down to it.

And the bug reports of the rest of us have been rejected for the last few years, often with the explanation that there is no specification so that there is nothing that tells us what is the correct or incorrect behavior. Then we were told that it cannot be fixed and that we need to get an entirely new alternative to contenteditable in which all behavior will be customizable by the JS code, and now we are being told that we won't get access to these primitives anyway. I don't think we are moving forward, and we kind of have presented bugs throughout the years in the form of bug reports. We mentioned some use cases in the other thread ( starting here: #56 (comment) ). We can go more into detail with those, or we can point to some of the bug reports that have been filed.

@rniwa
Copy link
Contributor

rniwa commented Jun 3, 2015

It would be valuable to have a markdown document / wiki page listing all those issues or use cases so that we can use it to evaluate each new feature/API proposal. Otherwise, we may keep talking past each other like you're saying.

@johanneswilm
Copy link
Contributor Author

@fredck @teleclimber @spocke: Do any of you have a list of everything that is wrong with contenteditable?

@rniwa Did you see the explainer documents that Benjamin created [1]? It lists a number of use cases and explains why we have to go beyond contentEditable=True.

[1] https://w3c.github.io/editing/editing-explainer.html

@rniwa
Copy link
Contributor

rniwa commented Jun 3, 2015

Yes, I was the one who suggested have those lists of use cases and goals.

But the fact contenteditable=true is broken doesn't mean that UAs need to have exactly one selection behavior and give up on platform friendless. Gecko, for example, allows users to change the way selection behaves in settings. OS X has a system-wide feature to enable split caret in bidirectional text. All these things need to be respected, and I don't see exposing each and every one of those configurations to editors as an option because developers are bound to get some combinations of them wrong.

We really need to understand exactly what's broken with selection and address those issues instead.

@johanneswilm
Copy link
Contributor Author

Have you tried to dig down into what current editors do? Basically they try to override everything, IME input/bidi/rtl is likely too complicated for many of those editors who only put 2-3 years of development time into an editor. So I doubt that there is much "common feel" in place today that you can break.

Just take what we are typing in here on Github: I am using Chrome, and I notice that overtype is disabled although it is enabled everywhere else. If I right-click and choose writing-direction->right-to-left the text moves to the other side. The physical directions of the caret are still respected, but if I type any letter, it is always inserted somewhere completely else than where the caret currently is. The same happens in Gmail. So sorry, also Gmail is broken.

We really need to understand exactly what's broken with selection and address those issues instead.

We have mentioned several use cases. The way forward, as I can see it, is to follow the Extensible Web Manifesto [1]: Gives us (the web developers) the necessary primitives to implement things ourselves in JavaScript. Once that has been done, and you can tell that there are some common operations that everyone does in the same way and that could gain something from being moved to the browser, then you can add specs with higher layer features on top of the lower layer spec you initially made.

I think it would be helpful to find out if we are going to get any compromise on this part from the part of browser makers, or if browsers are going to continue to try to manage editing down to the smallest detail and make it hard for JS to define or even override anything. If that is the case, then I cannot see how we are going to get any further with this spec then with what already exists.

[1] https://extensiblewebmanifesto.org/

@rniwa
Copy link
Contributor

rniwa commented Jun 3, 2015

I don't think we should add any API without understanding use cases. We need to understand each and every use case for which existing editors are overriding browser default behavior and come up with a solution instead of providing bunch of platform dependent "primitives" and hope for the best.

@johanneswilm
Copy link
Contributor Author

@rniwa: We have listed use cases both here, and as I pointed you to, Benjamin made an extensive document about just that.

It sounds to me as if you are thinking about fixing contentEditable=True. If it is possible to do that without breaking legacy sites, I am all for that. We have all provided a long list of bug reports to all the browsers over the years and we can point to all those again. The people you have been discussing with here (me excluded) have been building JS based editors for many many years and are probably some of the world's most dedicated experts when it comes to contentEditable=True, so it's not like they don't know what they are talking about.

Fixing contentEditable=True is a great idea. contentEditable=Typing is about something else. It is about providing primitives and to give control that used to be in the browser over to JavaScirpt. I understand your statement as meaning that you are against cE=Typing in principle. That is noted, but then I think it would probably be better if you concentrated your efforts on fixing contentEditable=True.

@rniwa
Copy link
Contributor

rniwa commented Jun 3, 2015

You're extrapolating too much. I'm only concerned about real problems. I'm against any API unless it solves some problem is all I'm saying, and the list of problems each API solves needs to be explicitly documented. It's not enough to say "beacuse that's a primitive necessary to build an editor". That's not a use case, and not any evidence to suggest the proposed API is necessary or the most appropriate form of the solution.

"Giving control to JavaScript" sounds cool and sexy but that doesn't solve any real problem on its own.

@johanneswilm
Copy link
Contributor Author

@rniwa: The idea with the Extensible Web Manifesto is that you start out by giving us JS developers the primitives needed to implement feature X entirely in JS. Then, as the next step, you the work together with JS developers to create higher level specs based on JS polyfills.
We have both given plenty of examples and files plenty of bug reports, and written blog posts, academic articles about the various issues and what the usecases are, so that part has been taken care of. We have moved beyond that stage.
Now we are at the stage of figuring out what primitives you are willing to offer us. We have come with some suggestions of primitives that could be of help to us, but I think we are all willing to accept other ones if you can offer us something else useful. But so far, the answer seems to have been: we don't want to offer any primitives at all. Instead we need to know what's broken with what we have already and then fix that instead.

Did I misunderstand you on any of that? Are there any new primitives you would be willing to offer? Such as exact information about where the caret(s) currently are? And a way to set them?

@rniwa
Copy link
Contributor

rniwa commented Jun 3, 2015

That's not all what I'm saying at all.

I'm here to participate in the discussion to come up with a new editing API that WORKS. It doesn't matter whether it "provides primitive" or "gives more power to JS". Letting JavaScript see exactly where the caret is placed doesn't solve any problem on its own and IMO introduces more problems for bidi users because caret will show up at two different locations at boundaries of bidi levels. Gecko, for exmaple, changes the location at which caret appears depending from which direction you moved the caret. I don't think Web apps want to have a bunch of if-else statements to check the preferences of Gecko and behave differently based on that. The fact selection behaves differently in different browsers is not necessary a bug. Some of the behavioral differences are intential and features.

So that's why I'm asking for you to list the problems you have with the current selection APIs and behaviors so that we can come up with the right set of APIs and spec's that address those issues without degrading user experience in CJK languages, bidirectional text, and platform-specific behaviors.

The reason editing API hasn't improved over the last decade or two isn't because we've been lazy. It's because HTML editing is really hard. We can't just add a bunch of half-baked "primitives" and magically solve the problem. If anything, that'll only exacerbate the problem we have today.

@johanneswilm
Copy link
Contributor Author

I'm here to participate in the discussion to come up with a new editing API that WORKS. It doesn't matter whether it "provides primitive" or "gives more power to JS".

That's fine, but that's not what contentEditable=Typing set out to do. It's only about offering primitives to JS libraries to create editors. It is not about providing an editor to end users that works.

I don't think Web apps want to have a bunch of if-else statements to check the preferences of Gecko and behave differently based on that.

I think that would be the least of our worries. For example, the standard package CKEditor is 2.9 MB, so a few if-else statements more would certainly not break any camel's back. And hopefully the 2.9 MB could be slimmed down quite a bit as well.

Some of the behavioral differences are intential and features.

If we could, many of us would simply override such behavior. And it's a bit weird: Noone tries to tell us what size or shape pull down menus are to be or that menu buttons only go on the right and that the background of all webpages is light blue when seen in Safari to preserve a common experience when surfing the web using Safari. Yet when it comes to editing, somehow it is felt that this needs to be centrally managed.

So that's why I'm asking for you to list the problems you have with the current selection APIs and behaviors so that we can come up with the right set of APIs and spec's that address those issues without degrading user experience in CJK languages, bidirectional text, and platform-specific behaviors.

Ok, so you want a list of the most important contentEdtiable bug reports? If there is a chance they will be fixed, I am certain we will be able to provide those to you very quickly. (Btw, this is mainly NOT about the selection API, but about contenteditable. Some things may end up being discovered as also be issues for the selection API, but in general that's not what the discussion is about here).

The reason editing API hasn't improved over the last decade or two isn't because we've been lazy. It's that HTML editing is really hard.

Noone is accusing you of being lazy. My understanding of the situation was that the browser makers accepted that they will not ever be able to solve this problem and that therefore they will instead hand the task of creating editors over to the JS groups/projects/companies that dedicate themselves to creating editors. That's why I am somewhat confused that you seem to want to go the other direction again and not give us the primitives and instead create a new form of contewntEditable=True.

We can't just add a bunch of half-baked "primitives" and magically solve the problem. If anything, that'll just exacerbate the problem we have today.

Can you explain why you think the problem will grow bigger if the editing logic is being moved to the JS? The primitives we are asking for are not just random things. They are all backed up with use cases and are suggested by people with many years of experience in this field. As for bugs: they have also been filed many years ago.

Otherwise, I don't think we get any further here. I suggest you start a new spec with the working editing api that does not offer primitives but "really works". The editing task force already hosts various specs, of which we are still not entirely certain which one survives, so adding one more shouldn't be a problem. I would then also suggest you look through our use cases and bug reports and come up with some concrete suggestions on how to handle things.

@rniwa
Copy link
Contributor

rniwa commented Jun 3, 2015

That's fine, but that's not what contentEditable=Typing set out to do. It's only about offering primitives to JS libraries to create editors. It is not about providing an editor to end users that works.

I beg your pardon? I was right there when we initially came up with the idea of contenteditable=typing in the editing community group / WebApps, and I don't think "offering primitives to JS libraries to create editors" was really a goal in the first place or at least the way you described it here. We had a specific list of use cases we wanted to solve in contenteditable=typing as outlined in the explainer:

Goals (https://w3c.github.io/editing/editing-explainer.html#goals):

  1. Empower authors with the right set of baseline behavior to enable creating complex editors
  2. Make it easy to implement custom behavior with appropriate APIs

@rniwa
Copy link
Contributor

rniwa commented Jun 3, 2015

Also in general, Web Apps WG and HTML WG design APIs to address concrete use cases. We don't just spec API because it exposes new primitives to JS.

I understand your frustration but you really need to give us a list of concrete use cases that necessiates each API/feature instead of saying that you know it better.

@johanneswilm
Copy link
Contributor Author

Goals (https://w3c.github.io/editing/editing-explainer.html#goals):

  1. Empower authors with the right set of baseline behavior to enable creating complex editors
  2. Make it easy to implement custom behavior with appropriate APIs

Yes, those two goals is what at least I understand as "exposing primitives to JS". But lets just agree to disagree on this.

I understand your frustration but you really need to list concrete use cases instead of saying that you know it better.

Ok, what was not good enough about the use cases that were already listed? Also note that I never claimed that I knew anything better. What primitives you are exposing is totally up to you. You are the browser expert, not me. We just need something.

@rniwa
Copy link
Contributor

rniwa commented Jun 3, 2015

Going back to the original topic of this issue, which is about how the default selection behavior should be defined, we need to understand selection behavior requirements for each use case below, and understand why the current selection API is inadaquate:

  1. Semantic HTML WYSIWYG editor
  2. Structured content editor with whitelisted DOM elements and/or classes
  3. Editor that supports areas of non-editable content
  4. Web-based code editor with syntax highlighting
  5. Browser based "word art" generator
  6. Track changes functionality within an editor
  7. Web-based DTP application
  8. Surface for plain text editing
  9. Style read-only text

For example, for 3, I'd imagine that selection cannot cross editability boundary so we need to spec how UA "fixes" selection when the selection is set across different editability. Or maybe we need to allow it. Or perhaps it needs to be configurable.

For 4, perhaps code highlighting happens asynchronusly so we need to provide a mechanism by which apps can replace the underlying DOM while preserving the selection set by the user.

And so forth. Once we've listed all those requirements, we can then begin to think of a solution that address them.

@johanneswilm
Copy link
Contributor Author

Going back to the original topic of this issue, which is about how the default selection behavior should be defined, we need to understand selection behavior requirements for each use case below, and understand why the current selection API is inadaquate

I think that's another topic (but also an important one!). "caret movement" was meant as "Where does the caret go when I hit the right/left/up/down arrow keys". As far as I can tell, the selection API says nothing about any of that.

But there may be some connection: I haven't investigated it, but I guess it's possible that the reason the caret currently isn't going into certain places currently when moving around with the arrow keys is that it is prevented from creating a selection in certain places.

@rniwa
Copy link
Contributor

rniwa commented Jun 3, 2015

The problem is that caret behavior is platform dependent just as much as focusing behavior is (see section 6 of HTML spec) and we can't really agree on single behavior across platforms and browsers.

We need to understand the underlying motivation / use case and come up with an alternative approach instead.

@johanneswilm
Copy link
Contributor Author

@rniwa OK, so your short answer is option D, correct?

@rniwa
Copy link
Contributor

rniwa commented Jun 3, 2015

Perhaps but we might be able to do C depending on what needs to be spec'ed. e.g. legal positions for selection end points.

@johanneswilm
Copy link
Contributor Author

D is a clear answer. Now you wonder why one would want to use standardized caret behavior in the various examples you mention there.

As for the examples you mention:

  1. Semantic Editor: Fidus Writer: only works in Webkit/Chrome. Actually it broke in Chrome a few Chrome versions ago, but I spent so much time fixing it in the past so it just didn't seem worth it continuing with that without fixing the problem at the root of this: that contenteditable isn't spec'ed in any way. I also tried getting it to work in Firefox, but I found out I would need to write all JS functions twice, so I gave up on that for now. I simplified it a little but by breaking it in certain cases (if two citations/footnotes go directly after oneanother, the caret can now no longer be placed in-between them). Most of the JS files here in soem degree try to fix CE behavior: https://github.com/fiduswriter/fiduswriter/tree/2.0/document/static/js
  2. Track changes -- I contributed a lot to the NY Times's ICE editor to make it work not only with Firefox but also Chrome/Webkit: http://nytimes.github.io/ice/demo/ . You can find my contributions in the github history. Unfortunately it is somewhat broken now, as the original maintainer didn't have the time to update it every six weeks when a new Chrome version appears and new things break. It includes a test suite and all.

I don't think any of those really can or should be done in contenteditable directly, even if it's 100% fixed. The amount of possible errors is just way too high. Instead it needs to be implemented as a datastructure that is managed by some Javascript code that renders it in the DOM and records any changes made to it by the user as atomic commits which can then be stored, rolled back, shared with others in a collaborative environment, etc.. This is probably also true for other complex editors, especially when combining several complex sub components.

@rniwa
Copy link
Contributor

rniwa commented Jun 3, 2015

Thanks for the clarification but what I'm asking why and how do the differences in selection behaviors among browsers are causing problems in those editors.

You've mentioned that you've filed many bugs in the past but what are those bugs? And which feature / user scenario end up encountering those bugs?

@johanneswilm
Copy link
Contributor Author

I think the track changes one is a good example: I don't think anyone knows why it worked about a year ago and what exactly make it stop. The way to create it was simply: Create some basic code and some basic tests. Add if clauses to the code until the tests all work. Then try it out in real-life. Whenever you run into another issue, create another test and add another if clause somewhere in the code until it works. Then you test on other browsers and add more if clauses, and so on. Every time a new Firefox or Chrome version comes out, run all the tests. If something is broken, add more if clauses in the code until all the tests run again, etc. . So it's just one gigantic mess of spaghetti code. What you can do is try to remove some of the if statements and then see what happens and what breaks in what browser. This track changes plugin can now be found in derived versions as plugins for the main contenteditable-based editors. And I think it's the only one so far.

As for some bug reports:

Your issue nr 3 (non-editable islands): https://code.google.com/p/chromium/issues/detail?id=238000#c6

Most relevant for caret movement is this one: https://bugzilla.mozilla.org/show_bug.cgi?id=873883 (also reported to Chrome and also contacted Webkit team at the time they still were united). The caret cannot move between these elements. It can move between some in Firefox and others in Chrome. Just moving around images is working in both. These are important because using canvases, within a line is a way to make sure that footnotes are placed correctly and can be moved with copy and pasting -- I created a demo with that here: http://johanneswilm.github.io/canvasContentEditable/ .

@rniwa
Copy link
Contributor

rniwa commented Jun 4, 2015

Oh those seems like real bugs that need to be fixed in each browser, and that's something we can definitely spec (how caret behaves around non-editable content).

@ctalau
Copy link

ctalau commented Jun 4, 2015

OK. I will give some use-cases in which the default caret movement behaviour (today) is not suitable:

  1. Change Tracking: the deleted content is rendered crossed out and the caret should not be placed by the used inside the crossed-out content. Note that the deleted content may span multiple nodes. E.g.
<p>this <span class="del" data-cid="1">is a </span><b><span class="del" data-cid="1">deleted </span>frag</b></p>

I don't want any caret position inside the two .del spans, nor between them.
2. Labels: intended to inform user about the content that would be inserted, but which are not editable

<p><b class="info">Chapter 1: </b> Title of chapter1</p>

When the caret is in the p element, i want the caret to be anywhere after the .info element, but not inside or before it.
3. Structured information: the caret should not appear between two elements that cannot have anything between them. E.g.:

<p><span class="street">1, Townsend st.</span><span class="city">San Francisco</span><span class="zip">9401</span></p>

There should be no caret between the span elements, text entered there does not have any meaning.
4. Inline widgets:

<p><div class="button">expand</div> ... content ... </p>

There should be no caret inside the .button element.
5. Code folding:

<span class="folded-marker">[...]</span>
cod|e

When the user moves the caret up, the .folded-marker should appear focused (get some fancy blue border) and the caret should disappear. Moving the caret up again should show the caret on the line above the .folded-marker.

Some personal remarks:

  • I think that platform-specific selection implementation is fundamental for accessibility and usability. I don't care if it is implemented by UA or script.

    However, even with enough API (e.g. showing the magnifying glass on an iPad), this would be a huge task for editor devs. So, I imagine there will be a handful of libraries that will have to offer some API in order to be customized by each editor. So we are back to square one: designing an API for managing selection.

  • If you override the selection once, the hidden selection-associated state (e.g. magic X coordinate in block-direction movement) gets out of sync, so one needs to override most of the subsequent selection changes.

  • I would propose some CSS property or HTML attribute that controls where the UA is allowed to place the caret (a la user-select). The specification of the default selection behaviour should only define illegal caret positions. The script will still be able to place the caret in any position currently defined by this specification.

@johanneswilm
Copy link
Contributor Author

I think that platform-specific selection implementation is fundamental for accessibility and usability. I don't care if it is implemented by UA or script.

However, even with enough API (e.g. showing the magnifying glass on an iPad), this would be a huge task for editor devs. So, I imagine there will be a handful of libraries that will have to offer some API in order to be customized by each editor. So we are back to square one: designing an API for managing selection.

I agree that this still does not create a full editor for us. The situation now however seems to be the following:

  1. Lowest layer: a limited number of contenteditable implementations that are incoherent used by most browsers nowadays.
  2. Middle layer: a limited number of editors (CKEditor, TinyMCE, Aloha 1.0, QuilJS) that have been developed over many years to work around the issues in the lowest layer. They are backed by companies that have the time and resources to have done the development in the first place and that now have the time and resources to monitor whether anything changes about the implementations in the lowest layer so they adapt to that. These editors are hundreds of kilobytes and even MB large because the ground they build on is so shaky.
  3. Highest level: The website. This can be Wordpress or Drupal or a custom system and they put the middle layer editor into their site. They add some plugins to make it work with the rest.

The above, I would assume, covers about 99.9% of small to medium sized sites.

Every fortnight there is someone saying he has created the perfect replacement for the above-mentioned editors that is able with just 2kb of code to replace the above editors. The way that goes is usually: they work enough to type a few words in an editor for demo purposes, but if one actually tries to write a text with them, one quickly runs into the numerous contenteditable bugs that they have not been able to cover with their 2kb code. So they start adding more code to it as they find out that their editor doesn't work. This can take some 2-3 years. AT that stage it's as complex as the above mentioned editors, or development has ceased before they ever got there.

I can see two other types of contenteditable-based editors:

  • Large organizations with the time and resources to create their own editor.
  • Projects with the need of a complex editor, who lack the resources to do the constant monitoring of cE in the browsers, time to reimplement everything 4 times to work around the bugs in each of these.

I would assume that you fall into one of these last two categories.

The idea is to shift the creation of these libraries from browsers, who have a million other things to do and don't really have time and resources to put into constantly thinking about editing, to JS developers working on editors who do nothing else than concern themselves with editing.

If the primitives actually get implemented, I expect there to grow maybe 1,2,3 different libraries that can take care of most of the editing. They shouldn't be as large and bulky as what is needed in the editors right now, because they can rely that the browsers behave the same way and don't constantly change. Also, the rest of us can commit JS patches much easier than patches to browsers. It is my understanding that the Chrome team even for a while had planned to move execCommand to Blink-in-JS internally for that precise reason.

The structure would then be:

  1. Lowest level: API offering access to browser primitives.
  2. Middle: JS libraries that offer access to what execCommand and contentEditable=true and others did previously.
  3. Highest: Editors of various degree of complexity that build on those libraries.

With time, the functions the Middle layer performs may be moved into the browser itself after having been spec'ed thoroughly.

@ctalau
Copy link

ctalau commented Jun 4, 2015

@johanneswilm If you talk about contenteditable=true in general, I totally agree with what you said. I was talking about selection in particular and I was just sceptical that a JS library will be able to reimplement the exact same selection behaviour that is today in browsers (and which works great for the end-users) and offer an API such that it can be easily integrated in an editor.

@rniwa Are the use-cases above what you were looking for?

@johanneswilm
Copy link
Contributor Author

@ctalau: I think we need to make a distinction between selection as meaning "the user highlights something" and "the user moves the caret"/"the user inserts something at the caret position". They may both have selection at their base, but I have a feeling their are handled quite differently by editors:

  • Caret movement/character insertion at caret place: The automatic caret positioning is almost entirely disregarded. At least one has a function in there that checks after each insertion or caret movement where the caret is and if it is not where one wants it to be, one moves it. For character insertions in places where the caret won't go by itself, it is not an uncommon practice in the JS code to first insert something in the place where one wants the character to go and highlight that, and then let the insertion event go which means that the new character will overwrite what one puts there in the meantime. If one tries to do several complex things simultaneously (for example: track changes, move caret around non-editable islands and islands with lakes, and collaborative with other users users by sending diffs over the networks) one may end up changing the selection programmatically up to 10-20 times in the process of inserting just a single new character. If one needs to move the caret to places where the browser refuses to draw it (between two SVGs, for example), moving the caret there can for example be achieved by inserting a zero-width space character there and removing it again when the caret goes somewhere else. Caret movement therefore at times also means content insertion/deletion.
  • Content selection: The user marks part of the content -- part of a sentence or several paragraphs. Here I have felt little need for intervention on the part of the JS code, at least as long as the user does nothing more. Should the user decide to want to delete the selected content or alike, the JS code likely will need to intervene again.

@johanneswilm
Copy link
Contributor Author

PS: Another difficulty with browsers that insert content and have restrictions on where carets can go in even slightly different ways is trying to synchronize them.

  • If two users on two different computers with different browsers are writing in the same document, one after another, one can have a "cleanup" function that cleans the content before the editing process starts and before saving it.
  • If two users on two different computers with different browsers are writing in the same document simultaneously, and the browsers need the content in different ways, it's not enough to just send diffs to the DOM back in forth. Instead, one needs to keep the document in a browser-independent format managed by the JS and synchronize between the DOM and this browser-independent format always when there is reason to believe there has been a change to one of them. For this there need to be distinct translators between DOM and browser-independent format for each of the four main browsers, if one wants to support all of them. The browser independent format then needs to synchronize with all the other participants in the editing process through some type of Operational Transformations. It's almost an MVC-model, but because the DOM is both used to render the current state of the document AND to record changes to it, it is a somewhat more messy process.
    If, instead, one could guarantee that all browsers are happy with the exact same DOM structure and also handle insertions/deletions the same way, one would be able to remove at least one level of complexity.

@ctalau
Copy link

ctalau commented Jun 4, 2015

I was talking about caret movement without necesarily inserting something right away. In the examples I gave, I simply would not want it to blink there.

At least one has a function in there that checks after each insertion or caret movement where the caret is and if it is not where one wants it to be, one moves it.

Does there exist an open-source implementation that moves the caret in block-direction in an arbitrarly styled HTML content?

@johanneswilm
Copy link
Contributor Author

Does there exist an open-source implementation that moves the caret in block-direction in an arbitrarly styled HTML content?

@ctalau: Yes

  • The Aloha editor 2.0 [1] is GPL and it is built on top of standard selections but without contenteditable drawing their own caret, so they must do this themselves (btw, they don't do it well yet). Their solution is to only allow one caret position per collapsed range (at start of line rather than the end), which means they don't have to deal with the problem of not knowing where the caret is placed.
  • CodeMirror [2] is licensed MIT can do block direction movement of the caret the way you showed in your demo. It has used several techniques to make editing work, and lately it has introduced contenteditable as part of one their modes, but it's still a hidden part of the total infrastructure and you don't get to see the contenteditable part directly. They solve the block-moving issue by controlling line breaking as well as the caret themselves in JS. I don't even know if they use the normal selection API.

[1] http://www.alohaeditor.org/demo/aloha-ui/
[2] http://codemirror.net/demo/variableheight.html

Btw -- in the cheapscape implementation I "only" spent about a year on programming for Fidus Writer, we let the browser handle the movement and only when it's done, we adjust the caret placement to go where it really "should" be. This approach seemed useful for a long time, but I have realized quite a while ago that this is unsolvable. Possibly it could be made to work by constantly having a 3-4 developer team monitor the state of all browsers and always fix everything when something changes, but that's just resources we don't have. Which is why we need to switch... to one of the already existing editors for that part. The problem with that is that none of them are able to do all the things we need (track changes, collaborative editing, non-editable islands, mathjax, comments, etc.).

@rniwa
Copy link
Contributor

rniwa commented Jun 4, 2015

@ctalau : the problems you've listed are extremely useful. It looks like me that the bulk of issues can be resolved if we introduced new values for user-select CSS property, or added a hook like beforeselect event that let JS modify the new selection. I've filed w3c/selection-api#45 and w3c/selection-api#46 to track those two.

Saving/restoring selection state is covered in w3c/selection-api#42.

@johanneswilm
Copy link
Contributor Author

Oh those seems like real bugs that need to be fixed in each browser, and that's something we can definitely spec (how caret behaves around non-editable content).

@rniwa The non-editable contents is just one example in that bug report [1]. Other issues are movement around inline SVGs, inline canvas elements and inline non-editable elements with editable islands. Where do you think such a specification should go?

[1] https://bugzilla.mozilla.org/show_bug.cgi?id=873883

@rniwa
Copy link
Contributor

rniwa commented Jun 4, 2015

Definitely, selection API. That's the spec for defining the selection behavior in general.

@johanneswilm
Copy link
Contributor Author

@rniwa: Ok, so will you add it there? Will fixing this not break anything that exists so far?

@rniwa
Copy link
Contributor

rniwa commented Jun 4, 2015

Well, that's up to the WebApps working group, the author of the specification. I'm just an editor; my job is to document the consensus of the working group. I can't decide what goes into the spec. Of course, I haven't updated the spec in a while since I've been busy with other stuff but I'm intending to get back to it in a couple of months (hopefully before F2F in Warsar).

@johanneswilm
Copy link
Contributor Author

@rniwa Sure the WG can can overrule a proposal from you to add this. But you agree that this should be specified, right? The same way you added an issue for w3c/selection-api#46 , could we also add an issue for this? I hadn't looked at the issue list of the selection API and I now notice that I added a number of things with examples there about half a year ago. Some of the things mentioned in issues there are the same things we have been mentioning here.

@rniwa
Copy link
Contributor

rniwa commented Jun 4, 2015

Yes, I agree. This should be spec'ed in selection API spec. Since I'm not too familiar with what kind of issues exist with inline SVG, etc... it would be best if you could file new issues.

@fredck
Copy link

fredck commented Jun 8, 2015

@rniwa, @johanneswilm, the whole discussion has been maybe way too noisy, unnecessarily. The root of the problem is that currently browsers don't have any specification to follow and so each one defines its own rules when implementing caret behavior. Therefore spec'ing it makes sense, even if good part of the documentation will state that "it should mimic the platform behavior".

Note that we're much probably not talking about the API specs (which ofc will be included) but about spec'ing the default expected behavior of UAs... default behavior hopefully built on top of the API, so it can be fully overriden by js.

@johanneswilm
Copy link
Contributor Author

@rniwa @fredck If I understand @rniwa correctly, everything that has to do with caret movement has been transferred to the selection API, which means that caret movement in contenteditable=Typing and and ce=true will be the same. I am totally OK with having predefined behavior that is platform dependent, as long as we have ways to override that. The most difficult thing in that respect that I know of has been moving the caret in the block direction. Now that it seems like we will get information about the caret placement (start or end of the line: w3c/selection-api#32 ), this should no longer be a problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants