From d95392f734895b2c72e1822f464dd70a22b322a4 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 1 Mar 2016 12:07:05 -0500 Subject: [PATCH] Large custom element spec rewrite to implement some F2F decisions Notable changes: - Implemented HTMLElement constructor using @rniwa's algorithm from #403. - Rewrote element upgrading to use @rniwa's algorithm from #403, and incorporated it into the rest of the upgrading considerations. - Got rid of the ability to extend SVGElement, thus allowing us to remove most mentions of namespaces from the spec. - Removed createdCallback. - Rewrote "registering elements": - Uses defineElement instead of registerElement - Preserves the constructor instead of grabbing the .prototype property and synthesizing a new constructor - No longer spread out over four separate algorithms plus registerElement; everything is now inline under defineElement - More precise about exactly how to get the custom element prototype and callbacks - Rewrote createElement and createElementNS to be replacements instead of patches, and to call the author-supplied constructor. - Removed the "All Algorithms in One Diagram" section since so many algorithms changed or were inlined into their callers. - Removed the "Custom Elements and ECMAScript 6" section since it is very obsolete and does not reflect our current thinking. - New and rewritten algorithms do not use the unorthodox INPUTS/OUTPUTS blocks, or capitalized variable names. This is kind of a nice marker of new vs. old content. - I have taken over as spec editor for custom elements Notable things *not* substantially changed: - Parser changes are not specced still, besides to say that they should construct the element using its constructor. - Lifecycle callbacks were not changed, except for removing createdCallback. - Type extensions were not removed (yet?); it seems better to have a modernized version of them that we atomically remove. - Registries were not made available everywhere. Closes #403. Closes #365. Closes #283. Closes #185. Closes #170. Closes #169. Closes #167. Closes #163. Closes #162. Closes #161. Closes #158. Closes #137 (modulo the fact that #165 is still open). Closes #134. Closes #133. --- spec/custom/W3CTRMANIFEST | 1 - spec/custom/custom-elements-whole-world.svg | 246 ------- spec/custom/index.html | 670 +++++++++----------- 3 files changed, 303 insertions(+), 614 deletions(-) delete mode 100644 spec/custom/custom-elements-whole-world.svg diff --git a/spec/custom/W3CTRMANIFEST b/spec/custom/W3CTRMANIFEST index f60d3338..1ed8dc4f 100644 --- a/spec/custom/W3CTRMANIFEST +++ b/spec/custom/W3CTRMANIFEST @@ -1,2 +1 @@ index.html?specStatus=WD;shortName=custom-elements;useExperimentalStyles=false respec -custom-elements-whole-world.svg diff --git a/spec/custom/custom-elements-whole-world.svg b/spec/custom/custom-elements-whole-world.svg deleted file mode 100644 index c5f8d4bf..00000000 --- a/spec/custom/custom-elements-whole-world.svg +++ /dev/null @@ -1,246 +0,0 @@ - - - - - - - - - element registration - algorithm - - - - - - - - - definition construction - algorithm - - - - - - - - - element upgrade - algorithm - - - - - - - - - custom element - constructor generation - algorithm - - - - - - - - - document.createElement - document.createElementNS - - - - - - - - - element is created - - - - - - - - - set custom element - prototype - - - - - - - - - element Attached - - - - - - - - - element Detached - - - - - - - - - attribute changed - - - - - - - - - enqueue a lifecycle - callback - - - - - - - - - an element is popped from - the stack of open elements - - - - - - - - - generated constructor - - - - - - - - - transition from user - agent code to script - - - - - - - - - microtask checkpoint - - - - - - - - - invoke lifecycle - callbacks - - - - - - - - - process base element - queue - - - - - - - - - transfer a lifecycle - callback - - - - - - - - - document.registerElement - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/spec/custom/index.html b/spec/custom/index.html index fc06a3bd..4ac4d7cd 100644 --- a/spec/custom/index.html +++ b/spec/custom/index.html @@ -11,10 +11,9 @@ useExperimentalStyles: true, edDraftURI: "https://w3c.github.io/webcomponents/spec/custom/", editors: [{ - name: "Dimitri Glazkov", - url: "mailto:dglazkov@chromium.org", - company: "Google, Inc.", - w3cid: 40456 + name: "Domenic Denicola", + url: "mailto:d@domenic.me", + company: "Google, Inc." }], wg: "Web Platform Working Group", wgURI: "http://www.w3.org/WebPlatform/WG/", @@ -80,7 +79,7 @@
-

