Closed Bug 1867058 Opened 8 months ago Closed 4 months ago

Add the initial support for shadow dom selection

Categories

(Core :: DOM: Core & HTML, task)

task

Tracking

()

RESOLVED FIXED
126 Branch
Tracking Status
firefox126 --- fixed

People

(Reporter: sefeng, Assigned: sefeng)

References

(Blocks 5 open bugs, Regressed 1 open bug)

Details

(Keywords: dev-doc-needed)

Attachments

(12 files, 6 obsolete files)

48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
No description provided.
Blocks: 1867059

A new type range called CrossBoundaryRange is introduced and attached
to a nsRange when needed. Unlike nsRange::mStart and nsRange::mEnd where
we collapse to one point when the start and the end are in different
DOM trees (ie, crossing shadow boundary), CrossBoundaryRange keeps
the the original start and the end.

Depends on D195301

This is mainly used for nsINode::IsMaybeSelected() to work for nodes
inside shadow tree.

Depends on D195303

With the abiliity to disable it as well

Depends on D195305

Attachment #9366585 - Attachment description: WIP: Bug 1867058 - Part 1: Implement Selection.direction r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 1: Implement Selection.direction r=#dom-core,jjaschke,smaug
Attachment #9366586 - Attachment description: WIP: Bug 1867058 - Part 2: Introduce the concept of CrossBoundaryRange r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 2: Introduce the concept of CrossBoundaryRange r=#dom-core,jjaschke,smaug
Attachment #9366587 - Attachment description: WIP: Bug 1867058 - Part 3: Implement Selection.GetComposedRanges r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 3: Implement Selection.GetComposedRanges r=#dom-core,jjaschke,smaug
Attachment #9366588 - Attachment description: WIP: Bug 1867058 - Part 4: Allow nodes inside shadow trees can be marked as descendants of ranges' common inclusive ancestor r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 4: Allow nodes inside shadow trees can be marked as descendants of ranges' common inclusive ancestor r=#dom-core,jjaschke,smaug
Attachment #9366589 - Attachment description: WIP: Bug 1867058 - Part 5: Update nsRange to create and update mCrossBoundaryRange when necessary r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 5: Update nsRange to create and update mCrossBoundaryRange when necessary r=#dom-core,jjaschke,smaug
Attachment #9366586 - Attachment description: Bug 1867058 - Part 2: Introduce the concept of CrossBoundaryRange r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 2: Make both StaticRange and nsRange to have a way to cross the trees r=#dom-core,jjaschke,smaug
Attachment #9366587 - Attachment description: Bug 1867058 - Part 3: Implement Selection.GetComposedRanges r=#dom-core,jjaschke,smaug → WIP: Bug 1867058 - Part 3: Implement Selection.GetComposedRanges r=#dom-core,jjaschke,smaug
Attachment #9366588 - Attachment description: Bug 1867058 - Part 4: Allow nodes inside shadow trees can be marked as descendants of ranges' common inclusive ancestor r=#dom-core,jjaschke,smaug → WIP: Bug 1867058 - Part 4: Allow nodes inside shadow trees can be marked as descendants of ranges' common inclusive ancestor r=#dom-core,jjaschke,smaug
Attachment #9366589 - Attachment description: Bug 1867058 - Part 5: Update nsRange to create and update mCrossBoundaryRange when necessary r=#dom-core,jjaschke,smaug → WIP: Bug 1867058 - Part 5: Update nsRange to create and update mCrossBoundaryRange when necessary r=#dom-core,jjaschke,smaug
Attachment #9368056 - Attachment description: WIP: Bug 1867058 - [Quirk] Part 15: Disallow ContentIterator to cross shadow boundary range when getting the client rect for nsRange → WIP: Bug 1867058 - Part 15: [Quirk] Disallow ContentIterator to cross shadow boundary range when getting the client rect for nsRange
Attachment #9366587 - Attachment description: WIP: Bug 1867058 - Part 3: Implement Selection.GetComposedRanges r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 3: Implement Selection.GetComposedRanges r=#dom-core,jjaschke,smaug
Attachment #9366588 - Attachment description: WIP: Bug 1867058 - Part 4: Allow nodes inside shadow trees can be marked as descendants of ranges' common inclusive ancestor r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 4: Allow nodes inside shadow trees can be marked as descendants of ranges' common inclusive ancestor r=#dom-core,jjaschke,smaug
Attachment #9366589 - Attachment description: WIP: Bug 1867058 - Part 5: Update nsRange to create and update mCrossBoundaryRange when necessary r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 5: Update nsRange to create and update mCrossBoundaryRange when necessary r=#dom-core,jjaschke,smaug
Attachment #9366590 - Attachment description: WIP: Bug 1867058 - Part 6: Update ContentIterator to allow iterating nodes inside ShadowDOM r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 6: Update ContentIterator to allow iterating nodes inside ShadowDOM r=#dom-core,jjaschke,smaug
Attachment #9368056 - Attachment description: WIP: Bug 1867058 - Part 15: [Quirk] Disallow ContentIterator to cross shadow boundary range when getting the client rect for nsRange → WIP: Bug 1867058 - Part 15: [Quirk] Disallow SelectNode to create RangeBoundary that crosses the boundary if the selected node is a slotted content
Attachment #9366591 - Attachment description: WIP: Bug 1867058 - Part 7: Reset the CrossBoundaryRange when nodes becomes shadow host r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 7: Reset the CrossBoundaryRange when nodes becomes shadow host r=#dom-core,jjaschke,smaug
Attachment #9366592 - Attachment description: WIP: Bug 1867058 - Part 8: Make RangeBoundary support nodes across ShadowDOM r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 8: Make RangeBoundary support nodes across ShadowDOM r=#dom-core,jjaschke,smaug
Attachment #9366593 - Attachment is obsolete: true
Attachment #9366594 - Attachment description: WIP: Bug 1867058 - Part 10: Update Selection to support across shadow dom selection r=#dom-core,jjaschke,smaug → WIP: Bug 1867058 - Part 9: Update Selection to support across shadow dom selection r=#dom-core,jjaschke,smaug
Attachment #9366594 - Attachment description: WIP: Bug 1867058 - Part 9: Update Selection to support across shadow dom selection r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 9: Update Selection to support across shadow dom selection r=#dom-core,jjaschke,smaug
Attachment #9366595 - Attachment is obsolete: true
Attachment #9366598 - Attachment description: WIP: Bug 1867058 - Part 14: [Quirk] Disable cross boundary range for nsPrintJob r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 11: [Quirk] Disable cross boundary range for nsPrintJob r=#dom-core,jjaschke,smaug
Attachment #9366597 - Attachment is obsolete: true
Attachment #9366596 - Attachment description: WIP: Bug 1867058 - Part 12: Add test cases for ShadowDOM selection r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 10: Add test cases for ShadowDOM selection r=#dom-core,jjaschke,smaug
Attachment #9368056 - Attachment description: WIP: Bug 1867058 - Part 15: [Quirk] Disallow SelectNode to create RangeBoundary that crosses the boundary if the selected node is a slotted content → Bug 1867058 - Part 12: [Quirk] Disallow SelectNode to create RangeBoundary that crosses the boundary if the selected node is a slotted content r=#dom-core,jjaschke,smaug
Attachment #9368776 - Attachment description: WIP: Bug 1867058 - Part 16: [Quirk] Disallow SerializeRangeToString to cross the shadow boundary → Bug 1867058 - Part 13: [Quirk] Disallow SerializeRangeToString to cross the shadow boundary r=#dom-core,jjaschke,smaug
Attachment #9366594 - Attachment description: Bug 1867058 - Part 9: Update Selection to support across shadow dom selection r=#dom-core,jjaschke,smaug → WIP: Bug 1867058 - Part 8: Update Selection to support across shadow dom selection r=#dom-core,jjaschke,smaug
Attachment #9366592 - Attachment is obsolete: true
Attachment #9366594 - Attachment description: WIP: Bug 1867058 - Part 8: Update Selection to support across shadow dom selection r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 8: Update Selection to support across shadow dom selection r=#dom-core,jjaschke,smaug
Attachment #9366596 - Attachment description: Bug 1867058 - Part 10: Add test cases for ShadowDOM selection r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 9: Add test cases for ShadowDOM selection r=#dom-core,jjaschke,smaug
Attachment #9368776 - Attachment description: Bug 1867058 - Part 13: [Quirk] Disallow SerializeRangeToString to cross the shadow boundary r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 10: [Quirk] Disallow SerializeRangeToString to cross the shadow boundary r=#dom-core,jjaschke,smaug
Blocks: 1881095
Blocks: 1881096
Blocks: 1881097
Duplicate of this bug: 1880343
Attachment #9366598 - Attachment is obsolete: true
Attachment #9368056 - Attachment is obsolete: true
Duplicate of this bug: 1430308
Attachment #9390045 - Attachment description: Bug 1867058 - Part 12: Fix a bug in ShadowDOM selection where existing ranges get removed unexpectedly → WIP: Bug 1867058 - Part 12: Fix a bug in ShadowDOM selection where existing ranges get removed unexpectedly r=#dom-core,jjaschke,smaug
Attachment #9390045 - Attachment description: WIP: Bug 1867058 - Part 12: Fix a bug in ShadowDOM selection where existing ranges get removed unexpectedly r=#dom-core,jjaschke,smaug → Bug 1867058 - Part 12: Fix a bug in ShadowDOM selection where existing ranges get removed unexpectedly r=#dom-core,jjaschke,smaug
Blocks: 1886028
Pushed by sefeng@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/8ce7972ea4df
Part 1: Implement Selection.direction r=jjaschke,dom-core
https://hg.mozilla.org/integration/autoland/rev/0837e15babab
Part 2: Make both StaticRange and nsRange to have a way to cross the trees r=jjaschke,smaug,dom-core
https://hg.mozilla.org/integration/autoland/rev/8efda4cce80c
Part 3: Implement Selection.GetComposedRanges r=jjaschke,dom-core
https://hg.mozilla.org/integration/autoland/rev/3cf108eb13a6
Part 4: Allow nodes inside shadow trees can be marked as descendants of ranges' common inclusive ancestor r=smaug
https://hg.mozilla.org/integration/autoland/rev/7b5a689dc7fd
Part 5: Update nsRange to create and update mCrossBoundaryRange when necessary r=smaug
https://hg.mozilla.org/integration/autoland/rev/67bb7158a09f
Part 6: Update ContentIterator to allow iterating nodes inside ShadowDOM r=smaug
https://hg.mozilla.org/integration/autoland/rev/42e226158dc9
Part 7: Reset the CrossBoundaryRange when nodes becomes shadow host r=jjaschke
https://hg.mozilla.org/integration/autoland/rev/39c5816dff6b
Part 8: Update Selection to support across shadow dom selection r=smaug
https://hg.mozilla.org/integration/autoland/rev/c30869c03a70
Part 9: Add test cases for ShadowDOM selection r=jjaschke,smaug,dom-core
https://hg.mozilla.org/integration/autoland/rev/a8bc41291ab3
Part 10: [Quirk] Disallow SerializeRangeToString to cross the shadow boundary r=smaug
https://hg.mozilla.org/integration/autoland/rev/2ad556d56736
Part 11: Ensure nsIFrame::SelectionStateChanged is called for frames in shadow tree. r=smaug
https://hg.mozilla.org/integration/autoland/rev/6254c9c51033
Part 12: Fix a bug in ShadowDOM selection where existing ranges get removed unexpectedly r=smaug
Created web-platform-tests PR https://github.com/web-platform-tests/wpt/pull/45282 for changes under testing/web-platform/tests

Backed out for causing bustages on AbstractRange.cpp

Flags: needinfo?(sefeng)
Upstream PR was closed without merging
Pushed by sefeng@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/0b237fd5577a
Part 1: Implement Selection.direction r=jjaschke,dom-core
https://hg.mozilla.org/integration/autoland/rev/713c66e124c7
Part 2: Make both StaticRange and nsRange to have a way to cross the trees r=jjaschke,smaug,dom-core
https://hg.mozilla.org/integration/autoland/rev/0710183c2311
Part 3: Implement Selection.GetComposedRanges r=jjaschke,dom-core
https://hg.mozilla.org/integration/autoland/rev/02d89b880ac5
Part 4: Allow nodes inside shadow trees can be marked as descendants of ranges' common inclusive ancestor r=smaug
https://hg.mozilla.org/integration/autoland/rev/b1f1e6ad93f8
Part 5: Update nsRange to create and update mCrossBoundaryRange when necessary r=smaug
https://hg.mozilla.org/integration/autoland/rev/3990acf05c58
Part 6: Update ContentIterator to allow iterating nodes inside ShadowDOM r=smaug
https://hg.mozilla.org/integration/autoland/rev/d665bdcc228a
Part 7: Reset the CrossBoundaryRange when nodes becomes shadow host r=jjaschke
https://hg.mozilla.org/integration/autoland/rev/edcf770a3a1d
Part 8: Update Selection to support across shadow dom selection r=smaug
https://hg.mozilla.org/integration/autoland/rev/adc0f4aa70db
Part 9: Add test cases for ShadowDOM selection r=jjaschke,smaug,dom-core
https://hg.mozilla.org/integration/autoland/rev/7340930e5a53
Part 10: [Quirk] Disallow SerializeRangeToString to cross the shadow boundary r=smaug
https://hg.mozilla.org/integration/autoland/rev/6a4069c6ee10
Part 11: Ensure nsIFrame::SelectionStateChanged is called for frames in shadow tree. r=smaug
https://hg.mozilla.org/integration/autoland/rev/ca6c1077eb87
Part 12: Fix a bug in ShadowDOM selection where existing ranges get removed unexpectedly r=smaug
Flags: needinfo?(sefeng)
Regressions: 1887880
Regressions: 1887881
Regressions: 1887893
Regressions: 1887896
Regressions: 1887907
Upstream PR merged by moz-wptsync-bot
Regressions: 1887974
Regressions: 1887930
Regressions: 1887963
Blocks: 1889477
Regressions: 1890888
Regressions: 1890902
Regressions: 1890899
Blocks: 1891783
Keywords: dev-doc-needed

