Skip to content

Commit

Permalink
feat(QTabs): enhance updateActiveRoute algorithm -- now has queryScor…
Browse files Browse the repository at this point in the history
…e too
  • Loading branch information
rstoenescu committed Oct 1, 2022
1 parent e0c43f7 commit 0c77106
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 21 deletions.
15 changes: 13 additions & 2 deletions ui/dev/src/pages/components/tabs-router.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
</q-item>
</div>

<q-item class="special-router-link" replace :to="{ query: { tab: '3', noScroll: true, y: '5' } }" active-class="special-router-link--active" exact-active-class="special-router-link--exact-active">
<q-item-section>3 + y=5</q-item-section>
</q-item>

<div class="col-12">Route query {{ $route.query }}</div>
</div>

Expand Down Expand Up @@ -62,8 +66,15 @@ export default {
},
navRedirect (e, go) {
e.navigate = false // we cancel the default navigation
go({ query: { tab: '2', noScroll: true } })
e.preventDefault()
go({
to: { query: { tab: '2', noScroll: true } }
})
// this is equivalent & and it should still work:
//
// e.navigate = false // we cancel the default navigation
// go({ query: { tab: '2', noScroll: true } })
},
navPass () {},
Expand Down
72 changes: 53 additions & 19 deletions ui/src/components/tabs/QTabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { slot } from '../../utils/private/slot.js'
import cache from '../../utils/private/cache.js'
import { rtlHasScrollBug } from '../../utils/scroll.js'
import { injectProp } from '../../utils/private/inject-obj-prop.js'
import { isDeepEqual } from '../../utils/is.js'

function getIndicatorClass (color, top, vertical) {
const pos = vertical === true
Expand All @@ -21,7 +22,19 @@ function getIndicatorClass (color, top, vertical) {
}

const alignValues = [ 'left', 'center', 'right', 'justify' ]
const getDefaultBestScore = () => ({ matchedLen: 0, hrefLen: 0, exact: false, redirected: true })
const getDefaultBestScore = () => ({ matchedLen: 0, queryScore: 0, hrefLen: 0, exact: false, redirected: true })

function getQueryScore (targetQuery, matchingQuery) {
let score = 0

for (const key in targetQuery) {
if (isDeepEqual(targetQuery[ key ], matchingQuery[ key ]) === true) {
score++
}
}

return score
}

export default Vue.extend({
name: 'QTabs',
Expand Down Expand Up @@ -434,7 +447,7 @@ export default Vue.extend({

// do not use directly; use __verifyRouteModel() instead
__updateActiveRoute () {
let name = null, best = getDefaultBestScore()
let name = null, bestScore = getDefaultBestScore()
const vmList = this.tabVmList.filter(tab => tab.hasRouterLink === true)
const vmLen = vmList.length

Expand All @@ -447,13 +460,13 @@ export default Vue.extend({
// then we don't deal with it
if (
tab[ exact === true ? 'linkIsExactActive' : 'linkIsActive' ] !== true ||
(best.exact === true && exact !== true)
(bestScore.exact === true && exact !== true)
) {
continue
}

const { route, href } = tab.resolvedLink
const { hash, matched } = route
const { hash, matched, query } = route
const redirected = route.redirectedFrom !== void 0

if (exact === true) {
Expand All @@ -463,34 +476,55 @@ export default Vue.extend({
break
}

if (best.exact === false) {
if (bestScore.exact === false) {
// we reset values so we can discard previous non-exact matches
// and so we can register this exact one below
best = getDefaultBestScore()
bestScore = getDefaultBestScore()
}
}

// if best is non-redirected and this one is redirected
// then this one is inferior so we don't care about it
if (best.redirected === false && redirected === true) {
if (bestScore.redirected === false && redirected === true) {
continue
}

const matchedLen = matched.length
const hrefLen = href.length - hash.length
const newScore = {
exact,
redirected,
matchedLen: matched.length,
queryScore: exact === true
? 0 // avoid computing as it's maximum anyway
: getQueryScore(query, this.$route.query),
hrefLen: href.length - hash.length
}

// if it has better score
if (
// tab.exact might be set to false in userland,
// but this is an exact match! so it should have higher priority
(exact === false && tab.linkIsExactActive === true) ||
if (newScore.matchedLen > bestScore.matchedLen) {
// it matches more routes so it's more specific so we set it as current champion
name = tab.name
bestScore = newScore
continue
}
else if (newScore.matchedLen !== bestScore.matchedLen) {
// it matches less routes than the current champion so we discard it
continue
}

(matchedLen === best.matchedLen
? hrefLen > best.hrefLen
: matchedLen > best.matchedLen)
) {
if (newScore.queryScore > bestScore.queryScore) {
// query is closer to the current one so we set it as current champion
name = tab.name
bestScore = newScore
continue
}
else if (newScore.queryScore !== bestScore.queryScore) {
// query is farther away than current champion so we discard it
continue
}

if (newScore.hrefLen > bestScore.hrefLen) {
// href is lengthier so it's more specific so we set it as current champion
name = tab.name
best = { matchedLen, hrefLen, exact, redirected }
bestScore = newScore
}
}

Expand Down

0 comments on commit 0c77106

Please sign in to comment.