- From: Joseph Orbegoso Pea <notifications@github.com>
- Date: Tue, 29 Nov 2016 16:46:51 -0800
- To: w3c/webcomponents <webcomponents@noreply.github.com>
- Message-ID: <w3c/webcomponents/issues/611/263748417@github.com>
@hayato, check this out. Custom Elements in my library observe `slot` elements in order to mark those elements' shadowParent (i.e. the parent of the slot they are distributed to), and adds distributed children to a `shadowChildren` list of the parent the `slot`. On `slotchange` of a slot, this code is ran:
```js
_handleDistributedChildren(slot) {
const diff = this._getDistributedChildDifference(slot)
for (const addedNode of diff.added) {
// We do this because if the given slot is assigned to another
// slot, then this logic will run again for the next slot on
// that next slot's slotchange, so we remove the distributed
// node from the previous shadowParent and add it to the next
// one. If we don't do this, then the distributed node will
// exist in multiple shadowChildren lists when there is an
// assignedSlot list. For more info, see
// https://github.com/w3c/webcomponents/issues/611
if (addedNode._shadowParent)
addedNode._shadowParent._shadowChildren.delete(addedNode)
addedNode._shadowParent = this
this._shadowChildren.add(addedNode)
}
for (const removedNode of diff.removed) {
removedNode._shadowParent = null
this._shadowChildren.delete(removedNode)
}
}
```
where `_getDistributedChildDifference` returns an object containing `added` and `removed` properties which are lists of nodes that were distributed and undistributed, respectively, and looks like this:
```js
_getDistributedChildDifference(slot) {
let previousNodes
if (this._slotElementsAssignedNodes.has(slot))
previousNodes = this._slotElementsAssignedNodes.get(slot)
else
previousNodes = []
const newNodes = slot.assignedNodes({flatten: true})
// save the newNodes to be used as the previousNodes for next time.
this._slotElementsAssignedNodes.set(slot, newNodes)
const diff = {
removed: [],
}
for (let i=0, l=previousNodes.length; i<l; i+=1) {
let oldNode = previousNodes[i]
let newIndex = newNodes.indexOf(oldNode)
// if it exists in the previousNodes but not the newNodes, then
// the node was removed.
if (!(newIndex >= 0)) {
diff.removed.push(oldNode)
}
// otherwise the node wasn't added or removed.
else {
newNodes.splice(i, 1)
}
}
// Remaining nodes in newNodes must have been added.
diff.added = newNodes
return diff
}
```
When a chain of assigned slots exists (i.e. slot1 assigned to slot2, slot2 assigned to slot3, etc), then the that code will run multiple times, once per `slotchange` of each slot in the chain.
Because there's not a way to get finally-distributed nodes, I have to guard against the fact that a previous slot in the chain might have added the distributed node to `shadowChildren` of the previous slot's parent.
If there were a `distributedNodes()` method, then that defensive check would not be needed and the code would look like this:
```js
_handleDistributedChildren(slot) {
const diff = this._getDistributedChildDifference(slot)
for (const addedNode of diff.added) {
addedNode._shadowParent = this
this._shadowChildren.add(addedNode)
}
for (const removedNode of diff.removed) {
removedNode._shadowParent = null
this._shadowChildren.delete(removedNode)
}
}
```
furthermore, this logic wouldn't have to fire once per slot if there was an event that only fired on finally-distributed children. Right now, if there is a chain of 4 slots across 4 shadow tree, then this logic will fire four times from shallowest to deepest slot.
TLDR: I've gotten it to work, but it's ugly due to the fact that there's no possible way to know if the nodes returned from from `slot.assignedNodes({flatten: true})` are finally-distributed to the current slot or not, so instead I am relying on the fact that the `slotchange` event will fire from shallowest to deepest slot.
Is that order ot `slotchange` events something I can rely on? Or is it just Chrome's behavior and could possibly be different in other browsers?
--
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/webcomponents/issues/611#issuecomment-263748417
Received on Wednesday, 30 November 2016 00:47:28 UTC