UNPKG

ember-gestures

Version:

TouchAction and Gesture support for Ember Applications

205 lines (164 loc) 5.78 kB
import { getOwner } from '@ember/application'; import { merge, assign as _assign } from '@ember/polyfills'; import { get, set } from '@ember/object'; import Ember from 'ember'; import defaultHammerEvents from './hammer-events'; import dasherizedToCamel from './utils/string/dasherized-to-camel'; import mobileDetection from './utils/is-mobile'; import { isNone } from '@ember/utils'; const { EventDispatcher, } = Ember; const eventEndings = { pan: ['Start', 'Move', 'End', 'Cancel', 'Left', 'Right', 'Up', 'Down'], pinch: ['Start', 'Move', 'End', 'Cancel', 'In', 'Out'], press: ['Up'], rotate: ['Start', 'Move', 'End', 'Cancel'], swipe: ['Left', 'Right', 'Up', 'Down'], tap: [] }; const assign = _assign || merge; const notFocusableTypes = ['submit', 'file', 'button', 'hidden', 'reset', 'range', 'radio', 'image', 'checkbox']; const fastFocusEvents = ['click', 'touchend']; export default EventDispatcher.extend({ /** Whether or not to cache handler paths on the element when `useCapture` is also true. This needs to be replaced by a feature flag. @private @type {boolean} */ useFastPaths: false, useCapture: false, _gestures: null, _initializeGestures() { const list = getModuleList(); const events = assign({}, defaultHammerEvents); list.forEach((name) => { const recognizer = getOwner(this).factoryFor('ember-gesture:recognizers/' + name); if (recognizer) { addEvent(events, recognizer.class.recognizer, recognizer.class.eventName || name); } }); // add them to the event dispatcher this.set('_gestures', events); }, _fastFocus() { let rootElementSelector = get(this, 'rootElement'); let rootElement; if (rootElementSelector.nodeType) { rootElement = rootElementSelector; } else { rootElement = document.querySelector(rootElementSelector); } fastFocusEvents.forEach((event) => { let listener = this._gestureEvents[event] = (e) => { if (mobileDetection.is()) { let element = e.currentTarget; let target = e.target; /* If the click was on an input element that needs to be able to focus, recast the click as a "focus" event. This fixes tap events on mobile where keyboardShrinksView or similar is true. Such devices depend on the ghost click to trigger focus, but the ghost click will never reach the element. */ //fastfocus if (element.tagName === 'TEXTAREA' || (element.tagName === 'INPUT' && notFocusableTypes.indexOf(element.getAttribute('type')) === -1)) { element.focus(); } else if (target.tagName === 'TEXTAREA' || (target.tagName === 'INPUT' && notFocusableTypes.indexOf(target.getAttribute('type')) === -1)) { target.focus(); } } }; rootElement.addEventListener(event, listener); }); }, willDestroy() { let rootElementSelector = get(this, 'rootElement'); let rootElement; if (rootElementSelector.nodeType) { rootElement = rootElementSelector; } else { rootElement = document.querySelector(rootElementSelector); } if (rootElement) { for (let event in this._gestureEvents) { rootElement.removeEventListener(event, this._gestureEvents[event]); delete this._gestureEvents[event]; } } this._super(...arguments); }, _finalEvents: null, init() { this._gestureEvents = Object.create(null); this._super(...arguments); }, setup(addedEvents, rootElement) { this._initializeGestures(); let events = assign({}, get(this, 'events')); // remove undesirable events from Ember's Eventing if (this.get('removeTracking')) { events.touchstart = null; events.touchmove = null; events.touchcancel = null; events.touchend = null; events.mousedown = null; events.mouseenter = null; events.mousemove = null; events.mouseleave = null; events.mouseup = null; events.drag = null; events.dragend = null; events.dragenter = null; events.dragleave = null; events.dragover = null; events.dragstart = null; events.drop = null; events.dblclick = null; } // delete unwanted events for (let event in events) { if (events.hasOwnProperty(event) && !events[event]) { delete events[event]; } } // override default events this.set('events', events); // add our events to addition events let additionalEvents = assign({}, addedEvents); additionalEvents = assign(additionalEvents, this.get('_gestures')); if (!isNone(rootElement)) { set(this, 'rootElement', rootElement); } this._fastFocus(); return this._super(additionalEvents, rootElement); } }); function addEvent(hash, gesture, name) { const eventName = dasherizedToCamel(name); const eventBase = eventName.toLowerCase(); const endings = eventEndings[gesture]; hash[eventBase] = eventName; endings.forEach((ending) => { const event = eventName + ending; hash[event.toLowerCase()] = event; }); } // this function can be replaced in ember 1.13 with a private api // and in ember 2.0 with a potentially public api matching 1.13's // private api. This is a stop gap for pre-ember 1.13 function getModuleList() { /* global requirejs */ const list = []; for (let moduleName in requirejs.entries) { if (Object.prototype.hasOwnProperty.call(requirejs.entries, moduleName)) { const parts = moduleName.match(/ember-gestures\/recognizers\/(.*)/); if (parts && parts[1].indexOf('jshint') === -1) { list.push(parts[1]); } } } return list; }