feat(render): don’t use the reflector for setting properties

BREAKING CHANGES:
- host actions don't take an expression as value any more but only a method name,
  and assumes to get an array via the EventEmitter with the method arguments.
- Renderer.setElementProperty does not take `style.`/... prefixes any more.
  Use the new methods `Renderer.setElementAttribute`, ... instead

Part of #2476
Closes #2637
This commit is contained in:
Tobias Bosch
2015-06-18 15:44:44 -07:00
parent 2932377769
commit 0a51ccbd68
32 changed files with 643 additions and 568 deletions

View File

@ -1,7 +1,6 @@
library angular.core.facade.dom;
import 'dart:html';
import 'dart:js' show JsObject;
import 'dom_adapter.dart' show setRootDomAdapter;
import 'generic_browser_adapter.dart' show GenericBrowserDomAdapter;
import '../facade/browser.dart';
@ -97,9 +96,28 @@ final _keyCodeToKeyMap = const {
};
class BrowserDomAdapter extends GenericBrowserDomAdapter {
js.JsFunction _setProperty;
js.JsFunction _getProperty;
js.JsFunction _hasProperty;
BrowserDomAdapter() {
_setProperty = js.context.callMethod('eval', ['(function(el, prop, value) { el[prop] = value; })']);
_getProperty = js.context.callMethod('eval', ['(function(el, prop) { return el[prop]; })']);
_hasProperty = js.context.callMethod('eval', ['(function(el, prop) { return prop in el; })']);
}
static void makeCurrent() {
setRootDomAdapter(new BrowserDomAdapter());
}
bool hasProperty(Element element, String name) =>
_hasProperty.apply([element, name]);
void setProperty(Element element, String name, Object value) =>
_setProperty.apply([element, name, value]);
getProperty(Element element, String name) =>
_getProperty.apply([element, name]);
invoke(Element element, String methodName, List args) =>
this.getProperty(element, methodName).apply(args, thisArg: element);
// TODO(tbosch): move this into a separate environment class once we have it
logError(error) {
@ -108,7 +126,7 @@ class BrowserDomAdapter extends GenericBrowserDomAdapter {
@override
Map<String, String> get attrToPropMap => const <String, String>{
'innerHtml': 'innerHtml',
'innerHtml': 'innerHTML',
'readonly': 'readOnly',
'tabindex': 'tabIndex',
};
@ -221,8 +239,6 @@ class BrowserDomAdapter extends GenericBrowserDomAdapter {
ShadowRoot getShadowRoot(Element el) => el.shadowRoot;
Element getHost(Element el) => (el as ShadowRoot).host;
clone(Node node) => node.clone(true);
bool hasProperty(Element element, String name) =>
new JsObject.fromBrowserObject(element).hasProperty(name);
List<Node> getElementsByClassName(Element element, String name) =>
element.getElementsByClassName(name);
List<Node> getElementsByTagName(Element element, String name) =>

View File

@ -50,6 +50,12 @@ var _chromeNumKeyPadMap = {
export class BrowserDomAdapter extends GenericBrowserDomAdapter {
static makeCurrent() { setRootDomAdapter(new BrowserDomAdapter()); }
hasProperty(element, name: string) { return name in element; }
setProperty(el: /*element*/ any, name: string, value: any) { el[name] = value; }
getProperty(el: /*element*/ any, name: string): any { return el[name]; }
invoke(el: /*element*/ any, methodName: string, args: List<any>): any {
el[methodName].apply(el, args);
}
// TODO(tbosch): move this into a separate environment class once we have it
logError(error) { window.console.error(error); }
@ -152,7 +158,6 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter {
getShadowRoot(el: HTMLElement): DocumentFragment { return (<any>el).shadowRoot; }
getHost(el: HTMLElement): HTMLElement { return (<any>el).host; }
clone(node: Node) { return node.cloneNode(true); }
hasProperty(element, name: string) { return name in element; }
getElementsByClassName(element, name: string) { return element.getElementsByClassName(name); }
getElementsByTagName(element, name: string) { return element.getElementsByTagName(name); }
classList(element): List<any> {

View File

@ -16,6 +16,11 @@ function _abstract() {
* Provides DOM operations in an environment-agnostic way.
*/
export class DomAdapter {
hasProperty(element, name: string): boolean { throw _abstract(); }
setProperty(el: /*element*/ any, name: string, value: any) { throw _abstract(); }
getProperty(el: /*element*/ any, name: string): any { throw _abstract(); }
invoke(el: /*element*/ any, methodName: string, args: List<any>): any { throw _abstract(); }
logError(error) { throw _abstract(); }
/**
@ -70,7 +75,6 @@ export class DomAdapter {
getHost(el): any { throw _abstract(); }
getDistributedNodes(el): List<any> { throw _abstract(); }
clone(node): any { throw _abstract(); }
hasProperty(element, name: string): boolean { throw _abstract(); }
getElementsByClassName(element, name: string): List<any> { throw _abstract(); }
getElementsByTagName(element, name: string): List<any> { throw _abstract(); }
classList(element): List<any> { throw _abstract(); }

View File

@ -10,13 +10,24 @@ class Html5LibDomAdapter implements DomAdapter {
setRootDomAdapter(new Html5LibDomAdapter());
}
hasProperty(element, String name) {
// This is needed for serverside compile to generate the right getters/setters...
return true;
}
void setProperty(Element element, String name, Object value) => throw 'not implemented';
getProperty(Element element, String name) => throw 'not implemented';
invoke(Element element, String methodName, List args) => throw 'not implemented';
logError(error) {
stderr.writeln('${error}');
}
@override
final attrToPropMap = const {
'innerHtml': 'innerHtml',
'innerHtml': 'innerHTML',
'readonly': 'readOnly',
'tabindex': 'tabIndex',
};
@ -184,11 +195,6 @@ class Html5LibDomAdapter implements DomAdapter {
throw 'not implemented';
}
clone(node) => node.clone(true);
hasProperty(element, String name) {
// This is needed for serverside compile to generate the right getters/setters...
return true;
}
getElementsByClassName(element, String name) {
throw 'not implemented';
}

View File

@ -26,6 +26,20 @@ function _notImplemented(methodName) {
export class Parse5DomAdapter extends DomAdapter {
static makeCurrent() { setRootDomAdapter(new Parse5DomAdapter()); }
hasProperty(element, name: string) { return _HTMLElementPropertyList.indexOf(name) > -1; }
// TODO(tbosch): don't even call this method when we run the tests on server side
// by not using the DomRenderer in tests. Keeping this for now to make tests happy...
setProperty(el: /*element*/ any, name: string, value: any) {
if (name === 'innerHTML') {
this.setInnerHTML(el, value);
} else {
el[name] = value;
}
}
// TODO(tbosch): don't even call this method when we run the tests on server side
// by not using the DomRenderer in tests. Keeping this for now to make tests happy...
getProperty(el: /*element*/ any, name: string): any { return el[name]; }
logError(error) { console.error(error); }
get attrToPropMap() { return _attrToPropMap; }
@ -268,7 +282,6 @@ export class Parse5DomAdapter extends DomAdapter {
return newParser.parseFragment(serialized).childNodes[0];
}
}
hasProperty(element, name: string) { return _HTMLElementPropertyList.indexOf(name) > -1; }
getElementsByClassName(element, name: string) {
return this.querySelectorAll(element, "." + name);
}