Skip to content

Commit 7af9743

Browse files
committed
Merge branch 'feature/handle-keyboard-events' into develop
2 parents 786d9fe + dd815e3 commit 7af9743

File tree

4 files changed

+107
-15
lines changed

4 files changed

+107
-15
lines changed

src/components/VStep.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export default {
5555
let params = this.step.params || {}
5656
let targetElement = document.querySelector(this.step.target)
5757
58-
// Add a debug mode?
58+
// TODO: debug mode
5959
// console.log('[Vue Tour] The target element ' + this.step.target + ' of .v-step[id="' + this.hash + '"] is:', targetElement)
6060
6161
if (targetElement) {

src/components/VTour.vue

+50-3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
</template>
3131

3232
<script>
33+
import { DEFAULT_OPTIONS, KEYS } from '../shared/constants'
34+
3335
export default {
3436
name: 'v-tour',
3537
props: {
@@ -39,6 +41,10 @@ export default {
3941
},
4042
name: {
4143
type: String
44+
},
45+
options: {
46+
type: Object,
47+
default: () => { return DEFAULT_OPTIONS }
4248
}
4349
},
4450
data () {
@@ -48,30 +54,71 @@ export default {
4854
},
4955
mounted () {
5056
this.$tours[this.name] = this
57+
58+
if (this.customOptions.useKeyboardNavigation) {
59+
window.addEventListener('keyup', this.handleKeyup)
60+
}
61+
},
62+
beforeDestroy () {
63+
// Remove the keyup listener if it has been defined
64+
if (this.customOptions.useKeyboardNavigation) {
65+
window.removeEventListener('keyup', this.handleKeyup)
66+
}
5167
},
5268
computed: {
69+
// Allow us to define custom options and merge them with the default options.
70+
// Since options is a computed property, it is reactive and can be updated during runtime.
71+
customOptions () {
72+
return {
73+
...DEFAULT_OPTIONS,
74+
...this.options
75+
}
76+
},
77+
// Return true if the tour is active, which means that there's a VStep displayed
78+
isRunning () {
79+
return this.currentStep > -1 && this.currentStep < this.numberOfSteps
80+
},
5381
isFirst () {
5482
return this.currentStep === 0
5583
},
5684
isLast () {
5785
return this.currentStep === this.steps.length - 1
86+
},
87+
numberOfSteps () {
88+
return this.steps.length
5889
}
5990
},
6091
methods: {
6192
start () {
6293
// Wait for the DOM to be loaded, then start the tour
6394
setTimeout(() => {
6495
this.currentStep = 0
65-
})
96+
}, this.customOptions.startTimeout)
6697
},
6798
previousStep () {
68-
this.currentStep--
99+
if (this.currentStep > 0) this.currentStep--
69100
},
70101
nextStep () {
71-
this.currentStep++
102+
if (this.currentStep < this.numberOfSteps - 1 && this.currentStep !== -1) this.currentStep++
72103
},
73104
stop () {
74105
this.currentStep = -1
106+
},
107+
108+
handleKeyup (e) {
109+
// TODO: debug mode
110+
// console.log('[Vue Tour] A keyup event occured:', e)
111+
switch (e.keyCode) {
112+
case KEYS.ARROW_RIGHT:
113+
this.nextStep()
114+
break
115+
case KEYS.ARROW_LEFT:
116+
this.previousStep()
117+
break
118+
case KEYS.ESCAPE:
119+
this.stop()
120+
break
121+
}
75122
}
76123
}
77124
}

src/shared/constants.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export const KEYS = {
2+
ARROW_RIGHT: 39,
3+
ARROW_LEFT: 37,
4+
ESCAPE: 27
5+
}
6+
7+
export const DEFAULT_OPTIONS = {
8+
useKeyboardNavigation: true,
9+
startTimeout: 0
10+
}

test/unit/VTour.spec.js

+46-11
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@ import VTour from '@/components/VTour.vue'
66

77
Vue.use(VueTour)
88

9+
const steps = [
10+
{
11+
target: '#v-step-0',
12+
content: `Discover <strong>Vue Tour</strong>!`
13+
},
14+
{
15+
target: '#v-step-1',
16+
content: 'An awesome plugin made with Vue.js!'
17+
}
18+
]
19+
920
describe('VTour.vue', () => {
1021
it('has the correct number of steps', () => {
11-
const steps = [
12-
{
13-
target: '#v-step-0',
14-
content: `Discover <strong>Vue Tour</strong>!`
15-
},
16-
{
17-
target: '#v-step-1',
18-
content: 'An awesome plugin made with Vue.js!'
19-
}
20-
]
21-
2222
const wrapper = mount(VTour, {
2323
propsData: {
2424
name: 'myTestTour',
@@ -39,4 +39,39 @@ describe('VTour.vue', () => {
3939

4040
expect(wrapper.vm.$tours).to.be.an('object').that.has.all.keys('myTestTour')
4141
})
42+
43+
it('stays within the boundaries of the number of steps', () => {
44+
const wrapper = mount(VTour, {
45+
propsData: {
46+
name: 'myTestTour',
47+
steps
48+
}
49+
})
50+
51+
expect(wrapper.vm.currentStep).to.equal(-1)
52+
53+
wrapper.vm.start()
54+
55+
setTimeout(() => {
56+
expect(wrapper.vm.currentStep).to.equal(0)
57+
58+
// We call nextStep one more time than needed
59+
for (let i = 0; i < steps.length; i++) {
60+
wrapper.vm.nextStep()
61+
}
62+
63+
expect(wrapper.vm.currentStep).to.equal(1)
64+
65+
// We call previousStep one more time than needed
66+
for (let i = 0; i < steps.length; i++) {
67+
wrapper.vm.previousStep()
68+
}
69+
70+
expect(wrapper.vm.currentStep).to.equal(0)
71+
72+
wrapper.vm.stop()
73+
74+
expect(wrapper.vm.currentStep).to.equal(-1)
75+
})
76+
})
4277
})

0 commit comments

Comments
 (0)