Skip to content

Commit 3a4dd26

Browse files
pdanpdanrstoenescu
authored andcommitted
Fixes related to router-link and QRouteTab (quasarframework#1543)
* Fixes related to router-link and QRouteTab - add full set of props to the mixin - allow configurable (exact)activeClass for CSS - enhance QRouteTab selection workflow to eliminate duplicate selections and to match the most specific tab * Simplify priority sort function * Update QTabs.vue
1 parent a2f4175 commit 3a4dd26

File tree

11 files changed

+141
-44
lines changed

11 files changed

+141
-44
lines changed

dev/components/components/tabs-playground.vue

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,35 @@
3131
<q-tab default slot="title" label="Gigiiiiiiiii sdfsdfs aadsf asfsda" />
3232
</q-tabs>
3333

34+
<p class="caption">Router tabs</p>
35+
<div class="row gutter-xs justify-stretch">
36+
<div class="col-12 col-sm-6 col-md">
37+
<q-btn class="fit" size="sm" color="secondary" @click="$router.push('/tabs/a#123')" label="/tabs/a#123 - select most specific tab" />
38+
</div>
39+
<div class="col-12 col-sm-6 col-md">
40+
<q-btn class="fit" size="sm" color="secondary" @click="$router.push('/tabs/a/a#123')" label="/tabs/a/a#123 - select most specific tab" />
41+
</div>
42+
<div class="col-12 col-sm-6 col-md">
43+
<q-btn class="fit" size="sm" color="secondary" @click="$router.push('/tabs/a/a')" label="/tabs/b#123 - select exact tab" />
44+
</div>
45+
<div class="col-12 col-sm-6 col-md">
46+
<q-btn class="fit" size="sm" color="secondary" @click="$router.push('/tabs/b#123')" label="/tabs/b#123 - select no tab" />
47+
</div>
48+
</div>
49+
<q-tabs class="test q-mt-sm" @input="onEvent('input', 'route', $event)" @change="onEvent('change', 'route', $event)" @select="onEvent('select', 'route', $event)" @click="onEvent('click', 'route', $event)">
50+
<q-route-tab slot="title" name="tabs" to="/tabs" exact label="/tabs" />
51+
<q-route-tab slot="title" name="tabs/a" to="/tabs/a" exact label="/tabs/a" />
52+
<q-route-tab slot="title" name="tabs/a *" to="/tabs/a" label="/tabs/a *" />
53+
<q-route-tab slot="title" name="tabs/a#1" to="/tabs/a#1" exact label="/tabs/a#1" />
54+
<q-route-tab slot="title" name="tabs/a/a" to="/tabs/a/a" exact label="/tabs/a/a" />
55+
<q-route-tab slot="title" name="tabs/a/a *" to="/tabs/a/a" label="/tabs/a/a *" />
56+
<q-route-tab slot="title" name="tabs/a/a#1" to="/tabs/a/a#1" exact label="/tabs/a/a#1" />
57+
<q-route-tab slot="title" name="tabs/a/b" to="/tabs/a/b" exact label="/tabs/a/b" />
58+
<q-route-tab slot="title" name="tabs/b" to="/tabs/b" exact label="/tabs/b" />
59+
<q-route-tab slot="title" name="tabs/b/a" to="/tabs/b/a" exact label="/tabs/b/a" />
60+
<q-route-tab slot="title" name="tabs/c" to="/tabs/c" exact label="/tabs/c" />
61+
</q-tabs>
62+
3463
<q-tabs inverted>
3564
<q-tab alert slot="title" v-if="third" label="Oaua" />
3665
<q-tab count="5" slot="title" label="Gogu" />
@@ -66,7 +95,7 @@
6695
<q-tab-pane name="three">Tab Three</q-tab-pane>
6796
</q-tabs>
6897

69-
<q-tabs v-model="tab" @select="onSelect('blue', $event)" @input="onInput('blue', $event)">
98+
<q-tabs v-model="tab" @select="onEvent('select', 'blue', $event)" @input="onEvent('input', 'blue', $event)">
7099
<q-tab alert slot="title" v-if="third" name="three" label="Oaua" />
71100
<q-tab count="5" slot="title" name="one" label="Gogu" />
72101
<q-tab default slot="title" name="two" label="Gigiiiiiiiii sdfsdfs aadsf asfsda" />
@@ -82,7 +111,7 @@
82111
v-model="tab"
83112
:align="align"
84113
color="purple"
85-
@select="onSelect(`purple_${ align }`, $event)" @input="onInput(`purple_${ align }`, $event)"
114+
@select="onEvent('select', `purple_${ align }`, $event)" @input="onEvent('input', `purple_${ align }`, $event)"
86115
>
87116
<q-tab slot="title" v-if="third" name="three" label="Oaua" />
88117
<q-tab slot="title" name="one" label="Gogu" />
@@ -281,11 +310,8 @@ export default {
281310
}
282311
},
283312
methods: {
284-
onSelect (source, payload) {
285-
console.log('selected', source, payload)
286-
},
287-
onInput (source, payload) {
288-
console.log('input', source, payload)
313+
onEvent (event, source, payload) {
314+
console.log(source, event, payload)
289315
}
290316
}
291317
}
@@ -294,4 +320,15 @@ export default {
294320
<style lang="stylus">
295321
.tabs-playground .q-tabs
296322
margin-bottom 25px
323+
.test
324+
.q-router-link-active, .q-router-link-exact-active
325+
&:after
326+
position absolute
327+
top 0
328+
.q-router-link-active:after
329+
content '=='
330+
color #f99
331+
.q-router-link-exact-active:after
332+
content '==='
333+
color #0f0
297334
</style>

dev/router.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@ function component (path) {
1818

1919
let routes = [
2020
{path: '/', component: load('index')},
21+
{
22+
path: '/tabs',
23+
component: load('components/tabs-playground'),
24+
children: [
25+
{ path: 'a' },
26+
{ path: 'a/a' },
27+
{ path: 'a/b' },
28+
{ path: 'b' },
29+
{ path: 'b/a' },
30+
{ path: 'c' }
31+
]
32+
},
2133
{
2234
path: '/lay',
2335
component: load('web-tests/layout'),

src/components/breadcrumbs/QBreadcrumbsEl.js

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,7 @@ export default {
1717
render (h) {
1818
return h(this.link ? 'router-link' : 'span', {
1919
staticClass: 'q-breadcrumbs-el flex inline items-center relative-position',
20-
props: this.link
21-
? {
22-
to: this.to,
23-
exact: this.exact,
24-
append: this.append,
25-
replace: this.replace
26-
}
27-
: null
20+
props: this.link ? this.$props : null
2821
},
2922
this.label || this.icon
3023
? [

src/components/collapsible/collapsible.ios.styl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
.q-card
88
margin-bottom 0
99

10-
.q-collapsible.router-link-active > .q-item
10+
.q-collapsible.{$router-link-active} > .q-item
1111
background $collapsible-active-color
1212

1313
.q-collapsible

src/components/collapsible/collapsible.mat.styl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
.q-card
88
margin-bottom 0
99

10-
.q-collapsible.router-link-active > .q-item
10+
.q-collapsible.{$router-link-active} > .q-item
1111
background $collapsible-active-color
1212

1313
.q-collapsible

src/components/list/list.ios.styl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
padding ($item-padding / 2) $item-padding
5757
min-height $item-min-height
5858

59-
&.active, &.router-link-active, &:focus
59+
&.active, &.{$router-link-active}, &:focus
6060
background $item-active-color
6161

6262
&:focus
@@ -138,7 +138,7 @@
138138
color $item-content-secondary-text-dark-color
139139
.q-item
140140
color white
141-
&.active, &.router-link-active, &:focus
141+
&.active, &.{$router-link-active}, &:focus
142142
background $item-active-dark-color
143143
.q-list-dark
144144
border 1px solid $item-separator-dark-color

src/components/list/list.mat.styl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
padding ($item-padding / 2) $item-padding
5757
min-height $item-min-height
5858

59-
&.active, &.router-link-active, &:focus
59+
&.active, &.{$router-link-active}, &:focus
6060
background $item-active-color
6161

6262
&:focus
@@ -138,7 +138,7 @@
138138
color $item-content-secondary-text-dark-color
139139
.q-item
140140
color white
141-
&.active, &.router-link-active, &:focus
141+
&.active, &.{$router-link-active}, &:focus
142142
background $item-active-dark-color
143143
.q-list-dark
144144
border 1px solid $item-separator-dark-color

src/components/tab/QRouteTab.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import TabMixin from './tab-mixin'
44
export default {
55
name: 'q-route-tab',
66
mixins: [TabMixin, RouterLinkMixin],
7+
inject: {
8+
selectTabRouter: {}
9+
},
710
watch: {
811
$route () {
912
this.checkIfSelected()
@@ -14,16 +17,20 @@ export default {
1417
this.$emit('click', this.name)
1518
if (!this.disable) {
1619
this.$el.dispatchEvent(routerLinkEvent)
17-
this.selectTab(this.name)
20+
this.selectTabRouter({ value: this.name, selected: true })
1821
}
1922
},
2023
checkIfSelected () {
2124
this.$nextTick(() => {
22-
if (this.$el.classList.contains('router-link-active') || this.$el.classList.contains('router-link-exact-active')) {
23-
this.selectTab(this.name)
25+
if (this.$el.classList.contains('q-router-link-exact-active')) {
26+
this.selectTabRouter({ value: this.name, selectable: true, exact: true })
27+
}
28+
else if (this.$el.classList.contains('q-router-link-active')) {
29+
const path = this.$router.resolve(this.to, undefined, this.append)
30+
this.selectTabRouter({ value: this.name, selectable: true, priority: path.href.length })
2431
}
2532
else if (this.active) {
26-
this.selectTab(null)
33+
this.selectTabRouter({ value: null })
2734
}
2835
})
2936
}
@@ -36,9 +43,12 @@ export default {
3643
props: {
3744
tag: 'div',
3845
to: this.to,
39-
replace: this.replace,
46+
exact: this.exact,
4047
append: this.append,
41-
event: routerLinkEventName
48+
replace: this.replace,
49+
event: routerLinkEventName,
50+
activeClass: 'q-router-link-active',
51+
exactActiveClass: 'q-router-link-exact-active'
4252
},
4353
nativeOn: {
4454
click: this.select

src/components/tab/QTabs.vue

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ export default {
7676
provide () {
7777
return {
7878
data: this.data,
79-
selectTab: this.selectTab
79+
selectTab: this.selectTab,
80+
selectTabRouter: this.selectTabRouter
8081
}
8182
},
8283
components: {
@@ -153,6 +154,40 @@ export default {
153154
this.__repositionBar()
154155
}
155156
},
157+
selectTabRouter (params) {
158+
const
159+
{ value, selectable, exact, selected, priority } = params,
160+
first = !this.buffer.length,
161+
existingIndex = first ? -1 : this.buffer.findIndex(t => t.value === value)
162+
163+
if (existingIndex > -1) {
164+
const buffer = this.buffer[existingIndex]
165+
exact && (buffer.exact = exact)
166+
selectable && (buffer.selectable = selectable)
167+
selected && (buffer.selected = selected)
168+
priority && (buffer.priority = priority)
169+
}
170+
else {
171+
this.buffer.push(params)
172+
}
173+
174+
if (first) {
175+
this.bufferTimer = setTimeout(() => {
176+
let tab = (
177+
this.buffer.find(t =>
178+
(t.selectable && t.exact && t.selected) ||
179+
(t.selectable && t.selected) ||
180+
t.exact
181+
) ||
182+
this.buffer.filter(t => t.selectable).sort((t1, t2) => t2.priority - t1.priority)[0] ||
183+
this.buffer[0]
184+
)
185+
186+
this.buffer.length = 0
187+
this.selectTab(tab.value)
188+
}, 100)
189+
}
190+
},
156191
__repositionBar () {
157192
clearTimeout(this.timer)
158193
@@ -326,7 +361,10 @@ export default {
326361
}
327362
},
328363
created () {
364+
this.timer = null
329365
this.scrollTimer = null
366+
this.bufferTimer = null
367+
this.buffer = []
330368
this.scrollable = !this.$q.platform.is.desktop
331369
332370
// debounce some costly methods;
@@ -352,6 +390,7 @@ export default {
352390
},
353391
beforeDestroy () {
354392
clearTimeout(this.timer)
393+
clearTimeout(this.bufferTimer)
355394
this.__stopAnimScroll()
356395
this.$refs.scroller.removeEventListener('scroll', this.__updateScrollIndicator, listenOpts.passive)
357396
window.removeEventListener('resize', this.__redraw, listenOpts.passive)

src/css/core.variables.styl

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,11 @@ $breakpoint-lg-max = $breakpoint-lg
7676
$breakpoint-xl-min = $sizes[xl]
7777
$breakpoint-xl-max = 9999px
7878

79-
$backdrop-opacity ?= .3
80-
$backdrop-background ?= rgba(0, 0, 0, $backdrop-opacity)
79+
$backdrop-opacity ?= .3
80+
$backdrop-background ?= rgba(0, 0, 0, $backdrop-opacity)
81+
82+
$router-link-active ?= router-link-active
83+
$router-link-exact-active ?= router-link-exact-active
8184

8285
$headings = {
8386
display-4: {
@@ -179,8 +182,8 @@ $faded ?= #777
179182
$form-light ?= #a7a7a7
180183
$form-dark ?= #979797
181184

182-
$link-color ?= lighten($primary, 25%)
183-
$link-color-active ?= $primary
185+
$link-color ?= lighten($primary, 25%)
186+
$link-color-active ?= $primary
184187

185188
$dimmed-background ?= rgba(0, 0, 0, .4)
186189
$light-dimmed-background ?= rgba(255, 255, 255, .6)
@@ -522,17 +525,17 @@ max(value1, value2)
522525

523526
$ios-statusbar-height ?= 20px
524527

525-
$z-fab ?= 990
526-
$z-side ?= 1000
527-
$z-marginals ?= 2000
528-
$z-fixed-drawer ?= 3000
529-
$z-modal ?= 5000
530-
$z-fullscreen ?= 6000
531-
$z-top ?= 7000
532-
$z-popover ?= 8000
533-
$z-tooltip ?= 9000
534-
$z-notify ?= 9500
535-
$z-max ?= 9998
528+
$z-fab ?= 990
529+
$z-side ?= 1000
530+
$z-marginals ?= 2000
531+
$z-fixed-drawer ?= 3000
532+
$z-modal ?= 5000
533+
$z-fullscreen ?= 6000
534+
$z-top ?= 7000
535+
$z-popover ?= 8000
536+
$z-tooltip ?= 9000
537+
$z-notify ?= 9500
538+
$z-max ?= 9998
536539

537540
$shadow-color ?= black
538541
$shadow-transition ?= box-shadow .28s cubic-bezier(.4, 0, .2, 1)

0 commit comments

Comments
 (0)