blob: eae602b9d588cc757abdea119be134b96f6a9d7a [file] [log] [blame]
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart.dom.html;
/// Checks whether the given [element] correctly extends from the native class
/// with the given [baseClassName]. This method will throw if the base class
/// doesn't match, except when the element extends from `template` and it's base
/// class is `HTMLUnknownElement`. This exclusion is needed to support extension
/// of template elements (used heavily in Polymer 1.0) on IE11 when using the
/// webcomponents-lite.js polyfill.
void _checkExtendsNativeClassOrTemplate(
Element element, String extendsTag, String baseClassName) {
if (!JS('bool', '(# instanceof window[#])', element, baseClassName) &&
!((extendsTag == 'template' &&
JS('bool', '(# instanceof window["HTMLUnknownElement"])',
element)))) {
throw new UnsupportedError('extendsTag does not match base native class');
}
}
/// Dart2JS implementation of ElementUpgrader
class _JSElementUpgrader implements ElementUpgrader {
var _interceptor;
var _constructor;
var _nativeType;
_JSElementUpgrader(Document document, Type type, String? extendsTag) {
var interceptorClass = findInterceptorConstructorForType(type);
if (interceptorClass == null) {
throw new ArgumentError(type);
}
_constructor = findConstructorForNativeSubclassType(type, 'created');
if (_constructor == null) {
throw new ArgumentError("$type has no constructor called 'created'");
}
// Workaround for 13190- use an article element to ensure that HTMLElement's
// interceptor is resolved correctly.
getNativeInterceptor(new Element.tag('article'));
var baseClassName = findDispatchTagForInterceptorClass(interceptorClass);
if (baseClassName == null) {
throw new ArgumentError(type);
}
if (extendsTag == null) {
if (baseClassName != 'HTMLElement') {
throw new UnsupportedError('Class must provide extendsTag if base '
'native class is not HtmlElement');
}
_nativeType = HtmlElement;
} else {
var element = document.createElement(extendsTag);
_checkExtendsNativeClassOrTemplate(element, extendsTag, baseClassName);
_nativeType = element.runtimeType;
}
_interceptor = JS('=Object', '#.prototype', interceptorClass);
}
Element upgrade(Element element) {
// Only exact type matches are supported- cannot be a subclass.
if (element.runtimeType != _nativeType) {
// Some browsers may represent non-upgraded elements <x-foo> as
// UnknownElement and not a plain HtmlElement.
if (_nativeType != HtmlElement || element.runtimeType != UnknownElement) {
throw new ArgumentError('element is not subclass of $_nativeType');
}
}
setNativeSubclassDispatchRecord(element, _interceptor);
JS('', '#(#)', _constructor, element);
return element;
}
}