Skip to content

Commit

Permalink
Merge 0965464 into c4e871e
Browse files Browse the repository at this point in the history
  • Loading branch information
francoismassart committed Nov 12, 2017
2 parents c4e871e + 0965464 commit 2bf78f6
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 25 deletions.
102 changes: 93 additions & 9 deletions src/components/timepicker/TimePicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,29 @@
<tbody>
<tr class="text-center">
<td>
<btn type="link" size="sm" @click="changeTime(1,1)" :disabled="readonly">
<btn
type="link"
size="sm"
@touchstart="startStepping(1, 1, $event)"
@touchend="stopStepping(1, 1, $event)"
@mousedown="startStepping(1, 1, $event)"
@mouseup="stopStepping(1, 1, $event)"
@click="stopStepping(1, 1, $event)"
:disabled="readonly">
<i :class="iconControlUp"></i>
</btn>
</td>
<td>&nbsp;</td>
<td>
<btn type="link" size="sm" @click="changeTime(0,1)" :disabled="readonly">
<btn
type="link"
size="sm"
@touchstart="startStepping(0, 1, $event)"
@touchend="stopStepping(0, 1, $event)"
@mousedown="startStepping(0, 1, $event)"
@mouseup="stopStepping(0, 1, $event)"
@click="stopStepping(0, 1, $event)"
:disabled="readonly">
<i :class="iconControlUp"></i>
</btn>
</td>
Expand All @@ -24,8 +40,10 @@
class="form-control text-center"
style="width: 50px"
@focus="selectInputValue"
@keyup.up="changeTime(1, 1)"
@keyup.down="changeTime(1, 0)"
@keydown.prevent.up="startStepping(1, 1, $event)"
@keydown.prevent.down="startStepping(1, 0, $event)"
@keyup.up="stopStepping(1, 1, $event)"
@keyup.down="stopStepping(1, 0, $event)"
@wheel="onWheel($event, true)"
placeholder="HH"
v-model.lazy="hoursText"
Expand All @@ -40,8 +58,10 @@
class="form-control text-center"
style="width: 50px"
@focus="selectInputValue"
@keyup.up="changeTime(0, 1)"
@keyup.down="changeTime(0, 0)"
@keydown.prevent.up="startStepping(0, 1, $event)"
@keydown.prevent.down="startStepping(0, 0, $event)"
@keyup.up="stopStepping(0, 1, $event)"
@keyup.down="stopStepping(0, 0, $event)"
@wheel="onWheel($event, false)"
placeholder="MM"
v-model.lazy="minutesText"
Expand All @@ -60,13 +80,29 @@
</tr>
<tr class="text-center">
<td>
<btn type="link" size="sm" @click="changeTime(1,0)" :disabled="readonly">
<btn
type="link"
size="sm"
@touchstart="startStepping(1, 0, $event)"
@touchend="stopStepping(1, 0, $event)"
@mousedown="startStepping(1, 0, $event)"
@mouseup="stopStepping(1, 0, $event)"
@click="stopStepping(1, 0, $event)"
:disabled="readonly">
<i :class="iconControlDown"></i>
</btn>
</td>
<td>&nbsp;</td>
<td>
<btn type="link" size="sm" @click="changeTime(0,0)" :disabled="readonly">
<btn
type="link"
size="sm"
@touchstart="startStepping(0, 0, $event)"
@touchend="stopStepping(0, 0, $event)"
@mousedown="startStepping(0, 0, $event)"
@mouseup="stopStepping(0, 0, $event)"
@click="stopStepping(0, 0, $event)"
:disabled="readonly">
<i :class="iconControlDown"></i>
</btn>
</td>
Expand Down Expand Up @@ -133,7 +169,11 @@
minutes: 0,
meridian: true,
hoursText: '',
minutesText: ''
minutesText: '',
stepperInterval: null,
stepperIntervalRan: false,
touchstartEventRan: false,
mousedownEventRan: false
}
},
mounted () {
Expand Down Expand Up @@ -269,6 +309,50 @@
this.$nextTick(() => {
e.target.setSelectionRange(0, 2)
})
},
eventShouldBePrevented (e) {
if (e.type === 'touchstart') {
this.touchstartEventRan = true
}
if (e.type === 'mousedown') {
this.mousedownEventRan = true
}
switch (e.type) {
case 'mousedown':
case 'mouseup':
return this.touchstartEventRan
case 'click':
return this.mousedownEventRan
default:
return false
}
},
clearStepperInterval () {
if (this.stepperInterval != null) {
clearInterval(this.stepperInterval)
this.stepperInterval = null
this.stepperIntervalRan = false
}
},
startStepping (isHour, isPlus, e) {
if (this.eventShouldBePrevented(e)) {
return
}
this.clearStepperInterval()
let ref = this
this.stepperInterval = setInterval(function () {
ref.changeTime(isHour, isPlus)
ref.stepperIntervalRan = true
}, 80)
},
stopStepping (isHour, isPlus, e) {
if (this.eventShouldBePrevented(e)) {
return
}
if (!this.stepperIntervalRan) {
this.changeTime(isHour, isPlus)
}
this.clearStepperInterval()
}
}
}
Expand Down
101 changes: 85 additions & 16 deletions test/unit/specs/TimePicker.spec.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import Vue from 'vue'
import $ from 'jquery'
import utils from './../utils'
import TimePickerDoc from '@docs/pages/components/TimePicker.md'

