Skip to content

Commit

Permalink
fix(link): non active repeatable params
Browse files Browse the repository at this point in the history
  • Loading branch information
posva committed Feb 28, 2020
1 parent 353d34e commit 0ccbc1e
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 36 deletions.
46 changes: 46 additions & 0 deletions __tests__/RouterLink.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,34 @@ const locations: Record<
name: undefined,
},
},
repeatedParams2: {
string: '/p/1/2',
normalized: {
fullPath: '/p/1/2',
path: '/p/1/2',
params: { p: ['1', '2'] },
meta: {},
query: {},
hash: '',
matched: [records.home],
redirectedFrom: undefined,
name: undefined,
},
},
repeatedParams3: {
string: '/p/1/2/3',
normalized: {
fullPath: '/p/1/2/3',
path: '/p/1/2/3',
params: { p: ['1', '2', '3'] },
meta: {},
query: {},
hash: '',
matched: [records.home],
redirectedFrom: undefined,
name: undefined,
},
},
}

describe('RouterLink', () => {
Expand Down Expand Up @@ -143,6 +171,24 @@ describe('RouterLink', () => {
expect(el.querySelector('a')!.className).toContain('router-link-active')
})

it('is not active with more repeated params', () => {
const { el } = factory(
locations.repeatedParams2.normalized,
{ to: locations.repeatedParams3.string },
locations.repeatedParams3.normalized
)
expect(el.querySelector('a')!.className).toBe('')
})

it('is not active with partial repeated params', () => {
const { el } = factory(
locations.repeatedParams3.normalized,
{ to: locations.repeatedParams2.string },
locations.repeatedParams2.normalized
)
expect(el.querySelector('a')!.className).toBe('')
})

it.todo('can be active as an alias')
it.todo('can be exact-active as an alias')
it.todo('is active when a child is active')
Expand Down
46 changes: 46 additions & 0 deletions __tests__/router.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,52 @@ describe('Router', () => {
})
})

it('can reroute to a replaced route with the same component', async () => {
const { router } = await newRouter()
router.addRoute({
path: '/new/foo',
component: components.Foo,
name: 'new',
})
// navigate to the route we just added
await router.replace({ name: 'new' })
// replace it
router.addRoute({
path: '/new/bar',
component: components.Foo,
name: 'new',
})
// navigate again
await router.replace({ name: 'new' })
expect(router.currentRoute.value).toMatchObject({
path: '/new/bar',
name: 'new',
})
})

it('can reroute to child', async () => {
const { router } = await newRouter()
router.addRoute({
path: '/new',
component: components.Foo,
children: [],
name: 'new',
})
// navigate to the route we just added
await router.replace('/new/child')
// replace it
router.addRoute('new', {
path: 'child',
component: components.Bar,
name: 'new-child',
})
// navigate again
await router.replace('/new/child')
expect(router.currentRoute.value).toMatchObject({
name: 'new-child',
})
})