This specification describes the method for enabling the author to define and use new types of DOM elements in a document.

+

This specification describes the method for enabling the author to define and use new types of DOM elements in a document. It will eventually be upstreamed into [[!WHATWG-DOM]], [[!HTML]], and [[!WEBIDL]].

@@ -106,13 +105,13 @@

Motivations

Any point, at which a conforming UA must make decisions about the state or reaction to the state of the conceptual model, is captured as algorithm. The algorithms are defined in terms of processing equivalence. The processing equivalence is a constraint imposed on the algorithm implementors, requiring the output of the both UA-implemented and the specified algorithm to be exactly the same for all inputs.

-

The IDL fragments in this specification must be interpreted as required for conforming IDL fragments, as described in the Web IDL specification [[!WebIDL]].

+

The IDL fragments in this specification must be interpreted as required for conforming IDL fragments, as described in the Web IDL specification [[!WEBIDL]].

Concepts

-

Custom element is platform object whose interface [[!WebIDL]] is defined by the author. The interface prototype object of a custom element's interface is called the custom element prototype.

+

A custom element is a platform object whose constructor and prototype is defined by the author. The constructor function supplied by the author is called the custom element constructor.

The custom element type identifies a custom element interface and is a sequence of characters that MUST match the NCName production [[!XML-NAMES]], MUST contain a U+002D HYPHEN-MINUS character, and MUST NOT contain any uppercase ASCII letters [[!HTML]]. The custom element type MUST NOT be one of the following values:

@@ -369,202 +325,122 @@

Creating and Passing Registries

Registering Custom Elements

-

Because element registration can occur at any time, a custom element could be created before its definition is registered. Such custom element instances are called unresolved elements. When an unresolved element is created, and if its element interface was not defined by HTML or other applicable specifications, the unresolved element's element interface MUST be:

- +

Because element registration can occur at any time, a custom element could be created before its definition is registered. Such custom element instances are called unresolved elements. When an unresolved element is created, and if its element interface was not defined by HTML or other applicable specifications, the unresolved element's element interface MUST be HTMLElement.

-The effect of this statement is that any HTML (or SVG) element with the local name that is a valid custom element type will have HTMLElement (or SVGElement) as element interface, rather than HTMLUnknownElement. +The effect of this statement is that any HTML element with a local name that is a valid custom element type will have HTMLElement as its element interface, rather than HTMLUnknownElement.
-

Each registry has an associated map of all instances of unresolved elements for a given pair of custom element type and namespace. This data structure is called the upgrade candidates map and is initially empty. Each value item in this map is a sorted element queue.

+

Each registry has an associated upgrade candidates map of all instances of unresolved elements, mapping a custom element type to a sorted element queue. It is is initially empty.

Whenever an unresolved element is created, it MUST be added to the respective sorted element queue in upgrade candidates map.

-

Registering an element definition is the responsibility of the element registration algorithm, which MUST be equivalent to running these steps:

+

Elements are upgraded from being unresolved by the upgrade a newly-defined element algorithm.

-
-
-
Input
-
DOCUMENT, the document
-
TYPE, the custom element type of the element being registered
-
PROTOTYPE, the custom element prototype
-
NAME, a local name, optional
-
Output
-
ERROR, a variable that holds one of these values: None, InvalidType, InvalidName, NoRegistry, or DuplicateDefinition
-
-
    -
  1. Let ERROR and DEFINITION be the result of running definition construction algorithm with DOCUMENT, TYPE, PROTOTYPE, and NAME as arguments
  2. -
  3. If ERROR is not None, stop.
  4. -
  5. Let REGISTRY be DOCUMENT's registry
  6. -
  7. If REGISTRY does not exist, set ERROR to NoRegistry and stop.
  8. -
  9. Add DEFINITION to REGISTRY
  10. -
  11. Let MAP be REGISTRY's upgrade candidates map
  12. -
  13. Run element upgrade algorithm with MAP and DEFINITION as arguments.
  14. -
-
- -

The definition construction algorithm creates an element definition and MUST be equivalent to running these steps:

