CustomElementsをextendsすることはできないぽい
Posted: Updated:
再現コード
Web Components のはなし。
去年8月時点に書かれた Custom Elements: defining new elements in HTML にも掲載されていたのと同じような感じのコードをChrome上で実行したらエラーになった。
var XFooProto = Object.create(HTMLElement.prototype); var XFoo = document.registerElement('x-foo', { prototype: XFooProto }); var XFooExtendedProto = Object.create(HTMLElement.prototype); var XFooExtended = document.registerElement('x-foo-extended', { prototype: XFooExtendedProto, extends: 'x-foo' });
エラーは次のとおりだ。
Error: Failed to execute 'registerElement' on 'Document': Registration failed for type 'x-foo-extended'. The tag name specified in 'extends' is a custom element name. Use inheritance instead.
extends
に CustomElements のタグ名が指定されてるからアカン、代わりに inheritance 使えって。
Google Chrome : Version 37.0.2062.94 & Version 39.0.2146.0 canary
そうなのかー
Blink の該当コード漁ったらたしかにそのような処理になっていた。
if (extendsProvidedAndNonNull) { localName = extends.lower(); if (!Document::isValidName(localName)) { CustomElementException::throwException(CustomElementException::ExtendsIsInvalidName, type, exceptionState); return false; } if (CustomElement::isValidName(localName)) { CustomElementException::throwException(CustomElementException::ExtendsIsCustomElementName, type, exceptionState); return false; } } else { if (namespaceURI == SVGNames::svgNamespaceURI) { CustomElementException::throwException(CustomElementException::ExtendsIsInvalidName, type, exceptionState); return false; } localName = type; }
CustomElements として Valid な名前だったら CustomElementException::ExtendsIsCustomElementName
が投げられている。
原典
W3C Editor's Draft 5 September 2014 Custom Elements で確認した。
- If PROTOTYPE is null, let PROTOTYPE be the result of invoking Object.create with HTMLElement's interface prototype object as only argument
- Let NAME be EXTENDS
- Let ERROR be the result of running the element registration algorithm with DOCUMENT, TYPE, PROTOTYPE, and NAME as arguments
- If ERROR is InvalidType, throw a SyntaxError and stop.
- If ERROR is not None, throw a NotSupportedError and stop.
NotSupportedError
ということなので、この辺でひっかかってると思うのだが。肝心の element registration algorithm をみると...
Input
> DOCUMENT, the document
> TYPE, the custom element type of the element being registered
> PROTOTYPE, the custom element prototype
> NAME, a local name, optional
Output
> ...中略...
> 8. If NAME was provided and is not null:
> Let BASE be the element interface for NAME and NAMESPACE
> If BASE does not exist or is an interface for a custom element, set ERROR to InvalidName and stop.
たぶんこのへんで止まってるのだろう。
単に prototype に渡すオブジェクトを継承させよう
ということで extends
というか JavaScript 伝統の継承的アレで prototype
の実装を引き継がせておいて、Document#registerElement
の extends
オプションは指定しないというのが正解になるっぽい。
現場からは以上です。