You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I showed how this method could be useful to editor implementors for altering the default caret movements without breaking internals like selection's X position: w3c/editing#56 (comment) (see point 3).
I'd jus like to chime in here and say that we use this at https://usecanvas.com quite heavily (we're working on polyfills for some browsers, still). We are a contenteditable-based editor, but as part of our effort to rely on its default behaviors as little as possible, we use Selection.modify(). Each of our document lines actually is a separate contenteditable element, and we use Selection.modify() to navigate between them based on user input.
We'd of course like to not rely on this API, but it's helped us achieve some significant simplifications in our editor.
I think the tricky part is spacing the actual behavior. I mean, I can just add text with the supported strings with some vague text like it moves the selection forward by character for modify('move', 'forward', 'character') if people think that's valuable.
Perhaps an unorthodox but practical way to go about this would be to find the tests for this in WebKit, convert+upstream those into a web-platform-tests PR to go with the spec change, and work backwards from what fails in Chrome or Firefox to see what parts of the spec should exactly match WebKit, and where we need to think about it.
A lot of work, I know. IMHO just having the surface-level API with a big FIXME would be a slight improvement on the current situation, if nobody has time to dive deep within the next few months.
Well, the problem here is that there appears to be a fundamental disagreement about what these APIs are for. Gecko, for example, has one behavior for how a whiteface around a word is treated in languages in which a word boundary is defined by white spaces across all platforms for modify() even though selection will be moved and extended differently on Mac & Windows by the user. WebKit (and Blink) for most part respected each platform's convention with regards to the treatments of whitespace even in modify.
Furthermore, moving caret or extending selection across word boundary is a fundamentally non-interoperable feature because the definition of a word boundary is not set in stone in many languages. For example, in Chinese and Japanese, there are no syntactical hint or mechanism to define a word boundary. As such, ICU relies on a bunch of heuristics and dictionary lookups to determine where the word boundary might be. This in turn means that each browser & platform has a different definition of what a word boundary means.
Would it be possible to define abstract operations whose general semantics are clear, but which allow for deviations based on platform conventions or user preference? The spec could invoke those, and we wouldn't be able to write tests for all of it, but if for example all implementations agree about the behavior of Latin script, at least that much could be asserted. Or if there are only 2-3 sensible things to for other scripts, assert that one of those things happens? That'd at least lock down behavior to what's already shipping and help if Edge wanted to add support.
all implementations agree about the behavior of Latin script, at least that much could be asserted.
We certainly don't. As a WebKit maintainer, I can say that we don't intend to match other browsers in this regard even for Latin script.
Or if there are only 2-3 sensible things to for other scripts, assert that one of those things happens?
No, in Chinese & Japanese, some browsers would treat each character as a word, and others would use dictionary-based lookups. Both behaviors are valid and there are many variants of these behaviors because they're inherently rely on dictionary based heuristics.
I don't expect non-interoperable nature of word boundary to change in foreseeable future.
Do you know if the differences with Latin script intentional? Perhaps other engines could match WebKit instead?
I found https://crbug.com/699903 so apparently people do care about this API a little bit. @yosinch to represent Blink in this discussion.
If there's no way to make word boundary logic more interoperable, then that could just be acknowledged as a problem in the spec, or a feature if it maps to diverging user preferences.
Do you know if the differences with Latin script intentional? Perhaps other engines could match WebKit instead?
Yes, WebKit behaves differently on Windows/Linux and Mac on purpose due to the differences in the underlying platform's convention.
If there's no way to make word boundary logic more interoperable, then that could just be acknowledged as a problem in the spec, or a feature if it maps to diverging user preferences.
Well, the problem exists for character, sentence, and other granularities. Figuring out where a sentence ends is not a trivial matter in many languages.
Having said that, we can at least add this method, and add some vague description about what different granularities are supposed to do, perhaps with some examples.
It seems this will also be useful for doing measurements, for example to create beforeinput events in JavaScript. The only odd aspect to it there is that one needs to be OK with losing the selection temporarily in order to do the measurement [1], but I guess that's not a major cause for concern? Is there any reason why this is part of selections rather than ranges? If one could extend ranges like this, one could use it both for selection and for measurement purposes without losing the selection.
I don't think we need to dispatch beforeinput for Selection#modify(), since we can use Proxy object or
manually override Selection#modify(). And make default action of UI events to call Selection#modify() instead of done in C++, e.g. default action of mouse double click to execute window.getSelection().modify('extend, 'forward', 'word')`.
Introducing beforeselectionchange, as replacement of selectionstart, with move/extent, direction, granularity is more suitable for watching selection change.
For measurement, I prefer to introduce "visible character iterator" rather than using Range#expand().
because of Selection#modify() uses "visible character" instead of DOM characters for ignoring collapsed whitespaces, display:none, etc.
In other words, I would like standardized what Blink/WebKit calls visible position canonicalization (not
reverse engineering of current implementation, though), to improve interoperability.
I don't think we need to dispatch beforeinput for Selection#modify(), since we can use Proxy object or
manually override Selection#modify().
I think we are misunderstanding each other. The point is not for the UA to dispatch a beforeinput event whenever Selection#modify() is used. The question is what to do when JS manually wants to trigger a beforeinput event as if it came from the browser. Some of the beforeinput events require a target range that is different from the selection -- for example "deleteWordBackward". Now if I want to make a button to delete words backward, and I want it to behave exactly like the browser would when hitting the keyboard shortcut for deleting a word backward, I need to know what the browser would consider a word boundary when going backward from the current selection. Selection#modify() seems to be able to give me such a measurement, but I would need to lose my selection during the process of measuring it. The Range#expand() that @foolip seems more meaningful, as it could be used to measure without losing the selection.
Having access to a "visible character iterator" in JavaScript would also be helpful for parts of this, but it wouldn't help us much with finding softline breaks and alike.
And make default action of UI events to call Selection#modify() instead of done in C++.
We object to that proposal. We don't do this elsewhere in the platform, and it's going to be impossible for us to implement such a behavior due to various security concerns.
And make default action of UI events to call Selection#modify() instead of done in C++.
We object to that proposal. We don't do this elsewhere in the platform, and it's going to be impossible for us to implement such a behavior due to various security concerns.
@rniwa
Could you explain about "various security concerns"? To make me not to think about calling JS method from C++ in future discussion.
Thanks!
Some of the beforeinput events require a target range that is different from the selection
How about adding effectiveRange to beforeInput to represent range will be removed?
The Range#expand() that @foolip seems more meaningful, as it could be used to measure without losing the selection.
I disagree with Range#expand() but I agree to haveSelection#compute(StaticRange, alter, direction, unit)
for purpose of UA's command, The API needs to work on visible characters rather than DOM characters.
I would like to keep Range to wok on DOM tree and isolated from visible characters.
@yosinch is the Blink expert here so I defer to him to express implementer interest here.
Given the usage, removing Range#expand() is still something that'd probably work out compat-wise, but in the past when I've been about to do I got stuck trying to write suggestions for web developers for what they should use instead.
Also, if anyone wants to attempts removal, it would be good to confirm with the other two vendors that this is not totally off the table.
Could you explain about "various security concerns"? To make me not to think about calling JS method from C++ in future discussion.
We modify selections in places where it's not safe to invoke JavaScript. This is why we don't have beforeinput for selection. selectstart event happens to fire in only places where it's safe to dispatch an event.
Also, if anyone wants to attempts removal, it would be good to confirm with the other two vendors that this is not totally off the table.
Removing this API is off the table for us in the foreseeable future. We should spec this API using the same underlying algorithm as getSelection().modify instead of trying to remove it.
It's true that it's not a great layering but TC39 still had to spec String.prototype.font for compatibility reasons. Here too, we have to suck it up and spec the API for compatibility reasons.
Removing this API is off the table for us in the foreseeable future. We should spec this API using the same underlying algorithm as getSelection().modify instead of trying to remove it.
modify is useful, but awkward in that it just updates the selection, and provides no way to query a caret motion without messing with the active selection. I'm not opposed to specifying modify as it exists, but I think an interface that allows you to query where a motion from a given position would go, without side effects, would be a lot more useful.
A further complication with that would be that selections, even cursor selections, contain additional hidden state beyond their parent node + offset (see #57, #32, probably there's more), and that kind of state needs to be accessible and representable to be able to properly model this.
Added a very basic definition in 12d6a89 now that all major browsers ship this feature. Please file separate issues for refining the definition of this method.
Activity
rniwa commentedon Dec 14, 2014
We should probably spec this function now that Gecko implements it.
njakobsen commentedon May 4, 2015
Low usage is probably related to variability in behaviour on major browsers
Reinmar commentedon Aug 19, 2015
I showed how this method could be useful to editor implementors for altering the default caret movements without breaking internals like selection's X position: w3c/editing#56 (comment) (see point 3).
Turns out that I reinvented the wheel there, because I didn't know that such method already existed, but it seems that I came to a nearly identical API as I found here https://developer.mozilla.org/en-US/docs/Web/API/Selection/modify
Hence, I would love to see this method in the spec.
rniwa commentedon Apr 11, 2016
Also see https://www.w3.org/Bugs/Public/show_bug.cgi?id=9514
jclem commentedon Apr 11, 2016
I'd jus like to chime in here and say that we use this at https://usecanvas.com quite heavily (we're working on polyfills for some browsers, still). We are a contenteditable-based editor, but as part of our effort to rely on its default behaviors as little as possible, we use
Selection.modify(). Each of our document lines actually is a separate contenteditable element, and we useSelection.modify()to navigate between them based on user input.We'd of course like to not rely on this API, but it's helped us achieve some significant simplifications in our editor.
rniwa commentedon Apr 11, 2016
It looks like there are enough demands and existing use in the wild that we need to spec this feature.
foolip commentedon Mar 9, 2017
Just as a start, the Web IDL would be something like this:
It's a no-op if passed anything other than these strings:
Actual behavior, I dunno :)
rniwa commentedon Mar 9, 2017
I think the tricky part is spacing the actual behavior. I mean, I can just add text with the supported strings with some vague text like it moves the selection forward by character for
modify('move', 'forward', 'character')if people think that's valuable.foolip commentedon Mar 9, 2017
Perhaps an unorthodox but practical way to go about this would be to find the tests for this in WebKit, convert+upstream those into a web-platform-tests PR to go with the spec change, and work backwards from what fails in Chrome or Firefox to see what parts of the spec should exactly match WebKit, and where we need to think about it.
A lot of work, I know. IMHO just having the surface-level API with a big FIXME would be a slight improvement on the current situation, if nobody has time to dive deep within the next few months.
rniwa commentedon Mar 10, 2017
Well, the problem here is that there appears to be a fundamental disagreement about what these APIs are for. Gecko, for example, has one behavior for how a whiteface around a word is treated in languages in which a word boundary is defined by white spaces across all platforms for
modify()even though selection will be moved and extended differently on Mac & Windows by the user. WebKit (and Blink) for most part respected each platform's convention with regards to the treatments of whitespace even inmodify.Furthermore, moving caret or extending selection across word boundary is a fundamentally non-interoperable feature because the definition of a word boundary is not set in stone in many languages. For example, in Chinese and Japanese, there are no syntactical hint or mechanism to define a word boundary. As such, ICU relies on a bunch of heuristics and dictionary lookups to determine where the word boundary might be. This in turn means that each browser & platform has a different definition of what a word boundary means.
foolip commentedon Mar 10, 2017
Would it be possible to define abstract operations whose general semantics are clear, but which allow for deviations based on platform conventions or user preference? The spec could invoke those, and we wouldn't be able to write tests for all of it, but if for example all implementations agree about the behavior of Latin script, at least that much could be asserted. Or if there are only 2-3 sensible things to for other scripts, assert that one of those things happens? That'd at least lock down behavior to what's already shipping and help if Edge wanted to add support.
rniwa commentedon Mar 14, 2017
We certainly don't. As a WebKit maintainer, I can say that we don't intend to match other browsers in this regard even for Latin script.
No, in Chinese & Japanese, some browsers would treat each character as a word, and others would use dictionary-based lookups. Both behaviors are valid and there are many variants of these behaviors because they're inherently rely on dictionary based heuristics.
I don't expect non-interoperable nature of word boundary to change in foreseeable future.
foolip commentedon Mar 14, 2017
Do you know if the differences with Latin script intentional? Perhaps other engines could match WebKit instead?
I found https://crbug.com/699903 so apparently people do care about this API a little bit. @yosinch to represent Blink in this discussion.
If there's no way to make word boundary logic more interoperable, then that could just be acknowledged as a problem in the spec, or a feature if it maps to diverging user preferences.
rniwa commentedon Mar 14, 2017
Yes, WebKit behaves differently on Windows/Linux and Mac on purpose due to the differences in the underlying platform's convention.
Well, the problem exists for
character,sentence, and other granularities. Figuring out where a sentence ends is not a trivial matter in many languages.rniwa commentedon Mar 14, 2017
Having said that, we can at least add this method, and add some vague description about what different granularities are supposed to do, perhaps with some examples.
johanneswilm commentedon Mar 23, 2017
It seems this will also be useful for doing measurements, for example to create beforeinput events in JavaScript. The only odd aspect to it there is that one needs to be OK with losing the selection temporarily in order to do the measurement [1], but I guess that's not a major cause for concern? Is there any reason why this is part of selections rather than ranges? If one could extend ranges like this, one could use it both for selection and for measurement purposes without losing the selection.
[1] w3c/input-events#54
foolip commentedon Mar 23, 2017
There's actually a Range#expand() API that we might consider standardizing as well. It's in Blink, EdgeHTML, and WebKit. I'll file an issue I think.
yosinch commentedon Apr 6, 2017
I don't think we need to dispatch
beforeinputforSelection#modify(), since we can use Proxy object ormanually override
Selection#modify(). And make default action of UI events to callSelection#modify()instead of done in C++, e.g. default action of mouse double click to executewindow.getSelection().modify('extend, 'forward', 'word')`.Introducing
beforeselectionchange, as replacement ofselectionstart, with move/extent, direction, granularity is more suitable for watching selection change.For measurement, I prefer to introduce "visible character iterator" rather than using
Range#expand().because of
Selection#modify()uses "visible character" instead of DOM characters for ignoring collapsed whitespaces, display:none, etc.In other words, I would like standardized what Blink/WebKit calls visible position canonicalization (not
reverse engineering of current implementation, though), to improve interoperability.
johanneswilm commentedon Apr 6, 2017
I think we are misunderstanding each other. The point is not for the UA to dispatch a beforeinput event whenever
Selection#modify()is used. The question is what to do when JS manually wants to trigger a beforeinput event as if it came from the browser. Some of the beforeinput events require a target range that is different from the selection -- for example"deleteWordBackward". Now if I want to make a button to delete words backward, and I want it to behave exactly like the browser would when hitting the keyboard shortcut for deleting a word backward, I need to know what the browser would consider a word boundary when going backward from the current selection.Selection#modify()seems to be able to give me such a measurement, but I would need to lose my selection during the process of measuring it. TheRange#expand()that @foolip seems more meaningful, as it could be used to measure without losing the selection.Having access to a "visible character iterator" in JavaScript would also be helpful for parts of this, but it wouldn't help us much with finding softline breaks and alike.
rniwa commentedon Apr 6, 2017
We object to that proposal. We don't do this elsewhere in the platform, and it's going to be impossible for us to implement such a behavior due to various security concerns.
yosinch commentedon Apr 6, 2017
@rniwa
Could you explain about "various security concerns"? To make me not to think about calling JS method from C++ in future discussion.
Thanks!
yosinch commentedon Apr 6, 2017
I disagree with
Range#expand()but I agree to haveSelection#compute(StaticRange, alter, direction, unit)for purpose of UA's command, The API needs to work on visible characters rather than DOM characters.
I would like to keep
Rangeto wok on DOM tree and isolated from visible characters.foolip commentedon Apr 6, 2017
@yosinch is the Blink expert here so I defer to him to express implementer interest here.
Given the usage, removing
Range#expand()is still something that'd probably work out compat-wise, but in the past when I've been about to do I got stuck trying to write suggestions for web developers for what they should use instead.Also, if anyone wants to attempts removal, it would be good to confirm with the other two vendors that this is not totally off the table.
rniwa commentedon Apr 6, 2017
We modify selections in places where it's not safe to invoke JavaScript. This is why we don't have
beforeinputfor selection.selectstartevent happens to fire in only places where it's safe to dispatch an event.Removing this API is off the table for us in the foreseeable future. We should spec this API using the same underlying algorithm as
getSelection().modifyinstead of trying to remove it.It's true that it's not a great layering but TC39 still had to spec
String.prototype.fontfor compatibility reasons. Here too, we have to suck it up and spec the API for compatibility reasons.yosinch commentedon Apr 7, 2017
It seems you said about
Range#expand(). Right?gked commentedon Apr 21, 2017
Editing my previous comment:
From edgehtml perspective, we should spec it.
marijnh commentedon Jan 23, 2020
modifyis useful, but awkward in that it just updates the selection, and provides no way to query a caret motion without messing with the active selection. I'm not opposed to specifyingmodifyas it exists, but I think an interface that allows you to query where a motion from a given position would go, without side effects, would be a lot more useful.A further complication with that would be that selections, even cursor selections, contain additional hidden state beyond their parent node + offset (see #57, #32, probably there's more), and that kind of state needs to be accessible and representable to be able to properly model this.
rniwa commentedon Jul 13, 2022
Added a very basic definition in 12d6a89 now that all major browsers ship this feature. Please file separate issues for refining the definition of this method.