Comments (25)
solution was: last input event of IME-construction will be cancelable IF the answer to the above investigation is "yes".
from input-events.
It's possible for Chrome to save the original text and insert back when cancelled, but I think it's making the default action confusing.
e.g. JS might want to do one of the following things by preventing default:
- Prevent text insertion/modification
- Apply custom text insertion
With the current plan the following script (for doing 2.) will not work as Chrome will try to put back the original text after:
document.addEventListener('beforeinput', event => {
if (event.inputType.indexOf('insert') == 0) {
event.preventDefault();
insertNewText(event.data);
}
});
Would it be better if we just clear the marked text when canceled, and let JS put back original text if they want? Assuming it's not too hard to grab original text during 'compositionstart'.
In this way, both 1. and 2. won't be too hard to achieve.
from input-events.
It's possible for Chrome to save the original text and insert back when cancelled, but I think it's making the default action confusing.
This is on Android?
For desktop IME, when IME is only used for input of new characters, my tests seemed to indicate that the browser is removing the entire composed character string, before reinserting it.
If this is not what is happening on all platforms, and the beforeinput event comes before any new content has been removed (removal only happens if the event is cancelled), then I agree, this doesn't make a ton of sense.
Would it be better if we just clear the marked text when canceled, and let JS put back original text if they want? Assuming it's not too hard to grab original text during 'compositionstart'.
Recompositioning text can go across element boundaries. For example in this case:
This <b>is a tes</b>t.
If the user taps on "test", then the word "test" will be loaded into the IME and probably either be moved entirely into the <b> , or it will go entirely outside of it. After the composition is done, it may therefore look like this:
This <b>is a </b>seahorse.
So the JS really needs to grab at least the entire block element including all its markup at composition start and then employ some kind of dom aware diffing mechanism to figure out what has changed, and probably even quite a bit more to interpret what the user was trying to do with that change. So altogether, that doesn't look like such a great solution for the JS author.
Would it not be possible to add some information to the beforeinput event that will let the JS revert the effect of the composition AND that makes it clearer what the user intended to do? If we oculd egt that information, so we don't need to employ complex diffing mechanisms in JS, then I think it would be OK for the cancel event to basically have no effect other than to remove the underlining.
from input-events.
@choniong: Would it maybe be possible to add a method to that last, cancel-able beforeinput event within composition which reverts any changes made within the composition?
Depending on what works best for browsers, this could be done either synchronously:
document.addEventListener('beforeinput', event => {
if (event.isComposing && event.cancelable) { // Best guess as to whether this is the last input event in the composition until there is a specific inputType
let revert = event.revertComposition();
let targetRanges = revert.getTargetedRanges();
// Handle insertion of composition
myInsertCompositionFunction(event.data, targetRanges);
}
});
or asynchronously:
document.addEventListener('beforeinput', event => {
if (event.isComposing && event.cancelable) {
event.revertComposition().then(function(revert){
let targetRanges = revert.getTargetedRanges();
// Handle insertion of composition
myInsertCompositionFunction(event.data, targetRanges);
});
}
});
from input-events.
Sorry for the late reply, I was trying to figure out possible solutions for this issue...
@choniong: Would it maybe be possible to add a method to that last, cancel-able beforeinput event within composition which reverts any changes made within the composition?
I can see how revertComposition()
would be useful, where JS can simply apply replacement algorithm after that. However I'm not sure whether this method should belong to InputEvent
.
@dtapuska suggested that we could support this mechanism in UndoManager
, where JS can query a stack ID during compositionstart
, and having an API to perform a series of Undo
s until reaching the given stack ID. WDYT?
Recompositioning text can go across element boundaries. For example in this case:
This is a test.
If I understand correctly JS wants to apply replacing text on original styled text after composition.
In other words Android IME is replacing text, Desktop IME is inserting text.
Since currently we don't UndoManager
, please see the following proposal for an alternative solution.
Proposal
Introduce additional beforeinput
before compositionstart
on Android, where
inputType
='deleteByComposition'
(or'deleteByIME'
,'markedByComposition'
)dataTransfer
= NULLdata to be removed, contains similar rich text info as Copy/Cut- cancelable. If canceled, the original text will stay, and IME will start with a copy of original text.
In this way we consider starting composition from existing text as
- Remove original text from DOM
- Start composition
- Update composition with original text
And canceling the last beforeinput
will only prevent inserting confirmed text.
Use Cases / Pros
- Canceling both
'deleteByComposition'
and the lastbeforeinput
will keep DOM unchanged
1. Editing text across boundary
* JS could listen to 'deleteByComposition'
and keep dataTransfer
, which should contain
similar data got from Copy/Cut, with all the necessary styles.
* During the last beforeinput
, JS could either
* Re-insert dataTransfer
using insertHTML
, or
* Just compute diff between new confirmed text and original dataTransfer
* This might also make it possible to solve https://crbug.com/620549 from JS side.
2. Easier to Implement cE=Caret
* One could just call preventDefault()
on all beforeinput
, and DOM will keep unchanged from user actions (except temporary IME composition)
Cons
- Calling
preventDefault()
on'deleteByComposition'
will cause a duplication of text- e.g. Original text and the copy of composition text
- Not sure if it will harm though
from input-events.
I can see how
revertComposition()
would be useful, where JS can simply apply replacement algorithm after that. However I'm not sure whether this method should belong toInputEvent
.
I can see how such a method would seem somewhat odd placed right there, so I'm not opposed to the idea to put it somewhere else.
@dtapuska suggested that we could support this mechanism in
UndoManager
, where JS can query a stack ID duringcompositionstart
, and having an API to perform a series ofUndo
s until reaching the given stack ID. WDYT?
That may indeed work. There are some potential issues with this though:
- It seems like we are not really using the browser-built-in undo manager in contenteditable at all -- so we may end up wanting to remove it some day and then we are stuck keeping it around for this reason.
- We still need to the target ranges. The static ranges contains constants and links to nodes. If we simply record the targetranges at composition start and then try to use them after going through the undo stacks, the constants should be the same, but can we really know if the same nodes are in the DOM? Likely not.
Take for example:
<p>This is a w<b>o</b>rd.</p>
With these three text nodes (T1-T3):
(<p>T1<b>T2</b>T3</>)
User touches the word "word". The getTargetranges for the first composition inputevent will give us a start in T1 and an end in T3. We store this static range as S1. As part of the composition, the DOM is mutating into:
<p>This is a word.</p>
(<p>T1</p>)
When the composition is done we would end up with:
<p>This is a sword.</p>
So at the very last, cancelable insertion event we have:
<p>This is a |.</p>
data = sword
Now we ask the undo manager to return to the state before the composition started and up with possibly:
<p>This is a w<b>o</b>rd.</p>
(<p>T1<b>T4</b>T5</p>)
I assume the browser cannot resurrect T2 and T3 that were removed from the DOM at the start of the composition, and will instead create new text nodes (T4/T5) to have the same contents. The problem is just that the S1 we kept from the start refers to T3, which no longer is in the DOM.
There is a way to get around this in JS, by converting the static range S1 in the beginning where one replaces the pointers to T1/T3 with a description of to reach these nodes by walking the DOM tree, and then uses that description as part of the very last step to find nodes T1/T5. It's possible, but it requires quite a lot of logic on the JS side. Also, if one wants to prevent the tree walking mechanism from getting overly complicated, one will likely want to prevent all other DOM changes during the composition.
Proposal
This solution will have the same issue of the target ranges, won't it?
dataTransfer
= data to be removed, contains similar rich text info as Copy/Cut
dataTransfer isn't defined for cut operations currently. It's only for inserting content that we use it.
Re-insert
dataTransfer
usinginsertHTML
Are you referring to execCommand here? If you insert html across element boundaries, you will again have the problem of the browser doing element merging, and you cannot really guarantee that the end result is as it was before the composition started. Also, execCommand is generally avoided by JS developers because it tends not to work. I think we are moving away from execCommand as much as possible, so it would really be preferable to use some command outside of execCommand instead of try to reuse an execCommand command that has legacy code depend on its particular quirks.
Just compute diff between new confirmed text and original
dataTransfer
So we would use the original targetrange, transformed as described above, and then use the data from this last event, and diffed the DOM back to it's original state? I think that may work, but it will require quite a lot of diffing/transformation operations on the side of the JS. We may end up with a situation where IME text input is just not supported in many editors, or only supported for European scripts, which is kind of what we wanted to move away from.
Still, both of these proposals are better than the current situation, I think.
from input-events.
Still, both of these proposals are better than the current situation, I think.
Actually, thinking about ti again, I don't think this will be change the current situation much. What they will do is what they currently do:
Editors with a data model
Will take a copy of the paragraph at composition start, and another at composition end, diff the two and calculate an atomic update.
Simple editors without a data model
If they don't have a DOM-aware diffing mechanism, they will likely default to not handling IME.
So I agree that revertComposition would be kind of oddly placed so we may have to find another place to put something similar. But unless the mechanism also returns what corresponds to the original targetrange, it will still require a rather complex JS editor to handle IME.
from input-events.
@choniong @dtapuska : Would it seem more "normal" if we had a method on the compositionend event that would allow rollback of the composition and return a targetrange and a data attrribute with the updated composed character?
from input-events.
It seems like we are not really using the browser-built-in undo manager in contenteditable at all -- so we may end up wanting to remove it some day and then we are stuck keeping it around for this reason.
OK, makes sense...
We still need to the target ranges. The static ranges contains constants and links to nodes. If we simply record the targetranges at composition start and then try to use them after going through the undo stacks, the constants should be the same, but can we really know if the same nodes are in the DOM? Likely not.
It seems to me that Chrome will put back the original node, see RemoveNodeCommand::doUnapply(). But yes we shouldn't rely on that.
dataTransfer= data to be removed, contains similar rich text info as Copy/Cut
dataTransfer isn't defined for cut operations currently. It's only for inserting content that we use it.
Sorry for the confusion. I was trying to say that this dataTransfer
should contain similar data to Clipboard API, as if the user pressed Ctrl-C
then Ctrl-V
.
e.g. For
<p>This is a w<b>o</b>rd.</p>
If you tap on word
, the dataTransfer
would contain something like
"text/html"=`<meta charset='utf-8'><span style="color: rgb(0, 0, 0); font-family: ....">w</span><b style="color: rgb(0, 0, 0); font-family: ...">o</b><span style="...">rd</span>`
If the editor has the ability to process insertFromPaste
it should be able to process this data, however I'm not sure if that's useful though.
Re-insert dataTransfer using insertHTML
Are you referring to execCommand here?
Or insert back into editor's data model with the similar method as how insertFromPaste
would be handled.
Just compute diff between new confirmed text and original dataTransfer
I mean if the original text is w<b>o</b>r<i>d</i>
and the new text is work
, we could keep the prefix and insert w<b>o</b>rk
directly (without going back to the original state and then replace).
from input-events.
Actually I guess I don't quite understand the pain point here, aren't we trying to get rid of DOM-aware diff mechanism?
Also it would be nice if we can have an example (or maybe a link to the bug?) where going back to the original state is necessary.
Here is one I can think of:
NYTimes/ICE has the ability to track changes, where deleted text are crossed, and new text are underlined. And unfortunately it doesn't work for IME.
To implement it using beforeinput
, a simple approach would be: (without knowing the existence of IME)
function handleDeletingText(ranges, sourceInputType) {
addDeletionStyle(ranges);
moveCaretAfterDeletion(ranges, sourceInputType);
}
document.addEventListener('beforeinput', event => {
if (!event.cancelable)
return;
if (event.inputType.indexOf('delete') == 0) {
event.preventDefault();
handleDeletingText(event.getTargetRanges() || getCurrentSelection(), event.inputType);
} else if (event.inputType.indexOf('insert') == 0) {
event.preventDefault();
handleDeletingText(event.getTargetRanges() || getCurrentSelection(), event.inputType);
handleInsertingText(event.data);
}
});
Example result (Mock result from desktop):
Tap word
(deleteByComposition
was canceled):
(The first word
is original text, and the second one is composition)
In additional, if the editor has the ability to handle replacing text (e.g. Select some text and paste) and has some knowledge about IME, it could be written as:
var originalTextRange = null;
document.addEventListener('beforeinput', event => {
if (!event.cancelable)
return;
if (event.inputType.indexOf('delete') == 0) {
event.preventDefault();
if (event.inputType == 'deleteByComposition') {
originalTextRange = event.getTargetRanges();
addPendingStyle(originalTextRange);
} else {
handleDeletingText(event.getTargetRanges() || getCurrentSelection(), event.inputType);
}
} else if (event.inputType.indexOf('insert') == 0) {
event.preventDefault();
removePendingStyle(originalTextRange);
let ranges = originalTextRange || event.getTargetRanges() || getCurrentSelection();
handleReplacingText(ranges, event.data);
}
});
Example result:
Tap word
(yellow background means pending text):
Choose suggested word work
and apply replacing algorithm:
from input-events.
That may indeed work. There are some potential issues with this though:
It seems like we are not really using the browser-built-in undo manager
in contenteditable at all -- so we may end up more or less removing it some
day and then we are stick keeping it around for this reason.
I was thinking that this could be solved by exposing the frame's undo redo
manager. But I think there are problems with cross frame Undo/Redos we were
talking about before; so the undo/redo manager is all a can of worms. But I
was wondering if we could punt the issue to be dependent on an API for that.
We still need to the target ranges. The static ranges contains constants
and links to nodes. If we simply record the targetranges at composition
start and then try to sue them after going through the undo stacks, the
constants should be the same, but can we really know if the same nodes are
in the DOM?
Once any DOM mutation occurs a static range isn't good anyways. So I'm not
sure keeping the static range around is good for any reason.
dave.
On Thu, Sep 15, 2016 at 6:31 PM, Johannes Wilm [email protected]
wrote:
I can see how revertComposition() would be useful, where JS can simply
apply replacement algorithm after that. However I'm not sure whether this
method should belong to InputEvent.I can see how such a method would seem somewhat odd placed right there, so
I'm not opposed to the idea to put it somewhere else.@dtapuska https://github.com/dtapuska suggested that we could support
this mechanism in UndoManager, where JS can query a stack ID during
compositionstart, and having an API to perform a series of Undos until
reaching the given stack ID. WDYT?That may indeed work. There are some potential issues with this though:
It seems like we are not really using the browser-built-in undo
manager in contenteditable at all -- so we may end up more or less removing
it some day and then we are stick keeping it around for this reason.
2.We still need to the target ranges. The static ranges contains
constants and links to nodes. If we simply record the targetranges at
composition start and then try to sue them after going through the undo
stacks, the constants should be the same, but can we really know if the
same nodes are in the DOM?Take for example:
This is a word.
With these three text nodes (T1-T3):
(
T1T2T3</>)
User touches the word "word". The getTargetranges for the first
composition inputevent will give us a start in T1 and an end in T3. We
store this static range as S1. As part of the composition, the DOM is
mutating into:This is a word.
(
T1
)When the composition is done we would end up with:
This is a sword.
So at the very last, cancelable insertion event we have:
This is a |.
data = sword
Now we ask the undo manager to return to the state before the composition
started and up with possibly:This is a word.
(
T1T4T5
)I assume the browser cannot resurrect T2 and T3 that were removed from the
DOM at the start of the composition, and will instead create new text nodes
(T4/T5) to have the same contents. The problem is just that the S1 we kept
from the start refers to T3, which no longer is in the DOM.There is a way to get around this in JS, by converting the static range S1
in the beginning where one replaces the pointers to T1/T3 with a
description of to reach these nodes by walking the DOM tree, and then uses
that description as part of the very last step to find nodes T1/T5. It's
possible, but it requires quite a lot of logic on the JS side. Also, if one
wants to prevent the tree walking mechanism from getting overly
complicated, one will likely want to prevent all other DOM changes during
the composition.Proposal
This solution will have the same issue of the target ranges, won't it?
- dataTransfer= data to be removed, contains similar rich text info as
Copy/CutdataTransfer isn't defined for cut operations currently. It's only for
inserting content that we use it.Re-insert dataTransfer using insertHTML
Are you referring to execCommand here? If you insert html across element
boundaries, you will again have the problem of the browser doing element
merging, and you cannot really guarantee that the end result is as it was
before the composition started. Also, execCommand is generally avoided by
JS developers because it tends not to work. I think we are moving away from
execCommand as much as possible, so it would really be preferable to use
some command outside of execCommand instead of try to reuse an execCommand
command that has legacy code depend on its particular quirks.Just compute diff between new confirmed text and original dataTransfer
So we would use the original targetrange, transformed as described above,
and then use the data from this last event, and diffed the DOM back to it's
original state? I think that may work, but it will require quite a lot of
diffing/transformation operations on the side of the JS. We may end up with
a situation where IME text input is just not supported in many editors, or
only supported for European scripts, which is kind of what we wanted to
move away from.Still, both of these proposals are better than the current situation, I
think.—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#17 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AJ7KREq8RVbvJV7Y_eLNl-BJ8wHMynnfks5qqcdIgaJpZM4Js3LG
.
from input-events.
NYTimes/ICE has the ability to track changes, where deleted text are crossed, and new text are underlined. And unfortunately it doesn't work for IME.
If you check the commit history, you will see I wrote a great part of it (the part that made it compatible with Chrome). But unfortunately it's unfixable: We set up a great number of tests and then made changes here and there until it would pass all the tests in all the browsers and would then have to add code here and there with every new browser release. But it's a nightmare spaghetti code and it breaks every time one of the supported browsers changes any of their contenteditable code.
ICE is also somewhat out of date because it built on the old, and simpler editor system where TinyMCE and CKeditor tried to just fix the output of contenteditable. (ICE was made to work with both of these). The newer and more complex model, found in the next generation of CKeditor and editors like ProseMirror or Substance.io based all their editing on a data model where each user input operation must be translated into a commit that can then be applied to the data model, wghich in turn can be turned into a change of the DOM.
As for your above code example: I don't think you can get around handling every inputtYpe individually, and you will likely still end up with a few thousand lines of code, even for a rather simple editor, but at least one would be able to handle IME more or less OK.
Actually I guess I don't quite understand the pain point here, aren't we trying to get rid of DOM-aware diff mechanism?
I think this takes us back to the fundamental question of why we create this new beforeinput event at all. The basic premise for all this seems to be that browsers cannot be trusted to make the DOM changes within the editable element that the JS editor needs to do. Therefore we created an event which allows to cancel the browser's automatic changes to the DOM and instead allow for managing the changes to the DOM in JavaScript.This task can be divided into two sub categories:
a) Handling changes of the structure of the text due to the user's clicking things in browser-builtin menus or hitting keyboard shortcuts that the browser is setup to handle automatically. This part we seem to have pretty well under control, with the exception of the many extra options that Safari has in its menus.
b) Handling text input. This part we can handle for b1) keyboard input, but that wasn't too difficult before either. The challenge here is for us to make this equally simple for b2) IME and that's what we are trying to achieve here. Unfortunately IME doesn't allow for canceling DOM-changes, so just for IME we have to follow a different model: the entire IME input has to be wrapable into a single commit that we can hand over to the JS to handle. Because the JS editor relies on being the only thing that does all changes to the DOM within the editable element, we need to revert to the previous state before we hand over this atomic change to the JS.
Did that make it clearer? If you want to, I can try to find the places in the code of the above mentioned editors where they handle IME input (as far as they do).
from input-events.
Once any DOM mutation occurs a static range isn't good anyways. So I'm not
sure keeping the static range around is good for any reason.
@dtapuska: If you look at my proposed method above, it would both return the DOM to its state as it was before the IME composition AND it would return a new target range, so that the JS can take this new target range and the data attribute form the beforeinput operation and then handle the entire IME operation all as one atomic commit.
But I do agree with you guys that putting this method there would be a little odd.
from input-events.
Sorry for the confusion. I was trying to say that this
dataTransfer
should contain similar data to Clipboard API, as if the user pressedCtrl-C
thenCtrl-V
.
e.g. For<p>This is a w<b>o</b>rd.</p>
If you tap on
word
, thedataTransfer
would contain something like"text/html"=`<meta charset='utf-8'><span style="color: rgb(0, 0, 0); font-family: ....">w</span><b style="color: rgb(0, 0, 0); font-family: ...">o</b><span style="...">rd</span>`
Two questions:
- Is it strictly necessary for the dataTransfer to contain HTML that is so different from what is in the DOM? Could we not just remove all the extra attributes, etc.? How can we differentiate between these attributes as being just auto-added by the browser in the cut/paste process and elements that really happen to have style attributes with such values?
- I am not sure I can follow you on why the dataTransfer would contain anything when you tap "word". If it would work similarly to how cut and drag work, it should not have any data or dataTransfer values and just a targetRange that refers to the DOM structure before the change has taken place, right? The last beforeinput for an insertion that is cancel-able would on the other hand have either a data or a dataTransfer attribute with the fully composed character/word. Most likely this should just be a data attribute, at least for those IMEs that only produce strings. Correct?
If the editor has the ability to process
insertFromPaste
it should be able to process this data, however I'm not sure if that's useful though.
I think those are somewhat different. Rolling back the IME input and using it with the original information on a target range relies on this process return exactly what one had before. So that would include having sibling text nodes recreated exactly as they were, sibling elements of the same type recreated as they were, etc. Pasting, on the other hand, requires a lower level of compatibility.
Take for example an editor that wraps every word into a span element and then tracks how all the span elements move around:
<p><span>hey</span><span> </span><span>world</span></p>
If the user pastes something form another document, the system is set up to then go through all that text and input spans and update it's lists of existing spans. If one clicks on one of these words to get it into an IME and then finishes the operation there, and one just has the HTML <span>word</span>
to insert into <p><span>hey</span><span> </span>|</p>
trying to do this through execCommand or some other browser method, the browser wouldn't be able to tell whether or not it can merge this span with the previous span. Of course one could exploit the same mechanism as for paste to create new spans around each word or space, but then our JS editor would no longer know whether this new span is the same span it tracked earlier or whether it is something entirely new. etc. Likely all of this could be fixed by adding some more JS code, but we will end up with quite a lot of code only to have a reliable mechanism to return to the structure as it was before the IME, and then it will likely mean that we will use the diffing mechanism, etc. that those editors that handle IME already use.
from input-events.
To implement it using
beforeinput
, a simple approach would be:
@choniong Text that is just within text node is mostly not that problematic. The issues start when it goes across them. For example let's say we have this:
<p>This a <span class="insert" user="hans">te</span>xt.</p>
And the user Peter touches the word "text" and changes it to "test". The browser will likely not understand the significance of the span. The cleanest way to deal with this on the part of the JS would be to simply receive the original DOM structure and together a target range that covers the span.insert and the "xt" and a data-attribute = "test".
from input-events.
Thanks for the explanation, I guess we'd better leave this to TPAC...
Just to summarize:
Issue
Android IME can start composition from existing text, and there is no easy way to revert back to the original state after composition.
Proposal 1
Introduce API revertComposition()
to go back to the original state, and return targetRanges
.
- Where the API should live is TBD.
Proposal 2
Introduce 'beforeinput' 'deleteByComposition'
and fired before 'compositionstart'
:
- Default Action: original text turns into marked(underscore) text
- Prevent Default: original text remains unchanged, but instead duplicate the text and add marks(underscore)
I am not sure I can follow you on why the dataTransfer would contain anything when you tap "word"
I was just trying to solve #17 (comment), where JS can have a reference about the original style, but yes it seems unnecessary and should be NULL.
from input-events.
@choniong Text that is just within text node is mostly not that problematic. The issues start when it goes across them.
Sorry just saw this, so with 'deleteByComposition'
it would be:
- Start
<p>This a <span class="insert" user="hans">te</span>xt.</p>
- Tap
text
and callpreventDefault()
on'deleteByComposition'
- Note how
text
was duplicated and the secondtext
is where composition happens
<p>This a <span class="insert" user="hans">te</span>xttext.</p>
- Tap suggested word
test
andpreventDefault()
on the lastbeforeinput
- Note that marked text will get removed
- The original
targetRange
should still work since DOM was reverted and nothing got removed&re-inserted.
<p>This a <span class="insert" user="hans">te</span>xt.</p>
- Handover to JS
But yes it's odd to have duplicated text...
from input-events.
I am not sure I can follow you on why the dataTransfer would contain anything when you tap "word"
I was just trying to solve #17 (comment), where JS can have a reference about the original style, but yes it seems unnecessary and should be NULL.
One could possibly extract the contents of the targetranges at the the time of the 'deleteByComposition'
event. But one probably couldn't differentiate between:
<p><b>testing </b>[<b>this</b>]</p>
and
<p><b>testing [this]</b></p>
from input-events.
Proposal 2
Introduce 'beforeinput''deleteByComposition'
and fired before'compositionstart'
:
- Default Action: original text turns into marked(underscore) text
- Prevent Default: original text remains unchanged, but instead duplicate the text and add marks(underscore)
So basically, IME constructions would turn two cancel-able edit operations: one that deletes, another that adds. @choniong Given thet the 'deleteByComposition'
happens before the composition starts, does that mean we can still move the caret (into a shadow DOm or alike), is that also impossible?
But yes it's odd to have duplicated text...
If the text really is there twice, I think the advantage of having inline IME disappears and it would seem better to simply have the construction happen in a little popup bubble. But maybe one could one apply "display:none" to the range that si to be replaced?
Also, I wonder how this would deal with canceling the composition before it's done. Or maybe that's not an option anyway?
from input-events.
- I don't see anything preventing us from moving the caret into a shadow
DOM or alike - Yes, JS can place it into a bubble or just hide the original text,
assuming JS is able to recover them - If the composition was canceled (e.g. Tap other locations) we should
still get the last 'beforeinput' with data= current marked text, so it
shouldn't harm IMO.
Sorry for the poor format, I don't have access to laptop right now.
from input-events.
Got it. So basically this should give us some new options for the creaters of any JS editor:
- The JS editor can move the entire composition process into a shadow DOM where it copies the contents of the current paragraph minus the part that was recently deleted, have the composition happen there and remove the shadow dom when the composition is done and turn the composition into one atomic operation which the JS can deal with further..
- The JS editor can move the composition into a "bubble" above the main text and have one atomic operation when the composition is done. Possibly that could even be made to work if the main text is being changed simultaneously due to updates from collaborators in a collaborative editor?
- The JS editor can treat the two operations deletion and insertion as two distinct atomic operations for Android users. This may feel slightly strange if the JS editor doesn't agree with deleting all parts of the initial word with parts of the word appearing twice. Also, it seems like under some circumstances Android users might click on a word, which is first deleted and then cancel the composition, and the JS part not handling that entirely correctly, for example if a word was partially styled.
This may all be good enough. It will require a fair bit of coordination in the JavaScript between the handling of the two beforeinput events to cover all edge cases, but unless there are cases we haven't thought off, that seems doable.
from input-events.
FWIW, adding (other than getter-like) methods to Events is kind of anti-pattern. It just doesn't tend to work well when there are several event listeners. (ServiceWorkers has added some methods to some events , but that doesn't mean it is a good idea.)
from input-events.
@smaug---- Yes, we have had to add at least one method already. But after we discovered some other information about partial commits in Japanese IMEs, and after I understood that the text doesn't actually have to be in the DOM twice, if one just removes it before the composition starts, I think we all agree to go with @choniong's proposal.
from input-events.
Which proposal? There are proposal 1 and proposal 2.
from input-events.
Proposal 2
from input-events.
Related Issues (20)
- Make "Input Events Level 1" declare "beforeinput cancelable" of "insertCompositionText" as "Undefined" HOT 27
- [feature request] Standardize long press touch event HOT 1
- InputType to insert image from software keyboard HOT 9
- Encourage browsers to include files in `beforeinput` DataTransfer event HOT 2
- Request: a way to get and react to target ranges for all changes HOT 6
- Add spec-prod GitHub Actions HOT 4
- Bug on Android Web. Input Value duplicates when typing too fast between input fields.
- Use new `[=xref=]` syntax for DND terms HOT 1
- Move to Jitsi for meetings? HOT 1
- inputType not specified for the input type="number" 'step up/down' event
- Gather informations on content replaced by insertReplacementText or trigger a deleteByReplacement event?
- Should the last beforeinput to occur before compositionend be cancellable? HOT 11
- Order and cancelation behavior of events in composition disagrees with UI Events
- InputEvent fired twice when inserted emoji HOT 5
- What is the intended/recommended approach to hijack composition events? HOT 2
- inputType on safari mobile is undefined HOT 2
- Proposal: better encapsulation of composition events HOT 1
- Adjustments for EditContext HOT 5
- Definitions for 'Update the DOM'/'Update the DOM element' HOT 2
- getTargetRanges of `beforeinput` differ between browsers (should not happen in EditContext) HOT 33
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from input-events.