describe('TimePicker', () => {
let vm
let $el
const stepDelay = 100

beforeEach(() => {
let Constructor = Vue.extend(TimePickerDoc)
const Constructor = Vue.extend(TimePickerDoc)
vm = new Constructor().$mount()
$el = $(vm.$el)
})
Expand All @@ -18,31 +20,60 @@ describe('TimePicker', () => {
})

it('should be able to toggle meridian', async () => {
let _vm = vm.$refs['time-picker-example']
const _vm = vm.$refs['time-picker-example']
_vm.time.setHours(9)
_vm.time = new Date(_vm.time)
await vm.$nextTick()
let toggleBtn = _vm.$el.querySelector('[data-action="toggleMeridian"]')
let meridianText = toggleBtn.textContent
const toggleBtn = _vm.$el.querySelector('[data-action="toggleMeridian"]')
const meridianText = toggleBtn.textContent
expect(meridianText).to.equal('AM')
toggleBtn.click()
utils.triggerEvent(toggleBtn, 'click')
await vm.$nextTick()
let meridianTextAfterClick = toggleBtn.textContent
const meridianTextAfterClick = toggleBtn.textContent
expect(meridianTextAfterClick).to.equal('PM')
toggleBtn.click()
utils.triggerEvent(toggleBtn, 'click')
await vm.$nextTick()
let meridianTextAfterTwoClick = toggleBtn.textContent
const meridianTextAfterTwoClick = toggleBtn.textContent
expect(meridianTextAfterTwoClick).to.equal('AM')
})

it('should be able to add 1 hours', async () => {
let _vm = vm.$refs['time-picker-example']
it('should be able to add hours', async () => {
const _vm = vm.$refs['time-picker-example']
await vm.$nextTick()
let beforeText = _vm.$el.querySelectorAll('input')[0].value
let hourPlus = _vm.$el.querySelectorAll('td')[0].querySelector('button')
hourPlus.click()
const hourInput = _vm.$el.querySelectorAll('input')[0]
const beforeText = hourInput.value
const hourPlus = _vm.$el.querySelectorAll('td')[0].querySelector('button')

// Due to the order in which the events are triggered by the browsers,
// safegards are used to prevented unwanted multiple increases, this is why
// tests should be in this order: click > mouseup > mousedown > touchend > touchstart > key > wheel

const testHourForSingleEvent = async (el, evtType) => {
_vm.time.setHours(2)
_vm.time = new Date(_vm.time)
await vm.$nextTick()
utils.triggerEvent(el, evtType)
await vm.$nextTick()
afterText = hourInput.value
expect(parseInt(afterText)).to.equal(3)
}

const testHourForQueuedEvents = async (el, firstEvtType, ticks, secondEvtType) => {
_vm.time.setHours(2)
_vm.time = new Date(_vm.time)
await vm.$nextTick()
utils.triggerEvent(el, firstEvtType)
await utils.sleep(ticks * stepDelay)
utils.triggerEvent(el, secondEvtType)
await vm.$nextTick()
afterText = hourInput.value
expect(parseInt(afterText)).to.equal(2 + ticks)
}

// click hourPlus
utils.triggerEvent(hourPlus, 'click')
await vm.$nextTick()
let afterText = _vm.$el.querySelectorAll('input')[0].value
let afterText = hourInput.value
if (parseInt(beforeText) !== 12) {
expect(parseInt(afterText)).to.equal(parseInt(beforeText) + 1)
} else {
Expand All @@ -51,10 +82,48 @@ describe('TimePicker', () => {
_vm.time.setHours(23)
_vm.time = new Date(_vm.time)
await vm.$nextTick()
hourPlus.click()
utils.triggerEvent(hourPlus, 'click')
await vm.$nextTick()
afterText = _vm.$el.querySelectorAll('input')[0].value
afterText = hourInput.value
expect(parseInt(afterText)).to.equal(12)

// mouseup hourPlus
await testHourForSingleEvent(hourPlus, 'mouseup')

// mousedown/up hourPlus
await testHourForQueuedEvents(hourPlus, 'mousedown', 1, 'mouseup')

// Long mousedown/up hourPlus
await testHourForQueuedEvents(hourPlus, 'mousedown', 2, 'mouseup')

// touchend hourPlus
await testHourForSingleEvent(hourPlus, 'touchend')

// touchstart/end hourPlus
await testHourForQueuedEvents(hourPlus, 'touchstart', 1, 'touchend')

// Long touchstart/end hourPlus
await testHourForQueuedEvents(hourPlus, 'touchstart', 2, 'touchend')

// Keypress up arrow
_vm.time.setHours(2)
_vm.time = new Date(_vm.time)
await vm.$nextTick()
utils.triggerKey(hourInput, 38, 'down')
await utils.sleep(stepDelay)
utils.triggerKey(hourInput, 38, 'up')
await vm.$nextTick()
afterText = hourInput.value
expect(parseInt(afterText)).to.equal(3)

// Wheel
_vm.time.setHours(2)
_vm.time = new Date(_vm.time)
await vm.$nextTick()
utils.triggerWheel(hourInput, 'wheel', -1)
await vm.$nextTick()
afterText = hourInput.value
expect(parseInt(afterText)).to.equal(3)
})

it('should be able to add 1 minutes', async () => {
Expand Down
9 changes: 9 additions & 0 deletions test/unit/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ export default {
el.dispatchEvent(eventObj)
}
},
triggerWheel (elm, name, deltaY) {
const evt = document.createEvent('MouseEvents')
evt.initEvent(name)
evt.deltaY = deltaY
elm.dispatchEvent
? elm.dispatchEvent(evt)
: elm.fireEvent('on' + name, evt)
return elm
},
sleep (time) {
return new Promise(resolve => {
setTimeout(resolve, time)
Expand Down

0 comments on commit 2bf78f6

Please sign in to comment.