diff --git a/lib/utils/gestures.html b/lib/utils/gestures.html index 451433a639..ebe1eac8a3 100644 --- a/lib/utils/gestures.html +++ b/lib/utils/gestures.html @@ -40,22 +40,34 @@ } })(); + /** + * @param {string} name Possible mouse event name + * @return {boolean} true if mouse event, false if not + */ + function isMouseEvent(name) { + return MOUSE_EVENTS.indexOf(name) > -1; + } + /* eslint no-empty: ["error", { "allowEmptyCatch": true }] */ // check for passive event listeners let SUPPORTS_PASSIVE = false; (function() { try { - let opts = Object.defineProperty({}, 'passive', {get: function() {SUPPORTS_PASSIVE = true;}}); + let opts = Object.defineProperty({}, 'passive', {get() {SUPPORTS_PASSIVE = true;}}); window.addEventListener('test', null, opts); window.removeEventListener('test', null, opts); } catch(e) {} })(); + // decide whether to use {passive: true} for gestures listening for touch events + let PASSIVE_TOUCH = Boolean(HAS_NATIVE_TA && SUPPORTS_PASSIVE && Polymer.passiveTouchGestures); + // Check for touch-only devices let IS_TOUCH_ONLY = navigator.userAgent.match(/iP(?:[oa]d|hone)|Android/); let GestureRecognizer = function(){}; // eslint-disable-line no-unused-vars - GestureRecognizer.prototype.reset = function(){}; + /** @type {function()} */ + GestureRecognizer.prototype.reset; /** @type {function(MouseEvent) | undefined} */ GestureRecognizer.prototype.mousedown; /** @type {(function(MouseEvent) | undefined)} */ @@ -140,7 +152,7 @@ function hasLeftMouseButton(ev) { let type = ev.type; // exit early if the event is not a mouse event - if (MOUSE_EVENTS.indexOf(type) === -1) { + if (!isMouseEvent(type)) { return false; } // ev.button is not reliable for mousemove (0 is overloaded as both left button and no buttons) @@ -450,7 +462,7 @@ for (let i = 0, dep, gd; i < deps.length; i++) { dep = deps[i]; // don't add mouse handlers on iOS because they cause gray selection overlays - if (IS_TOUCH_ONLY && MOUSE_EVENTS.indexOf(dep) > -1 && dep !== 'click') { + if (IS_TOUCH_ONLY && isMouseEvent(dep) && dep !== 'click') { continue; } gd = gobj[dep]; @@ -458,7 +470,8 @@ gobj[dep] = gd = {_count: 0}; } if (gd._count === 0) { - node.addEventListener(dep, this._handleNative); + let options = !isMouseEvent(dep) && PASSIVE_TOUCH ? {passive: true} : undefined; + node.addEventListener(dep, this._handleNative, options); } gd[name] = (gd[name] || 0) + 1; gd._count = (gd._count || 0) + 1; @@ -491,7 +504,8 @@ gd[name] = (gd[name] || 1) - 1; gd._count = (gd._count || 1) - 1; if (gd._count === 0) { - node.removeEventListener(dep, this._handleNative); + let options = !isMouseEvent(dep) && PASSIVE_TOUCH ? {passive: true} : undefined; + node.removeEventListener(dep, this._handleNative, options); } } } diff --git a/lib/utils/settings.html b/lib/utils/settings.html index 4846ef5334..56e91f1945 100644 --- a/lib/utils/settings.html +++ b/lib/utils/settings.html @@ -93,5 +93,15 @@ Polymer.setSanitizeDOMValue = function(newSanitizeDOMValue) { Polymer.sanitizeDOMValue = newSanitizeDOMValue; }; + + /** + * Globally settable property to make Polymer Gestures use passive TouchEvent listeners when recognizing gestures. + * When set to `true`, gestures made from touch will not be able to prevent scrolling, allowing for smoother + * scrolling performance. + * Defaults to `false` for backwards compatibility. + * + * @memberof Polymer + */ + Polymer.passiveTouchGestures = false; })();