- -
-
-
Input
-
DOCUMENT, the document
-
TYPE, the custom element type of the element being registered
-
PROTOTYPE, the custom element prototype
-
NAME, a local name, optional
-
Output
-
DEFINITION, the element definition
-
ERROR, a variable that holds one of these values: None, InvalidType, InvalidName, or DuplicateDefinition
-
-
    -
  1. Let ERROR be None
  2. -
  3. Convert TYPE to ASCII lowercase
  4. -
  5. If DOCUMENT is an HTML document, convert NAME to ASCII lowercase
  6. -
  7. If TYPE is an invalid custom element type, set ERROR to InvalidType and stop.
  8. -
  9. Let NAMESPACE be HTML Namespace
  10. -
  11. Let IS-SVG be the result of running SVGElement inheritance detection algorithm with PROTOTYPE and the global environment of DOCUMENT as arguments
  12. -
  13. If IS-SVG is true, set NAMESPACE to SVG Namespace [[!SVG11]]
  14. -
  15. If there already exists a definition with the same TYPE, set ERROR to DuplicateDefinition and stop.
  16. -
  17. If NAME was provided and is not null: -
      -
    1. Let BASE be the element interface for NAME and NAMESPACE
    2. -
    3. If BASE does not exist or is an interface for a custom element, set ERROR to InvalidName and stop.
    4. -
  18. -
  19. Otherwise: -
      -
    1. If NAMESPACE is SVG Namespace, set ERROR to InvalidName and stop.
    2. -
    3. Let NAME be TYPE
    4. -
  20. -
  21. Let LIFECYCLE be lifecycle callbacks
  22. -
  23. Transfer callback named createdCallback to LIFECYCLE from property named createdCallback on PROTOTYPE
  24. -
  25. Transfer callback named attachedCallback to LIFECYCLE from property named attachedCallback on PROTOTYPE
  26. -
  27. Transfer callback named detachedCallback to LIFECYCLE from property named detachedCallback on PROTOTYPE
  28. -
  29. Transfer callback named attributeChangedCallback to LIFECYCLE from property named attributeChangedCallback on PROTOTYPE
  30. -
  31. Let DEFINITION be an element definition with custom element type set to TYPE, local name to NAME, namespace to NAMESPACE, custom element prototype to PROTOTYPE, and lifecycle callbacks to LIFECYCLE.
  32. -
-
- -

The SVGElement inheritance detection algorithm MUST run these steps:

- -
-
-
Input
-
DESCENDANT, an object whose inheritance is being detected
-
ENVIRONMENT, a global environment
-
Output
-
RESULT, true, if DESCENDANT inherits from SVGElement or false otherwise
-
-
    -
  1. Set RESULT to true
  2. -
  3. Let SVG-PROTOTYPE be the SVGElement's interface prototype object for ENVIRONMENT
  4. -
  5. Let PROTOTYPE be DESCENDANT
  6. -
  7. Repeat until PROTOTYPE is undefined: -
      -
    1. If PROTOTYPE strictly equals to SVG-PROTOTYPE, stop and return RESULT.
    2. -
    3. Let PROTOTYPE be the result of getting a prototype of PROTOTYPE
    4. -
    -
  8. Set RESULT to false
  9. -
  10. Return RESULT.
  11. -
-
- - -

The element upgrade algorithm upgrades unresolved elements whose definition is now registered and MUST be equivalent to running these steps:

- -
-
-
Input
-
Let MAP, an upgrade candidates map
-
DEFINITION, element definition
-
Output
-
None
-
-
    -
  1. Let TYPE be the custom element type in DEFINITION
  2. -
  3. Let CANDIDATES be the sorted element queue for TYPE and NAMESPACE in MAP
  4. -
  5. For each item ELEMENT in CANDIDATES: -
      -
    1. Enqueue created callback for ELEMENT
    2. -
  6. -
  7. Set CANDIDATES to empty sorted element queue.
  8. -
-
-

Extensions to Document Interface

+

New Document Method

-

The registerElement method of the Document interface provides a way to register a custom element and returns its custom element constructor.

+

The defineElement method of the Document interface provides a way to register a custom element.

 partial interface Document {
-    Function registerElement(DOMString type, optional ElementRegistrationOptions options);
+    void defineElement(DOMString type, Function constructor, optional ElementRegistrationOptions options);
 };
 
 dictionary ElementRegistrationOptions {
-     object? prototype = null;
      DOMString? extends = null;
 };
 
-

When called, the registerElement method MUST run these steps:

