Mobile Safari “swallowing” events in Backbone.js app
-
12-12-2019 - |
Question
I'm experiencing a strange issue w/ a Backbone.js app. In my main view, I want to capture all input events that occur over the view and route them to input handler methods. I also have some links in the view that navigate to other parts of the app. Relevant (CoffeeScript) code:
events:
'click a.quit': 'quit'
'mousedown': 'onActionStart'
'mouseup': 'onActionEnd'
'touchstart': 'onActionStart'
'touchmove': 'onActionMove'
'touchend': 'onActionEnd'
The event handling works as expected in desktop Safari. When I click the "quit" link, the "onAction__" methods fire, and then the "quit" method is called. However, on Mobile Safari, the "quit" method doesn't get called. If I modify the touch event selectors to only respond to a smaller area in the view (i.e. an element not overlapping the link), then it works as expected. (All the methods that are triggered via user input have preventDefault() calls in them, but that shouldn't stop the events from bubbling.) Is this a known Mobile Safari issue?
Solution
Well, I ended up turning the "events" object into a function and doing basic browser sniffing to detect platforms with touchscreens. Turning 'click a.quit': 'quit'
into 'mouseup a.quit': 'quit'
gets called correctly, even though the Safari docs say
If the user taps a clickable element, events arrive in this order: mouseover, mousemove, mousedown, mouseup, and click
Here's my result:
events: ->
# Determine whether touchscreen or desktop
agent = navigator.userAgent.toLowerCase()
if agent.match(/ip(hone|od|ad)/i) or agent.match(/android/i)
events =
'touchend a.quit': 'quit'
'touchend a.reset': 'reset'
'touchstart': 'onActionStart'
'touchmove': 'onActionMove'
'touchend': 'onActionEnd'
'onscroll': 'preventDefault'
'gesturestart': 'preventDefault'
'gesturechange': 'preventDefault'
'gestureend': 'preventDefault'
else
events =
'click a.quit': 'quit'
'click a.reset': 'reset'
'mousedown': 'onActionStart'
'mouseup': 'onActionEnd'