Skip to content

Commit 5cd4f1b

Browse files
authored
feat(QAjaxBar/LoadingBar): (backport from Qv2) new prop (Function) -> hijack-filter quasarframework#11952 quasarframework#6303 (quasarframework#11986)
1 parent 06b3fe7 commit 5cd4f1b

File tree

6 files changed

+152
-33
lines changed

6 files changed

+152
-33
lines changed

docs/src/pages/quasar-plugins/loading-bar.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ this.$q.loadingBar.setDefaults({
5555
})
5656
```
5757

58-
Outside of Vue components:
58+
Outside of Vue components (includes boot files):
5959

6060
```js
6161
import { LoadingBar } from 'quasar'
@@ -66,3 +66,20 @@ LoadingBar.setDefaults({
6666
position: 'bottom'
6767
})
6868
```
69+
70+
### Using an Ajax filter <q-badge align="top" color="brand-primary" label="v1.17.2+" />
71+
72+
Should you want to trigger LoadingBar only for some URLs, then you can use the `setDefaults()` method (described above) to configure the `hijackFilter` property:
73+
74+
```js
75+
import { LoadingBar } from 'quasar'
76+
77+
LoadingBar.setDefaults({
78+
// return a Boolean which has the meaning of
79+
// "should this URL trigger LoadingBar?"
80+
hijackFilter (url) {
81+
// example (only https://my-service.com/* should trigger)
82+
return /^https:\/\/my-service\.com/.test(url)
83+
}
84+
})
85+
```

docs/src/pages/vue-components/ajax-bar.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,33 @@ The QAjaxBar component captures Ajax calls automatically (unless told not to).
2323

2424
The example below triggers events manually for demonstrating purposes only. This one is set to appear at bottom (multiple positions available!) of the page, with a 10px size (default is different) and uses a custom color.
2525

26+
### Basic
27+
2628
<doc-example title="Basic" file="QAjaxBar/Basic" />
2729

2830
Please check out the API section for all properties that you can use.
2931

32+
### Ajax filter <q-badge align="top" color="brand-primary" label="v1.17.2+" />
33+
34+
Should you want QAjaxBar to trigger only for some URLs (and not for all, like in the default behavior), then you can use the `hijackFilter` property:
35+
36+
```html
37+
<template>
38+
<q-ajax-bar :hijack-filter="myFilterFn" />
39+
</template>
40+
41+
<script>
42+
export default {
43+
methods () {
44+
myFilterFn (url) {
45+
// example (only https://my-service.com/* should trigger)
46+
return /^https:\/\/my-service\.com/.test(url)
47+
}
48+
}
49+
}
50+
</script>
51+
```
52+
3053
## Tips
3154
* If multiple events are captured by Ajax Bar simultaneously, `@start` and `@stop` will still be triggered only once: when bar starts showing up and when it becomes hidden.
3255

ui/dev/src/pages/components/ajax-bar.vue

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,44 @@
5757
</q-card-section>
5858
</q-card>
5959
</div>
60-
<q-ajax-bar ref="bar" :position="position" :reverse="reverse" :size="computedSize" />
60+
61+
<div class="q-ma-md">
62+
<q-btn label="xhr /server (trigger)" color="primary" @click="triggerXhr1" no-caps />
63+
<q-btn label="xhr /second-server (NO trigger)" color="primary" @click="triggerXhr2" no-caps class="q-ml-sm" />
64+
</div>
65+
66+
<q-ajax-bar ref="bar" :position="position" :reverse="reverse" :size="computedSize" skip-hijack />
6167
</div>
6268
</template>
6369

6470
<script>
71+
import { LoadingBar } from 'quasar'
72+
function sendXhr (url) {
73+
const xhr = new XMLHttpRequest()
74+
xhr.open('GET', url, true)
75+
xhr.send(null)
76+
// setTimeout(() => {
77+
// xhr.open('GET', '/mimi', true)
78+
// xhr.send(null)
79+
// }, 500)
80+
}
81+
6582
export default {
83+
created () {
84+
LoadingBar.setDefaults({
85+
hijackFilter (url) {
86+
const res = /\/server/.test(url) === true &&
87+
/\/other-server/.test(url) === false
88+
console.log(url, res)
89+
return res
90+
}
91+
})
92+
},
93+
94+
beforeUnmount () {
95+
LoadingBar.setDefaults({ hijackFilter: void 0 })
96+
},
97+
6698
data () {
6799
return {
68100
position: 'top',
@@ -98,6 +130,13 @@ export default {
98130
99131
stop () {
100132
this.$refs.bar.stop()
133+
},
134+
135+
triggerXhr1 () {
136+
sendXhr('/server')
137+
},
138+
triggerXhr2 () {
139+
sendXhr('/second-server')
101140
}
102141
}
103142
}

ui/src/components/ajax-bar/QAjaxBar.js

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,22 @@ import { ariaHidden } from '../../mixins/attrs'
66

77
const
88
xhr = isSSR ? null : XMLHttpRequest,
9-
send = isSSR ? null : xhr.prototype.send,
10-
stackStart = [],
11-
stackStop = []
9+
open = isSSR ? null : xhr.prototype.open,
10+
positionValues = [ 'top', 'right', 'bottom', 'left' ]
1211

12+
let stack = []
1313
let highjackCount = 0
1414

1515
function translate ({ p, pos, active, horiz, reverse, dir }) {
1616
let x = 1, y = 1
1717

18-
if (horiz) {
19-
if (reverse) { x = -1 }
18+
if (horiz === true) {
19+
if (reverse === true) { x = -1 }
2020
if (pos === 'bottom') { y = -1 }
2121
return { transform: `translate3d(${x * (p - 100)}%,${active ? 0 : y * -200}%,0)` }
2222
}
2323

24-
if (reverse) { y = -1 }
24+
if (reverse === true) { y = -1 }
2525
if (pos === 'right') { x = -1 }
2626
return { transform: `translate3d(${active ? 0 : dir * x * -200}%,${y * (p - 100)}%,0)` }
2727
}
@@ -47,32 +47,46 @@ function inc (p, amount) {
4747
return between(p + amount, 0, 100)
4848
}
4949

50-
function highjackAjax (start, stop) {
51-
stackStart.push(start)
52-
stackStop.push(stop)
53-
50+
function highjackAjax (stackEntry) {
5451
highjackCount++
5552

53+
stack.push(stackEntry)
54+
5655
if (highjackCount > 1) { return }
5756

58-
function endHandler () {
59-
stackStop.forEach(fn => { fn() })
60-
}
57+
xhr.prototype.open = function (_, url) {
58+
const stopStack = []
59+
60+
const loadStart = () => {
61+
stack.forEach(entry => {
62+
const hijackFilter = entry.getHijackFilter()
63+
if (
64+
hijackFilter === null ||
65+
hijackFilter(url) === true
66+
) {
67+
entry.start()
68+
stopStack.push(entry.stop)
69+
}
70+
})
71+
}
6172

62-
xhr.prototype.send = function (/* ...args */) {
63-
stackStart.forEach(fn => { fn() })
64-
this.addEventListener('loadend', endHandler, false)
65-
send.apply(this, arguments)
73+
const loadEnd = () => {
74+
stopStack.forEach(stop => { stop() })
75+
}
76+
77+
this.addEventListener('loadstart', loadStart, { once: true })
78+
this.addEventListener('loadend', loadEnd, { once: true })
79+
80+
open.apply(this, arguments)
6681
}
6782
}
6883

69-
function restoreAjax (start, stop) {
70-
stackStart.splice(stackStart.indexOf(start), 1)
71-
stackStop.splice(stackStop.indexOf(stop), 1)
84+
function restoreAjax (start) {
85+
stack = stack.filter(entry => entry.start !== start)
7286

7387
highjackCount = Math.max(0, highjackCount - 1)
7488
if (!highjackCount) {
75-
xhr.prototype.send = send
89+
xhr.prototype.open = open
7690
}
7791
}
7892

@@ -83,15 +97,19 @@ export default Vue.extend({
8397
position: {
8498
type: String,
8599
default: 'top',
86-
validator: val => ['top', 'right', 'bottom', 'left'].includes(val)
100+
validator: val => positionValues.includes(val)
87101
},
102+
88103
size: {
89104
type: String,
90105
default: '2px'
91106
},
107+
92108
color: String,
109+
reverse: Boolean,
110+
93111
skipHijack: Boolean,
94-
reverse: Boolean
112+
hijackFilter: Function
95113
},
96114

97115
data () {
@@ -119,7 +137,7 @@ export default Vue.extend({
119137
active,
120138
horiz: this.horizontal,
121139
reverse: this.$q.lang.rtl === true && ['top', 'bottom'].includes(this.position)
122-
? !this.reverse
140+
? this.reverse === false
123141
: this.reverse,
124142
dir: this.$q.lang.rtl === true ? -1 : 1
125143
})
@@ -224,13 +242,17 @@ export default Vue.extend({
224242
mounted () {
225243
if (this.skipHijack !== true) {
226244
this.hijacked = true
227-
highjackAjax(this.start, this.stop)
245+
highjackAjax({
246+
start: this.start,
247+
stop: this.stop,
248+
getHijackFilter: () => this.hijackFilter || null
249+
})
228250
}
229251
},
230252

231253
beforeDestroy () {
232254
clearTimeout(this.timer)
233-
this.hijacked === true && restoreAjax(this.start, this.stop)
255+
this.hijacked === true && restoreAjax(this.start)
234256
},
235257

236258
render (h) {

ui/src/components/ajax-bar/QAjaxBar.json

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,34 @@
2222
"extends": "color"
2323
},
2424

25-
"skip-hijack": {
25+
"reverse": {
2626
"type": "Boolean",
27-
"desc": "Skip Ajax hijacking (not a reactive prop)",
27+
"desc": "Reverse direction of progress",
2828
"category": "behavior"
2929
},
3030

31-
"reverse": {
31+
"skip-hijack": {
3232
"type": "Boolean",
33-
"desc": "Reverse direction of progress",
33+
"desc": "Skip Ajax hijacking (not a reactive prop)",
3434
"category": "behavior"
35+
},
36+
37+
"hijack-filter": {
38+
"type": "Function",
39+
"desc": "Filter which URL should trigger start() + stop()",
40+
"params": {
41+
"url": {
42+
"type": "String",
43+
"desc": "The URL being triggered",
44+
"examples": [ "https://some.url/path" ]
45+
}
46+
},
47+
"returns": {
48+
"type": "Boolean",
49+
"desc": "Should the URL received as param trigger start() + stop()?"
50+
},
51+
"category": "behavior",
52+
"addedIn": "v1.17.2"
3553
}
3654
},
3755

ui/src/plugins/LoadingBar.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"definition": {
1111
"...props": {
1212
"type": "Object",
13-
"desc": "QAjaxBar component props",
13+
"desc": "QAjaxBar component props, EXCEPT for 'hijack-filter'",
1414
"__exemption": [ "examples" ]
1515
}
1616
}

0 commit comments

Comments
 (0)