4.13. ~custom要素

4.13.1. 序論

~INFORMATIVE

`~custom要素$は、作者に, “全装備の” ~DOM要素を自前で築く仕方を提供する。 作者は常に自身の文書に非~標準の要素を利用して,~scripting等が起きた後に~app特有の挙動を追加することもできるが、そのような要素は,歴史的に非~適合とされてきており,また 機能~面でも不足である。 ~custom要素を`定義-$することにより、作者は,要素を適正に構築する方法, および その類の要素が変化に対しどう反応すべきか,を構文解析器に伝えれるようになる。 ◎ Custom elements provide a way for authors to build their own fully-featured DOM elements. Although authors could always use non-standard elements in their documents, with application-specific behavior added after the fact by scripting or similar, such elements have historically been non-conforming and not very functional. By defining a custom element, authors can inform the parser how to properly construct an element and how elements of that class should react to changes.

~custom要素は、(~HTMLの要素の様な)既存の~platform特色機能を[ 低levelの,作者~向けに公開される拡張可能点(~custom要素~定義の様な) ]を通して説明することにより、より大きな, “~platformを合理化する” ~~活動の一環を成す。 今日の~custom要素の能力には まだ制限が多く、~HTMLの既存の要素の挙動を — 機能, 意味論の両面で — 全部的には説明できないが、この隔たりは,時を経るうちに埋められるものと期待0されている。 ◎ Custom elements are part of a larger effort to "rationalise the platform", by explaining existing platform features (like the elements of HTML) in terms of lower-level author-exposed extensibility points (like custom element definition). Although today there are many limitations on the capabilities of custom elements—both functionally and semantically—that prevent them from fully explaining the behaviors of HTML's existing elements, we hope to shrink this gap over time.

4.13.1.1. 自律的~custom要素の作成法

~INFORMATIVE

`自律的~custom要素$の作成-法を例で~~説明するため、ここでは,小さな国旗~icon( `flag-icon^e )の描画を~encapsulateする~custom要素を定義してみる。 目標は、次の様な利用を可能にすることである: ◎ For the purposes of illustrating how to create an autonomous custom element, let's define a custom element that encapsulates rendering a small icon for a country flag. Our goal is to be able to use it like so:

<flag-icon country="nl"></flag-icon>

これを行うため、先ず,~custom要素~用に `HTMLElement$I を拡張する~classを宣言する: ◎ To do this, we first declare a class for the custom element, extending HTMLElement:

class FlagIcon extends HTMLElement {
  constructor() {
    super();
    this._countryCode = null;
  }

  static get observedAttributes() { return ["country"]; }

  attributeChangedCallback(%name, %oldValue, %newValue) {
    /* 
%name は常に, `observedAttributes^jc が返す結果のどれか(ここでは `country^l のみ)
◎
name will always be "country" due to observedAttributes
 */
    this._countryCode = %newValue;
    this._updateRendering();
  }
  connectedCallback() {
    this._updateRendering();
  }

  get country() {
    return this._countryCode;
  }
  set country(%v) {
    this.setAttribute("country", %v);
  }

  _updateRendering() {
/* 
読者への演習に残しておく。
が,おそらく、
`this.ownerDocument.defaultView^m で,挿入-先の文書が`属する閲覧文脈$があるかどうか検査して、ないなら何もしないことが求められるであろう。
◎
Left as an exercise for the reader. But, you'll probably want to check this.ownerDocument.defaultView to see if we've been inserted into a document with a browsing context, and avoid doing any work if not.
 */
  }
}

次に,この~classを利用して要素を定義する必要がある: ◎ We then need to use this class to define the element:

`customElements$m.define("flag-icon", FlagIcon);

この時点で、上の~codeは働くことになる! 構文解析器は、 `flag-icon^e ~tagに出会う度に, `FlagIcon^jc ~classの新たな~instanceを構築して,その新たな `country^jc 属性について上の~codeに伝えてくることになり、~codeは,それを利用して,当の要素の内部~状態を設定し, (適切なときは)その描画も更新する。 ◎ At this point, our above code will work! The parser, whenever it sees the flag-icon tag, will construct a new instance of our FlagIcon class, and tell our code about its new country attribute, which we then use to set the element's internal state and update its rendering (when appropriate).

`flag-icon^e 要素を ~DOM~APIを利用して作成することもできる: ◎ You can also create flag-icon elements using the DOM API:

const %flagIcon = document.createElement("flag-icon")
%flagIcon.country = "jp"
document.body.appendChild(%flagIcon)

最後に、`~custom要素~構築子$自身を利用することもできる。 すなわち、上の~codeは次に等価になる: ◎ Finally, we can also use the custom element constructor itself. That is, the above code is equivalent to:

const %flagIcon = new FlagIcon()
%flagIcon.country = "jp"
document.body.appendChild(%flagIcon)

4.13.1.2. ~custom化された組込みの要素の作成法

~INFORMATIVE

`~custom化された組込みの要素$は、別種の`~custom要素$であり,その定義は少しばかり異なる。 また、その利用は,`自律的~custom要素$に比較してかなり異なる。 それは、既存の~HTML要素の挙動を 新たな~custom機能性で拡張して,再利用できるようにするものである。 この再利用は重要になる — あいにく,~HTML要素の既存の挙動の多くは、純粋に`自律的~custom要素$だけでは~~再現できないので。 代わりに,`~custom化された組込みの要素$では、[ 構築~時に~customな挙動を~installすること, ~lifecycle~hook, 既存の要素への~prototype~chain ]が許容され、本質的に,これらの能力を既存の要素の上層に “mix-in” する。 ◎ Customized built-in elements are a distinct kind of custom element, which are defined slightly differently and used very differently compared to autonomous custom elements. They exist to allow reuse of behaviors from the existing elements of HTML, by extending those elements with new custom functionality. This is important since many of the existing behaviors of HTML elements can unfortunately not be duplicated by using purely autonomous custom elements. Instead, customized built-in elements allow the installation of custom construction behavior, lifecycle hooks, and prototype chain onto existing elements, essentially "mixing in" these capabilities on top of the already-existing element.

`~custom化された組込みの要素$には、`自律的~custom要素$とは別個の構文が要求される — ~UAや他の~softwareは、当の要素の意味論と挙動を 要素の局所~名で識別しているので。 すなわち、既存の挙動の上層に,`~custom化された組込みの要素$の概念を築くためには、拡張元の要素が自身の元の局所~名を保ち続けることが不可欠になる。 ◎ Customized built-in elements require a distinct syntax from autonomous custom elements because user agents and other software key off an element's local name in order to identify the element's semantics and behavior. That is, the concept of customized built-in elements building on top of existing behavior depends crucially on the extended elements retaining their original local name.

次の例では、 `plastic-button^jc という名前の`~custom化された組込みの要素$を作成する。 それは,通常の~buttonの様に挙動するが、~click時には気の利いた~animation効果が追加される。 前と同様,~classを定義する所から始めるが、今度は, `HTMLElement$I でなく `HTMLButtonElement$I を拡張する: ◎ In this example, we'll be creating a customized built-in element named plastic-button, which behaves like a normal button but gets fancy animation effects added whenever you click on it. We start by defining a class, just like before, although this time we extend HTMLButtonElement instead of HTMLElement:

class PlasticButton extends HTMLButtonElement {
  constructor() {
    super();

    this.addEventListener("click", () => {
      /* 
何か気の利いた~animation効果を描く
◎
Draw some fancy animation effects!
 */
    });
  }
}

上のような~custom要素を定義するときには、 `extends^jc ~optionも指定する必要がある: ◎ When defining our custom element, we have to also specify the extends option:

`customElements$m.define("plastic-button", PlasticButton, { extends: "button" });

一般に,どの名前の要素を拡張しているかは、どの要素~interfaceを拡張しているか見るだけでは決定できない。 多くの要素は、同じ~interfaceを共有しているので(例えば、 `q$e と `blockquote$e は `HTMLQuoteElement$I を共有している)。 ◎ In general, the name of the element being extended cannot be determined simply by looking at what element interface it extends, as many elements share the same interface (such as q and blockquote both sharing HTMLQuoteElement).

なので,`~custom化された組込みの要素$を利用するためには、 `button$e 要素~上で `is$a 属性を利用する: ◎ To use our customized built-in element, we use the is attribute on a button element:

<button `is$a="plastic-button">Click Me!</button>

`~custom化された組込みの要素$を`自律的~custom要素$として利用しようと試行しても、働かない。 すなわち、 `<plastic-button>Click me?</plastic-button>^s は、 単純に 特別な挙動を何も伴わない `HTMLElement$I を作成することになる。 ◎ Trying to use a customized built-in element as an autonomous custom element will not work; that is, <plastic-button>Click me?</plastic-button> will simply create an HTMLElement with no special behavior.

型~拡張された要素を~program的に作成する必要がある場合、次の形による `createElement()$m を利用できる: ◎ If you need to create a type-extended element programmatically, you can use the following form of createElement():

const %plasticButton = document.createElement("button", { is: "plastic-button" });
%plasticButton.textContent = "Click me!";

構築子は、前と同様に働くことになる: ◎ And as before, the constructor will also work:

const %plasticButton2 = new PlasticButton();
console.log(%plasticButton2.localName);          /* 
`button^l と出力される
◎
will output "button"
 */
