Open
Bug 1494609
Opened 6 years ago
Updated 2 years ago
assignedNodes({flatten: true}) and flattening assigned nodes in spec does not fallback correctly
Categories
(Core :: DOM: Core & HTML, defect, P3)
Tracking
()
UNCONFIRMED
People
(Reporter: orstavik77, Unassigned)
References
Details
Attachments
(2 files)
User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0
Build ID: 20180830143136
Steps to reproduce:
https://codepen.io/orstavik/pen/YOmLjG
<script>
class TheMother extends HTMLElement {
constructor(){
super();
this.attachShadow({mode: "open"});
this.shadowRoot.innerHTML = "<the-son><slot></slot></the-son>";
}
}
class TheFather extends HTMLElement {
constructor(){
super();
this.attachShadow({mode: "open"});
this.shadowRoot.innerHTML = "<the-son><slot>father decides</slot></the-son>";
}
}
class TheSon extends HTMLElement {
constructor(){
super();
this.attachShadow({mode: "open"});
this.shadowRoot.innerHTML = "DOM engine: <b><slot>son decides</slot></b>";
}
}
customElements.define("the-mother", TheMother);
customElements.define("the-father", TheFather);
customElements.define("the-son", TheSon);
</script>
#son <br><the-son id="son">God decides</the-son><hr>
#son2 <br><the-son id="son2"></the-son><hr>
#son3 <br><the-son id="son3"><slot>God again</slot></the-son><hr>
#son4 <br><the-son id="son4"><slot></slot></the-son><hr>
#pap <br><the-father id="pap">God decides</the-father><hr>
#pap2 <br><the-father id="pap2"></the-father><hr>
#pap3 <br><the-father id="pap3"><slot>God again</slot></the-father><hr>
#pap4 <br><the-father id="pap4"><slot></slot></the-father><hr>
#mom <br><the-mother id="mom">God decides</the-mother><hr>
#mom2 (????)<br><the-mother id="mom2"></the-mother><hr>
#mom3 <br><the-mother id="mom3"><slot>God again</slot></the-mother><hr>
#mom4 <br><the-mother id="mom4"><slot></slot></the-mother><hr>
<script>
function assignedNodesFlattenSuggestion(slot){
let res = [];
for(let assigned of slot.assignedNodes()){
if (assigned instanceof HTMLSlotElement){
res = res.concat(assignedNodesFlattenSuggestion(assigned));
} else {
res.push(assigned);
}
}
if (res.length === 0){
res = Array.from(slot.childNodes);
}
return res;
}
function printAssigned(label, ar, parent){
const div = document.createElement("div");
ar = ar.map(n => {
if (n instanceof HTMLSlotElement)
return "SLOT->[" + Array.from(n.childNodes).map(n2 => n2.textContent).join(", ") + "]";
return n.textContent;
});
div.innerText = label + ": [" + ar.join("") + "]";
parent.after(div);
}
function whoDecides(selector){
let parent = document.querySelector(selector);
let root = parent;
while (parent.tagName !== "THE-SON")
parent = parent.shadowRoot.children[0];
const sonSlot = parent.shadowRoot.children[0].children[0];
printAssigned("suggestion.assignedNodes({flatten: true})", assignedNodesFlattenSuggestion(sonSlot), root);
printAssigned("API.assignedNodes({flatten: true})", sonSlot.assignedNodes({flatten: true}), root);
}
whoDecides("#son");
whoDecides("#son2");
whoDecides("#son3");
whoDecides("#son4");
whoDecides("#pap");
whoDecides("#pap2");
whoDecides("#pap3");
whoDecides("#pap4");
whoDecides("#mom");
whoDecides("#mom2");
whoDecides("#mom3");
whoDecides("#mom4");
</script>
Actual results:
When FF flattens the DOM it works the same as both Chrome and Safari and the spec.
But HTMLSlotElement.assignedNodes({flatten: true}) returns the wrong result for:
#son3, #pap3 and #mom3.
Also, #son3, #pap3 and #mom3 and #son4, #pap4 and #mom4 should return a list that contains the Slot element from the main document.
The error is that it is an empty array instead of an array with a text node "God again".
Expected results:
The problem is that the expected result from the spec that one sees in both Chrome and Safari is itself problematic.
1. You create a custom element with a slot, with slot childNodes as default fallback content (the son custom element).
2. You use this custom element in the shadowRoot of another custom element (the mom custom element). The mom custom element should be used by other custom elements/main document.
3. When you make the mom element, you want to:
3a. let the author decide slot content first, and
3b. if you don't have a particular opinion about a child elements slot content, you want to let the child element slots fallback to their own default content.
4. But how do you accomplish that?
For a full discussion of the problem, see attachment or just:
https://codepen.io/orstavik/pen/YOmLjG
It seems FF behavior for .assignedNodes({flatten: true}) is closer to what the spec should be, than what the spec is.
Comment 1•6 years ago
|
||
Thanks for bringing this to our attention. Our plan is to fix the mismatch with the DOM Standard to not allow slot elements to be used outside shadow trees.
Pursuing a change in the standard is probably best done through https://github.com/whatwg/html/issues for this particular API, but I suspect it's too late to make such a change. Maybe an alternative API could be added if there's sufficient demand.
Reporter | ||
Comment 2•6 years ago
|
||
Reporter | ||
Comment 3•6 years ago
|
||
Thank you very much for the quick response!
I did a little more research into this. And I found another related problem with Slot childNodes (Slot fallback nodes) and CSS. See the slotFallbackCSS.html attachment or https://codepen.io/orstavik/pen/dgyWMM
I'm not 100% sure, but with the current setup for assigning childNodes of slot elements, I think CSS style encapsulation for web components break?
Also, so not to cause confusion, the problem with the standard is that it DOES allow the use of slot elements outside of shadowRoot. In fact, slot elements in the main document (outside shadowRoot) persist into the flattened DOM. The joke becoming: "Do you know what an abnormal slot element is? a normal html element."
I will try to pursue the problem with whatwg.org directly.
Updated•6 years ago
|
Component: Untriaged → DOM
Priority: -- → P3
Product: Firefox → Core
Updated•6 years ago
|
Assignee | ||
Updated•6 years ago
|
Component: DOM → DOM: Core & HTML
Updated•2 years ago
|
Severity: normal → S3
You need to log in
before you can comment on or make changes to this bug.
Description
•