| 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 the controller `onChange` | 119 * * `&onChange` maps the expression into tho controllers `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 |
| 139 const NgAnnotation({ | 146 const NgAnnotation({ |
| 140 this.selector, | 147 this.selector, |
| 141 this.children: NgAnnotation.COMPILE_CHILDREN, | 148 this.children: NgAnnotation.COMPILE_CHILDREN, |
| 142 this.visibility: NgDirective.LOCAL_VISIBILITY, | 149 this.visibility: NgDirective.LOCAL_VISIBILITY, |
| 150 this.publishAs, |
| 143 this.publishTypes: const [], | 151 this.publishTypes: const [], |
| 144 this.map: const {}, | 152 this.map: const {}, |
| 145 this.exportExpressions: const [], | 153 this.exportExpressions: const [], |
| 146 this.exportExpressionAttrs: const [] | 154 this.exportExpressionAttrs: const [] |
| 147 }); | 155 }); |
| 148 | 156 |
| 149 toString() => selector; | 157 toString() => selector; |
| 150 get hashCode => selector.hashCode; | 158 get hashCode => selector.hashCode; |
| 151 operator==(other) => | 159 operator==(other) => |
| 152 other is NgAnnotation && this.selector == other.selector; | 160 other is NgAnnotation && this.selector == other.selector; |
| 153 | 161 |
| 154 NgAnnotation cloneWithNewMap(newMap); | 162 NgAnnotation cloneWithNewMap(newMap); |
| 155 } | 163 } |
| 156 | 164 |
| 157 | 165 |
| 158 /** | 166 /** |
| 159 * Meta-data marker placed on a class which should act as a controller for the | 167 * Meta-data marker placed on a class which should act as a controller for the |
| 160 * component. Angular components are a light-weight version of web-components. | 168 * component. Angular components are a light-weight version of web-components. |
| 161 * Angular components use shadow-DOM for rendering their templates. | 169 * Angular components use shadow-DOM for rendering their templates. |
| 162 * | 170 * |
| 163 * Angular components are instantiated using dependency injection, and can | 171 * Angular components are instantiated using dependency injection, and can |
| 164 * ask for any injectable object in their constructor. Components | 172 * ask for any injectable object in their constructor. Components |
| 165 * can also ask for other components or directives declared on the DOM element. | 173 * can also ask for other components or directives declared on the DOM element. |
| 166 * | 174 * |
| 167 * Components can implement [NgAttachAware], [NgDetachAware], | 175 * Components can implement [NgAttachAware], [NgDetachAware], [NgShadowRootAware
] and |
| 168 * [NgShadowRootAware] and declare these optional methods: | 176 * declare these optional methods: |
| 169 * | 177 * |
| 170 * * `attach()` - Called on first [Scope.apply()]. | 178 * * `attach()` - Called on first [Scope.$digest()]. |
| 171 * * `detach()` - Called on when owning scope is destroyed. | 179 * * `detach()` - Called on when owning scope is destroyed. |
| 172 * * `onShadowRoot(ShadowRoot shadowRoot)` - Called when [ShadowRoot] is loaded. | 180 * * `onShadowRoot(ShadowRoot shadowRoot)` - Called when [ShadowRoot] is loaded. |
| 173 */ | 181 */ |
| 174 class NgComponent extends NgAnnotation { | 182 class NgComponent extends NgAnnotation { |
| 175 /** | 183 /** |
| 176 * Inlined HTML template for the component. | 184 * Inlined HTML template for the component. |
| 177 */ | 185 */ |
| 178 final String template; | 186 final String template; |
| 179 | 187 |
| 180 /** | 188 /** |
| 181 * A URL to HTML template. This will be loaded asynchronously and | 189 * A URL to HTML template. This will be loaded asynchronously and |
| 182 * cached for future component instances. | 190 * cached for future component instances. |
| 183 */ | 191 */ |
| 184 final String templateUrl; | 192 final String templateUrl; |
| 185 | 193 |
| 186 /** | 194 /** |
| 195 * A CSS URL to load into the shadow DOM. |
| 196 */ |
| 197 final String cssUrl; |
| 198 |
| 199 /** |
| 187 * A list of CSS URLs to load into the shadow DOM. | 200 * A list of CSS URLs to load into the shadow DOM. |
| 188 */ | 201 */ |
| 189 final _cssUrls; | 202 final List<String> cssUrls; |
| 190 | 203 |
| 191 /** | 204 List<String> get allCssUrls { |
| 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 /** |
| 192 * Set the shadow root applyAuthorStyles property. See shadow-DOM | 212 * Set the shadow root applyAuthorStyles property. See shadow-DOM |
| 193 * documentation for further details. | 213 * documentation for further details. |
| 194 */ | 214 */ |
| 195 final bool applyAuthorStyles; | 215 final bool applyAuthorStyles; |
| 196 | 216 |
| 197 /** | 217 /** |
| 198 * Set the shadow root resetStyleInheritance property. See shadow-DOM | 218 * Set the shadow root resetStyleInheritance property. See shadow-DOM |
| 199 * documentation for further details. | 219 * documentation for further details. |
| 200 */ | 220 */ |
| 201 final bool resetStyleInheritance; | 221 final bool resetStyleInheritance; |
| 202 | 222 |
| 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 | |
| 210 const NgComponent({ | 223 const NgComponent({ |
| 211 this.template, | 224 this.template, |
| 212 this.templateUrl, | 225 this.templateUrl, |
| 213 cssUrl, | 226 this.cssUrl, |
| 227 this.cssUrls, |
| 214 this.applyAuthorStyles, | 228 this.applyAuthorStyles, |
| 215 this.resetStyleInheritance, | 229 this.resetStyleInheritance, |
| 216 this.publishAs, | 230 publishAs, |
| 217 map, | 231 map, |
| 218 selector, | 232 selector, |
| 219 visibility, | 233 visibility, |
| 220 publishTypes : const <Type>[], | 234 publishTypes : const <Type>[], |
| 221 exportExpressions, | 235 exportExpressions, |
| 222 exportExpressionAttrs}) | 236 exportExpressionAttrs |
| 223 : _cssUrls = cssUrl, | 237 }) : super(selector: selector, |
| 224 super(selector: selector, | |
| 225 children: NgAnnotation.COMPILE_CHILDREN, | 238 children: NgAnnotation.COMPILE_CHILDREN, |
| 226 visibility: visibility, | 239 visibility: visibility, |
| 227 publishTypes: publishTypes, | 240 publishTypes: publishTypes, |
| 241 publishAs: publishAs, |
| 228 map: map, | 242 map: map, |
| 229 exportExpressions: exportExpressions, | 243 exportExpressions: exportExpressions, |
| 230 exportExpressionAttrs: exportExpressionAttrs); | 244 exportExpressionAttrs: exportExpressionAttrs); |
| 231 | 245 |
| 232 List<String> get cssUrls => _cssUrls == null ? | |
| 233 const [] : | |
| 234 _cssUrls is List ? _cssUrls : [_cssUrls]; | |
| 235 | |
| 236 NgAnnotation cloneWithNewMap(newMap) => | 246 NgAnnotation cloneWithNewMap(newMap) => |
| 237 new NgComponent( | 247 new NgComponent( |
| 238 template: template, | 248 template: template, |
| 239 templateUrl: templateUrl, | 249 templateUrl: templateUrl, |
| 240 cssUrl: cssUrls, | 250 cssUrl: cssUrl, |
| 251 cssUrls: cssUrls, |
| 241 applyAuthorStyles: applyAuthorStyles, | 252 applyAuthorStyles: applyAuthorStyles, |
| 242 resetStyleInheritance: resetStyleInheritance, | 253 resetStyleInheritance: resetStyleInheritance, |
| 243 publishAs: publishAs, | 254 publishAs: publishAs, |
| 244 map: newMap, | 255 map: newMap, |
| 245 selector: selector, | 256 selector: selector, |
| 246 visibility: visibility, | 257 visibility: visibility, |
| 247 publishTypes: publishTypes, | 258 publishTypes: publishTypes, |
| 248 exportExpressions: exportExpressions, | 259 exportExpressions: exportExpressions, |
| 249 exportExpressionAttrs: exportExpressionAttrs); | 260 exportExpressionAttrs: exportExpressionAttrs); |
| 250 } | 261 } |
| 251 | 262 |
| 252 RegExp _ATTR_NAME = new RegExp(r'\[([^\]]+)\]$'); | 263 RegExp _ATTR_NAME = new RegExp(r'\[([^\]]+)\]$'); |
| 253 | 264 |
| 254 /** | 265 /** |
| 255 * Meta-data marker placed on a class which should act as a directive. | 266 * Meta-data marker placed on a class which should act as a directive. |
| 256 * | 267 * |
| 257 * Angular directives are instantiated using dependency injection, and can | 268 * Angular directives are instantiated using dependency injection, and can |
| 258 * ask for any injectable object in their constructor. Directives | 269 * ask for any injectable object in their constructor. Directives |
| 259 * can also ask for other components or directives declared on the DOM element. | 270 * can also ask for other components or directives declared on the DOM element. |
| 260 * | 271 * |
| 261 * Directives can implement [NgAttachAware], [NgDetachAware] and | 272 * Directives can implement [NgAttachAware], [NgDetachAware] and |
| 262 * declare these optional methods: | 273 * declare these optional methods: |
| 263 * | 274 * |
| 264 * * `attach()` - Called on first [Scope.apply()]. | 275 * * `attach()` - Called on first [Scope.$digest()]. |
| 265 * * `detach()` - Called on when owning scope is destroyed. | 276 * * `detach()` - Called on when owning scope is destroyed. |
| 266 */ | 277 */ |
| 267 class NgDirective extends NgAnnotation { | 278 class NgDirective extends NgAnnotation { |
| 268 static const String LOCAL_VISIBILITY = 'local'; | 279 static const String LOCAL_VISIBILITY = 'local'; |
| 269 static const String CHILDREN_VISIBILITY = 'children'; | 280 static const String CHILDREN_VISIBILITY = 'children'; |
| 270 static const String DIRECT_CHILDREN_VISIBILITY = 'direct_children'; | 281 static const String DIRECT_CHILDREN_VISIBILITY = 'direct_children'; |
| 271 | 282 |
| 272 const NgDirective({children: NgAnnotation.COMPILE_CHILDREN, | 283 const NgDirective({ |
| 284 children: NgAnnotation.COMPILE_CHILDREN, |
| 285 publishAs, |
| 273 map, | 286 map, |
| 274 selector, | 287 selector, |
| 275 visibility, | 288 visibility, |
| 276 publishTypes : const <Type>[], | 289 publishTypes : const <Type>[], |
| 277 exportExpressions, | 290 exportExpressions, |
| 278 exportExpressionAttrs}) : super(selector: selector, children
: children, visibility: visibility, | 291 exportExpressionAttrs |
| 279 publishTypes: publishTypes, map: map, | 292 }) : super(selector: selector, children: children, visibilit
y: visibility, |
| 293 publishTypes: publishTypes, publishAs: publishAs, map: map, |
| 280 exportExpressions: exportExpressions, | 294 exportExpressions: exportExpressions, |
| 281 exportExpressionAttrs: exportExpressionAttrs); | 295 exportExpressionAttrs: exportExpressionAttrs); |
| 282 | 296 |
| 283 NgAnnotation cloneWithNewMap(newMap) => | 297 NgAnnotation cloneWithNewMap(newMap) => |
| 284 new NgDirective( | 298 new NgDirective( |
| 285 children: children, | 299 children: children, |
| 300 publishAs: publishAs, |
| 286 map: newMap, | 301 map: newMap, |
| 287 selector: selector, | 302 selector: selector, |
| 288 visibility: visibility, | 303 visibility: visibility, |
| 289 publishTypes: publishTypes, | 304 publishTypes: publishTypes, |
| 290 exportExpressions: exportExpressions, | 305 exportExpressions: exportExpressions, |
| 291 exportExpressionAttrs: exportExpressionAttrs); | 306 exportExpressionAttrs: exportExpressionAttrs); |
| 292 } | 307 } |
| 293 | 308 |
| 294 /** | 309 /** |
| 295 * Meta-data marker placed on a class which should act as a controller for your
application. | 310 * Meta-data marker placed on a class which should act as a controller for your
application. |
| 296 * | 311 * |
| 297 * Controllers are essentially [NgDirective]s with few key differences: | 312 * Controllers are essentially [NgDirective]s with few key differences: |
| 298 * | 313 * |
| 299 * * Controllers create a new scope at the element. | 314 * * Controllers create a new scope at the element. |
| 300 * * Controllers should not do any DOM manipulation. | 315 * * Controllers should not do any DOM manipulation. |
| 301 * * Controllers are meant for application-logic | 316 * * Controllers are meant for application-logic |
| 302 * (rather then DOM monipulation logic which directives are meant for.) | 317 * (rather then DOM monipulation logic which directives are meant for.) |
| 303 * | 318 * |
| 304 * Controllers can implement [NgAttachAware], [NgDetachAware] and | 319 * Controllers can implement [NgAttachAware], [NgDetachAware] and |
| 305 * declare these optional methods: | 320 * declare these optional methods: |
| 306 * | 321 * |
| 307 * * `attach()` - Called on first [Scope.apply()]. | 322 * * `attach()` - Called on first [Scope.$digest()]. |
| 308 * * `detach()` - Called on when owning scope is destroyed. | 323 * * `detach()` - Called on when owning scope is destroyed. |
| 309 */ | 324 */ |
| 310 class NgController extends NgDirective { | 325 class NgController extends NgDirective { |
| 311 static const String LOCAL_VISIBILITY = 'local'; | 326 static const String LOCAL_VISIBILITY = 'local'; |
| 312 static const String CHILDREN_VISIBILITY = 'children'; | 327 static const String CHILDREN_VISIBILITY = 'children'; |
| 313 static const String DIRECT_CHILDREN_VISIBILITY = 'direct_children'; | 328 static const String DIRECT_CHILDREN_VISIBILITY = 'direct_children'; |
| 314 | 329 |
| 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 | |
| 322 const NgController({ | 330 const NgController({ |
| 323 children: NgAnnotation.COMPILE_CHILDREN, | 331 children: NgAnnotation.COMPILE_CHILDREN, |
| 324 this.publishAs, | 332 publishAs, |
| 325 map, | 333 map, |
| 326 selector, | 334 selector, |
| 327 visibility, | 335 visibility, |
| 328 publishTypes : const <Type>[], | 336 publishTypes : const <Type>[], |
| 329 exportExpressions, | 337 exportExpressions, |
| 330 exportExpressionAttrs | 338 exportExpressionAttrs |
| 331 }) : super(selector: selector, children: children, visibilit
y: visibility, | 339 }) : super(selector: selector, children: children, visibilit
y: visibility, |
| 332 publishTypes: publishTypes, map: map, | 340 publishTypes: publishTypes, publishAs: publishAs, map: map, |
| 333 exportExpressions: exportExpressions, | 341 exportExpressions: exportExpressions, |
| 334 exportExpressionAttrs: exportExpressionAttrs); | 342 exportExpressionAttrs: exportExpressionAttrs); |
| 335 | 343 |
| 336 NgAnnotation cloneWithNewMap(newMap) => | 344 NgAnnotation cloneWithNewMap(newMap) => |
| 337 new NgController( | 345 new NgController( |
| 338 children: children, | 346 children: children, |
| 339 publishAs: publishAs, | 347 publishAs: publishAs, |
| 340 map: newMap, | 348 map: newMap, |
| 341 selector: selector, | 349 selector: selector, |
| 342 visibility: visibility, | 350 visibility: visibility, |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 417 } | 425 } |
| 418 | 426 |
| 419 /** | 427 /** |
| 420 * Implementing directives or components [detach] method will be called when | 428 * Implementing directives or components [detach] method will be called when |
| 421 * the associated scope is destroyed. | 429 * the associated scope is destroyed. |
| 422 */ | 430 */ |
| 423 abstract class NgDetachAware { | 431 abstract class NgDetachAware { |
| 424 void detach(); | 432 void detach(); |
| 425 } | 433 } |
| 426 | 434 |
| 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 |