console.log(%plasticButton2.getAttribute("is")); /* 
`plastic-button^l と出力される
◎
will output "plastic-button"
 */

特筆すべき点として、 `button$e に備わる特別なふるまい — その,~focus時の挙動, `~form提出$に関与する能, `disabled$a 属性, 等々 — すべては、この種の “plastic ~button” にも適用される。 ◎ Notably, all the of the ways in which button is special apply to such "plastic buttons" as well: their focus behavior, ability to participate in form submission, the disabled attribute, and so on.

`~custom化された組込みの要素$は、既存の~HTML要素を,~UAが供給する有用な挙動や~APIが備わるように拡張できるように設計されている。 そのようなわけで、拡張できるのは この仕様に定義される既存の~HTML要素に限られ、次に挙げるような,`要素~interface$として `HTMLUnknownElement$I を利用するものと定義されている旧来の要素は 拡張できない ⇒ `bgsound$eO, `blink$eO, `isindex$eO, `keygen$eO, `multicol$eO, `nextid$eO, `spacer$eO ◎ Customized built-in elements are designed to allow extension of existing HTML elements that have useful user-agent supplied behavior or APIs. As such, they can only extend existing HTML elements defined in this specification, and cannot extend legacy elements such as bgsound, blink, isindex, keygen, multicol, nextid, or spacer that have been defined to use HTMLUnknownElement as their element interface.

この要件を定めている理由には、将来との互換性もある: 仮に,`~custom化された組込みの要素$が現在~未知の要素 — 例えば `combobox^e とする — を拡張するように定義された場合、そのように派生された要素の消費者たちは,[ その基底である `combobox^e 要素は,~UAが供給する挙動に関わらないこと ]に依存することになり、この仕様が将来に `combobox^e 要素を定義できなくなる。 ◎ One reason for this requirement is future-compatibility: if a customized built-in element was defined that extended a currently-unknown element, for example combobox, this would prevent this specification from defining a combobox element in the future, as consumers of the derived customized built-in element would have come to depend on their base element having no interesting user-agent-supplied behavior.

加えて、 `applet$e 要素も拡張できない — それは ~Web~platformから除去されつつある過程にあるので。 ◎ Additionally, applet elements cannot be extended, as they are in the process of being removed from the Web platform.

4.13.1.3. 自律的~custom要素の欠点

~INFORMATIVE

下に指定されるように,および上に示唆されたように、単純に `taco-button^e と称される要素を定義した上で利用しても,その種の要素が~buttonを`表現-$することにはならない。 すなわち、[ ~Web~browser, 検索engine, ~accessibility技術 ]などの~toolは、結果の要素を,単に定義された名前に基づいて自動的に~buttonとして扱うわけではない。 ◎ As specified below, and alluded to above, simply defining and using an element called taco-button does not mean that such elements represent buttons. That is, tools such as Web browsers, search engines, or accessibility technology will not automatically treat the resulting element as a button just based on its defined name.

`自律的~custom要素$を利用しつつ,[ 様々な利用者から欲される,~buttonの意味論 ]を伝達するためには、いくつかの技法を使役する必要がある: ◎ To convey the desired button semantics to a variety of users, while still using an autonomous custom element, a number of techniques would need to be employed:

  • `tabindex$a 属性を追加すれば、 `taco-button^e を`対話的~内容$にし,その結果,要素は`~focus可能$になる。 この場合、 `taco-button^e が論理的に不能化されたときには, `tabindex$a 属性も除去する必要があることに注意。 ◎ The addition of the tabindex attribute would make the taco-button interactive content, thus making it focusable. Note that if the taco-button were to become logically disabled, the tabindex attribute would need to be removed.
  • 種々の~ARIA属性を追加すれば、意味論を~accessibility技術に伝達する一助になる。 例えば、 `role$a 属性を `button$l に設定すれば、 “要素は~buttonである” という意味論を伝達することになり、利用者は自身の~accessibility技術の下で,通例の~buttonの様に,その~controlとやりとり可能になる。 また, `aria-label$a 属性を設定して、当の~buttonに`~access可能な名前$を与えることも必要とされる — さもなければ、~accessibility技術は,子~text~nodeを走査して それらを発声することになる。 また,~buttonが論理的に不能化されたときには、 `aria-disabled$a を `true^l に設定すれば,その状態は~accessibility技術へ伝達される。 ◎ The addition of various ARIA attributes helps convey semantics to accessibility technology. For example, setting the role attribute to "button" will convey the semantics that this is a button, enabling users to successfully interact with the control using usual button-like interactions in their accessibility technology. Setting the aria-label attribute is necessary to give the button an accessible name, instead of having accessibility technology traverse its child text nodes and announce them. And setting aria-disabled to "true" when the button is logically disabled conveys to accessibility technology the button's disabled state.
  • ~buttonに共通的に期待される挙動を取扱うために ~event~handlerを追加することも、 ~Web~browser利用者に~buttonの意味論を伝達する一助になる。 この事例で最も関連する~event~handlerは、適切な `keydown$et ~eventを代理して, `click$et ~event化するものになるであろう — そうすれば、~keyboardでも~clickでも,~buttonを作動化できるようになるので。 ◎ The addition of event handlers to handle commonly-expected button behaviors helps convey the semantics of the button to Web browser users. In this case, the most relevant event handler would be one that proxies appropriate keydown events to become click events, so that you can activate the button both with keyboard and by clicking.
  • 既定で提供される視覚的~stylingの他に、 `taco-button^e 要素は,[ 不能化されるなどの,論理的な状態~変化 ]を反映するときにも更新される必要がある。 すなわち、 `taco-button^e に対する~stylesheet規則が何であれ, `taco-button[disabled]^css に対する規則も必要になる。 ◎ In addition to any default visual styling provided for taco-button elements, the visual styling will also need to be updated to reflect changes in logical state, such as becoming disabled; that is, whatever stylesheet has rules for taco-button will also need to have rules for taco-button[disabled].

これらの点を念頭に、~buttonの意味論を伝達する責を負う,全装備の `taco-button^e (不能化させる能も含む)は、次の様な~~形をとるであろう: ◎ With these points in mind, a full-featured taco-button that took on the responsibility of conveying button semantics (including the ability to be disabled) might look something like this:

class TacoButton extends HTMLElement {
  static get observedAttributes() { return ["disabled"]; }

  constructor() {
    super();

    this.addEventListener("keydown", %e => {
      if (%e.keyCode === 32 || %e.keyCode === 13) {
        this.dispatchEvent(new MouseEvent("click", {
          bubbles: true,
          cancelable: true
        }));
      }
    });

    this.addEventListener("click", %e => {
      if (this.disabled) {
        %e.preventDefault();
        %e.stopPropagation();
      }
    });

    this._observer = new MutationObserver(() => {
      this.setAttribute("aria-label", this.textContent);
    });
  }

  connectedCallback() {
    this.setAttribute("role", "button");
    this.setAttribute("tabindex", "0");

    this._observer.observe(this, {
      childList: true,
      characterData: true,
      subtree: true
    });
  }

  disconnectedCallback() {
    this._observer.disconnect();
  }

  get disabled() {
    return this.hasAttribute("disabled");
  }

  set disabled(%v) {
    if (%v) {
      this.setAttribute("disabled", "");
    } else {
      this.removeAttribute("disabled");
    }
  }

  attributeChangedCallback() {
/* 
`observedAttributes^jc に因り
`disabled^a 属性に対してのみ~callされる
◎
only is called for the disabled attribute due to observedAttributes
 */
    if (this.disabled) {
      this.removeAttribute("tabindex");
      this.setAttribute("aria-disabled", "true");
    } else {
      this.setAttribute("tabindex", "0");
      this.setAttribute("aria-disabled", "false");
    }
  }
}

このそれなりに複雑な要素~定義をもってしても、要素は,消費者にとって利用するのは楽でない: それは、そいつの意志で `tabindex$a や `aria-*$a 属性を “不断に生やし続ける” ことになる。 このことは、今の所~custom要素に対しては、既定の[ ~accessibility意味論や, ~focus時の挙動 ]を指定する仕方がなく、そうするためには,これらの属性の利用を強いられるからである(これらは,通例的には、消費者が既定の挙動を上書きするために予約されているが)。 ◎ Even with this rather-complicated element definition, the element is not a pleasure to use for consumers: it will be continually "sprouting" tabindex and aria-* attributes of its own volition. This is because as of now there is no way to specify default accessibility semantics or focus behavior for custom elements, forcing the use of these attributes to do so (even though they are usually reserved for allowing the consumer to override default behavior).

対照的に,前~節に示した 単純な`~custom化された組込みの要素$は、 `button$e 要素の意味論と挙動を自動的に継承することになるので、これらの挙動を手動で実装する必要はない。 一般に、[ 自明でない挙動と意味論を伴うような,~HTMLの既存の要素 ]の上層に築かれる どの要素についても、`~custom化された組込みの要素$の方が[ 開発する/保守する/消費する ]のは容易になる。 ◎ In contrast, a simple customized built-in element, as shown in the previous section, would automatically inherit the semantics and behavior of the button element, with no need to implement these behaviors manually. In general, for any elements with nontrivial behavior and semantics that build on top of existing elements of HTML, customized built-in elements will be easier to develop, maintain, and consume.

