Re: [custom-elements] Steps inside HTMLElement's constructor

2016-02-22 Thread Ryosuke Niwa

> On Feb 22, 2016, at 10:46 PM, Ryosuke Niwa  wrote:
> 
> Here are steps to construct a custom element as agreed during Jan F2F as I 
> promised to write down [1] [2]:

There's a very appealing alternative to this, which doesn't involve having a 
element construction stack per definition.

We add an extra argument, let us call it exoticNewTarget, to [[Construct]] 
internal method [7], which is initially Null.  More precisely, [[Construct]] 
now takes arguments (a List of any, Object, Object) where the third argument is 
a newly created exotic object.

Add a new environmental records field, [[ExoticNewTarget]], which is either an 
Object or undefined. If this Environment Record was created by the 
[[Construct]] internal method, [[ExoticNewTarget]] is the value of the 
[[ExoticNewTarget]] exoticNewTarget parameter. Otherwise, its value is 
undefined.

Add a new abstract operation GetExoticNewTarget(), which performs the following 
steps:
1. Let envRec be GetThisEnvironment().
2. Assert: envRec has a [[ExoticNewTarget]] field.
3. Return envRec.[[ExoticNewTarget]].

We also modify step 7 of runtime semantics of SuperCall from:
7. Let result be Construct(func, argList, newTarget).
to
7. Let result be Construct(func, argList, newTarget, GetExoticNewTarget()).

With these simple changes, we can simplify the algorithm as follows and it 
would ALWYAS construct the right element:


== 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.
7. Invoke the [[Construct]] internal method [3] on the custom element 
interface, INTERFACE, of DEFINITION
   with (INTERFACE, an empty list, INTERFACE, EXOTIC-TARGET)
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 an instance of INTERFACE with local name, NAME, set ERROR 
to "InvalidStateError", and terminate these steps.


== HTMLElement constructor ==

1. Let TARGET be GetNewTarget(). [4]
2. Let EXOTIC-TARGET be GetExoticNewTarget().
3. If EXOTIC-TARGET is not undefined, return EXOTIC-TARGET and terminate these 
steps.
4. Let DOCUMENT be the associated document of the global object (the result of 
GetGlobalObject() [5]).
5. Let REGISTRY be the (custom element) registry of DOCUMENT.
6. Let DEFINITION be the element definition with the element interface, TARGET, 
in REGISTRY.
7. If there is no matching definition, throw TypeError and terminate these 
steps.
8. Let NAME be the local name of DEFINITION.
9. 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.

[7] http://www.ecma-international.org/ecma-262/6.0/#table-6
[8] 
http://www.ecma-international.org/ecma-262/6.0/#sec-super-keyword-runtime-semantics-evaluation




[custom-elements] Steps inside HTMLElement's constructor

2016-02-22 Thread Ryosuke Niwa
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