[custom-elements] Steps inside HTMLElement's constructor

Hi all,

Here are steps to construct a custom element as agreed during Jan F2F as I promised to write down [1] [2]:

Modify http://w3c.github.io/webcomponents/spec/custom/#dfn-element-definition as follows:
The element definition describes a custom element and consists of:

 * custom element type,
 * local name,
 * namespace,
 * custom element interface,
 * lifecycle callbacks, and
 * element construction stack.

Each element construction stack is initially empty, and each entry is an instance of Element or a "AlreadyConstructed" marker.

Non-Normative Note: We need a stack per element definition to allow construction of other custom elements inside a custom element's constructor. Without such a stack per element definition, we would end up walking through entries in the stack to find the "right" entry.  Implementors are free to take such an approach to minimize the memory usage, etc..., but there are a lot of edge cases that need to be taken care of, and it's not a great way to spec an interoperable behavior.


== Custom Element Construction Algorithm ==

Input
  NAME, the custom element name.
  DOCUMENT, the owner document for new custom element.
  EXOTIC-TARGET, the target Element to be constructed / upgraded.
OUTPUT
  ELEMENT, new custom element instance.
  ERROR, could be either "None", "NotFound", "InvalidStateError", or an ECMAScript exception.

1. Let ERROR be "None".
2. Let REGISTRY be the (custom element) registry of DOCUMENT.
3. If DOCUMENT is an HTML document, let NAME be converted to ASCII lowercase.
4. Let DEFINITION be the element definition of with the local name, NAME, in REGISTRY.
5. If there is no matching definition, set ERROR to "NotFound" and terminate these steps.
6. Otherwise, push a new entry, EXOTIC-TARGET, to the element construction stack of DEFINITION.
7. Invoke the [[Construct]] internal method [3] on custom element interface of DEFINITION.
8. Pop the entry from the element construction stack of DEFINITION.
9. If the [[Construct]] invocation resulted in an exception, set ERROR to the raised exception, and terminate these steps.
10. Otherwise, let ELEMENT be the result of the invocation.
11. If ELEMENT is not the same Object value as EXOTIC-TARGET, set ERROR to "InvalidStateError", and terminate these steps.

Non-Normative Note: we can modify step 4 to support non-HTML elements in the future. In step 11, ELEMENT can be different from EXOTIC-TARGET if the custom element's constructor instantiates another instance of the same custom element before calling super().


== HTMLElement constructor ==

Non-Normative Note: HTMLElement's constructor is called via super() call inside the custom element constructor.

1. Let TARGET be GetNewTarget(). [4]
2. Let DOCUMENT be the associated document of the global object (the result of GetGlobalObject() [5]).
3. Let REGISTRY be the (custom element) registry of DOCUMENT.
4. Let DEFINITION be the element definition with the element interface, TARGET, in REGISTRY.
5. If there is no matching definition, throw TypeError and terminate these steps.
6. Let NAME be the local name of DEFINITION.
7. If the element construction stack of DEFINITION is empty,
   1. Return a new element that implements HTMLElement, with no attributes, namespace set to the HTML namespace,
      local name set to NAME, and node document set to DOCUMENT.
8. Otherwise, let INSTANCE be the last entry in the element construction stack (i.e. in LIFO).
9. If INSTANCE is a "AlreadyConstructed" marker, throw InvalidStateError and terminate these steps.
10. Otherwise, replace the last entry in the element construction stack with a "AlreadyConstructed" marker.
11. Return INSTANCE.

Non-Normative Note: step 7.1. is like step 4 in createElement [6] and happens when author script instantiates a custom element without going through DOM. e.g. "new X". Checks in Step 9 and 10 are needed when author scripts constructs invokes super() multiple times inside a custom element constructor. Step 9 is sufficient for the Custom Element Construction Algorithm to fail because it checks the exception in step 9. Step 5 could throw NotSupportedError instead if people would prefer that.


[1] https://github.com/w3c/WebPlatformWG/blob/gh-pages/meetings/25janWC.md
[2] https://www.w3.org/2016/01/25-webapps-minutes.html
[3] http://www.ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-construct-argumentslist-newtarget
[4] http://www.ecma-international.org/ecma-262/6.0/#sec-getnewtarget
[5] http://www.ecma-international.org/ecma-262/6.0/#sec-getglobalobject
[6] https://dom.spec.whatwg.org/#dom-document-createelement


- R. Niwa

Received on Tuesday, 23 February 2016 06:47:19 UTC