4.13.1.4. 要素の作成~後の昇格法

~INFORMATIVE

`要素~定義$は,いつでも生じさせ得る — ~customでない要素が`作成-$された後,適切な`~custom要素~定義$を登録した後に、それを`~custom要素$にすることもできる。 この処理-は、通常の要素から~custom要素への “昇格処理” と呼ばれる。 ◎ Because element definition can occur at any time, a non-custom element could be created, and then later become a custom element after an appropriate definition is registered. We call this process "upgrading" the element, from a normal element into a custom element.

`~custom要素~定義$を登録するのは、それに関連する要素が 構文解析器などにより初期~時に作成された後の方が,好ましいこともある。 `昇格$は、そのような~~用法を可能化し,~custom要素の内容を漸進的に増強できるようにする。 例えば、次の~HTML文書と `img-viewer^e に対する要素~定義は,非同期的に読込まれる: ◎ Upgrades enable scenarios where it may be preferable for custom element definitions to be registered after relevant elements has been initially created, such as by the parser. They allow progressive enhancement of the content in the custom element. For example, in the following HTML document the element definition for img-viewer is loaded asynchronously:

<!DOCTYPE html>
<html lang="ja">
<title>画像~viewerの例</title>

<img-viewer filter="Kelvin">
  <img src="images/tree.jpg" alt="何もないサバンナにそびえる美しい~~木">
</img-viewer>

<script src="js/elements/img-viewer.js" async></script>

ここでの `img-viewer^e 要素に対する定義は、[ ~markup内の `<img-viewer>^s ~tagの後に置かれた, `async$a 属性を有する `script$e 要素 ]を利用して読込まれる。 ~scriptを読込んでいる間、 `img-viewer^e 要素は, `span$e に似た未定義の要素として扱われることになる。 ~scriptが読込まれ,それが `img-viewer^e 要素を定義したとき、頁~上の既存の `img-viewer^e 要素は,その~custom要素~定義が適用されて昇格されることになる(それは、文字列 `Kelvin^l で識別される画像~filterを適用して画像の視覚的な外観を増強することが~~想定されている)。 ◎ The definition for the img-viewer element here is loaded using a script element marked with the async attribute, placed after the <img-viewer> tag in the markup. While the script is loading, the img-viewer element will be treated as an undefined element, similar to a span. Once the script loads, it will define the img-viewer element, and the existing img-viewer element on the page will be upgraded, applying the custom element's definition (which presumably includes applying an image filter identified by the string "Kelvin", enhancing the image's visual appearance).

【 `img-viewer^e の名前には~hyphenがあるので、将来も含めて,~scriptが読込まれる前に特別な意味を持つ要素に解釈される心配はない(`妥当な~custom要素~名$を見よ)。 】


`昇格$が適用されるのは、文書~木~内にある(正式には,`接続されて$いる)要素に限られることに注意。 文書に挿入されていない要素は、昇格されないままになる。 この点について例で~~説明すると: ◎ Note that upgrades only apply to elements in the document tree. (Formally, elements that are connected.) An element that is not inserted into a document will stay un-upgraded. An example illustrates this point:

<!DOCTYPE html>
<html lang="en">
<title>昇格の際どい事例</title>

<example-element></example-element>

<script>
  "use strict";

  const %文書内 = document.querySelector("example-element");
  const %文書外 = document.createElement("example-element");

  /* 
要素~定義の前:
両者とも `HTMLElement^I :
◎
Before the element definition, both are HTMLElement:
 */
  console.assert(%文書内 instanceof HTMLElement);
  console.assert(%文書外 instanceof HTMLElement);

  class ExampleElement extends HTMLElement {}
  `customElements$m.define("example-element", ExampleElement);

  /* 
要素~定義の後:
文書~内にあった方の要素は,この時点で昇格されている:
◎
After element definition, the in-document element was upgraded:
 */
  console.assert(%文書内 instanceof ExampleElement);
  console.assert(!(%文書外 instanceof ExampleElement));

  document.body.appendChild(%文書外);

  /* 
そうでない方の要素を文書の中に移動した後には,それも昇格される:
◎
Now that we've moved the element into the document, it too was upgraded:
 */
  console.assert(%文書外 instanceof ExampleElement);
</script>

4.13.2. ~custom要素の構築子に課される要件

`~custom要素~構築子$を著作する際には、作者には,次の適合性~要件が課される: ◎ When authoring custom element constructors, authors are bound by the following conformance requirements:

  • 正しい~prototype~chain および this 値を確立するため、他のすべての~codeが走る前に — 構築子の本体における最初の文で — `super()^jc が~parameterなしで~callされ~MUST。 ◎ A parameter-less call to super() must be the first statement in the constructor body, to establish the correct prototype chain and this value before any further code is run.
  • `return^jc 文は、単純な早期 return ( `return^jc / `return this^jc )でない限り,構築子の本体に現れては~MUST_NOT。 ◎ A return statement must not appear anywhere inside the constructor body, unless it is a simple early-return (return or return this).
  • 構築子は、[ `document.write()$m / `document.open()$m ]~methodを利用しては~MUST_NOT。 ◎ The constructor must not use the document.write() or document.open() methods.
  • 要素の どの[ 属性/子 ]であれ,検分されては~MUST_NOT — `昇格$がない場合には何も無く、昇格に依拠することは,要素を利用し難いものにするので。 `?^tnote ◎ The element's attributes and children must not be inspected, as in the non-upgrade case none will be present, and relying on upgrades makes the element less usable.
  • どの[ 属性/子 ]であれ,要素に持たせては~MUST_NOT — それは、[ `createElement()$m / `createElementNS()$m ]~methodを用いる消費者の期待に違反するので。 ◎ The element must not gain any attributes or children, as this violates the expectations of consumers who use the createElement or createElementNS methods.
  • 一般に、可能0な限り,仕事は — とりわけ,資源の~fetchingや具現化を孕むものは — `connectedCallback()^jc へ先送りされるべきである。 しかしながら, `connectedCallback()^jc は複数回~callされ得ることに注意 — 初期化を行うような~~真に一度限りの仕事は、重ねて走らないよう,防護する必要がある。 ◎ In general, work should be deferred to connectedCallback as much as possible—especially work involving fetching resources or rendering. However, note that connectedCallback can be called more than once, so any initialization work that is truly one-time will need a guard to prevent it from running twice.
  • 一般に,構築子は、[ 初期~状態や既定の値,あるいは~event~listener,場合によっては`~shadow根$ ]を設定しておくために利用されるべきである。 ◎ 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.

これらの要件のうちいくつかは、`要素を作成-$する間に 直接的/間接的 に検査される。 要件に従わない場合、~custom要素は,構文解析器や~DOM~APIにより~instance化できなくなる。 このことは、構築子から起動される極小taskの内側で行われる仕事にも該当する — `極小task~checkpoint$は、構築の直後から生じれるので。 ◎ Several of these requirements are checked during element creation, either directly or indirectly, and failing to follow them will result in a custom element that cannot be instantiated by the parser or DOM APIs. This is true even if the work is done inside a constructor-initiated microtask, as a microtask checkpoint can occur immediately after construction.

4.13.3. 中核~概念

`~custom要素@ は、`~customである$要素である†。 これは,非公式に言えば、その構築子と~prototypeが,~UAに代わって 作者により定義されることを意味する。 作者が供給する,この構築子~関数は、 `~custom要素~構築子@ と呼ばれる。 ◎ A custom element is an element that is custom. Informally, this means that its constructor and prototype are defined by the author, instead of by the user agent. This author-supplied constructor function is called the custom element constructor.

【† すなわち,昇格される前は、まだ “~customでない” 】

次の 2 つの別個の種別の,`~custom要素$を定義できる: ◎ Two distinct types of custom elements can be defined:

  1. `自律的~custom要素@ は、 `extends^jc ~optionを伴わずに定義されるものである。 この種別の~custom要素の局所~名は、それに定義された`名前$cDに等しくなる。 ◎ An autonomous custom element, which is defined with no extends option. These types of custom elements have a local name equal to their defined name.
  2. `~custom化された組込みの要素@ は、 `extends^jc ~optionを伴って定義されるものである。 この種別の~custom要素の局所~名は,その `extends^jc ~optionに渡される値に等しくなり、それに定義された`名前$cDは `is@a 属性の値として利用される — したがって、値は`妥当な~custom要素~名$で~MUST。 ◎ A customized built-in element, which is defined with an extends option. These types of custom elements have a local name equal to the value passed in their extends option, and their defined name is used as the value of the is attribute, which therefore must be a valid custom element name.

`~custom要素$が`作成-$された後に `is$a 属性の値を変更しても,[ `~is0値$として要素に保存-済みの,要素の挙動 ]は変化しない。 ◎ After a custom element is created, changing the value of the is attribute does not change the element's behavior, as it is saved on the element as its is value.

`自律的~custom要素$の 要素~定義 は、次で与えられる: ◎ Autonomous custom elements have the following element definition:

`分類$:
`~flow内容$/`句内容$/`可触~内容$ ◎ Flow content. ◎ Phrasing content. ◎ Palpable content.
`この要素を利用できる文脈$:
`句内容$が期待される所。 ◎ Where phrasing content is expected.
`内容~model$:
`透過的$。 ◎ Transparent.
`内容~属性$:
`大域~属性$ — ただし、 `is$a 属性は除く。 ◎ Global attributes, except the is attribute
他の,どの名前空間にも属さない任意の属性(注釈文を見よ)。 ◎ Any other attribute that has no namespace (see prose).
`~DOM~interface$:
要素の作者が供給する( `HTMLElement$I を継承する)。 ◎ Supplied by the element's author (inherits from HTMLElement)

