import {isPresent, isBlank, RegExpWrapper, BaseException, StringWrapper} from 'angular2/src/facade/lang'; import {MapWrapper} from 'angular2/src/facade/collection'; import {Parser, AST, ExpressionWithSource} from 'angular2/change_detection'; import {CompileStep} from './compile_step'; import {CompileElement} from './compile_element'; import {CompileControl} from './compile_control'; import {dashCaseToCamelCase} from '../util'; import {setterFactory} from './property_setter_factory'; // Group 1 = "bind" // Group 2 = "var" // Group 3 = "on" // Group 4 = the identifier after "bind", "var", or "on" // Group 5 = idenitifer inside square braces // Group 6 = identifier inside parenthesis // Group 7 = "#" // Group 8 = identifier after "#" var BIND_NAME_REGEXP = RegExpWrapper.create( '^(?:(?:(?:(bind)|(var)|(on))-(.+))|\\[([^\\]]+)\\]|\\(([^\\)]+)\\)|(#)(.+))$'); /** * Parses the property bindings on a single element. */ export class PropertyBindingParser extends CompileStep { _parser:Parser; constructor(parser:Parser) { super(); this._parser = parser; } process(parent:CompileElement, current:CompileElement, control:CompileControl) { if (current.ignoreBindings) { return; } var attrs = current.attrs(); var newAttrs = MapWrapper.create(); MapWrapper.forEach(attrs, (attrValue, attrName) => { var bindParts = RegExpWrapper.firstMatch(BIND_NAME_REGEXP, attrName); if (isPresent(bindParts)) { if (isPresent(bindParts[1])) { // match: bind-prop this._bindProperty(bindParts[4], attrValue, current, newAttrs); } else if (isPresent(bindParts[2]) || isPresent(bindParts[7])) { // match: var-name / var-name="iden" / #name / #name="iden" var identifier = (isPresent(bindParts[4]) && bindParts[4] !== '') ? bindParts[4] : bindParts[8]; var value = attrValue == '' ? '\$implicit' : attrValue; this._bindVariable(identifier, value, current, newAttrs); } else if (isPresent(bindParts[3])) { // match: on-event this._bindEvent(bindParts[4], attrValue, current, newAttrs); } else if (isPresent(bindParts[5])) { // match: [prop] this._bindProperty(bindParts[5], attrValue, current, newAttrs); } else if (isPresent(bindParts[6])) { // match: (event) this._bindEvent(bindParts[6], attrValue, current, newAttrs); } } else { var expr = this._parser.parseInterpolation( attrValue, current.elementDescription ); if (isPresent(expr)) { this._bindPropertyAst(attrName, expr, current, newAttrs); } } }); MapWrapper.forEach(newAttrs, (attrValue, attrName) => { MapWrapper.set(attrs, attrName, attrValue); }); } _bindVariable(identifier, value, current:CompileElement, newAttrs) { current.bindElement().bindVariable(dashCaseToCamelCase(identifier), value); MapWrapper.set(newAttrs, identifier, value); } _bindProperty(name, expression, current:CompileElement, newAttrs) { this._bindPropertyAst( name, this._parser.parseBinding(expression, current.elementDescription), current, newAttrs ); } _bindPropertyAst(name, ast, current:CompileElement, newAttrs) { var binder = current.bindElement(); var camelCaseName = dashCaseToCamelCase(name); binder.bindProperty(camelCaseName, ast); binder.bindPropertySetter(camelCaseName, setterFactory(camelCaseName)); MapWrapper.set(newAttrs, name, ast.source); } _bindEvent(name, expression, current:CompileElement, newAttrs) { current.bindElement().bindEvent( dashCaseToCamelCase(name), this._parser.parseAction(expression, current.elementDescription) ); // Don't detect directives for event names for now, // so don't add the event name to the CompileElement.attrs } }