From 6847cf47916b99b573e4a49b083dec937f10c83a Mon Sep 17 00:00:00 2001 From: Alexander Marks Date: Thu, 2 Aug 2018 14:58:07 -0700 Subject: [PATCH] Make Polymer gestures library safe for Closure property renaming (take 2). (#5314) Make Polymer gestures library safe for Closure property renaming. The issue here was that we were assuming that the method for a given gesture would always match the string name of that gesture, e.g. that if the gesture name was "mousedown" that we could call gestureDefinition.mousedown. In actuality, gestureDefinition.mousedown could be renamed by Closure, which would throw with "undefined is not a function". The fix is to move the GesturesRecognizer type into our externs, which prevents those methods from being renamed. --- externs/polymer-internal-shared-types.js | 48 ++++++++++++++++++++++++ lib/utils/gestures.js | 47 ++--------------------- 2 files changed, 51 insertions(+), 44 deletions(-) diff --git a/externs/polymer-internal-shared-types.js b/externs/polymer-internal-shared-types.js index 937ba617ed..fd954c1180 100644 --- a/externs/polymer-internal-shared-types.js +++ b/externs/polymer-internal-shared-types.js @@ -164,3 +164,51 @@ function AsyncInterface(){} AsyncInterface.prototype.run; /** @type {function(number): void} */ AsyncInterface.prototype.cancel; + +/** @record */ +let GestureInfo = function(){}; +/** @type {string|undefined} */ +GestureInfo.prototype.state; +/** @type {boolean|undefined} */ +GestureInfo.prototype.started; +/** @type {!Array|undefined} */ +GestureInfo.prototype.moves; +/** @type {number|undefined} */ +GestureInfo.prototype.x; +/** @type {number|undefined} */ +GestureInfo.prototype.y; +/** @type {boolean|undefined} */ +GestureInfo.prototype.prevent; +/** @type {function(?): void|undefined} */ +GestureInfo.prototype.addMove; +/** @type {null|undefined} */ +GestureInfo.prototype.movefn; +/** @type {null|undefined} */ +GestureInfo.prototype.upFn; + +/** @record */ +let GestureRecognizer = function(){}; +/** @type {string} */ +GestureRecognizer.prototype.name; +/** @type {!Array} */ +GestureRecognizer.prototype.deps; +/** @type {function(): void} */ +GestureRecognizer.prototype.reset; +/** @type {function(MouseEvent): void | undefined} */ +GestureRecognizer.prototype.mousedown; +/** @type {(function(MouseEvent): void | undefined)} */ +GestureRecognizer.prototype.mousemove; +/** @type {(function(MouseEvent): void | undefined)} */ +GestureRecognizer.prototype.mouseup; +/** @type {(function(TouchEvent): void | undefined)} */ +GestureRecognizer.prototype.touchstart; +/** @type {(function(TouchEvent): void | undefined)} */ +GestureRecognizer.prototype.touchmove; +/** @type {(function(TouchEvent): void | undefined)} */ +GestureRecognizer.prototype.touchend; +/** @type {(function(MouseEvent): void | undefined)} */ +GestureRecognizer.prototype.click; +/** @type {!GestureInfo} */ +GestureRecognizer.prototype.info; +/** @type {!Array} */ +GestureRecognizer.prototype.emits; diff --git a/lib/utils/gestures.js b/lib/utils/gestures.js index 9b0548bf4d..c2a93270a1 100644 --- a/lib/utils/gestures.js +++ b/lib/utils/gestures.js @@ -92,50 +92,6 @@ function PASSIVE_TOUCH(eventName) { // Check for touch-only devices let IS_TOUCH_ONLY = navigator.userAgent.match(/iP(?:[oa]d|hone)|Android/); -/** @record */ -const GestureInfo = function(){}; // eslint-disable-line no-unused-vars -/** @type {string|undefined} */ -GestureInfo.prototype.state; -/** @type {boolean|undefined} */ -GestureInfo.prototype.started; -/** @type {!Array|undefined} */ -GestureInfo.prototype.moves; -/** @type {number|undefined} */ -GestureInfo.prototype.x; -/** @type {number|undefined} */ -GestureInfo.prototype.y; -/** @type {boolean|undefined} */ -GestureInfo.prototype.prevent; -/** @type {function(?): void|undefined} */ -GestureInfo.prototype.addMove; -/** @type {null|undefined} */ -GestureInfo.prototype.movefn; -/** @type {null|undefined} */ -GestureInfo.prototype.upFn; - -/** @record */ -const GestureRecognizer = function(){}; // eslint-disable-line no-unused-vars -/** @type {function(): void} */ -GestureRecognizer.prototype.reset; -/** @type {function(MouseEvent): void | undefined} */ -GestureRecognizer.prototype.mousedown; -/** @type {(function(MouseEvent): void | undefined)} */ -GestureRecognizer.prototype.mousemove; -/** @type {(function(MouseEvent): void | undefined)} */ -GestureRecognizer.prototype.mouseup; -/** @type {(function(TouchEvent): void | undefined)} */ -GestureRecognizer.prototype.touchstart; -/** @type {(function(TouchEvent): void | undefined)} */ -GestureRecognizer.prototype.touchmove; -/** @type {(function(TouchEvent): void | undefined)} */ -GestureRecognizer.prototype.touchend; -/** @type {(function(MouseEvent): void | undefined)} */ -GestureRecognizer.prototype.click; -/** @type {!GestureInfo} */ -GestureRecognizer.prototype.info; -/** @type {!Array} */ -GestureRecognizer.prototype.emits; - // keep track of any labels hit by the mouseCanceller /** @type {!Array} */ const clickedLabels = []; @@ -378,7 +334,10 @@ function untrackDocument(stateObj) { // Use passive event listeners, if supported, to not affect scrolling performance document.addEventListener('touchend', ignoreMouse, SUPPORTS_PASSIVE ? {passive: true} : false); +/** @type {!Object} */ export const gestures = {}; + +/** @type {!Array} */ export const recognizers = []; /**