refactor: move angular source to /packages rather than modules/@angular

This commit is contained in:
Jason Aden
2017-03-02 10:48:42 -08:00
parent 5ad5301a3e
commit 3e51a19983
1051 changed files with 18 additions and 18 deletions

View File

@ -0,0 +1,248 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {LocationStrategy} from '@angular/common';
import {Attribute, Directive, ElementRef, HostBinding, HostListener, Input, OnChanges, OnDestroy, Renderer, isDevMode} from '@angular/core';
import {Subscription} from 'rxjs/Subscription';
import {QueryParamsHandling} from '../config';
import {NavigationEnd} from '../events';
import {Router} from '../router';
import {ActivatedRoute} from '../router_state';
import {UrlTree} from '../url_tree';
/**
* @whatItDoes Lets you link to specific parts of your app.
*
* @howToUse
*
* Consider the following route configuration:
* `[{ path: 'user/:name', component: UserCmp }]`
*
* When linking to this `user/:name` route, you can write:
* `<a routerLink='/user/bob'>link to user component</a>`
*
* @description
*
* The RouterLink directives let you link to specific parts of your app.
*
* When the link is static, you can use the directive as follows:
* `<a routerLink="/user/bob">link to user component</a>`
*
* If you use dynamic values to generate the link, you can pass an array of path
* segments, followed by the params for each segment.
*
* For instance `['/team', teamId, 'user', userName, {details: true}]`
* means that we want to generate a link to `/team/11/user/bob;details=true`.
*
* Multiple static segments can be merged into one
* (e.g., `['/team/11/user', userName, {details: true}]`).
*
* The first segment name can be prepended with `/`, `./`, or `../`:
* * If the first segment begins with `/`, the router will look up the route from the root of the
* app.
* * If the first segment begins with `./`, or doesn't begin with a slash, the router will
* instead look in the children of the current activated route.
* * And if the first segment begins with `../`, the router will go up one level.
*
* You can set query params and fragment as follows:
*
* ```
* <a [routerLink]="['/user/bob']" [queryParams]="{debug: true}" fragment="education">
* link to user component
* </a>
* ```
* RouterLink will use these to generate this link: `/user/bob#education?debug=true`.
*
* (Deprecated in v4.0.0 use `queryParamsHandling` instead) You can also tell the
* directive to preserve the current query params and fragment:
*
* ```
* <a [routerLink]="['/user/bob']" preserveQueryParams preserveFragment>
* link to user component
* </a>
* ```
*
* You can tell the directive to how to handle queryParams, available options are:
* - 'merge' merge the queryParams into the current queryParams
* - 'preserve' prserve the current queryParams
* - default / '' use the queryParams only
* same options for {@link NavigationExtras.queryParamsHandling}
*
* ```
* <a [routerLink]="['/user/bob']" [queryParams]="{debug: true}" queryParamsHandling="merge">
* link to user component
* </a>
* ```
*
* The router link directive always treats the provided input as a delta to the current url.
*
* For instance, if the current url is `/user/(box//aux:team)`.
*
* Then the following link `<a [routerLink]="['/user/jim']">Jim</a>` will generate the link
* `/user/(jim//aux:team)`.
*
* @ngModule RouterModule
*
* See {@link Router.createUrlTree} for more information.
*
* @stable
*/
@Directive({selector: ':not(a)[routerLink]'})
export class RouterLink {
@Input() queryParams: {[k: string]: any};
@Input() fragment: string;
@Input() queryParamsHandling: QueryParamsHandling;
@Input() preserveFragment: boolean;
@Input() skipLocationChange: boolean;
@Input() replaceUrl: boolean;
private commands: any[] = [];
private preserve: boolean;
constructor(
private router: Router, private route: ActivatedRoute,
@Attribute('tabindex') tabIndex: string, renderer: Renderer, el: ElementRef) {
if (tabIndex == null) {
renderer.setElementAttribute(el.nativeElement, 'tabindex', '0');
}
}
@Input()
set routerLink(commands: any[]|string) {
if (commands != null) {
this.commands = Array.isArray(commands) ? commands : [commands];
} else {
this.commands = [];
}
}
/**
* @deprecated 4.0.0 use `queryParamsHandling` instead.
*/
@Input()
set preserveQueryParams(value: boolean) {
if (isDevMode() && <any>console && <any>console.warn) {
console.warn('preserveQueryParams is deprecated!, use queryParamsHandling instead.');
}
this.preserve = value;
}
@HostListener('click')
onClick(): boolean {
const extras = {
skipLocationChange: attrBoolValue(this.skipLocationChange),
replaceUrl: attrBoolValue(this.replaceUrl),
};
this.router.navigateByUrl(this.urlTree, extras);
return true;
}
get urlTree(): UrlTree {
return this.router.createUrlTree(this.commands, {
relativeTo: this.route,
queryParams: this.queryParams,
fragment: this.fragment,
preserveQueryParams: attrBoolValue(this.preserve),
queryParamsHandling: this.queryParamsHandling,
preserveFragment: attrBoolValue(this.preserveFragment),
});
}
}
/**
* @whatItDoes Lets you link to specific parts of your app.
*
* See {@link RouterLink} for more information.
*
* @ngModule RouterModule
*
* @stable
*/
@Directive({selector: 'a[routerLink]'})
export class RouterLinkWithHref implements OnChanges, OnDestroy {
@HostBinding('attr.target') @Input() target: string;
@Input() queryParams: {[k: string]: any};
@Input() fragment: string;
@Input() queryParamsHandling: QueryParamsHandling;
@Input() preserveFragment: boolean;
@Input() skipLocationChange: boolean;
@Input() replaceUrl: boolean;
private commands: any[] = [];
private subscription: Subscription;
private preserve: boolean;
// the url displayed on the anchor element.
@HostBinding() href: string;
constructor(
private router: Router, private route: ActivatedRoute,
private locationStrategy: LocationStrategy) {
this.subscription = router.events.subscribe(s => {
if (s instanceof NavigationEnd) {
this.updateTargetUrlAndHref();
}
});
}
@Input()
set routerLink(commands: any[]|string) {
if (commands != null) {
this.commands = Array.isArray(commands) ? commands : [commands];
} else {
this.commands = [];
}
}
@Input()
set preserveQueryParams(value: boolean) {
if (isDevMode() && <any>console && <any>console.warn) {
console.warn('preserveQueryParams is deprecated, use queryParamsHandling instead.');
}
this.preserve = value;
}
ngOnChanges(changes: {}): any { this.updateTargetUrlAndHref(); }
ngOnDestroy(): any { this.subscription.unsubscribe(); }
@HostListener('click', ['$event.button', '$event.ctrlKey', '$event.metaKey'])
onClick(button: number, ctrlKey: boolean, metaKey: boolean): boolean {
if (button !== 0 || ctrlKey || metaKey) {
return true;
}
if (typeof this.target === 'string' && this.target != '_self') {
return true;
}
const extras = {
skipLocationChange: attrBoolValue(this.skipLocationChange),
replaceUrl: attrBoolValue(this.replaceUrl),
};
this.router.navigateByUrl(this.urlTree, extras);
return false;
}
private updateTargetUrlAndHref(): void {
this.href = this.locationStrategy.prepareExternalUrl(this.router.serializeUrl(this.urlTree));
}
get urlTree(): UrlTree {
return this.router.createUrlTree(this.commands, {
relativeTo: this.route,
queryParams: this.queryParams,
fragment: this.fragment,
preserveQueryParams: attrBoolValue(this.preserve),
queryParamsHandling: this.queryParamsHandling,
preserveFragment: attrBoolValue(this.preserveFragment),
});
}
}
function attrBoolValue(s: any): boolean {
return s === '' || !!s;
}

