Skip to content

Offset: $.fn.offset() on element inside shadowRoot #1976

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from

Conversation

nazar-pc
Copy link
Contributor

$.fn.offset() didn't worked on html>...>shadowRoot>...>target_element, while target_element.getBoundingClientRect worked fine with correct result.
The reason was that check for disconnected node made by checking whether document contains target_element fails, which is correct, element inside shadowDOM, not in main DOM.

That is why I've added recursive traversal from element to its parent until it reaches document or until parent_element.parentNode is falsy (for disconnected nodes it will be null, if pass some badly composed object - it may be undefined, so, just falsy, in this case we just return).
If we encounter DocumentFragment (shadowRoot), we take parent_element.host property instead of parent_element.parentNode in order to get parent element of that shadowRoot.
Also it was necessary to add explicit check for target_element.getBoundingClientRect property.

This is modern, Web Components-aware version of ea507b3

@mgol
Copy link
Member

mgol commented Dec 26, 2014

See #1784 for the discussion; also a related ticket for the elem.html setter is here: http://bugs.jquery.com/ticket/13342.

We want to think this through as supporting shadow nodes correctly may require changes in many places in code. It's also quite early - only Blink is shipping Shadow DOM support so we have no guarantee the spec doesn't change before we could rely on this interface.

We need to be careful here.

@nazar-pc
Copy link
Contributor Author

I'm actively using Web Components, so I'm patching most of components in some ways to make them working together nicely. It is difficult to maintain custom patches, so usually I'm sending the to upstream, thankfully, most developers supports me in this direction.
There are many places where patches might be needed inside jQuery, but this patch covers only one method, and allows many pluging to work properly with absolute positioning (in particularly for tooltips). To be honest - this patch can be generalize and replace $.contains(), but I was concerned about performance. About compatibility - I think it is better to have some support now than have no support at all.

@dmethvin
Copy link
Member

Please do see the discussion in gh-1784, it seems that the standard either wanted to prevent this type of usage or did not account for it. We can, of course, try to work around it inside jQuery since there is always a way. But to me this indicates there are use cases the spec is not addressing. The best course of action is for the people who think these are still valid use cases to argue them to the standards bodies.

return box;
// We have element in ShadowDOM, need recursive traversal from element to its parent
if ( elem.matches && elem.matches( ":host *" ) ) {
if ( !elem.getBoundingClientRect ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any situation where a browser would support shadowDOM but not getBoundingClientRect? seems unlikely.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't check form getBoundingClientRect at all, I removed this if in my commit dropping older browsers.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right, that was for some old BlackBerry.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed that

@dmethvin
Copy link
Member

This needs unit tests.

@nazar-pc
Copy link
Contributor Author

Just merged upstream and dropped getBoundingClientRect check.
@dmethvin, how to run unit test properly here? Because to test this we need shadowDOM support from browser.
I've tried (document.body.shadowRoot === undefined ? skip : test)(...), but skip is unavailable.

@mgol
Copy link
Member

mgol commented Jan 12, 2015

skip is unavailable.

Try QUnit.skip; we'll need to migrate all those globals to the QUnit namespace some time, perhaps skip isn't exposed as a global at all since it's a new API.

@nazar-pc
Copy link
Contributor Author

Thanks, @mzgol, it works.
Added unit test, will be skipped if browser do not have native support for shadowDOM.

@ghost
Copy link

ghost commented Jan 31, 2015

Anything holding this up? Encountered this issue while using web components as well.

@nazar-pc
Copy link
Contributor Author

Please, read discussion #1784 and pull request #2043.
There is different pull request that addresses this issue, also code might be simplified for 3.0 due to dropping support for some old browsers.

@gibson042
Copy link
Member

Closing in favor of #2043, which is just about ready to land.

@gibson042 gibson042 closed this Feb 25, 2015
@lock lock bot locked as resolved and limited conversation to collaborators Jan 19, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Development

Successfully merging this pull request may close these issues.

5 participants