Closed Bug 1867058 Opened 10 months ago Closed 6 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 3 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.

Attachment

General

Created:
Updated:
Size: