]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
fix(link): make alias of empty child active
authorEduardo San Martin Morote <posva13@gmail.com>
Wed, 29 Apr 2020 15:27:21 +0000 (17:27 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Wed, 29 Apr 2020 15:27:21 +0000 (17:27 +0200)
__tests__/RouterLink.spec.ts
playground/App.vue
playground/router.ts
src/RouterLink.ts

index fb627e0d78771cc86833ddf202f3863413e2f543..caadb7dd2f9b469ff3dc75103f34ef7cab003d0a 100644 (file)
@@ -20,7 +20,9 @@ const records = {
   foo: {} as RouteRecordNormalized,
   parent: {} as RouteRecordNormalized,
   childEmpty: {} as RouteRecordNormalized,
+  childEmptyAlias: {} as RouteRecordNormalized,
   child: {} as RouteRecordNormalized,
+  childChild: {} as RouteRecordNormalized,
   parentAlias: {} as RouteRecordNormalized,
   childAlias: {} as RouteRecordNormalized,
 }
@@ -31,6 +33,7 @@ records.parentAlias = {
   aliasOf: records.parent,
 } as RouteRecordNormalized
 records.childAlias = { aliasOf: records.child } as RouteRecordNormalized
+records.childEmptyAlias.aliasOf = records.childEmpty
 
 type RouteLocationResolved = RouteLocationNormalized & { href: string }
 
@@ -189,6 +192,21 @@ const locations = createLocations({
       name: undefined,
     },
   },
+  childEmptyAlias: {
+    string: '/parent/alias',
+    normalized: {
+      fullPath: '/parent/alias',
+      href: '/parent/alias',
+      path: '/parent/alias',
+      params: {},
+      meta: {},
+      query: {},
+      hash: '',
+      matched: [records.parent, records.childEmptyAlias],
+      redirectedFrom: undefined,
+      name: undefined,
+    },
+  },
   child: {
     string: '/parent/child',
     normalized: {
@@ -204,6 +222,21 @@ const locations = createLocations({
       name: undefined,
     },
   },
+  childChild: {
+    string: '/parent/child/child',
+    normalized: {
+      fullPath: '/parent/child/child',
+      href: '/parent/child/child',
+      path: '/parent/child/child',
+      params: {},
+      meta: {},
+      query: {},
+      hash: '',
+      matched: [records.parent, records.child, records.childChild],
+      redirectedFrom: undefined,
+      name: undefined,
+    },
+  },
   childAsAbsolute: {
     string: '/absolute-child',
     normalized: {
@@ -503,6 +536,42 @@ describe('RouterLink', () => {
     )
   })
 
+  it('alias of empty path child is active as if it was the parent when on adjacent child', async () => {
+    const { wrapper } = await factory(
+      locations.child.normalized,
+      { to: locations.childEmptyAlias.string },
+      locations.childEmptyAlias.normalized
+    )
+    expect(wrapper.find('a')!.className).toContain('router-link-active')
+    expect(wrapper.find('a')!.className).not.toContain(
+      'router-link-exact-active'
+    )
+  })
+
+  it('empty path child is active as if it was the parent when on adjacent nested child', async () => {
+    const { wrapper } = await factory(
+      locations.childChild.normalized,
+      { to: locations.childEmpty.string },
+      locations.childEmpty.normalized
+    )
+    expect(wrapper.find('a')!.className).toContain('router-link-active')
+    expect(wrapper.find('a')!.className).not.toContain(
+      'router-link-exact-active'
+    )
+  })
+
+  it('alias of empty path child is active as if it was the parent when on adjacent nested nested child', async () => {
+    const { wrapper } = await factory(
+      locations.childChild.normalized,
+      { to: locations.childEmptyAlias.string },
+      locations.childEmptyAlias.normalized
+    )
+    expect(wrapper.find('a')!.className).toContain('router-link-active')
+    expect(wrapper.find('a')!.className).not.toContain(
+      'router-link-exact-active'
+    )
+  })
+
   it('alias parent is active if the child is an absolute path', async () => {
     const { wrapper } = await factory(
       locations.childAsAbsolute.normalized,
index 95bdf45cae5cb16579ebec7ce5d8f4709f115329..aca3f94a0f5fb3aee7dc9c9ea4c8413d0d99eb0b 100644 (file)
@@ -72,6 +72,9 @@
       <li>
         <router-link to="/children">/children</router-link>
       </li>
+      <li>
+        <router-link to="/children/alias">/children/alias</router-link>
+      </li>
       <li>
         <router-link :to="{ name: 'default-child' }"
           >/children (child named)</router-link
       <li>
         <router-link to="/children/b">/children/b</router-link>
       </li>
+      <li>
+        <router-link to="/children/b/a2">/children/b/a2</router-link>
+      </li>
+      <li>
+        <router-link to="/children/b/b2">/children/b/b2</router-link>
+      </li>
       <li>
         <router-link to="/nested">/nested</router-link>
       </li>
index d1ba49e31563249ae8f3c46969478015b10a337f..8c520fd1ff302e22b7941d4d4b955eb53006598b 100644 (file)
@@ -62,9 +62,18 @@ export const router = createRouter({
       name: 'WithChildren',
       component,
       children: [
-        { path: '', name: 'default-child', component },
+        { path: '', alias: 'alias', name: 'default-child', component },
         { path: 'a', name: 'a-child', component },
-        { path: 'b', name: 'b-child', component },
+        {
+          path: 'b',
+          name: 'b-child',
+          component,
+          children: [
+            { path: '', component },
+            { path: 'a2', component },
+            { path: 'b2', component },
+          ],
+        },
       ],
     },
     { path: '/with-data', component: ComponentWithData, name: 'WithData' },
index 21829e28afe8c0923404c62cd6e245a77ff142e0..189c93a2b22344edc2af32d75128e2d1ab230338 100644 (file)
@@ -40,19 +40,22 @@ export function useLink(props: UseLinkOptions) {
     )
     if (index > -1) return index
     // possible parent record
-    let parentRecord = matched[length - 2]
-    if (
+    let parentRecordPath = getOriginalPath(
+      matched[length - 2] as RouteRecord | undefined
+    )
+    return (
+      // we are dealing with nested routes
       length > 1 &&
-      // if the have the same path, this link is referring to the empty child
-      // are we currently are on a different child of the same parent
-      routeMatched.path === parentRecord.path &&
-      // avoid comparing the child with its parent
-      currentMatched[currentMatched.length - 1].path !== parentRecord.path
+        // if the have the same path, this link is referring to the empty child
+        // are we currently are on a different child of the same parent
+        getOriginalPath(routeMatched) === parentRecordPath &&
+        // avoid comparing the child with its parent
+        currentMatched[currentMatched.length - 1].path !== parentRecordPath
+        ? currentMatched.findIndex(
+            isSameRouteRecord.bind(null, matched[length - 2])
+          )
+        : index
     )
-      return currentMatched.findIndex(
-        isSameRouteRecord.bind(null, matched[length - 2])
-      )
-    return index
   })
 
   const isActive = computed<boolean>(
@@ -168,3 +171,11 @@ function includesParams(
 
   return true
 }
+
+/**
+ * Get the original path value of a record by following its aliasOf
+ * @param record
+ */
+function getOriginalPath(record: RouteRecord | undefined): string {
+  return record ? (record.aliasOf ? record.aliasOf.path : record.path) : ''
+}