| Index: sdk/lib/html/dartium/html_dartium.dart
|
| diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
|
| index 6d84226de82586655c9f7a3df4df51566f9711e0..a4d3eb755b61d0b3ac9a44b42ab3225d92542bc8 100644
|
| --- a/sdk/lib/html/dartium/html_dartium.dart
|
| +++ b/sdk/lib/html/dartium/html_dartium.dart
|
| @@ -1116,7 +1116,7 @@ void _addCustomElementType(String tagName, Type dartClass, [String extendTag]) {
|
| }
|
|
|
| Type _getCustomElementType(object) {
|
| - var entry = _knownCustomElements[_getCustomElementName(object)];
|
| + var entry = _getCustomElementEntry(object);
|
| if (entry != null) {
|
| return entry['type'];
|
| }
|
| @@ -1124,14 +1124,53 @@ Type _getCustomElementType(object) {
|
| }
|
|
|
| String _getCustomElementExtends(object) {
|
| - var entry = _knownCustomElements[_getCustomElementName(object)];
|
| + var entry = _getCustomElementEntry(object);
|
| if (entry != null) {
|
| return entry['extends'];
|
| }
|
| return null;
|
| }
|
|
|
| -_getCustomElement(object) => _knownCustomElements[_getCustomElementName(object)];
|
| +_getCustomElementEntry(element) {
|
| + var hasAttribute = false;
|
| +
|
| + var jsObject;
|
| + var tag = "";
|
| + var runtimeType = element.runtimeType;
|
| + if (runtimeType == HtmlElement) {
|
| + tag = element.localName;
|
| + } else if (runtimeType == TemplateElement) {
|
| + // Data binding with a Dart class.
|
| + tag = element.attributes['is'];
|
| + } else if (runtimeType == js.JsObjectImpl) {
|
| + // It's a Polymer core element (written in JS).
|
| + // Make sure it's an element anything else we can ignore.
|
| + if (element.hasProperty('nodeType') && element['nodeType'] == 1) {
|
| + if (js.JsNative.callMethod(element, 'hasAttribute', ['is'])) {
|
| + hasAttribute = true;
|
| + // It's data binding use the is attribute.
|
| + tag = js.JsNative.callMethod(element, 'getAttribute', ['is']);
|
| + } else {
|
| + // It's a custom element we want the local name.
|
| + tag = element['localName'];
|
| + }
|
| + }
|
| + } else {
|
| + throw new UnsupportedError('Element is incorrect type. Got ${runtimeType}, expected HtmlElement/HtmlTemplate/JsObjectImpl.');
|
| + }
|
| +
|
| + var entry = _knownCustomElements[tag];
|
| + if (entry != null) {
|
| + // If there's an 'is' attribute then check if the extends tag registered
|
| + // matches the tag if so then return the entry that's registered for this
|
| + // extendsTag or if there's no 'is' tag then return the entry found.
|
| + if ((hasAttribute && entry['extends'] == tag) || !hasAttribute) {
|
| + return entry;
|
| + }
|
| + }
|
| +
|
| + return null;
|
| +}
|
|
|
| // Return the tag name or is attribute of the custom element or data binding.
|
| String _getCustomElementName(element) {
|
| @@ -1206,18 +1245,19 @@ wrap_jso(jsObject) {
|
| var wrapper = js.getDartHtmlWrapperFor(jsObject);
|
| // if we have a wrapper return the Dart instance.
|
| if (wrapper != null) {
|
| - if (wrapper.runtimeType == HtmlElement && !wrapper._isBadUpgrade) {
|
| - // We're a Dart instance but we need to upgrade.
|
| - var customElementClass = _getCustomElementType(wrapper);
|
| - if (customElementClass != null) {
|
| - var dartClass_instance;
|
| - try {
|
| - dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
|
| - } finally {
|
| - dartClass_instance.blink_jsObject = jsObject;
|
| - jsObject['dart_class'] = dartClass_instance;
|
| - js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
|
| - return dartClass_instance;
|
| + var customElementClass = _getCustomElementType(wrapper.blink_jsObject);
|
| + if (wrapper.runtimeType != customElementClass && customElementClass != null) {
|
| + if (wrapper.runtimeType == HtmlElement && !wrapper._isBadUpgrade) {
|
| + // We're a Dart instance if it's HtmlElement and we have a customElement
|
| + // class then we need to upgrade.
|
| + if (customElementClass != null) {
|
| + var dartClass_instance;
|
| + try {
|
| + dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
|
| + } finally {
|
| + dartClass_instance.blink_jsObject = jsObject;
|
| + return dartClass_instance;
|
| + }
|
| }
|
| }
|
| }
|
| @@ -1255,49 +1295,39 @@ wrap_jso(jsObject) {
|
| }
|
|
|
| var dartClass_instance;
|
| - if (jsObject.hasProperty('dart_class')) {
|
| - // Got a dart_class (it's a custom element) use it it's already set up
|
| - // make sure it's upgraded.
|
| - dartClass_instance = _upgradeHtmlElement(jsObject['dart_class']);
|
| + var customElementClass = null;
|
| + var extendsTag = "";
|
| + var custom = _getCustomElementEntry(jsObject);
|
| + if (custom != null) {
|
| + customElementClass = custom['type'];
|
| + extendsTag = custom['extends'];
|
| + }
|
| +
|
| + // Custom Element to upgrade.
|
| + if (customElementClass != null && extendsTag == "") {
|
| + try {
|
| + dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
|
| + } finally {
|
| + dartClass_instance.blink_jsObject = jsObject;
|
| + js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
|
| + }
|
| } else {
|
| - var customElementClass = null;
|
| - var extendsTag = "";
|
| - var custom = _getCustomElement(jsObject);
|
| - if (custom != null) {
|
| - customElementClass = custom['type'];
|
| - extendsTag = custom['extends'];
|
| - }
|
| - // Custom Element to upgrade.
|
| - if (jsTypeName == 'HTMLElement' && customElementClass != null && extendsTag == "") {
|
| - try {
|
| - dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
|
| - } finally {
|
| - dartClass_instance.blink_jsObject = jsObject;
|
| - jsObject['dart_class'] = dartClass_instance;
|
| - js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
|
| - }
|
| - } else {
|
| - // TODO(terry): Verify with jakemacd that this is right?
|
| - // If we every get an auto-binding we're matching previous non-JS Interop
|
| - // did to return a TemplateElement.
|
| + var func = getHtmlCreateFunction(jsTypeName);
|
| + if (func == null) {
|
| if (jsTypeName == 'auto-binding') {
|
| - jsTypeName = "HTMLTemplateElement";
|
| - }
|
| -
|
| - var func = getHtmlCreateFunction(jsTypeName);
|
| - if (func == null) {
|
| + func = getHtmlCreateFunction("HTMLTemplateElement");
|
| + } else if (jsObject.toString() == "[object HTMLElement]") {
|
| // One last ditch effort could be a JS custom element.
|
| - if (jsObject.toString() == "[object HTMLElement]") {
|
| - func = getHtmlCreateFunction("HTMLElement");
|
| - }
|
| - }
|
| - if (func != null) {
|
| - dartClass_instance = func();
|
| - dartClass_instance.blink_jsObject = jsObject;
|
| - js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
|
| + func = getHtmlCreateFunction("HTMLElement");
|
| }
|
| }
|
| + if (func != null) {
|
| + dartClass_instance = func();
|
| + dartClass_instance.blink_jsObject = jsObject;
|
| + js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
|
| + }
|
| }
|
| +
|
| // TODO(jacobr): cache that this is not a dart:html JS class.
|
| return dartClass_instance;
|
| } catch(e, stacktrace){
|
| @@ -1429,7 +1459,6 @@ _upgradeHtmlElement(dartInstance) {
|
| dartInstance._badUpgrade();
|
| } finally {
|
| dartInstance.blink_jsObject = jsObject;
|
| - jsObject['dart_class'] = dartInstance;
|
| js.setDartHtmlWrapperFor(jsObject, dartInstance);
|
| }
|
| }
|
| @@ -9327,7 +9356,7 @@ class CustomEvent extends Event {
|
| }
|
|
|
| // Need for identity.
|
| - e.blink_jsObject['dart_class'] = e;
|
| + js.setDartHtmlWrapperFor(e.blink_jsObject, e);
|
|
|
| return e;
|
| }
|
| @@ -20322,12 +20351,28 @@ class HtmlDocument extends Document {
|
| return isElement ? jsClassName : null;
|
| }
|
|
|
| + // Get the first class that's a super of a dart.dom library.
|
| + ClassMirror _getDartHtmlClassName(ClassMirror classMirror) {
|
| + while (classMirror.superclass != null) {
|
| + var fullName = classMirror.superclass.qualifiedName;
|
| + var domLibrary = MirrorSystem.getName(fullName).startsWith('dart.dom.');
|
| + if (domLibrary) {
|
| + return classMirror.superclass;
|
| + }
|
| +
|
| + classMirror = classMirror.superclass;
|
| + }
|
| +
|
| + return null;
|
| + }
|
| +
|
| /**
|
| * Get the class that immediately derived from a class in dart:html or
|
| * dart:svg (has an attribute DomName of either HTML* or SVG*).
|
| */
|
| ClassMirror _getDomSuperClass(ClassMirror classMirror) {
|
| var isElement = false;
|
| + var foundSuperElement = null;
|
|
|
| while (classMirror.superclass != null) {
|
| var fullName = classMirror.superclass.qualifiedName;
|
| @@ -20335,6 +20380,9 @@ class HtmlDocument extends Document {
|
|
|
| var domLibrary = MirrorSystem.getName(fullName).startsWith('dart.dom.');
|
| if (domLibrary) {
|
| + if (foundSuperElement == null) {
|
| + foundSuperElement = classMirror.superclass;
|
| + }
|
| // Lookup JS class (if not found).
|
| var metadatas = classMirror.metadata;
|
| for (var metadata in metadatas) {
|
| @@ -20342,7 +20390,7 @@ class HtmlDocument extends Document {
|
| var metaType = reflectClass(metaDataMirror.runtimeType);
|
| if (MirrorSystem.getName(metaType.simpleName) == 'DomName' &&
|
| (metaDataMirror.name.startsWith('HTML') || metaDataMirror.name.startsWith('SVG'))) {
|
| - if (isElement) return classMirror;
|
| + if (isElement) return foundSuperElement;
|
| }
|
| }
|
| }
|
| @@ -20463,6 +20511,25 @@ class HtmlDocument extends Document {
|
| throw new DomException.jsInterop("HierarchyRequestError: Only HTML elements can be customized.");
|
| }
|
|
|
| + var customClassType = _getDartHtmlClassName(classMirror);
|
| +
|
| + if (extendsTag != null) {
|
| + var nativeElement = document.createElement(extendsTag);
|
| +
|
| + // Trying to extend a native element is it the Dart class consistent with the
|
| + // extendsTag?
|
| + if (nativeElement.runtimeType != customClassType.reflectedType) {
|
| + var nativeElementClassMirror = reflectClass(nativeElement.runtimeType);
|
| + var customClassNativeElement = MirrorSystem.getName(customClassType.simpleName);
|
| + var extendsNativeElement = MirrorSystem.getName(nativeElementClassMirror.simpleName);
|
| + throw new DomException.jsInterop("HierarchyRequestError: Custom class type ($customClassNativeElement) and extendsTag class ($extendsNativeElement) don't match .");
|
| + }
|
| + } else if (customClassType.reflectedType != HtmlElement && customClassType.reflectedType != svg.SvgElement) {
|
| + var customClassName = MirrorSystem.getName(classMirror.simpleName);
|
| + var customClassElement = MirrorSystem.getName(customClassType.simpleName);
|
| + throw new DomException.jsInterop("HierarchyRequestError: Custom element $customClassName is a native $customClassElement should be derived from HtmlElement or SvgElement.");
|
| + }
|
| +
|
| if (_hasCreatedConstructor(classMirror)) {
|
| // Start the hookup the JS way create an <x-foo> element that extends the
|
| // <x-base> custom element. Inherit its prototype and signal what tag is
|
| @@ -20499,9 +20566,26 @@ class HtmlDocument extends Document {
|
|
|
| var dartClass;
|
| try {
|
| + if (extendsTag != null) {
|
| + // If we're extending a native element then create that element.
|
| + // Then upgrade that element to the customElementClass through
|
| + // normal flow.
|
| + dartClass = document.createElement(extendsTag);
|
| + js.setDartHtmlWrapperFor($this, dartClass);
|
| + dartClass.blink_jsObject = $this;
|
| + }
|
| +
|
| + // Upgrade to the CustomElement Dart class.
|
| dartClass = _blink.Blink_Utils.constructElement(customElementClass, $this);
|
| } catch (e) {
|
| + // Got a problem make it an HtmlElement and rethrow the error.
|
| dartClass = HtmlElement.internalCreateHtmlElement();
|
| + // We need to remember the JS object (because constructElement failed
|
| + // it normally sets up the blink_jsObject.
|
| + dartClass.blink_jsObject = $this;
|
| +
|
| + // Mark to only try this once don't try upgrading from HtmlElement
|
| + // to the user's Dart class - we had a problem.
|
| dartClass._badUpgrade();
|
| throw e;
|
| } finally {
|
| @@ -47163,9 +47247,11 @@ class _VariableSizeListIterator<T> implements Iterator<T> {
|
| class _VMElementUpgrader implements ElementUpgrader {
|
| final Type _type;
|
| final Type _nativeType;
|
| + final String _extendsTag;
|
|
|
| _VMElementUpgrader(Document document, Type type, String extendsTag) :
|
| _type = type,
|
| + _extendsTag = extendsTag,
|
| _nativeType = _validateCustomType(type).reflectedType {
|
|
|
| if (extendsTag == null) {
|
| @@ -47183,20 +47269,39 @@ class _VMElementUpgrader implements ElementUpgrader {
|
|
|
| Element upgrade(element) {
|
| var jsObject;
|
| - var tag = _getCustomElementName(element);
|
| + var tag;
|
| + var isNativeElementExtension = false;
|
| +
|
| + try {
|
| + tag = _getCustomElementName(element);
|
| + } catch (e) {
|
| + isNativeElementExtension = element.localName == _extendsTag;
|
| + }
|
| +
|
| if (element.runtimeType == HtmlElement || element.runtimeType == TemplateElement) {
|
| + if (tag != _extendsTag) {
|
| + throw new UnsupportedError('$tag is not registered.');
|
| + }
|
| jsObject = unwrap_jso(element);
|
| } else if (element.runtimeType == js.JsObjectImpl) {
|
| // It's a Polymer core element (written in JS).
|
| jsObject = element;
|
| - } else {
|
| + } else if (isNativeElementExtension) {
|
| + // Extending a native element.
|
| + jsObject = element.blink_jsObject;
|
| +
|
| + // Element to extend is the real tag.
|
| + tag = element.localName;
|
| + } else if (tag != null && element.localName != tag) {
|
| + throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected native Html or Svg element to extend.');
|
| + } else if (tag == null) {
|
| throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected HtmlElement/JsObjectImpl.');
|
| }
|
|
|
| // Remember Dart class to tagName for any upgrading done in wrap_jso.
|
| - _addCustomElementType(tag, _type);
|
| + _addCustomElementType(tag, _type, _extendsTag);
|
|
|
| - return createCustomUpgrader(_nativeType, jsObject);
|
| + return createCustomUpgrader(_type, jsObject);
|
| }
|
| }
|
|
|
|
|