+

The defineElement(type, constructor, options) method, when invoked, must run these steps:

-
-
-
Input
-
DOCUMENT, method's context object, a document
-
TYPE, the custom element type of the element being registered
-
PROTOTYPE, the custom element prototype, optional
-
EXTENDS, the local name of an HTML or SVG element that is being extended, optional
-
Output
-
CONSTRUCTOR, the custom element constructor
-
-
    -
  1. If PROTOTYPE is null, let PROTOTYPE be the result of invoking Object.create with HTMLElement's interface prototype object as only argument
  2. -
  3. Let NAME be EXTENDS
  4. -
  5. Let ERROR be the result of running the element registration algorithm with DOCUMENT, TYPE, PROTOTYPE, and NAME as arguments
  6. -
  7. If ERROR is InvalidType, throw a SyntaxError and stop.
  8. -
  9. If ERROR is not None, throw a NotSupportedError and stop.
  10. -
  11. Return result of running custom element constructor generation algorithm with DOCUMENT and PROTOTYPE as arguments.
  12. +
      +
    1. If IsConstructor(constructor) is false, throw a TypeError and abort these steps.
    2. + +
    3. If the context object is an HTML document, let type be converted to ASCII lowercase.
    4. + +
    5. If type is an invalid custom element type, throw a SyntaxError and abort these steps.
    6. + +
    7. Let registry be the context object's registry. If registry does not exist, throw a NotSupportedError and abort these steps.
    8. + +
    9. If registry contains an entry with type type, throw a NotSupportedError and abort these steps.
    10. + +
    11. If registry contains an entry with contructor constructor, throw a NotSupportedError and abort these steps.
    12. + +
    13. Let localName be type.
    14. + +
    15. Let extends be the value of the extends member of options.
    16. + +
    17. +

      If extends is not null:

      + +
        +
      1. If the context object is an HTML document, let extends be converted to ASCII lowercase.
      2. + +
      3. If there is no element interface for extends and the HTML namespace, throw a NotSupportedError and abort these steps.
      4. + +
      5. Set localName to extends.
      6. +
      +
    18. + +
    19. Let prototype be Get(constructor, "prototype"). Rethrow any exceptions.
    20. + +
    21. If Type(prototype) is not Object, throw a TypeError exception.
    22. + +
    23. Let attachedCallback be Get(prototype, "attachedCallback"). Rethrow any exceptions.
    24. + +
    25. Let detachedCallback be Get(prototype, "detachedCallback"). Rethrow any exceptions.
    26. + +
    27. Let attributeChangedCallback be Get(prototype, "attributeChangedCallback"). Rethrow any exceptions.
    28. + +
    29. Let definition be a new custom element definition with custom element type type, local name localName, constructor constructor, prototype prototype, and lifecycle callbacks attachedCallback, detachedCallback, and attributeChangedCallback.
    30. + +
    31. Add definition to registry.
    32. + +
    33. Let map be registry's upgrade candidates map.
    34. + +
    35. Upgrade a newly-defined element given map and definition.
    -
-
-

ElementRegistrationOptions is an abstraction that enables using function objects and ES6 classes as the second argument of document.registerElement method.

-
+
+

A simple example of registering a custom element using [[!ECMASCRIPT]] class syntax:

-
-

In order to register a custom element with a prototype, other than HTMLElement or SVGElement, the caller of document.registerElement has to first build a proper prototype object that inherits from HTMLElement. Here's a simple example of how one could do this:

-
-document.registerElement('x-foo', {
-    prototype: Object.create(HTMLParagraphElement.prototype, {
-        firstMember: {
-            get: function() { return "foo"; },
-            enumerable: true,
-            configurable: true
-        },
-        // specify more members for your prototype.
-        // ...
-    }),
-    extends: 'p'
-});
-

Note the use of extends option to specify that the element is being registered as a type extension -- that is, this element does not introduce a new tag (like the custom tag elements do), but rather extends an existing element of type HTMLParagraphElement. Here's how one could instantiate this element:

-
-<p is="x-foo">Paragraph of amazement</p>
-
-Or imperatively, in JavaScript: -
-var foo = document.createElement('p', 'x-foo');
-
+
+    document.defineElement("x-foo", class XFoo extends HTMLElement {
+        constructor() {
+            super(); // this is mandatory
+
+            this._initialData = "foo";
+        }
+    });
+ +

