EagleLand

2014.10.07

HTML Importsでインポート先に引き継がれる内容

https://github.com/pazguille/github-card/blob/master/webcomponent/github-card.html これってなんでdoc.registerElementになってるんだろう・・

っていう質問をされたので調べたメモ。内容的にはHTML ImportsするHTMLのコンテキストになるdocumentの続きにあたるかも。

registerElementの実行者とカスタム要素の登録先

以下の様なカスタム要素を作成し、ロードする場合を考える。

sample-element.html

<script>
  var doc = document.currentScript.ownerDocument;
  doc.variable = 'this is the variable in sample-element.html';
  window.SampleElement = document.registerElement('sample-element', {
    prototype: Object.create(HTMLElement.prototype)
  });
</script>

loader.html

<html>
  <head>
    <meta charset="utf-8">
    <link rel="import" href="sample-element.html">
  </head>
  <body>
    <sample-element>Sample</sample-element>
  </body>
</html>

document.currentScript.ownerDocumentdocにキャッシュしないと、sample-element.html内に書いた要素を取得する時に困る話は前述のエントリでしてある。 document.registerElement('sample-element', {});しているのは、sample-element.htmlをインポートするHTMLのdocumentになる。

でも<github-card>ではこの例で言うところのsample-element.htmldocumentregisterElement()を実行している。 感覚的に言えばインポートする側のdocumentで登録を実行するほうがしっくりくるんだけどそうでもないんだろうか。

HTML Importsでカスタム要素の定義もインポートされる

感覚の話はさておき、<github-card>を見る限りregisterElement()したカスタム要素は引き継がれるよう。 sample-element.htmlでわざとらしく宣言したvariableという変数も見てみる。引き継がれないだろうけど、一応。

当然のごとくvariabledocにしかない。が、document.createElement('sample-element')は両方とも成功している。

Firefox Nightly 35.0a1でも試してみた。

インポートしているsample-element.html内で宣言しているdocundefinedになってしまっているんだけど、docに登録している<sample-element>はちゃんとインポート先のdocumentに登録されていた。

スタイルシートも引き継がれる

sample-element.html内でsample-element.cssをロードし、そのsample-element.htmlをインポートするとインポート先でsample-element.cssで定義しているクラスは利用出来る。

このとき、sample-element.cssdoc.styleSheetsにぶら下がっているけど、当然document.styleSheetsには属さない。

HTML ImportsとCustom Elementsの仕様を見てみる

HTML Importはこんな感じでlink関係をツリー上に持つらしい。で、このHTML Importsのツリーは

The import tree order of a given custom element of an import tree is determined by tree order in an import tree that was flattened by replacing every import link with the content of its imported document.

インポートしてくるドキュメントでリプレイスされ、ドキュメント達は構造上並列になる(と書いてあるように見える)。

Element registration is a process of adding an element definition to a registry. One element definition can only be registered with one registry.

ひとつのドキュメントにつき、ひとつのレジストリが存在し、要素の定義はそのレジストリに定義される。

色々読み漁ったけど、英語力足りなすぎて直接言及している場所がどこかわからなかった。かろうじて、

When creating an import, use the registry of the master document.

先程のスタイルシートの挙動から察するに、 HTML Importsのツリー上の子孫にいるカスタム要素のレジストリは親から参照出来る ってことなんだと思うが、HTML Importが発生した時点でインポート先のドキュメントにカスタム要素の宣言がマージされることを意味しているような気も。

詳しい人おしえて下さい。