

























The straw-man proposal for Imperative Shadow DOM distribution API. The context is: https://github.com/whatwg/html/issues/3534
[Update] This proposal was posted here.
Mixing declarative API and imperative API would be troublesome and can be the cause of confusions for web developers. We can invent complex rules, however, no one wants to remember complex rules. Also, supporting both in the same shadow tree would make a browser engine complex, which I don't want.
Thus, we don't allow mixing declarative API and imperative API in the same shadow tree. Web developers have to show their opt-in to use imperative API for each shadow tree.
A shadow root has an associated slotting. Web developers can set shadow root's slotting to manual by specifying it in attachShadow:
const sr = attachShadow({ mode: ..., (optional) slotting: 'manual' })
The manual means "we support only imperative APIs for the shadow tree". The default is "we support only declarative API for the shadow tree".
In addition to assigned nodes, which is already defined in DOM Standard, a slot has an associated manually-assigned-nodes (ordered list). Unless stated otherwise, it is empty.
A slot gets new API, called assign (tentative name).
Basically, slot.assign(sequence<Node> nodes) sets the slot's
manually-assigned-nodes to nodes. See the later section for details.
manually-assigned-nodes is an internal field. It is write-only. Users cannot read the value directly.
partial interface HTMLSlotElement {
...
void assign(sequence<Node> nodes)
}
slot.assign(sequence<Node> nodes) runs the following steps:
step 2 is required because we have to re-calculate assigned nodes of every slots in the tree at this timing.
Note: The detail is explained later, however, it would be worth noting that
manually-assigned-nodes is not used as assigned nodes as is. You can think
that slot.assign(sequence<Node> nodes) tell the engine candidate nodes from
where assigned nodes are constructed.
ShadowRootInit {
...
(optional) sloting: 'manual'|'auto' // (if omitted, it is 'auto');
}
To find a slot need to be updated. Other steps don't need to be updated from the standard's perspective, I think, thanks to well-factored each steps.
To find a slot for a given slotable slotable and an optional open flag (unset unless stated otherwise), run these steps:
If slotable’s parent is null, then return null.
Let shadow be slotable’s parent’s shadow root.
If shadow is null, then return null.
If the open flag is set and shadow’s mode is not "open", then return null.
[New Step] If shadow's slotting is manual, return the first slot in shadow’s tree whose manually-assigned-nodes includes slotable, if any, and null otherwise.
Otherwise, return the first slot in shadow’s tree whose name is slotable’s name, if any, and null otherwise. (<= No change)
Note: This change implies:
manually-assigned-nodes is used only when a slot is in a shadow tree whose slotting is manual.
manually-assigned-nodes is not used when a slot is in a shadow tree whose slotting is auto.
Web developers can call slot.assign(...) for such a slot, however, it is a
sort of no-op, at least until the slot is moved to another shadow tree with
'manual', where manually-assigned-nodes might have a meaning (but it is
unlikely).
If the same node is set to manually-assigned-nodes of more than one slots, the first slot in tree-order takes that node. The slot's location in the tree matters, as declarative API does so.
host
├──/shadowroot (slotting=manual)
│ ├── slot1
│ └── slot2
├── A
└── B
// '==' means ArrayEquals.
assert(slot1.assignedNodes() == []);
assert(slot2.assignedNodes() == []);
slot2.assign([A]);
assert(slot2.assignedNodes() == [A]);
slot2.assign([B, A]); // The order doesn't matter.
assert(slot2.assignedNodes() == [A, B]);
slot1.assign(A);
assert(slot1.assignedNodes() == [A]);
assert(slot2.assignedNodes() == [B]);
slot1.assign([A, A, A, host]); // We don't throw an exepction here.
assert(slot1.assignedNodes() == [A]);
assert(slot2.assignedNodes() == [B]);
slot1.assign([]);
assert(slot1.assignedNodes() == []);
assert(slot2.assignedNodes() == [A, B]);
slot2.assign([]);
assert(slot1.assignedNodes() == []);
assert(slot2.assignedNodes() == []);
host
├──/shadowroot (slotting=auto) (default)
│ ├── slot1 name=slot1
│ └── slot2 name=slot2
├── A slot=slot1
└── B slot=slot2
assert(slot1.assignedNodes() == [A]);
assert(slot2.assignedNodes() == [B]);
slot1.assign([A, B]); // This doesn't have any effect because this shadow tree's slotting is auto
assert(slot1.assignedNodes() == [A]);
assert(slot2.assignedNodes() == [B]);
Should we reset manually-assigned-nodes at some timings? e.g. when a slot is connected / or disconnected.
The current proposal never resets manually-assigned-nodes. This rule is easy to remember. That would cover the most use cases, I think.
Using sequence<Node> would be a right choice in slot.assign, given that the
order doesn't matter?
If WebIDL has a better type, like Set<Node>, we should use it.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。