An example of registering an element that uses a type extension:

+ +
+    document.defineElement("x-bar", class XBar extends HTMLParagraphElement {
+        constructor() {
+            super(); // still mandatory
+
+            this._initialData = "bar";
+        }
+    }, { extends: "p" });
+ +

This latter example does not introduce a new tag (like the custom tag elements do), but rather extends an existing element of type HTMLParagraphElement. Here's how one could instantiate this element:

+ +
+    <p is="x-foo">Paragraph of amazement</p>
+ + Or imperatively, in JavaScript: + +
+    var foo = document.createElement("p", "x-foo");
-

Elements with SVGElement prototype deserve a special mention: using custom tag approach results in ignored elements in SVG. Thus, your SVG-based custom elements would almost always be type extensions.

+

:unresolved Element Pseudo-class

-

The :unresolved pseudo-class [[!CSS3-SELECTORS]] MUST match all custom elements whose created callback has not yet been invoked.

+

The :unresolved pseudo-class [[!CSS3-SELECTORS]] MUST match all custom elements whose custom element constructor has not yet been invoked.

The :unresolved pseudo-class could be used to mitigate the flash of unstyled content [[FOUC]] issues with custom elements. @@ -584,167 +460,237 @@

Instantiating Custom Elements

If both types of custom element types are provided at the time of element's instantiation, the custom tag MUST win over the type extension. -

All custom elements MUST be constructable with a function object, called custom element constructor. This constructor MUST be created with the custom element constructor generation algorithm, which MUST be equivalent to running these steps:

-
-
-
Input
-
PROTOTYPE, the custom element prototype.
-
DOCUMENT, the owner document for new custom element
-
Output
-
CONSTRUCTOR, the custom element constructor
-
-
    -
  1. If PROTOTYPE is already an interface prototype object for any interface object or PROTOTYPE has a non-configurable property named constructor, throw a NotSupportedError and stop.
  2. -
  3. Let DEFINITION be an element definition that has PROTOTYPE as custom element prototype
  4. -
  5. Let CONSTRUCTOR be the interface object whose interface prototype object is PROTOTYPE and when called as a constructor, executes these steps: -
      -
    1. Let ELEMENT be the context object
    2. -
    3. Let TYPE be the custom element type in DEFINITION
    4. -
    5. Let NAME be the local name in DEFINITION
    6. -
    7. Let NAMESPACE be the namespace in DEFINITION
    8. -
    9. Set ELEMENT's local name to NAME, namespace to the NAMESPACE, and node document to DOCUMENT
    10. -
    11. If TYPE is not the same as NAME, set the value of ELEMENT's is attribute to TYPE
    12. -
    13. Enqueue created callback for ELEMENT
    14. -
    15. Return ELEMENT.
    16. -
  6. +
    +

    The HTMLElement Constructor

    + +The HTMLElement interface gains following annotation: + +
    +[Constructor]
    +
    + +The HTMLElement constructor, when invoked, must perform the following steps: + +
      +
    1. Let realm be the result of GetFunctionRealm(the currently executing HTMLElement function).
    2. +
    3. Let document be the associated document of realm's [[\GlobalObject]].
    4. + +
    5. Let registry be document's registry. If document has no registry, throw a TypeError and abort these steps.
    6. + +
    7. Let definition be the entry in registry with constructor equal to NewTarget. If there is no such definition, throw a TypeError and abort these steps.
    8. + +
    9. +

      If definition's construction stack is empty, perform the following substeps:

      + +
        +
      1. Let localName be the definition's local name.
      2. + +
      3. Return a new element that implements HTMLElement, with no attributes, namespace set to the HTML namespace, local name set to localName, and node document set to document.
      4. +
      + +

      This occurs when author script constructs a new custom element directly, e.g. via new MyCustomElement().

      +
    10. + +
    11. Let instance be the last entry in definition's construction stack.
    12. + +
    13. +

      If instance is an already constructed marker, throw an InvalidStateError and abort these steps.

      + +

      This can occur when the author code inside the custom element constructor invokes super() multiple times.

      +
    14. + +
    15. Let prototype be definition's prototype.
    16. + +
    17. Perform element.[[\SetPrototypeOf]](prototype). Rethrow any exceptions.
    18. + +
    19. Replace the last entry in definition's construction stacka with an already constructed marker.
    20. + +
    21. +

      Return instance.

      + +

      This step is normally reached when upgrading a custom element; the existing element is returned, so that the super() call inside the custom element constructor assigns that existing element to this.

      +
    -
