2016-06-23 12:47:54 -04:00
|
|
|
/**
|
|
|
|
* @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
|
|
|
|
*/
|
|
|
|
|
2016-11-09 18:25:47 -05:00
|
|
|
import {Route, UrlMatchResult} from './config';
|
|
|
|
import {UrlSegment, UrlSegmentGroup} from './url_tree';
|
|
|
|
|
|
|
|
|
2016-05-26 19:51:44 -04:00
|
|
|
/**
|
2018-04-05 06:51:21 -04:00
|
|
|
* @description
|
|
|
|
*
|
|
|
|
* Name of the primary outlet.
|
2016-06-27 15:27:23 -04:00
|
|
|
*
|
2018-04-05 17:31:44 -04:00
|
|
|
*
|
2016-05-26 19:51:44 -04:00
|
|
|
*/
|
2016-07-22 16:25:48 -04:00
|
|
|
export const PRIMARY_OUTLET = 'primary';
|
2016-05-26 19:51:44 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A collection of parameters.
|
2016-06-27 15:27:23 -04:00
|
|
|
*
|
2018-04-05 17:31:44 -04:00
|
|
|
*
|
2016-05-26 19:51:44 -04:00
|
|
|
*/
|
2016-06-08 14:13:41 -04:00
|
|
|
export type Params = {
|
2016-06-14 19:29:37 -04:00
|
|
|
[key: string]: any
|
2016-06-08 14:13:41 -04:00
|
|
|
};
|
2016-08-24 13:20:44 -04:00
|
|
|
|
2017-03-17 13:09:42 -04:00
|
|
|
/**
|
|
|
|
* Matrix and Query parameters.
|
|
|
|
*
|
|
|
|
* `ParamMap` makes it easier to work with parameters as they could have either a single value or
|
2017-03-22 20:14:11 -04:00
|
|
|
* multiple value. Because this should be known by the user, calling `get` or `getAll` returns the
|
2017-03-17 13:09:42 -04:00
|
|
|
* correct type (either `string` or `string[]`).
|
|
|
|
*
|
|
|
|
* The API is inspired by the URLSearchParams interface.
|
|
|
|
* see https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
|
|
|
|
*
|
2018-04-05 17:31:44 -04:00
|
|
|
*
|
2017-03-17 13:09:42 -04:00
|
|
|
*/
|
|
|
|
export interface ParamMap {
|
|
|
|
has(name: string): boolean;
|
|
|
|
/**
|
|
|
|
* Return a single value for the given parameter name:
|
|
|
|
* - the value when the parameter has a single value,
|
|
|
|
* - the first value if the parameter has multiple values,
|
|
|
|
* - `null` when there is no such parameter.
|
|
|
|
*/
|
|
|
|
get(name: string): string|null;
|
|
|
|
/**
|
|
|
|
* Return an array of values for the given parameter name.
|
|
|
|
*
|
|
|
|
* If there is no such parameter, an empty array is returned.
|
|
|
|
*/
|
|
|
|
getAll(name: string): string[];
|
2017-03-20 12:19:25 -04:00
|
|
|
|
|
|
|
/** Name of the parameters */
|
|
|
|
readonly keys: string[];
|
2017-03-17 13:09:42 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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 [];
|
|
|
|
}
|
2017-03-20 12:19:25 -04:00
|
|
|
|
|
|
|
get keys(): string[] { return Object.keys(this.params); }
|
2017-03-17 13:09:42 -04:00
|
|
|
}
|
|
|
|
|
2017-03-20 12:19:25 -04:00
|
|
|
/**
|
2018-04-05 06:53:57 -04:00
|
|
|
* Convert a `Params` instance to a `ParamMap`.
|
2017-03-20 12:19:25 -04:00
|
|
|
*
|
2018-04-05 17:31:44 -04:00
|
|
|
*
|
2017-03-20 12:19:25 -04:00
|
|
|
*/
|
2017-03-17 13:09:42 -04:00
|
|
|
export function convertToParamMap(params: Params): ParamMap {
|
|
|
|
return new ParamsAsMap(params);
|
|
|
|
}
|
|
|
|
|
2017-01-24 12:05:34 -05:00
|
|
|
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) {
|
2017-09-28 14:06:08 -04:00
|
|
|
return error && (error as any)[NAVIGATION_CANCELING_ERROR];
|
2016-08-25 03:50:16 -04:00
|
|
|
}
|
2016-11-09 18:25:47 -05:00
|
|
|
|
2017-04-02 20:21:56 -04:00
|
|
|
// Matches the route configuration (`route`) against the actual URL (`segments`).
|
2016-11-09 18:25:47 -05:00
|
|
|
export function defaultUrlMatcher(
|
2017-04-02 20:21:56 -04:00
|
|
|
segments: UrlSegment[], segmentGroup: UrlSegmentGroup, route: Route): UrlMatchResult|null {
|
2017-04-17 14:13:13 -04:00
|
|
|
const parts = route.path !.split('/');
|
2016-11-09 18:25:47 -05:00
|
|
|
|
2017-04-02 20:21:56 -04:00
|
|
|
if (parts.length > segments.length) {
|
|
|
|
// The actual URL is shorter than the config, no match
|
|
|
|
return null;
|
|
|
|
}
|
2016-11-09 18:25:47 -05:00
|
|
|
|
2017-04-02 20:21:56 -04:00
|
|
|
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;
|
|
|
|
}
|
2016-11-09 18:25:47 -05:00
|
|
|
|
2017-04-02 20:21:56 -04:00
|
|
|
const posParams: {[key: string]: UrlSegment} = {};
|
2016-11-09 18:25:47 -05:00
|
|
|
|
2017-04-02 20:21:56 -04:00
|
|
|
// 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;
|
2016-11-09 18:25:47 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-02 20:21:56 -04:00
|
|
|
return {consumed: segments.slice(0, parts.length), posParams};
|
2016-11-09 18:25:47 -05:00
|
|
|
}
|