feat(core): add support for ambient directives
Ambient directives can be configured when bootstraping an application. Ambient directives can be used in every component of the application without needing to explicitly list them.
This commit is contained in:
@ -38,7 +38,6 @@ import {AppViewManager} from 'angular2/src/core/linker/view_manager';
|
||||
import {AppViewManagerUtils} from 'angular2/src/core/linker/view_manager_utils';
|
||||
import {AppViewListener} from 'angular2/src/core/linker/view_listener';
|
||||
import {ProtoViewFactory} from './linker/proto_view_factory';
|
||||
import {DEFAULT_PIPES} from 'angular2/src/core/pipes';
|
||||
import {ViewResolver} from './linker/view_resolver';
|
||||
import {DirectiveResolver} from './linker/directive_resolver';
|
||||
import {PipeResolver} from './linker/pipe_resolver';
|
||||
@ -48,6 +47,8 @@ import {AppViewManager_} from "./linker/view_manager";
|
||||
import {Compiler_} from "./linker/compiler";
|
||||
import {wtfLeave, wtfCreateScope, WtfScopeFn} from './profile/profile';
|
||||
import {ChangeDetectorRef} from 'angular2/src/core/change_detection/change_detector_ref';
|
||||
import {AMBIENT_DIRECTIVES, AMBIENT_PIPES} from "angular2/src/core/compiler/ambient";
|
||||
import {COMMON_DIRECTIVES, COMMON_PIPES} from "angular2/common";
|
||||
|
||||
/**
|
||||
* Constructs the set of providers meant for use at the platform level.
|
||||
@ -104,11 +105,12 @@ export function applicationCommonProviders(): Array<Type | Provider | any[]> {
|
||||
AppViewListener,
|
||||
ProtoViewFactory,
|
||||
ViewResolver,
|
||||
DEFAULT_PIPES,
|
||||
provide(IterableDiffers, {useValue: defaultIterableDiffers}),
|
||||
provide(KeyValueDiffers, {useValue: defaultKeyValueDiffers}),
|
||||
DirectiveResolver,
|
||||
PipeResolver,
|
||||
provide(AMBIENT_PIPES, {useValue: COMMON_PIPES, multi: true}),
|
||||
provide(AMBIENT_DIRECTIVES, {useValue: COMMON_DIRECTIVES, multi: true}),
|
||||
provide(DynamicComponentLoader, {useClass: DynamicComponentLoader_})
|
||||
];
|
||||
}
|
||||
|
53
modules/angular2/src/core/compiler/ambient.ts
Normal file
53
modules/angular2/src/core/compiler/ambient.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import {OpaqueToken} from "angular2/src/core/di";
|
||||
import {CONST_EXPR} from "angular2/src/core/facade/lang";
|
||||
|
||||
/**
|
||||
* A token that can be provided when bootstraping an application to make an array of directives
|
||||
* available in every component of the application.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```typescript
|
||||
* import {AMBIENT_DIRECTIVES} from 'angular2/angular2';
|
||||
* import {OtherDirective} from './myDirectives';
|
||||
*
|
||||
* @Component({
|
||||
* selector: 'my-component',
|
||||
* template: `
|
||||
* <!-- can use other directive even though the component does not list it in `directives` -->
|
||||
* <other-directive></other-directive>
|
||||
* `
|
||||
* })
|
||||
* export class MyComponent {
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* bootstrap(MyComponent, [provide(AMBIENT_DIRECTIVES, {useValue: [OtherDirective], multi:true})]);
|
||||
* ```
|
||||
*/
|
||||
export const AMBIENT_DIRECTIVES: OpaqueToken = CONST_EXPR(new OpaqueToken("Ambient Directives"));
|
||||
|
||||
/**
|
||||
* A token that can be provided when bootstraping an application to make an array of pipes
|
||||
* available in every component of the application.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```typescript
|
||||
* import {AMBIENT_PIPES} from 'angular2/angular2';
|
||||
* import {OtherPipe} from './myPipe';
|
||||
*
|
||||
* @Component({
|
||||
* selector: 'my-component',
|
||||
* template: `
|
||||
* {{123 | other-pipe}}
|
||||
* `
|
||||
* })
|
||||
* export class MyComponent {
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* bootstrap(MyComponent, [provide(AMBIENT_PIPES, {useValue: [OtherPipe], multi:true})]);
|
||||
* ```
|
||||
*/
|
||||
export const AMBIENT_PIPES: OpaqueToken = CONST_EXPR(new OpaqueToken("Ambient Pipes"));
|
@ -6,6 +6,7 @@ export {
|
||||
CompileTemplateMetadata
|
||||
} from './directive_metadata';
|
||||
export {SourceModule, SourceWithImports} from './source_module';
|
||||
export {AMBIENT_DIRECTIVES, AMBIENT_PIPES} from './ambient';
|
||||
|
||||
import {assertionsEnabled, Type} from 'angular2/src/core/facade/lang';
|
||||
import {provide, Provider} from 'angular2/src/core/di';
|
||||
|
@ -17,14 +17,16 @@ import {ViewMetadata} from 'angular2/src/core/metadata/view';
|
||||
import {hasLifecycleHook} from 'angular2/src/core/linker/directive_lifecycle_reflector';
|
||||
import {LifecycleHooks, LIFECYCLE_HOOKS_VALUES} from 'angular2/src/core/linker/interfaces';
|
||||
import {reflector} from 'angular2/src/core/reflection/reflection';
|
||||
import {Injectable} from 'angular2/src/core/di';
|
||||
import {Injectable, Inject, Optional} from 'angular2/src/core/di';
|
||||
import {AMBIENT_DIRECTIVES} from 'angular2/src/core/compiler/ambient';
|
||||
import {MODULE_SUFFIX} from './util';
|
||||
|
||||
@Injectable()
|
||||
export class RuntimeMetadataResolver {
|
||||
private _cache = new Map<Type, cpl.CompileDirectiveMetadata>();
|
||||
|
||||
constructor(private _directiveResolver: DirectiveResolver, private _viewResolver: ViewResolver) {}
|
||||
constructor(private _directiveResolver: DirectiveResolver, private _viewResolver: ViewResolver,
|
||||
@Optional() @Inject(AMBIENT_DIRECTIVES) private _ambientDirectives: Type[]) {}
|
||||
|
||||
getMetadata(directiveType: Type): cpl.CompileDirectiveMetadata {
|
||||
var meta = this._cache.get(directiveType);
|
||||
@ -68,7 +70,7 @@ export class RuntimeMetadataResolver {
|
||||
|
||||
getViewDirectivesMetadata(component: Type): cpl.CompileDirectiveMetadata[] {
|
||||
var view = this._viewResolver.resolve(component);
|
||||
var directives = flattenDirectives(view);
|
||||
var directives = flattenDirectives(view, this._ambientDirectives);
|
||||
for (var i = 0; i < directives.length; i++) {
|
||||
if (!isValidDirective(directives[i])) {
|
||||
throw new BaseException(
|
||||
@ -86,18 +88,22 @@ function removeDuplicates(items: any[]): any[] {
|
||||
return MapWrapper.keys(m);
|
||||
}
|
||||
|
||||
function flattenDirectives(view: ViewMetadata): Type[] {
|
||||
if (isBlank(view.directives)) return [];
|
||||
var directives = [];
|
||||
flattenList(view.directives, directives);
|
||||
function flattenDirectives(view: ViewMetadata, ambientDirectives: any[]): Type[] {
|
||||
let directives = [];
|
||||
if (isPresent(ambientDirectives)) {
|
||||
flattenArray(ambientDirectives, directives);
|
||||
}
|
||||
if (isPresent(view.directives)) {
|
||||
flattenArray(view.directives, directives);
|
||||
}
|
||||
return directives;
|
||||
}
|
||||
|
||||
function flattenList(tree: any[], out: Array<Type | any[]>): void {
|
||||
function flattenArray(tree: any[], out: Array<Type | any[]>): void {
|
||||
for (var i = 0; i < tree.length; i++) {
|
||||
var item = resolveForwardRef(tree[i]);
|
||||
if (isArray(item)) {
|
||||
flattenList(item, out);
|
||||
flattenArray(item, out);
|
||||
} else {
|
||||
out.push(item);
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
import {ListWrapper} from 'angular2/src/core/facade/collection';
|
||||
import {isPresent, isBlank, Type, isArray, isNumber} from 'angular2/src/core/facade/lang';
|
||||
|
||||
import {RenderProtoViewRef} from 'angular2/src/core/render/api';
|
||||
|
||||
import {Injectable, Provider, resolveForwardRef, Inject} from 'angular2/src/core/di';
|
||||
import {Optional, Injectable, Provider, resolveForwardRef, Inject} from 'angular2/src/core/di';
|
||||
|
||||
import {PipeProvider} from '../pipes/pipe_provider';
|
||||
import {ProtoPipes} from '../pipes/pipes';
|
||||
@ -15,7 +14,7 @@ import {DirectiveResolver} from './directive_resolver';
|
||||
import {ViewResolver} from './view_resolver';
|
||||
import {PipeResolver} from './pipe_resolver';
|
||||
import {ViewMetadata} from '../metadata/view';
|
||||
import {DEFAULT_PIPES_TOKEN} from 'angular2/src/core/pipes';
|
||||
import {AMBIENT_PIPES} from 'angular2/src/core/compiler/ambient';
|
||||
|
||||
import {
|
||||
visitAllCommands,
|
||||
@ -38,15 +37,10 @@ import {APP_ID} from 'angular2/src/core/application_tokens';
|
||||
@Injectable()
|
||||
export class ProtoViewFactory {
|
||||
private _cache: Map<number, AppProtoView> = new Map<number, AppProtoView>();
|
||||
private _defaultPipes: Type[];
|
||||
private _appId: string;
|
||||
|
||||
constructor(private _renderer: Renderer, @Inject(DEFAULT_PIPES_TOKEN) defaultPipes: Type[],
|
||||
constructor(private _renderer: Renderer,
|
||||
@Optional() @Inject(AMBIENT_PIPES) private _ambientPipes: Array<Type | any[]>,
|
||||
private _directiveResolver: DirectiveResolver, private _viewResolver: ViewResolver,
|
||||
private _pipeResolver: PipeResolver, @Inject(APP_ID) appId: string) {
|
||||
this._defaultPipes = defaultPipes;
|
||||
this._appId = appId;
|
||||
}
|
||||
private _pipeResolver: PipeResolver, @Inject(APP_ID) private _appId: string) {}
|
||||
|
||||
clearCache() { this._cache.clear(); }
|
||||
|
||||
@ -118,9 +112,13 @@ export class ProtoViewFactory {
|
||||
}
|
||||
|
||||
private _flattenPipes(view: ViewMetadata): any[] {
|
||||
if (isBlank(view.pipes)) return this._defaultPipes;
|
||||
var pipes = ListWrapper.clone(this._defaultPipes);
|
||||
_flattenList(view.pipes, pipes);
|
||||
let pipes = [];
|
||||
if (isPresent(this._ambientPipes)) {
|
||||
_flattenArray(this._ambientPipes, pipes);
|
||||
}
|
||||
if (isPresent(view.pipes)) {
|
||||
_flattenArray(view.pipes, pipes);
|
||||
}
|
||||
return pipes;
|
||||
}
|
||||
}
|
||||
@ -313,11 +311,11 @@ function arrayToMap(arr: string[], inverse: boolean): Map<string, string> {
|
||||
return result;
|
||||
}
|
||||
|
||||
function _flattenList(tree: any[], out: Array<Type | Provider | any[]>): void {
|
||||
function _flattenArray(tree: any[], out: Array<Type | Provider | any[]>): void {
|
||||
for (var i = 0; i < tree.length; i++) {
|
||||
var item = resolveForwardRef(tree[i]);
|
||||
if (isArray(item)) {
|
||||
_flattenList(item, out);
|
||||
_flattenArray(item, out);
|
||||
} else {
|
||||
out.push(item);
|
||||
}
|
||||
|
@ -3,12 +3,31 @@
|
||||
* @description
|
||||
* This module provides a set of common Pipes.
|
||||
*/
|
||||
import {AsyncPipe} from './pipes/async_pipe';
|
||||
import {UpperCasePipe} from './pipes/uppercase_pipe';
|
||||
import {LowerCasePipe} from './pipes/lowercase_pipe';
|
||||
import {JsonPipe} from './pipes/json_pipe';
|
||||
import {SlicePipe} from './pipes/slice_pipe';
|
||||
import {DatePipe} from './pipes/date_pipe';
|
||||
import {DecimalPipe, PercentPipe, CurrencyPipe} from './pipes/number_pipe';
|
||||
import {CONST_EXPR} from 'angular2/src/core/facade/lang';
|
||||
|
||||
export {AsyncPipe} from './pipes/async_pipe';
|
||||
export {DatePipe} from './pipes/date_pipe';
|
||||
export {DEFAULT_PIPES, DEFAULT_PIPES_TOKEN} from './pipes/default_pipes';
|
||||
export {JsonPipe} from './pipes/json_pipe';
|
||||
export {SlicePipe} from './pipes/slice_pipe';
|
||||
export {LowerCasePipe} from './pipes/lowercase_pipe';
|
||||
export {NumberPipe, DecimalPipe, PercentPipe, CurrencyPipe} from './pipes/number_pipe';
|
||||
export {UpperCasePipe} from './pipes/uppercase_pipe';
|
||||
|
||||
export const COMMON_PIPES = CONST_EXPR([
|
||||
AsyncPipe,
|
||||
UpperCasePipe,
|
||||
LowerCasePipe,
|
||||
JsonPipe,
|
||||
SlicePipe,
|
||||
DecimalPipe,
|
||||
PercentPipe,
|
||||
CurrencyPipe,
|
||||
DatePipe
|
||||
]);
|
||||
|
@ -1,27 +0,0 @@
|
||||
import {AsyncPipe} from './async_pipe';
|
||||
import {UpperCasePipe} from './uppercase_pipe';
|
||||
import {LowerCasePipe} from './lowercase_pipe';
|
||||
import {JsonPipe} from './json_pipe';
|
||||
import {SlicePipe} from './slice_pipe';
|
||||
import {DatePipe} from './date_pipe';
|
||||
import {DecimalPipe, PercentPipe, CurrencyPipe} from './number_pipe';
|
||||
|
||||
import {CONST_EXPR} from 'angular2/src/core/facade/lang';
|
||||
import {Provider, OpaqueToken} from 'angular2/src/core/di';
|
||||
|
||||
const DEFAULT_PIPES_LIST = CONST_EXPR([
|
||||
AsyncPipe,
|
||||
UpperCasePipe,
|
||||
LowerCasePipe,
|
||||
JsonPipe,
|
||||
SlicePipe,
|
||||
DecimalPipe,
|
||||
PercentPipe,
|
||||
CurrencyPipe,
|
||||
DatePipe
|
||||
]);
|
||||
|
||||
export const DEFAULT_PIPES_TOKEN: OpaqueToken = CONST_EXPR(new OpaqueToken("Default Pipes"));
|
||||
|
||||
export const DEFAULT_PIPES: Provider =
|
||||
CONST_EXPR(new Provider(DEFAULT_PIPES_TOKEN, {useValue: DEFAULT_PIPES_LIST}));
|
Reference in New Issue
Block a user