parent
							
								
									afda43dc02
								
							
						
					
					
						commit
						b39d2c0101
					
				| @ -6,6 +6,7 @@ import {Decorator, Component, Viewport} from '../../annotations/annotations'; | ||||
| import {ElementBinder} from '../element_binder'; | ||||
| import {ProtoElementInjector} from '../element_injector'; | ||||
| import {ProtoView} from '../view'; | ||||
| import {dashCaseToCamelCase} from './util'; | ||||
| 
 | ||||
| import {AST} from 'angular2/change_detection'; | ||||
| 
 | ||||
| @ -114,7 +115,7 @@ export class CompileElement { | ||||
|     if (isBlank(this.propertyBindings)) { | ||||
|       this.propertyBindings = MapWrapper.create(); | ||||
|     } | ||||
|     MapWrapper.set(this.propertyBindings, property, expression); | ||||
|     MapWrapper.set(this.propertyBindings, dashCaseToCamelCase(property), expression); | ||||
|   } | ||||
| 
 | ||||
|   addVariableBinding(variableName:string, variableValue:string) { | ||||
|  | ||||
| @ -10,7 +10,8 @@ import {CompileStep} from './compile_step'; | ||||
| import {CompileElement} from './compile_element'; | ||||
| import {CompileControl} from './compile_control'; | ||||
| 
 | ||||
| import {isSpecialProperty} from './element_binder_builder';; | ||||
| import {isSpecialProperty} from './element_binder_builder'; | ||||
| import {dashCaseToCamelCase, camelCaseToDashCase} from './util'; | ||||
| 
 | ||||
| var PROPERTY_BINDING_REGEXP = RegExpWrapper.create('^ *([^\\s\\|]+)'); | ||||
| 
 | ||||
| @ -84,7 +85,7 @@ function updateMatchedProperties(matchedProperties, selector, directive) { | ||||
|     if (isPresent(attrs)) { | ||||
|       for (var idx = 0; idx<attrs.length; idx+=2) { | ||||
|         // attribute name is stored on even indexes
 | ||||
|         StringMapWrapper.set(matchedProperties, attrs[idx], true); | ||||
|         StringMapWrapper.set(matchedProperties, dashCaseToCamelCase(attrs[idx]), true); | ||||
|       } | ||||
|     } | ||||
|     // some properties can be used by the directive, so we need to register them
 | ||||
| @ -97,7 +98,7 @@ function updateMatchedProperties(matchedProperties, selector, directive) { | ||||
|         // keep the property name and remove the pipe
 | ||||
|         var bindProp = RegExpWrapper.firstMatch(PROPERTY_BINDING_REGEXP, value); | ||||
|         if (isPresent(bindProp) && isPresent(bindProp[1])) { | ||||
|           StringMapWrapper.set(matchedProperties, bindProp[1], true); | ||||
|           StringMapWrapper.set(matchedProperties, dashCaseToCamelCase(bindProp[1]), true); | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
| @ -130,7 +131,7 @@ function checkMissingDirectives(current, matchedProperties, isTemplateElement) { | ||||
|       MapWrapper.forEach(ppBindings, (expression, prop) => { | ||||
|         if (!DOM.hasProperty(current.element, prop) && !isSpecialProperty(prop)) { | ||||
|           if (!isPresent(matchedProperties) || !isPresent(StringMapWrapper.get(matchedProperties, prop))) { | ||||
|             throw new BaseException(`Missing directive to handle '${prop}' in ${current.elementDescription}`); | ||||
|             throw new BaseException(`Missing directive to handle '${camelCaseToDashCase(prop)}' in ${current.elementDescription}`); | ||||
|           } | ||||
|         } | ||||
|       }); | ||||
|  | ||||
| @ -11,21 +11,24 @@ import {DirectiveMetadata} from '../directive_metadata'; | ||||
| import {CompileStep} from './compile_step'; | ||||
| import {CompileElement} from './compile_element'; | ||||
| import {CompileControl} from './compile_control'; | ||||
| import {dashCaseToCamelCase, camelCaseToDashCase} from './util'; | ||||
| 
 | ||||
| var DOT_REGEXP = RegExpWrapper.create('\\.'); | ||||
| 
 | ||||
| const ARIA_PREFIX = 'aria-'; | ||||
| const ARIA_PREFIX = 'aria'; | ||||
| var ariaSettersCache = StringMapWrapper.create(); | ||||
| 
 | ||||
| function ariaSetterFactory(attrName:string) { | ||||
|   var setterFn = StringMapWrapper.get(ariaSettersCache, attrName); | ||||
|   var ariaAttrName; | ||||
| 
 | ||||
|   if (isBlank(setterFn)) { | ||||
|     ariaAttrName = camelCaseToDashCase(attrName); | ||||
|     setterFn = function(element, value) { | ||||
|       if (isPresent(value)) { | ||||
|         DOM.setAttribute(element, attrName, stringify(value)); | ||||
|         DOM.setAttribute(element, ariaAttrName, stringify(value)); | ||||
|       } else { | ||||
|         DOM.removeAttribute(element, attrName); | ||||
|         DOM.removeAttribute(element, ariaAttrName); | ||||
|       } | ||||
|     }; | ||||
|     StringMapWrapper.set(ariaSettersCache, attrName, setterFn); | ||||
| @ -34,7 +37,6 @@ function ariaSetterFactory(attrName:string) { | ||||
|   return setterFn; | ||||
| } | ||||
| 
 | ||||
| const CLASS_ATTR = 'class'; | ||||
| const CLASS_PREFIX = 'class.'; | ||||
| var classSettersCache = StringMapWrapper.create(); | ||||
| 
 | ||||
| @ -55,22 +57,23 @@ function classSetterFactory(className:string) { | ||||
|   return setterFn; | ||||
| } | ||||
| 
 | ||||
| const STYLE_ATTR = 'style'; | ||||
| const STYLE_PREFIX = 'style.'; | ||||
| var styleSettersCache = StringMapWrapper.create(); | ||||
| 
 | ||||
| function styleSetterFactory(styleName:string, stylesuffix:string) { | ||||
|   var cacheKey = styleName + stylesuffix; | ||||
|   var setterFn = StringMapWrapper.get(styleSettersCache, cacheKey); | ||||
|   var dashCasedStyleName; | ||||
| 
 | ||||
|   if (isBlank(setterFn)) { | ||||
|     dashCasedStyleName = camelCaseToDashCase(styleName); | ||||
|     setterFn = function(element, value) { | ||||
|       var valAsStr; | ||||
|       if (isPresent(value)) { | ||||
|         valAsStr = stringify(value); | ||||
|         DOM.setStyle(element, styleName, valAsStr + stylesuffix); | ||||
|         DOM.setStyle(element, dashCasedStyleName, valAsStr + stylesuffix); | ||||
|       } else { | ||||
|         DOM.removeStyle(element, styleName); | ||||
|         DOM.removeStyle(element, dashCasedStyleName); | ||||
|       } | ||||
|     }; | ||||
|     StringMapWrapper.set(classSettersCache, cacheKey, setterFn); | ||||
| @ -229,7 +232,7 @@ export class ElementBinderBuilder extends CompileStep { | ||||
|         var elProp = ListWrapper.removeAt(pipes, 0); | ||||
| 
 | ||||
|         var bindingAst = isPresent(compileElement.propertyBindings) ? | ||||
|           MapWrapper.get(compileElement.propertyBindings, elProp) : | ||||
|           MapWrapper.get(compileElement.propertyBindings, dashCaseToCamelCase(elProp)) : | ||||
|             null; | ||||
| 
 | ||||
|         if (isBlank(bindingAst)) { | ||||
| @ -246,7 +249,7 @@ export class ElementBinderBuilder extends CompileStep { | ||||
|             directiveIndex, | ||||
|             fullExpAstWithBindPipes, | ||||
|             dirProp, | ||||
|             reflector.setter(dirProp) | ||||
|             reflector.setter(dashCaseToCamelCase(dirProp)) | ||||
|           ); | ||||
|         } | ||||
|       }); | ||||
|  | ||||
							
								
								
									
										16
									
								
								modules/angular2/src/core/compiler/pipeline/util.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								modules/angular2/src/core/compiler/pipeline/util.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| import {StringWrapper, RegExpWrapper} from 'angular2/src/facade/lang'; | ||||
| 
 | ||||
| var DASH_CASE_REGEXP = RegExpWrapper.create('-([a-z])'); | ||||
| var CAMEL_CASE_REGEXP = RegExpWrapper.create('([A-Z])'); | ||||
| 
 | ||||
| export function dashCaseToCamelCase(input:string) { | ||||
|   return StringWrapper.replaceAllMapped(input, DASH_CASE_REGEXP, (m) => { | ||||
|     return m[1].toUpperCase(); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| export function camelCaseToDashCase(input:string) { | ||||
|   return StringWrapper.replaceAllMapped(input, CAMEL_CASE_REGEXP, (m) => { | ||||
|     return '-' + m[1].toLowerCase(); | ||||
|   }); | ||||
| } | ||||
| @ -21,7 +21,7 @@ class BrowserDomAdapter extends GenericBrowserDomAdapter { | ||||
| 
 | ||||
|   @override | ||||
|   final attrToPropMap = const { | ||||
|     'inner-html': 'innerHtml', | ||||
|     'innerHtml': 'innerHtml', | ||||
|     'readonly': 'readOnly', | ||||
|     'tabindex': 'tabIndex', | ||||
|   }; | ||||
|  | ||||
| @ -4,9 +4,9 @@ import {setRootDomAdapter} from './dom_adapter'; | ||||
| import {GenericBrowserDomAdapter} from './generic_browser_adapter'; | ||||
| 
 | ||||
| var _attrToPropMap = { | ||||
|   'inner-html': 'innerHTML', | ||||
|   'innerHtml': 'innerHTML', | ||||
|   'readonly': 'readOnly', | ||||
|   'tabindex': 'tabIndex', | ||||
|   'tabindex': 'tabIndex' | ||||
| }; | ||||
| 
 | ||||
| export class BrowserDomAdapter extends GenericBrowserDomAdapter { | ||||
|  | ||||
| @ -13,7 +13,7 @@ import {BaseException, isPresent, isBlank} from 'angular2/src/facade/lang'; | ||||
| import {SelectorMatcher, CssSelector} from 'angular2/src/core/compiler/selector'; | ||||
| 
 | ||||
| var _attrToPropMap = { | ||||
|   'inner-html': 'innerHTML', | ||||
|   'innerHtml': 'innerHTML', | ||||
|   'readonly': 'readOnly', | ||||
|   'tabindex': 'tabIndex', | ||||
| }; | ||||
| @ -206,7 +206,7 @@ export class Parse5DomAdapter extends DomAdapter { | ||||
|   } | ||||
|   setText(el, value:string) { | ||||
|     if (this.isTextNode(el)) { | ||||
|       el.data = value;   | ||||
|       el.data = value; | ||||
|     } else { | ||||
|       this.clearNodes(el); | ||||
|       treeAdapter.insertText(el, value); | ||||
| @ -315,7 +315,7 @@ export class Parse5DomAdapter extends DomAdapter { | ||||
|     for (var key in styleMap) { | ||||
|       var newValue = styleMap[key]; | ||||
|       if (newValue && newValue.length > 0) { | ||||
|         styleAttrValue += key + ":" + styleMap[key] + ";";   | ||||
|         styleAttrValue += key + ":" + styleMap[key] + ";"; | ||||
|       } | ||||
|     } | ||||
|     element.attribs["style"] = styleAttrValue; | ||||
| @ -427,7 +427,7 @@ export class Parse5DomAdapter extends DomAdapter { | ||||
|           var declaration = parsedRule.declarations[j]; | ||||
|           rule.style[declaration.property] = declaration.value; | ||||
|           rule.style.cssText += declaration.property + ": " + declaration.value + ";"; | ||||
|         }   | ||||
|         } | ||||
|       } else if (parsedRule.type == "media") { | ||||
|         rule.type = 4; | ||||
|         rule.media = {mediaText: parsedRule.media}; | ||||
|  | ||||
| @ -133,6 +133,23 @@ export function main() { | ||||
|         }); | ||||
|       })); | ||||
| 
 | ||||
|       it('should consume binding to camel-cased properties using dash-cased syntax in templates', inject([AsyncTestCompleter], (async) => { | ||||
|         tplResolver.setTemplate(MyComp, new Template({inline: '<input [read-only]="ctxBoolProp">'})); | ||||
| 
 | ||||
|         compiler.compile(MyComp).then((pv) => { | ||||
|           createView(pv); | ||||
| 
 | ||||
|           cd.detectChanges(); | ||||
|           expect(view.nodes[0].readOnly).toBeFalsy(); | ||||
| 
 | ||||
|           ctx.ctxBoolProp = true; | ||||
|           cd.detectChanges(); | ||||
|           expect(view.nodes[0].readOnly).toBeTruthy(); | ||||
| 
 | ||||
|           async.done(); | ||||
|         }); | ||||
|       })); | ||||
| 
 | ||||
|       it('should consume binding to inner-html', inject([AsyncTestCompleter], (async) => { | ||||
|         tplResolver.setTemplate(MyComp, new Template({inline: '<div inner-html="{{ctxProp}}"></div>'})); | ||||
| 
 | ||||
| @ -592,9 +609,11 @@ class PushBasedComp { | ||||
| class MyComp { | ||||
|   ctxProp:string; | ||||
|   ctxNumProp; | ||||
|   ctxBoolProp; | ||||
|   constructor() { | ||||
|     this.ctxProp = 'initial value'; | ||||
|     this.ctxNumProp = 0; | ||||
|     this.ctxBoolProp = false; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user