angular2
Version:
Angular 2 - a web framework for modern web apps
131 lines (130 loc) • 7.18 kB
JavaScript
import { isBlank, isPresent, StringWrapper } from 'angular2/src/facade/lang';
import { ListWrapper, StringMapWrapper } from 'angular2/src/facade/collection';
import { EventHandlerVars, ViewProperties } from './constants';
import * as o from '../output/output_ast';
import { CompileMethod } from './compile_method';
import { convertCdStatementToIr } from './expression_converter';
import { CompileBinding } from './compile_binding';
export class CompileEventListener {
constructor(compileElement, eventTarget, eventName, listenerIndex) {
this.compileElement = compileElement;
this.eventTarget = eventTarget;
this.eventName = eventName;
this._hasComponentHostListener = false;
this._actionResultExprs = [];
this._method = new CompileMethod(compileElement.view);
this._methodName =
`_handle_${santitizeEventName(eventName)}_${compileElement.nodeIndex}_${listenerIndex}`;
this._eventParam =
new o.FnParam(EventHandlerVars.event.name, o.importType(this.compileElement.view.genConfig.renderTypes.renderEvent));
}
static getOrCreate(compileElement, eventTarget, eventName, targetEventListeners) {
var listener = targetEventListeners.find(listener => listener.eventTarget == eventTarget &&
listener.eventName == eventName);
if (isBlank(listener)) {
listener = new CompileEventListener(compileElement, eventTarget, eventName, targetEventListeners.length);
targetEventListeners.push(listener);
}
return listener;
}
addAction(hostEvent, directive, directiveInstance) {
if (isPresent(directive) && directive.isComponent) {
this._hasComponentHostListener = true;
}
this._method.resetDebugInfo(this.compileElement.nodeIndex, hostEvent);
var context = isPresent(directiveInstance) ? directiveInstance : o.THIS_EXPR.prop('context');
var actionStmts = convertCdStatementToIr(this.compileElement.view, context, hostEvent.handler);
var lastIndex = actionStmts.length - 1;
if (lastIndex >= 0) {
var lastStatement = actionStmts[lastIndex];
var returnExpr = convertStmtIntoExpression(lastStatement);
var preventDefaultVar = o.variable(`pd_${this._actionResultExprs.length}`);
this._actionResultExprs.push(preventDefaultVar);
if (isPresent(returnExpr)) {
// Note: We need to cast the result of the method call to dynamic,
// as it might be a void method!
actionStmts[lastIndex] =
preventDefaultVar.set(returnExpr.cast(o.DYNAMIC_TYPE).notIdentical(o.literal(false)))
.toDeclStmt(null, [o.StmtModifier.Final]);
}
}
this._method.addStmts(actionStmts);
}
finishMethod() {
var markPathToRootStart = this._hasComponentHostListener ?
this.compileElement.appElement.prop('componentView') :
o.THIS_EXPR;
var resultExpr = o.literal(true);
this._actionResultExprs.forEach((expr) => { resultExpr = resultExpr.and(expr); });
var stmts = [markPathToRootStart.callMethod('markPathToRootAsCheckOnce', []).toStmt()]
.concat(this._method.finish())
.concat([new o.ReturnStatement(resultExpr)]);
this.compileElement.view.eventHandlerMethods.push(new o.ClassMethod(this._methodName, [this._eventParam], stmts, o.BOOL_TYPE, [o.StmtModifier.Private]));
}
listenToRenderer() {
var listenExpr;
var eventListener = o.THIS_EXPR.callMethod('eventHandler', [
o.fn([this._eventParam], [
new o.ReturnStatement(o.THIS_EXPR.callMethod(this._methodName, [EventHandlerVars.event]))
])
]);
if (isPresent(this.eventTarget)) {
listenExpr = ViewProperties.renderer.callMethod('listenGlobal', [o.literal(this.eventTarget), o.literal(this.eventName), eventListener]);
}
else {
listenExpr = ViewProperties.renderer.callMethod('listen', [this.compileElement.renderNode, o.literal(this.eventName), eventListener]);
}
var disposable = o.variable(`disposable_${this.compileElement.view.disposables.length}`);
this.compileElement.view.disposables.push(disposable);
this.compileElement.view.createMethod.addStmt(disposable.set(listenExpr).toDeclStmt(o.FUNCTION_TYPE, [o.StmtModifier.Private]));
}
listenToDirective(directiveInstance, observablePropName) {
var subscription = o.variable(`subscription_${this.compileElement.view.subscriptions.length}`);
this.compileElement.view.subscriptions.push(subscription);
var eventListener = o.THIS_EXPR.callMethod('eventHandler', [
o.fn([this._eventParam], [o.THIS_EXPR.callMethod(this._methodName, [EventHandlerVars.event]).toStmt()])
]);
this.compileElement.view.createMethod.addStmt(subscription.set(directiveInstance.prop(observablePropName)
.callMethod(o.BuiltinMethod.SubscribeObservable, [eventListener]))
.toDeclStmt(null, [o.StmtModifier.Final]));
}
}
export function collectEventListeners(hostEvents, dirs, compileElement) {
var eventListeners = [];
hostEvents.forEach((hostEvent) => {
compileElement.view.bindings.push(new CompileBinding(compileElement, hostEvent));
var listener = CompileEventListener.getOrCreate(compileElement, hostEvent.target, hostEvent.name, eventListeners);
listener.addAction(hostEvent, null, null);
});
ListWrapper.forEachWithIndex(dirs, (directiveAst, i) => {
var directiveInstance = compileElement.directiveInstances[i];
directiveAst.hostEvents.forEach((hostEvent) => {
compileElement.view.bindings.push(new CompileBinding(compileElement, hostEvent));
var listener = CompileEventListener.getOrCreate(compileElement, hostEvent.target, hostEvent.name, eventListeners);
listener.addAction(hostEvent, directiveAst.directive, directiveInstance);
});
});
eventListeners.forEach((listener) => listener.finishMethod());
return eventListeners;
}
export function bindDirectiveOutputs(directiveAst, directiveInstance, eventListeners) {
StringMapWrapper.forEach(directiveAst.directive.outputs, (eventName, observablePropName) => {
eventListeners.filter(listener => listener.eventName == eventName)
.forEach((listener) => { listener.listenToDirective(directiveInstance, observablePropName); });
});
}
export function bindRenderOutputs(eventListeners) {
eventListeners.forEach(listener => listener.listenToRenderer());
}
function convertStmtIntoExpression(stmt) {
if (stmt instanceof o.ExpressionStatement) {
return stmt.expr;
}
else if (stmt instanceof o.ReturnStatement) {
return stmt.value;
}
return null;
}
function santitizeEventName(name) {
return StringWrapper.replaceAll(name, /[^a-zA-Z_]/g, '_');
}