| OLD | NEW |
| 1 part of angular.core; | 1 part of angular.core; |
| 2 | 2 |
| 3 abstract class NgAnnotation { | 3 abstract class NgAnnotation { |
| 4 /** | 4 /** |
| 5 * CSS selector which will trigger this component/directive. | 5 * CSS selector which will trigger this component/directive. |
| 6 * CSS Selectors are limited to a single element and can contain: | 6 * CSS Selectors are limited to a single element and can contain: |
| 7 * | 7 * |
| 8 * * `element-name` limit to a given element name. | 8 * * `element-name` limit to a given element name. |
| 9 * * `.class` limit to an element with a given class. | 9 * * `.class` limit to an element with a given class. |
| 10 * * `[attribute]` limit to an element with a given attribute name. | 10 * * `[attribute]` limit to an element with a given attribute name. |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 * | 109 * |
| 110 * * `@title` maps the title DOM attribute to the controller `title` | 110 * * `@title` maps the title DOM attribute to the controller `title` |
| 111 * field. Notice that this maps the content of the attribute, which | 111 * field. Notice that this maps the content of the attribute, which |
| 112 * means that it can be used with `{{}}` interpolation. | 112 * means that it can be used with `{{}}` interpolation. |
| 113 * | 113 * |
| 114 * * `<=>currentItem` maps the expression (in this case the `selectedItem` | 114 * * `<=>currentItem` maps the expression (in this case the `selectedItem` |
| 115 * in the current scope into the `currentItem` in the controller. Notice | 115 * in the current scope into the `currentItem` in the controller. Notice |
| 116 * that mapping is bi-directional. A change either in field or on | 116 * that mapping is bi-directional. A change either in field or on |
| 117 * parent scope will result in change to the other. | 117 * parent scope will result in change to the other. |
| 118 * | 118 * |
| 119 * * `&onChange` maps the expression into tho controllers `onChange` | 119 * * `&onChange` maps the expression into the controller `onChange` |
| 120 * field. The result of mapping is a callable function which can be | 120 * field. The result of mapping is a callable function which can be |
| 121 * invoked at any time by the controller. The invocation of the | 121 * invoked at any time by the controller. The invocation of the |
| 122 * callable function will result in the expression `doSomething()` to | 122 * callable function will result in the expression `doSomething()` to |
| 123 * be executed in the parent context. | 123 * be executed in the parent context. |
| 124 */ | 124 */ |
| 125 final Map<String, String> map; | 125 final Map<String, String> map; |
| 126 | 126 |
| 127 /** | 127 /** |
| 128 * Use the list to specify expression containing attributes which are not | 128 * Use the list to specify expression containing attributes which are not |
| 129 * included under [map] with '=' or '@' specification. | 129 * included under [map] with '=' or '@' specification. |
| 130 */ | 130 */ |
| 131 final List<String> exportExpressionAttrs; | 131 final List<String> exportExpressionAttrs; |
| 132 | 132 |
| 133 /** | 133 /** |
| 134 * Use the list to specify a expressions which are evaluated dynamically | 134 * Use the list to specify a expressions which are evaluated dynamically |
| 135 * (ex. via [Scope.$eval]) and are otherwise not statically discoverable. | 135 * (ex. via [Scope.eval]) and are otherwise not statically discoverable. |
| 136 */ | 136 */ |
| 137 final List<String> exportExpressions; | 137 final List<String> exportExpressions; |
| 138 | 138 |
| 139 /** | |
| 140 * An expression under which the controller instance will be published into. | |
| 141 * This allows the expressions in the template to be referring to controller | |
| 142 * instance and its properties. | |
| 143 */ | |
| 144 final String publishAs; | |
| 145 | |
| 146 const NgAnnotation({ | 139 const NgAnnotation({ |
| 147 this.selector, | 140 this.selector, |
| 148 this.children: NgAnnotation.COMPILE_CHILDREN, | 141 this.children: NgAnnotation.COMPILE_CHILDREN, |
| 149 this.visibility: NgDirective.LOCAL_VISIBILITY, | 142 this.visibility: NgDirective.LOCAL_VISIBILITY, |
| 150 this.publishAs, | |
| 151 this.publishTypes: const [], | 143 this.publishTypes: const [], |
| 152 this.map: const {}, | 144 this.map: const {}, |
| 153 this.exportExpressions: const [], | 145 this.exportExpressions: const [], |
| 154 this.exportExpressionAttrs: const [] | 146 this.exportExpressionAttrs: const [] |
| 155 }); | 147 }); |
| 156 | 148 |
| 157 toString() => selector; | 149 toString() => selector; |
| 158 get hashCode => selector.hashCode; | 150 get hashCode => selector.hashCode; |
| 159 operator==(other) => | 151 operator==(other) => |
| 160 other is NgAnnotation && this.selector == other.selector; | 152 other is NgAnnotation && this.selector == other.selector; |
| 161 | 153 |
| 162 NgAnnotation cloneWithNewMap(newMap); | 154 NgAnnotation cloneWithNewMap(newMap); |
| 163 } | 155 } |
| 164 | 156 |
| 165 | 157 |
| 166 /** | 158 /** |
| 167 * Meta-data marker placed on a class which should act as a controller for the | 159 * Meta-data marker placed on a class which should act as a controller for the |
| 168 * component. Angular components are a light-weight version of web-components. | 160 * component. Angular components are a light-weight version of web-components. |
| 169 * Angular components use shadow-DOM for rendering their templates. | 161 * Angular components use shadow-DOM for rendering their templates. |
| 170 * | 162 * |
| 171 * Angular components are instantiated using dependency injection, and can | 163 * Angular components are instantiated using dependency injection, and can |
| 172 * ask for any injectable object in their constructor. Components | 164 * ask for any injectable object in their constructor. Components |
| 173 * can also ask for other components or directives declared on the DOM element. | 165 * can also ask for other components or directives declared on the DOM element. |
| 174 * | 166 * |
| 175 * Components can implement [NgAttachAware], [NgDetachAware], [NgShadowRootAware
] and | 167 * Components can implement [NgAttachAware], [NgDetachAware], |
| 176 * declare these optional methods: | 168 * [NgShadowRootAware] and declare these optional methods: |
| 177 * | 169 * |
| 178 * * `attach()` - Called on first [Scope.$digest()]. | 170 * * `attach()` - Called on first [Scope.apply()]. |
| 179 * * `detach()` - Called on when owning scope is destroyed. | 171 * * `detach()` - Called on when owning scope is destroyed. |
| 180 * * `onShadowRoot(ShadowRoot shadowRoot)` - Called when [ShadowRoot] is loaded. | 172 * * `onShadowRoot(ShadowRoot shadowRoot)` - Called when [ShadowRoot] is loaded. |
| 181 */ | 173 */ |
| 182 class NgComponent extends NgAnnotation { | 174 class NgComponent extends NgAnnotation { |
| 183 /** | 175 /** |
| 184 * Inlined HTML template for the component. | 176 * Inlined HTML template for the component. |
| 185 */ | 177 */ |
| 186 final String template; | 178 final String template; |
| 187 | 179 |
| 188 /** | 180 /** |
| 189 * A URL to HTML template. This will be loaded asynchronously and | 181 * A URL to HTML template. This will be loaded asynchronously and |
| 190 * cached for future component instances. | 182 * cached for future component instances. |
| 191 */ | 183 */ |
| 192 final String templateUrl; | 184 final String templateUrl; |
| 193 | 185 |
| 194 /** | 186 /** |
| 195 * A CSS URL to load into the shadow DOM. | |
| 196 */ | |
| 197 final String cssUrl; | |
| 198 | |
| 199 /** | |
| 200 * A list of CSS URLs to load into the shadow DOM. | 187 * A list of CSS URLs to load into the shadow DOM. |
| 201 */ | 188 */ |
| 202 final List<String> cssUrls; | 189 final _cssUrls; |
| 203 | 190 |
| 204 List<String> get allCssUrls { | 191 /** |
| 205 if (cssUrls == null && cssUrl == null) return null; | |
| 206 if (cssUrls == null && cssUrl != null) return [cssUrl]; | |
| 207 if (cssUrls != null && cssUrl == null) return cssUrls; | |
| 208 if (cssUrls != null && cssUrl != null) return [cssUrl]..addAll(cssUrls); | |
| 209 } | |
| 210 | |
| 211 /** | |
| 212 * Set the shadow root applyAuthorStyles property. See shadow-DOM | 192 * Set the shadow root applyAuthorStyles property. See shadow-DOM |
| 213 * documentation for further details. | 193 * documentation for further details. |
| 214 */ | 194 */ |
| 215 final bool applyAuthorStyles; | 195 final bool applyAuthorStyles; |
| 216 | 196 |
| 217 /** | 197 /** |
| 218 * Set the shadow root resetStyleInheritance property. See shadow-DOM | 198 * Set the shadow root resetStyleInheritance property. See shadow-DOM |
| 219 * documentation for further details. | 199 * documentation for further details. |
| 220 */ | 200 */ |
| 221 final bool resetStyleInheritance; | 201 final bool resetStyleInheritance; |
| 222 | 202 |
| 203 /** |
| 204 * An expression under which the component's controller instance will be |
| 205 * published into. This allows the expressions in the template to be referring |
| 206 * to controller instance and its properties. |
| 207 */ |
| 208 final String publishAs; |
| 209 |
| 223 const NgComponent({ | 210 const NgComponent({ |
| 224 this.template, | 211 this.template, |
| 225 this.templateUrl, | 212 this.templateUrl, |
| 226 this.cssUrl, | 213 cssUrl, |
| 227 this.cssUrls, | |
| 228 this.applyAuthorStyles, | 214 this.applyAuthorStyles, |
| 229 this.resetStyleInheritance, | 215 this.resetStyleInheritance, |
| 230 publishAs, | 216 this.publishAs, |
| 231 map, | 217 map, |
| 232 selector, | 218 selector, |
| 233 visibility, | 219 visibility, |
| 234 publishTypes : const <Type>[], | 220 publishTypes : const <Type>[], |
| 235 exportExpressions, | 221 exportExpressions, |
| 236 exportExpressionAttrs | 222 exportExpressionAttrs}) |
| 237 }) : super(selector: selector, | 223 : _cssUrls = cssUrl, |
| 224 super(selector: selector, |
| 238 children: NgAnnotation.COMPILE_CHILDREN, | 225 children: NgAnnotation.COMPILE_CHILDREN, |
| 239 visibility: visibility, | 226 visibility: visibility, |
| 240 publishTypes: publishTypes, | 227 publishTypes: publishTypes, |
| 241 publishAs: publishAs, | |
| 242 map: map, | 228 map: map, |
| 243 exportExpressions: exportExpressions, | 229 exportExpressions: exportExpressions, |
| 244 exportExpressionAttrs: exportExpressionAttrs); | 230 exportExpressionAttrs: exportExpressionAttrs); |
| 245 | 231 |
| 232 List<String> get cssUrls => _cssUrls == null ? |
| 233 const [] : |
| 234 _cssUrls is List ? _cssUrls : [_cssUrls]; |
| 235 |
| 246 NgAnnotation cloneWithNewMap(newMap) => | 236 NgAnnotation cloneWithNewMap(newMap) => |
| 247 new NgComponent( | 237 new NgComponent( |
| 248 template: template, | 238 template: template, |
| 249 templateUrl: templateUrl, | 239 templateUrl: templateUrl, |
| 250 cssUrl: cssUrl, | 240 cssUrl: cssUrls, |
| 251 cssUrls: cssUrls, | |
| 252 applyAuthorStyles: applyAuthorStyles, | 241 applyAuthorStyles: applyAuthorStyles, |
| 253 resetStyleInheritance: resetStyleInheritance, | 242 resetStyleInheritance: resetStyleInheritance, |
| 254 publishAs: publishAs, | 243 publishAs: publishAs, |
| 255 map: newMap, | 244 map: newMap, |
| 256 selector: selector, | 245 selector: selector, |
| 257 visibility: visibility, | 246 visibility: visibility, |
| 258 publishTypes: publishTypes, | 247 publishTypes: publishTypes, |
| 259 exportExpressions: exportExpressions, | 248 exportExpressions: exportExpressions, |
| 260 exportExpressionAttrs: exportExpressionAttrs); | 249 exportExpressionAttrs: exportExpressionAttrs); |
| 261 } | 250 } |
| 262 | 251 |
| 263 RegExp _ATTR_NAME = new RegExp(r'\[([^\]]+)\]$'); | 252 RegExp _ATTR_NAME = new RegExp(r'\[([^\]]+)\]$'); |
| 264 | 253 |
| 265 /** | 254 /** |
| 266 * Meta-data marker placed on a class which should act as a directive. | 255 * Meta-data marker placed on a class which should act as a directive. |
| 267 * | 256 * |
| 268 * Angular directives are instantiated using dependency injection, and can | 257 * Angular directives are instantiated using dependency injection, and can |
| 269 * ask for any injectable object in their constructor. Directives | 258 * ask for any injectable object in their constructor. Directives |
| 270 * can also ask for other components or directives declared on the DOM element. | 259 * can also ask for other components or directives declared on the DOM element. |
| 271 * | 260 * |
| 272 * Directives can implement [NgAttachAware], [NgDetachAware] and | 261 * Directives can implement [NgAttachAware], [NgDetachAware] and |
| 273 * declare these optional methods: | 262 * declare these optional methods: |
| 274 * | 263 * |
| 275 * * `attach()` - Called on first [Scope.$digest()]. | 264 * * `attach()` - Called on first [Scope.apply()]. |
| 276 * * `detach()` - Called on when owning scope is destroyed. | 265 * * `detach()` - Called on when owning scope is destroyed. |
| 277 */ | 266 */ |
| 278 class NgDirective extends NgAnnotation { | 267 class NgDirective extends NgAnnotation { |
| 279 static const String LOCAL_VISIBILITY = 'local'; | 268 static const String LOCAL_VISIBILITY = 'local'; |
| 280 static const String CHILDREN_VISIBILITY = 'children'; | 269 static const String CHILDREN_VISIBILITY = 'children'; |
| 281 static const String DIRECT_CHILDREN_VISIBILITY = 'direct_children'; | 270 static const String DIRECT_CHILDREN_VISIBILITY = 'direct_children'; |
| 282 | 271 |
| 283 const NgDirective({ | 272 const NgDirective({children: NgAnnotation.COMPILE_CHILDREN, |
| 284 children: NgAnnotation.COMPILE_CHILDREN, | |
| 285 publishAs, | |
| 286 map, | 273 map, |
| 287 selector, | 274 selector, |
| 288 visibility, | 275 visibility, |
| 289 publishTypes : const <Type>[], | 276 publishTypes : const <Type>[], |
| 290 exportExpressions, | 277 exportExpressions, |
| 291 exportExpressionAttrs | 278 exportExpressionAttrs}) : super(selector: selector, children
: children, visibility: visibility, |
| 292 }) : super(selector: selector, children: children, visibilit
y: visibility, | 279 publishTypes: publishTypes, map: map, |
| 293 publishTypes: publishTypes, publishAs: publishAs, map: map, | |
| 294 exportExpressions: exportExpressions, | 280 exportExpressions: exportExpressions, |
| 295 exportExpressionAttrs: exportExpressionAttrs); | 281 exportExpressionAttrs: exportExpressionAttrs); |
| 296 | 282 |
| 297 NgAnnotation cloneWithNewMap(newMap) => | 283 NgAnnotation cloneWithNewMap(newMap) => |
| 298 new NgDirective( | 284 new NgDirective( |
| 299 children: children, | 285 children: children, |
| 300 publishAs: publishAs, | |
| 301 map: newMap, | 286 map: newMap, |
| 302 selector: selector, | 287 selector: selector, |
| 303 visibility: visibility, | 288 visibility: visibility, |
| 304 publishTypes: publishTypes, | 289 publishTypes: publishTypes, |
| 305 exportExpressions: exportExpressions, | 290 exportExpressions: exportExpressions, |
| 306 exportExpressionAttrs: exportExpressionAttrs); | 291 exportExpressionAttrs: exportExpressionAttrs); |
| 307 } | 292 } |
| 308 | 293 |
| 309 /** | 294 /** |
| 310 * Meta-data marker placed on a class which should act as a controller for your
application. | 295 * Meta-data marker placed on a class which should act as a controller for your
application. |
| 311 * | 296 * |
| 312 * Controllers are essentially [NgDirective]s with few key differences: | 297 * Controllers are essentially [NgDirective]s with few key differences: |
| 313 * | 298 * |
| 314 * * Controllers create a new scope at the element. | 299 * * Controllers create a new scope at the element. |
| 315 * * Controllers should not do any DOM manipulation. | 300 * * Controllers should not do any DOM manipulation. |
| 316 * * Controllers are meant for application-logic | 301 * * Controllers are meant for application-logic |
| 317 * (rather then DOM monipulation logic which directives are meant for.) | 302 * (rather then DOM monipulation logic which directives are meant for.) |
| 318 * | 303 * |
| 319 * Controllers can implement [NgAttachAware], [NgDetachAware] and | 304 * Controllers can implement [NgAttachAware], [NgDetachAware] and |
| 320 * declare these optional methods: | 305 * declare these optional methods: |
| 321 * | 306 * |
| 322 * * `attach()` - Called on first [Scope.$digest()]. | 307 * * `attach()` - Called on first [Scope.apply()]. |
| 323 * * `detach()` - Called on when owning scope is destroyed. | 308 * * `detach()` - Called on when owning scope is destroyed. |
| 324 */ | 309 */ |
| 325 class NgController extends NgDirective { | 310 class NgController extends NgDirective { |
| 326 static const String LOCAL_VISIBILITY = 'local'; | 311 static const String LOCAL_VISIBILITY = 'local'; |
| 327 static const String CHILDREN_VISIBILITY = 'children'; | 312 static const String CHILDREN_VISIBILITY = 'children'; |
| 328 static const String DIRECT_CHILDREN_VISIBILITY = 'direct_children'; | 313 static const String DIRECT_CHILDREN_VISIBILITY = 'direct_children'; |
| 329 | 314 |
| 315 /** |
| 316 * An expression under which the controller instance will be published into. |
| 317 * This allows the expressions in the template to be referring to controller |
| 318 * instance and its properties. |
| 319 */ |
| 320 final String publishAs; |
| 321 |
| 330 const NgController({ | 322 const NgController({ |
| 331 children: NgAnnotation.COMPILE_CHILDREN, | 323 children: NgAnnotation.COMPILE_CHILDREN, |
| 332 publishAs, | 324 this.publishAs, |
| 333 map, | 325 map, |
| 334 selector, | 326 selector, |
| 335 visibility, | 327 visibility, |
| 336 publishTypes : const <Type>[], | 328 publishTypes : const <Type>[], |
| 337 exportExpressions, | 329 exportExpressions, |
| 338 exportExpressionAttrs | 330 exportExpressionAttrs |
| 339 }) : super(selector: selector, children: children, visibilit
y: visibility, | 331 }) : super(selector: selector, children: children, visibilit
y: visibility, |
| 340 publishTypes: publishTypes, publishAs: publishAs, map: map, | 332 publishTypes: publishTypes, map: map, |
| 341 exportExpressions: exportExpressions, | 333 exportExpressions: exportExpressions, |
| 342 exportExpressionAttrs: exportExpressionAttrs); | 334 exportExpressionAttrs: exportExpressionAttrs); |
| 343 | 335 |
| 344 NgAnnotation cloneWithNewMap(newMap) => | 336 NgAnnotation cloneWithNewMap(newMap) => |
| 345 new NgController( | 337 new NgController( |
| 346 children: children, | 338 children: children, |
| 347 publishAs: publishAs, | 339 publishAs: publishAs, |
| 348 map: newMap, | 340 map: newMap, |
| 349 selector: selector, | 341 selector: selector, |
| 350 visibility: visibility, | 342 visibility: visibility, |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 } | 417 } |
| 426 | 418 |
| 427 /** | 419 /** |
| 428 * Implementing directives or components [detach] method will be called when | 420 * Implementing directives or components [detach] method will be called when |
| 429 * the associated scope is destroyed. | 421 * the associated scope is destroyed. |
| 430 */ | 422 */ |
| 431 abstract class NgDetachAware { | 423 abstract class NgDetachAware { |
| 432 void detach(); | 424 void detach(); |
| 433 } | 425 } |
| 434 | 426 |
| 435 @NgInjectableService() | |
| 436 class DirectiveMap extends AnnotationsMap<NgAnnotation> { | |
| 437 DirectiveMap(Injector injector, MetadataExtractor metadataExtractor, | |
| 438 FieldMetadataExtractor fieldMetadataExtractor) | |
| 439 : super(injector, metadataExtractor) { | |
| 440 Map<NgAnnotation, List<Type>> directives = {}; | |
| 441 forEach((NgAnnotation annotation, Type type) { | |
| 442 var match; | |
| 443 var fieldMetadata = fieldMetadataExtractor(type); | |
| 444 if (fieldMetadata.isNotEmpty) { | |
| 445 var newMap = annotation.map == null ? {} : new Map.from(annotation.map); | |
| 446 fieldMetadata.forEach((String fieldName, AttrFieldAnnotation ann) { | |
| 447 var attrName = ann.attrName; | |
| 448 if (newMap.containsKey(attrName)) { | |
| 449 throw 'Mapping for attribute $attrName is already defined (while ' | |
| 450 'processing annottation for field $fieldName of $type)'; | |
| 451 } | |
| 452 newMap[attrName] = '${ann.mappingSpec}$fieldName'; | |
| 453 }); | |
| 454 annotation = annotation.cloneWithNewMap(newMap); | |
| 455 } | |
| 456 directives.putIfAbsent(annotation, () => []).add(type); | |
| 457 }); | |
| 458 _map.clear(); | |
| 459 _map.addAll(directives); | |
| 460 } | |
| 461 } | |
| 462 | |
| 463 @NgInjectableService() | |
| 464 class FieldMetadataExtractor { | |
| 465 List<TypeMirror> _fieldAnnotations = [reflectType(NgAttr), | |
| 466 reflectType(NgOneWay), reflectType(NgOneWayOneTime), | |
| 467 reflectType(NgTwoWay), reflectType(NgCallback)]; | |
| 468 | |
| 469 Map<String, AttrFieldAnnotation> call(Type type) { | |
| 470 ClassMirror cm = reflectType(type); | |
| 471 Map<String, AttrFieldAnnotation> fields = <String, AttrFieldAnnotation>{}; | |
| 472 cm.declarations.forEach((Symbol name, DeclarationMirror decl) { | |
| 473 if (decl is VariableMirror || | |
| 474 (decl is MethodMirror && (decl.isGetter || decl.isSetter))) { | |
| 475 var fieldName = MirrorSystem.getName(name); | |
| 476 if (decl is MethodMirror && decl.isSetter) { | |
| 477 // Remove = from the end of the setter. | |
| 478 fieldName = fieldName.substring(0, fieldName.length - 1); | |
| 479 } | |
| 480 decl.metadata.forEach((InstanceMirror meta) { | |
| 481 if (_fieldAnnotations.contains(meta.type)) { | |
| 482 if (fields[fieldName] != null) { | |
| 483 throw 'Attribute annotation for $fieldName is defined more ' | |
| 484 'than once in $type'; | |
| 485 } | |
| 486 fields[fieldName] = meta.reflectee as AttrFieldAnnotation; | |
| 487 } | |
| 488 }); | |
| 489 } | |
| 490 }); | |
| 491 return fields; | |
| 492 } | |
| 493 } | |
| OLD | NEW |