`自律的~custom要素$は、特別な意味を有さず,その子たちを`表現-$する。 `~custom化された組込みの要素$は、それが拡張する要素の意味論を継承する。 ◎ An autonomous custom element does not have any special meaning: it represents its children. A customized built-in element inherits the semantics of the element that it extends.

作者は、`自律的~custom要素$に,その機能に関連するものと決定した任意の属性を指定できる — その属性が次を満たす限り:

  • どの名前空間にも属さない。
  • その名前は、`~XML互換$, かつ`~ASCII英大文字$を包含しない。

ただし例外として、 `is$a 属性は,`自律的~custom要素$に指定されては~MUST_NOT(また、指定されても効果はない)。

◎ Any namespace-less attribute that is relevant to the element's functioning, as determined by the element's author, may be specified on an autonomous custom element, so long as the attribute name is XML-compatible and contains no ASCII upper alphas. The exception is the is attribute, which must not be specified on an autonomous custom element (and which will have no effect if it is).

`~custom化された組込みの要素$の属性は、それが拡張する要素に基づく通常の要件に従う。 ~custom属性に基づく挙動を追加するためには、 `data-*$a 属性を利用する。 ◎ Customized built-in elements follow the normal requirements for attributes, based on the elements they extend. To add custom attribute-based behavior, use data-* attributes.


`妥当な~custom要素~名@ は、次の両~要件を満たす文字~並びである: ◎ A valid custom element name is a sequence of characters name that meets all of the following requirements:

  • `PotentialCustomElementName$P 生成規則に合致し~MUST: ◎ name must match the PotentialCustomElementName production:

    `PotentialCustomElementName@P ::=
    [a-z] (`PCENChar$P)* '-' (`PCENChar$P)*
    `PCENChar@P ::=
    "-" | "." | [0-9] | "_" | [a-z] | #xB7 | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x203F-#x2040] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]

    この生成規則は、 `XML$r 仕様の `EBNF 記法$を利用している。 ◎ This uses the EBNF notation from the XML specification. [XML]

  • 次のいずれにも該当しては~MUST_NOT: ◎ name must not be any of the following:

    • `annotation-xml^l
    • `color-profile^l
    • `font-face^l
    • `font-face-src^l
    • `font-face-uri^l
    • `font-face-format^l
    • `font-face-name^l
    • `missing-glyph^l

    注記: 上に挙げた名前は、`適用し得る仕様$ — すなわちここでは `SVG$r, `MATHML$r — に定義される要素のうち,~hyphenを包含するものすべてを要約したものである。 ◎ The list of names above is the summary of all hyphen-containing element names from the applicable specifications, namely SVG and MathML. [SVG] [MATHML]

注記: これらの要件は、`妥当な~custom要素~名$に求められる いくつかの目標を確保するためにある: ◎ These requirements ensure a number of goals for valid custom element names:

  • `~ASCII英小文字$から始まる — ~HTML構文解析器が,それを~textではなく~tagとして扱うことを確保するため。 ◎ They start with an ASCII lower alpha, ensuring that the HTML parser will treat them as tags instead of as text.
  • `~ASCII英大文字$は一切~包含しない — ~UAが ~HTML要素を 常に ~ASCII大小無視に扱えることを確保するため。 ◎ They do not contain any ASCII upper alphas, ensuring that the user agent can always treat HTML elements ASCII-case-insensitively.
  • ~hyphenを包含する — 名前空間付けの利用,および 前方互換性を確保するため(将来において、~hyphenを包含するような局所~名を伴う要素が ~HTML, ~SVG, ~MathML に追加されることはないので)。 ◎ They contain a hyphen, used for namespacing and to ensure forward compatibility (since no elements will be added to HTML, SVG, or MathML with hyphen-containing local names in the future).
  • 構文解析器による制約を超えるそれがある `createElement()$m / `createElementNS()$m でも,常に作成できるようにする。 ◎ They can always be created with createElement() and createElementNS(), which have restrictions that go beyond the parser's.

これらの制約は別として、可能な限り柔軟にするため,多様な名前が許容される — `<math-α>^s や `<emotion-😍>^s の様な利用~事例のために。 ◎ Apart from these restrictions, a large variety of names is allowed, to give maximum flexibility for use cases like <math-α> or <emotion-😍>.

`~custom要素~定義@ は、`~custom要素$を記述し,次のものからなる: ◎ A custom element definition describes a custom element and consists of:

`名前@cD ◎ A name
`妥当な~custom要素~名$ ◎ A valid custom element name
`局所~名@cD ◎ A local name
局所~名 ◎ A local name
`構築子@cD ◎ A constructor
`~custom要素~構築子$を包装する,~Web~IDL `Function$I ~callback関数~型の値 ◎ A Web IDL Function callback function type value wrapping the custom element constructor
`観測先の属性~list@cD ◎ A list of observed attributes
`sequence<DOMString>^jc 型~値 ◎ A sequence<DOMString>
【 観測-対象にする内容~属性たちの名前を~~保持する。 】
`~lifecycle~callback~map@cD ◎ A collection of lifecycle callbacks
次の 4 個の~keyを伴い,いずれの~keyに対応する値も[ ~NULL (既定~値), ~Web~IDL `Function$I ~callback関数~型の値 ]のいずれかをとるような,~map ⇒ `connectedCallback^l, `adoptedCallback^l, `disconnectedCallback^l, `attributeChangedCallback^l ◎ A map, whose four keys are the strings "connectedCallback", "disconnectedCallback", "adoptedCallback", and "attributeChangedCallback". The corresponding values are either a Web IDL Function callback function type value, or null. By default the value of each entry is null.
【 これらがいつ呼ばれるかは, ~custom要素~反応 節を見よ。 】
`構築~stack@cD ◎ A construction stack
初期~時は空~list。 この~listは、`要素を昇格$する~algo, および `~HTML要素~構築子$により操作される。 ~list内の各~entryは、要素, または `すでに構築-済みを表す~marker@i のいずれかになる。 ◎ A list, initially empty, that is manipulated by the upgrade an element algorithm and the HTML element constructors. Each entry in the list will be either an element or an already constructed marker.

`~custom要素~定義を検索-@ する手続きは、所与の ( %文書, %名前空間, %局所~名, %is ) に対し[ `~custom要素~定義$, ~NULL ]のいずれかを返す: ◎ To look up a custom element definition, given a document, namespace, localName, and is, perform the following steps. They will return either a custom element definition or null:

  1. ~IF[ %名前空間 ~NEQ `~HTML名前空間$ ] ⇒ ~RET ~NULL ◎ If namespace is not the HTML namespace, return null.
  2. ~IF[ %文書 が`属する閲覧文脈$はない ] ⇒ ~RET ~NULL ◎ If document does not have a browsing context, return null.
  3. %~registry ~LET %文書 が`属する閲覧文脈$の `Window$I の `CustomElementRegistry$I ~obj ◎ Let registry be document's browsing context's Window's CustomElementRegistry object.
  4. ~IF[ %~registry 内に[ ( `名前$cD, `局所~名$cD ) ~EQ ( %局所~名, %局所~名 ) ]なる`~custom要素~定義$はある ] ⇒ ~RET その`~custom要素~定義$ ◎ If there is custom element definition in registry with name and local name both equal to localName, return that custom element definition.
  5. ~IF[ %~registry 内に[ ( `名前$cD, `局所~名$cD ) ~EQ ( %is, %局所~名 ) ]なる`~custom要素~定義$はある ⇒ ~RET その`~custom要素~定義$ ◎ If there is a custom element definition in registry with name equal to is and local name equal to localName, return that custom element definition.
  6. ~RET ~NULL ◎ Return null.

4.13.4. `CustomElementRegistry^I ~interface

各 `Window$I ~objには、その作成-時に, `CustomElementRegistry$I ~objの一意な~instanceが結付けられる。 ◎ Each Window object is associated with a unique instance of a CustomElementRegistry object, allocated when the Window object is created.

注記: ~custom要素~registryが結付けられるのは, `Document$I ~objではなく, `Window$I ~objである — 各 `~custom要素~構築子$は `HTMLElement$I ~interfaceを継承し, `HTMLElement$I ~interfaceは `Window$I ~objごとに正確に 1 個あるので。 ◎ Custom element registries are associated with Window objects, instead of Document objects, since each custom element constructor inherits from the HTMLElement interface, and there is exactly one HTMLElement interface per Window object.

`Window$I ~interfaceの `customElements@m 属性は、その `Window$I ~objに対する `CustomElementRegistry$I ~objを返さ~MUST。 ◎ The customElements attribute of the Window interface must return the CustomElementRegistry object for that Window object.

interface `CustomElementRegistry@I {
[`CEReactions$] void `define$m(
       DOMString %name,
       Function %constructor,
       optional `ElementDefinitionOptions$I %options
  );
  any `get$m(DOMString name);
  Promise<void> `whenDefined$m(DOMString %name);
};

