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 @@
-
-
diff --git a/spec/custom/index.html b/spec/custom/index.html
index fc06a3bd..06b1e0e5 100644
--- a/spec/custom/index.html
+++ b/spec/custom/index.html
@@ -80,7 +80,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]] and [[!HTML]].
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 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:
The element definition describes a custom element and consists of:
+A custom element definition describes a custom element and consists of:
At the time of creation, a document could be associated with a registry. A registry is a set of element definitions.
+Each custom element definition's construction stack is manipulated by the upgrade a custom element algorithm and the HTMLElement
constructor. Each entry in the list will be either an element or an already constructed marker.
Element registration is a process of adding an element definition to a registry. One element definition can only be registered with one registry.
+At the time of creation, a document could be associated with a registry. A registry is a set of custom element definitions.
-If a document has a registry associated with it, then for this document and a given element definition in the registry, the custom element's interface MUST be the element interface for local name and namespace values of custom element type and the namespace of the element definition, respectively.
-Element registration is a process of adding an custom element definition to a registry. One custom element definition can only be registered with one registry.
If a document does not have a registry associated with it, all attempts at element registration will fail.
@@ -158,32 +156,15 @@A custom element can go through these changes during its lifetime:
Various callbacks can be invoked when a custom element goes through some of these changes. These callbacks are stored internally as a collection of key-value pairs and called lifecycle callbacks.
- -To transfer a callback named name from an object property named property to lifecycle callbacks, the user agent MUST run the following steps:
-Various callbacks can be invoked when a custom element goes through some of these changes. These callbacks are stored internally as a collection of lifecycle callbacks. They can be looked up by name, which is one of attachedCallback
, detachedCallback
, or attributeChangedCallback
.
The following callbacks are recognized:
To set custom element prototype on a custom element, a conforming user agent MUST run the following steps or their equivalent:
- -[[\Prototype]]
internal property of ELEMENT to PROTOTYPE.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
, if the namespace is HTML Namespace [[!HTML]];SVGElement
, if namespace is SVG Namespace [[!SVG11]]; orBecause 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
.
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:
- -None
, InvalidType
, InvalidName
, NoRegistry
, or DuplicateDefinition
None
, stop.NoRegistry
and stop.The definition construction algorithm creates an element definition and MUST be equivalent to running these steps:
- -None
, InvalidType
, InvalidName
, or DuplicateDefinition
None
InvalidType
and stop.SVGElement
inheritance detection algorithm with PROTOTYPE and the global environment of DOCUMENT as argumentsDuplicateDefinition
and stop.InvalidName
and stop.InvalidName
and stop.The SVGElement
inheritance detection algorithm MUST run these steps:
SVGElement
or false otherwiseSVGElement
's interface prototype object for ENVIRONMENTundefined
:
- Elements are upgraded from being unresolved by the upgrade a newly-defined element algorithm.
-The element upgrade algorithm upgrades unresolved elements whose definition is now registered and MUST be equivalent to running these steps:
- -Document
InterfaceDocument
MethodThe 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); + Function 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 method, when invoked, must run these steps:
-Object.create
with HTMLElement
's interface prototype object as only argumentInvalidType
, throw a SyntaxError
and stop.None
, throw a NotSupportedError
and stop.SyntaxError
and abort these steps.NotSupportedError
and abort these steps.NotSupportedError
and abort these steps.extends
member of options.If extends is not null:
+ +NotSupportedError
and abort these steps.TypeError
exception.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-classThe :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 +457,224 @@
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:
-constructor
, throw a NotSupportedError
and stop.is
attribute to TYPEHTMLElement
ConstructorHTMLElement
interface gains following annotation:
+
++[Constructor] ++ +The
HTMLElement
constructor, when invoked, must perform the following steps:
+
+TypeError
and abort these steps.If definition's construction stack is empty, perform the following substeps:
+ +HTMLElement
, with no attributes, namespace set to the HTML namespace, local name set to localName, and node document set to document.This occurs when author script constructs the custom element directly, e.g. via new MyCustomElement()
.
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.
For now, the HTMLElement
constructor cannot be invoked directly. It only works when used via a super()
call inside a custom element constructor.
Document
InterfaceDocument
MethodsTo 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); };-
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:
createElement
)Name
production, throw an InvalidCharacterError
exception.If typeExtension is provided:
+ +TypeError
exception and abort these steps.is
and type.Otherwise, if registry contains an entry with local name localName:
+ +Otherwise:
+ +Additionally, both createElement or createElementNS methods MUST run the following steps just before returning the result:
+ThecreateElementNS(namespace, qualifiedName, typeExtension)
method, when invoked, must run these steps:
+
is
attribute to TYPEIf typeExtension is provided:
+ +TypeError
exception and abort these steps.TypeError
exception and abort these steps.is
and type.Otherwise, if namespace is the HTML namespace and registry contains an entry with local name localName:
+ +TypeError
exception and abort these steps.Otherwise:
+ +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, a conforming UA MUST run enqueue created callback whenever creating a custom element.
+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).
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).
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.
+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.
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.
+To accommodate this change, the element registration algorithm to the following steps:
+None
, InvalidType
, InvalidName
, NoRegistry
, or DuplicateDefinition
None
, stop.NoRegistry
and stop.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:
-FunctionAllocate
with HTMLElement
as the functionPrototype and true as strictHTMLElement
's interface prototype object as only argumentDefinePropertyOrThrow(
PROTOTYPE, "constructor", PropertyDescriptor{[[\Value]]:
FUNCTION, [[\Writable]]: false, [[\Enumerable]]: false, [[\Configurable]]: false})
DefinePropertyOrThrow(
FUNCTION, "prototype", PropertyDescriptor{[[\Value]]:
PROTOTYPE, [[\Writable]]: false, [[\Enumerable]]: false, [[\Configurable]]: false})
Get(
FUNCTION, "prototype")
InvalidType
, throw a SyntaxError
and stop.None
, throw a NotSupportedError
and stop.Similarly, the custom element constructor generation algorithm will change as follows:
+NotSupportedError
and stop.is
attribute to TYPEDefinePropertyOrThrow(
FUNCTION, @@create, PropertyDescriptor{[[\Value]]:
CREATE, [[\Writable]]: false, [[\Enumerable]]: false, [[\Configurable]]: false})
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()
.
The default semantics of a custom element is dependent upon the form in which it is instantiated:
@@ -830,17 +760,7 @@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.
- - - -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.