From 7f63535da39a1cbf7f8f68563abc6f05f760990a Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 6 Apr 2016 13:17:48 -0400 Subject: [PATCH] Add support for custom elements This is the first part of upstreaming custom elements into the DOM and HTML Standards, instead of having them be in a separate spec that is essentially a bunch of monkeypatches. The second part will be upstreaming the remaining portions into HTML. See https://rawgit.com/w3c/webcomponents/15a203c8393aef0df7223ab1d43406aa11a7e71e/spec/custom/index.html for the source material, in particular the sections labeled "DOM+". Some minor bugs were fixed while upstreaming, mainly in the "remove" algorithm for elements. The rest of the changes were editorial. --- dom.bs | 404 +++++++++++++++++++++++++++++++++++++++++++++++-------- dom.html | 282 +++++++++++++++++++++++++++++++------- 2 files changed, 581 insertions(+), 105 deletions(-) diff --git a/dom.bs b/dom.bs index 07a4a67e..75cb7ef4 100644 --- a/dom.bs +++ b/dom.bs @@ -23,6 +23,7 @@ Bikeshed problems: --> +
 urlPrefix: https://encoding.spec.whatwg.org/
@@ -95,6 +96,22 @@ urlPrefix: https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#
         text: service worker
         text: script resource
         text: has ever been evaluated flag
+urlPrefix: https://rawgit.com/w3c/webcomponents/15a203c8393aef0df7223ab1d43406aa11a7e71e/spec/custom/index.html#
+    type: selector; url: dfn-defined; text: :defined
+    type: dfn; urlPrefix: dfn-
+        text: look up a custom element definition; url: look-up-custom-element-definition
+        text: type extension
+        text: name; url: element-definition-name; for: custom element definition
+        text: local name; url: element-definition-local-name; for: custom element definition
+        text: constructor; url: element-definition-constructor; for: custom element definition
+        text: upgrade an element; url: upgrade-a-custom-element
+        text: enqueue a custom element upgrade reaction; url: enqueue-upgrade
+        text: enqueue a custom element callback reaction; url: enqueue-lifecycle-callback
+        text: valid custom element name
+        text: try to upgrade an element; url: try-upgrade
+urlPrefix: https://tc39.github.io/ecma262/#; spec: ECMASCRIPT
+    text: Construct; url: sec-construct; type: abstract-op
+    text: TypeError; url: sec-native-error-types-used-in-this-standard-typeerror; type: exception
 

Document nodes are simply known as documents.

@@ -2509,25 +2544,25 @@

The getElementsByTagNameNS(namespace, localName) method, when invoked, must return the list of elements with namespace namespace and local name localName for the context object.

The getElementsByClassName(classNames) method, when invoked, must return the list of elements with class names classNames for the context object.

-
- Given the following XHTML fragment: -
<div id="example">
-  <p id="p1" class="aaa bbb"/>
-  <p id="p2" class="aaa ccc"/>
-  <p id="p3" class="bbb ccc"/>
-</div>
-
+
+ Given the following XHTML fragment: +
<div id="example">
+  <p id="p1" class="aaa bbb"/>
+  <p id="p2" class="aaa ccc"/>
+  <p id="p3" class="bbb ccc"/>
+</div>

A call to document.getElementById("example").getElementsByClassName("aaa") would return a HTMLCollection with the two paragraphs p1 and p2 in it.

A call to getElementsByClassName("ccc bbb") would only return one node, however, namely p3. A call to document.getElementById("example").getElementsByClassName("bbb  ccc ") would return the same thing.

A call to getElementsByClassName("aaa,bbb") would return no nodes; none of the elements above are in the aaa,bbb class.


-
element = document . createElement(localName) +
element = document . createElement(localName [, options])
Returns an element in the HTML namespace with localName as local name. (In an HTML document localName is lowercased.)

If localName does not match the Name production an InvalidCharacterError exception will be thrown.

-
element = document . createElementNS(namespace, qualifiedName) +

When supplied, optionsis member can be used to create a type extension.

+
element = document . createElementNS(namespace, qualifiedName [, options])
Returns an element with namespace namespace. Its namespace prefix will be everything before ":" (U+003E) in qualifiedName or null. Its local name will be @@ -2543,13 +2578,14 @@

namespace is the XMLNS namespace and neither qualifiedName nor namespace prefix is "xmlns". -
documentFragment = document . createDocumentFragment() +

