Skip to content

Commit

Permalink
Hide the .content() property for declarative shadow roots
Browse files Browse the repository at this point in the history
With this CL, the .content() property of a declarative shadow root
(a <template shadowroot="open|closed"> element being parsed) will return
null. Note that this <template> element only exists during parsing,
and upon the closing </template> tag being encountered by the parser,
the shadowroot will be created, the <template> contents will be moved
into the shadowroot, and the <template> itself will be deleted. So
this change is only visible from MutationObservers and other script
that runs *during* parsing. This CL prevents that script from accessing
the contents of the (potentially closed) shadow root.

See point #1 at [1] for more context.

[1] whatwg/dom#831 (comment)

Bug: 1042130
Change-Id: Id096d1b65dc94b7a75afdc6143341eb4521da41a
Cq-Do-Not-Cancel-Tryjobs: true
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2133308
Commit-Queue: Mason Freed <masonfreed@chromium.org>
Reviewed-by: Kouhei Ueno <kouhei@chromium.org>
Reviewed-by: Kent Tamura <tkent@chromium.org>
Auto-Submit: Mason Freed <masonfreed@chromium.org>
Cr-Commit-Position: refs/heads/master@{#759495}
  • Loading branch information
mfreed7 authored and chromium-wpt-export-bot committed Apr 16, 2020
1 parent 9264888 commit c6631ff
Showing 1 changed file with 88 additions and 0 deletions.
88 changes: 88 additions & 0 deletions shadow-dom/declarative/script-access.tentative.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<!DOCTYPE html>
<title>Declarative Shadow DOM</title>
<link rel='author' title='Mason Freed' href='mailto:masonfreed@chromium.org'>
<link rel='help' href='https://github.com/whatwg/dom/issues/831'>
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>

<body>
<script>
let templatesSeen = 0;
function myObserver(mutationsList, observer) {
for (let mutation of mutationsList) {
for (let n of mutation.addedNodes) {
if (n.localName === 'template') {
templatesSeen++;
switch (mutation.target.id) {
case 'openhost':
case 'closedhost':
const shadowroot = n.getAttribute('shadowroot');
assert_in_array(shadowroot, ['open','closed'], 'Declarative template should have shadowroot attribute');
assert_equals(n.content, null, 'Declarative template content should be null');
assert_equals(n.innerHTML, "", 'Declarative template innerHTML should be empty');

// Make sure removing the shadowroot attribute doesn't affect things.
n.removeAttribute('shadowroot');
assert_equals(n.content, null, 'Declarative template content should *still* be null');
assert_equals(n.innerHTML, "", 'Declarative template innerHTML should *still* be empty');
break;
case 'noroot':
// Make sure adding 'shadowroot' attribute doesn't trigger a shadow root,
// even if added before parsing completes.
n.setAttribute('shadowroot','open');
assert_not_equals(n.content, null, 'Regular template should have content, even after adding shadowroot attribute');
assert_not_equals(n.innerHTML, "", 'Regular template should have innerHTML, even after adding shadowroot attribute');
break;
default:
assert_unreached('Unrecognized template');
}
}
}
}
}
const observer = new MutationObserver(myObserver);
observer.observe(document.body, { childList: true, subtree: true });
assert_equals(templatesSeen, 0, 'No mutations yet');
</script>

<div id=openhost>
<template shadowroot=open>
<slot></slot>
</template>
</div>

<div id=closedhost>
<template shadowroot=closed>
<slot></slot>
</template>
</div>

<div id=noroot>
<template>
<slot></slot>
</template>
</div>

<script>
test(t => {
t.add_cleanup(function() { observer.disconnect(); });

assert_equals(templatesSeen, 3);

// Open shadow root
let host = document.querySelector('#openhost');
assert_equals(host.querySelector('template'), null, 'No leftover template node');
assert_true(!!host.shadowRoot, 'Shadow root should exist');

// Closed shadow root
host = document.querySelector('#closedhost');
assert_equals(host.querySelector('template'), null, 'No leftover template node');
assert_true(!host.shadowRoot, 'Closed shadow root (can\'t detect)');

// No shadow root
host = document.querySelector('#noroot');
assert_true(!!host.querySelector('template'), 'Template node still present');
assert_true(!host.shadowRoot, 'No shadow root');
},'Declarative Shadow DOM: template .content() should be null');
</script>
</body>

0 comments on commit c6631ff

Please sign in to comment.