Core: Recognize Shadow DOM in attachment checks

Allow `isAttached` to check Shadow DOM for attachment.

Fixes gh-3504
Closes gh-3996
Ref gh-3977
This commit is contained in:
Saptak Sengupta 2018-11-09 16:45:31 +05:30 committed by Michał Gołębiowski-Owczarek
parent 549b32a05a
commit 9b77def560
8 changed files with 138 additions and 15 deletions

22
src/core/isAttached.js Normal file
View File

@ -0,0 +1,22 @@
define( [
"../core",
"../var/documentElement",
"../selector" // jQuery.contains
], function( jQuery, documentElement ) {
"use strict";
var isAttached = function( elem ) {
return jQuery.contains( elem.ownerDocument, elem );
},
composed = { composed: true };
// Check attachment across shadow DOM boundaries when possible (gh-3504)
if ( documentElement.attachShadow ) {
isAttached = function( elem ) {
return jQuery.contains( elem.ownerDocument, elem ) ||
elem.getRootNode( composed ) === elem.ownerDocument;
};
}
return isAttached;
} );

View File

@ -1,6 +1,6 @@
define( [ define( [
"../core", "../core",
"../var/isAttached", "../core/isAttached",
"./var/rboxStyle", "./var/rboxStyle",
"./var/rnumnonpx", "./var/rnumnonpx",
"./var/getStyles", "./var/getStyles",

View File

@ -1,6 +1,6 @@
define( [ define( [
"../../core", "../../core",
"../../var/isAttached" "../../core/isAttached"
// css is assumed // css is assumed
], function( jQuery, isAttached ) { ], function( jQuery, isAttached ) {

View File

@ -1,6 +1,6 @@
define( [ define( [
"./core", "./core",
"./var/isAttached", "./core/isAttached",
"./var/concat", "./var/concat",
"./var/isFunction", "./var/isFunction",
"./var/push", "./var/push",

View File

@ -1,7 +1,7 @@
define( [ define( [
"../core", "../core",
"../core/toType", "../core/toType",
"../var/isAttached", "../core/isAttached",
"./var/rtagName", "./var/rtagName",
"./var/rscriptType", "./var/rscriptType",
"./wrapMap", "./wrapMap",

View File

@ -1,11 +0,0 @@
define( [
"../core",
"../selector" // Get jQuery.contains
], function( jQuery ) {
"use strict";
return function isAttached( obj ) {
return jQuery.contains( obj.ownerDocument, obj );
};
} );

View File

@ -641,6 +641,63 @@ QUnit.test( "show/hide detached nodes", function( assert ) {
span.remove(); span.remove();
} ); } );
QUnit[ document.body.attachShadow ? "test" : "skip" ]( "show/hide shadow child nodes", function( assert ) {
assert.expect( 28 );
jQuery( "<div id='shadowHost'></div>" ).appendTo( "#qunit-fixture" );
var shadowHost = document.querySelector( "#shadowHost" );
var shadowRoot = shadowHost.attachShadow( { mode: "open" } );
shadowRoot.innerHTML = "" +
"<style>.hidden{display: none;}</style>" +
"<div class='hidden' id='shadowdiv'>" +
" <p class='hidden' id='shadowp'>" +
" <a href='#' class='hidden' id='shadowa'></a>" +
" </p>" +
" <code class='hidden' id='shadowcode'></code>" +
" <pre class='hidden' id='shadowpre'></pre>" +
" <span class='hidden' id='shadowspan'></span>" +
"</div>" +
"<table class='hidden' id='shadowtable'>" +
" <thead class='hidden' id='shadowthead'>" +
" <tr class='hidden' id='shadowtr'>" +
" <th class='hidden' id='shadowth'></th>" +
" </tr>" +
" </thead>" +
" <tbody class='hidden' id='shadowtbody'>" +
" <tr class='hidden'>" +
" <td class='hidden' id='shadowtd'></td>" +
" </tr>" +
" </tbody>" +
"</table>" +
"<ul class='hidden' id='shadowul'>" +
" <li class='hidden' id='shadowli'></li>" +
"</ul>";
var test = {
"div": "block",
"p": "block",
"a": "inline",
"code": "inline",
"pre": "block",
"span": "inline",
"table": "table",
"thead": "table-header-group",
"tbody": "table-row-group",
"tr": "table-row",
"th": "table-cell",
"td": "table-cell",
"ul": "block",
"li": "list-item"
};
jQuery.each( test, function( selector, expected ) {
var shadowChild = shadowRoot.querySelector( "#shadow" + selector );
var $shadowChild = jQuery( shadowChild );
assert.strictEqual( $shadowChild.css( "display" ), "none", "is hidden" );
$shadowChild.show();
assert.strictEqual( $shadowChild.css( "display" ), expected, "Show using correct display type for " + selector );
} );
} );
QUnit.test( "hide hidden elements (bug #7141)", function( assert ) { QUnit.test( "hide hidden elements (bug #7141)", function( assert ) {
assert.expect( 3 ); assert.expect( 3 );
@ -966,6 +1023,29 @@ QUnit[ jQuery.find.compile && jQuery.fn.toggle ? "test" : "skip" ]( "detached to
"cascade-hidden element in detached tree" ); "cascade-hidden element in detached tree" );
} ); } );
QUnit[ jQuery.find.compile && jQuery.fn.toggle && document.body.attachShadow ? "test" : "skip" ]( "shadow toggle()", function( assert ) {
assert.expect( 4 );
jQuery( "<div id='shadowHost'></div>" ).appendTo( "#qunit-fixture" );
var shadowHost = document.querySelector( "#shadowHost" );
var shadowRoot = shadowHost.attachShadow( { mode: "open" } );
shadowRoot.innerHTML = "" +
"<style>.hidden{display: none;}</style>" +
"<div id='shadowHiddenChild' class='hidden'></div>" +
"<div id='shadowChild'></div>";
var shadowChild = shadowRoot.querySelector( "#shadowChild" );
var shadowHiddenChild = shadowRoot.querySelector( "#shadowHiddenChild" );
var $shadowChild = jQuery( shadowChild );
assert.strictEqual( $shadowChild.css( "display" ), "block", "is visible" );
$shadowChild.toggle();
assert.strictEqual( $shadowChild.css( "display" ), "none", "is hidden" );
$shadowChild = jQuery( shadowHiddenChild );
assert.strictEqual( $shadowChild.css( "display" ), "none", "is hidden" );
$shadowChild.toggle();
assert.strictEqual( $shadowChild.css( "display" ), "block", "is visible" );
} );
QUnit.test( "jQuery.css(elem, 'height') doesn't clear radio buttons (bug #1095)", function( assert ) { QUnit.test( "jQuery.css(elem, 'height') doesn't clear radio buttons (bug #1095)", function( assert ) {
assert.expect( 4 ); assert.expect( 4 );

32
test/unit/effects.js vendored
View File

@ -220,6 +220,38 @@ supportjQuery.each( hideOptions, function( type, setup ) {
assert.expectJqData( this, $span, "olddisplay" ); assert.expectJqData( this, $span, "olddisplay" );
} ); } );
QUnit[ document.body.attachShadow ? "test" : "skip" ](
"Persist correct display value - " + type + " hidden, shadow child", function( assert ) {
assert.expect( 3 );
jQuery( "<div id='shadowHost'></div>" ).appendTo( "#qunit-fixture" );
var shadowHost = document.querySelector( "#shadowHost" );
var shadowRoot = shadowHost.attachShadow( { mode: "open" } );
shadowRoot.innerHTML = "<style>.hidden{display: none;}</style>" +
"<span id='shadowChild' class='hidden'></span>";
var shadowChild = shadowRoot.querySelector( "#shadowChild" );
var $shadowChild = jQuery( shadowChild );
var displayNone = "none";
var display = "inline";
var clock = this.clock;
$shadowChild.fadeIn( 100, function() {
assert.equal( $shadowChild.css( "display" ), display, "Expecting shadow display: " + display );
$shadowChild.fadeOut( 100, function() {
assert.equal( $shadowChild.css( "display" ), displayNone, "Expecting shadow display: " + displayNone );
$shadowChild.fadeIn( 100, function() {
assert.equal( $shadowChild.css( "display" ), display, "Expecting shadow display: " + display );
} );
} );
} );
clock.tick( 300 );
assert.expectJqData( this, $shadowChild, "olddisplay" );
} );
} ); } );
QUnit.test( "animate(Hash, Object, Function)", function( assert ) { QUnit.test( "animate(Hash, Object, Function)", function( assert ) {