dictionary `ElementDefinitionOptions@I {
  DOMString `extends^m;
};

各 `CustomElementRegistry$I は、次のものを持つ: ◎ ↓

`~custom要素~定義$の集合
初期~時は空。 一般に,この仕様の各種~algoは、この~registry内の要素を[ `名前$cD, `局所~名$cD, `構築子$cD ]で検索する。 ◎ Every CustomElementRegistry has a set of custom element definitions, initially empty. In general, algorithms in this specification look up elements in the registry by any of name, local name, or constructor.
`要素~定義は走っている~flag@
初期~時は ~OFF。 `要素~定義$が再入的に呼出されるのを防止するためにある。 ◎ Every CustomElementRegistry also has an element definition is running flag which is used to prevent reentrant invocations of element definition. It is initially unset.
`定義済時~promise~map@
`妥当な~custom要素~名$から~promiseへの対応付けを与え、 `whenDefined()$m ~methodを実装するために利用される。 ◎ Every CustomElementRegistry also has a when-defined promise map, mapping valid custom element names to promises. It is used to implement the whenDefined() method.
【 これらの~promiseは、`定義済み$になったとき`解決-$される。 】
%window . `customElements$m . `define(name, constructor)$m
`名前$cD %name の新たな`~custom要素$ — `自律的~custom要素$ — を定義する。 %constructor が その構築子を与え、 %name はその構築子に対応付けられる。 ◎ Defines a new custom element, mapping the given name to the given constructor as an autonomous custom element.
%window . `customElements$m . `define$m(%name, %constructor, { extends: %baseLocalName })
`名前$cD %name の新たな`~custom要素$ — `~custom化された組込みの要素$ — を定義する。 %constructor が その構築子を与え、 %name はその構築子に対応付けられる。 拡張される`要素~型$は、 %baseLocalName 値で識別される。 [ `~custom要素$/未知の要素 ]を拡張しようと試行した場合、 `NotSupportedError$E 例外が投出される。 ◎ Defines a new custom element, mapping the given name to the given constructor as a customized built-in element for the element type identified by the supplied baseLocalName. A "NotSupportedError" DOMException will be thrown upon trying to extend a custom element or an unknown element.
%window . `customElements$m . `get(name)$m
所与の`名前$cD( %name )に対し定義されている`~custom要素~構築子$を検索取得する。 そのような`~custom要素~定義$が見つからない場合は、 `undefined^js を返す。 ◎ Retrieves the custom element constructor defined for the given name. Returns undefined if there is no custom element definition with the given name.
%window . `customElements$m . `whenDefined(name)$m
所与の`名前$cD( %name )の`~custom要素$が`定義済み$になったとき充足されることになる,~promiseを返す(すでに定義済みであれば、充足-済みの~promiseが即時に返されることになる)。 %name が`妥当な~custom要素~名$でない場合、 `SyntaxError$E 例外で`却下された~promise$を返す。 ◎ 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" DOMException if not given a valid custom element name.

`要素~定義@ は、`~custom要素~定義$を `CustomElementRegistry$I に追加する処理-である。 これは、 `define()$m ~methodにより達成される。 ◎ Element definition is a process of adding a custom element definition to the CustomElementRegistry. This is accomplished by the define() method. When invoked, the define(name, constructor, options) method must run these steps:

`define(name, constructor, options)@m ~methodの被呼出時には、次の手続きを走らせ~MUST: ◎ ↑

  1. ~IF[ `IsConstructor$jA( %constructor ) ~EQ ~F ] ⇒ ~THROW `TypeError$E ◎ If IsConstructor(constructor) is false, then throw a TypeError and abort these steps.
  2. ~IF[ %name は`妥当な~custom要素~名$でない ] ⇒ ~THROW `SyntaxError$E ◎ If name is not a valid custom element name, then throw a "SyntaxError" DOMException and abort these steps.
  3. ~IF[ 此れ内に[ `名前$cD ~EQ %name ]なる~entryがある ] ⇒ ~THROW `NotSupportedError$E ◎ If this CustomElementRegistry contains an entry with name name, then throw a "NotSupportedError" DOMException and abort these steps.
  4. ~IF[ 此れ内に[ `構築子$cD ~EQ %constructor ]なる~entryがある ] ⇒ ~THROW `NotSupportedError$E ◎ If this CustomElementRegistry contains an entry with constructor constructor, then throw a "NotSupportedError" DOMException and abort these steps.
  5. %局所~名 ~LET %name ◎ Let localName be name.
  6. %extends ~LET %options に `extends^jc ~memberが[ あれば その値 / なければ ~NULL ] ◎ Let extends be the value of the extends member of options, or null if no such member exists.
  7. ~IF[ %extends ~NEQ ~NULL ]: ◎ If extends is not null, then:

    1. ~IF[ %extends は`妥当な~custom要素~名$である ] ⇒ ~THROW `NotSupportedError$E ◎ If extends is a valid custom element name, then throw a "NotSupportedError" DOMException.
    2. ~IF[ ( %extends, `~HTML名前空間$ ) に対する`要素~interface$ ~EQ `HTMLUnknownElement$I (例えば, %extends がこの仕様~内の要素~定義を指示していないとき) ] ⇒ ~THROW `NotSupportedError$E ◎ If the element interface for extends and the HTML namespace is HTMLUnknownElement (e.g., if extends does not indicate an element definition in this specification), then throw a "NotSupportedError" DOMException.
    3. %局所~名 ~SET %extends ◎ Set localName to extends.
  8. ~IF[ 此れの`要素~定義は走っている~flag$ ~EQ ~ON ] ⇒ ~THROW `NotSupportedError$E ◎ If this CustomElementRegistry's element definition is running flag is set, then throw a "NotSupportedError" DOMException and abort these steps.
  9. 此れの`要素~定義は走っている~flag$ ~SET ~ON ◎ Set this CustomElementRegistry's element definition is running flag.
  10. 次の下位手続き (A), (B) を順に走らす — ただし, (A) にて例外が投出されたときは、~catchして,下の (B) に~~移行する: ◎ Run the following substeps while catching any exceptions:

    (A):

    1. %~prototype ~LET `Get$jA( %constructor, `prototype^l ) (例外投出あり) ◎ Let prototype be Get(constructor, "prototype"). Rethrow any exceptions.
    2. ~IF[ `Type$jA( %~prototype ) ~NEQ `Object^jc ] ⇒ ~THROW `TypeError$E ◎ If Type(prototype) is not Object, then throw a TypeError exception.
    3. %lifecycleCallbacks ~LET 次の~keyを伴い, どの~keyに対応する値も ~NULL にされた~map ⇒ `connectedCallback^l, `disconnectedCallback^l, `adoptedCallback^l, `attributeChangedCallback^l ◎ Let lifecycleCallbacks be a map with the four keys "connectedCallback", "disconnectedCallback", "adoptedCallback", and "attributeChangedCallback", each of which belongs to an entry whose value is null.
    4. ~FOR %lifecycleCallbacks 内の ~EACH ( ~key %~callback名 ) に対し,前~段に挙げられた順に: ◎ For each of the four keys callbackName in lifecycleCallbacks, in the order listed in the previous step:

      1. %~callback値 ~LET `Get$jA( %~prototype, %~callback名 ) (例外投出あり) ◎ Let callbackValue be Get(prototype, callbackName). Rethrow any exceptions.
      2. ~IF[ %~callback値 ~NEQ `undefined^js ] ⇒ %lifecycleCallbacks の~key %~callback名 に対応する値 ~SET %~callback値 を~Web~IDL `Function$I ~callback型`に変換-$した結果 (例外投出あり) ◎ If callbackValue is not undefined, then set the value of the entry in lifecycleCallbacks with key callbackName to the result of converting callbackValue to the Web IDL Function callback type. Rethrow any exceptions from the conversion.
    5. %観測先~属性~list ~LET 空の `sequence<DOMString>^jc ◎ Let observedAttributes be an empty sequence<DOMString>.
    6. ~IF[ %lifecycleCallbacks の~key `attributeChangedCallback^l に対応する値 ~NEQ ~NULL ]: ◎ If the value of the entry in lifecycleCallbacks with key "attributeChangedCallback" is not null, then:

      1. %観測先~属性~反復子 ~LET `Get$jA( %constructor, `observedAttributes^l ) (例外投出あり) ◎ Let observedAttributesIterable be Get(constructor, "observedAttributes"). Rethrow any exceptions.
      2. ~IF[ %観測先~属性~反復子 ~NEQ `undefined^js ] ⇒ %観測先~属性~list ~SET %観測先~属性~反復子 を `sequence<DOMString>^jc 型`に変換-$した結果 (例外投出あり) ◎ If observedAttributesIterable is not undefined, then set observedAttributes to the result of converting observedAttributesIterable to a sequence<DOMString>. Rethrow any exceptions from the conversion.

    (B): ◎ Then, perform the following substep, regardless of whether the above steps threw an exception or not:

    1. 此れの`要素~定義は走っている~flag$ ~SET ~OFF ◎ Unset this CustomElementRegistry's element definition is running flag.
    2. ~IF[ 上の (A) にて例外が投出された ] ⇒ ~THROW その例外 ◎ Finally, if the first set of substeps threw an exception, then rethrow that exception, and terminate this algorithm. Otherwise, continue onward.
  11. %定義 ~LET 次のようにされた,新たな `~custom要素~定義$:

    • `名前$cD ~SET %name
    • `局所~名$cD ~SET %局所~名
    • `構築子$cD ~SET %constructor
    • `観測先の属性~list$cD ~SET %観測先~属性~list
    • `~lifecycle~callback~map$cD ~SET %lifecycleCallbacks
    ◎ Let definition be a new custom element definition with name name, local name localName, constructor constructor, observed attributes observedAttributes, and lifecycle callbacks lifecycleCallbacks.
  12. 此れに %定義 を追加する ◎ Add definition to this CustomElementRegistry.
  13. %文書 ~LET 此れに`関連する大域~obj$に`結付けられている文書$ ◎ Let document be this CustomElementRegistry's relevant global object's associated Document.
  14. %昇格~候補 ~LET %文書 の`~shadowも含む子孫$のうち,次を満たす要素からなる `~shadowも含む木~順序$による~list:

    • ( 名前空間, 局所~名 ) ~EQ ( `~HTML名前空間$, %局所~名 )
    • 加えて,[ %extends ~NEQ ~NULL ]の場合は、次も満たす ⇒ 要素の`~is0値$ ~EQ %name
    ◎ Let upgrade candidates be all elements that are shadow-including descendants of document, whose namespace is the HTML namespace and whose local name is localName, in shadow-including tree order. Additionally, if extends is non-null, only include elements whose is value is equal to name.
  15. ~FOR %昇格~候補 内の ~EACH ( 要素 %要素 ) に対し ⇒ 次を与える下で,`~custom要素を昇格する反応を待入れる$ ⇒ ( %要素, %定義 ) ◎ For each element element in upgrade candidates, enqueue a custom element upgrade reaction given element and definition.
  16. ~IF[ 此れの`定義済時~promise~map$内に[ ~key ~EQ %name ]なる~entry %~entry がある ]: ◎ If this CustomElementRegistry's when-defined promise map contains an entry with key name:

    1. `undefined^js で[ %~entry の値( ~promise ) ]を`解決-$する ◎ Let promise be the value of that entry. ◎ Resolve promise with undefined.
    2. 此れの`定義済時~promise~map$から %~entry を削除する ◎ Delete the entry with key name from this CustomElementRegistry's when-defined promise map.

`get(name)@m ~methodの被呼出時には、次の手続きを走らせ~MUST: ◎ When invoked, the get(name) method must run these steps:

  1. ~IF[ 此れ内に[ `名前$cD ~EQ %name ]なる~entryがある ] ⇒ ~RET その~entryの`構築子$cD ◎ If this CustomElementRegistry contains an entry with name name, then return that entry's constructor.
  2. ~RET `undefined^js ◎ Otherwise, return undefined.

`whenDefined(name)@m ~methodの被呼出時には、次の手続きを走らせ~MUST: ◎ When invoked, the whenDefined(name) method must run these steps:

  1. ~IF[ %name は`妥当な~custom要素~名$でない ] ⇒ ~RET `SyntaxError$E 例外で`却下された新たな~promise$ ◎ If name is not a valid custom element name, then return a new promise rejected with a "SyntaxError" DOMException and abort these steps.
  2. ~IF[ 此れ内に[ `名前$cD ~EQ %name ]なる~entryがある ] ⇒ ~RET `undefined^js で`解決された新たな~promise$ ◎ If this CustomElementRegistry contains an entry with name name, then return a new promise resolved with undefined and abort these steps.
  3. %~map ~LET 此れの`定義済時~promise~map$ ◎ Let map be this CustomElementRegistry's when-defined promise map.
  4. ~IF[ %~map 内に[ ~key ~EQ %name ]なる~entryはない ] ⇒ %~map 内に[ (~key, 値 ) ~SET ( %name, `新たな~promise$ ) ]にされた~entryを作成する ◎ If map does not contain an entry with key name, create an entry in map with key name and whose value is a new promise.
  5. %~promise ~LET %~map 内の[ ~key ~EQ %name ]なる~entryの値 ◎ Let promise be the value of the entry in map with key name.
  6. ~RET %~promise ◎ Return promise.

`whenDefined()$m ~methodは、適切な`~custom要素$がすべて`定義済み$になるまでは,動作が遂行されるのを避けたいときに利用できる。 次の例では、 `defined$ps 疑似類と組合せて、利用する`自律的~custom要素$のすべてが定義済みになるまでは,動的に読込まれる記事の内容( %articleContainer )を隠す。 ◎ 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;
  });

4.13.5. 昇格

`要素を昇格@ する手続きは、所与の ( `~custom要素~定義$ %定義, 要素 %要素 ) に対し,次を走らす: ◎ To upgrade an element, given as input a custom element definition definition and an element element, run the following steps:

  1. ~IF[ %要素 は`~customである$ ] ⇒ ~RET ◎ If element is custom, abort these steps.

    これが生じ得るのは、次の例に示すように,この~algoが再入的に呼出されたときである: ◎ This can occur due to reentrant invocation of this algorithm, as in the following example:

    <!DOCTYPE html>
    <x-foo id="a"></x-foo>
    <x-foo id="b"></x-foo>
    
    <script>
    /* 
    `a^v, `b^v の両者に対し,昇格~反応を待入れるように定義する:
    ◎
    Defining enqueues upgrade reactions for both "a" and "b"
     */
    
    customElements.define("x-foo", class extends HTMLElement {
      constructor() {
        super();
    
        const %b = document.querySelector("#b");
        %b.remove();
    
    /* 
    `a^v, `b^v に対し この構築子が走っている間, `a^v, `b^v は依然として未定義なので、次のように `b^v を文書の中へ挿入するときには、
    `x-foo^e の定義-時に待入れられるものに加え,
    `b^v に対する 2 度目の昇格~反応も待入れることになる。
    ◎
    While this constructor is running for "a", "b" is still undefined, and so inserting it into the document will enqueue a second upgrade reaction for "b" in addition to the one enqueued by defining x-foo.
     */
        document.body.appendChild(%b);
      }
    })
    </script>
    

    したがってこの段は、 `b^v に対し,`要素を昇格$が 2 度目に呼出されるとき、~algoを早退させることになる。 ◎ This step will thus bail out the algorithm early when upgrade an element is invoked with "b" a second time.

  2. ~IF[ %要素 の`~custom要素~状態$ ~EQ `failed^l ] ⇒ ~RET ◎ If element's custom element state is "failed", then abort these steps.
  3. ~FOR %要素 の`属性~list$ 内の ~EACH ( %属性 ) に対し,順に:

    1. 次を与える下で,`~custom要素~callback反応を待入れる$:

      • %要素
      • ~callback名: `attributeChangedCallback^l
      • 引数~list: ( %属性 の局所~名, ~NULL, %属性 の値, %属性 の名前空間 )
    ◎ For each attribute in element's attribute list, in order, 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.
  4. ~IF[ %要素 は`接続されて$いる ]:

    1. 次を与える下で,`~custom要素~callback反応を待入れる$:

      • %要素
      • ~callback名: `connectedCallback^l
      • 引数~list: 空
    ◎ If element is connected, then enqueue a custom element callback reaction with element, callback name "connectedCallback", and an empty argument list.
  5. %定義 の`構築~stack$cDの末尾に %要素 を追加する ◎ Add element to the end of definition's construction stack.
  6. %C ~LET %定義 の`構築子$cD ◎ Let C be definition's constructor.
  7. 次の下位手続き (A), (B) を順に走らす — ただし, (A) にて例外が投出されたときは、~catchして,下の (B) に~~移行する: ◎ Run the following substeps while catching any exceptions:

    (A):

    1. %構築-結果 ~LET ( %C, 空の引数~list ) を与える下で,`~callback関数で構築-$した結果 ◎ Let constructResult be the result of constructing C, with no arguments.

      %C が不適合に `CEReactions$xA 拡張属性~付きの~APIを利用している場合、この~algoの冒頭にて待入れられた反応は、 %C が終わってこの~algoに制御を返す前の,この段の間に実行されることになる。 他の場合、 %C と残りの昇格~処理-を終えた後に実行されることになる。 ◎ If C non-conformantly uses an API decorated with the [CEReactions] extended attribute, then the reactions enqueued at the beginning of this algorithm will execute during this step, before C finishes and control returns to this algorithm. Otherwise, they will execute after C and the rest of the upgrade process finishes.

    2. ~IF[ `SameValue$jA( %構築-結果 . [[value]], %要素 ) ~EQ ~F ] ⇒ ~THROW `InvalidStateError$E ◎ If SameValue(constructResult, element) is false, then throw an "InvalidStateError" DOMException.

      注記: これは、次の場合に生じ得る:

      • %C が、 `super()^jc を~callする前に,同じ~custom要素の別の~instanceを構築している
      • %C が、構築子から任意の~objを返すような,~JS による `return^jc を上書きする特色機能を利用している
      ◎ 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.

    (B): ◎ Then, perform the following substep, regardless of whether the above steps threw an exception or not:

    1. %定義 の`構築~stack$cDから最後の~entryを除去する ◎ Remove the last entry from the end of definition's construction stack.

      注記: %C が `super()^jc を~callして(適合するならば そうすることになる), かつ その~callが成功した場合、除去される~entryは,[ この~algoの冒頭で~pushされた) %要素 ]を置換した, `すでに構築-済みを表す~marker$i になる(`~HTML要素~構築子$がこの置換を行う)。 ◎ Assuming C calls super() (as it will if it is conformant), and that the call succeeds, this will be the already constructed marker that replaced the element we pushed at the beginning of this algorithm. (The HTML element constructor carries out this replacement.)

      そうでない場合( `super()^jc を~callしなかった(すなわち,適合しない)か, `~HTML要素~構築子$が例外を投出した場合)、この~entryは依然として %要素 のままになる。 ◎ If C does not call super() (i.e. it is not conformant), or if any step in the HTML element constructor throws, then this entry will still be element.

    2. ~IF[ 上の (A) にて例外が投出された ]: ◎ Finally, if the above steps threw an exception, then:

      1. %要素 の`~custom要素~状態$ ~SET `failed^l ◎ Set element's custom element state to "failed".
      2. %要素 の`~custom要素~反応~待行列$を空にする ◎ Empty element's custom element reaction queue.
      3. ~THROW 投出された例外 ◎ Rethrow the exception, and terminate this algorithm.
  8. %要素 の`~custom要素~状態$ ~SET `custom^l ◎ Set element's custom element state to "custom".
  9. %要素 の`~custom要素~定義$x ~SET %定義 ◎ Set element's custom element definition to definition.

