Skip to content

Commit efbc8bc

Browse files
authored
Progress Management (#44)
This PR includes simple progress management. There is a new state that contains progresses of loaders, it allows user to convert an indeterminate loader to determinate loader on its way.
1 parent 3e6d97d commit efbc8bc

File tree

8 files changed

+274
-41
lines changed

8 files changed

+274
-41
lines changed

README.md

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ Returns boolean value if any loader exists in page.
133133
</template>
134134
```
135135

136-
#### `.is(loader String | Matcher)`
136+
#### `.is(loader String | Matcher)` or `.waiting(loader String | Matcher)`
137137

138138
Returns boolean value if given loader exists in page.
139139

@@ -143,6 +143,16 @@ Returns boolean value if given loader exists in page.
143143
</template>
144144
```
145145

146+
You can use **`waiting`** alias instead of **`is`**.
147+
148+
```html
149+
<template>
150+
<div v-if="$wait.waiting('fetching users')">
151+
Fetching users...
152+
</div>
153+
</template>
154+
```
155+
146156
Also you can use matcher to make it more flexible:
147157

148158
Please see [matcher](https://github.com/sindresorhus/matcher/) library to see how to use matchers.
@@ -153,7 +163,7 @@ Please see [matcher](https://github.com/sindresorhus/matcher/) library to see ho
153163
</template>
154164
```
155165

156-
#### `.is(loaders Array<String | Matcher>)`
166+
#### `.is(loaders Array<String | Matcher>)` or `.waiting(loaders Array<String | Matcher>)`
157167

158168
Returns boolean value if some of given loaders exists in page.
159169

@@ -183,6 +193,44 @@ Stops the given loader.
183193
</template>
184194
```
185195

196+
#### `.progress(loader String, current [, total = 100])`
197+
198+
Sets the progress of the given loader.
199+
200+
```html
201+
<template>
202+
<progress min="0" max="100" :value="$wait.percent('downloading')" />
203+
<button @click="$wait.progress('downloading', 10)">Set progress to 10</button>
204+
<button @click="$wait.progress('downloading', 50)">Set progress to 50</button>
205+
<button @click="$wait.progress('downloading', 50, 200)">Set progress to 50 of 200 (25%)</button>
206+
</template>
207+
```
208+
209+
##### Completing the Progress
210+
211+
To complete the progress, `current` value should be set bigger than `100`.
212+
If you `total` is given, `current` must be bigger than `total`.
213+
214+
```html
215+
<button @click="$wait.progress('downloading', 101)">Set as downloaded (101 of 100)</button>
216+
```
217+
218+
or
219+
220+
```html
221+
<button @click="$wait.progress('downloading', 5, 6)">Set as downloaded (6 of 5)</button>
222+
```
223+
224+
#### `.percent(loader String)`
225+
226+
Returns the percentage of the given loader.
227+
228+
```html
229+
<template>
230+
<progress min="0" max="100" :value="$wait.percent('downloading')" />
231+
</template>
232+
```
233+
186234
## 🏹 Directives
187235

188236
You can use directives to make your template cleaner.
@@ -258,6 +306,16 @@ Toggles given loader on click.
258306
</template>
259307
```
260308

309+
#### `v-wait:click.progress='["loader name", 80]'`
310+
311+
Sets the progress of given loader on click.
312+
313+
```html
314+
<template>
315+
<button v-wait:click.progress='["downloading", 80]'>Set the "downloading" loader to 80</button>
316+
</template>
317+
```
318+
261319
## 🔌 Loading Action and Getter Mappers
262320

263321
**vue-wait** provides `mapWaitingActions` and `mapWaitingGetters` mapper to be used with your Vuex stores.
@@ -316,7 +374,7 @@ actions: {
316374
},
317375
```
318376

319-
#### `waitFor(loader String, func Function, [,force_sync = false])`
377+
#### `waitFor(loader String, func Function [,forceSync = false])`
320378

321379
Decorator that wraps function, will trigger a loading and will end loader after the original function (`func` argument) is finished.
322380

dist/vue-wait.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/vuex-example/main.vue

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,26 @@
5353
</v-wait>
5454
</button>
5555
<span v-if='isIncrementing'>is incrementing...</span>
56+
<hr>
57+
Percentage of <code>writing code</code>: <span>{{ $l.percent('writing code') }}</span>
58+
<p>
59+
<label>Native Progress</label><br>
60+
<progress min="0" max="100" :value='$l.percent("writing code")'></progress>
61+
</p>
62+
<p>
63+
<label>Custom Progress</label><br>
64+
<span class="progress">
65+
<span class="percent" :style="`width: ${$l.percent('writing code')}%`"></span>
66+
</span>
67+
</p>
68+
<button @click='writeCode()'>
69+
Start <code>writing code</code>
70+
</button>
71+
<button v-wait:click.progress="['writing code', 10]">Set progress to 10</button>
72+
<button v-wait:click.progress="['writing code', 50]">Set progress to 50</button>
73+
<button v-wait:click.progress="['writing code', 100, 100]">Set progress to 100 of 100</button>
74+
<button v-wait:click.progress="['writing code', 101]">Set progress to 101 (complete)</button>
75+
<button v-wait:click.progress="['writing code', 50, 200]">Set progress to 50 of 200 (25%)</button>
5676
</div>
5777
</template>
5878

@@ -67,10 +87,16 @@
6787
loaders: ['a', 'c', 'b', 'a', 'b', 'a', 'c', 'a', 'c', 'a', 'b']
6888
};
6989
},
90+
watch: {
91+
isWritingCode() {
92+
if (!this.isWritingCode) clearInterval(this.timer);
93+
}
94+
},
7095
computed: {
7196
...mapGetters(['count']),
7297
...mapWaitingGetters({
7398
isIncrementing: 'incrementing count',
99+
isWritingCode: 'writing code',
74100
}),
75101
},
76102
methods: {
@@ -79,9 +105,14 @@
79105
}),
80106
writeCode() {
81107
this.$l.start('writing code');
108+
let i = this.$l.percent('writing code');
109+
this.timer = setInterval(() => {
110+
this.$l.progress('writing code', i++);
111+
}, 100);
82112
},
83113
end() {
84114
this.$l.end('writing code');
115+
clearInterval(this.timer);
85116
},
86117
toggleLoader(loader) {
87118
if (this.$l.is(loader)) {
@@ -125,6 +156,25 @@
125156
padding: 50px;
126157
}
127158
159+
.progress {
160+
width: 400px;
161+
height: 40px;
162+
background-color: #ccc;
163+
border: 1px solid #999;
164+
margin: 0 auto;
165+
display: inline-block;
166+
position: relative;
167+
}
168+
169+
.percent {
170+
position: absolute;
171+
top: 0;
172+
left: 0;
173+
height: 40px;
174+
background-color: blue;
175+
transition-duration: 600ms;
176+
}
177+
128178
button {
129179
border: 0;
130180
background-color: #fff;

src/directives/wait.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ function bind(el, binding, vNode, oldVNode) {
1111
el.addEventListener('click', () => instance.end(value), false);
1212
break;
1313
}
14+
if (modifiers.progress) {
15+
el.addEventListener('click', () => instance.progress(...value), false);
16+
break;
17+
}
1418
break;
1519
case 'toggle':
1620
el.addEventListener(

src/utils.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,33 @@ export function end(waitingFor, waiter) {
2525
return uniqArray(waitingFor).filter(l => l !== waiter);
2626
}
2727

28+
export function progress(progresses, waiter, current, total = 100) {
29+
if (current > total) {
30+
return endProgress(progresses, waiter);
31+
}
32+
33+
return {
34+
...progresses,
35+
[waiter]: {
36+
current,
37+
total,
38+
percent: (100 * current) / total
39+
}
40+
};
41+
}
42+
43+
export function endProgress(progresses, waiter) {
44+
const { [waiter]: omit, ...omittedProgresses } = progresses;
45+
return omittedProgresses;
46+
}
47+
48+
export function percent(progresses, waiter) {
49+
const progress = progresses[waiter];
50+
if (!progress) return 0;
51+
52+
return progress.percent;
53+
}
54+
2855
export function nodeIsDebug() {
2956
return process.env.NODE_ENV !== 'production';
3057
}

src/vue-wait.js

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
import { is, any, start, end, nodeIsDebug } from './utils';
1+
import {
2+
is,
3+
any,
4+
start,
5+
end,
6+
progress,
7+
percent,
8+
endProgress,
9+
nodeIsDebug
10+
} from './utils';
211

312
// Import to export
413
import { mapWaitingActions, mapWaitingGetters, waitFor } from './helpers';
@@ -61,14 +70,17 @@ export default class VueWait {
6170
this.stateHandler = new Vue({
6271
computed: {
6372
is: () => waiter => store.getters[`${vuexModuleName}/is`](waiter),
64-
any: () => store.getters[`${vuexModuleName}/any`]
73+
any: () => store.getters[`${vuexModuleName}/any`],
74+
percent: () => waiter =>
75+
store.getters[`${vuexModuleName}/percent`](waiter)
6576
}
6677
});
6778
} else {
6879
this.stateHandler = new Vue({
6980
data() {
7081
return {
71-
waitingFor: []
82+
waitingFor: [],
83+
progresses: {}
7284
};
7385
},
7486
computed: {
@@ -77,6 +89,9 @@ export default class VueWait {
7789
},
7890
any() {
7991
return any(this.waitingFor);
92+
},
93+
percent() {
94+
return waiter => percent(this.progresses, waiter);
8095
}
8196
},
8297
methods: {
@@ -85,6 +100,10 @@ export default class VueWait {
85100
},
86101
end(waiter) {
87102
this.waitingFor = end(this.waitingFor, waiter);
103+
this.progresses = endProgress(this.progresses, waiter);
104+
},
105+
progress({ waiter, current, total }) {
106+
this.progresses = progress(this.progresses, waiter, current, total);
88107
}
89108
}
90109
});
@@ -101,6 +120,15 @@ export default class VueWait {
101120
return this.stateHandler.is(waiter);
102121
}
103122

123+
// alias for `is`
124+
waiting(waiter) {
125+
return this.is(waiter);
126+
}
127+
128+
percent(waiter) {
129+
return this.stateHandler.percent(waiter);
130+
}
131+
104132
dispatchWaitingAction(action, waiter) {
105133
const { vuexModuleName } = this.options;
106134
this.store.dispatch(`${vuexModuleName}/${action}`, waiter, {
@@ -123,6 +151,23 @@ export default class VueWait {
123151
}
124152
this.stateHandler.end(waiter);
125153
}
154+
155+
progress(waiter, current, total = 100) {
156+
if (!this.is(waiter)) {
157+
this.start(waiter);
158+
}
159+
160+
if (current > total) {
161+
this.end(waiter);
162+
return;
163+
}
164+
165+
if (this.options.useVuex) {
166+
this.dispatchWaitingAction('progress', { waiter, current, total });
167+
return;
168+
}
169+
this.stateHandler.progress({ waiter, current, total });
170+
}
126171
}
127172

128173
export function install(Vue) {

src/vuex/store.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,37 @@
1-
import { is, any, start, end } from '../utils';
1+
import { is, any, start, end, progress, percent, endProgress } from '../utils';
22

33
const mutations = {
44
START: 'START',
5-
END: 'END'
5+
END: 'END',
6+
PROGRESS: 'PROGRESS'
67
};
78

89
export default {
910
namespaced: true,
1011
state: {
11-
waitingFor: []
12+
waitingFor: [],
13+
progresses: {}
1214
},
1315
getters: {
1416
is: state => waiter => is(state.waitingFor, waiter),
15-
any: state => any(state.waitingFor)
17+
any: state => any(state.waitingFor),
18+
percent: state => waiter => percent(state.progresses, waiter)
1619
},
1720
actions: {
1821
start: ({ commit }, waiter) => commit(mutations.START, waiter),
19-
end: ({ commit }, waiter) => commit(mutations.END, waiter)
22+
end: ({ commit }, waiter) => commit(mutations.END, waiter),
23+
progress: ({ commit }, progress) => commit(mutations.PROGRESS, progress)
2024
},
2125
mutations: {
2226
[mutations.START](state, waiter) {
2327
state.waitingFor = start(state.waitingFor, waiter);
2428
},
2529
[mutations.END](state, waiter) {
2630
state.waitingFor = end(state.waitingFor, waiter);
31+
state.progresses = endProgress(state.progresses, waiter);
32+
},
33+
[mutations.PROGRESS](state, { waiter, current, total }) {
34+
state.progresses = progress(state.progresses, waiter, current, total);
2735
}
2836
}
2937
};

0 commit comments

Comments
 (0)