When supplied, optionsis member can be used to create a type extension.

+
documentFragment = document . createDocumentFragment()
Returns a DocumentFragment node. -
text = document . createTextNode(data) +
text = document . createTextNode(data)
Returns a Text node whose data is data. -
comment = document . createComment(data) +
comment = document . createComment(data)
Returns a Comment node whose data is data. -
processingInstruction = document . createProcessingInstruction(target, data) +
processingInstruction = document . createProcessingInstruction(target, data)
Returns a ProcessingInstruction node whose target is target and data is data. If target does not match the Name production an InvalidCharacterError exception will be thrown. If data contains "?>" an InvalidCharacterError exception will be thrown. @@ -2557,23 +2593,34 @@

The element interface for any name and namespace is Element, unless stated otherwise.

The HTML Standard will e.g. define that for html and the HTML namespace, the HTMLHtmlElement interface is used. [HTML]

-

The createElement(localName) method, when +

The createElement(localName) method, when invoked, must run these steps:

  1. If localName does not match the Name production, throw an InvalidCharacterError exception.
  2. If the context object is an HTML document, let localName be converted to ASCII lowercase. -
  3. Let interface be the element interface for localName and the HTML namespace. -
  4. 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. +
  5. Let is be the value of is member of options, or null if no + such member exists. +
  6. Let definition be the result of looking up a custom element definition, given the context object, the HTML namespace, localName, and is. +
  7. If is is non-null and definition is null, then throw a NotFoundError. +
  8. Let element be the result of creating an element given the context object, localName, null, the HTML namespace, is, and + with the synchronous custom elements flag set. Rethrow any exceptions. +
  9. If is is non-null, then set an attribute value for element using + "is" and is. +
  10. Return element.
-

The createElementNS(namespace, qualifiedName) method, when invoked, must run these steps:

+

The createElementNS(namespace, qualifiedName) method, when invoked, must run these steps:

  1. Let namespace, prefix, and localName be the result of passing namespace and qualifiedName to validate and extract. Rethrow any exceptions. -
  2. Let interface be the element interface for localName and namespace. -
  3. Return a new element that implements interface, - with no attributes, namespace set to namespace, namespace prefix set to prefix, local name set to localName, and node document set to the context object. +
  4. Let is be the value of is member of options, or null if no + such member exists. +
  5. Let definition be the result of looking up a custom element definition, given the context object, namespace, localName, and is. +
  6. If is is non-null and definition is null, then throw a NotFoundError. +
  7. Let element be the result of creating an element given the context object, localName, prefix, namespace, is, and with the synchronous custom elements flag set. Rethrow any exceptions. +
  8. If is is non-null, then set an attribute value for element using + "is" and is. +
  9. Return element.

The createDocumentFragment() method, when invoked, must return a new DocumentFragment node with its node document set to the context object.

@@ -2925,12 +2972,123 @@

Element nodes are simply known as elements.

-

Elements have an associated namespace, namespace prefix, and local name. When an element is created, its local name is always given. Unless -explicitly given when an element is created, its namespace and namespace prefix are null.

-

Elements also have an associated shadow root (null or a shadow root). Null unless otherwise stated.

+

Elements have an associated namespace, namespace prefix, local name, and custom element state. When an element is created, all of these values are +initialized.

+

An element’s custom element state is one of "undefined", +"uncustomized", or "custom". An element whose custom element state is "uncustomized" or "custom" is said to be defined. An element whose custom element state is "custom", is said to be custom.

+

Whether or not an element is defined is used to determine the behavior of the :defined pseudo-class. Whether or not an element is custom is used to determine the +behavior of the mutation algorithms.

+
+ +

The following code illustrates elements in each of these three states:

+
<!DOCTYPE html>
+<script>
+  window.customElements.define("sw-rey", class extends HTMLElement {})
+  window.customElements.define("sw-finn", class extends HTMLElement {}, { extends: "p" })
+  window.customElements.define("sw-kylo", class extends HTMLElement {
+    constructor() {
+      super()
+      throw new Error("The droid... stole a freighter?")
+    }
+  })
+</script>
+
+<!-- "undefined" (not defined, not custom) -->
+<sw-han></sw-han>
+<sw-kylo></sw-kylo>
+<p is="sw-luke"></p>
+<p is="asdf"></p>
+
+<!-- "uncustomized" (defined, not custom) -->
+<p></p>
+<asdf></asdf>
+
+<!-- "custom" (defined, custom) -->
+<sw-rey></sw-rey>
+<p is="sw-finn"></p>
+
+