View File

@ -0,0 +1,142 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {AfterContentInit, ChangeDetectorRef, ContentChildren, Directive, ElementRef, Input, OnChanges, OnDestroy, QueryList, Renderer, SimpleChanges} from '@angular/core';
import {Subscription} from 'rxjs/Subscription';
import {NavigationEnd} from '../events';
import {Router} from '../router';
import {RouterLink, RouterLinkWithHref} from './router_link';
/**
* @whatItDoes Lets you add a CSS class to an element when the link's route becomes active.
*
* @howToUse
*
* ```
* <a routerLink="/user/bob" routerLinkActive="active-link">Bob</a>
* ```
*
* @description
*
* The RouterLinkActive directive lets you add a CSS class to an element when the link's route
* becomes active.
*
* Consider the following example:
*
* ```
* <a routerLink="/user/bob" routerLinkActive="active-link">Bob</a>
* ```
*
* When the url is either '/user' or '/user/bob', the active-link class will
* be added to the `a` tag. If the url changes, the class will be removed.
*
* You can set more than one class, as follows:
*
* ```
* <a routerLink="/user/bob" routerLinkActive="class1 class2">Bob</a>
* <a routerLink="/user/bob" [routerLinkActive]="['class1', 'class2']">Bob</a>
* ```
*
* You can configure RouterLinkActive by passing `exact: true`. This will add the classes
* only when the url matches the link exactly.
*
* ```
* <a routerLink="/user/bob" routerLinkActive="active-link" [routerLinkActiveOptions]="{exact:
* true}">Bob</a>
* ```
*
* You can assign the RouterLinkActive instance to a template variable and directly check
* the `isActive` status.
* ```
* <a routerLink="/user/bob" routerLinkActive #rla="routerLinkActive">
* Bob {{ rla.isActive ? '(already open)' : ''}}
* </a>
* ```
*
* Finally, you can apply the RouterLinkActive directive to an ancestor of a RouterLink.
*
* ```
* <div routerLinkActive="active-link" [routerLinkActiveOptions]="{exact: true}">
* <a routerLink="/user/jim">Jim</a>
* <a routerLink="/user/bob">Bob</a>
* </div>
* ```
*
* This will set the active-link class on the div tag if the url is either '/user/jim' or
* '/user/bob'.
*
* @ngModule RouterModule
*
* @stable
*/
@Directive({
selector: '[routerLinkActive]',
exportAs: 'routerLinkActive',
})
export class RouterLinkActive implements OnChanges,
OnDestroy, AfterContentInit {
@ContentChildren(RouterLink, {descendants: true}) links: QueryList<RouterLink>;
@ContentChildren(RouterLinkWithHref, {descendants: true})
linksWithHrefs: QueryList<RouterLinkWithHref>;
private classes: string[] = [];
private subscription: Subscription;
private active: boolean = false;
@Input() routerLinkActiveOptions: {exact: boolean} = {exact: false};
constructor(
private router: Router, private element: ElementRef, private renderer: Renderer,
private cdr: ChangeDetectorRef) {
this.subscription = router.events.subscribe(s => {
if (s instanceof NavigationEnd) {
this.update();
}
});
}
get isActive(): boolean { return this.active; }
ngAfterContentInit(): void {
this.links.changes.subscribe(_ => this.update());
this.linksWithHrefs.changes.subscribe(_ => this.update());
this.update();
}
@Input()
set routerLinkActive(data: string[]|string) {
const classes = Array.isArray(data) ? data : data.split(' ');
this.classes = classes.filter(c => !!c);
}
ngOnChanges(changes: SimpleChanges): void { this.update(); }
ngOnDestroy(): void { this.subscription.unsubscribe(); }
private update(): void {
if (!this.links || !this.linksWithHrefs || !this.router.navigated) return;
const hasActiveLinks = this.hasActiveLinks();
// react only when status has changed to prevent unnecessary dom updates
if (this.active !== hasActiveLinks) {
this.active = hasActiveLinks;
this.classes.forEach(
c => this.renderer.setElementClass(this.element.nativeElement, c, hasActiveLinks));
this.cdr.detectChanges();
}
}
private isLinkActive(router: Router): (link: (RouterLink|RouterLinkWithHref)) => boolean {
return (link: RouterLink | RouterLinkWithHref) =>
router.isActive(link.urlTree, this.routerLinkActiveOptions.exact);
}
private hasActiveLinks(): boolean {
return this.links.some(this.isLinkActive(this.router)) ||
this.linksWithHrefs.some(this.isLinkActive(this.router));
}
}

