W3C home > Mailing lists > Public > public-editing-tf@w3.org > February 2017

Re: 2 Proposals for Minimum Viable InputEvent

From: Piotr Koszuliński <p.koszulinski@cksource.com>
Date: Mon, 13 Feb 2017 21:46:49 +0100
Message-ID: <CAFk9newXoavtNkDqbipsE--OPis9rso4y7kJ4JmRU=Vg0pH0oA@mail.gmail.com>
To: Alexandre Elias <aelias@google.com>
Cc: Johannes Wilm <johannes@fiduswriter.org>, Chong Zhang <chongz@chromium.org>, Dave Tapuska <dtapuska@chromium.org>, "public-editing-tf@w3.org" <public-editing-tf@w3.org>
>
>
> I believe this use case can only be solved by the long-term "full
> model/view/controller" IME solution yosin@ and I ultimately prefer,
> whereby IME talks to an invisible textbox "model" and JS maps it to any
> DOM/canvas/WebGL.  You need 100% separation between plaintext distillation
> and user-visible representation to do things like this, and none of the
> proposals on the table address it.
>

Just a quick question – I was worried about that "full mvc" IME solution
mentioned earlier. Hopefully, you don't mean to force normal RTE editors
(which renders and reads from the same cE element) to use that invisible
textbox? :) AFAIR Google Docs is using such a solution, but this sounds
really bad. It may solve some issues, but triggers an entire spectrum of
issues with which we don't have to deal currently like positioning of that
textbox, rendering IME's controls and text styling.


>
> > For example, how do we handle the backspace and delete keys now? We
> listen to keydown, discover which key was pressed and with what modifiers
> and delete the content. We might not be able to implement "delete word" or
> "delete soft line" very precisely, but these are really minor issues. So,
> in this case the before input wouldn't give us anything. Actually, it'd be
> even worse than listening to the keydown event because we can cancel the
> keydown event.
>
> Acknowledged, the backspace-to-delete-line problem is quite familiar to
> me.  Note that on Android, IME typically send deleteSurroundingText(1, 0)
> IME event when soft backspace key is pressed, or even
> setComposition("hell") (if previous text was currently-being-composed
> "hello").  So some amount of JS hackery for rich backspace seems
> unavoidable, unfortunately.
>

I'm ok with some JS hackery :). If hacking is possible, it means that
there's some solution. Currently, many issues we're dealing with have no
feasible solutions.


> > However, there's one nasty case which may still require hacking if the
> event isn't cancelled. It's how the editor can delete the content itself
> when the user is typing over a non-empty selection. We can't let the
> browser do that because we wouldn't know how to convert those changes to
> the model (and sometimes it might simply be impossible).
>
> Understood.  I'm not a fan of the solutions to this issue proposed so far,
> but how about this: what if we extend "getTargetRanges()" to work on the
> "input" event (not only "beforeinput") to indicate what range of text has
> just been inserted?  That should provide the same information as the
> "deletion/insert" split option, without adding one of those "phantom"
> events I dislike.  Knowing precisely what range has just been inserted,
> your JS could then remove it from DOM, apply your deletion reconciliation
> algorithm, and then reinsert it.
>
>
>
I think that fixing the DOM on the input event is too late. Taken that we
must not touch the DOM if composition takes place (because this breaks
composition), let's consider this scenario:

1. Initial content: <h1>fo[o</h1><p>b]ar</p>.
2. User presses "x". Let's say this should trigger composition start.
3. Browser fires beforeinput, but we can't do anything now (we can't cancel
it).
4. Browser deletes the selected content ("o" and "b") and inserts "x".
However, it also applies arbitrary DOM changes – e.g. – it merges both
blocks: <h1>fo[x]ar</h1>.
5. Browser fires the input event.
6. Now, JS editor kicks in. It gets the target ranges – [x] – and, tries to
handle the insertion of the "x" character. But, its internal model still
contains the initial structure: <heading
level=1>fo[o</heading><paragraph>b]ar</paragraph>.
7. First, JS editor engine calls its internal deleteContent( selection )
algorithm which results in: <heading
level=1>fo[]</heading><paragraph>ar</paragraph>.
8. Now, the JS editor engine inserts the "x" character: <heading
level=1>fo[x]</heading><paragraph>ar</paragraph> (I'm assuming that the JS
engine knows that the composition takes place and "x" must be selected).
9.  Finally, the engine renders the model to the virtual DOM and the
problem appears. The virtual DOM differs significantly from the real DOM.
In the virtual DOM we have <h1>fo[x]</h1><p>ar</p> while in the real DOM we
have <h1>fo[x]ar</h1>.

And this is a stalemate. We can't touch the DOM at this point because this
is going to break the composition and the DOM is significantly different
than the editor's model. Hence, JS editor must be able to prepare the DOM
for "x" insertion before browser triggers its internal delete content
mechanisms.

You said that you don't want (and/or can't) to split the beforeinput
beginning the composition into "delete" and "insert" parts. So, how about
the alternative option in which the JS editor will, based on the
beforeinput event, prepare the DOM for "x" insertion.

In this case, the above scenario would look like this:

1. Initial content: <h1>fo[o</h1><p>b]ar</p>.
2. User presses "x". Let's say this should trigger composition start.
3. Browser fires beforeinput.
4. The JS editor checks that the selection isn't empty and triggers its
internal deleteContent( selection ) algorithm which changes its internal
model
    * from: <heading level=1>fo[o</heading><paragraph>b]ar</paragraph>
    * to: <heading level=1>fo[]</heading><paragraph>ar</paragraph>
5. The change to the model is rendered to the virtual DOM and then straight
to the real DOM resulting in: <h1>fo[]</h1><p>ar</p>
6. The beforeinput wasn't cancelled (because it couldn't be), so the
browser continues its work. It calls its internal delete content mechanism
(but the selection is empty so nothing happens) and then it inserts "x".
This results in: <h1>fo[x]</h1><p>ar</p>. Composition is started.
7. The input and compositionstart events are fired.
8. One one of them, the JS editor inserts "x" to its internal model, which
results in: <heading level=1>fo[x]</heading><paragraph>ar</paragraph>. This
renders to the virtual DOM, but the real DOM doesn't have to be touched
because it's identical.

The above algorithm would be acceptable from our POV. We just need to be
able to act on beforeinput and to somehow learn that we need to insert "x"
to our model.

Do you think that you the browser engine could allow us to do that?
Received on Monday, 13 February 2017 20:47:54 UTC

This archive was generated by hypermail 2.3.1 : Monday, 13 February 2017 20:47:55 UTC