FF126 MDN work for this can be tracked in https://github.com/mdn/content/issues/33180

I have some questions:

  1. This appears to add support for Selection.direction and Selection.getComposedRange().
  2. Selection.getComposedRange() returns an array of StaticRange. Is it correct that all current implementations in practise return a single range?
  3. This is named composed range.
    • Reading around that seems to indicate that the range you get back is different from the old selections. It sounds like those are nodes and offsets, while "composed" might be a kind of flattened version that reflects the components as the UI would render them.
    • SO I'm "guessing" that this means a simplified version. Is this "close" to the right view of things, and what impact does using composed range have on users?
    • What do they have to think about because of this?
  4. This returns a StaticRange. Reading the docs it sounds like this is the range at the time you got the selection.
    • So If the underlying DOM changes the StaticRange will be incorrect - presumably selecting something else?
    • What are the implications for someone using this? They have to make sure they fetch a new range every time their is a DOM change?

Bit out of my depth on this.

Flags: needinfo?(sefeng)
Regressions: 1893673

This appears to add support for Selection.direction and Selection.getComposedRange().
Is that it? I mean the original explainer had a whole section Changes to existing Selection APIs - did that stuff happen too?

Some of those stuff happened but some of them didn't....

  • Selection.getRangeAt() should return ... - This didn't happen

  • Selection.anchorNode/anchorOffset/focusNode/focusOffset should return ...- This didn't happen

  • Selection.setBaseAndExtent() should now accept .... - This happened

  • Selection.collapse() should now accept ... - This happened

  • Selection.collapseToEnd()/collapseToStart() should .... - This didn't happen

  • deleteFromDocument() should .... - This didn't happen

  • extend() should .... This happened

  • User selection via mouse, keyboard, etc .... This happened

