feat(compiler): added support for host actions
This commit is contained in:
@ -620,6 +620,33 @@ export class Directive extends Injectable {
|
|||||||
*/
|
*/
|
||||||
hostAttributes:any; // String map
|
hostAttributes:any; // String map
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies which DOM methods a directive can invoke.
|
||||||
|
*
|
||||||
|
* ## Syntax
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* @Directive({
|
||||||
|
* selector: 'input',
|
||||||
|
* hostActions: {
|
||||||
|
* 'emitFocus': 'focus()'
|
||||||
|
* }
|
||||||
|
* })
|
||||||
|
* class InputDirective {
|
||||||
|
* constructor() {
|
||||||
|
* this.emitFocus = new EventEmitter();
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* focus() {
|
||||||
|
* this.emitFocus.next();
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* In this example calling focus on InputDirective will result in calling focus on the DOM element.
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
hostActions:any; // String map
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies a set of lifecycle hostListeners in which the directive participates.
|
* Specifies a set of lifecycle hostListeners in which the directive participates.
|
||||||
*
|
*
|
||||||
@ -641,6 +668,7 @@ export class Directive extends Injectable {
|
|||||||
hostListeners,
|
hostListeners,
|
||||||
hostProperties,
|
hostProperties,
|
||||||
hostAttributes,
|
hostAttributes,
|
||||||
|
hostActions,
|
||||||
lifecycle,
|
lifecycle,
|
||||||
compileChildren = true,
|
compileChildren = true,
|
||||||
}:{
|
}:{
|
||||||
@ -650,6 +678,7 @@ export class Directive extends Injectable {
|
|||||||
hostListeners: any,
|
hostListeners: any,
|
||||||
hostProperties: any,
|
hostProperties: any,
|
||||||
hostAttributes: any,
|
hostAttributes: any,
|
||||||
|
hostActions: any,
|
||||||
lifecycle:List,
|
lifecycle:List,
|
||||||
compileChildren:boolean
|
compileChildren:boolean
|
||||||
}={})
|
}={})
|
||||||
@ -661,6 +690,7 @@ export class Directive extends Injectable {
|
|||||||
this.hostListeners = hostListeners;
|
this.hostListeners = hostListeners;
|
||||||
this.hostProperties = hostProperties;
|
this.hostProperties = hostProperties;
|
||||||
this.hostAttributes = hostAttributes;
|
this.hostAttributes = hostAttributes;
|
||||||
|
this.hostActions = hostActions;
|
||||||
this.lifecycle = lifecycle;
|
this.lifecycle = lifecycle;
|
||||||
this.compileChildren = compileChildren;
|
this.compileChildren = compileChildren;
|
||||||
}
|
}
|
||||||
@ -858,6 +888,7 @@ export class Component extends Directive {
|
|||||||
hostListeners,
|
hostListeners,
|
||||||
hostProperties,
|
hostProperties,
|
||||||
hostAttributes,
|
hostAttributes,
|
||||||
|
hostActions,
|
||||||
injectables,
|
injectables,
|
||||||
lifecycle,
|
lifecycle,
|
||||||
changeDetection = DEFAULT,
|
changeDetection = DEFAULT,
|
||||||
@ -870,6 +901,7 @@ export class Component extends Directive {
|
|||||||
hostListeners:any,
|
hostListeners:any,
|
||||||
hostProperties:any,
|
hostProperties:any,
|
||||||
hostAttributes:any,
|
hostAttributes:any,
|
||||||
|
hostActions:any,
|
||||||
injectables:List,
|
injectables:List,
|
||||||
lifecycle:List,
|
lifecycle:List,
|
||||||
changeDetection:string,
|
changeDetection:string,
|
||||||
@ -884,6 +916,7 @@ export class Component extends Directive {
|
|||||||
hostListeners: hostListeners,
|
hostListeners: hostListeners,
|
||||||
hostProperties: hostProperties,
|
hostProperties: hostProperties,
|
||||||
hostAttributes: hostAttributes,
|
hostAttributes: hostAttributes,
|
||||||
|
hostActions: hostActions,
|
||||||
lifecycle: lifecycle,
|
lifecycle: lifecycle,
|
||||||
compileChildren: compileChildren
|
compileChildren: compileChildren
|
||||||
});
|
});
|
||||||
|
@ -233,6 +233,7 @@ export class Compiler {
|
|||||||
hostListeners: isPresent(ann.hostListeners) ? MapWrapper.createFromStringMap(ann.hostListeners) : null,
|
hostListeners: isPresent(ann.hostListeners) ? MapWrapper.createFromStringMap(ann.hostListeners) : null,
|
||||||
hostProperties: isPresent(ann.hostProperties) ? MapWrapper.createFromStringMap(ann.hostProperties) : null,
|
hostProperties: isPresent(ann.hostProperties) ? MapWrapper.createFromStringMap(ann.hostProperties) : null,
|
||||||
hostAttributes: isPresent(ann.hostAttributes) ? MapWrapper.createFromStringMap(ann.hostAttributes) : null,
|
hostAttributes: isPresent(ann.hostAttributes) ? MapWrapper.createFromStringMap(ann.hostAttributes) : null,
|
||||||
|
hostActions: isPresent(ann.hostActions) ? MapWrapper.createFromStringMap(ann.hostActions) : null,
|
||||||
properties: isPresent(ann.properties) ? MapWrapper.createFromStringMap(ann.properties) : null,
|
properties: isPresent(ann.properties) ? MapWrapper.createFromStringMap(ann.properties) : null,
|
||||||
readAttributes: readAttributes
|
readAttributes: readAttributes
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import {isPresent, isBlank, Type, int, BaseException} from 'angular2/src/facade/lang';
|
import {isPresent, isBlank, Type, int, BaseException, stringify} from 'angular2/src/facade/lang';
|
||||||
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
import {Math} from 'angular2/src/facade/math';
|
import {Math} from 'angular2/src/facade/math';
|
||||||
import {List, ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
|
import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||||
import {Injector, Key, Dependency, bind, Binding, ResolvedBinding, NoBindingError,
|
import {Injector, Key, Dependency, bind, Binding, ResolvedBinding, NoBindingError,
|
||||||
AbstractBindingError, CyclicDependencyError} from 'angular2/di';
|
AbstractBindingError, CyclicDependencyError} from 'angular2/di';
|
||||||
import {Parent, Ancestor} from 'angular2/src/core/annotations_impl/visibility';
|
import {Parent, Ancestor} from 'angular2/src/core/annotations_impl/visibility';
|
||||||
@ -248,6 +248,10 @@ export class DirectiveBinding extends ResolvedBinding {
|
|||||||
return isPresent(this.annotation) && isPresent(this.annotation.events) ? this.annotation.events : [];
|
return isPresent(this.annotation) && isPresent(this.annotation.events) ? this.annotation.events : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get hostActions() { //StringMap
|
||||||
|
return isPresent(this.annotation) && isPresent(this.annotation.hostActions) ? this.annotation.hostActions : {};
|
||||||
|
}
|
||||||
|
|
||||||
get changeDetection() {
|
get changeDetection() {
|
||||||
if (this.annotation instanceof Component) {
|
if (this.annotation instanceof Component) {
|
||||||
var c:Component = this.annotation;
|
var c:Component = this.annotation;
|
||||||
@ -297,6 +301,22 @@ class EventEmitterAccessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class HostActionAccessor {
|
||||||
|
actionExpression:string;
|
||||||
|
getter:Function;
|
||||||
|
|
||||||
|
constructor(actionExpression:string, getter:Function) {
|
||||||
|
this.actionExpression = actionExpression;
|
||||||
|
this.getter = getter;
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribe(view:viewModule.AppView, boundElementIndex:number, directive:Object) {
|
||||||
|
var eventEmitter = this.getter(directive);
|
||||||
|
return ObservableWrapper.subscribe(eventEmitter,
|
||||||
|
actionObj => view.callAction(boundElementIndex, this.actionExpression, actionObj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
Difference between di.Injector and ElementInjector
|
Difference between di.Injector and ElementInjector
|
||||||
@ -346,6 +366,7 @@ export class ProtoElementInjector {
|
|||||||
distanceToParent:number;
|
distanceToParent:number;
|
||||||
attributes:Map;
|
attributes:Map;
|
||||||
eventEmitterAccessors:List<List<EventEmitterAccessor>>;
|
eventEmitterAccessors:List<List<EventEmitterAccessor>>;
|
||||||
|
hostActionAccessors:List<List<HostActionAccessor>>;
|
||||||
|
|
||||||
numberOfDirectives:number;
|
numberOfDirectives:number;
|
||||||
|
|
||||||
@ -380,56 +401,67 @@ export class ProtoElementInjector {
|
|||||||
this.numberOfDirectives = bindings.length;
|
this.numberOfDirectives = bindings.length;
|
||||||
var length = bindings.length;
|
var length = bindings.length;
|
||||||
this.eventEmitterAccessors = ListWrapper.createFixedSize(length);
|
this.eventEmitterAccessors = ListWrapper.createFixedSize(length);
|
||||||
|
this.hostActionAccessors = ListWrapper.createFixedSize(length);
|
||||||
|
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
this._binding0 = this._createBinding(bindings[0]);
|
this._binding0 = this._createBinding(bindings[0]);
|
||||||
this._keyId0 = this._binding0.key.id;
|
this._keyId0 = this._binding0.key.id;
|
||||||
this.eventEmitterAccessors[0] = this._createEventEmitterAccessors(this._binding0);
|
this.eventEmitterAccessors[0] = this._createEventEmitterAccessors(this._binding0);
|
||||||
|
this.hostActionAccessors[0] = this._createHostActionAccessors(this._binding0);
|
||||||
}
|
}
|
||||||
if (length > 1) {
|
if (length > 1) {
|
||||||
this._binding1 = this._createBinding(bindings[1]);
|
this._binding1 = this._createBinding(bindings[1]);
|
||||||
this._keyId1 = this._binding1.key.id;
|
this._keyId1 = this._binding1.key.id;
|
||||||
this.eventEmitterAccessors[1] = this._createEventEmitterAccessors(this._binding1);
|
this.eventEmitterAccessors[1] = this._createEventEmitterAccessors(this._binding1);
|
||||||
|
this.hostActionAccessors[1] = this._createHostActionAccessors(this._binding1);
|
||||||
}
|
}
|
||||||
if (length > 2) {
|
if (length > 2) {
|
||||||
this._binding2 = this._createBinding(bindings[2]);
|
this._binding2 = this._createBinding(bindings[2]);
|
||||||
this._keyId2 = this._binding2.key.id;
|
this._keyId2 = this._binding2.key.id;
|
||||||
this.eventEmitterAccessors[2] = this._createEventEmitterAccessors(this._binding2);
|
this.eventEmitterAccessors[2] = this._createEventEmitterAccessors(this._binding2);
|
||||||
|
this.hostActionAccessors[2] = this._createHostActionAccessors(this._binding2);
|
||||||
}
|
}
|
||||||
if (length > 3) {
|
if (length > 3) {
|
||||||
this._binding3 = this._createBinding(bindings[3]);
|
this._binding3 = this._createBinding(bindings[3]);
|
||||||
this._keyId3 = this._binding3.key.id;
|
this._keyId3 = this._binding3.key.id;
|
||||||
this.eventEmitterAccessors[3] = this._createEventEmitterAccessors(this._binding3);
|
this.eventEmitterAccessors[3] = this._createEventEmitterAccessors(this._binding3);
|
||||||
|
this.hostActionAccessors[3] = this._createHostActionAccessors(this._binding3);
|
||||||
}
|
}
|
||||||
if (length > 4) {
|
if (length > 4) {
|
||||||
this._binding4 = this._createBinding(bindings[4]);
|
this._binding4 = this._createBinding(bindings[4]);
|
||||||
this._keyId4 = this._binding4.key.id;
|
this._keyId4 = this._binding4.key.id;
|
||||||
this.eventEmitterAccessors[4] = this._createEventEmitterAccessors(this._binding4);
|
this.eventEmitterAccessors[4] = this._createEventEmitterAccessors(this._binding4);
|
||||||
|
this.hostActionAccessors[4] = this._createHostActionAccessors(this._binding4);
|
||||||
}
|
}
|
||||||
if (length > 5) {
|
if (length > 5) {
|
||||||
this._binding5 = this._createBinding(bindings[5]);
|
this._binding5 = this._createBinding(bindings[5]);
|
||||||
this._keyId5 = this._binding5.key.id;
|
this._keyId5 = this._binding5.key.id;
|
||||||
this.eventEmitterAccessors[5] = this._createEventEmitterAccessors(this._binding5);
|
this.eventEmitterAccessors[5] = this._createEventEmitterAccessors(this._binding5);
|
||||||
|
this.hostActionAccessors[5] = this._createHostActionAccessors(this._binding5);
|
||||||
}
|
}
|
||||||
if (length > 6) {
|
if (length > 6) {
|
||||||
this._binding6 = this._createBinding(bindings[6]);
|
this._binding6 = this._createBinding(bindings[6]);
|
||||||
this._keyId6 = this._binding6.key.id;
|
this._keyId6 = this._binding6.key.id;
|
||||||
this.eventEmitterAccessors[6] = this._createEventEmitterAccessors(this._binding6);
|
this.eventEmitterAccessors[6] = this._createEventEmitterAccessors(this._binding6);
|
||||||
|
this.hostActionAccessors[6] = this._createHostActionAccessors(this._binding6);
|
||||||
}
|
}
|
||||||
if (length > 7) {
|
if (length > 7) {
|
||||||
this._binding7 = this._createBinding(bindings[7]);
|
this._binding7 = this._createBinding(bindings[7]);
|
||||||
this._keyId7 = this._binding7.key.id;
|
this._keyId7 = this._binding7.key.id;
|
||||||
this.eventEmitterAccessors[7] = this._createEventEmitterAccessors(this._binding7);
|
this.eventEmitterAccessors[7] = this._createEventEmitterAccessors(this._binding7);
|
||||||
|
this.hostActionAccessors[7] = this._createHostActionAccessors(this._binding7);
|
||||||
}
|
}
|
||||||
if (length > 8) {
|
if (length > 8) {
|
||||||
this._binding8 = this._createBinding(bindings[8]);
|
this._binding8 = this._createBinding(bindings[8]);
|
||||||
this._keyId8 = this._binding8.key.id;
|
this._keyId8 = this._binding8.key.id;
|
||||||
this.eventEmitterAccessors[8] = this._createEventEmitterAccessors(this._binding8);
|
this.eventEmitterAccessors[8] = this._createEventEmitterAccessors(this._binding8);
|
||||||
|
this.hostActionAccessors[8] = this._createHostActionAccessors(this._binding8);
|
||||||
}
|
}
|
||||||
if (length > 9) {
|
if (length > 9) {
|
||||||
this._binding9 = this._createBinding(bindings[9]);
|
this._binding9 = this._createBinding(bindings[9]);
|
||||||
this._keyId9 = this._binding9.key.id;
|
this._keyId9 = this._binding9.key.id;
|
||||||
this.eventEmitterAccessors[9] = this._createEventEmitterAccessors(this._binding9);
|
this.eventEmitterAccessors[9] = this._createEventEmitterAccessors(this._binding9);
|
||||||
|
this.hostActionAccessors[9] = this._createHostActionAccessors(this._binding9);
|
||||||
}
|
}
|
||||||
if (length > 10) {
|
if (length > 10) {
|
||||||
throw 'Maximum number of directives per element has been reached.';
|
throw 'Maximum number of directives per element has been reached.';
|
||||||
@ -442,6 +474,14 @@ export class ProtoElementInjector {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_createHostActionAccessors(b:DirectiveBinding) {
|
||||||
|
var res = [];
|
||||||
|
StringMapWrapper.forEach(b.hostActions, (actionExpression, actionName) => {
|
||||||
|
ListWrapper.push(res, new HostActionAccessor(actionExpression, reflector.getter(actionName)))
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
instantiate(parent:ElementInjector):ElementInjector {
|
instantiate(parent:ElementInjector):ElementInjector {
|
||||||
return new ElementInjector(this, parent);
|
return new ElementInjector(this, parent);
|
||||||
}
|
}
|
||||||
@ -661,6 +701,10 @@ export class ElementInjector extends TreeNode {
|
|||||||
return this._proto.eventEmitterAccessors;
|
return this._proto.eventEmitterAccessors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getHostActionAccessors() {
|
||||||
|
return this._proto.hostActionAccessors;
|
||||||
|
}
|
||||||
|
|
||||||
getComponent() {
|
getComponent() {
|
||||||
if (this._proto._binding0IsComponent) {
|
if (this._proto._binding0IsComponent) {
|
||||||
return this._obj0;
|
return this._obj0;
|
||||||
|
4
modules/angular2/src/core/compiler/view.js
vendored
4
modules/angular2/src/core/compiler/view.js
vendored
@ -126,6 +126,10 @@ export class AppView {
|
|||||||
return isPresent(childView) ? childView.changeDetector : null;
|
return isPresent(childView) ? childView.changeDetector : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callAction(elementIndex:number, actionExpression:string, action:Object) {
|
||||||
|
this.renderer.callAction(this.render, elementIndex, actionExpression, action);
|
||||||
|
}
|
||||||
|
|
||||||
// implementation of EventDispatcher#dispatchEvent
|
// implementation of EventDispatcher#dispatchEvent
|
||||||
// returns false if preventDefault must be applied to the DOM event
|
// returns false if preventDefault must be applied to the DOM event
|
||||||
dispatchEvent(elementIndex:number, eventName:string, locals:Map<string, any>): boolean {
|
dispatchEvent(elementIndex:number, eventName:string, locals:Map<string, any>): boolean {
|
||||||
|
@ -192,6 +192,7 @@ export class AppViewManagerUtils {
|
|||||||
if (isPresent(elementInjector)) {
|
if (isPresent(elementInjector)) {
|
||||||
elementInjector.instantiateDirectives(appInjector, hostElementInjector, view.preBuiltObjects[i]);
|
elementInjector.instantiateDirectives(appInjector, hostElementInjector, view.preBuiltObjects[i]);
|
||||||
this._setUpEventEmitters(view, elementInjector, i);
|
this._setUpEventEmitters(view, elementInjector, i);
|
||||||
|
this._setUpHostActions(view, elementInjector, i);
|
||||||
|
|
||||||
// The exporting of $implicit is a special case. Since multiple elements will all export
|
// The exporting of $implicit is a special case. Since multiple elements will all export
|
||||||
// the different values as $implicit, directly assign $implicit bindings to the variable
|
// the different values as $implicit, directly assign $implicit bindings to the variable
|
||||||
@ -220,6 +221,19 @@ export class AppViewManagerUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_setUpHostActions(view:viewModule.AppView, elementInjector:eli.ElementInjector, boundElementIndex:number) {
|
||||||
|
var hostActions = elementInjector.getHostActionAccessors();
|
||||||
|
for (var directiveIndex = 0; directiveIndex < hostActions.length; ++directiveIndex) {
|
||||||
|
var directiveHostActions = hostActions[directiveIndex];
|
||||||
|
var directive = elementInjector.getDirectiveAtIndex(directiveIndex);
|
||||||
|
|
||||||
|
for (var index = 0; index < directiveHostActions.length; ++index) {
|
||||||
|
var hostActionAccessor = directiveHostActions[index];
|
||||||
|
hostActionAccessor.subscribe(view, boundElementIndex, directive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dehydrateView(view:viewModule.AppView) {
|
dehydrateView(view:viewModule.AppView) {
|
||||||
var binders = view.proto.elementBinders;
|
var binders = view.proto.elementBinders;
|
||||||
for (var i = 0; i < binders.length; ++i) {
|
for (var i = 0; i < binders.length; ++i) {
|
||||||
|
@ -82,6 +82,9 @@ class StringMapWrapper {
|
|||||||
}
|
}
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
static List<String> keys(Map<String,dynamic> a) {
|
||||||
|
return a.keys.toList();
|
||||||
|
}
|
||||||
static bool isEmpty(Map m) => m.isEmpty;
|
static bool isEmpty(Map m) => m.isEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,6 +53,7 @@ export class StringMapWrapper {
|
|||||||
static contains(map, key) { return map.hasOwnProperty(key); }
|
static contains(map, key) { return map.hasOwnProperty(key); }
|
||||||
static get(map, key) { return map.hasOwnProperty(key) ? map[key] : undefined; }
|
static get(map, key) { return map.hasOwnProperty(key) ? map[key] : undefined; }
|
||||||
static set(map, key, value) { map[key] = value; }
|
static set(map, key, value) { map[key] = value; }
|
||||||
|
static keys(map) { return Object.keys(map); }
|
||||||
static isEmpty(map) {
|
static isEmpty(map) {
|
||||||
for (var prop in map) {
|
for (var prop in map) {
|
||||||
return false;
|
return false;
|
||||||
|
18
modules/angular2/src/render/api.js
vendored
18
modules/angular2/src/render/api.js
vendored
@ -117,16 +117,18 @@ export class DirectiveMetadata {
|
|||||||
hostListeners:Map<string, string>;
|
hostListeners:Map<string, string>;
|
||||||
hostProperties:Map<string, string>;
|
hostProperties:Map<string, string>;
|
||||||
hostAttributes:Map<string, string>;
|
hostAttributes:Map<string, string>;
|
||||||
|
hostActions:Map<string, string>;
|
||||||
properties:Map<string, string>;
|
properties:Map<string, string>;
|
||||||
readAttributes:List<string>;
|
readAttributes:List<string>;
|
||||||
type:number;
|
type:number;
|
||||||
constructor({id, selector, compileChildren, hostListeners, hostProperties, hostAttributes, properties, readAttributes, type}) {
|
constructor({id, selector, compileChildren, hostListeners, hostProperties, hostAttributes, hostActions, properties, readAttributes, type}) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.selector = selector;
|
this.selector = selector;
|
||||||
this.compileChildren = isPresent(compileChildren) ? compileChildren : true;
|
this.compileChildren = isPresent(compileChildren) ? compileChildren : true;
|
||||||
this.hostListeners = hostListeners;
|
this.hostListeners = hostListeners;
|
||||||
this.hostProperties = hostProperties;
|
this.hostProperties = hostProperties;
|
||||||
this.hostAttributes = hostAttributes;
|
this.hostAttributes = hostAttributes;
|
||||||
|
this.hostActions = hostActions;
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
this.readAttributes = readAttributes;
|
this.readAttributes = readAttributes;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
@ -228,7 +230,7 @@ export class Renderer {
|
|||||||
/**
|
/**
|
||||||
* Hydrates a view after it has been attached. Hydration/dehydration is used for reusing views inside of the view pool.
|
* Hydrates a view after it has been attached. Hydration/dehydration is used for reusing views inside of the view pool.
|
||||||
*/
|
*/
|
||||||
hydrateView(hviewRef:RenderViewRef) {
|
hydrateView(viewRef:RenderViewRef) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -238,14 +240,22 @@ export class Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a porperty on an element.
|
* Sets a property on an element.
|
||||||
* Note: This will fail if the property was not mentioned previously as a host property
|
* Note: This will fail if the property was not mentioned previously as a host property
|
||||||
* in the ProtoView
|
* in the ProtoView
|
||||||
*/
|
*/
|
||||||
setElementProperty(viewRef:RenderViewRef, elementIndex:number, propertyName:string, propertyValue:any):void {
|
setElementProperty(viewRef:RenderViewRef, elementIndex:number, propertyName:string, propertyValue:any):void {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|
* Calls an action.
|
||||||
|
* Note: This will fail if the action was not mentioned previously as a host action
|
||||||
|
* in the ProtoView
|
||||||
|
*/
|
||||||
|
callAction(viewRef:RenderViewRef, elementIndex:number, actionExpression:string, actionArgs:any):void {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
* Sets the value of a text node.
|
* Sets the value of a text node.
|
||||||
*/
|
*/
|
||||||
setText(viewRef:RenderViewRef, textNodeIndex:number, text:string):void {
|
setText(viewRef:RenderViewRef, textNodeIndex:number, text:string):void {
|
||||||
|
@ -73,6 +73,11 @@ export class DirectiveParser extends CompileStep {
|
|||||||
this._bindDirectiveEvent(eventName, action, current, directiveBinderBuilder);
|
this._bindDirectiveEvent(eventName, action, current, directiveBinderBuilder);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (isPresent(directive.hostActions)) {
|
||||||
|
MapWrapper.forEach(directive.hostActions, (action, actionName) => {
|
||||||
|
this._bindHostAction(actionName, action, current, directiveBinderBuilder);
|
||||||
|
});
|
||||||
|
}
|
||||||
if (isPresent(directive.hostProperties)) {
|
if (isPresent(directive.hostProperties)) {
|
||||||
MapWrapper.forEach(directive.hostProperties, (hostPropertyName, directivePropertyName) => {
|
MapWrapper.forEach(directive.hostProperties, (hostPropertyName, directivePropertyName) => {
|
||||||
this._bindHostProperty(hostPropertyName, directivePropertyName, current, directiveBinderBuilder);
|
this._bindHostProperty(hostPropertyName, directivePropertyName, current, directiveBinderBuilder);
|
||||||
@ -136,7 +141,11 @@ export class DirectiveParser extends CompileStep {
|
|||||||
} else {
|
} else {
|
||||||
directiveBinderBuilder.bindEvent(eventName, ast);
|
directiveBinderBuilder.bindEvent(eventName, ast);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_bindHostAction(actionName, actionExpression, compileElement, directiveBinderBuilder) {
|
||||||
|
var ast = this._parser.parseAction(actionExpression, compileElement.elementDescription);
|
||||||
|
directiveBinderBuilder.bindHostAction(actionName, actionExpression, ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
_bindHostProperty(hostPropertyName, directivePropertyName, compileElement, directiveBinderBuilder) {
|
_bindHostProperty(hostPropertyName, directivePropertyName, compileElement, directiveBinderBuilder) {
|
||||||
|
2
modules/angular2/src/render/dom/convert.js
vendored
2
modules/angular2/src/render/dom/convert.js
vendored
@ -14,6 +14,7 @@ export function directiveMetadataToMap(meta: DirectiveMetadata): Map {
|
|||||||
['hostListeners', _cloneIfPresent(meta.hostListeners)],
|
['hostListeners', _cloneIfPresent(meta.hostListeners)],
|
||||||
['hostProperties', _cloneIfPresent(meta.hostProperties)],
|
['hostProperties', _cloneIfPresent(meta.hostProperties)],
|
||||||
['hostAttributes', _cloneIfPresent(meta.hostAttributes)],
|
['hostAttributes', _cloneIfPresent(meta.hostAttributes)],
|
||||||
|
['hostActions', _cloneIfPresent(meta.hostActions)],
|
||||||
['properties', _cloneIfPresent(meta.properties)],
|
['properties', _cloneIfPresent(meta.properties)],
|
||||||
['readAttributes', _cloneIfPresent(meta.readAttributes)],
|
['readAttributes', _cloneIfPresent(meta.readAttributes)],
|
||||||
['type', meta.type],
|
['type', meta.type],
|
||||||
@ -33,6 +34,7 @@ export function directiveMetadataFromMap(map: Map): DirectiveMetadata {
|
|||||||
compileChildren: MapWrapper.get(map, 'compileChildren'),
|
compileChildren: MapWrapper.get(map, 'compileChildren'),
|
||||||
hostListeners: _cloneIfPresent(MapWrapper.get(map, 'hostListeners')),
|
hostListeners: _cloneIfPresent(MapWrapper.get(map, 'hostListeners')),
|
||||||
hostProperties: _cloneIfPresent(MapWrapper.get(map, 'hostProperties')),
|
hostProperties: _cloneIfPresent(MapWrapper.get(map, 'hostProperties')),
|
||||||
|
hostActions: _cloneIfPresent(MapWrapper.get(map, 'hostActions')),
|
||||||
hostAttributes: _cloneIfPresent(MapWrapper.get(map, 'hostAttributes')),
|
hostAttributes: _cloneIfPresent(MapWrapper.get(map, 'hostAttributes')),
|
||||||
properties: _cloneIfPresent(MapWrapper.get(map, 'properties')),
|
properties: _cloneIfPresent(MapWrapper.get(map, 'properties')),
|
||||||
readAttributes: _cloneIfPresent(MapWrapper.get(map, 'readAttributes')),
|
readAttributes: _cloneIfPresent(MapWrapper.get(map, 'readAttributes')),
|
||||||
|
@ -192,6 +192,11 @@ export class DomRenderer extends Renderer {
|
|||||||
view.setElementProperty(elementIndex, propertyName, propertyValue);
|
view.setElementProperty(elementIndex, propertyName, propertyValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callAction(viewRef:RenderViewRef, elementIndex:number, actionExpression:string, actionArgs:any):void {
|
||||||
|
var view = resolveInternalDomView(viewRef);
|
||||||
|
view.callAction(elementIndex, actionExpression, actionArgs);
|
||||||
|
}
|
||||||
|
|
||||||
setText(viewRef:RenderViewRef, textNodeIndex:number, text:string):void {
|
setText(viewRef:RenderViewRef, textNodeIndex:number, text:string):void {
|
||||||
var view = resolveInternalDomView(viewRef);
|
var view = resolveInternalDomView(viewRef);
|
||||||
DOM.setText(view.boundTextNodes[textNodeIndex], text);
|
DOM.setText(view.boundTextNodes[textNodeIndex], text);
|
||||||
|
@ -14,6 +14,7 @@ export class ElementBinder {
|
|||||||
parentIndex:number;
|
parentIndex:number;
|
||||||
distanceToParent:number;
|
distanceToParent:number;
|
||||||
propertySetters: Map<string, SetterFn>;
|
propertySetters: Map<string, SetterFn>;
|
||||||
|
hostActions: Map<string, AST>;
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
textNodeIndices,
|
textNodeIndices,
|
||||||
@ -23,6 +24,7 @@ export class ElementBinder {
|
|||||||
eventLocals,
|
eventLocals,
|
||||||
localEvents,
|
localEvents,
|
||||||
globalEvents,
|
globalEvents,
|
||||||
|
hostActions,
|
||||||
parentIndex,
|
parentIndex,
|
||||||
distanceToParent,
|
distanceToParent,
|
||||||
propertySetters
|
propertySetters
|
||||||
@ -34,6 +36,7 @@ export class ElementBinder {
|
|||||||
this.eventLocals = eventLocals;
|
this.eventLocals = eventLocals;
|
||||||
this.localEvents = localEvents;
|
this.localEvents = localEvents;
|
||||||
this.globalEvents = globalEvents;
|
this.globalEvents = globalEvents;
|
||||||
|
this.hostActions = hostActions;
|
||||||
this.parentIndex = parentIndex;
|
this.parentIndex = parentIndex;
|
||||||
this.distanceToParent = distanceToParent;
|
this.distanceToParent = distanceToParent;
|
||||||
this.propertySetters = propertySetters;
|
this.propertySetters = propertySetters;
|
||||||
@ -51,3 +54,15 @@ export class Event {
|
|||||||
this.fullName = fullName;
|
this.fullName = fullName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class HostAction {
|
||||||
|
actionName: string;
|
||||||
|
actionExpression: string;
|
||||||
|
expression: AST;
|
||||||
|
|
||||||
|
constructor(actionName: string, actionExpression: string, expression: AST) {
|
||||||
|
this.actionName = actionName;
|
||||||
|
this.actionExpression = actionExpression;
|
||||||
|
this.expression = expression;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
} from 'angular2/change_detection';
|
} from 'angular2/change_detection';
|
||||||
|
|
||||||
import {DomProtoView, DomProtoViewRef, resolveInternalDomProtoView} from './proto_view';
|
import {DomProtoView, DomProtoViewRef, resolveInternalDomProtoView} from './proto_view';
|
||||||
import {ElementBinder, Event} from './element_binder';
|
import {ElementBinder, Event, HostAction} from './element_binder';
|
||||||
import {setterFactory} from './property_setter_factory';
|
import {setterFactory} from './property_setter_factory';
|
||||||
|
|
||||||
import * as api from '../../api';
|
import * as api from '../../api';
|
||||||
@ -48,6 +48,7 @@ export class ProtoViewBuilder {
|
|||||||
var apiElementBinders = [];
|
var apiElementBinders = [];
|
||||||
ListWrapper.forEach(this.elements, (ebb) => {
|
ListWrapper.forEach(this.elements, (ebb) => {
|
||||||
var propertySetters = MapWrapper.create();
|
var propertySetters = MapWrapper.create();
|
||||||
|
var hostActions = MapWrapper.create();
|
||||||
|
|
||||||
var apiDirectiveBinders = ListWrapper.map(ebb.directives, (dbb) => {
|
var apiDirectiveBinders = ListWrapper.map(ebb.directives, (dbb) => {
|
||||||
ebb.eventBuilder.merge(dbb.eventBuilder);
|
ebb.eventBuilder.merge(dbb.eventBuilder);
|
||||||
@ -56,6 +57,10 @@ export class ProtoViewBuilder {
|
|||||||
MapWrapper.set(propertySetters, hostPropertyName, setterFactory(hostPropertyName));
|
MapWrapper.set(propertySetters, hostPropertyName, setterFactory(hostPropertyName));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ListWrapper.forEach(dbb.hostActions, (hostAction) => {
|
||||||
|
MapWrapper.set(hostActions, hostAction.actionExpression, hostAction.expression);
|
||||||
|
});
|
||||||
|
|
||||||
return new api.DirectiveBinder({
|
return new api.DirectiveBinder({
|
||||||
directiveIndex: dbb.directiveIndex,
|
directiveIndex: dbb.directiveIndex,
|
||||||
propertyBindings: dbb.propertyBindings,
|
propertyBindings: dbb.propertyBindings,
|
||||||
@ -90,6 +95,7 @@ export class ProtoViewBuilder {
|
|||||||
eventLocals: new LiteralArray(ebb.eventBuilder.buildEventLocals()),
|
eventLocals: new LiteralArray(ebb.eventBuilder.buildEventLocals()),
|
||||||
localEvents: ebb.eventBuilder.buildLocalEvents(),
|
localEvents: ebb.eventBuilder.buildLocalEvents(),
|
||||||
globalEvents: ebb.eventBuilder.buildGlobalEvents(),
|
globalEvents: ebb.eventBuilder.buildGlobalEvents(),
|
||||||
|
hostActions: hostActions,
|
||||||
propertySetters: propertySetters
|
propertySetters: propertySetters
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
@ -213,6 +219,7 @@ export class DirectiveBuilder {
|
|||||||
directiveIndex:number;
|
directiveIndex:number;
|
||||||
propertyBindings: Map<string, ASTWithSource>;
|
propertyBindings: Map<string, ASTWithSource>;
|
||||||
hostPropertyBindings: Map<string, ASTWithSource>;
|
hostPropertyBindings: Map<string, ASTWithSource>;
|
||||||
|
hostActions: List<HostAction>;
|
||||||
eventBindings: List<api.EventBinding>;
|
eventBindings: List<api.EventBinding>;
|
||||||
eventBuilder: EventBuilder;
|
eventBuilder: EventBuilder;
|
||||||
|
|
||||||
@ -220,6 +227,7 @@ export class DirectiveBuilder {
|
|||||||
this.directiveIndex = directiveIndex;
|
this.directiveIndex = directiveIndex;
|
||||||
this.propertyBindings = MapWrapper.create();
|
this.propertyBindings = MapWrapper.create();
|
||||||
this.hostPropertyBindings = MapWrapper.create();
|
this.hostPropertyBindings = MapWrapper.create();
|
||||||
|
this.hostActions = ListWrapper.create();
|
||||||
this.eventBindings = ListWrapper.create();
|
this.eventBindings = ListWrapper.create();
|
||||||
this.eventBuilder = new EventBuilder();
|
this.eventBuilder = new EventBuilder();
|
||||||
}
|
}
|
||||||
@ -232,6 +240,10 @@ export class DirectiveBuilder {
|
|||||||
MapWrapper.set(this.hostPropertyBindings, name, expression);
|
MapWrapper.set(this.hostPropertyBindings, name, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindHostAction(actionName:string, actionExpression:string, expression:ASTWithSource) {
|
||||||
|
ListWrapper.push(this.hostActions, new HostAction(actionName, actionExpression, expression));
|
||||||
|
}
|
||||||
|
|
||||||
bindEvent(name, expression, target = null) {
|
bindEvent(name, expression, target = null) {
|
||||||
ListWrapper.push(this.eventBindings, this.eventBuilder.add(name, expression, target));
|
ListWrapper.push(this.eventBindings, this.eventBuilder.add(name, expression, target));
|
||||||
}
|
}
|
||||||
|
13
modules/angular2/src/render/dom/view/view.js
vendored
13
modules/angular2/src/render/dom/view/view.js
vendored
@ -1,5 +1,6 @@
|
|||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
|
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
|
||||||
|
import {Locals} from 'angular2/change_detection';
|
||||||
import {int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
import {int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
import {DomViewContainer} from './view_container';
|
import {DomViewContainer} from './view_container';
|
||||||
@ -80,6 +81,18 @@ export class DomView {
|
|||||||
setter(this.boundElements[elementIndex], value);
|
setter(this.boundElements[elementIndex], value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callAction(elementIndex:number, actionExpression:string, actionArgs:any) {
|
||||||
|
var binder = this.proto.elementBinders[elementIndex];
|
||||||
|
var hostAction = MapWrapper.get(binder.hostActions, actionExpression);
|
||||||
|
hostAction.eval(this.boundElements[elementIndex], this._localsWithAction(actionArgs));
|
||||||
|
}
|
||||||
|
|
||||||
|
_localsWithAction(action:Object):Locals {
|
||||||
|
var map = MapWrapper.create();
|
||||||
|
MapWrapper.set(map, '$action', action);
|
||||||
|
return new Locals(null, map);
|
||||||
|
}
|
||||||
|
|
||||||
setText(textIndex:number, value:string) {
|
setText(textIndex:number, value:string) {
|
||||||
DOM.setText(this.boundTextNodes[textIndex], value);
|
DOM.setText(this.boundTextNodes[textIndex], value);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ import {ViewRef, Renderer} from 'angular2/src/render/api';
|
|||||||
import {QueryList} from 'angular2/src/core/compiler/query_list';
|
import {QueryList} from 'angular2/src/core/compiler/query_list';
|
||||||
|
|
||||||
class DummyDirective extends Directive {
|
class DummyDirective extends Directive {
|
||||||
constructor({lifecycle, events} = {}) { super({lifecycle: lifecycle, events: events}); }
|
constructor({lifecycle, events, hostActions} = {}) { super({lifecycle: lifecycle, events: events, hostActions:hostActions}); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@proxy
|
@proxy
|
||||||
@ -97,6 +97,13 @@ class HasEventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class HasHostAction {
|
||||||
|
hostActionName;
|
||||||
|
constructor() {
|
||||||
|
this.hostActionName = "hostAction";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class NeedsAttribute {
|
class NeedsAttribute {
|
||||||
typeAttribute;
|
typeAttribute;
|
||||||
titleAttribute;
|
titleAttribute;
|
||||||
@ -381,7 +388,7 @@ export function main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('event emitters', () => {
|
describe('event emitters', () => {
|
||||||
it('should return a list of event emitter accessors', () => {
|
it('should return a list of event accessors', () => {
|
||||||
var binding = DirectiveBinding.createFromType(
|
var binding = DirectiveBinding.createFromType(
|
||||||
HasEventEmitter, new DummyDirective({events: ['emitter']}));
|
HasEventEmitter, new DummyDirective({events: ['emitter']}));
|
||||||
|
|
||||||
@ -392,6 +399,18 @@ export function main() {
|
|||||||
expect(accessor.eventName).toEqual('emitter');
|
expect(accessor.eventName).toEqual('emitter');
|
||||||
expect(accessor.getter(new HasEventEmitter())).toEqual('emitter');
|
expect(accessor.getter(new HasEventEmitter())).toEqual('emitter');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return a list of hostAction accessors', () => {
|
||||||
|
var binding = DirectiveBinding.createFromType(
|
||||||
|
HasEventEmitter, new DummyDirective({hostActions: {'hostActionName' : 'onAction'}}));
|
||||||
|
|
||||||
|
var inj = new ProtoElementInjector(null, 0, [binding]);
|
||||||
|
expect(inj.hostActionAccessors.length).toEqual(1);
|
||||||
|
|
||||||
|
var accessor = inj.hostActionAccessors[0][0];
|
||||||
|
expect(accessor.actionExpression).toEqual('onAction');
|
||||||
|
expect(accessor.getter(new HasHostAction())).toEqual('hostAction');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -581,15 +581,37 @@ export function main() {
|
|||||||
|
|
||||||
expect(listener.msg).toEqual('');
|
expect(listener.msg).toEqual('');
|
||||||
|
|
||||||
emitter.fireEvent('fired !');
|
ObservableWrapper.subscribe(emitter.event, (_) => {
|
||||||
|
|
||||||
PromiseWrapper.setTimeout(() => {
|
|
||||||
expect(listener.msg).toEqual('fired !');
|
expect(listener.msg).toEqual('fired !');
|
||||||
async.done();
|
async.done();
|
||||||
}, 0);
|
});
|
||||||
|
|
||||||
|
emitter.fireEvent('fired !');
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
if (DOM.supportsDOMEvents()) {
|
||||||
|
it("should support invoking methods on the host element via hostActions", inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||||
|
tb.overrideView(MyComp, new View({
|
||||||
|
template: '<div update-host-actions></div>',
|
||||||
|
directives: [DirectiveUpdatingHostActions]
|
||||||
|
}));
|
||||||
|
|
||||||
|
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||||
|
var injector = view.rawView.elementInjectors[0];
|
||||||
|
var domElement = view.rootNodes[0];
|
||||||
|
var updateHost = injector.get(DirectiveUpdatingHostActions);
|
||||||
|
|
||||||
|
ObservableWrapper.subscribe(updateHost.setAttr, (_) => {
|
||||||
|
expect(DOM.getOuterHTML(domElement)).toEqual('<div update-host-actions="" class="ng-binding" key="value"></div>');
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
|
||||||
|
updateHost.triggerSetAttr('value');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
it('should support render events', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
it('should support render events', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||||
tb.overrideView(MyComp, new View({
|
tb.overrideView(MyComp, new View({
|
||||||
template: '<div listener></div>',
|
template: '<div listener></div>',
|
||||||
@ -671,6 +693,7 @@ export function main() {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
if (DOM.supportsDOMEvents()) {
|
if (DOM.supportsDOMEvents()) {
|
||||||
it('should support preventing default on render events', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
it('should support preventing default on render events', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||||
tb.overrideView(MyComp, new View({
|
tb.overrideView(MyComp, new View({
|
||||||
@ -1218,6 +1241,24 @@ class DirectiveUpdatingHostProperties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Directive({
|
||||||
|
selector: '[update-host-actions]',
|
||||||
|
hostActions: {
|
||||||
|
'setAttr': 'setAttribute("key", $action["attrValue"])'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
class DirectiveUpdatingHostActions {
|
||||||
|
setAttr:EventEmitter;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.setAttr = new EventEmitter();
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerSetAttr(attrValue) {
|
||||||
|
ObservableWrapper.callNext(this.setAttr, {'attrValue': attrValue});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: '[listener]',
|
selector: '[listener]',
|
||||||
hostListeners: {'event': 'onEvent($event)'}
|
hostListeners: {'event': 'onEvent($event)'}
|
||||||
|
@ -31,6 +31,7 @@ import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils
|
|||||||
export function main() {
|
export function main() {
|
||||||
// TODO(tbosch): add more tests here!
|
// TODO(tbosch): add more tests here!
|
||||||
|
|
||||||
|
|
||||||
describe('AppViewManagerUtils', () => {
|
describe('AppViewManagerUtils', () => {
|
||||||
|
|
||||||
var metadataReader;
|
var metadataReader;
|
||||||
@ -71,6 +72,7 @@ export function main() {
|
|||||||
'isExportingComponent' : false,
|
'isExportingComponent' : false,
|
||||||
'isExportingElement' : false,
|
'isExportingElement' : false,
|
||||||
'getEventEmitterAccessors' : [],
|
'getEventEmitterAccessors' : [],
|
||||||
|
'getHostActionAccessors' : [],
|
||||||
'getComponent' : null,
|
'getComponent' : null,
|
||||||
'getDynamicallyLoadedComponent': null,
|
'getDynamicallyLoadedComponent': null,
|
||||||
'getHost': host
|
'getHost': host
|
||||||
@ -154,11 +156,13 @@ export function main() {
|
|||||||
var hostView = createView(hostPv);
|
var hostView = createView(hostPv);
|
||||||
var spyEventAccessor1 = SpyObject.stub({"subscribe" : null});
|
var spyEventAccessor1 = SpyObject.stub({"subscribe" : null});
|
||||||
SpyObject.stub(hostView.elementInjectors[0], {
|
SpyObject.stub(hostView.elementInjectors[0], {
|
||||||
|
'getHostActionAccessors': [],
|
||||||
'getEventEmitterAccessors': [[spyEventAccessor1]],
|
'getEventEmitterAccessors': [[spyEventAccessor1]],
|
||||||
'getDirectiveAtIndex': dir
|
'getDirectiveAtIndex': dir
|
||||||
});
|
});
|
||||||
var spyEventAccessor2 = SpyObject.stub({"subscribe" : null});
|
var spyEventAccessor2 = SpyObject.stub({"subscribe" : null});
|
||||||
SpyObject.stub(hostView.elementInjectors[1], {
|
SpyObject.stub(hostView.elementInjectors[1], {
|
||||||
|
'getHostActionAccessors': [],
|
||||||
'getEventEmitterAccessors': [[spyEventAccessor2]],
|
'getEventEmitterAccessors': [[spyEventAccessor2]],
|
||||||
'getDirectiveAtIndex': dir
|
'getDirectiveAtIndex': dir
|
||||||
});
|
});
|
||||||
@ -172,6 +176,36 @@ export function main() {
|
|||||||
expect(spyEventAccessor2.spy('subscribe')).toHaveBeenCalledWith(hostView, 1, dir);
|
expect(spyEventAccessor2.spy('subscribe')).toHaveBeenCalledWith(hostView, 1, dir);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should set up host action listeners", () => {
|
||||||
|
var dir = new Object();
|
||||||
|
|
||||||
|
var hostPv = createProtoView([
|
||||||
|
createComponentElBinder(null),
|
||||||
|
createEmptyElBinder()
|
||||||
|
]);
|
||||||
|
var hostView = createView(hostPv);
|
||||||
|
var spyActionAccessor1 = SpyObject.stub({"subscribe" : null});
|
||||||
|
SpyObject.stub(hostView.elementInjectors[0], {
|
||||||
|
'getHostActionAccessors': [[spyActionAccessor1]],
|
||||||
|
'getEventEmitterAccessors': [],
|
||||||
|
'getDirectiveAtIndex': dir
|
||||||
|
});
|
||||||
|
var spyActionAccessor2 = SpyObject.stub({"subscribe" : null});
|
||||||
|
SpyObject.stub(hostView.elementInjectors[1], {
|
||||||
|
'getHostActionAccessors': [[spyActionAccessor2]],
|
||||||
|
'getEventEmitterAccessors': [],
|
||||||
|
'getDirectiveAtIndex': dir
|
||||||
|
});
|
||||||
|
|
||||||
|
var shadowView = createView();
|
||||||
|
utils.attachComponentView(hostView, 0, shadowView);
|
||||||
|
|
||||||
|
utils.attachAndHydrateInPlaceHostView(null, null, hostView, createInjector());
|
||||||
|
|
||||||
|
expect(spyActionAccessor1.spy('subscribe')).toHaveBeenCalledWith(hostView, 0, dir);
|
||||||
|
expect(spyActionAccessor2.spy('subscribe')).toHaveBeenCalledWith(hostView, 1, dir);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('attachViewInContainer', () => {
|
describe('attachViewInContainer', () => {
|
||||||
|
@ -25,7 +25,8 @@ export function main() {
|
|||||||
someDirectiveWithHostProperties,
|
someDirectiveWithHostProperties,
|
||||||
someDirectiveWithHostAttributes,
|
someDirectiveWithHostAttributes,
|
||||||
someDirectiveWithEvents,
|
someDirectiveWithEvents,
|
||||||
someDirectiveWithGlobalEvents
|
someDirectiveWithGlobalEvents,
|
||||||
|
someDirectiveWithHostActions
|
||||||
];
|
];
|
||||||
parser = new Parser(new Lexer());
|
parser = new Parser(new Lexer());
|
||||||
});
|
});
|
||||||
@ -171,6 +172,14 @@ export function main() {
|
|||||||
expect(eventBinding.source.source).toEqual('doItGlobal()');
|
expect(eventBinding.source.source).toEqual('doItGlobal()');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should bind directive host actions', () => {
|
||||||
|
var results = process(
|
||||||
|
el('<div some-decor-host-actions></div>')
|
||||||
|
);
|
||||||
|
var directiveBinding = results[0].directives[0];
|
||||||
|
expect(directiveBinding.hostActions[0].actionName).toEqual('focus');
|
||||||
|
});
|
||||||
|
|
||||||
//TODO: assertions should be enabled when running tests: https://github.com/angular/angular/issues/1340
|
//TODO: assertions should be enabled when running tests: https://github.com/angular/angular/issues/1340
|
||||||
describe('component directives', () => {
|
describe('component directives', () => {
|
||||||
it('should save the component id', () => {
|
it('should save the component id', () => {
|
||||||
@ -276,6 +285,13 @@ var someDirectiveWithEvents = new DirectiveMetadata({
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var someDirectiveWithHostActions = new DirectiveMetadata({
|
||||||
|
selector: '[some-decor-host-actions]',
|
||||||
|
hostActions: MapWrapper.createFromStringMap({
|
||||||
|
'focus': 'focus()'
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
var someDirectiveWithGlobalEvents = new DirectiveMetadata({
|
var someDirectiveWithGlobalEvents = new DirectiveMetadata({
|
||||||
selector: '[some-decor-globalevents]',
|
selector: '[some-decor-globalevents]',
|
||||||
hostListeners: MapWrapper.createFromStringMap({
|
hostListeners: MapWrapper.createFromStringMap({
|
||||||
|
10
modules/angular2/test/render/dom/convert_spec.js
vendored
10
modules/angular2/test/render/dom/convert_spec.js
vendored
@ -2,7 +2,7 @@ import {MapWrapper} from 'angular2/src/facade/collection';
|
|||||||
import {DirectiveMetadata} from 'angular2/src/render/api';
|
import {DirectiveMetadata} from 'angular2/src/render/api';
|
||||||
import {directiveMetadataFromMap, directiveMetadataToMap} from
|
import {directiveMetadataFromMap, directiveMetadataToMap} from
|
||||||
'angular2/src/render/dom/convert';
|
'angular2/src/render/dom/convert';
|
||||||
import {describe, expect, it} from 'angular2/test_lib';
|
import {ddescribe, describe, expect, it} from 'angular2/test_lib';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('convert', () => {
|
describe('convert', () => {
|
||||||
@ -12,6 +12,8 @@ export function main() {
|
|||||||
hostListeners: MapWrapper.createFromPairs([['listenKey', 'listenVal']]),
|
hostListeners: MapWrapper.createFromPairs([['listenKey', 'listenVal']]),
|
||||||
hostProperties:
|
hostProperties:
|
||||||
MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']]),
|
MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']]),
|
||||||
|
hostActions:
|
||||||
|
MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']]),
|
||||||
id: 'someComponent',
|
id: 'someComponent',
|
||||||
properties: MapWrapper.createFromPairs([['propKey', 'propVal']]),
|
properties: MapWrapper.createFromPairs([['propKey', 'propVal']]),
|
||||||
readAttributes: ['read1', 'read2'],
|
readAttributes: ['read1', 'read2'],
|
||||||
@ -24,6 +26,8 @@ export function main() {
|
|||||||
MapWrapper.createFromPairs([['listenKey', 'listenVal']]));
|
MapWrapper.createFromPairs([['listenKey', 'listenVal']]));
|
||||||
expect(MapWrapper.get(map, 'hostProperties')).toEqual(
|
expect(MapWrapper.get(map, 'hostProperties')).toEqual(
|
||||||
MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']]));
|
MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']]));
|
||||||
|
expect(MapWrapper.get(map, 'hostActions')).toEqual(
|
||||||
|
MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']]));
|
||||||
expect(MapWrapper.get(map, 'id')).toEqual('someComponent');
|
expect(MapWrapper.get(map, 'id')).toEqual('someComponent');
|
||||||
expect(MapWrapper.get(map, 'properties')).toEqual(
|
expect(MapWrapper.get(map, 'properties')).toEqual(
|
||||||
MapWrapper.createFromPairs([['propKey', 'propVal']]));
|
MapWrapper.createFromPairs([['propKey', 'propVal']]));
|
||||||
@ -39,6 +43,8 @@ export function main() {
|
|||||||
['hostListeners', MapWrapper.createFromPairs([['testKey', 'testVal']])],
|
['hostListeners', MapWrapper.createFromPairs([['testKey', 'testVal']])],
|
||||||
['hostProperties',
|
['hostProperties',
|
||||||
MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']])],
|
MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']])],
|
||||||
|
['hostActions',
|
||||||
|
MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']])],
|
||||||
['id', 'testId'],
|
['id', 'testId'],
|
||||||
['properties', MapWrapper.createFromPairs([['propKey', 'propVal']])],
|
['properties', MapWrapper.createFromPairs([['propKey', 'propVal']])],
|
||||||
['readAttributes', ['readTest1', 'readTest2']],
|
['readAttributes', ['readTest1', 'readTest2']],
|
||||||
@ -51,6 +57,8 @@ export function main() {
|
|||||||
MapWrapper.createFromPairs([['testKey', 'testVal']]));
|
MapWrapper.createFromPairs([['testKey', 'testVal']]));
|
||||||
expect(meta.hostProperties).toEqual(
|
expect(meta.hostProperties).toEqual(
|
||||||
MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']]));
|
MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']]));
|
||||||
|
expect(meta.hostActions).toEqual(
|
||||||
|
MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']]));
|
||||||
expect(meta.id).toEqual('testId');
|
expect(meta.id).toEqual('testId');
|
||||||
expect(meta.properties).toEqual(
|
expect(meta.properties).toEqual(
|
||||||
MapWrapper.createFromPairs([['propKey', 'propVal']]));
|
MapWrapper.createFromPairs([['propKey', 'propVal']]));
|
||||||
|
@ -96,6 +96,25 @@ export function main() {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should call actions on the element',
|
||||||
|
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
|
tb.compileAll([someComponent,
|
||||||
|
new ViewDefinition({
|
||||||
|
componentId: 'someComponent',
|
||||||
|
template: '<div with-host-actions></div>',
|
||||||
|
directives: [directiveWithHostActions]
|
||||||
|
})
|
||||||
|
]).then( (protoViewDtos) => {
|
||||||
|
var views = tb.createRootViews(protoViewDtos);
|
||||||
|
var componentView = views[1];
|
||||||
|
|
||||||
|
tb.renderer.callAction(componentView.viewRef, 0, 'setAttribute("key", "value")', null);
|
||||||
|
expect(DOM.getOuterHTML(tb.rootEl)).toContain('key="value"');
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
it('should add and remove views to and from containers',
|
it('should add and remove views to and from containers',
|
||||||
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
tb.compileAll([someComponent,
|
tb.compileAll([someComponent,
|
||||||
@ -152,3 +171,12 @@ var someComponent = new DirectiveMetadata({
|
|||||||
type: DirectiveMetadata.COMPONENT_TYPE,
|
type: DirectiveMetadata.COMPONENT_TYPE,
|
||||||
selector: 'some-comp'
|
selector: 'some-comp'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var directiveWithHostActions = new DirectiveMetadata({
|
||||||
|
id: 'withHostActions',
|
||||||
|
type: DirectiveMetadata.DIRECTIVE_TYPE,
|
||||||
|
selector: '[with-host-actions]',
|
||||||
|
hostActions: MapWrapper.createFromStringMap({
|
||||||
|
'setAttr' : 'setAttribute("key", "value")'
|
||||||
|
})
|
||||||
|
});
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
"hostListeners": {},
|
"hostListeners": {},
|
||||||
"hostProperties": {},
|
"hostProperties": {},
|
||||||
"hostAttributes": {},
|
"hostAttributes": {},
|
||||||
|
"hostActions": null,
|
||||||
"properties": {},
|
"properties": {},
|
||||||
"readAttributes": [],
|
"readAttributes": [],
|
||||||
"type": 1,
|
"type": 1,
|
||||||
|
Reference in New Issue
Block a user