From 4fced1a568257f999b47c5fb76cb532823a81267 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 13 Apr 2016 18:17:33 -0400 Subject: [PATCH] Add customElements.whenDefined() API As discussed in https://github.com/w3c/webcomponents/issues/427, this adds the ability for authors to wait for a given custom element name to become defined. --- source | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/source b/source index 24f8974201e..fb044f6ab1c 100644 --- a/source +++ b/source @@ -66977,7 +66977,7 @@ console.log(plasticButton2.getAttribute("is")); // will output "plastic-button"< is truly one-time will need a guard to prevent it from running twice.

  • In general, the constructor should be used to set up initial state and default values, and - to set up event listeners and possibly a shadow root

    .
  • + to set up event listeners and possibly a shadow root.

    Several of these requirements are checked during element @@ -67202,6 +67202,7 @@ console.log(plasticButton2.getAttribute("is")); // will output "plastic-button"<

    interface CustomElementsRegistry {
       void define(DOMString name, Function constructor, optional ElementRegistrationOptions options);
       any get(DOMString name);
    +  Promise<void> whenDefined(DOMString name);
     };
     
     dictionary ElementRegistrationOptions {
    @@ -67215,6 +67216,11 @@ dictionary ElementRegistrationOptions {
       data-x="concept-custom-element-definition-local-name">local name, or constructor.

    +

    Every CustomElementsRegistry also has a when-defined promise map, + mapping valid custom element names to lists of + promises. It is used to implement the whenDefined() method.

    +
    window . customElements . define(name, @@ -67240,6 +67246,14 @@ dictionary ElementRegistrationOptions { data-x="concept-custom-element-definition-name">name. Returns undefined if there is no custom element definition with the given name. + +
    window . customElements . whenDefined(name)
    + +
    Returns a promise that will be fulfilled when a custom element becomes defined + with the given name. (If such a custom element is already defined, the returned + promise will be immediately fulfilled.) Returns a promise rejected with a + SyntaxError if not given a valid custom element name.

    Element definition is a process of adding a custom element definition @@ -67336,6 +67350,21 @@ dictionary ElementRegistrationOptions { attributeChangedCallback (stored by their corresponding name).

  • Add definition to this CustomElementsRegistry.

  • + +
  • +

    If this CustomElementsRegistry's when-defined promise map + contains an entry with key name:

    + +
      +
    1. Let promiseList be the value of that entry.

    2. + +
    3. For each promise in promiseList, resolve promise with + undefined.

    4. + +
    5. Delete that entry from this CustomElementsRegistry's when-defined + promise map.

    6. +
    +
  • When invoked, the ElementRegistrationOptions {

  • Otherwise, return undefined.

  • +

    When invoked, the whenDefined(name) method + must run these steps:

    + +
      +
    1. If name is not a valid custom element name, then return a promise + rejected with a SyntaxError exception and abort these steps.

    2. + +
    3. If this CustomElementsRegistry contains an entry with name name, then return a + promise resolved with undefined and abort these steps.

    4. + +
    5. Let map be this CustomElementsRegistry's when-defined + promise map.

    6. + +
    7. If map does not contain an entry with key name, create an entry in + map with key name and whose value is an empty list.

    8. + +
    9. Let promiseList be the value of the entry in map with key + name.

    10. + +
    11. Let promise be a new promise, and append promise to + promiseList.

    12. + +
    13. Return promise.

    14. +
    + +
    +

    The whenDefined() method can be + used to avoid performing an action until all appropriate custom + elements are defined. In this example, we + combine it with the :defined pseudo-class to hide a + dynamically-loaded article's contents until we're sure that all of the autonomous custom elements it uses are defined.

    + +
    articleContainer.hidden = true;
    +
    +fetch(articleURL)
    +  .then(response => response.text())
    +  .then(text => {
    +    articleContainer.innerHTML = text;
    +
    +    return Promise.all(
    +      [...articleContainer.querySelectorAll(":not(:defined)")]
    +        .map(el => customElements.whenDefined(el.localName))
    +    );
    +  })
    +  .then(() => {
    +    articleContainer.hidden = false;
    +  });
    +
    +

    Upgrades

    To upgrade an element, given as @@ -119286,6 +119367,7 @@ INSERT INTERFACES HERE J. King, Jacob Davies, Jacques Distler, + Jake Archibald, Jake Verbaten, Jakub Łopuszański, Jakub Wilk,