parent
7c95cea3a8
commit
b96e560c8d
|
@ -367,6 +367,8 @@ export class Directive extends Injectable {
|
|||
* - `event1`: the DOM event that the directive listens to.
|
||||
* - `statement`: the statement to execute when the event occurs.
|
||||
*
|
||||
* To listen to global events, a target must be added to the event name.
|
||||
* The target can be `window`, `document` or `body`.
|
||||
*
|
||||
* When writing a directive event binding, you can also refer to the following local variables:
|
||||
* - `$event`: Current event object which triggered the event.
|
||||
|
@ -380,6 +382,7 @@ export class Directive extends Injectable {
|
|||
* @Directive({
|
||||
* hostListeners: {
|
||||
* 'event1': 'onMethod1(arguments)',
|
||||
* 'target:event2': 'onMethod2(arguments)',
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
|
@ -387,19 +390,22 @@ export class Directive extends Injectable {
|
|||
*
|
||||
* ## Basic Event Binding:
|
||||
*
|
||||
* Suppose you want to write a directive that triggers on `change` hostListeners in the DOM. You would define the event
|
||||
* binding as follows:
|
||||
* Suppose you want to write a directive that triggers on `change` events in the DOM and on `resize` events in window.
|
||||
* You would define the event binding as follows:
|
||||
*
|
||||
* ```
|
||||
* @Decorator({
|
||||
* selector: 'input',
|
||||
* hostListeners: {
|
||||
* 'change': 'onChange($event)'
|
||||
* 'change': 'onChange($event)',
|
||||
* 'window:resize': 'onResize($event)'
|
||||
* }
|
||||
* })
|
||||
* class InputDecorator {
|
||||
* onChange(event:Event) {
|
||||
* }
|
||||
* onResize(event:Event) {
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
|
|
|
@ -118,9 +118,7 @@ export class ProtoViewFactory {
|
|||
protoView.bindElementProperty(astWithSource.ast, propertyName);
|
||||
});
|
||||
// events
|
||||
MapWrapper.forEach(renderElementBinder.eventBindings, (astWithSource, eventName) => {
|
||||
protoView.bindEvent(eventName, astWithSource.ast, -1);
|
||||
});
|
||||
protoView.bindEvent(renderElementBinder.eventBindings, -1);
|
||||
// variables
|
||||
// The view's locals needs to have a full set of variable names at construction time
|
||||
// in order to prevent new variables from being set later in the lifecycle. Since we don't want
|
||||
|
@ -143,9 +141,7 @@ export class ProtoViewFactory {
|
|||
protoView.bindDirectiveProperty(i, astWithSource.ast, propertyName, setter);
|
||||
});
|
||||
// directive events
|
||||
MapWrapper.forEach(renderDirectiveMetadata.eventBindings, (astWithSource, eventName) => {
|
||||
protoView.bindEvent(eventName, astWithSource.ast, i);
|
||||
});
|
||||
protoView.bindEvent(renderDirectiveMetadata.eventBindings, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -272,7 +272,7 @@ export class AppView {
|
|||
var elBinder = this.proto.elementBinders[elementIndex];
|
||||
if (isBlank(elBinder.hostListeners)) return;
|
||||
var eventMap = elBinder.hostListeners[eventName];
|
||||
if (isBlank(eventName)) return;
|
||||
if (isBlank(eventMap)) return;
|
||||
MapWrapper.forEach(eventMap, (expr, directiveIndex) => {
|
||||
var context;
|
||||
if (directiveIndex === -1) {
|
||||
|
@ -407,19 +407,23 @@ export class AppProtoView {
|
|||
* @param {int} directiveIndex The directive index in the binder or -1 when the event is not bound
|
||||
* to a directive
|
||||
*/
|
||||
bindEvent(eventName:string, expression:AST, directiveIndex: int = -1) {
|
||||
bindEvent(eventBindings: List<renderApi.EventBinding>, directiveIndex: int = -1) {
|
||||
var elBinder = this.elementBinders[this.elementBinders.length - 1];
|
||||
var events = elBinder.hostListeners;
|
||||
if (isBlank(events)) {
|
||||
events = StringMapWrapper.create();
|
||||
elBinder.hostListeners = events;
|
||||
}
|
||||
var event = StringMapWrapper.get(events, eventName);
|
||||
if (isBlank(event)) {
|
||||
event = MapWrapper.create();
|
||||
StringMapWrapper.set(events, eventName, event);
|
||||
for (var i = 0; i < eventBindings.length; i++) {
|
||||
var eventBinding = eventBindings[i];
|
||||
var eventName = eventBinding.fullName;
|
||||
var event = StringMapWrapper.get(events, eventName);
|
||||
if (isBlank(event)) {
|
||||
event = MapWrapper.create();
|
||||
StringMapWrapper.set(events, eventName, event);
|
||||
}
|
||||
MapWrapper.set(event, directiveIndex, eventBinding.source);
|
||||
}
|
||||
MapWrapper.set(event, directiveIndex, expression);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -119,6 +119,12 @@ class BrowserDomAdapter extends GenericBrowserDomAdapter {
|
|||
// addEventListener misses zones so we use element.on.
|
||||
element.on[event].listen(callback);
|
||||
}
|
||||
Function onAndCancel(EventTarget element, String event, callback(arg)) {
|
||||
// due to https://code.google.com/p/dart/issues/detail?id=17406
|
||||
// addEventListener misses zones so we use element.on.
|
||||
var subscription = element.on[event].listen(callback);
|
||||
return subscription.cancel;
|
||||
}
|
||||
void dispatchEvent(EventTarget el, Event evt) {
|
||||
el.dispatchEvent(evt);
|
||||
}
|
||||
|
@ -288,4 +294,13 @@ class BrowserDomAdapter extends GenericBrowserDomAdapter {
|
|||
int keyCode = event.keyCode;
|
||||
return _keyCodeToKeyMap.containsKey(keyCode) ? _keyCodeToKeyMap[keyCode] : 'Unidentified';
|
||||
}
|
||||
getGlobalEventTarget(String target) {
|
||||
if (target == "window") {
|
||||
return window;
|
||||
} else if (target == "document") {
|
||||
return document;
|
||||
} else if (target == "body") {
|
||||
return document.body;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,6 +73,12 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter {
|
|||
on(el, evt, listener) {
|
||||
el.addEventListener(evt, listener, false);
|
||||
}
|
||||
onAndCancel(el, evt, listener): Function {
|
||||
el.addEventListener(evt, listener, false);
|
||||
//Needed to follow Dart's subscription semantic, until fix of
|
||||
//https://code.google.com/p/dart/issues/detail?id=17406
|
||||
return () => {el.removeEventListener(evt, listener, false);};
|
||||
}
|
||||
dispatchEvent(el, evt) {
|
||||
el.dispatchEvent(evt);
|
||||
}
|
||||
|
@ -353,4 +359,13 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter {
|
|||
}
|
||||
return key;
|
||||
}
|
||||
getGlobalEventTarget(target:string) {
|
||||
if (target == "window") {
|
||||
return window;
|
||||
} else if (target == "document") {
|
||||
return document;
|
||||
} else if (target == "body") {
|
||||
return document.body;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,9 @@ export class DomAdapter {
|
|||
on(el, evt, listener) {
|
||||
throw _abstract();
|
||||
}
|
||||
onAndCancel(el, evt, listener): Function {
|
||||
throw _abstract();
|
||||
}
|
||||
dispatchEvent(el, evt) {
|
||||
throw _abstract();
|
||||
}
|
||||
|
@ -273,4 +276,7 @@ export class DomAdapter {
|
|||
supportsNativeShadowDOM(): boolean {
|
||||
throw _abstract();
|
||||
}
|
||||
getGlobalEventTarget(target:string) {
|
||||
throw _abstract();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ class Html5LibDomAdapter implements DomAdapter {
|
|||
on(el, evt, listener) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
Function onAndCancel(el, evt, listener) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
dispatchEvent(el, evt) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
|
|
@ -86,6 +86,9 @@ export class Parse5DomAdapter extends DomAdapter {
|
|||
on(el, evt, listener) {
|
||||
//Do nothing, in order to not break forms integration tests
|
||||
}
|
||||
onAndCancel(el, evt, listener): Function {
|
||||
//Do nothing, in order to not break forms integration tests
|
||||
}
|
||||
dispatchEvent(el, evt) {
|
||||
throw _notImplemented('dispatchEvent');
|
||||
}
|
||||
|
|
|
@ -10,6 +10,6 @@ export class MockVmTurnZone extends VmTurnZone {
|
|||
}
|
||||
|
||||
runOutsideAngular(fn) {
|
||||
fn();
|
||||
return fn();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,16 @@ import {ASTWithSource} from 'angular2/change_detection';
|
|||
* - render compiler is not on the critical path as
|
||||
* its output will be stored in precompiled templates.
|
||||
*/
|
||||
export class EventBinding {
|
||||
fullName: string; // name/target:name, e.g "click", "window:resize"
|
||||
source: ASTWithSource;
|
||||
|
||||
constructor(fullName :string, source: ASTWithSource) {
|
||||
this.fullName = fullName;
|
||||
this.source = source;
|
||||
}
|
||||
}
|
||||
|
||||
export class ElementBinder {
|
||||
index:number;
|
||||
parentIndex:number;
|
||||
|
@ -26,7 +36,7 @@ export class ElementBinder {
|
|||
// Note: this contains a preprocessed AST
|
||||
// that replaced the values that should be extracted from the element
|
||||
// with a local name
|
||||
eventBindings: Map<string, ASTWithSource>;
|
||||
eventBindings: List<EventBinding>;
|
||||
textBindings: List<ASTWithSource>;
|
||||
readAttributes: Map<string, string>;
|
||||
|
||||
|
@ -57,7 +67,7 @@ export class DirectiveBinder {
|
|||
// Note: this contains a preprocessed AST
|
||||
// that replaced the values that should be extracted from the element
|
||||
// with a local name
|
||||
eventBindings: Map<string, ASTWithSource>;
|
||||
eventBindings: List<EventBinding>;
|
||||
constructor({
|
||||
directiveIndex, propertyBindings, eventBindings
|
||||
}) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {isPresent, isBlank, BaseException, assertionsEnabled, RegExpWrapper} from 'angular2/src/facade/lang';
|
||||
import {isPresent, isBlank, BaseException, assertionsEnabled, RegExpWrapper, StringWrapper} from 'angular2/src/facade/lang';
|
||||
import {List, MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {Parser} from 'angular2/change_detection';
|
||||
|
@ -10,7 +10,7 @@ import {CompileElement} from './compile_element';
|
|||
import {CompileControl} from './compile_control';
|
||||
|
||||
import {DirectiveMetadata} from '../../api';
|
||||
import {dashCaseToCamelCase, camelCaseToDashCase} from '../util';
|
||||
import {dashCaseToCamelCase, camelCaseToDashCase, EVENT_TARGET_SEPARATOR} from '../util';
|
||||
|
||||
/**
|
||||
* Parses the directives on a single element. Assumes ViewSplitter has already created
|
||||
|
@ -132,7 +132,13 @@ export class DirectiveParser extends CompileStep {
|
|||
|
||||
_bindDirectiveEvent(eventName, action, compileElement, directiveBinder) {
|
||||
var ast = this._parser.parseAction(action, compileElement.elementDescription);
|
||||
directiveBinder.bindEvent(eventName, ast);
|
||||
if (StringWrapper.contains(eventName, EVENT_TARGET_SEPARATOR)) {
|
||||
var parts = eventName.split(EVENT_TARGET_SEPARATOR);
|
||||
directiveBinder.bindEvent(parts[1], ast, parts[0]);
|
||||
} else {
|
||||
directiveBinder.bindEvent(eventName, ast);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_splitBindConfig(bindConfig:string) {
|
||||
|
|
|
@ -18,13 +18,15 @@ export class EventManager {
|
|||
}
|
||||
|
||||
addEventListener(element, eventName: string, handler: Function) {
|
||||
var shouldSupportBubble = eventName[0] == BUBBLE_SYMBOL;
|
||||
if (shouldSupportBubble) {
|
||||
eventName = StringWrapper.substring(eventName, 1);
|
||||
}
|
||||
var withoutBubbleSymbol = this._removeBubbleSymbol(eventName);
|
||||
var plugin = this._findPluginFor(withoutBubbleSymbol);
|
||||
plugin.addEventListener(element, withoutBubbleSymbol, handler, withoutBubbleSymbol != eventName);
|
||||
}
|
||||
|
||||
var plugin = this._findPluginFor(eventName);
|
||||
plugin.addEventListener(element, eventName, handler, shouldSupportBubble);
|
||||
addGlobalEventListener(target: string, eventName: string, handler: Function): Function {
|
||||
var withoutBubbleSymbol = this._removeBubbleSymbol(eventName);
|
||||
var plugin = this._findPluginFor(withoutBubbleSymbol);
|
||||
return plugin.addGlobalEventListener(target, withoutBubbleSymbol, handler, withoutBubbleSymbol != eventName);
|
||||
}
|
||||
|
||||
getZone(): VmTurnZone {
|
||||
|
@ -41,6 +43,10 @@ export class EventManager {
|
|||
}
|
||||
throw new BaseException(`No event manager plugin found for event ${eventName}`);
|
||||
}
|
||||
|
||||
_removeBubbleSymbol(eventName: string): string {
|
||||
return eventName[0] == BUBBLE_SYMBOL ? StringWrapper.substring(eventName, 1) : eventName;
|
||||
}
|
||||
}
|
||||
|
||||
export class EventManagerPlugin {
|
||||
|
@ -54,8 +60,11 @@ export class EventManagerPlugin {
|
|||
return false;
|
||||
}
|
||||
|
||||
addEventListener(element, eventName: string, handler: Function,
|
||||
shouldSupportBubble: boolean) {
|
||||
addEventListener(element, eventName: string, handler: Function, shouldSupportBubble: boolean) {
|
||||
throw "not implemented";
|
||||
}
|
||||
|
||||
addGlobalEventListener(element, eventName: string, handler: Function, shouldSupportBubble: boolean): Function {
|
||||
throw "not implemented";
|
||||
}
|
||||
}
|
||||
|
@ -69,17 +78,27 @@ export class DomEventsPlugin extends EventManagerPlugin {
|
|||
return true;
|
||||
}
|
||||
|
||||
addEventListener(element, eventName: string, handler: Function,
|
||||
shouldSupportBubble: boolean) {
|
||||
var outsideHandler = shouldSupportBubble ?
|
||||
DomEventsPlugin.bubbleCallback(element, handler, this.manager._zone) :
|
||||
DomEventsPlugin.sameElementCallback(element, handler, this.manager._zone);
|
||||
|
||||
addEventListener(element, eventName: string, handler: Function, shouldSupportBubble: boolean) {
|
||||
var outsideHandler = this._getOutsideHandler(shouldSupportBubble, element, handler, this.manager._zone);
|
||||
this.manager._zone.runOutsideAngular(() => {
|
||||
DOM.on(element, eventName, outsideHandler);
|
||||
});
|
||||
}
|
||||
|
||||
addGlobalEventListener(target:string, eventName: string, handler: Function, shouldSupportBubble: boolean): Function {
|
||||
var element = DOM.getGlobalEventTarget(target);
|
||||
var outsideHandler = this._getOutsideHandler(shouldSupportBubble, element, handler, this.manager._zone);
|
||||
return this.manager._zone.runOutsideAngular(() => {
|
||||
return DOM.onAndCancel(element, eventName, outsideHandler);
|
||||
});
|
||||
}
|
||||
|
||||
_getOutsideHandler(shouldSupportBubble: boolean, element, handler: Function, zone: VmTurnZone) {
|
||||
return shouldSupportBubble ?
|
||||
DomEventsPlugin.bubbleCallback(element, handler, zone) :
|
||||
DomEventsPlugin.sameElementCallback(element, handler, zone);
|
||||
}
|
||||
|
||||
static sameElementCallback(element, handler, zone) {
|
||||
return (event) => {
|
||||
if (event.target === element) {
|
||||
|
|
|
@ -3,6 +3,8 @@ import {StringWrapper, RegExpWrapper, isPresent} from 'angular2/src/facade/lang'
|
|||
export const NG_BINDING_CLASS_SELECTOR = '.ng-binding';
|
||||
export const NG_BINDING_CLASS = 'ng-binding';
|
||||
|
||||
export const EVENT_TARGET_SEPARATOR = ':';
|
||||
|
||||
var CAMEL_CASE_REGEXP = RegExpWrapper.create('([A-Z])');
|
||||
var DASH_CASE_REGEXP = RegExpWrapper.create('-([a-z])');
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@ export class ElementBinder {
|
|||
textNodeIndices: List<number>;
|
||||
nestedProtoView: protoViewModule.RenderProtoView;
|
||||
eventLocals: AST;
|
||||
eventNames: List<string>;
|
||||
localEvents: List<Event>;
|
||||
globalEvents: List<Event>;
|
||||
componentId: string;
|
||||
parentIndex:number;
|
||||
distanceToParent:number;
|
||||
|
@ -20,7 +21,8 @@ export class ElementBinder {
|
|||
nestedProtoView,
|
||||
componentId,
|
||||
eventLocals,
|
||||
eventNames,
|
||||
localEvents,
|
||||
globalEvents,
|
||||
parentIndex,
|
||||
distanceToParent,
|
||||
propertySetters
|
||||
|
@ -30,9 +32,22 @@ export class ElementBinder {
|
|||
this.nestedProtoView = nestedProtoView;
|
||||
this.componentId = componentId;
|
||||
this.eventLocals = eventLocals;
|
||||
this.eventNames = eventNames;
|
||||
this.localEvents = localEvents;
|
||||
this.globalEvents = globalEvents;
|
||||
this.parentIndex = parentIndex;
|
||||
this.distanceToParent = distanceToParent;
|
||||
this.propertySetters = propertySetters;
|
||||
}
|
||||
}
|
||||
|
||||
export class Event {
|
||||
name: string;
|
||||
target: string;
|
||||
fullName: string;
|
||||
|
||||
constructor(name: string, target: string, fullName: string) {
|
||||
this.name = name;
|
||||
this.target = target;
|
||||
this.fullName = fullName;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
||||
import {ListWrapper, MapWrapper, Set, SetWrapper} from 'angular2/src/facade/collection';
|
||||
import {ListWrapper, MapWrapper, Set, SetWrapper, List} from 'angular2/src/facade/collection';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
|
||||
import {
|
||||
|
@ -8,13 +8,13 @@ import {
|
|||
import {SetterFn} from 'angular2/src/reflection/types';
|
||||
|
||||
import {RenderProtoView} from './proto_view';
|
||||
import {ElementBinder} from './element_binder';
|
||||
import {ElementBinder, Event} from './element_binder';
|
||||
import {setterFactory} from './property_setter_factory';
|
||||
|
||||
import * as api from '../../api';
|
||||
import * as directDomRenderer from '../direct_dom_renderer';
|
||||
|
||||
import {NG_BINDING_CLASS} from '../util';
|
||||
import {NG_BINDING_CLASS, EVENT_TARGET_SEPARATOR} from '../util';
|
||||
|
||||
export class ProtoViewBuilder {
|
||||
rootElement;
|
||||
|
@ -56,12 +56,12 @@ export class ProtoViewBuilder {
|
|||
var apiElementBinders = [];
|
||||
ListWrapper.forEach(this.elements, (ebb) => {
|
||||
var propertySetters = MapWrapper.create();
|
||||
var eventLocalsAstSplitter = new EventLocalsAstSplitter();
|
||||
var apiDirectiveBinders = ListWrapper.map(ebb.directives, (db) => {
|
||||
ebb.eventBuilder.merge(db.eventBuilder);
|
||||
return new api.DirectiveBinder({
|
||||
directiveIndex: db.directiveIndex,
|
||||
propertyBindings: db.propertyBindings,
|
||||
eventBindings: eventLocalsAstSplitter.splitEventAstIntoLocals(db.eventBindings)
|
||||
eventBindings: db.eventBindings
|
||||
});
|
||||
});
|
||||
MapWrapper.forEach(ebb.propertySetters, (setter, propertyName) => {
|
||||
|
@ -75,7 +75,7 @@ export class ProtoViewBuilder {
|
|||
directives: apiDirectiveBinders,
|
||||
nestedProtoView: nestedProtoView,
|
||||
propertyBindings: ebb.propertyBindings, variableBindings: ebb.variableBindings,
|
||||
eventBindings: eventLocalsAstSplitter.splitEventAstIntoLocals(ebb.eventBindings),
|
||||
eventBindings: ebb.eventBindings,
|
||||
textBindings: ebb.textBindings,
|
||||
readAttributes: ebb.readAttributes
|
||||
}));
|
||||
|
@ -86,8 +86,9 @@ export class ProtoViewBuilder {
|
|||
distanceToParent: ebb.distanceToParent,
|
||||
nestedProtoView: isPresent(nestedProtoView) ? nestedProtoView.render.delegate : null,
|
||||
componentId: ebb.componentId,
|
||||
eventLocals: eventLocalsAstSplitter.buildEventLocals(),
|
||||
eventNames: eventLocalsAstSplitter.buildEventNames(),
|
||||
eventLocals: new LiteralArray(ebb.eventBuilder.buildEventLocals()),
|
||||
localEvents: ebb.eventBuilder.buildLocalEvents(),
|
||||
globalEvents: ebb.eventBuilder.buildGlobalEvents(),
|
||||
propertySetters: propertySetters
|
||||
}));
|
||||
});
|
||||
|
@ -112,7 +113,8 @@ export class ElementBinderBuilder {
|
|||
nestedProtoView:ProtoViewBuilder;
|
||||
propertyBindings: Map<string, ASTWithSource>;
|
||||
variableBindings: Map<string, string>;
|
||||
eventBindings: Map<string, ASTWithSource>;
|
||||
eventBindings: List<api.EventBinding>;
|
||||
eventBuilder: EventBuilder;
|
||||
textBindingIndices: List<number>;
|
||||
textBindings: List<ASTWithSource>;
|
||||
contentTagSelector:string;
|
||||
|
@ -129,7 +131,8 @@ export class ElementBinderBuilder {
|
|||
this.nestedProtoView = null;
|
||||
this.propertyBindings = MapWrapper.create();
|
||||
this.variableBindings = MapWrapper.create();
|
||||
this.eventBindings = MapWrapper.create();
|
||||
this.eventBindings = ListWrapper.create();
|
||||
this.eventBuilder = new EventBuilder();
|
||||
this.textBindings = [];
|
||||
this.textBindingIndices = [];
|
||||
this.contentTagSelector = null;
|
||||
|
@ -191,8 +194,8 @@ export class ElementBinderBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
bindEvent(name, expression) {
|
||||
MapWrapper.set(this.eventBindings, name, expression);
|
||||
bindEvent(name, expression, target = null) {
|
||||
ListWrapper.push(this.eventBindings, this.eventBuilder.add(name, expression, target));
|
||||
}
|
||||
|
||||
bindText(index, expression) {
|
||||
|
@ -212,49 +215,53 @@ export class ElementBinderBuilder {
|
|||
export class DirectiveBuilder {
|
||||
directiveIndex:number;
|
||||
propertyBindings: Map<string, ASTWithSource>;
|
||||
eventBindings: Map<string, ASTWithSource>;
|
||||
eventBindings: List<api.EventBinding>;
|
||||
eventBuilder: EventBuilder;
|
||||
|
||||
constructor(directiveIndex) {
|
||||
this.directiveIndex = directiveIndex;
|
||||
this.propertyBindings = MapWrapper.create();
|
||||
this.eventBindings = MapWrapper.create();
|
||||
this.eventBindings = ListWrapper.create();
|
||||
this.eventBuilder = new EventBuilder();
|
||||
}
|
||||
|
||||
bindProperty(name, expression) {
|
||||
MapWrapper.set(this.propertyBindings, name, expression);
|
||||
}
|
||||
|
||||
bindEvent(name, expression) {
|
||||
MapWrapper.set(this.eventBindings, name, expression);
|
||||
bindEvent(name, expression, target = null) {
|
||||
ListWrapper.push(this.eventBindings, this.eventBuilder.add(name, expression, target));
|
||||
}
|
||||
}
|
||||
|
||||
export class EventLocalsAstSplitter extends AstTransformer {
|
||||
locals:List<AST>;
|
||||
eventNames:List<string>;
|
||||
_implicitReceiver:AST;
|
||||
export class EventBuilder extends AstTransformer {
|
||||
locals: List<AST>;
|
||||
localEvents: List<Event>;
|
||||
globalEvents: List<Event>;
|
||||
_implicitReceiver: AST;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.locals = [];
|
||||
this.eventNames = [];
|
||||
this.localEvents = [];
|
||||
this.globalEvents = [];
|
||||
this._implicitReceiver = new ImplicitReceiver();
|
||||
}
|
||||
|
||||
splitEventAstIntoLocals(eventBindings:Map<string, ASTWithSource>):Map<string, ASTWithSource> {
|
||||
if (isPresent(eventBindings)) {
|
||||
var result = MapWrapper.create();
|
||||
MapWrapper.forEach(eventBindings, (astWithSource, eventName) => {
|
||||
// TODO(tbosch): reenable this when we are parsing element properties
|
||||
// out of action expressions
|
||||
// var adjustedAst = astWithSource.ast.visit(this);
|
||||
var adjustedAst = astWithSource.ast;
|
||||
MapWrapper.set(result, eventName, new ASTWithSource(adjustedAst, astWithSource.source, ''));
|
||||
ListWrapper.push(this.eventNames, eventName);
|
||||
});
|
||||
return result;
|
||||
add(name: string, source: ASTWithSource, target: string): api.EventBinding {
|
||||
// TODO(tbosch): reenable this when we are parsing element properties
|
||||
// out of action expressions
|
||||
// var adjustedAst = astWithSource.ast.visit(this);
|
||||
var adjustedAst = source.ast;
|
||||
var fullName = isPresent(target) ? target + EVENT_TARGET_SEPARATOR + name : name;
|
||||
var result = new api.EventBinding(fullName, new ASTWithSource(adjustedAst, source.source, ''));
|
||||
var event = new Event(name, target, fullName);
|
||||
if (isBlank(target)) {
|
||||
ListWrapper.push(this.localEvents, event);
|
||||
} else {
|
||||
ListWrapper.push(this.globalEvents, event);
|
||||
}
|
||||
return null;
|
||||
return result;
|
||||
}
|
||||
|
||||
visitAccessMember(ast:AccessMember) {
|
||||
|
@ -277,10 +284,32 @@ export class EventLocalsAstSplitter extends AstTransformer {
|
|||
}
|
||||
|
||||
buildEventLocals() {
|
||||
return new LiteralArray(this.locals);
|
||||
return this.locals;
|
||||
}
|
||||
|
||||
buildEventNames() {
|
||||
return this.eventNames;
|
||||
buildLocalEvents() {
|
||||
return this.localEvents;
|
||||
}
|
||||
|
||||
buildGlobalEvents() {
|
||||
return this.globalEvents;
|
||||
}
|
||||
|
||||
merge(eventBuilder: EventBuilder) {
|
||||
this._merge(this.localEvents, eventBuilder.localEvents);
|
||||
this._merge(this.globalEvents, eventBuilder.globalEvents);
|
||||
ListWrapper.concat(this.locals, eventBuilder.locals);
|
||||
}
|
||||
|
||||
_merge(host: List<Event>, tobeAdded: List<Event>) {
|
||||
var names = ListWrapper.create();
|
||||
for (var i = 0; i < host.length; i++) {
|
||||
ListWrapper.push(names, host[i].fullName);
|
||||
}
|
||||
for (var j = 0; j < tobeAdded.length; j++) {
|
||||
if (!ListWrapper.contains(names, tobeAdded[j].fullName)) {
|
||||
ListWrapper.push(host, tobeAdded[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import {ViewContainer} from './view_container';
|
|||
import {RenderProtoView} from './proto_view';
|
||||
import {LightDom} from '../shadow_dom/light_dom';
|
||||
import {Content} from '../shadow_dom/content_tag';
|
||||
import {EventManager} from 'angular2/src/render/dom/events/event_manager';
|
||||
|
||||
import {ShadowDomStrategy} from '../shadow_dom/shadow_dom_strategy';
|
||||
|
||||
|
@ -29,12 +30,14 @@ export class RenderView {
|
|||
contentTags: List<Content>;
|
||||
lightDoms: List<LightDom>;
|
||||
proto: RenderProtoView;
|
||||
eventManager: EventManager;
|
||||
_hydrated: boolean;
|
||||
_eventDispatcher: any/*EventDispatcher*/;
|
||||
_eventHandlerRemovers: List<Function>;
|
||||
|
||||
constructor(
|
||||
proto:RenderProtoView, rootNodes:List,
|
||||
boundTextNodes: List, boundElements:List, viewContainers:List, contentTags:List) {
|
||||
boundTextNodes: List, boundElements:List, viewContainers:List, contentTags:List, eventManager: EventManager) {
|
||||
this.proto = proto;
|
||||
this.rootNodes = rootNodes;
|
||||
this.boundTextNodes = boundTextNodes;
|
||||
|
@ -42,9 +45,11 @@ export class RenderView {
|
|||
this.viewContainers = viewContainers;
|
||||
this.contentTags = contentTags;
|
||||
this.lightDoms = ListWrapper.createFixedSize(boundElements.length);
|
||||
this.eventManager = eventManager;
|
||||
ListWrapper.fill(this.lightDoms, null);
|
||||
this.componentChildViews = ListWrapper.createFixedSize(boundElements.length);
|
||||
this._hydrated = false;
|
||||
this._eventHandlerRemovers = null;
|
||||
}
|
||||
|
||||
hydrated() {
|
||||
|
@ -130,6 +135,26 @@ export class RenderView {
|
|||
lightDom.redistribute();
|
||||
}
|
||||
}
|
||||
|
||||
//add global events
|
||||
this._eventHandlerRemovers = ListWrapper.create();
|
||||
var binders = this.proto.elementBinders;
|
||||
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
||||
var binder = binders[binderIdx];
|
||||
if (isPresent(binder.globalEvents)) {
|
||||
for (var i = 0; i < binder.globalEvents.length; i++) {
|
||||
var globalEvent = binder.globalEvents[i];
|
||||
var remover = this._createGlobalEventListener(binderIdx, globalEvent.name, globalEvent.target, globalEvent.fullName);
|
||||
ListWrapper.push(this._eventHandlerRemovers, remover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_createGlobalEventListener(elementIndex, eventName, eventTarget, fullName): Function {
|
||||
return this.eventManager.addGlobalEventListener(eventTarget, eventName, (event) => {
|
||||
this.dispatchEvent(elementIndex, fullName, event);
|
||||
});
|
||||
}
|
||||
|
||||
dehydrate() {
|
||||
|
@ -156,6 +181,13 @@ export class RenderView {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
//remove global events
|
||||
for (var i = 0; i < this._eventHandlerRemovers.length; i++) {
|
||||
this._eventHandlerRemovers[i]();
|
||||
}
|
||||
|
||||
this._eventHandlerRemovers = null;
|
||||
this._eventDispatcher = null;
|
||||
this._hydrated = false;
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ export class ViewFactory {
|
|||
|
||||
var view = new viewModule.RenderView(
|
||||
protoView, viewRootNodes,
|
||||
boundTextNodes, boundElements, viewContainers, contentTags
|
||||
boundTextNodes, boundElements, viewContainers, contentTags, this._eventManager
|
||||
);
|
||||
|
||||
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
||||
|
@ -139,10 +139,10 @@ export class ViewFactory {
|
|||
}
|
||||
|
||||
// events
|
||||
if (isPresent(binder.eventLocals)) {
|
||||
ListWrapper.forEach(binder.eventNames, (eventName) => {
|
||||
this._createEventListener(view, element, binderIdx, eventName, binder.eventLocals);
|
||||
});
|
||||
if (isPresent(binder.eventLocals) && isPresent(binder.localEvents)) {
|
||||
for (var i = 0; i < binder.localEvents.length; i++) {
|
||||
this._createEventListener(view, element, binderIdx, binder.localEvents[i].name, binder.eventLocals);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,7 @@ import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
|||
import {NgElement} from 'angular2/src/core/compiler/ng_element';
|
||||
import {Directive} from 'angular2/src/core/annotations/annotations';
|
||||
import {BindingPropagationConfig, Parser, Lexer} from 'angular2/change_detection';
|
||||
|
||||
import {ViewRef, Renderer} from 'angular2/src/render/api';
|
||||
import {ViewRef, Renderer, EventBinding} from 'angular2/src/render/api';
|
||||
import {QueryList} from 'angular2/src/core/compiler/query_list';
|
||||
|
||||
class DummyDirective extends Directive {
|
||||
|
@ -701,7 +700,9 @@ export function main() {
|
|||
StringMapWrapper.set(handlers, eventName, eventHandler);
|
||||
var pv = new AppProtoView(null, null, null);
|
||||
pv.bindElement(null, 0, null, null, null);
|
||||
pv.bindEvent(eventName, new Parser(new Lexer()).parseAction('handler()', ''));
|
||||
var eventBindings = ListWrapper.create();
|
||||
ListWrapper.push(eventBindings, new EventBinding(eventName, new Parser(new Lexer()).parseAction('handler()', '')));
|
||||
pv.bindEvent(eventBindings);
|
||||
|
||||
var view = new AppView(pv, MapWrapper.create());
|
||||
view.context = new ContextWithHandler(eventHandler);
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
import {TestBed} from 'angular2/src/test_lib/test_bed';
|
||||
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {Type, isPresent, BaseException, assertionsEnabled, isJsObject} from 'angular2/src/facade/lang';
|
||||
import {Type, isPresent, BaseException, assertionsEnabled, isJsObject, global} from 'angular2/src/facade/lang';
|
||||
import {PromiseWrapper} from 'angular2/src/facade/async';
|
||||
|
||||
import {Injector, bind} from 'angular2/di';
|
||||
|
@ -541,6 +541,66 @@ export function main() {
|
|||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should support render global events', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideView(MyComp, new View({
|
||||
template: '<div listener></div>',
|
||||
directives: [DecoratorListeningDomEvent]
|
||||
}));
|
||||
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
var injector = view.rawView.elementInjectors[0];
|
||||
|
||||
var listener = injector.get(DecoratorListeningDomEvent);
|
||||
dispatchEvent(DOM.getGlobalEventTarget("window"), 'domEvent');
|
||||
expect(listener.eventType).toEqual('window_domEvent');
|
||||
|
||||
listener = injector.get(DecoratorListeningDomEvent);
|
||||
dispatchEvent(DOM.getGlobalEventTarget("document"), 'domEvent');
|
||||
expect(listener.eventType).toEqual('document_domEvent');
|
||||
|
||||
view.rawView.dehydrate();
|
||||
listener = injector.get(DecoratorListeningDomEvent);
|
||||
dispatchEvent(DOM.getGlobalEventTarget("body"), 'domEvent');
|
||||
expect(listener.eventType).toEqual('');
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should support render global events from multiple directives', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideView(MyComp, new View({
|
||||
template: '<div *if="ctxBoolProp" listener listenerother></div>',
|
||||
directives: [If, DecoratorListeningDomEvent, DecoratorListeningDomEventOther]
|
||||
}));
|
||||
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
globalCounter = 0;
|
||||
ctx.ctxBoolProp = true;
|
||||
view.detectChanges();
|
||||
|
||||
var subview = view.rawView.viewContainers[0].get(0);
|
||||
var injector = subview.elementInjectors[0];
|
||||
var listener = injector.get(DecoratorListeningDomEvent);
|
||||
var listenerother = injector.get(DecoratorListeningDomEventOther);
|
||||
dispatchEvent(DOM.getGlobalEventTarget("window"), 'domEvent');
|
||||
expect(listener.eventType).toEqual('window_domEvent');
|
||||
expect(listenerother.eventType).toEqual('other_domEvent');
|
||||
expect(globalCounter).toEqual(1);
|
||||
|
||||
ctx.ctxBoolProp = false;
|
||||
view.detectChanges();
|
||||
dispatchEvent(DOM.getGlobalEventTarget("window"), 'domEvent');
|
||||
expect(globalCounter).toEqual(1);
|
||||
|
||||
ctx.ctxBoolProp = true;
|
||||
view.detectChanges();
|
||||
dispatchEvent(DOM.getGlobalEventTarget("window"), 'domEvent');
|
||||
expect(globalCounter).toEqual(2);
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
describe("dynamic components", () => {
|
||||
|
@ -894,18 +954,49 @@ class DecoratorListeningEvent {
|
|||
|
||||
@Decorator({
|
||||
selector: '[listener]',
|
||||
hostListeners: {'domEvent': 'onEvent($event.type)'}
|
||||
hostListeners: {
|
||||
'domEvent': 'onEvent($event.type)',
|
||||
'window:domEvent': 'onWindowEvent($event.type)',
|
||||
'document:domEvent': 'onDocumentEvent($event.type)',
|
||||
'body:domEvent': 'onBodyEvent($event.type)'
|
||||
}
|
||||
})
|
||||
class DecoratorListeningDomEvent {
|
||||
eventType: string;
|
||||
|
||||
constructor() {
|
||||
this.eventType = '';
|
||||
}
|
||||
|
||||
onEvent(eventType: string) {
|
||||
this.eventType = eventType;
|
||||
}
|
||||
onWindowEvent(eventType: string) {
|
||||
this.eventType = "window_" + eventType;
|
||||
}
|
||||
onDocumentEvent(eventType: string) {
|
||||
this.eventType = "document_" + eventType;
|
||||
}
|
||||
onBodyEvent(eventType: string) {
|
||||
this.eventType = "body_" + eventType;
|
||||
}
|
||||
}
|
||||
|
||||
var globalCounter = 0;
|
||||
@Decorator({
|
||||
selector: '[listenerother]',
|
||||
hostListeners: {
|
||||
'window:domEvent': 'onEvent($event.type)'
|
||||
}
|
||||
})
|
||||
class DecoratorListeningDomEventOther {
|
||||
eventType: string;
|
||||
counter: int;
|
||||
constructor() {
|
||||
this.eventType = '';
|
||||
}
|
||||
onEvent(eventType: string) {
|
||||
globalCounter++;
|
||||
this.eventType = "other_" + eventType;
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
|
|
|
@ -23,7 +23,8 @@ export function main() {
|
|||
someDecorator,
|
||||
someDecoratorIgnoringChildren,
|
||||
someDecoratorWithProps,
|
||||
someDecoratorWithEvents
|
||||
someDecoratorWithEvents,
|
||||
someDecoratorWithGlobalEvents
|
||||
];
|
||||
parser = new Parser(new Lexer());
|
||||
});
|
||||
|
@ -130,8 +131,21 @@ export function main() {
|
|||
el('<div some-decor-events></div>')
|
||||
);
|
||||
var directiveBinding = results[0].directives[0];
|
||||
expect(MapWrapper.get(directiveBinding.eventBindings, 'click').source)
|
||||
.toEqual('doIt()');
|
||||
expect(directiveBinding.eventBindings.length).toEqual(1);
|
||||
var eventBinding = directiveBinding.eventBindings[0];
|
||||
expect(eventBinding.fullName).toEqual('click');
|
||||
expect(eventBinding.source.source).toEqual('doIt()');
|
||||
});
|
||||
|
||||
it('should bind directive global events', () => {
|
||||
var results = process(
|
||||
el('<div some-decor-globalevents></div>')
|
||||
);
|
||||
var directiveBinding = results[0].directives[0];
|
||||
expect(directiveBinding.eventBindings.length).toEqual(1);
|
||||
var eventBinding = directiveBinding.eventBindings[0];
|
||||
expect(eventBinding.fullName).toEqual('window:resize');
|
||||
expect(eventBinding.source.source).toEqual('doItGlobal()');
|
||||
});
|
||||
|
||||
describe('viewport directives', () => {
|
||||
|
@ -246,3 +260,10 @@ var someDecoratorWithEvents = new DirectiveMetadata({
|
|||
'click': 'doIt()'
|
||||
})
|
||||
});
|
||||
|
||||
var someDecoratorWithGlobalEvents = new DirectiveMetadata({
|
||||
selector: '[some-decor-globalevents]',
|
||||
hostListeners: MapWrapper.createFromStringMap({
|
||||
'window:resize': 'doItGlobal()'
|
||||
})
|
||||
});
|
||||
|
|
|
@ -96,10 +96,14 @@ export function main() {
|
|||
|
||||
it('should detect () syntax', () => {
|
||||
var results = process(el('<div (click)="b()"></div>'));
|
||||
expect(MapWrapper.get(results[0].eventBindings, 'click').source).toEqual('b()');
|
||||
var eventBinding = results[0].eventBindings[0];
|
||||
expect(eventBinding.source.source).toEqual('b()');
|
||||
expect(eventBinding.fullName).toEqual('click');
|
||||
// "(click[])" is not an expected syntax and is only used to validate the regexp
|
||||
results = process(el('<div (click[])="b()"></div>'));
|
||||
expect(MapWrapper.get(results[0].eventBindings, 'click[]').source).toEqual('b()');
|
||||
eventBinding = results[0].eventBindings[0];
|
||||
expect(eventBinding.source.source).toEqual('b()');
|
||||
expect(eventBinding.fullName).toEqual('click[]');
|
||||
});
|
||||
|
||||
it('should detect () syntax only if an attribute name starts and ends with ()', () => {
|
||||
|
@ -109,17 +113,23 @@ export function main() {
|
|||
|
||||
it('should parse event handlers using () syntax as actions', () => {
|
||||
var results = process(el('<div (click)="foo=bar"></div>'));
|
||||
expect(MapWrapper.get(results[0].eventBindings, 'click').source).toEqual('foo=bar');
|
||||
var eventBinding = results[0].eventBindings[0];
|
||||
expect(eventBinding.source.source).toEqual('foo=bar');
|
||||
expect(eventBinding.fullName).toEqual('click');
|
||||
});
|
||||
|
||||
it('should detect on- syntax', () => {
|
||||
var results = process(el('<div on-click="b()"></div>'));
|
||||
expect(MapWrapper.get(results[0].eventBindings, 'click').source).toEqual('b()');
|
||||
var eventBinding = results[0].eventBindings[0];
|
||||
expect(eventBinding.source.source).toEqual('b()');
|
||||
expect(eventBinding.fullName).toEqual('click');
|
||||
});
|
||||
|
||||
it('should parse event handlers using on- syntax as actions', () => {
|
||||
var results = process(el('<div on-click="foo=bar"></div>'));
|
||||
expect(MapWrapper.get(results[0].eventBindings, 'click').source).toEqual('foo=bar');
|
||||
var eventBinding = results[0].eventBindings[0];
|
||||
expect(eventBinding.source.source).toEqual('foo=bar');
|
||||
expect(eventBinding.fullName).toEqual('click');
|
||||
});
|
||||
|
||||
it('should store bound properties as temporal attributes', () => {
|
||||
|
|
|
@ -83,6 +83,28 @@ export function main() {
|
|||
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
});
|
||||
|
||||
it('should add and remove global event listeners with correct bubbling', () => {
|
||||
var element = el('<div><div></div></div>');
|
||||
DOM.appendChild(document.body, element);
|
||||
var dispatchedEvent = DOM.createMouseEvent('click');
|
||||
var receivedEvent = null;
|
||||
var handler = (e) => { receivedEvent = e; };
|
||||
var manager = new EventManager([domEventPlugin], new FakeVmTurnZone());
|
||||
|
||||
var remover = manager.addGlobalEventListener("document", '^click', handler);
|
||||
DOM.dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
|
||||
receivedEvent = null;
|
||||
remover();
|
||||
DOM.dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(null);
|
||||
|
||||
remover = manager.addGlobalEventListener("document", 'click', handler);
|
||||
DOM.dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -104,6 +126,8 @@ class FakeEventManagerPlugin extends EventManagerPlugin {
|
|||
addEventListener(element, eventName: string, handler: Function, shouldSupportBubble: boolean) {
|
||||
MapWrapper.set(shouldSupportBubble ? this._bubbleEventHandlers : this._nonBubbleEventHandlers,
|
||||
eventName, handler);
|
||||
return () => {MapWrapper.delete(shouldSupportBubble ? this._bubbleEventHandlers : this._nonBubbleEventHandlers,
|
||||
eventName)};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,6 +141,6 @@ class FakeVmTurnZone extends VmTurnZone {
|
|||
}
|
||||
|
||||
runOutsideAngular(fn) {
|
||||
fn();
|
||||
return fn();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -173,6 +173,7 @@ export class FakeEventManagerPlugin extends EventManagerPlugin {
|
|||
|
||||
addEventListener(element, eventName: string, handler: Function, shouldSupportBubble: boolean) {
|
||||
MapWrapper.set(this._eventHandlers, eventName, handler);
|
||||
return () => {MapWrapper.delete(this._eventHandlers, eventName);}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ export function main() {
|
|||
it('should attach the view nodes as child of the host element', () => {
|
||||
var host = el('<div><span>original content</span></div>');
|
||||
var nodes = el('<div>view</div>');
|
||||
var view = new RenderView(null, [nodes], [], [], [], []);
|
||||
var view = new RenderView(null, [nodes], [], [], [], [], null);
|
||||
|
||||
strategy.attachTemplate(host, view);
|
||||
var firstChild = DOM.firstChild(host);
|
||||
|
|
|
@ -42,7 +42,7 @@ export function main() {
|
|||
it('should attach the view nodes as child of the host element', () => {
|
||||
var host = el('<div><span>original content</span></div>');
|
||||
var nodes = el('<div>view</div>');
|
||||
var view = new RenderView(null, [nodes], [], [], [], []);
|
||||
var view = new RenderView(null, [nodes], [], [], [], [], null);
|
||||
|
||||
strategy.attachTemplate(host, view);
|
||||
var firstChild = DOM.firstChild(host);
|
||||
|
|
|
@ -35,7 +35,7 @@ export function main() {
|
|||
it('should attach the view nodes to the shadow root', () => {
|
||||
var host = el('<div><span>original content</span></div>');
|
||||
var nodes = el('<div>view</div>');
|
||||
var view = new RenderView(null, [nodes], [], [], [], []);
|
||||
var view = new RenderView(null, [nodes], [], [], [], [], null);
|
||||
|
||||
strategy.attachTemplate(host, view);
|
||||
var shadowRoot = DOM.getShadowRoot(host);
|
||||
|
|
|
@ -2,6 +2,7 @@ import {describe, ddescribe, it, iit, xit, xdescribe, expect, beforeEach, el} fr
|
|||
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
|
||||
import {RenderProtoView} from 'angular2/src/render/dom/view/proto_view';
|
||||
import {RenderView} from 'angular2/src/render/dom/view/view';
|
||||
import {ShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/shadow_dom_strategy';
|
||||
import {LightDom} from 'angular2/src/render/dom/shadow_dom/light_dom';
|
||||
|
@ -9,14 +10,15 @@ import {LightDom} from 'angular2/src/render/dom/shadow_dom/light_dom';
|
|||
export function main() {
|
||||
|
||||
function createView() {
|
||||
var proto = null;
|
||||
var proto = new RenderProtoView({element: el('<div></div>'), isRootView: false, elementBinders: []});
|
||||
var rootNodes = [el('<div></div>')];
|
||||
var boundTextNodes = [];
|
||||
var boundElements = [el('<div></div>')];
|
||||
var viewContainers = [];
|
||||
var contentTags = [];
|
||||
var eventManager = null;
|
||||
return new RenderView(proto, rootNodes,
|
||||
boundTextNodes, boundElements, viewContainers, contentTags);
|
||||
boundTextNodes, boundElements, viewContainers, contentTags, eventManager);
|
||||
}
|
||||
|
||||
function createShadowDomStrategy(log) {
|
||||
|
|
Loading…
Reference in New Issue