w3c / editing

Specs and explainers maintained by the editing task force
http://w3c.github.io/editing/
Other
193 stars 40 forks source link

Preserving the integrity of the contentEditable's hidden state #223

Open Dalzhim opened 4 years ago

Dalzhim commented 4 years ago

Context Empirical observation of the behavior of different browsers and platforms reveals a hidden state associated with contentEditable elements. A simple example is the following:

  1. Insert a word such as "erase" by swiping on the keyboard on Android or iOS
  2. Hit backspace
  3. Reinsert the word "erase" by swiping again
  4. Insert a space
  5. Hit backspace twice

Observed behavior: Hitting backspace right after a swipe insert erases the whole word whereas hitting backspace at another time only erases a single character.

The problem This hidden state is not preserved when the DOM is being modified programmatically. This means that programmatically modifying the contents of a contentEditable at any time may lead to inconsistencies that cannot be prevented of remediated. Here is an example:

  1. Insert "erase" by swiping on the keyboard
  2. In the inspector, apply the following steps using the console
  3. $range = new Range()
  4. $range.selectNode(document.querySelector("[contentEditable]")
  5. $node = document.createElement("b")
  6. $range.surroundContents($node)
  7. Fix the selection's position by applying the following steps in the console
  8. document.getSelection().setBaseAndExtent($node, 1, $node, 1)
  9. Hit backspace on the device's keyboard

Observed behavior: A single character is erased. Expected behavior: A whole word is erased.

Why is this a problem? There are various use cases for which programmatic modification of the contents is required but unavoidably leads to interference with the user's ability to edit the contents in an intuitive way. Here are two important use cases:

  1. Range-based metadata: applying style on ranges of text to convey metadata and enable productivity features
  2. Collaborative editing: reproducing one user's changes on the other connected editors

What is the way forward?

I am not sure which is the best way forward at this point. I am bringing up those issues so that they can be discussed.

Dalzhim commented 4 years ago

Here is a clarifying note to emphasize why I believe this issue is important. I used a single example where a contentEditable element's hidden state is being interfered with when programmatic changes but there is a wide array of such cases. Here is a non-exhaustive list of such cases:

  1. Normal text insertion leads to autocomplete/autocorrect proposals being displayed to the user
  2. Swipe insertion leads to alternate proposals being displayed to the user
  3. Swipe insertion may provide autocorrect suggestion based on the two previous words (swipe insert "out home" and iOS suggests "our home" as a replacement)
  4. Normal text insertion knows to insert a space before a new character after a swipe insert has occured
  5. etc.
johanneswilm commented 4 years ago

On Android this seems to depend on the keyboard. Swiftkey doesn't seem to do this. Gboard does. Is this possibly an action that happens inside the IME that therefore depends on the decisions of that IME? If so, my guess that using EditContext will solve this, once we get that.

Dalzhim commented 4 years ago

I have read the EditContext proposal and it does look like an interesting effort to standardize the contents of the hidden state we have right now. It makes it easy to modify the EditContext when you have the intent to do so.

However, the complexity of understanding the current context and whether or not a modification to the DOM should or shouldn't change the EditContext will remain a very difficult problem. In the event of new advanced capabilities appearing in the future, relying on this API also means participating in a cat and mouse chase where user code must always catch up with the new latest advanced smart insertion mechanic that is being invented.

An alternate direction is to identify a set of mutations that can be performed on the DOM and where the user agent must do its best to preserve the EditContext as it is, without pushing the burden of knowing what is part of that context on the user code.

Should any further discussion be taken to the other repository or is this still the appropriate place?

gked commented 4 years ago

@Dalzhim I think, for the time being this thread should suffice. If you plan on participating in these discussions, would you please fill out this form for an invited expert status? I believe, Johannes has sent an email to working groups chairs already.

Dalzhim commented 4 years ago

I had to wait for internal approvals before I could apply for the invited expert status. I have now filled out the form! What's the next step?

gked commented 4 years ago

I had to wait for internal approvals before I could apply for the invited expert status. I have now filled out the form! What's the next step?

Sorry for delayed response. To my knowledge, this is all W3C needs. We have monthly calls where we seek to drive opened issues to resolutions. If you like to discuss an issue like this one, feel free to label it with Agenda+ and it will put the issue in the queue. And definitely, we can discuss this online in the meantime. Next meeting is on February 14th, at 9:00am Seattle, Washington time.