Selection.getComposedRange() returns an array of StaticRange. Is it correct that all current implementations in practise return a single range?

In practice, only Firefox can return multiple ranges, other implementations can only return one range at max.

This is named composed range....
Reading around that seems to indicate that the range you get back is different from the old selections. It sounds like those are nodes and offsets, while "composed" might be a kind of flattened version that reflects the components as the UI would render them.
SO I'm "guessing" that this means a simplified version. Is this "close" to the right view of things, and what impact does using composed range have on users?
What do they have to think about because of this?

So basically it'll return the "true range" if the user provides the correct shadow roots of the corresponding boundaries.
And if the correct shadow roots are not provided, it'll rescope the boundaries to parent element of the root's host element (
if the parent is still in a shadow tree, it'll keep rescoping until the root is not a shadow root)

I think it makes sense to call this "close" to the right view of the boundaries. Speaking of impacts...I am not sure,
it's not going to be very useful if they don't provide the shadow roots. Though it's still better than calling
getRangeAt() because the range returned by getRangeAt() is going to be a collapsed range (at least in Firefox), which is even less useful.

This returns a StaticRange. Reading the docs it sounds like this is the range at the time you got the selection.
So If the underlying DOM changes the StaticRange will be incorrect - presumably selecting something else?
What are the implications for someone using this? They have to make sure they fetch a new range every time their is a DOM change?

Yeah, if the underlying DOM changes, the returned static range will be incorrect. In fact, if DOM mutation
happens, the entire "true range" can be incorrect, because the correct behaviour is undefined at the moment.
See https://github.com/w3c/selection-api/issues/168. So develpers should aware of these issues.

Hamish, hope this shed some lights, let me know if I can help more. Thanks

Flags: needinfo?(sefeng)
Blocks: 1880435

Thanks very much Sean - that's very helpful.

  1. I have captured the "other API" compatibility changes in https://github.com/mdn/browser-compat-data/pull/23013

    • Is it correct these are all behind the same preference and also that they are standard (such as, returning multiple ranges)
    • I have marked that we are the only ones who have implemented all this new stuff so far - is that correct as far as we know.
    • For the the parts above that were not done, is that because they didn't make it into the spec, or they just haven't been implemented by anyone yet?
  2. So with respect to a change to the underlying DOM, what should a user DO now? Can they monitor for such changes and re-fetch a range in some way? I mean I can document that this might happen, but it would be even better to be able to say "you can monitor for mutations by doing X, and fix them by doing Y".

    My "guess" is that you might be able to monitor for mutations (?) but if the nodes in the range could just become completely wrong, you might as well just throw away the selection at that point, or perhaps again "rescope to the parent of the shadow dom".

Flags: needinfo?(sefeng)

Is it correct these are all behind the same preference and also that they are standard (such as, returning multiple ranges)

Yeah, they all behind the same preference. Returning multiple ranges isn't a standardized behaviour, in fact the spec only asks to return one range.

I have marked that we are the only ones who have implemented all this new stuff so far - is that correct as far as we know.

Safari also have the getComposedRanges and selection.direction implement, I think Chrome doesn't, but some of the APIs might work in Chrome.

For the the parts above that were not done, is that because they didn't make it into the spec, or they just haven't been implemented by anyone yet?

Yeah...it's a mix of both. Really need to look this case-by-case. i.e, getRangeAt should be updated to include that rescope algorithm, but for things like collapseToEnd, it's just I didn't implement it.

So with respect to a change to the underlying DOM, what should a user DO now? Can they monitor for such changes and re-fetch a range in some way? I mean I can document that this might happen, but it would be even better to be able to say "you can monitor for mutations by doing X, and fix them by doing Y".

So if developers want to update the selection, they can use MutationObserver to monitor DOM mutations and then calling setBaseAndExtent to update it. To monitor the selection made by users, I think they should remain to do what they are currently doing? I think the scenario should be pretty much the same as without ShadowDOM selection.

Let me know if I can clarify more things!

Flags: needinfo?(sefeng)

Thanks very much Sean! I'll ping you if I need more.

Changes to things such as collapseToEnd aren't always obvious to writers or the browser compat tests, both of which rely on the IDL having a visible change.
So when/if you implement these, please highlight them by marking the bug as dev-docs-needed and adding a specific note.

Sean, mostly just for my interest:

  • I understand that getComposedRanges() returns a single range in the spec, but Firefox can return multiple range objects
  • Selection.direction returns the direction of a selection. But if a selection covers multiple ranges, to which selection does the value apply?
Flags: needinfo?(sefeng)

It's the direction of the most recent selection.

Flags: needinfo?(sefeng)
Regressions: 1896229
Blocks: 1900426
Blocks: 1903870
You need to log in before you can comment on or make changes to this bug.