Elements also have an associated shadow root (null or a shadow root). It is null unless otherwise stated.

An element’s qualified name is its local name if its namespace prefix is null, and its namespace prefix, followed by ":", followed by its local name, otherwise.

User agents could have this as an internal slot as an optimization, but are not required to do so. The standard has this concept for readability.

+

To create an element, +given a document, prefix, localName, namespace, is, and optional synchronous custom elements flag, run these steps:

+
    +
  1. +

    Let result be null.

    +
  2. +

    Let definition be the result of looking up a custom element definition given document, namespace, localName, and is.

    +
  3. +

    If definition is non-null, and definition’s name is not equal to its local name (i.e., definition represents a type extension), then:

    +
      +
    1. +

      Let interface be the element interface for localName and the HTML namespace.

      +
    2. +

      Set result to a new element that implements interface, + with no attributes, namespace set to the HTML namespace, namespace prefix set to prefix, local name set + to localName, custom element state set to "undefined", and node document set to document.

      +
    3. +

      If the synchronous custom elements flag is set, upgrade element using definition.

      +
    4. +

      Otherwise, enqueue a custom element upgrade reaction given result and definition.

      +
    +
  4. +

    Otherwise, if definition is non-null, then:

    +
      +
    1. +

      If the synchronous custom elements flag is set:

      +
        +
      1. +

        Let C be definition’s constructor.

        +
      2. +

        Set result to Construct(C). Rethrow any + exceptions.

        +
      3. +

        If result does not implement the HTMLElement interface, throw a TypeError exception.

        +

        This is meant to be a brand check to ensure that the object was allocated by the HTMLElement constructor. See webidl #97 about making this more + precise.

        +
      4. +

        If result’s attribute list is not empty, throw a NotSupportedError exception.

        +
      5. +

        If result has children, throw a NotSupportedError exception.

        +
      6. +

        If result’s parent is not null, throw a NotSupportedError exception.

        +
      7. +

        If result’s node document is not document, throw a NotSupportedError exception.

        +
      8. +

        If result’s namespace is not the HTML namespace, throw a NotSupportedError exception.

        +
      9. +

        If result’s local name is not equal to localName, throw a NotSupportedError exception.

        +
      10. +

        Set result’s namespace prefix to prefix.

        +
      11. +

        Set result’s custom element state to "custom".

        +
      +
    2. +

      Otherwise:

      +
        +
      1. +

        Set result to a new element that implements the HTMLElement interface, with no attributes, namespace set to the HTML namespace, namespace prefix set to prefix, local name set + to localName, custom element state set to "undefined", and node document set to document.

        +
      2. +

        Enqueue a custom element upgrade reaction given result and definition.

        +
      +
    +
  5. +

    Otherwise:

    +
      +
    1. +

      Let interface be the element interface for localName and namespace.

      +
    2. +

      Set result to a new element that implements interface, + with no attributes, namespace set to namespace, namespace prefix set to prefix, local name set + to localName, custom element state set to "uncustomized", and node document set to document.

      +
    3. +

      If document has a browsing context, and namespace is the HTML namespace, and either localName is a valid custom element name or is is is non-null, set result’s custom element state to "undefined".

      +
    +
  6. +

    Return result.

    +

Elements also have an ordered attribute list exposed through a NamedNodeMap. Unless explicitly given when an element is created, its attribute list is empty. An element has an attribute A if A is in its attribute list.

This specification uses and applicable specifications can use the hooks an attribute is set, an attribute is changed, an attribute is added, and an attribute is removed, for further processing of the attribute’s value.