+ +

For now, the HTMLElement constructor cannot be invoked directly. It only works when used via a super() call inside a custom element constructor.

+ +
+
-

Extensions to Document Interface

+

Changes to Document Methods

-

To allow creating both custom tag and type extension-style custom elements, the createElement or createElementNS methods have overloads with a typeExtension argument:

+

To allow creating both custom tag and type extension-style custom elements, the createElement or createElementNS methods gain optional typeExtension arguments. Their new definitions are:

 partial interface Document {
-    Element createElement(DOMString localName, DOMString typeExtension);
-    Element createElementNS(DOMString? namespace, DOMString qualifiedName, DOMString typeExtension);
+    Element createElement(DOMString localName, optional DOMString typeExtension);
+    Element createElementNS(DOMString? namespace, DOMString qualifiedName, optional DOMString typeExtension);
 };
 
-
+
+ +The createElement(localName, typeExtension) method, when invoked, must run these steps: -

Instead of step 3 in createElement and step 9 in createElementNS (the steps that determine element interface, createElement and createElementNS methods MUST run the following -steps:

    -
  1. Let TYPE be typeExtension, or localName if typeExtension is not present
  2. -
  3. If an element definition with matching localName, namespace, and TYPE is not registered with token's document, set TYPE to localName
  4. -
  5. Let interface be the element interface for TYPE as local name and namespace (HTML Namespace for createElement)
  6. +
  7. If localName does not match the Name production, throw an InvalidCharacterError exception.
  8. + +
  9. If the context object is an HTML document, let localName be converted to ASCII lowercase.
  10. + +
  11. Let registry be the context object's registry.
  12. + +
  13. +

    If typeExtension is provided:

    + +
      +
    1. Let definition be the entry in registry with custom element type typeExtension.
    2. + +
    3. If definition's local name is not localName, throw a TypeError exception and abort these steps.
    4. + +
    5. Let interface be the element interface for localName and the HTML namespace.
    6. + +
    7. Let result be a new element that implements interface, with no attributes, namespace set to the HTML namespace, local name set to localName, and node document set to the context object.
    8. + +
    9. Set the attribute value for result using is and type.
    10. +
    +
  14. + +
  15. +

    Otherwise, if registry contains an entry with local name localName:

    + +
      +
    1. Let definition be the entry in registry with local name localName.
    2. + +
    3. Let C be definition's constructor.
    4. + +
    5. Return the result of Construct(C), rethrowing any exceptions.
    6. +
    +
  16. + +
  17. +

    Otherwise:

    + +
      +
    1. Let interface be the element interface for localName and the HTML namespace.
    2. + +
    3. Return a new element that implements interface, with no attributes, namespace set to the HTML namespace, local name set to localName, and node document set to the context object.
    4. +
    +
-

Additionally, both createElement or createElementNS methods MUST run the following steps just before returning the result:

+The createElementNS(namespace, qualifiedName, typeExtension) method, when invoked, must run these steps: +
    -
  1. If TYPE is not the same as localName, set the value of ELEMENT's is attribute to TYPE
  2. -
  3. Enqueue created callback for ELEMENT
  4. +
  5. Let namespace, prefix, and localName be the result of passing namespace and qualifiedName to validate and extract. Rethrow any exceptions.
  6. + +
  7. Let registry be the context object's registry.
  8. + +
  9. +

    If typeExtension is provided:

    + +
      +
    1. If namespace is not the HTML namespace, or if prefix is not null, throw a TypeError exception and abort these steps.
    2. + +
    3. Let definition be the entry in registry with custom element type typeExtension.
    4. + +
    5. If definition's local name is not localName, throw a TypeError exception and abort these steps.
    6. + +
    7. Let interface be the element interface for localName and the HTML namespace.
    8. + +
    9. Let result be a new element that implements interface, with no attributes, namespace set to the HTML namespace, local name set to localName, and node document set to the context object.
    10. + +
    11. Set the attribute value for result using is and type.
    12. +
    +
  10. + +
  11. +

    Otherwise, if namespace is the HTML namespace and registry contains an entry with local name localName:

    + +
      +
    1. If prefix is not null, throw a TypeError exception and abort these steps.
    2. + +
    3. Let definition be the entry in registry with local name localName.
    4. + +
    5. Let C be definition's constructor.
    6. + +
    7. Let result be Construct(C). Rethrow any exceptions.
    8. + +
    9. +

      If result does not implement the HTMLElement interface, throw a TypeError exception and abort these steps.

      + +

      This is meant to be a brand check to ensure that the object was allocated by the HTMLElement constructor. Eventually Web IDL may give us a more precise way to do brand checks.

      +
    10. + +
    11. Return result.
    12. +
    +
  12. + +
  13. +

    Otherwise:

    + +
      +
    1. Let interface be the element interface for localName and the HTML namespace.
    2. + +
    3. Return a new element that implements interface, with no attributes, namespace set to the HTML namespace, local name set to localName, and node document set to the context object.
    4. +
    +
+
+
-
+
-

Parsing Custom Elements

+

Changes to the HTML Parser

-

To enable instantiating custom elements during tree construction, a conforming UA MUST run enqueue created callback whenever creating a custom element.

+

This section needs a lot more detail added on how exactly it is going to patch [[HTML]], in order to execute script during parsing.

+ +

To enable instantiating custom elements during tree construction, whenever creating a custom element, the user agent must pause (similar to when parsing <script>) and run Construct(the relevant custom element constructor). It'll need to handle errors and cases where the wrong interface is returned.

-

This modification to tree construction has the consequence of custom elements being created when parsing HTML documents or fragments.

+

This modification to tree construction has the consequence of custom elements being created when parsing HTML documents or fragments. Probably we need to tweak this a bit so that fragment parsing is done differently (with upgrade semantics).

-
-

Custom Elements and ECMAScript 6

-

Once the ECMAScript Standard Edition 6 [[ECMASCRIPT-6.0]] is released, this section will be integrated into the respective areas of this specification. Until then, here is an overview of how ECMAScript 6 and Custom Elements integrate.

+
+

Upgrading

-

If the user agent implements the @@create method, this specification would stop treating the ElementRegistrationOptions options argument in registerElement as a dictionary, and instead view it as a the custom element constructor.

+

To upgrade a newly-defined element, given a custom element definition definition and an upgrade candidates map map, perform the following steps:

-

Instead of generating a constructor, the user agent will now mutate this argument to have a new @@create method that creates a new element object.

+
    +
  1. Let type be definition's custom element type.
  2. -

    Since the registerElement's second argument is now a constructor function, the element definition should change to hold that constructor function, rather than the custom element prototype.

    +
  3. Let candidates be the sorted element queue which is the value of the entry in map with key type.
  4. -

    To accommodate this change, the element registration algorithm to the following steps:

    +
  5. For each element candidate in candidates, enqueue a lifecycle callback for candidate that upgrades candidate.
  6. -
    -
    -
    Input
    -
    DOCUMENT, the document
    -
    TYPE, the custom element type of the element being registered
    -
    FUNCTION, the custom element constructor
    -
    NAME, a local name, optional
    -
    Output
    -
    ERROR, a variable that holds one of these values: None, InvalidType, InvalidName, NoRegistry, or DuplicateDefinition
    -
    -
      -
    1. Let ERROR and DEFINITION be the result of running definition construction algorithm with DOCUMENT, TYPE, PROTOTYPE, and NAME as arguments
    2. -
    3. If ERROR is not None, stop.
    4. -
    5. Let REGISTRY be DOCUMENT's registry
    6. -
    7. If REGISTRY does not exist, set ERROR to NoRegistry and stop.
    8. -
    9. Add DEFINITION to REGISTRY
    10. -
    11. Let MAP be REGISTRY's upgrade candidates map
    12. -
    13. Run element upgrade algorithm with MAP and DEFINITION as arguments.
    14. +
    15. Set the value of the entry in map whose key is type to an empty sorted element queue.
    -
    -

    The steps run when calling registerElement will change to:

    +

    To upgrade a custom element, given as input a custom element definition definition and an element element, run the following steps:

    -
    -
    -
    Input
    -
    DOCUMENT, method's context object, a document
    -
    TYPE, the custom element type of the element being registered
    -
    FUNCTION, the custom element constructor, optional
    -
    EXTENDS, the local name of an HTML or SVG element that is being extended, optional
    -
    Output
    -
    CONSTRUCTOR, the custom element constructor
    -
    -
      -
    1. If FUNCTION is null: -
        -
      1. Let FUNCTION be the result of calling FunctionAllocate with HTMLElement as the functionPrototype and true as strict
      2. -
      3. Let PROTOTYPE be the result of calling Object.create with HTMLElement's interface prototype object as only argument
      4. -
      5. Call DefinePropertyOrThrow(PROTOTYPE, "constructor", PropertyDescriptor{[[\Value]]: FUNCTION, [[\Writable]]: false, [[\Enumerable]]: false, [[\Configurable]]: false})
      6. -
      7. Call DefinePropertyOrThrow(FUNCTION, "prototype", PropertyDescriptor{[[\Value]]: PROTOTYPE, [[\Writable]]: false, [[\Enumerable]]: false, [[\Configurable]]: false})
      8. -
    2. -
    3. Otherwise: -
        -
      1. Let PROTOTYPE be the result of Get(FUNCTION, "prototype")
      2. -
    4. +
        +
      1. Add element to the end of definition's construction stack.
      2. -
      3. Let NAME be EXTENDS
      4. -
      5. Let ERROR be the result of running the element registration algorithm with DOCUMENT, TYPE, PROTOTYPE, and NAME as arguments
      6. -
      7. If ERROR is InvalidType, throw a SyntaxError and stop.
      8. -
      9. If ERROR is not None, throw a NotSupportedError and stop.
      10. -
      11. Return result of running custom element constructor generation algorithm with PROTOTYPE, FUNCTION, and DOCUMENT as arguments.
      12. -
      -
    +
  7. Let C be definition's constructor.
  8. -

    Similarly, the custom element constructor generation algorithm will change as follows:

    +
  9. Let constructResult be Construct(C).
  10. -
    -
    -
    Input
    -
    PROTOTYPE, the custom element prototype
    -
    FUNCTION, the custom element constructor
    -
    DOCUMENT, the owner document for new custom element
    -
    Output
    -
    FUNCTION, the mutated custom element constructor
    -
    -
      -
    1. If FUNCTION is already an interface object for any interface, throw a NotSupportedError and stop.
    2. -
    3. Let DEFINITION be an element definition that has PROTOTYPE as custom element prototype
    4. -
    5. Let CREATE be a function which when called, executes these steps: -
        -
      1. Let ELEMENT be the context object
      2. -
      3. Let TYPE be the custom element type in DEFINITION
      4. -
      5. Let NAME be the local name in DEFINITION
      6. -
      7. Let NAMESPACE be the namespace in DEFINITION
      8. -
      9. Set ELEMENT's local name to NAME, namespace to the NAMESPACE, and node document to DOCUMENT
      10. -
      11. If TYPE is not the same as NAME, set the value of ELEMENT's is attribute to TYPE
      12. -
      13. Enqueue created callback for ELEMENT
      14. -
      15. Return ELEMENT.
      16. -
    6. -
    7. Call DefinePropertyOrThrow(FUNCTION, @@create, PropertyDescriptor{[[\Value]]: CREATE, [[\Writable]]: false, [[\Enumerable]]: false, [[\Configurable]]: false})
    8. -
    9. Return FUNCTION.
    10. +
    11. Remove element from the end of definition's construction stack.
    12. + +
    13. If constructResult is an abrupt completion, return constructResult (i.e., re-throw the exception).
    14. + +
    15. +

      If SameValue(constructResult.[[\value]], element) is false, throw a InvalidStateError and terminate these steps.

      + +

      This can occur if C constructs another instance of the same custom element before calling super(), or if C uses JavaScript's return-override feature to return an arbitrary object from the constructor.

      +
    -
    + +
+
+

Custom Element Semantics

The default semantics of a custom element is dependent upon the form in which it is instantiated:

@@ -830,17 +776,7 @@

Further Reading for Developers

-

All Algorithms in One Diagram

-

To help navigate through various parts of the spec and their interactions, here is a diagram that attempts to put all algorithms actions that trigger them in one space. Click on each box to go to the corresponding algorithm or action.

- -
- -
All algorithms in one diagram
-
- -
-

Acknowledgments

David Hyatt developed XBL 1.0, and Ian Hickson co-wrote XBL 2.0. These documents provided tremendous insight into the problem of behavior attachment and greatly influenced this specification.