所与の要素 %要素 を `昇格しようと試行する@ ときは、次の手続きを走らす: ◎ To try to upgrade an element, given as input an element element, run the following steps:

  1. %定義 ~LET 次を与える下で,`~custom要素~定義を検索-$した結果 ⇒ ( %要素 の`~node文書$, %要素 の名前空間, %要素 の局所~名, %要素 の`~is0値$ ) ◎ Let definition be the result of looking up a custom element definition given element's node document, element's namespace, element's local name, and element's is value.
  2. ~IF[ %定義 ~NEQ ~NULL ] ⇒ 次を与える下で,`~custom要素を昇格する反応を待入れる$ ⇒ ( %要素, %定義 ) ◎ If definition is not null, then enqueue a custom element upgrade reaction given element and definition.

4.13.6. ~custom要素~反応

`~custom要素$は、作者~codeを走らすことにより,一定の出来事に応答する能を備える: ◎ A custom element possesses the ability to respond to certain occurrences by running author code:

  • 要素の`昇格$時には、`~custom要素~構築子$を走らす。 ◎ When upgraded, its constructor is run.
  • 要素が`接続され$たときは、その `connectedCallback()^jc を走らす。 ◎ When it becomes connected, its connectedCallback is run.
  • 要素が`切断され$たときは、その `disconnectedCallback()^jc を走らす。 ◎ When it becomes disconnected, its disconnectedCallback is run.
  • 要素が他の文書に`受入され$たときは、その `adoptedCallback()^jc を走らす。 ◎ When it is adopted into a new document, its adoptedCallback is run.
  • 要素のいずれかの属性が[ `変更-$A / `付加-$A / `除去-$A / `置換-$A ]されたときは、その `attributeChangedCallback()^jc を走らす。 ◎ When any of its attributes are changed, appended, removed, or replaced, its attributeChangedCallback is run.

これらの反応は、 `~custom要素~反応@ と総称される。 ◎ We call these reactions collectively custom element reactions.

