Re: [webcomponents] [Custom Elements] Write-up proposal for using a "state object" (#287)

The goal is to use a state object to unify the non-upgrade and upgrade scenarios such that the developer ergonomics are essentially the same for both. To do this, we consider providing a state object _instead_ of the actual element participating in the lifecycle callbacks.

At first blush this seemed like adding just a few APIs to the state object would be enough:
* function to create a ```ShadowRoot```
* attribute to view the element's tag name

Then, it seemed you might not know which APIs would be most convenient for the developer, so you might as well add:
* ```nodeName```
* ```nodeType```

It starts to look like you end up populating the state object with many of the same APIs already present on (or inherited from) ```HTMLElement.``` :-(

Some APIs we could add to the state object might be imbued with special powers, such as the ability to show only a subset of the attributes and/or children that are really present on the element, in order to make the element appear to have consistent state as if an attribute was just added, etc.

In general, the state object would appear to only support _read only_ access to the element's state. You don't include APIs that can cause mutations to the element's attributes or children (at least during certain stages of the lifecycle callbacks) because you may be providing the state object to an element in an upgrade scenario, and you don't want the developer to accidentally add attributes or child elements where existing attributes and children are already present (but potentially hidden).

Rather than re-invent the HTMLElement type-hierarchy (e.g., an ```HTMLElementReadOnly``` that inherits from an ```ElementReadOnly```, etc.), It seemed to me that only three new flags were necessary and could be plumbed through the existing DOM:

1. **readonly element flag** -- makes all attempts to mutate the element's state throw. (e.g. ```appendChild()```, ```setAttribute()```, etc., would throw when the element is in this state. Similarily, any other element attempting to append this node into the tree would fail as well.)
2. **hidden attribute flag** -- available for an Attr object. If set, this attribute is excluded from the ```attributes``` collection and invisible to ```getAttribute```, etc.
3. **hidden children flag** -- hides the element's current children, if any, from ```childNodes```, ```children```, ```firstChild``` etc.

The use of these flags are handled while lifecycle callbacks are in effect. Something like this:

1. constructor -- all flags are set (attributes + children hidden), element can't be modified
2. attrchanged -- each attribute in turn is revealed (attribute flag is unset one-at-a-time). children hidden, element can't be modified
3. inserted -- all flags off (attributes, children all visible)
4. insertedIntoDoc -- same as 3.

I think this could work in conjunction with Parser-created Constructors. However, it doesn't provide the strict separation that will be necessary for an isolated custom element model--so from that stand-point, I'm wondering if adding the ReadOnly objects are a good idea?

Also, these flags and states could be managed by a proxy just as easily--does this proposal just boil down to a specific kind of Proxy object?



---
Reply to this email directly or view it on GitHub:
https://github.com/w3c/webcomponents/issues/287#issuecomment-124776677

Received on Saturday, 25 July 2015 00:30:21 UTC