@@ -2938,6 +3096,8 @@

  • Queue a mutation record of "attributes" for element with name attribute’s local name, namespace attribute’s namespace, and oldValue attribute’s value. +
  • If element is custom, then enqueue a custom element callback reaction with element, callback name "attributeChangedCallback", and an argument + list containing attribute’s local name, attribute’s value, value, and attribute’s namespace.
  • Set attribute’s value to value.
  • An attribute is set and an attribute is changed. @@ -2948,6 +3108,8 @@

    Queue a mutation record of "attributes" for element with name attribute’s local name, namespace attribute’s namespace, and oldValue null. +
  • If element is custom, then enqueue a custom element callback reaction with element, callback name "attributeChangedCallback", and an argument + list containing attribute’s local name, null, attribute’s value, and attribute’s namespace.
  • Append the attribute to the element’s attribute list.
  • Set attribute’s element to element.
  • An attribute is set and an attribute is added. @@ -2957,6 +3119,8 @@

  • Queue a mutation record of "attributes" for element with name attribute’s local name, namespace attribute’s namespace, and oldValue attribute’s value. +
  • If element is custom, then enqueue a custom element callback reaction with element, callback name "attributeChangedCallback", and an argument + list containing attribute’s local name, attribute’s value, null, and attribute’s namespace.
  • Remove attribute from the element’s attribute list.
  • Set attribute’s element to null.
  • An attribute is removed. @@ -2967,6 +3131,8 @@

    Queue a mutation record of "attributes" for element with name oldAttr’s local name, namespace oldAttr’s namespace, and oldValue oldAttr’s value.

    +
  • If element is custom, then enqueue a custom element callback reaction with element, callback name "attributeChangedCallback", and an argument + list containing oldAttr’s local name, oldAttr’s value, newAttr’s value, and oldAttr’s namespace.
  • Replace oldAttr by newAttr in the element’s attribute list.

  • @@ -4854,10 +5020,12 @@

    Acknowledgmen

    This standard is written by Anne van Kesteren (Mozilla, annevk@annevk.nl) with substantial contributions from Aryeh Gregor (Mozilla, ayg@aryeh.name) and Ms2ger (Mozilla, ms2ger@gmail.com).

    +

    Part of the revision history of the integration points related to custom elements can be +found in the w3c/webcomponents repository, which +is available under the W3C Permissive Document License.

    Per CC0, to the extent possible under law, the editors have waived all copyright and related or neighboring rights to this work.

    -

    Index

    Terms defined by this specification

    @@ -4991,6 +5159,7 @@

    converted to ASCII lowercase, in §2.2
  • converted to ASCII uppercase, in §2.2
  • converting nodes into a node, in §4.2.6 +
  • create an element, in §4.9
  • createAttribute(localName), in §4.5
  • createAttributeNS(namespace, qualifiedName), in §4.5
  • createCDATASection(), in §8.2 @@ -5000,7 +5169,9 @@

    createDocument(namespace, qualifiedName, doctype), in §4.5.1
  • createDocumentType(qualifiedName, publicId, systemId), in §4.5.1
  • createElement(localName), in §4.5 +
  • createElement(localName, options), in §4.5
  • createElementNS(namespace, qualifiedName), in §4.5 +
  • createElementNS(namespace, qualifiedName, options), in §4.5
  • createEntityReference(), in §8.2
  • createEvent(interface), in §4.5
  • createHTMLDocument(), in §4.5.1 @@ -5014,8 +5185,11 @@

    createTreeWalker(root), in §4.5
  • createTreeWalker(root, whatToShow), in §4.5
  • createTreeWalker(root, whatToShow, filter), in §4.5 +
  • creating an element, in §4.9
  • currentNode, in §6.2
  • currentTarget, in §3.2 +
  • custom, in §4.9 +
  • custom element state, in §4.9
  • CustomEvent, in §3.3
  • CustomEventInit, in §3.3
  • CustomEvent(type), in §3.3 @@ -5027,6 +5201,7 @@

    attribute for CharacterData, in §4.10
  • defaultPrevented, in §3.2 +
  • defined, in §4.9
  • deleteContents(), in §5.2
  • deleteData(offset, count), in §4.10
  • descendant, in §2.1 @@ -5092,6 +5267,7 @@

    dfn for Attr, in §4.9.2
  • Element, in §4.9 +
  • ElementCreationOptions, in §4.5
  • element interface, in §4.5
  • ELEMENT_NODE, in §4.4
  • empty, in §4.2 @@ -5240,6 +5416,7 @@

    internalSubset, in §8.2
  • intersectsNode(node), in §5.2
  • invoke, in §3.8 +
  • is, in §4.5
  • isConnected, in §4.4
  • isDefaultNamespace(namespace), in §4.4
  • isElementContentWhitespace, in §8.2 @@ -5679,6 +5856,12 @@

    Terms defined by reference