View File

@ -0,0 +1,113 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Attribute, ComponentFactoryResolver, ComponentRef, Directive, EventEmitter, Injector, OnDestroy, Output, ReflectiveInjector, ResolvedReflectiveProvider, ViewContainerRef} from '@angular/core';
import {RouterOutletMap} from '../router_outlet_map';
import {ActivatedRoute} from '../router_state';
import {PRIMARY_OUTLET} from '../shared';
/**
* @whatItDoes Acts as a placeholder that Angular dynamically fills based on the current router
* state.
*
* @howToUse
*
* ```
* <router-outlet></router-outlet>
* <router-outlet name='left'></router-outlet>
* <router-outlet name='right'></router-outlet>
* ```
*
* A router outlet will emit an activate event any time a new component is being instantiated,
* and a deactivate event when it is being destroyed.
*
* ```
* <router-outlet
* (activate)='onActivate($event)'
* (deactivate)='onDeactivate($event)'></router-outlet>
* ```
* @ngModule RouterModule
*
* @stable
*/
@Directive({selector: 'router-outlet'})
export class RouterOutlet implements OnDestroy {
private activated: ComponentRef<any>;
private _activatedRoute: ActivatedRoute;
public outletMap: RouterOutletMap;
@Output('activate') activateEvents = new EventEmitter<any>();
@Output('deactivate') deactivateEvents = new EventEmitter<any>();
constructor(
private parentOutletMap: RouterOutletMap, private location: ViewContainerRef,
private resolver: ComponentFactoryResolver, @Attribute('name') private name: string) {
parentOutletMap.registerOutlet(name ? name : PRIMARY_OUTLET, this);
}
ngOnDestroy(): void { this.parentOutletMap.removeOutlet(this.name ? this.name : PRIMARY_OUTLET); }
get locationInjector(): Injector { return this.location.injector; }
get locationFactoryResolver(): ComponentFactoryResolver { return this.resolver; }
get isActivated(): boolean { return !!this.activated; }
get component(): Object {
if (!this.activated) throw new Error('Outlet is not activated');
return this.activated.instance;
}
get activatedRoute(): ActivatedRoute {
if (!this.activated) throw new Error('Outlet is not activated');
return this._activatedRoute;
}
detach(): ComponentRef<any> {
if (!this.activated) throw new Error('Outlet is not activated');
this.location.detach();
const r = this.activated;
this.activated = null;
this._activatedRoute = null;
return r;
}
attach(ref: ComponentRef<any>, activatedRoute: ActivatedRoute) {
this.activated = ref;
this._activatedRoute = activatedRoute;
this.location.insert(ref.hostView);
}
deactivate(): void {
if (this.activated) {
const c = this.component;
this.activated.destroy();
this.activated = null;
this._activatedRoute = null;
this.deactivateEvents.emit(c);
}
}
activate(
activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver, injector: Injector,
providers: ResolvedReflectiveProvider[], outletMap: RouterOutletMap): void {
if (this.isActivated) {
throw new Error('Cannot activate an already activated outlet');
}
this.outletMap = outletMap;
this._activatedRoute = activatedRoute;
const snapshot = activatedRoute._futureSnapshot;
const component: any = <any>snapshot._routeConfig.component;
const factory = resolver.resolveComponentFactory(component);
const inj = ReflectiveInjector.fromResolvedProviders(providers, injector);
this.activated = this.location.createComponent(factory, this.location.length, inj, []);
this.activated.changeDetectorRef.detectChanges();
this.activateEvents.emit(this.activated.instance);
}
}