2016-01-06 14:13:44 -08:00
|
|
|
import * as cdAst from '../expression_parser/ast';
|
|
|
|
import * as o from '../output/output_ast';
|
|
|
|
import {Identifiers} from '../identifiers';
|
|
|
|
import {DetectChangesVars} from './constants';
|
|
|
|
|
|
|
|
import {
|
|
|
|
BoundTextAst,
|
|
|
|
BoundElementPropertyAst,
|
|
|
|
DirectiveAst,
|
|
|
|
PropertyBindingType,
|
|
|
|
TemplateAst
|
|
|
|
} from '../template_ast';
|
|
|
|
|
2016-04-25 21:47:33 -07:00
|
|
|
import {isBlank, isPresent, isArray} from 'angular2/src/facade/lang';
|
2016-01-06 14:13:44 -08:00
|
|
|
|
|
|
|
import {CompileView} from './compile_view';
|
|
|
|
import {CompileElement, CompileNode} from './compile_element';
|
|
|
|
import {CompileMethod} from './compile_method';
|
|
|
|
|
|
|
|
import {LifecycleHooks} from 'angular2/src/core/metadata/lifecycle_hooks';
|
|
|
|
import {isDefaultChangeDetectionStrategy} from 'angular2/src/core/change_detection/constants';
|
|
|
|
import {camelCaseToDashCase} from '../util';
|
|
|
|
|
|
|
|
import {convertCdExpressionToIr} from './expression_converter';
|
|
|
|
|
|
|
|
import {CompileBinding} from './compile_binding';
|
|
|
|
|
|
|
|
function createBindFieldExpr(exprIndex: number): o.ReadPropExpr {
|
|
|
|
return o.THIS_EXPR.prop(`_expr_${exprIndex}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
function createCurrValueExpr(exprIndex: number): o.ReadVarExpr {
|
|
|
|
return o.variable(`currVal_${exprIndex}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
function bind(view: CompileView, currValExpr: o.ReadVarExpr, fieldExpr: o.ReadPropExpr,
|
|
|
|
parsedExpression: cdAst.AST, context: o.Expression, actions: o.Statement[],
|
|
|
|
method: CompileMethod) {
|
|
|
|
var checkExpression =
|
|
|
|
convertCdExpressionToIr(view, context, parsedExpression, DetectChangesVars.valUnwrapper);
|
|
|
|
if (isBlank(checkExpression.expression)) {
|
|
|
|
// e.g. an empty expression was given
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
view.fields.push(new o.ClassField(fieldExpr.name, null, [o.StmtModifier.Private]));
|
|
|
|
view.createMethod.addStmt(
|
|
|
|
o.THIS_EXPR.prop(fieldExpr.name).set(o.importExpr(Identifiers.uninitialized)).toStmt());
|
|
|
|
|
|
|
|
if (checkExpression.needsValueUnwrapper) {
|
|
|
|
var initValueUnwrapperStmt = DetectChangesVars.valUnwrapper.callMethod('reset', []).toStmt();
|
|
|
|
method.addStmt(initValueUnwrapperStmt);
|
|
|
|
}
|
|
|
|
method.addStmt(
|
|
|
|
currValExpr.set(checkExpression.expression).toDeclStmt(null, [o.StmtModifier.Final]));
|
|
|
|
|
|
|
|
var condition: o.Expression =
|
|
|
|
o.importExpr(Identifiers.checkBinding)
|
|
|
|
.callFn([DetectChangesVars.throwOnChange, fieldExpr, currValExpr]);
|
|
|
|
if (checkExpression.needsValueUnwrapper) {
|
|
|
|
condition = DetectChangesVars.valUnwrapper.prop('hasWrappedValue').or(condition);
|
|
|
|
}
|
|
|
|
method.addStmt(new o.IfStmt(
|
|
|
|
condition,
|
|
|
|
actions.concat([<o.Statement>o.THIS_EXPR.prop(fieldExpr.name).set(currValExpr).toStmt()])));
|
|
|
|
}
|
|
|
|
|
|
|
|
export function bindRenderText(boundText: BoundTextAst, compileNode: CompileNode,
|
|
|
|
view: CompileView) {
|
|
|
|
var bindingIndex = view.bindings.length;
|
|
|
|
view.bindings.push(new CompileBinding(compileNode, boundText));
|
|
|
|
var currValExpr = createCurrValueExpr(bindingIndex);
|
|
|
|
var valueField = createBindFieldExpr(bindingIndex);
|
2016-04-20 18:10:19 -07:00
|
|
|
view.detectChangesRenderPropertiesMethod.resetDebugInfo(compileNode.nodeIndex, boundText);
|
2016-01-06 14:13:44 -08:00
|
|
|
|
2016-04-28 14:00:31 -07:00
|
|
|
bind(view, currValExpr, valueField, boundText.value, view.componentContext,
|
2016-01-06 14:13:44 -08:00
|
|
|
[
|
|
|
|
o.THIS_EXPR.prop('renderer')
|
|
|
|
.callMethod('setText', [compileNode.renderNode, currValExpr])
|
|
|
|
.toStmt()
|
|
|
|
],
|
2016-04-20 18:10:19 -07:00
|
|
|
view.detectChangesRenderPropertiesMethod);
|
2016-01-06 14:13:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
function bindAndWriteToRenderer(boundProps: BoundElementPropertyAst[], context: o.Expression,
|
|
|
|
compileElement: CompileElement) {
|
|
|
|
var view = compileElement.view;
|
|
|
|
var renderNode = compileElement.renderNode;
|
|
|
|
boundProps.forEach((boundProp) => {
|
|
|
|
var bindingIndex = view.bindings.length;
|
|
|
|
view.bindings.push(new CompileBinding(compileElement, boundProp));
|
2016-04-20 18:10:19 -07:00
|
|
|
view.detectChangesRenderPropertiesMethod.resetDebugInfo(compileElement.nodeIndex, boundProp);
|
2016-01-06 14:13:44 -08:00
|
|
|
var fieldExpr = createBindFieldExpr(bindingIndex);
|
|
|
|
var currValExpr = createCurrValueExpr(bindingIndex);
|
|
|
|
var renderMethod: string;
|
|
|
|
var renderValue: o.Expression = currValExpr;
|
|
|
|
var updateStmts = [];
|
|
|
|
switch (boundProp.type) {
|
|
|
|
case PropertyBindingType.Property:
|
|
|
|
renderMethod = 'setElementProperty';
|
|
|
|
if (view.genConfig.logBindingUpdate) {
|
|
|
|
updateStmts.push(logBindingUpdateStmt(renderNode, boundProp.name, currValExpr));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PropertyBindingType.Attribute:
|
|
|
|
renderMethod = 'setElementAttribute';
|
|
|
|
renderValue =
|
|
|
|
renderValue.isBlank().conditional(o.NULL_EXPR, renderValue.callMethod('toString', []));
|
|
|
|
break;
|
|
|
|
case PropertyBindingType.Class:
|
|
|
|
renderMethod = 'setElementClass';
|
|
|
|
break;
|
|
|
|
case PropertyBindingType.Style:
|
|
|
|
renderMethod = 'setElementStyle';
|
|
|
|
var strValue: o.Expression = renderValue.callMethod('toString', []);
|
|
|
|
if (isPresent(boundProp.unit)) {
|
|
|
|
strValue = strValue.plus(o.literal(boundProp.unit));
|
|
|
|
}
|
|
|
|
renderValue = renderValue.isBlank().conditional(o.NULL_EXPR, strValue);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
updateStmts.push(
|
|
|
|
o.THIS_EXPR.prop('renderer')
|
|
|
|
.callMethod(renderMethod, [renderNode, o.literal(boundProp.name), renderValue])
|
|
|
|
.toStmt());
|
|
|
|
|
|
|
|
bind(view, currValExpr, fieldExpr, boundProp.value, context, updateStmts,
|
2016-04-20 18:10:19 -07:00
|
|
|
view.detectChangesRenderPropertiesMethod);
|
2016-01-06 14:13:44 -08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
export function bindRenderInputs(boundProps: BoundElementPropertyAst[],
|
|
|
|
compileElement: CompileElement): void {
|
2016-04-28 14:00:31 -07:00
|
|
|
bindAndWriteToRenderer(boundProps, compileElement.view.componentContext, compileElement);
|
2016-01-06 14:13:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
export function bindDirectiveHostProps(directiveAst: DirectiveAst, directiveInstance: o.Expression,
|
|
|
|
compileElement: CompileElement): void {
|
|
|
|
bindAndWriteToRenderer(directiveAst.hostProperties, directiveInstance, compileElement);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function bindDirectiveInputs(directiveAst: DirectiveAst, directiveInstance: o.Expression,
|
|
|
|
compileElement: CompileElement) {
|
|
|
|
if (directiveAst.inputs.length === 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var view = compileElement.view;
|
|
|
|
var detectChangesInInputsMethod = view.detectChangesInInputsMethod;
|
|
|
|
detectChangesInInputsMethod.resetDebugInfo(compileElement.nodeIndex, compileElement.sourceAst);
|
|
|
|
|
|
|
|
var lifecycleHooks = directiveAst.directive.lifecycleHooks;
|
|
|
|
var calcChangesMap = lifecycleHooks.indexOf(LifecycleHooks.OnChanges) !== -1;
|
|
|
|
var isOnPushComp = directiveAst.directive.isComponent &&
|
|
|
|
!isDefaultChangeDetectionStrategy(directiveAst.directive.changeDetection);
|
|
|
|
if (calcChangesMap) {
|
|
|
|
detectChangesInInputsMethod.addStmt(DetectChangesVars.changes.set(o.NULL_EXPR).toStmt());
|
|
|
|
}
|
|
|
|
if (isOnPushComp) {
|
|
|
|
detectChangesInInputsMethod.addStmt(DetectChangesVars.changed.set(o.literal(false)).toStmt());
|
|
|
|
}
|
|
|
|
directiveAst.inputs.forEach((input) => {
|
|
|
|
var bindingIndex = view.bindings.length;
|
|
|
|
view.bindings.push(new CompileBinding(compileElement, input));
|
|
|
|
detectChangesInInputsMethod.resetDebugInfo(compileElement.nodeIndex, input);
|
|
|
|
var fieldExpr = createBindFieldExpr(bindingIndex);
|
|
|
|
var currValExpr = createCurrValueExpr(bindingIndex);
|
|
|
|
var statements: o.Statement[] =
|
|
|
|
[directiveInstance.prop(input.directiveName).set(currValExpr).toStmt()];
|
|
|
|
if (calcChangesMap) {
|
|
|
|
statements.push(new o.IfStmt(DetectChangesVars.changes.identical(o.NULL_EXPR), [
|
|
|
|
DetectChangesVars.changes.set(o.literalMap([], new o.MapType(
|
|
|
|
o.importType(Identifiers.SimpleChange))))
|
|
|
|
.toStmt()
|
|
|
|
]));
|
|
|
|
statements.push(
|
|
|
|
DetectChangesVars.changes.key(o.literal(input.directiveName))
|
|
|
|
.set(o.importExpr(Identifiers.SimpleChange).instantiate([fieldExpr, currValExpr]))
|
|
|
|
.toStmt());
|
|
|
|
}
|
|
|
|
if (isOnPushComp) {
|
|
|
|
statements.push(DetectChangesVars.changed.set(o.literal(true)).toStmt());
|
|
|
|
}
|
|
|
|
if (view.genConfig.logBindingUpdate) {
|
|
|
|
statements.push(
|
|
|
|
logBindingUpdateStmt(compileElement.renderNode, input.directiveName, currValExpr));
|
|
|
|
}
|
2016-04-28 14:00:31 -07:00
|
|
|
bind(view, currValExpr, fieldExpr, input.value, view.componentContext, statements,
|
2016-01-06 14:13:44 -08:00
|
|
|
detectChangesInInputsMethod);
|
|
|
|
});
|
|
|
|
if (isOnPushComp) {
|
|
|
|
detectChangesInInputsMethod.addStmt(new o.IfStmt(DetectChangesVars.changed, [
|
2016-04-18 13:24:42 -07:00
|
|
|
compileElement.appElement.prop('componentView')
|
2016-01-06 14:13:44 -08:00
|
|
|
.callMethod('markAsCheckOnce', [])
|
|
|
|
.toStmt()
|
|
|
|
]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function logBindingUpdateStmt(renderNode: o.Expression, propName: string,
|
|
|
|
value: o.Expression): o.Statement {
|
|
|
|
return o.THIS_EXPR.prop('renderer')
|
|
|
|
.callMethod('setBindingDebugInfo',
|
|
|
|
[
|
|
|
|
renderNode,
|
|
|
|
o.literal(`ng-reflect-${camelCaseToDashCase(propName)}`),
|
|
|
|
value.isBlank().conditional(o.NULL_EXPR, value.callMethod('toString', []))
|
|
|
|
])
|
|
|
|
.toStmt();
|
|
|
|
}
|