From 3b8171922f67f84b2a63bb6e10a29e8e34e0b157 Mon Sep 17 00:00:00 2001 From: Alexander Marks Date: Thu, 26 Jul 2018 14:44:10 -0700 Subject: [PATCH] Upstream a bunch of g3 changes. --- externs/closure-types.js | 27 +- externs/polymer-externs.js | 80 +++++- externs/polymer-internal-shared-types.js | 1 + lib/elements/dom-module.js | 1 + lib/legacy/legacy-element-mixin.js | 2 +- lib/legacy/polymer.dom.js | 64 +++-- lib/mixins/gesture-event-listeners.js | 78 +++--- lib/mixins/properties-changed.js | 36 ++- lib/mixins/properties-mixin.js | 13 +- lib/mixins/template-stamp.js | 10 +- lib/utils/case-map.js | 7 +- lib/utils/gestures.js | 323 ++++++++++++----------- lib/utils/html-tag.js | 1 + lib/utils/mixin.js | 2 +- 14 files changed, 385 insertions(+), 260 deletions(-) diff --git a/externs/closure-types.js b/externs/closure-types.js index 8e7f3dd19a..42c1a702bf 100644 --- a/externs/closure-types.js +++ b/externs/closure-types.js @@ -33,7 +33,7 @@ Polymer_PropertiesChanged.prototype._addPropertyToAttributeMap = function(proper */ Polymer_PropertiesChanged.prototype._definePropertyAccessor = function(property, readOnly){}; /** -* @return {void} +* @return {void|!Promise} */ Polymer_PropertiesChanged.prototype.ready = function(){}; /** @@ -105,7 +105,7 @@ Polymer_PropertiesChanged.prototype._shouldPropertyChange = function(property, v * @param {string} name Name of attribute that changed * @param {?string} old Old attribute value * @param {?string} value New attribute value -* @param {?string} namespace Attribute namespace. +* @param {?string} namespace Namespace of the attribute * @return {void} */ Polymer_PropertiesChanged.prototype.attributeChangedCallback = function(name, old, value, namespace){}; @@ -379,7 +379,7 @@ Polymer_PropertyEffects.prototype.__templateInfo; Polymer_PropertyEffects.prototype._stampTemplate = function(template){}; /** * @override -* @return {void} +* @return {void|!Promise} */ Polymer_PropertyEffects.prototype.ready = function(){}; /** @@ -760,7 +760,7 @@ Polymer_PropertyEffects._addTemplatePropertyEffect = function(templateInfo, prop */ Polymer_PropertyEffects._parseBindings = function(text, templateInfo){}; /** -* @param {this} inst Element that should be used as scope for +* @param {Element} inst Element that should be used as scope for binding dependencies * @param {BindingPart} part Binding part metadata * @param {string} path Property/path that triggered this effect @@ -973,7 +973,7 @@ Polymer_LegacyElementMixin.prototype._initializeProperties = function(){}; * @param {string} name Name of attribute. * @param {?string} old Old value of attribute. * @param {?string} value Current value of attribute. -* @param {?string} namespace Attribute namespace. +* @param {?string} namespace Namespace of the attribute * @return {void} */ Polymer_LegacyElementMixin.prototype.attributeChangedCallback = function(name, old, value, namespace){}; @@ -1174,7 +1174,7 @@ Polymer_LegacyElementMixin.prototype.getComputedStyleValue = function(property){ * @param {string} jobName String to identify the debounce job. * @param {function (): void} callback Function that is called (with `this` context) when the wait time elapses. -* @param {number} wait Optional wait time in milliseconds (ms) after the +* @param {number=} wait Optional wait time in milliseconds (ms) after the last signal that must elapse before invoking `callback` * @return {!Object} */ @@ -1379,17 +1379,6 @@ Polymer_ArraySelectorMixin.prototype.select = function(item){}; Polymer_ArraySelectorMixin.prototype.selectIndex = function(idx){}; /** * @interface -* @extends {Polymer_PropertyEffects} -*/ -function Polymer_StrictBindingParser(){} -/** -* @param {string} text Text to parse from attribute or textContent -* @param {Object} templateInfo Current template metadata -* @return {Array.} -*/ -Polymer_StrictBindingParser._parseBindings = function(text, templateInfo){}; -/** -* @interface * @extends {Polymer_ElementMixin} */ function Polymer_DisableUpgradeMixin(){} @@ -1404,7 +1393,7 @@ Polymer_DisableUpgradeMixin.prototype._enableProperties = function(){}; /** * @override */ -Polymer_DisableUpgradeMixin.prototype.attributeChangedCallback = function(name, old, value, namespace){}; +Polymer_DisableUpgradeMixin.prototype.attributeChangedCallback = function(name, old, value){}; /** * @override */ @@ -1412,4 +1401,4 @@ Polymer_DisableUpgradeMixin.prototype.connectedCallback = function(){}; /** * @override */ -Polymer_DisableUpgradeMixin.prototype.disconnectedCallback = function(){}; \ No newline at end of file +Polymer_DisableUpgradeMixin.prototype.disconnectedCallback = function(){}; diff --git a/externs/polymer-externs.js b/externs/polymer-externs.js index 53bcf01323..a34727c2bc 100644 --- a/externs/polymer-externs.js +++ b/externs/polymer-externs.js @@ -15,22 +15,23 @@ /** * @typedef {{ - * type: !Function, - * value: *, - * readOnly: (boolean | undefined), - * computed: (string | undefined), - * reflectToAttribute: (boolean | undefined), - * notify: (boolean | undefined), - * observer: (string | function(*,*) | undefined) + * type: !Function, + * value: (* | undefined), + * readOnly: (boolean | undefined), + * computed: (string | undefined), + * reflectToAttribute: (boolean | undefined), + * notify: (boolean | undefined), + * observer: (string | function(this:?, ?, ?) | undefined) * }} */ let PolymerElementPropertiesMeta; /** - * @typedef {Object} + * @typedef {Object} */ let PolymerElementProperties; +/** @record */ let PolymerInit = function(){}; /** @type {string} */ PolymerInit.prototype.is; @@ -59,9 +60,12 @@ PolymerElementConstructor.observers; /** @type {(!HTMLTemplateElement | string | undefined)} */ PolymerElementConstructor.template; +/** @interface */ let PropertiesMixinConstructor = function (){}; /** @type {(!PolymerElementProperties | undefined)} */ -PropertiesMixinConstructor.properties; +PropertiesMixinConstructor.prototype.properties; +/** @return {void} */ +PropertiesMixinConstructor.prototype.finalize = function() {}; /** * @param {!PolymerInit} init @@ -69,9 +73,6 @@ PropertiesMixinConstructor.properties; */ function Polymer(init){} -/** @type {PolymerElementProperties} */ -Polymer.ElementProperties; - /** * @type {(function(*,string,string,Node):*)|undefined} */ @@ -95,7 +96,7 @@ PolymerTelemetry._regLog; /** @type {function(HTMLElement)} */ PolymerTelemetry.register; /** @type {function(HTMLElement)} */ -PolymerTelemetry.dumpRegistrations;; +PolymerTelemetry.dumpRegistrations; /** @type {PolymerTelemetry} */ Polymer.telemetry; @@ -110,3 +111,56 @@ Polymer.version; * @implements {Polymer_LegacyElementMixin} */ var PolymerElement = function() {}; + +/** + * On create callback. + * @override + */ +PolymerElement.prototype.created = function() {}; +/** + * On ready callback. + * @override + */ +PolymerElement.prototype.ready = function() {}; +/** On registered callback. */ +PolymerElement.prototype.registered = function() {}; +/** + * On attached to the DOM callback. + * @override + */ +PolymerElement.prototype.attached = function() {}; +/** + * On detached from the DOM callback. + * @override + */ +PolymerElement.prototype.detached = function() {}; + +/** + * @typedef {{ + * index: number, + * removed: !Array, + * addedCount: number, + * object: !Array, + * type: string, + * }} + */ +var PolymerSplice; +/** + * @typedef {{ + * indexSplices: ?Array, + * }} + */ +var PolymerSpliceChange; + +/** + * The type of the object received by an observer function when deep + * sub-property observation is enabled. See: + * https://www.polymer-project.org/2.0/docs/devguide/observers#deep-observation + * + * @typedef {{ + * path: string, + * value: (?Object|undefined), + * base: (?Object|undefined) + * }} + */ +var PolymerDeepPropertyChange; diff --git a/externs/polymer-internal-shared-types.js b/externs/polymer-internal-shared-types.js index 274f60351d..937ba617ed 100644 --- a/externs/polymer-internal-shared-types.js +++ b/externs/polymer-internal-shared-types.js @@ -1,5 +1,6 @@ /** * @fileoverview Internal shared types for Polymer + * @externs * * @license * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. diff --git a/lib/elements/dom-module.js b/lib/elements/dom-module.js index ae35fe99bb..055f37b30e 100644 --- a/lib/elements/dom-module.js +++ b/lib/elements/dom-module.js @@ -78,6 +78,7 @@ export class DomModule extends HTMLElement { * @param {?string} value Current value of attribute. * @param {?string} namespace Attribute namespace. * @return {void} + * @override */ attributeChangedCallback(name, old, value, namespace) { if (old !== value) { diff --git a/lib/legacy/legacy-element-mixin.js b/lib/legacy/legacy-element-mixin.js index 5a6e1c030c..5b9a769c86 100644 --- a/lib/legacy/legacy-element-mixin.js +++ b/lib/legacy/legacy-element-mixin.js @@ -467,7 +467,7 @@ export const LegacyElementMixin = dedupingMixin((base) => { * @return {void} */ setScrollDirection(direction, node) { - setTouchAction( (node || this), DIRECTION_MAP[direction] || 'auto'); + setTouchAction(/** @type {Element} */ (node || this), DIRECTION_MAP[direction] || 'auto'); } /* **** End Events **** */ diff --git a/lib/legacy/polymer.dom.js b/lib/legacy/polymer.dom.js index 95364f8391..ec79419604 100644 --- a/lib/legacy/polymer.dom.js +++ b/lib/legacy/polymer.dom.js @@ -231,23 +231,6 @@ function forwardProperties(proto, properties) { } } -forwardMethods(DomApi.prototype, [ - 'cloneNode', 'appendChild', 'insertBefore', 'removeChild', - 'replaceChild', 'setAttribute', 'removeAttribute', - 'querySelector', 'querySelectorAll' -]); - -forwardReadOnlyProperties(DomApi.prototype, [ - 'parentNode', 'firstChild', 'lastChild', - 'nextSibling', 'previousSibling', 'firstElementChild', - 'lastElementChild', 'nextElementSibling', 'previousElementSibling', - 'childNodes', 'children', 'classList' -]); - -forwardProperties(DomApi.prototype, [ - 'textContent', 'innerHTML' -]); - /** * Event API wrapper class returned from `Polymer.dom.(target)` when @@ -343,6 +326,53 @@ DomApi.prototype.querySelector; */ DomApi.prototype.querySelectorAll; +/** @type {?Node} */ +DomApi.prototype.parentNode; +/** @type {?Node} */ +DomApi.prototype.firstChild; +/** @type {?Node} */ +DomApi.prototype.lastChild; +/** @type {?Node} */ +DomApi.prototype.nextSibling; +/** @type {?Node} */ +DomApi.prototype.previousSibling; +/** @type {?HTMLElement} */ +DomApi.prototype.firstElementChild; +/** @type {?HTMLElement} */ +DomApi.prototype.lastElementChild; +/** @type {?HTMLElement} */ +DomApi.prototype.nextElementSibling; +/** @type {?HTMLElement} */ +DomApi.prototype.previousElementSibling; +/** @type {!Array} */ +DomApi.prototype.childNodes; +/** @type {!Array} */ +DomApi.prototype.children; +/** @type {?DOMTokenList} */ +DomApi.prototype.classList; + +/** @type {string} */ +DomApi.prototype.textContent; +/** @type {string} */ +DomApi.prototype.innerHTML; + +forwardMethods(DomApi.prototype, [ + 'cloneNode', 'appendChild', 'insertBefore', 'removeChild', + 'replaceChild', 'setAttribute', 'removeAttribute', + 'querySelector', 'querySelectorAll' +]); + +forwardReadOnlyProperties(DomApi.prototype, [ + 'parentNode', 'firstChild', 'lastChild', + 'nextSibling', 'previousSibling', 'firstElementChild', + 'lastElementChild', 'nextElementSibling', 'previousElementSibling', + 'childNodes', 'children', 'classList' +]); + +forwardProperties(DomApi.prototype, [ + 'textContent', 'innerHTML' +]); + /** * Legacy DOM and Event manipulation API wrapper factory used to abstract * differences between native Shadow DOM and "Shady DOM" when polyfilling on diff --git a/lib/mixins/gesture-event-listeners.js b/lib/mixins/gesture-event-listeners.js index af1bd0dde9..355a9285d2 100644 --- a/lib/mixins/gesture-event-listeners.js +++ b/lib/mixins/gesture-event-listeners.js @@ -29,45 +29,45 @@ const gestures = gestures$0; * cross-platform * gesture events to nodes */ -export const GestureEventListeners = dedupingMixin(superClass => { +export const GestureEventListeners = dedupingMixin( + /** @param {function(new:HTMLElement)} superClass */ + (superClass) => { + /** + * @polymer + * @mixinClass + * @implements {Polymer_GestureEventListeners} + */ + class GestureEventListeners extends superClass { + /** + * Add the event listener to the node if it is a gestures event. + * + * @param {!Node} node Node to add event listener to + * @param {string} eventName Name of event + * @param {function(!Event):void} handler Listener function to add + * @return {void} + * @override + */ + _addEventListenerToNode(node, eventName, handler) { + if (!gestures.addListener(node, eventName, handler)) { + super._addEventListenerToNode(node, eventName, handler); + } + } - /** - * @polymer - * @mixinClass - * @implements {Polymer_GestureEventListeners} - */ - class GestureEventListeners extends superClass { - - /** - * Add the event listener to the node if it is a gestures event. - * - * @param {!Node} node Node to add event listener to - * @param {string} eventName Name of event - * @param {function(!Event):void} handler Listener function to add - * @return {void} - */ - _addEventListenerToNode(node, eventName, handler) { - if (!gestures.addListener(node, eventName, handler)) { - super._addEventListenerToNode(node, eventName, handler); - } - } - - /** - * Remove the event listener to the node if it is a gestures event. - * - * @param {!Node} node Node to remove event listener from - * @param {string} eventName Name of event - * @param {function(!Event):void} handler Listener function to remove - * @return {void} - */ - _removeEventListenerFromNode(node, eventName, handler) { - if (!gestures.removeListener(node, eventName, handler)) { - super._removeEventListenerFromNode(node, eventName, handler); + /** + * Remove the event listener to the node if it is a gestures event. + * + * @param {!Node} node Node to remove event listener from + * @param {string} eventName Name of event + * @param {function(!Event):void} handler Listener function to remove + * @return {void} + * @override + */ + _removeEventListenerFromNode(node, eventName, handler) { + if (!gestures.removeListener(node, eventName, handler)) { + super._removeEventListenerFromNode(node, eventName, handler); + } + } } - } - - } - - return GestureEventListeners; -}); + return GestureEventListeners; + }); diff --git a/lib/mixins/properties-changed.js b/lib/mixins/properties-changed.js index 7922bcf233..56089d5d4d 100644 --- a/lib/mixins/properties-changed.js +++ b/lib/mixins/properties-changed.js @@ -33,12 +33,13 @@ const microtask = microTask; * @summary Element class mixin for reacting to property changes from * generated property accessors. */ -export const PropertiesChanged = dedupingMixin(superClass => { +export const PropertiesChanged = dedupingMixin( + /** @param {function(new:HTMLElement)} superClass */ + (superClass) => { /** * @polymer * @mixinClass - * @extends {superClass} * @implements {Polymer_PropertiesChanged} * @unrestricted */ @@ -97,6 +98,7 @@ export const PropertiesChanged = dedupingMixin(superClass => { * protected `_setProperty` function must be used to set the property * @return {void} * @protected + * @override */ _createPropertyAccessor(property, readOnly) { this._addPropertyToAttributeMap(property); @@ -115,6 +117,7 @@ export const PropertiesChanged = dedupingMixin(superClass => { * used when deserializing attribute values to properties. * * @param {string} property Name of the property + * @override */ _addPropertyToAttributeMap(property) { if (!this.hasOwnProperty('__dataAttributes')) { @@ -131,6 +134,7 @@ export const PropertiesChanged = dedupingMixin(superClass => { * @param {string} property Name of the property * @param {boolean=} readOnly When true, no setter is created * @return {void} + * @override */ _definePropertyAccessor(property, readOnly) { Object.defineProperty(this, property, { @@ -171,8 +175,9 @@ export const PropertiesChanged = dedupingMixin(superClass => { * bindings. `super.ready()` must be called to ensure the data system * becomes enabled. * - * @return {void} + * @return {void|!Promise} * @public + * @override */ ready() { this.__dataReady = true; @@ -187,6 +192,7 @@ export const PropertiesChanged = dedupingMixin(superClass => { * * @return {void} * @protected + * @override */ _initializeProperties() { // Capture instance properties; these will be set into accessors @@ -213,6 +219,7 @@ export const PropertiesChanged = dedupingMixin(superClass => { * when creating property accessors. * @return {void} * @protected + * @override */ _initializeInstanceProperties(props) { Object.assign(this, props); @@ -226,6 +233,7 @@ export const PropertiesChanged = dedupingMixin(superClass => { * @param {*} value Value to set * @return {void} * @protected + * @override */ _setProperty(property, value) { if (this._setPendingProperty(property, value)) { @@ -238,6 +246,7 @@ export const PropertiesChanged = dedupingMixin(superClass => { * @param {string} property Name of property * @return {*} Value for the given property * @protected + * @override */ _getProperty(property) { return this.__data[property]; @@ -255,6 +264,7 @@ export const PropertiesChanged = dedupingMixin(superClass => { * @param {boolean=} ext Not used here; affordance for closure * @return {boolean} Returns true if the property changed * @protected + * @override */ _setPendingProperty(property, value, ext) { let old = this.__data[property]; @@ -281,6 +291,7 @@ export const PropertiesChanged = dedupingMixin(superClass => { * * @return {void} * @protected + * @override */ _invalidateProperties() { if (!this.__dataInvalid && this.__dataReady) { @@ -304,6 +315,7 @@ export const PropertiesChanged = dedupingMixin(superClass => { * * @return {void} * @protected + * @override */ _enableProperties() { if (!this.__dataEnabled) { @@ -324,6 +336,7 @@ export const PropertiesChanged = dedupingMixin(superClass => { * * @return {void} * @protected + * @override */ _flushProperties() { const props = this.__data; @@ -342,11 +355,12 @@ export const PropertiesChanged = dedupingMixin(superClass => { * properties are pending. Override to customize when * `_propertiesChanged` is called. * @param {!Object} currentProps Bag of all current accessor values - * @param {!Object} changedProps Bag of properties changed since the last + * @param {?Object} changedProps Bag of properties changed since the last * call to `_propertiesChanged` - * @param {!Object} oldProps Bag of previous values for each property + * @param {?Object} oldProps Bag of previous values for each property * in `changedProps` * @return {boolean} true if changedProps is truthy + * @override */ _shouldPropertiesChange(currentProps, changedProps, oldProps) { // eslint-disable-line no-unused-vars return Boolean(changedProps); @@ -357,12 +371,13 @@ export const PropertiesChanged = dedupingMixin(superClass => { * `_createPropertyAccessor` have been set. * * @param {!Object} currentProps Bag of all current accessor values - * @param {!Object} changedProps Bag of properties changed since the last + * @param {?Object} changedProps Bag of properties changed since the last * call to `_propertiesChanged` - * @param {!Object} oldProps Bag of previous values for each property + * @param {?Object} oldProps Bag of previous values for each property * in `changedProps` * @return {void} * @protected + * @override */ _propertiesChanged(currentProps, changedProps, oldProps) { // eslint-disable-line no-unused-vars } @@ -384,6 +399,7 @@ export const PropertiesChanged = dedupingMixin(superClass => { * @return {boolean} Whether the property should be considered a change * and enqueue a `_proeprtiesChanged` callback * @protected + * @override */ _shouldPropertyChange(property, value, old) { return ( @@ -404,6 +420,7 @@ export const PropertiesChanged = dedupingMixin(superClass => { * @param {?string} namespace Attribute namespace. * @return {void} * @suppress {missingProperties} Super may or may not implement the callback + * @override */ attributeChangedCallback(name, old, value, namespace) { if (old !== value) { @@ -425,6 +442,7 @@ export const PropertiesChanged = dedupingMixin(superClass => { * @param {*=} type type to deserialize to, defaults to the value * returned from `typeForProperty` * @return {void} + * @override */ _attributeToProperty(attribute, value, type) { if (!this.__serializing) { @@ -444,6 +462,7 @@ export const PropertiesChanged = dedupingMixin(superClass => { * @param {string=} attribute Attribute name to reflect to. * @param {*=} value Property value to refect. * @return {void} + * @override */ _propertyToAttribute(property, attribute, value) { this.__serializing = true; @@ -465,6 +484,7 @@ export const PropertiesChanged = dedupingMixin(superClass => { * @param {*} value Value to serialize. * @param {string} attribute Attribute name to serialize to. * @return {void} + * @override */ _valueToNodeAttribute(node, value, attribute) { const str = this._serializeValue(value); @@ -485,6 +505,7 @@ export const PropertiesChanged = dedupingMixin(superClass => { * @param {*} value Property value to serialize. * @return {string | undefined} String serialized from the provided * property value. + * @override */ _serializeValue(value) { switch (typeof value) { @@ -506,6 +527,7 @@ export const PropertiesChanged = dedupingMixin(superClass => { * @param {?string} value Value to deserialize. * @param {*=} type Type to deserialize the string to. * @return {*} Typed value deserialized from the provided string. + * @override */ _deserializeValue(value, type) { switch (type) { diff --git a/lib/mixins/properties-mixin.js b/lib/mixins/properties-mixin.js index a6d25ae6e9..a74889d115 100644 --- a/lib/mixins/properties-mixin.js +++ b/lib/mixins/properties-mixin.js @@ -51,7 +51,6 @@ export const PropertiesMixin = dedupingMixin(superClass => { /** * @constructor - * @extends {superClass} * @implements {Polymer_PropertiesChanged} * @private */ @@ -62,7 +61,7 @@ export const PropertiesMixin = dedupingMixin(superClass => { * instance of the PropertiesMixin. * * @param {!PropertiesMixinConstructor} constructor PropertiesMixin constructor - * @return {PropertiesMixinConstructor} Super class constructor + * @return {?PropertiesMixinConstructor} Super class constructor */ function superPropertiesClass(constructor) { const superCtor = Object.getPrototypeOf(constructor); @@ -72,7 +71,7 @@ export const PropertiesMixin = dedupingMixin(superClass => { // because the mixin is deduped and guaranteed only to apply once, hence // all constructors in a proto chain will see the same `PropertiesMixin` return (superCtor.prototype instanceof PropertiesMixin) ? - /** @type {PropertiesMixinConstructor} */ (superCtor) : null; + /** @type {!PropertiesMixinConstructor} */ (superCtor) : null; } /** @@ -124,7 +123,7 @@ export const PropertiesMixin = dedupingMixin(superClass => { */ static finalize() { if (!this.hasOwnProperty(JSCompiler_renameProperty('__finalized', this))) { - const superCtor = superPropertiesClass(/** @type {PropertiesMixinConstructor} */(this)); + const superCtor = superPropertiesClass(/** @type {!PropertiesMixinConstructor} */(this)); if (superCtor) { superCtor.finalize(); } @@ -141,7 +140,7 @@ export const PropertiesMixin = dedupingMixin(superClass => { * @protected */ static _finalizeClass() { - const props = ownProperties(/** @type {PropertiesMixinConstructor} */(this)); + const props = ownProperties(/** @type {!PropertiesMixinConstructor} */(this)); if (props) { this.createProperties(props); } @@ -158,7 +157,7 @@ export const PropertiesMixin = dedupingMixin(superClass => { static get _properties() { if (!this.hasOwnProperty( JSCompiler_renameProperty('__properties', this))) { - const superCtor = superPropertiesClass(/** @type {PropertiesMixinConstructor} */(this)); + const superCtor = superPropertiesClass(/** @type {!PropertiesMixinConstructor} */(this)); this.__properties = Object.assign({}, superCtor && superCtor._properties, ownProperties(/** @type {PropertiesMixinConstructor} */(this))); @@ -196,6 +195,7 @@ export const PropertiesMixin = dedupingMixin(superClass => { * `PropertiesChanged`. * @suppress {missingProperties} Super may or may not implement the callback * @return {void} + * @override */ connectedCallback() { if (super.connectedCallback) { @@ -208,6 +208,7 @@ export const PropertiesMixin = dedupingMixin(superClass => { * Called when the element is removed from a document * @suppress {missingProperties} Super may or may not implement the callback * @return {void} + * @override */ disconnectedCallback() { if (super.disconnectedCallback) { diff --git a/lib/mixins/template-stamp.js b/lib/mixins/template-stamp.js index 8dd7a1195d..f96909f54c 100644 --- a/lib/mixins/template-stamp.js +++ b/lib/mixins/template-stamp.js @@ -105,7 +105,9 @@ function createNodeEventHandler(context, eventName, methodName) { * @polymer * @summary Element class mixin that provides basic template parsing and stamping */ -export const TemplateStamp = dedupingMixin(superClass => { +export const TemplateStamp = dedupingMixin( + /** @param {function(new:HTMLElement)} superClass */ + (superClass) => { /** * @polymer @@ -406,6 +408,7 @@ export const TemplateStamp = dedupingMixin(superClass => { * * @param {!HTMLTemplateElement} template Template to stamp * @return {!StampedTemplate} Cloned template content + * @override */ _stampTemplate(template) { // Polyfill support: bootstrap the template if it has not already been @@ -443,6 +446,7 @@ export const TemplateStamp = dedupingMixin(superClass => { * @param {*=} context Context the method will be called on (defaults * to `node`) * @return {Function} Generated handler function + * @override */ _addMethodEventListenerToNode(node, eventName, methodName, context) { context = context || node; @@ -458,6 +462,7 @@ export const TemplateStamp = dedupingMixin(superClass => { * @param {string} eventName Name of event * @param {function(!Event):void} handler Listener function to add * @return {void} + * @override */ _addEventListenerToNode(node, eventName, handler) { node.addEventListener(eventName, handler); @@ -466,10 +471,11 @@ export const TemplateStamp = dedupingMixin(superClass => { /** * Override point for adding custom or simulated event handling. * - * @param {!Node} node Node to remove event listener from + * @param {Node} node Node to remove event listener from * @param {string} eventName Name of event * @param {function(!Event):void} handler Listener function to remove * @return {void} + * @override */ _removeEventListenerFromNode(node, eventName, handler) { node.removeEventListener(eventName, handler); diff --git a/lib/utils/case-map.js b/lib/utils/case-map.js index feaf52dda9..1963b025b5 100644 --- a/lib/utils/case-map.js +++ b/lib/utils/case-map.js @@ -14,11 +14,8 @@ const DASH_TO_CAMEL = /-[a-z]/g; const CAMEL_TO_DASH = /([A-Z])/g; /** - * Module with utilities for converting between "dash-case" and "camelCase" - * identifiers. - * - * @summary Module that provides utilities for converting between "dash-case" - * and "camelCase". + * @fileoverview Module with utilities for converting between "dash-case" and + * "camelCase" identifiers. */ /** diff --git a/lib/utils/gestures.js b/lib/utils/gestures.js index b32f596c02..9b0548bf4d 100644 --- a/lib/utils/gestures.js +++ b/lib/utils/gestures.js @@ -7,6 +7,20 @@ The complete set of contributors may be found at http://polymer.github.io/CONTRI Code distributed by Google as part of the polymer project is also subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt */ + +/** + * @fileoverview + * + * Module for adding listeners to a node for the following normalized + * cross-platform "gesture" events: + * - `down` - mouse or touch went down + * - `up` - mouse or touch went up + * - `tap` - mouse click or finger tap + * - `track` - mouse drag or touch move + * + * @summary Module for adding cross-platform gesture event listeners. + */ + import './boot.js'; import { timeOut, microTask } from './async.js'; @@ -78,7 +92,29 @@ function PASSIVE_TOUCH(eventName) { // 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 +/** @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} */ @@ -95,6 +131,10 @@ GestureRecognizer.prototype.touchmove; 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} */ @@ -338,20 +378,6 @@ function untrackDocument(stateObj) { // Use passive event listeners, if supported, to not affect scrolling performance document.addEventListener('touchend', ignoreMouse, SUPPORTS_PASSIVE ? {passive: true} : false); -/** - * Module for adding listeners to a node for the following normalized - * cross-platform "gesture" events: - * - `down` - mouse or touch went down - * - `up` - mouse or touch went up - * - `tap` - mouse click or finger tap - * - `track` - mouse drag or touch move - * - * @summary Module for adding cross-platform gesture event listeners. - */ -`TODO(modulizer): A namespace named Polymer.Gestures was -declared here. The surrounding comments should be reviewed, -and this string can then be deleted`; - export const gestures = {}; export const recognizers = []; @@ -391,7 +417,7 @@ export function deepTargetFind(x, y) { * a cheaper check than ev.composedPath()[0]; * * @private - * @param {Event} ev Event. + * @param {Event|Touch} ev Event. * @return {EventTarget} Returns the event target. */ function _findOriginalTarget(ev) { @@ -485,19 +511,19 @@ function _handleTouchAction(ev) { } POINTERSTATE.touch.scrollDecided = true; let ta = firstTouchAction(ev); - let prevent = false; + let shouldPrevent = false; let dx = Math.abs(POINTERSTATE.touch.x - t.clientX); let dy = Math.abs(POINTERSTATE.touch.y - t.clientY); if (!ev.cancelable) { // scrolling is happening } else if (ta === 'none') { - prevent = true; + shouldPrevent = true; } else if (ta === 'pan-x') { - prevent = dy > dx; + shouldPrevent = dy > dx; } else if (ta === 'pan-y') { - prevent = dx > dy; + shouldPrevent = dx > dy; } - if (prevent) { + if (shouldPrevent) { ev.preventDefault(); } else { prevent('track'); @@ -512,7 +538,6 @@ function _handleTouchAction(ev) { * @param {string} evType Gesture type: `down`, `up`, `track`, or `tap` * @param {!function(!Event):void} handler Event listener function to call * @return {boolean} Returns true if a gesture event listener was added. - * @this {Gestures} */ export function addListener(node, evType, handler) { if (gestures[evType]) { @@ -530,7 +555,6 @@ export function addListener(node, evType, handler) { * @param {!function(!Event):void} handler Event listener function previously passed to * `addListener`. * @return {boolean} Returns true if a gesture event listener was removed. - * @this {Gestures} */ export function removeListener(node, evType, handler) { if (gestures[evType]) { @@ -544,11 +568,10 @@ export function removeListener(node, evType, handler) { * automate the event listeners for the native events * * @private - * @param {!HTMLElement} node Node on which to add the event. + * @param {!Node} node Node on which to add the event. * @param {string} evType Event type to add. * @param {function(!Event)} handler Event handler function. * @return {void} - * @this {Gestures} */ function _add(node, evType, handler) { let recognizer = gestures[evType]; @@ -584,11 +607,10 @@ function _add(node, evType, handler) { * automate event listener removal for native events * * @private - * @param {!HTMLElement} node Node on which to remove the event. + * @param {!Node} node Node on which to remove the event. * @param {string} evType Event type to remove. - * @param {function(Event?)} handler Event handler function. + * @param {function(!Event): void} handler Event handler function. * @return {void} - * @this {Gestures} */ function _remove(node, evType, handler) { let recognizer = gestures[evType]; @@ -617,7 +639,6 @@ function _remove(node, evType, handler) { * * @param {!GestureRecognizer} recog Gesture recognizer descriptor * @return {void} - * @this {Gestures} */ export function register(recog) { recognizers.push(recog); @@ -630,7 +651,6 @@ export function register(recog) { * @private * @param {string} evName Event name. * @return {Object} Returns the gesture for the given event name. - * @this {Gestures} */ function _findRecognizerByEvent(evName) { for (let i = 0, r; i < recognizers.length; i++) { @@ -651,7 +671,7 @@ function _findRecognizerByEvent(evName) { * This value is checked on first move, thus it should be called prior to * adding event listeners. * - * @param {!Element} node Node to set touch action setting on + * @param {!Node} node Node to set touch action setting on * @param {string} value Touch action value * @return {void} */ @@ -695,7 +715,6 @@ function _fire(target, type, detail) { * * @param {string} evName Event name. * @return {void} - * @this {Gestures} */ export function prevent(evName) { let recognizer = _findRecognizerByEvent(evName); @@ -756,18 +775,18 @@ register({ let self = this; let movefn = function movefn(e) { if (!hasLeftMouseButton(e)) { - self._fire('up', t, e); + downupFire('up', t, e); untrackDocument(self.info); } }; let upfn = function upfn(e) { if (hasLeftMouseButton(e)) { - self._fire('up', t, e); + downupFire('up', t, e); } untrackDocument(self.info); }; trackDocument(this.info, movefn, upfn); - this._fire('down', t, e); + downupFire('down', t, e); }, /** * @this {GestureRecognizer} @@ -775,7 +794,7 @@ register({ * @return {void} */ touchstart: function(e) { - this._fire('down', _findOriginalTarget(e), e.changedTouches[0], e); + downupFire('down', _findOriginalTarget(e), e.changedTouches[0], e); }, /** * @this {GestureRecognizer} @@ -783,28 +802,32 @@ register({ * @return {void} */ touchend: function(e) { - this._fire('up', _findOriginalTarget(e), e.changedTouches[0], e); - }, - /** - * @param {string} type - * @param {!EventTarget} target - * @param {Event} event - * @param {Function} preventer - * @return {void} - */ - _fire: function(type, target, event, preventer) { - _fire(target, type, { - x: event.clientX, - y: event.clientY, - sourceEvent: event, - preventer: preventer, - prevent: function(e) { - return prevent(e); - } - }); + downupFire('up', _findOriginalTarget(e), e.changedTouches[0], e); } }); +/** + * @param {string} type + * @param {EventTarget} target + * @param {Event|Touch} event + * @param {Event=} preventer + * @return {void} + */ +function downupFire(type, target, event, preventer) { + if (!target) { + return; + } + _fire(target, type, { + x: event.clientX, + y: event.clientY, + sourceEvent: event, + preventer: preventer, + prevent: function(e) { + return prevent(e); + } + }); +} + register({ name: 'track', touchAction: 'none', @@ -821,7 +844,7 @@ register({ state: 'start', started: false, moves: [], - /** @this {GestureRecognizer} */ + /** @this {GestureInfo} */ addMove: function(move) { if (this.moves.length > TRACK_LENGTH) { this.moves.shift(); @@ -847,23 +870,6 @@ register({ untrackDocument(this.info); }, - /** - * @this {GestureRecognizer} - * @param {number} x - * @param {number} y - * @return {boolean} - */ - hasMovedEnough: function(x, y) { - if (this.info.prevent) { - return false; - } - if (this.info.started) { - return true; - } - let dx = Math.abs(this.info.x - x); - let dy = Math.abs(this.info.y - y); - return (dx >= TRACK_DISTANCE || dy >= TRACK_DISTANCE); - }, /** * @this {GestureRecognizer} * @param {MouseEvent} e @@ -877,7 +883,7 @@ register({ let self = this; let movefn = function movefn(e) { let x = e.clientX, y = e.clientY; - if (self.hasMovedEnough(x, y)) { + if (trackHasMovedEnough(self.info, x, y)) { // first move is 'start', subsequent moves are 'move', mouseup is 'end' self.info.state = self.info.started ? (e.type === 'mouseup' ? 'end' : 'track') : 'start'; if (self.info.state === 'start') { @@ -886,11 +892,13 @@ register({ } self.info.addMove({x: x, y: y}); if (!hasLeftMouseButton(e)) { - // always _fire "end" + // always fire "end" self.info.state = 'end'; untrackDocument(self.info); } - self._fire(t, e); + if (t) { + trackFire(self.info, t, e); + } self.info.started = true; } }; @@ -926,13 +934,13 @@ register({ let t = _findOriginalTarget(e); let ct = e.changedTouches[0]; let x = ct.clientX, y = ct.clientY; - if (this.hasMovedEnough(x, y)) { + if (trackHasMovedEnough(this.info, x, y)) { if (this.info.state === 'start') { // if and only if tracking, always prevent tap prevent('tap'); } this.info.addMove({x: x, y: y}); - this._fire(t, ct); + trackFire(this.info, t, ct); this.info.state = 'track'; this.info.started = true; } @@ -950,42 +958,62 @@ register({ // reset started state on up this.info.state = 'end'; this.info.addMove({x: ct.clientX, y: ct.clientY}); - this._fire(t, ct, e); + trackFire(this.info, t, ct); } - }, + } +}); - /** - * @this {GestureRecognizer} - * @param {!EventTarget} target - * @param {Touch} touch - * @return {void} - */ - _fire: function(target, touch) { - let secondlast = this.info.moves[this.info.moves.length - 2]; - let lastmove = this.info.moves[this.info.moves.length - 1]; - let dx = lastmove.x - this.info.x; - let dy = lastmove.y - this.info.y; - let ddx, ddy = 0; - if (secondlast) { - ddx = lastmove.x - secondlast.x; - ddy = lastmove.y - secondlast.y; - } - _fire(target, 'track', { - state: this.info.state, - x: touch.clientX, - y: touch.clientY, - dx: dx, - dy: dy, - ddx: ddx, - ddy: ddy, - sourceEvent: touch, - hover: function() { - return deepTargetFind(touch.clientX, touch.clientY); - } - }); +/** + * @param {!GestureInfo} info + * @param {number} x + * @param {number} y + * @return {boolean} + */ +function trackHasMovedEnough(info, x, y) { + if (info.prevent) { + return false; } + if (info.started) { + return true; + } + let dx = Math.abs(info.x - x); + let dy = Math.abs(info.y - y); + return (dx >= TRACK_DISTANCE || dy >= TRACK_DISTANCE); +} -}); +/** + * @param {!GestureInfo} info + * @param {?EventTarget} target + * @param {Touch} touch + * @return {void} + */ +function trackFire(info, target, touch) { + if (!target) { + return; + } + let secondlast = info.moves[info.moves.length - 2]; + let lastmove = info.moves[info.moves.length - 1]; + let dx = lastmove.x - info.x; + let dy = lastmove.y - info.y; + let ddx, ddy = 0; + if (secondlast) { + ddx = lastmove.x - secondlast.x; + ddy = lastmove.y - secondlast.y; + } + _fire(target, 'track', { + state: info.state, + x: touch.clientX, + y: touch.clientY, + dx: dx, + dy: dy, + ddx: ddx, + ddy: ddy, + sourceEvent: touch, + hover: function() { + return deepTargetFind(touch.clientX, touch.clientY); + } + }); +} register({ name: 'tap', @@ -1009,15 +1037,6 @@ register({ this.info.y = NaN; this.info.prevent = false; }, - /** - * @this {GestureRecognizer} - * @param {MouseEvent} e - * @return {void} - */ - save: function(e) { - this.info.x = e.clientX; - this.info.y = e.clientY; - }, /** * @this {GestureRecognizer} * @param {MouseEvent} e @@ -1025,7 +1044,8 @@ register({ */ mousedown: function(e) { if (hasLeftMouseButton(e)) { - this.save(e); + this.info.x = e.clientX; + this.info.y = e.clientY; } }, /** @@ -1035,7 +1055,7 @@ register({ */ click: function(e) { if (hasLeftMouseButton(e)) { - this.forward(e); + trackForward(this.info, e); } }, /** @@ -1044,7 +1064,9 @@ register({ * @return {void} */ touchstart: function(e) { - this.save(e.changedTouches[0], e); + const touch = e.changedTouches[0]; + this.info.x = touch.clientX; + this.info.y = touch.clientY; }, /** * @this {GestureRecognizer} @@ -1052,37 +1074,38 @@ register({ * @return {void} */ touchend: function(e) { - this.forward(e.changedTouches[0], e); - }, - /** - * @this {GestureRecognizer} - * @param {Event | Touch} e - * @param {Event=} preventer - * @return {void} - */ - forward: function(e, preventer) { - let dx = Math.abs(e.clientX - this.info.x); - let dy = Math.abs(e.clientY - this.info.y); - // find original target from `preventer` for TouchEvents, or `e` for MouseEvents - let t = _findOriginalTarget((preventer || e)); - if (!t || (canBeDisabled[/** @type {!HTMLElement} */(t).localName] && t.hasAttribute('disabled'))) { - return; - } - // dx,dy can be NaN if `click` has been simulated and there was no `down` for `start` - if (isNaN(dx) || isNaN(dy) || (dx <= TAP_DISTANCE && dy <= TAP_DISTANCE) || isSyntheticClick(e)) { - // prevent taps from being generated if an event has canceled them - if (!this.info.prevent) { - _fire(t, 'tap', { - x: e.clientX, - y: e.clientY, - sourceEvent: e, - preventer: preventer - }); - } - } + trackForward(this.info, e.changedTouches[0], e); } }); +/** + * @param {!GestureInfo} info + * @param {Event | Touch} e + * @param {Event=} preventer + * @return {void} + */ +function trackForward(info, e, preventer) { + let dx = Math.abs(e.clientX - info.x); + let dy = Math.abs(e.clientY - info.y); + // find original target from `preventer` for TouchEvents, or `e` for MouseEvents + let t = _findOriginalTarget((preventer || e)); + if (!t || (canBeDisabled[/** @type {!HTMLElement} */(t).localName] && t.hasAttribute('disabled'))) { + return; + } + // dx,dy can be NaN if `click` has been simulated and there was no `down` for `start` + if (isNaN(dx) || isNaN(dy) || (dx <= TAP_DISTANCE && dy <= TAP_DISTANCE) || isSyntheticClick(e)) { + // prevent taps from being generated if an event has canceled them + if (!info.prevent) { + _fire(t, 'tap', { + x: e.clientX, + y: e.clientY, + sourceEvent: e, + preventer: preventer + }); + } + } +} + /* eslint-enable valid-jsdoc */ /** @deprecated */ diff --git a/lib/utils/html-tag.js b/lib/utils/html-tag.js index d5640629b9..3b0e3def9e 100644 --- a/lib/utils/html-tag.js +++ b/lib/utils/html-tag.js @@ -21,6 +21,7 @@ class LiteralString { } /** * @return {string} LiteralString string value + * @override */ toString() { return this.value; diff --git a/lib/utils/mixin.js b/lib/utils/mixin.js index b62283b424..b79c7f9a20 100644 --- a/lib/utils/mixin.js +++ b/lib/utils/mixin.js @@ -62,6 +62,6 @@ export const dedupingMixin = function(mixin) { return extended; } - return /** @type {T} */ (dedupingMixin); + return dedupingMixin; }; /* eslint-enable valid-jsdoc */