- From: Piotr Koszuliński <p.koszulinski@cksource.com>
- Date: Mon, 13 Feb 2017 21:46:49 +0100
- 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>
- Message-ID: <CAFk9newXoavtNkDqbipsE--OPis9rso4y7kJ4JmRU=Vg0pH0oA@mail.gmail.com>
> > > 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