153 lines
4.0 KiB
TypeScript
153 lines
4.0 KiB
TypeScript
/**
|
|
* @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 {Route, UrlMatchResult} from './config';
|
|
import {UrlSegment, UrlSegmentGroup} from './url_tree';
|
|
|
|
|
|
/**
|
|
* The primary routing outlet.
|
|
*
|
|
* @publicApi
|
|
*/
|
|
export const PRIMARY_OUTLET = 'primary';
|
|
|
|
/**
|
|
* A collection of matrix and query URL parameters.
|
|
* @see `convertToParamMap()`
|
|
* @see `ParamMap`
|
|
*
|
|
* @publicApi
|
|
*/
|
|
export type Params = {
|
|
[key: string]: any
|
|
};
|
|
|
|
/**
|
|
* A map that provides access to the required and optional parameters
|
|
* specific to a route.
|
|
* The map supports retrieving a single value with `get()`
|
|
* or multiple values with `getAll()`.
|
|
*
|
|
* @see [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
|
|
*
|
|
* @publicApi
|
|
*/
|
|
export interface ParamMap {
|
|
/**
|
|
* Reports whether the map contains a given parameter.
|
|
* @param name The parameter name.
|
|
* @returns True if the map contains the given parameter, false otherwise.
|
|
*/
|
|
has(name: string): boolean;
|
|
/**
|
|
* Retrieves a single value for a parameter.
|
|
* @param name The parameter name.
|
|
* @return The parameter's single value,
|
|
* or the first value if the parameter has multiple values,
|
|
* or `null` when there is no such parameter.
|
|
*/
|
|
get(name: string): string|null;
|
|
/**
|
|
* Retrieves multiple values for a parameter.
|
|
* @param name The parameter name.
|
|
* @return An array containing one or more values,
|
|
* or an empty array if there is no such parameter.
|
|
*
|
|
*/
|
|
getAll(name: string): string[];
|
|
|
|
/** Names of the parameters in the map. */
|
|
readonly keys: string[];
|
|
}
|
|
|
|
class ParamsAsMap implements ParamMap {
|
|
private params: Params;
|
|
|
|
constructor(params: Params) { this.params = params || {}; }
|
|
|
|
has(name: string): boolean { return this.params.hasOwnProperty(name); }
|
|
|
|
get(name: string): string|null {
|
|
if (this.has(name)) {
|
|
const v = this.params[name];
|
|
return Array.isArray(v) ? v[0] : v;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
getAll(name: string): string[] {
|
|
if (this.has(name)) {
|
|
const v = this.params[name];
|
|
return Array.isArray(v) ? v : [v];
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
get keys(): string[] { return Object.keys(this.params); }
|
|
}
|
|
|
|
/**
|
|
* Converts a `Params` instance to a `ParamMap`.
|
|
* @param params The instance to convert.
|
|
* @returns The new map instance.
|
|
*
|
|
* @publicApi
|
|
*/
|
|
export function convertToParamMap(params: Params): ParamMap {
|
|
return new ParamsAsMap(params);
|
|
}
|
|
|
|
const NAVIGATION_CANCELING_ERROR = 'ngNavigationCancelingError';
|
|
|
|
export function navigationCancelingError(message: string) {
|
|
const error = Error('NavigationCancelingError: ' + message);
|
|
(error as any)[NAVIGATION_CANCELING_ERROR] = true;
|
|
return error;
|
|
}
|
|
|
|
export function isNavigationCancelingError(error: Error) {
|
|
return error && (error as any)[NAVIGATION_CANCELING_ERROR];
|
|
}
|
|
|
|
// Matches the route configuration (`route`) against the actual URL (`segments`).
|
|
export function defaultUrlMatcher(
|
|
segments: UrlSegment[], segmentGroup: UrlSegmentGroup, route: Route): UrlMatchResult|null {
|
|
const parts = route.path !.split('/');
|
|
|
|
if (parts.length > segments.length) {
|
|
// The actual URL is shorter than the config, no match
|
|
return null;
|
|
}
|
|
|
|
if (route.pathMatch === 'full' &&
|
|
(segmentGroup.hasChildren() || parts.length < segments.length)) {
|
|
// The config is longer than the actual URL but we are looking for a full match, return null
|
|
return null;
|
|
}
|
|
|
|
const posParams: {[key: string]: UrlSegment} = {};
|
|
|
|
// Check each config part against the actual URL
|
|
for (let index = 0; index < parts.length; index++) {
|
|
const part = parts[index];
|
|
const segment = segments[index];
|
|
const isParameter = part.startsWith(':');
|
|
if (isParameter) {
|
|
posParams[part.substring(1)] = segment;
|
|
} else if (part !== segment.path) {
|
|
// The actual URL part does not match the config, no match
|
|
return null;
|
|
}
|
|
}
|
|
|
|
return {consumed: segments.slice(0, parts.length), posParams};
|
|
}
|