mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-11-09 16:16:41 +08:00
fix(router): popping route now accounts for route params (#24315)
This commit is contained in:
@ -30,15 +30,24 @@ const CHAIN_3: RouteChain = [
|
|||||||
describe('matchesIDs', () => {
|
describe('matchesIDs', () => {
|
||||||
it('should match simple set of ids', () => {
|
it('should match simple set of ids', () => {
|
||||||
const chain: RouteChain = CHAIN_1;
|
const chain: RouteChain = CHAIN_1;
|
||||||
expect(matchesIDs(['2'], chain)).toBe(1);
|
expect(matchesIDs([{ id: '2' }], chain)).toBe(1);
|
||||||
expect(matchesIDs(['2', '1'], chain)).toBe(2);
|
expect(matchesIDs([{ id: '2' }, { id: '1' }], chain)).toBe(2);
|
||||||
expect(matchesIDs(['2', '1', '3'], chain)).toBe(3);
|
expect(matchesIDs([{ id: '2' }, { id: '1' }, { id: '3' }], chain)).toBe(3);
|
||||||
expect(matchesIDs(['2', '1', '3', '4'], chain)).toBe(4);
|
expect(matchesIDs([{ id: '2' }, { id: '1' }, { id: '3' }, { id: '4' }], chain)).toBe(4);
|
||||||
expect(matchesIDs(['2', '1', '3', '4', '5'], chain)).toBe(4);
|
expect(matchesIDs([{ id: '2' }, { id: '1' }, { id: '3' }, { id: '4' }, { id: '5' }], chain)).toBe(4);
|
||||||
|
|
||||||
expect(matchesIDs([], chain)).toBe(0);
|
expect(matchesIDs([], chain)).toBe(0);
|
||||||
expect(matchesIDs(['1'], chain)).toBe(0);
|
expect(matchesIDs([{ id: '1' }], chain)).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should match path with params', () => {
|
||||||
|
const ids = [{ id: 'my-page', params: { s1: 'a', s2: 'b' } }];
|
||||||
|
|
||||||
|
expect(matchesIDs(ids, [{ id: 'my-page', path: [''], params: {} }])).toBe(1);
|
||||||
|
expect(matchesIDs(ids, [{ id: 'my-page', path: [':s1'], params: {} }])).toBe(1);
|
||||||
|
expect(matchesIDs(ids, [{ id: 'my-page', path: [':s1', ':s2'], params: {} }])).toBe(3);
|
||||||
|
expect(matchesIDs(ids, [{ id: 'my-page', path: [':s1', ':s2', ':s3'], params: {} }])).toBe(1);
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('matchesPath', () => {
|
describe('matchesPath', () => {
|
||||||
|
|||||||
@ -32,16 +32,60 @@ export const findRouteRedirect = (path: string[], redirects: RouteRedirect[]) =>
|
|||||||
return redirects.find(redirect => matchesRedirect(path, redirect));
|
return redirects.find(redirect => matchesRedirect(path, redirect));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const matchesIDs = (ids: string[], chain: RouteChain): number => {
|
export const matchesIDs = (ids: Pick<RouteID, 'id' | 'params'>[], chain: RouteChain): number => {
|
||||||
const len = Math.min(ids.length, chain.length);
|
const len = Math.min(ids.length, chain.length);
|
||||||
let i = 0;
|
|
||||||
for (; i < len; i++) {
|
let score = 0;
|
||||||
if (ids[i].toLowerCase() !== chain[i].id) {
|
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
const routeId = ids[i];
|
||||||
|
const routeChain = chain[i];
|
||||||
|
// Skip results where the route id does not match the chain at the same index
|
||||||
|
if (routeId.id.toLowerCase() !== routeChain.id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (routeId.params) {
|
||||||
|
const routeIdParams = Object.keys(routeId.params);
|
||||||
|
/**
|
||||||
|
* Only compare routes with the chain that have the same number of parameters.
|
||||||
|
*/
|
||||||
|
if (routeIdParams.length === routeChain.path.length) {
|
||||||
|
/**
|
||||||
|
* Maps the route's params into a path based on the path variable names,
|
||||||
|
* to compare against the route chain format.
|
||||||
|
*
|
||||||
|
* Before:
|
||||||
|
* ```ts
|
||||||
|
* {
|
||||||
|
* params: {
|
||||||
|
* s1: 'a',
|
||||||
|
* s2: 'b'
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* After:
|
||||||
|
* ```ts
|
||||||
|
* [':s1',':s2']
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
const pathWithParams = routeIdParams.map(key => `:${key}`);
|
||||||
|
for (let j = 0; j < pathWithParams.length; j++) {
|
||||||
|
// Skip results where the path variable is not a match
|
||||||
|
if (pathWithParams[j].toLowerCase() !== routeChain.path[j]) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// Weight path matches for the same index higher.
|
||||||
|
score++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Weight id matches
|
||||||
|
score++;
|
||||||
|
}
|
||||||
|
return score;
|
||||||
}
|
}
|
||||||
return i;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const matchesPath = (inputPath: string[], chain: RouteChain): RouteChain | null => {
|
export const matchesPath = (inputPath: string[], chain: RouteChain): RouteChain | null => {
|
||||||
const segments = new RouterSegments(inputPath);
|
const segments = new RouterSegments(inputPath);
|
||||||
@ -97,9 +141,9 @@ export const mergeParams = (a: {[key: string]: any} | undefined, b: {[key: strin
|
|||||||
export const routerIDsToChain = (ids: RouteID[], chains: RouteChain[]): RouteChain | null => {
|
export const routerIDsToChain = (ids: RouteID[], chains: RouteChain[]): RouteChain | null => {
|
||||||
let match: RouteChain | null = null;
|
let match: RouteChain | null = null;
|
||||||
let maxMatches = 0;
|
let maxMatches = 0;
|
||||||
const plainIDs = ids.map(i => i.id);
|
|
||||||
for (const chain of chains) {
|
for (const chain of chains) {
|
||||||
const score = matchesIDs(plainIDs, chain);
|
const score = matchesIDs(ids, chain);
|
||||||
if (score > maxMatches) {
|
if (score > maxMatches) {
|
||||||
match = chain;
|
match = chain;
|
||||||
maxMatches = score;
|
maxMatches = score;
|
||||||
|
|||||||
Reference in New Issue
Block a user