it('can reroute when adding a new route', async () => {
const { router } = await newRouter()
await router.push('/p/p')
Expand Down
9 changes: 9 additions & 0 deletions playground/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,15 @@
>/docs/é</router-link
>
</li>
<li>
<router-link to="/rep">/rep</router-link>
</li>
<li>
<router-link to="/rep/a">/rep/a</router-link>
</li>
<li>
<router-link to="/rep/a/b">/rep/a/b</router-link>
</li>
</ul>
<!-- <transition
name="fade"
Expand Down
54 changes: 23 additions & 31 deletions src/components/Link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ import {
unref,
} from 'vue'
import { RouteLocation, RouteLocationNormalized, Immutable } from '../types'
import { isSameLocationObject } from '../utils'
import { isSameLocationObject, isSameRouteRecord } from '../utils'
import { routerKey } from '../injectKeys'
import { RouteRecordNormalized } from '../matcher/types'

type VueUseOptions<T> = {
[k in keyof T]: Ref<T[k]> | T[k]
Expand All @@ -25,35 +24,6 @@ interface LinkProps {

type UseLinkOptions = VueUseOptions<LinkProps>

function isSameRouteRecord(
a: Immutable<RouteRecordNormalized>,
b: Immutable<RouteRecordNormalized>
): boolean {
// TODO: handle aliases
return a === b
}

function includesParams(
outter: Immutable<RouteLocationNormalized['params']>,
inner: Immutable<RouteLocationNormalized['params']>
): boolean {
for (let key in inner) {
let innerValue = inner[key]
let outterValue = outter[key]
if (typeof innerValue === 'string') {
if (innerValue !== outterValue) return false
} else {
if (
!Array.isArray(outterValue) ||
innerValue.some((value, i) => value !== outterValue[i])
)
return false
}
}

return true
}

export function useLink(props: UseLinkOptions) {
const router = inject(routerKey)!

Expand Down Expand Up @@ -147,3 +117,25 @@ function guardEvent(e: MouseEvent) {

return true
}

function includesParams(
outter: Immutable<RouteLocationNormalized['params']>,
inner: Immutable<RouteLocationNormalized['params']>
): boolean {
for (let key in inner) {
let innerValue = inner[key]
let outterValue = outter[key]
if (typeof innerValue === 'string') {
if (innerValue !== outterValue) return false
} else {
if (
!Array.isArray(outterValue) ||
outterValue.length !== innerValue.length ||
innerValue.some((value, i) => value !== outterValue[i])
)
return false
}
}

return true
}
8 changes: 5 additions & 3 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
guardToPromiseFn,
isSameLocationObject,
applyToParams,
isSameRouteRecord,
} from './utils'
import { useCallbacks } from './utils/callbacks'
import { encodeParam, decode } from './utils/encoding'
Expand Down Expand Up @@ -177,7 +178,7 @@ export function createRouter({
path: matchedRoute.path,
}),
hash: location.hash || '',
query: normalizeQuery(location.query || {}),
query: normalizeQuery(location.query),
...matchedRoute,
redirectedFrom: undefined,
}
Expand All @@ -197,7 +198,6 @@ export function createRouter({
const force: boolean | undefined = to.force

// TODO: should we throw an error as the navigation was aborted
// TODO: needs a proper check because order in query could be different
if (!force && isSameLocation(from, toLocation)) return from

toLocation.redirectedFrom = redirectedFrom
Expand Down Expand Up @@ -543,6 +543,8 @@ function isSameLocation(
a.name === b.name &&
a.path === b.path &&
a.hash === b.hash &&
isSameLocationObject(a.query, b.query)
isSameLocationObject(a.query, b.query) &&
a.matched.length === b.matched.length &&
a.matched.every((record, i) => isSameRouteRecord(record, b.matched[i]))
)
}
13 changes: 12 additions & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ export function applyToParams(
return newParams
}

export function isSameRouteRecord(
a: Immutable<RouteRecordNormalized>,
b: Immutable<RouteRecordNormalized>
): boolean {
// TODO: handle aliases
return a === b
}

export function isSameLocationObject(
a: Immutable<RouteLocationNormalized['query']>,
b: Immutable<RouteLocationNormalized['query']>
Expand Down Expand Up @@ -97,6 +105,9 @@ function isSameLocationObjectValue(
if (typeof a !== typeof b) return false
// both a and b are arrays
if (Array.isArray(a))
return a.every((value, i) => value === (b as LocationQueryValue[])[i])
return (
a.length === (b as any[]).length &&
a.every((value, i) => value === (b as LocationQueryValue[])[i])
)
return a === b
}
4 changes: 3 additions & 1 deletion src/utils/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ export function stringifyQuery(query: LocationQueryRaw): string {
* null in arrays
* @param query
*/
export function normalizeQuery(query: LocationQueryRaw): LocationQuery {
export function normalizeQuery(
query: LocationQueryRaw | undefined
): LocationQuery {
const normalizedQuery: LocationQuery = {}

for (let key in query) {
Expand Down

0 comments on commit 0ccbc1e

Please sign in to comment.