`~custom要素~反応$は、[ それを与える作者~codeが,他から~~干渉されると困る演算の途中で走らない ]ように,特別に~careされる下で呼出される。 それらの反応は、実質的に “利用者~scriptに~~制御が返される直前まで” 遅延される。 このことは、ほとんどの目的0においては,それらは同期的に実行するように現れるが、いくつかの演算(`~cloneする$, `範囲$を操作するなど)が複雑に複合された事例では、関連する~UA処理~手続きすべてが完了するまで遅延された上で,~~一括して走らすことを意味する。 ◎ The way in which custom element reactions are invoked is done with special care, to avoid running author code during the middle of delicate operations. Effectively, they are delayed until "just before returning to user script". This means that for most purposes they appear to execute synchronously, but in the case of complicated composite operations (like cloning, or range manipulation), they will instead be delayed until after all the relevant user agent processing steps have completed, and then run together as a batch.

加えて,これらの反応の精確な順序付けは、下に述べる,待行列たちの~stackが成す,いくぶん複雑な~systemを介して管理される。 この~systemの背後にある意図は、少なくとも単独の`~custom要素$における局所的な文脈~下では、各`~custom要素~反応$は,常に,それらを誘発した動作たちの順序と同じ順序で呼出されることを保証することである。 (`~custom要素~反応$の~codeは,自前で`他の要素に対する^tnote変異を遂行できるので、複数の要素にわたる大域的な順序付けを保証することは,可能0でない) ◎ Additionally, the precise ordering of these reactions is managed via a somewhat-complicated stack-of-queues system, described below. The intention behind this system is to guarantee that custom element reactions always are invoked in the same order as their triggering actions, at least within the local context of a single custom element. (Because custom element reaction code can perform its own mutations, it is not possible to give a global ordering guarantee across multiple elements.)


各 `互いに関係するかつ生成元も類似する閲覧文脈~群$は、初期~時は空の, `~custom要素~反応~stack@ を有する。 この~stack内の各~itemは, `要素~待行列@ であり、これらも初期~時は空である。 また、この~stackの一番上に積まれた`要素~待行列$を,特に `現在の要素~待行列@ という。 `要素~待行列$内の各~itemは、要素である(この待行列は,`昇格$時にも利用されるので、各~要素は,この時点では必ずしも`~customである$とは限らない。) ◎ Each unit of related similar-origin browsing contexts has a custom element reactions stack, which is initially empty. The current element queue is the element queue at the top of the custom element reactions stack. Each item in the stack is an element queue, which is initially empty as well. Each item in an element queue is an element. (The elements are not necessarily custom yet, since this queue is used for upgrades as well.)

各`~custom要素~反応~stack$には、初期~時は空の`要素~待行列$である, `予備の要素~待行列@ も結付けられる。 [ `CEReactions$xA 付きの~APIを通さずに, あるいは 構文解析器の`~tokenに対し要素を作成する$~algoを通して ]~DOMに影響するような演算の間、要素は`予備の要素~待行列$に~pushされる。 例えば、`編集可能$な要素の子孫や属性を改変するような,利用者により起動される編集~演算が挙げられる。 `予備の要素~待行列$の処理-時における再入を防ぐため、各`~custom要素~反応~stack$には、初期-時は ~OFF の `予備の要素~待行列は処理中~flag@ も結付けられる。 ◎ Each custom element reactions stack has an associated backup element queue, which an initially-empty element queue. Elements are pushed onto the backup element queue during operations that affect the DOM without going through an API decorated with [CEReactions], or through the parser's create an element for the token algorithm. An example of this is a user-initiated editing operation which modifies the descendants or attributes of an editable element. To prevent reentrancy when processing the backup element queue, each custom element reactions stack also has a processing the backup element queue flag, initially unset.

各 要素には、初期~時は空の, `~custom要素~反応~待行列@ が結付けられる。 `~custom要素~反応~待行列$内の各~itemは、次の 2 種いずれかになる: ◎ All elements have an associated custom element reaction queue, initially empty. Each item in the custom element reaction queue is of one of two types:

  • ~custom要素を`昇格$することになる, `昇格~反応@ 。 その内容は、`~custom要素~定義$である。 ◎ An upgrade reaction, which will upgrade the custom element and contains a custom element definition; or
  • ~lifecycle~callbackを~callすることになる, `~callback反応@ 。 その内容は、[ ~callback関数, および それに対する引数の~list ]からなる。 ◎ A callback reaction, which will call a lifecycle callback, and contains a callback function as well as a list of arguments.

これらすべては、次の図式に要約される: ◎ This is all summarized in the following schematic diagram:

関係図
~custom要素
反応~stack
要素~待行列
~custom要素~反応~待行列
昇格
属性
変更-時
属性
変更-時
接続-時
~custom要素~反応~stackは、いくつかの要素~待行列からなる~stackである。 図のある待行列に着目すると,いくつかの要素(この例では, <x-a>, <x-b>, <x-c> )を包含していることが見てとれる。 待行列~内のどの要素も、~custom要素~反応~待行列を持つ。 ある~custom要素~反応~待行列に着目すれば,待入された種々の反応を包含していることが見てとれる(この例では、[ 昇格~時, 属性~変更-時, もう一つの属性~変更-時, 接続-時 ]に反応するもの)。 ◎ A custom element reactions stack consists of a stack of element queues. Zooming in on a particular queue, we see that it contains a number of elements (in our example, <x-a>, then <x-b>, then <x-c>). Any particular element in the queue then has a custom element reaction queue. Zooming in on the custom element reaction queue, we see that it contains a variety of queued-up reactions (in our example, upgrade, then attribute changed, then another attribute changed, then connected).

所与の要素 %要素 を `適切な要素~待行列に入れる@ ときは、次を走らす: ◎ To enqueue an element on the appropriate element queue, given an element element, run the following steps:

  1. ~IF[ `~custom要素~反応~stack$は空である ]: ◎ If the custom element reactions stack is empty, then:

    1. %要素 を`予備の要素~待行列$に追加する ◎ Add element to the backup element queue.
    2. ~IF[ `予備の要素~待行列は処理中~flag$ ~EQ ~ON ] ⇒ ~RET ◎ If the processing the backup element queue flag is set, abort this algorithm.
    3. `予備の要素~待行列は処理中~flag$ ~SET ~ON ◎ Set the processing the backup element queue flag.
    4. 次の手続きを遂行する`極小taskを待入する$: ◎ Queue a microtask to perform the following steps:

      1. `予備の要素~待行列$内の`~custom要素~反応たちを呼出す$ ◎ Invoke custom element reactions in the backup element queue.
      2. `予備の要素~待行列は処理中~flag$ ~SET ~OFF ◎ Unset the processing the backup element queue flag.
  2. ~ELSE ⇒ %要素 を`現在の要素~待行列$に追加する ◎ Otherwise, add element to the current element queue.

`~custom要素~callback反応を待入れる@ 手続きは、所与の ( `~custom要素$ %要素, ~callback名 %~callback名, 引数~list %引数~list ) に対し,次を走らす: ◎ To enqueue a custom element callback reaction, given a custom element element, a callback name callbackName, and a list of arguments args, run the following steps:

  1. %定義 ~LET %要素 の`~custom要素~定義$x ◎ Let definition be element's custom element definition.
  2. %~callback ~LET %定義 の`~lifecycle~callback~map$cD内の[ ~key ~EQ %~callback名 ]なる~entryの値 ◎ Let callback be the value of the entry in definition's lifecycle callbacks with key callbackName.
  3. ~IF[ %~callback ~EQ ~NULL ] ⇒ ~RET ◎ If callback is null, then abort these steps.
  4. ~IF[ %~callback名 ~EQ `attributeChangedCallback^l ]: ◎ If callbackName is "attributeChangedCallback", then:

    1. %属性~名 ~LET %引数~list 内の最初の引数 ◎ Let attributeName be the first element of args.
    2. ~IF[ %定義 の`観測先の属性~list$cDは %属性~名 を包含しない ] ⇒ ~RET ◎ If definition's observed attributes does not contain attributeName, then abort these steps.
  5. ( ~callback関数, 引数~list ) として ( %~callback, %引数~list ) を伴う新たな`~callback反応$を, %要素 の`~custom要素~反応~待行列$に追加する ◎ Add a new callback reaction to element's custom element reaction queue, with callback function callback and arguments args.
  6. %要素 を`適切な要素~待行列に入れる$ ◎ Enqueue an element on the appropriate element queue given element.

`~custom要素を昇格する反応を待入れる@ 手続きは、所与の ( 要素 %要素, `~custom要素~定義$ %定義 ) に対し,次を走らす: ◎ To enqueue a custom element upgrade reaction, given an element element and custom element definition definition, run the following steps:

  1. `~custom要素~定義$として %定義 を伴う新たな`昇格~反応$を, %要素 の`~custom要素~反応~待行列$に追加する ◎ Add a new upgrade reaction to element's custom element reaction queue, with custom element definition definition.
  2. %要素 を`適切な要素~待行列に入れる$ ◎ Enqueue an element on the appropriate element queue given element.

`要素~待行列$ %待行列 内の `~custom要素~反応たちを呼出す@ ときは、次の手続きを走らす: ◎ To invoke custom element reactions in an element queue queue, run the following steps:

  1. ~FOR %待行列 内の ~EACH ( `~custom要素$ %要素 ) に対し: ◎ For each custom element element in queue:

    1. %反応~待行列 ~LET %要素 の`~custom要素~反応~待行列$ ◎ Let reactions be element's custom element reaction queue.
    2. ~WHILE[ %反応~待行列 は空でない ]: ◎ Repeat until reactions is empty:

      1. %反応~待行列 から最初の~itemを除去する ◎ Remove the first element of reactions, and\
      2. %反応 ~LET 前~段で除去した~item ◎ let reaction be that element.\
      3. %反応 の種別に応じて: ◎ Switch on reaction's type:

        `昇格~反応$
        次を与える下で,`要素を昇格$する ⇒ ( %反応 の`~custom要素~定義$, %要素 ) ◎ Upgrade element using reaction's custom element definition.
        `~callback反応$
        次を与える下で, %反応 の`~callback関数を呼出す$ ⇒ 引数~list: %反応 の引数~list,
        `~callback this 値$: %要素 ◎ Invoke reaction's callback function with reaction's arguments, and with element as the callback this value.

        この段の中で例外が投出されたときは、~catchして ⇒ その`例外を報告する$ ◎ If this throws an exception, catch it, and report the exception.


`~custom要素~反応$が適切に誘発されることを確保するため、この仕様は, `CEReactions@xA ~IDL `拡張属性$を導入する。 それは、`~custom要素~反応$を適切に追跡して呼出すため,関連する~algoに追加の手続きを増補することを指示する。 ◎ To ensure custom element reactions are triggered appropriately, we introduce the [CEReactions] IDL extended attribute. It indicates that the relevant algorithm is to be supplemented with additional steps in order to appropriately track and invoke custom element reactions.

【 以下に現れる各種 IDL 用語の参照先: 演算, 属性, 設定子と削除子, 読専

`CEReactions$xA 拡張属性は:

  • 引数をとっては~MUST_NOT。
  • [ 演算, 属性, 設定子, 削除子 ]以外のものに現れては~MUST_NOT。
  • 読専( readonly )属性~上に現れては~MUST_NOT。
◎ The [CEReactions] extended attribute must take no arguments, and must not appear on anything other than an operation, attribute, setter, or deleter. Additionally, it must not appear on readonly attributes.

`CEReactions$xA 拡張属性 注釈付きの[ 演算, 属性, 設定子, 削除子 ]に対しては、その[ 演算 / 設定子 / 削除子 / 属性の設定子 ]の記述に挙げられている動作を囲むように次の手続きを走らせ~MUST: ◎ Operations, attributes, setters, or deleters annotated with the [CEReactions] extended attribute must run the following steps surrounding the actions listed in the description of the operation, setter, deleter, or the attribute's setter:

挙げられている動作を実行する前に: ◎ Before executing the listed actions
`~custom要素~反応~stack$に新たな`要素~待行列$を~pushする ◎ Push a new element queue onto the custom element reactions stack.
挙げられている動作を実行した後に: ◎ After executing the listed actions
`~custom要素~反応~stack$から`要素~待行列$を~popした上で、~popされた待行列~内の`~custom要素~反応たちを呼出す$ ◎ Pop the element queue from the custom element reactions stack, and invoke custom element reactions in that queue.

注記: この拡張属性の背後にある意図には、微妙な所がある。 その目標を達成するためには、代わりに,次を記しておくことも一つではあるが…:

  • ~platform上のどの[ 演算, 属性, 設定子, 削除子 ]にも,上述の手続きを挿入しなければならない。
  • 実装者には、不必要な事例については最適化して外すことも許容される(そこでは、`~custom要素~反応$を生じさせるような~DOM変異は,可能0でない)。
◎ The intent behind this extended attribute is somewhat subtle. One way of accomplishing its goals would be to say that every operation, attribute, setter, and deleter on the platform must have these steps inserted, and to allow implementers to optimize away unnecessary cases (where no DOM mutation is possible that could cause custom element reactions to occur).

…が、このような不精確な~~指定では、`~custom要素~反応$の実装は,実施において相互運用可能でなくなりかねない — ある実装は,一部の事例でこの手続きを呼び出し忘れるかもしれない。 代わりに,相互運用可能な挙動を確保するため、この手続きが必要とされる事例すべてを,実装者が容易に見分けられるように、関連するすべての~IDL構成子に この拡張属性による注釈を明示的に付与する~approachをとって,決着させることにする。 ◎ However, in practice this imprecision could lead to non-interoperable implementations of custom element reactions, as some implementations might forget to invoke these steps in some cases. Instead, we settled on the approach of explicitly annotating all relevant IDL constructs, as a way of ensuring interoperable behavior and helping implementations easily pinpoint all cases where these steps are necessary.

~UAにより導入される非~標準~APIのうち、~DOMを改変し得る結果,[ `~custom要素~callback反応を待入れる$ / `~custom要素を昇格する反応を待入れる$ ]もの — 例えば何らかの属性や子~要素を改変するものなど — には、`CEReactions$xA 属性が付与され~MUST。 ◎ Any nonstandard APIs introduced by the user agent that could modify the DOM in such a way as to cause enqueuing a custom element callback reaction or enqueuing a custom element upgrade reaction, for example by modifying any attributes or child elements, must also be decorated with the [CEReactions] attribute.

注記: これを書いている時点では、次に挙げる[ 非~標準の, または標準~化されていない ]~APIが,これに該当するものとして知られている: ◎ As of the time of this writing, the following nonstandard or not-yet-standardized APIs are known to fall into this category:

  • `HTMLElement$I の `outerText^m ~IDL属性 ◎ HTMLElement's outerText IDL attribute
  • `HTMLInputElement$I の[ `webkitdirectory^m, `incremental^m ]~IDL属性 ◎ HTMLInputElement's webkitdirectory and incremental IDL attributes
  • `HTMLLinkElement$I の[ `disabled^m, `scope^m ]~IDL属性 ◎ HTMLLinkElement's disabled and scope IDL attributes
  • `ShadowRoot$I の `innerHTML^m ~IDL属性 ◎ ShadowRoot's innerHTML IDL attribute