Index: tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate |
diff --git a/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate b/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate |
index 3d9e6afb5cedefa436b006eb0483131cdaea4545..bf8f0ffc2c5ef6293eeff7f52d9889876db75987 100644 |
--- a/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate |
+++ b/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate |
@@ -17,7 +17,7 @@ $else |
BodyElement get body => _body; |
@DomName('Document.body') |
- void set body(BodyElement value) { |
+ set body(BodyElement value) { |
_body = value; |
} |
$endif |
@@ -90,7 +90,7 @@ $endif |
@DomName('Document.selectedStylesheetSet') |
String get selectedStylesheetSet => _selectedStylesheetSet; |
- void set selectedStylesheetSet(String value) { |
+ set selectedStylesheetSet(String value) { |
_selectedStylesheetSet = value; |
} |
@@ -101,7 +101,7 @@ $endif |
String get title => _title; |
@DomName('Document.title') |
- void set title(String value) { |
+ set title(String value) { |
_title = value; |
} |
@@ -187,6 +187,41 @@ $if DART2JS |
$else |
String get visibilityState => _webkitVisibilityState; |
$endif |
+$if DARTIUM |
+ |
+ /** |
+ * Internal routine to find the DOM JS class name being extended for custom |
+ * elements. |
+ */ |
+ String _getJSClassName(ClassMirror classMirror) { |
+ var jsClassName = null; |
+ var isElement = false; |
+ |
+ while (classMirror.superclass != null) { |
+ var fullName = classMirror.superclass.qualifiedName; |
+ isElement = isElement || (fullName == #dart.dom.html.Element); |
+ |
+ var domLibrary = MirrorSystem.getName(fullName).startsWith('dart.dom.'); |
+ if (jsClassName == null && domLibrary) { |
+ // Lookup JS class name (if not found). |
+ var metadatas = classMirror.metadata; |
+ for (var metadata in metadatas) { |
+ var metaDataMirror = metadata.reflectee; |
+ var metaType = reflectClass(metaDataMirror.runtimeType); |
+ if (MirrorSystem.getName(metaType.simpleName) == 'DomName' && |
+ metaDataMirror.name.startsWith('HTML')) { |
+ jsClassName = metadata.reflectee.name; |
+ } |
+ } |
+ } |
+ |
+ classMirror = classMirror.superclass; |
+ } |
+ |
+ // If we're an element then everything is okay. |
+ return isElement ? jsClassName : null; |
+ } |
+$endif |
@Experimental() |
/** |
@@ -236,7 +271,73 @@ $if DART2JS |
_registerCustomElement(JS('', 'window'), this, tag, customElementClass, |
extendsTag); |
$else |
- _Utils.register(this, tag, customElementClass, extendsTag); |
+ // TODO(terry): Need to handle the extendsTag. |
+ |
+ // Figure out which DOM class is being extended from the user's Dart class. |
+ var classMirror = reflectClass(customElementClass); |
+ var jsClassName = _getJSClassName(classMirror); |
+ if (jsClassName == null) { |
+ // Only components derived from HTML* can be extended. |
+ throw new DomException.jsInterop("HierarchyRequestError: Only HTML elements can be customized."); |
+ } |
+ |
+ // 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 |
+ // inherited: |
+ // |
+ // var myProto = Object.create(HTMLElement.prototype); |
+ // var myElement = document.registerElement('x-foo', {prototype: myProto}); |
+ var baseElement = js.context[jsClassName]; |
+ if (baseElement == null) { |
+ // Couldn't find the HTML element so use a generic one. |
+ baseElement = js.context['HTMLElement']; |
+ } |
+ var elemProto = js.context['Object'].callMethod("create", [baseElement['prototype']]); |
+ |
+ // TODO(terry): Hack to stop recursion re-creating custom element when the |
+ // created() constructor of the custom element does e.g., |
+ // |
+ // MyElement.created() : super.created() { |
+ // this.innerHtml = "<b>I'm an x-foo-with-markup!</b>"; |
+ // } |
+ // |
+ // sanitizing causes custom element to created recursively |
+ // until stack overflow. |
+ // |
+ // See https://github.com/dart-lang/sdk/issues/23666 |
+ int creating = 0; |
+ elemProto['createdCallback'] = new js.JsFunction.withThis(($this) { |
+ if (_getJSClassName(reflectClass(customElementClass).superclass) != null && creating < 2) { |
+ creating++; |
+ |
+ var dartClass = _blink.Blink_Utils.constructElement(customElementClass, $this); |
+ |
+ // Need to remember the Dart class that was created for this custom so |
+ // return it and setup the blink_jsObject to the $this that we'll be working |
+ // with as we talk to blink. |
+ $this['dart_class'] = dartClass; |
+ |
+ creating--; |
+ } |
+ }); |
+ elemProto['attributeChangedCallback'] = new js.JsFunction.withThis(($this, attrName, oldVal, newVal) { |
+ if ($this["dart_class"] != null && $this['dart_class'].attributeChanged != null) { |
+ $this['dart_class'].attributeChanged(attrName, oldVal, newVal); |
+ } |
+ }); |
+ elemProto['attachedCallback'] = new js.JsFunction.withThis(($this) { |
+ if ($this["dart_class"] != null && $this['dart_class'].attached != null) { |
+ $this['dart_class'].attached(); |
+ } |
+ }); |
+ elemProto['detachedCallback'] = new js.JsFunction.withThis(($this) { |
+ if ($this["dart_class"] != null && $this['dart_class'].detached != null) { |
+ $this['dart_class'].detached(); |
+ } |
+ }); |
+ // document.registerElement('x-foo', {prototype: elemProto, extends: extendsTag}); |
+ var jsMap = new js.JsObject.jsify({'prototype': elemProto, 'extends': extendsTag}); |
+ js.context['document'].callMethod('registerElement', [tag, jsMap]); |
$endif |
} |