Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tap and dbltap events #100

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/base/events/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,8 @@ Events.CONTAINER_PAUSE = 'container:pause'
Events.CONTAINER_ENDED = 'container:ended'
Events.CONTAINER_CLICK = 'container:click'
Events.CONTAINER_DBLCLICK = 'container:dblclick'
Events.CONTAINER_TAP = 'container:tap'
Events.CONTAINER_DBLTAP = 'container:dbltap'
Events.CONTAINER_CONTEXTMENU = 'container:contextmenu'
Events.CONTAINER_MOUSE_ENTER = 'container:mouseenter'
Events.CONTAINER_MOUSE_LEAVE = 'container:mouseleave'
Expand Down
43 changes: 30 additions & 13 deletions src/components/container/container.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import Events from '@/base/events'
import UIObject from '@/base/ui_object'
import ErrorMixin from '@/base/error_mixin'
import Styler from '@/base/styler'
import { DoubleEventHandler } from '@/utils'

import ContainerStyle from './public/style.scss'

Expand All @@ -37,7 +36,7 @@ export default class Container extends UIObject {
return {
'click': 'clicked',
'dblclick': 'dblClicked',
'touchend': 'dblTap',
'touchend': 'tapped',
'contextmenu': 'onContextMenu',
'mouseenter': 'mouseEnter',
'mouseleave': 'mouseLeave',
Expand Down Expand Up @@ -144,9 +143,9 @@ export default class Container extends UIObject {
this.isReady = false
this.mediaControlDisabled = false
this.plugins = [this.playback]
this.dblTapHandler = new DoubleEventHandler(500)
this.clickTimer = null
this.clickDelay = 200 // FIXME: could be a player option
this.tapTimer = null
this.actionsMetadata = {}
this.bindEvents()
}
Expand Down Expand Up @@ -378,12 +377,13 @@ export default class Container extends UIObject {
this.currentTime = 0
}

clicked() {
clicked(evt) {
if (!this.options.chromeless || this.options.allowUserInteraction) {
// The event is delayed because it can be canceled by a double-click event
// An example of use is to prevent playback from pausing when switching to full screen
this.clickTimer = setTimeout(() => {
this.clickTimer && this.trigger(Events.CONTAINER_CLICK, this, this.name)
this.clickTimer && this.trigger(Events.CONTAINER_CLICK, this, this.name, evt)
this.clickTimer = null
}, this.clickDelay)
}
}
Expand All @@ -393,20 +393,37 @@ export default class Container extends UIObject {
this.clickTimer = null
}

dblClicked() {
dblClicked(evt) {
if (!this.options.chromeless || this.options.allowUserInteraction) {
this.cancelClicked()
this.trigger(Events.CONTAINER_DBLCLICK, this, this.name)
this.trigger(Events.CONTAINER_DBLCLICK, this, this.name, evt)
}
}

dblTap(evt) {
if (!this.options.chromeless || this.options.allowUserInteraction) {
this.dblTapHandler.handle(evt, () => {
this.cancelClicked()
this.trigger(Events.CONTAINER_DBLCLICK, this, this.name)
})
tapped(evt) {
if (this.options.chromeless || !this.options.allowUserInteraction) return

if (this.tapTimer) {
this.cancelTapped()
this.cancelClicked()
this.trigger(Events.CONTAINER_DBLTAP, this, this.name, evt)
// Do not let the browser emit a click event afterward
evt.preventDefault()
return
}

// The event is delayed because it can be canceled by a double tap event
this.tapTimer = setTimeout(() => {
if (this.tapTimer) {
this.trigger(Events.CONTAINER_TAP, this, this.name, evt)
this.tapTimer = null
}
}, this.clickDelay)
}

cancelTapped() {
clearTimeout(this.tapTimer)
this.tapTimer = null
}

onContextMenu(event) {
Expand Down
30 changes: 30 additions & 0 deletions src/components/container/container.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -315,4 +315,34 @@ describe('Container', function() {
expect(this.container.trigger).not.toHaveBeenCalled()
})
})

describe('triggers a CONTAINER_TAP or CONTAINER_DBLTAP depending on the value of the tapTimer', () => {
jest.useFakeTimers()

test('triggers CONTAINER_TAP on touchend', () => {
this.container.options.allowUserInteraction = true
const evt = new TouchEvent('touchend')
const spy = jest.spyOn(this.container, 'trigger')
this.container.tapped(evt)

jest.advanceTimersByTime(this.container.clickDelay)

expect(spy).toHaveBeenCalledWith(Events.CONTAINER_TAP, expect.anything(Object), this.container.name, evt)
})

test('triggers CONTAINER_DBLTAP on double touchend', () => {
this.container.options.allowUserInteraction = true
const evt = new Event('touchend')
const spy = jest.spyOn(this.container, 'trigger')
this.container.tapped(evt)

setTimeout(() => {
this.container.tapped(evt)
}, this.container.clickDelay / 2)

jest.runOnlyPendingTimers()
expect(spy).not.toHaveBeenCalledWith(Events.CONTAINER_TAP)
expect(spy).toHaveBeenCalledWith(Events.CONTAINER_DBLTAP, expect.anything(Object), this.container.name, evt)
})
})
})
21 changes: 0 additions & 21 deletions src/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,26 +309,6 @@ export class DomRecycler {

DomRecycler.options = { recycleVideo: false }

export class DoubleEventHandler {
constructor(delay = 500) {
this.delay = delay
this.lastTime = 0
}

handle(event, cb, prevented = true) {
// Based on http://jsfiddle.net/brettwp/J4djY/
let currentTime = new Date().getTime()
let diffTime = currentTime - this.lastTime

if (diffTime < this.delay && diffTime > 0) {
cb()
prevented && event.preventDefault()
}

this.lastTime = currentTime
}
}

export default {
Config,
Fullscreen,
Expand All @@ -349,5 +329,4 @@ export default {
listContainsIgnoreCase,
canAutoPlayMedia,
Media,
DoubleEventHandler,
}
15 changes: 0 additions & 15 deletions src/utils/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -412,19 +412,4 @@ describe('Utils', () => {
expect(video1).toEqual(video2)
})
})

describe('DoubleEventHandler module', () => {
test('handle double event', (done) => {
const handler = new utils.DoubleEventHandler()
const spy = jest.fn()
const evt = new Event('touchend')

handler.handle(evt, spy)
setTimeout(() => {
handler.handle(evt, spy)
expect(spy).toHaveBeenCalledTimes(1)
done()
}, 500/2)
})
})
})