diff --git a/.eslintrc.json b/.eslintrc.json
index c25f61e55a..de64bd22f8 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -19,9 +19,11 @@
"Boolean": "boolean",
"Number": "number",
"String": "string",
- "object": "Object"
+ "object": "Object",
+ "array": "Array"
}
- }]
+ }],
+ "no-useless-escape": "off"
},
"env": {
"browser": true,
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000000..4046195b53
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,2 @@
+# Code owners for Polymer
+* @sorvell @kevinpschaaf @TimvdLippe @azakus
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index dcdd713500..8d68054f92 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -1,6 +1,6 @@
@@ -9,8 +9,11 @@ If you are asking a question rather than filing a bug, try one of these instead:
#### Live Demo
-
-http://jsbin.com/luhaxab/1/edit
+
+https://jsbin.com/luhaxab/1/edit
+
+https://glitch.com/edit/#!/polymer-repro?path=my-element.html:2:0
+
#### Steps to Reproduce
+
+
+
+
+
+
diff --git a/lib/mixins/properties-mixin.html b/lib/mixins/properties-mixin.html
new file mode 100644
index 0000000000..782311bb8e
--- /dev/null
+++ b/lib/mixins/properties-mixin.html
@@ -0,0 +1,230 @@
+
+
+
+
+
+
+
diff --git a/lib/mixins/property-accessors.html b/lib/mixins/property-accessors.html
index aad5ee7373..f26f467b12 100644
--- a/lib/mixins/property-accessors.html
+++ b/lib/mixins/property-accessors.html
@@ -11,7 +11,7 @@
-
+
\ No newline at end of file
+
diff --git a/lib/utils/async.html b/lib/utils/async.html
index 1283856349..4ddd961c6f 100644
--- a/lib/utils/async.html
+++ b/lib/utils/async.html
@@ -14,9 +14,6 @@
'use strict';
- /** @typedef {{run: function(function(), number=):number, cancel: function(number)}} */
- let AsyncInterface; // eslint-disable-line no-unused-vars
-
// Microtask implemented using Mutation Observer
let microtaskCurrHandle = 0;
let microtaskLastHandle = 0;
@@ -67,30 +64,38 @@
* delay.
*
* @memberof Polymer.Async.timeOut
- * @param {number} delay Time to wait before calling callbacks in ms
- * @return {AsyncInterface} An async timeout interface
+ * @param {number=} delay Time to wait before calling callbacks in ms
+ * @return {!AsyncInterface} An async timeout interface
*/
after(delay) {
- return {
- run(fn) { return setTimeout(fn, delay); },
- cancel: window.clearTimeout.bind(window)
+ return {
+ run(fn) { return window.setTimeout(fn, delay); },
+ cancel(handle) {
+ window.clearTimeout(handle);
+ }
};
},
/**
* Enqueues a function called in the next task.
*
* @memberof Polymer.Async.timeOut
- * @param {Function} fn Callback to run
+ * @param {!Function} fn Callback to run
+ * @param {number=} delay Delay in milliseconds
* @return {number} Handle used for canceling task
*/
- run: window.setTimeout.bind(window),
+ run(fn, delay) {
+ return window.setTimeout(fn, delay);
+ },
/**
* Cancels a previously enqueued `timeOut` callback.
*
* @memberof Polymer.Async.timeOut
* @param {number} handle Handle returned from `run` of callback to cancel
+ * @return {void}
*/
- cancel: window.clearTimeout.bind(window)
+ cancel(handle) {
+ window.clearTimeout(handle);
+ }
},
/**
@@ -105,17 +110,22 @@
* Enqueues a function called at `requestAnimationFrame` timing.
*
* @memberof Polymer.Async.animationFrame
- * @param {Function} fn Callback to run
+ * @param {function(number):void} fn Callback to run
* @return {number} Handle used for canceling task
*/
- run: window.requestAnimationFrame.bind(window),
+ run(fn) {
+ return window.requestAnimationFrame(fn);
+ },
/**
* Cancels a previously enqueued `animationFrame` callback.
*
- * @memberof Polymer.Async.timeOut
+ * @memberof Polymer.Async.animationFrame
* @param {number} handle Handle returned from `run` of callback to cancel
+ * @return {void}
*/
- cancel: window.cancelAnimationFrame.bind(window)
+ cancel(handle) {
+ window.cancelAnimationFrame(handle);
+ }
},
/**
@@ -131,7 +141,7 @@
* Enqueues a function called at `requestIdleCallback` timing.
*
* @memberof Polymer.Async.idlePeriod
- * @param {function(IdleDeadline)} fn Callback to run
+ * @param {function(!IdleDeadline):void} fn Callback to run
* @return {number} Handle used for canceling task
*/
run(fn) {
@@ -144,6 +154,7 @@
*
* @memberof Polymer.Async.idlePeriod
* @param {number} handle Handle returned from `run` of callback to cancel
+ * @return {void}
*/
cancel(handle) {
window.cancelIdleCallback ?
@@ -172,7 +183,7 @@
* Enqueues a function called at microtask timing.
*
* @memberof Polymer.Async.microTask
- * @param {Function} callback Callback to run
+ * @param {!Function=} callback Callback to run
* @return {number} Handle used for canceling task
*/
run(callback) {
@@ -186,6 +197,7 @@
*
* @memberof Polymer.Async.microTask
* @param {number} handle Handle returned from `run` of callback to cancel
+ * @return {void}
*/
cancel(handle) {
const idx = handle - microtaskLastHandle;
diff --git a/lib/utils/boot.html b/lib/utils/boot.html
index d3e9a1094e..96ee134d27 100644
--- a/lib/utils/boot.html
+++ b/lib/utils/boot.html
@@ -49,7 +49,7 @@
};
/* eslint-enable */
- window.Polymer.version = '2.2.0';
+ window.Polymer.version = '2.4.0';
/* eslint-disable no-unused-vars */
/*
diff --git a/lib/utils/debounce.html b/lib/utils/debounce.html
index 7fff476678..8344af328f 100644
--- a/lib/utils/debounce.html
+++ b/lib/utils/debounce.html
@@ -15,9 +15,6 @@
(function() {
'use strict';
- /** @typedef {{run: function(function(), number=):number, cancel: function(number)}} */
- let AsyncModule; // eslint-disable-line no-unused-vars
-
/**
* @summary Collapse multiple callbacks into one invocation after a timer.
* @memberof Polymer
@@ -33,8 +30,9 @@
* a callback and optional arguments to be passed to the run function
* from the async module.
*
- * @param {!AsyncModule} asyncModule Object with Async interface.
+ * @param {!AsyncInterface} asyncModule Object with Async interface.
* @param {function()} callback Callback to run.
+ * @return {void}
*/
setConfig(asyncModule, callback) {
this._asyncModule = asyncModule;
@@ -46,6 +44,8 @@
}
/**
* Cancels an active debouncer and returns a reference to itself.
+ *
+ * @return {void}
*/
cancel() {
if (this.isActive()) {
@@ -55,6 +55,8 @@
}
/**
* Flushes an active debouncer and returns a reference to itself.
+ *
+ * @return {void}
*/
flush() {
if (this.isActive()) {
@@ -70,36 +72,36 @@
isActive() {
return this._timer != null;
}
- /**
- * Creates a debouncer if no debouncer is passed as a parameter
- * or it cancels an active debouncer otherwise. The following
- * example shows how a debouncer can be called multiple times within a
- * microtask and "debounced" such that the provided callback function is
- * called once. Add this method to a custom element:
- *
- * _debounceWork() {
- * this._debounceJob = Polymer.Debouncer.debounce(this._debounceJob,
- * Polymer.Async.microTask, () => {
- * this._doWork();
- * });
- * }
- *
- * If the `_debounceWork` method is called multiple times within the same
- * microtask, the `_doWork` function will be called only once at the next
- * microtask checkpoint.
- *
- * Note: In testing it is often convenient to avoid asynchrony. To accomplish
- * this with a debouncer, you can use `Polymer.enqueueDebouncer` and
- * `Polymer.flush`. For example, extend the above example by adding
- * `Polymer.enqueueDebouncer(this._debounceJob)` at the end of the
- * `_debounceWork` method. Then in a test, call `Polymer.flush` to ensure
- * the debouncer has completed.
- *
- * @param {Debouncer?} debouncer Debouncer object.
- * @param {!AsyncModule} asyncModule Object with Async interface
- * @param {function()} callback Callback to run.
- * @return {!Debouncer} Returns a debouncer object.
- */
+ /**
+ * Creates a debouncer if no debouncer is passed as a parameter
+ * or it cancels an active debouncer otherwise. The following
+ * example shows how a debouncer can be called multiple times within a
+ * microtask and "debounced" such that the provided callback function is
+ * called once. Add this method to a custom element:
+ *
+ * _debounceWork() {
+ * this._debounceJob = Polymer.Debouncer.debounce(this._debounceJob,
+ * Polymer.Async.microTask, () => {
+ * this._doWork();
+ * });
+ * }
+ *
+ * If the `_debounceWork` method is called multiple times within the same
+ * microtask, the `_doWork` function will be called only once at the next
+ * microtask checkpoint.
+ *
+ * Note: In testing it is often convenient to avoid asynchrony. To accomplish
+ * this with a debouncer, you can use `Polymer.enqueueDebouncer` and
+ * `Polymer.flush`. For example, extend the above example by adding
+ * `Polymer.enqueueDebouncer(this._debounceJob)` at the end of the
+ * `_debounceWork` method. Then in a test, call `Polymer.flush` to ensure
+ * the debouncer has completed.
+ *
+ * @param {Debouncer?} debouncer Debouncer object.
+ * @param {!AsyncInterface} asyncModule Object with Async interface
+ * @param {function()} callback Callback to run.
+ * @return {!Debouncer} Returns a debouncer object.
+ */
static debounce(debouncer, asyncModule, callback) {
if (debouncer instanceof Debouncer) {
debouncer.cancel();
diff --git a/lib/utils/flattened-nodes-observer.html b/lib/utils/flattened-nodes-observer.html
index 5ea0085a4e..2273b1604f 100644
--- a/lib/utils/flattened-nodes-observer.html
+++ b/lib/utils/flattened-nodes-observer.html
@@ -16,7 +16,7 @@
/**
* Returns true if `node` is a slot element
- * @param {HTMLElement} node Node to test.
+ * @param {Node} node Node to test.
* @return {boolean} Returns true if the given `node` is a slot
* @private
*/
@@ -44,6 +44,24 @@
* `MutationObserver` and the `` element's `slotchange` event which
* are asynchronous.
*
+ * An example:
+ * ```js
+ * class TestSelfObserve extends Polymer.Element {
+ * static get is() { return 'test-self-observe';}
+ * connectedCallback() {
+ * super.connectedCallback();
+ * this._observer = new Polymer.FlattenedNodesObserver(this, (info) => {
+ * this.info = info;
+ * });
+ * }
+ * disconnectedCallback() {
+ * super.disconnectedCallback();
+ * this._observer.disconnect();
+ * }
+ * }
+ * customElements.define(TestSelfObserve.is, TestSelfObserve);
+ * ```
+ *
* @memberof Polymer
* @summary Class that listens for changes (additions or removals) to
* "flattened nodes" on a given `node`.
@@ -79,22 +97,35 @@
}
/**
- * @param {Node} target Node on which to listen for changes.
- * @param {Function} callback Function called when there are additions
+ * @param {Element} target Node on which to listen for changes.
+ * @param {?function(!Element, { target: !Element, addedNodes: !Array, removedNodes: !Array }):void} callback Function called when there are additions
* or removals from the target's list of flattened nodes.
*/
constructor(target, callback) {
- /** @type {MutationObserver} */
+ /**
+ * @type {MutationObserver}
+ * @private
+ */
this._shadyChildrenObserver = null;
- /** @type {MutationObserver} */
+ /**
+ * @type {MutationObserver}
+ * @private
+ */
this._nativeChildrenObserver = null;
this._connected = false;
+ /**
+ * @type {Element}
+ * @private
+ */
this._target = target;
this.callback = callback;
this._effectiveNodes = [];
this._observer = null;
this._scheduled = false;
- /** @type {function()} */
+ /**
+ * @type {function()}
+ * @private
+ */
this._boundSchedule = () => {
this._schedule();
};
@@ -106,11 +137,13 @@
* Activates an observer. This method is automatically called when
* a `FlattenedNodesObserver` is created. It should only be called to
* re-activate an observer that has been deactivated via the `disconnect` method.
+ *
+ * @return {void}
*/
connect() {
if (isSlot(this._target)) {
this._listenSlots([this._target]);
- } else {
+ } else if (this._target.children) {
this._listenSlots(this._target.children);
if (window.ShadyDOM) {
this._shadyChildrenObserver =
@@ -133,11 +166,13 @@
* the observer callback will not be called when changes to flattened nodes
* occur. The `connect` method may be subsequently called to reactivate
* the observer.
+ *
+ * @return {void}
*/
disconnect() {
if (isSlot(this._target)) {
this._unlistenSlots([this._target]);
- } else {
+ } else if (this._target.children) {
this._unlistenSlots(this._target.children);
if (window.ShadyDOM && this._shadyChildrenObserver) {
ShadyDOM.unobserveChildren(this._shadyChildrenObserver);
@@ -150,6 +185,10 @@
this._connected = false;
}
+ /**
+ * @return {void}
+ * @private
+ */
_schedule() {
if (!this._scheduled) {
this._scheduled = true;
@@ -157,11 +196,21 @@
}
}
+ /**
+ * @param {Array} mutations Mutations signaled by the mutation observer
+ * @return {void}
+ * @private
+ */
_processMutations(mutations) {
this._processSlotMutations(mutations);
this.flush();
}
+ /**
+ * @param {Array} mutations Mutations signaled by the mutation observer
+ * @return {void}
+ * @private
+ */
_processSlotMutations(mutations) {
if (mutations) {
for (let i=0; i < mutations.length; i++) {
@@ -227,6 +276,11 @@
return didFlush;
}
+ /**
+ * @param {!Array|!NodeList} nodeList Nodes that could change
+ * @return {void}
+ * @private
+ */
_listenSlots(nodeList) {
for (let i=0; i < nodeList.length; i++) {
let n = nodeList[i];
@@ -236,6 +290,11 @@
}
}
+ /**
+ * @param {!Array|!NodeList} nodeList Nodes that could change
+ * @return {void}
+ * @private
+ */
_unlistenSlots(nodeList) {
for (let i=0; i < nodeList.length; i++) {
let n = nodeList[i];
diff --git a/lib/utils/flush.html b/lib/utils/flush.html
index 331442292d..3feaad6166 100644
--- a/lib/utils/flush.html
+++ b/lib/utils/flush.html
@@ -18,7 +18,8 @@
* Adds a `Polymer.Debouncer` to a list of globally flushable tasks.
*
* @memberof Polymer
- * @param {Polymer.Debouncer} debouncer Debouncer to enqueue
+ * @param {!Polymer.Debouncer} debouncer Debouncer to enqueue
+ * @return {void}
*/
Polymer.enqueueDebouncer = function(debouncer) {
debouncerQueue.push(debouncer);
@@ -44,6 +45,7 @@
* - ShadyDOM distribution
*
* @memberof Polymer
+ * @return {void}
*/
Polymer.flush = function() {
let shadyDOM, debouncers;
diff --git a/lib/utils/gestures.html b/lib/utils/gestures.html
index b741455a9d..738940f406 100644
--- a/lib/utils/gestures.html
+++ b/lib/utils/gestures.html
@@ -62,9 +62,13 @@
/**
* Generate settings for event listeners, dependant on `Polymer.passiveTouchGestures`
*
+ * @param {string} eventName Event name to determine if `{passive}` option is needed
* @return {{passive: boolean} | undefined} Options to use for addEventListener and removeEventListener
*/
- function PASSIVE_TOUCH() {
+ function PASSIVE_TOUCH(eventName) {
+ if (isMouseEvent(eventName) || eventName === 'touchend') {
+ return;
+ }
if (HAS_NATIVE_TA && SUPPORTS_PASSIVE && Polymer.passiveTouchGestures) {
return {passive: true};
} else {
@@ -76,21 +80,21 @@
let IS_TOUCH_ONLY = navigator.userAgent.match(/iP(?:[oa]d|hone)|Android/);
let GestureRecognizer = function(){}; // eslint-disable-line no-unused-vars
- /** @type {function()} */
+ /** @type {function(): void} */
GestureRecognizer.prototype.reset;
- /** @type {function(MouseEvent) | undefined} */
+ /** @type {function(MouseEvent): void | undefined} */
GestureRecognizer.prototype.mousedown;
- /** @type {(function(MouseEvent) | undefined)} */
+ /** @type {(function(MouseEvent): void | undefined)} */
GestureRecognizer.prototype.mousemove;
- /** @type {(function(MouseEvent) | undefined)} */
+ /** @type {(function(MouseEvent): void | undefined)} */
GestureRecognizer.prototype.mouseup;
- /** @type {(function(TouchEvent) | undefined)} */
+ /** @type {(function(TouchEvent): void | undefined)} */
GestureRecognizer.prototype.touchstart;
- /** @type {(function(TouchEvent) | undefined)} */
+ /** @type {(function(TouchEvent): void | undefined)} */
GestureRecognizer.prototype.touchmove;
- /** @type {(function(TouchEvent) | undefined)} */
+ /** @type {(function(TouchEvent): void | undefined)} */
GestureRecognizer.prototype.touchend;
- /** @type {(function(MouseEvent) | undefined)} */
+ /** @type {(function(MouseEvent): void | undefined)} */
GestureRecognizer.prototype.click;
// touch will make synthetic mouse events
@@ -126,6 +130,7 @@
/**
* @param {boolean=} setup True to add, false to remove.
+ * @return {void}
*/
function setupTeardownMouseCanceller(setup) {
let events = IS_TOUCH_ONLY ? ['click'] : MOUSE_EVENTS;
@@ -311,8 +316,9 @@
_findOriginalTarget: function(ev) {
// shadowdom
if (ev.composedPath) {
- const target = /** @type {EventTarget} */(ev.composedPath()[0]);
- return target;
+ const targets = /** @type {!Array} */(ev.composedPath());
+ // It shouldn't be, but sometimes targets is empty (window on Safari).
+ return targets.length > 0 ? targets[0] : ev.target;
}
// shadydom
return ev.target;
@@ -321,6 +327,7 @@
/**
* @private
* @param {Event} ev Event.
+ * @return {void}
*/
_handleNative: function(ev) {
let handled;
@@ -382,6 +389,7 @@
/**
* @private
* @param {TouchEvent} ev Event.
+ * @return {void}
*/
_handleTouchAction: function(ev) {
let t = ev.changedTouches[0];
@@ -420,9 +428,9 @@
* Adds an event listener to a node for the given gesture type.
*
* @memberof Polymer.Gestures
- * @param {Node} node Node to add listener on
+ * @param {!Node} node Node to add listener on
* @param {string} evType Gesture type: `down`, `up`, `track`, or `tap`
- * @param {Function} handler Event listener function to call
+ * @param {!function(!Event):void} handler Event listener function to call
* @return {boolean} Returns true if a gesture event listener was added.
* @this {Gestures}
*/
@@ -438,9 +446,9 @@
* Removes an event listener from a node for the given gesture type.
*
* @memberof Polymer.Gestures
- * @param {Node} node Node to remove listener from
+ * @param {!Node} node Node to remove listener from
* @param {string} evType Gesture type: `down`, `up`, `track`, or `tap`
- * @param {Function} handler Event listener function previously passed to
+ * @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}
@@ -457,9 +465,10 @@
* automate the event listeners for the native events
*
* @private
- * @param {HTMLElement} node Node on which to add the event.
+ * @param {!HTMLElement} node Node on which to add the event.
* @param {string} evType Event type to add.
- * @param {function(Event?)} handler Event handler function.
+ * @param {function(!Event)} handler Event handler function.
+ * @return {void}
* @this {Gestures}
*/
_add: function(node, evType, handler) {
@@ -481,8 +490,7 @@
gobj[dep] = gd = {_count: 0};
}
if (gd._count === 0) {
- let options = !isMouseEvent(dep) && PASSIVE_TOUCH();
- node.addEventListener(dep, this._handleNative, options);
+ node.addEventListener(dep, this._handleNative, PASSIVE_TOUCH(dep));
}
gd[name] = (gd[name] || 0) + 1;
gd._count = (gd._count || 0) + 1;
@@ -497,9 +505,10 @@
* automate event listener removal for native events
*
* @private
- * @param {HTMLElement} node Node on which to remove the event.
+ * @param {!HTMLElement} node Node on which to remove the event.
* @param {string} evType Event type to remove.
* @param {function(Event?)} handler Event handler function.
+ * @return {void}
* @this {Gestures}
*/
_remove: function(node, evType, handler) {
@@ -515,8 +524,7 @@
gd[name] = (gd[name] || 1) - 1;
gd._count = (gd._count || 1) - 1;
if (gd._count === 0) {
- let options = !isMouseEvent(dep) && PASSIVE_TOUCH();
- node.removeEventListener(dep, this._handleNative, options);
+ node.removeEventListener(dep, this._handleNative, PASSIVE_TOUCH(dep));
}
}
}
@@ -529,7 +537,8 @@
* gesture event types.
*
* @memberof Polymer.Gestures
- * @param {GestureRecognizer} recog Gesture recognizer descriptor
+ * @param {!GestureRecognizer} recog Gesture recognizer descriptor
+ * @return {void}
* @this {Gestures}
*/
register: function(recog) {
@@ -565,12 +574,19 @@
* adding event listeners.
*
* @memberof Polymer.Gestures
- * @param {Element} node Node to set touch action setting on
+ * @param {!Element} node Node to set touch action setting on
* @param {string} value Touch action value
+ * @return {void}
*/
setTouchAction: function(node, value) {
if (HAS_NATIVE_TA) {
- node.style.touchAction = value;
+ // NOTE: add touchAction async so that events can be added in
+ // custom element constructors. Otherwise we run afoul of custom
+ // elements restriction against settings attributes (style) in the
+ // constructor.
+ Polymer.Async.microTask.run(() => {
+ node.style.touchAction = value;
+ });
}
node[TOUCH_ACTION] = value;
},
@@ -579,9 +595,10 @@
* Dispatches an event on the `target` element of `type` with the given
* `detail`.
* @private
- * @param {EventTarget} target The element on which to fire an event.
+ * @param {!EventTarget} target The element on which to fire an event.
* @param {string} type The type of event to fire.
- * @param {Object=} detail The detail object to populate on the event.
+ * @param {!Object=} detail The detail object to populate on the event.
+ * @return {void}
*/
_fire: function(target, type, detail) {
let ev = new Event(type, { bubbles: true, cancelable: true, composed: true });
@@ -601,6 +618,7 @@
*
* @memberof Polymer.Gestures
* @param {string} evName Event name.
+ * @return {void}
* @this {Gestures}
*/
prevent: function(evName) {
@@ -618,6 +636,7 @@
* Calling this method in production may cause duplicate taps or other Gestures.
*
* @memberof Polymer.Gestures
+ * @return {void}
*/
resetMouseCanceller: function() {
if (POINTERSTATE.mouse.mouseIgnoreJob) {
@@ -642,7 +661,10 @@
upfn: null
},
- /** @this {GestureRecognizer} */
+ /**
+ * @this {GestureRecognizer}
+ * @return {void}
+ */
reset: function() {
untrackDocument(this.info);
},
@@ -650,6 +672,7 @@
/**
* @this {GestureRecognizer}
* @param {MouseEvent} e
+ * @return {void}
*/
mousedown: function(e) {
if (!hasLeftMouseButton(e)) {
@@ -675,6 +698,7 @@
/**
* @this {GestureRecognizer}
* @param {TouchEvent} e
+ * @return {void}
*/
touchstart: function(e) {
this._fire('down', Gestures._findOriginalTarget(e), e.changedTouches[0], e);
@@ -682,15 +706,17 @@
/**
* @this {GestureRecognizer}
* @param {TouchEvent} e
+ * @return {void}
*/
touchend: function(e) {
this._fire('up', Gestures._findOriginalTarget(e), e.changedTouches[0], e);
},
/**
* @param {string} type
- * @param {EventTarget} target
+ * @param {!EventTarget} target
* @param {Event} event
* @param {Function} preventer
+ * @return {void}
*/
_fire: function(type, target, event, preventer) {
Gestures._fire(target, type, {
@@ -733,7 +759,10 @@
prevent: false
},
- /** @this {GestureRecognizer} */
+ /**
+ * @this {GestureRecognizer}
+ * @return {void}
+ */
reset: function() {
this.info.state = 'start';
this.info.started = false;
@@ -764,6 +793,7 @@
/**
* @this {GestureRecognizer}
* @param {MouseEvent} e
+ * @return {void}
*/
mousedown: function(e) {
if (!hasLeftMouseButton(e)) {
@@ -806,6 +836,7 @@
/**
* @this {GestureRecognizer}
* @param {TouchEvent} e
+ * @return {void}
*/
touchstart: function(e) {
let ct = e.changedTouches[0];
@@ -815,6 +846,7 @@
/**
* @this {GestureRecognizer}
* @param {TouchEvent} e
+ * @return {void}
*/
touchmove: function(e) {
let t = Gestures._findOriginalTarget(e);
@@ -834,6 +866,7 @@
/**
* @this {GestureRecognizer}
* @param {TouchEvent} e
+ * @return {void}
*/
touchend: function(e) {
let t = Gestures._findOriginalTarget(e);
@@ -849,8 +882,9 @@
/**
* @this {GestureRecognizer}
- * @param {EventTarget} target
+ * @param {!EventTarget} target
* @param {Touch} touch
+ * @return {void}
*/
_fire: function(target, touch) {
let secondlast = this.info.moves[this.info.moves.length - 2];
@@ -892,13 +926,20 @@
y: NaN,
prevent: false
},
- /** @this {GestureRecognizer} */
+ /**
+ * @this {GestureRecognizer}
+ * @return {void}
+ */
reset: function() {
this.info.x = NaN;
this.info.y = NaN;
this.info.prevent = false;
},
- /** @this {GestureRecognizer} */
+ /**
+ * @this {GestureRecognizer}
+ * @param {MouseEvent} e
+ * @return {void}
+ */
save: function(e) {
this.info.x = e.clientX;
this.info.y = e.clientY;
@@ -906,6 +947,7 @@
/**
* @this {GestureRecognizer}
* @param {MouseEvent} e
+ * @return {void}
*/
mousedown: function(e) {
if (hasLeftMouseButton(e)) {
@@ -915,6 +957,7 @@
/**
* @this {GestureRecognizer}
* @param {MouseEvent} e
+ * @return {void}
*/
click: function(e) {
if (hasLeftMouseButton(e)) {
@@ -924,6 +967,7 @@
/**
* @this {GestureRecognizer}
* @param {TouchEvent} e
+ * @return {void}
*/
touchstart: function(e) {
this.save(e.changedTouches[0], e);
@@ -931,6 +975,7 @@
/**
* @this {GestureRecognizer}
* @param {TouchEvent} e
+ * @return {void}
*/
touchend: function(e) {
this.forward(e.changedTouches[0], e);
@@ -939,12 +984,16 @@
* @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 = Gestures._findOriginalTarget(/** @type {Event} */(preventer || e));
+ if (!t) {
+ 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
diff --git a/lib/utils/html-tag.html b/lib/utils/html-tag.html
new file mode 100644
index 0000000000..e6189cde7c
--- /dev/null
+++ b/lib/utils/html-tag.html
@@ -0,0 +1,129 @@
+
+
+
diff --git a/lib/utils/import-href.html b/lib/utils/import-href.html
index 24b394159e..80d354bc77 100644
--- a/lib/utils/import-href.html
+++ b/lib/utils/import-href.html
@@ -36,13 +36,13 @@
*
* @memberof Polymer
* @param {string} href URL to document to load.
- * @param {Function=} onload Callback to notify when an import successfully
+ * @param {?function(!Event):void=} onload Callback to notify when an import successfully
* loaded.
- * @param {Function=} onerror Callback to notify when an import
+ * @param {?function(!ErrorEvent):void=} onerror Callback to notify when an import
* unsuccessfully loaded.
* @param {boolean=} optAsync True if the import should be loaded `async`.
* Defaults to `false`.
- * @return {HTMLLinkElement} The link element for the URL to be loaded.
+ * @return {!HTMLLinkElement} The link element for the URL to be loaded.
*/
Polymer.importHref = function(href, onload, onerror, optAsync) {
let link = /** @type {HTMLLinkElement} */
diff --git a/lib/utils/mixin.html b/lib/utils/mixin.html
index 525d1bc209..e97b3e2123 100644
--- a/lib/utils/mixin.html
+++ b/lib/utils/mixin.html
@@ -38,6 +38,7 @@
* @memberof Polymer
* @template T
* @param {T} mixin ES6 class expression mixin to wrap
+ * @return {T}
* @suppress {invalidCasts}
*/
Polymer.dedupingMixin = function(mixin) {
@@ -68,7 +69,7 @@
return extended;
}
- return dedupingMixin;
+ return /** @type {T} */ (dedupingMixin);
};
/* eslint-enable valid-jsdoc */
diff --git a/lib/utils/path.html b/lib/utils/path.html
index 67c045665a..924c9d0abb 100644
--- a/lib/utils/path.html
+++ b/lib/utils/path.html
@@ -115,7 +115,7 @@
* Example:
*
* ```
- * Polymer.Path.translate('foo.bar', 'zot' 'foo.bar.baz') // 'zot.baz'
+ * Polymer.Path.translate('foo.bar', 'zot', 'foo.bar.baz') // 'zot.baz'
* ```
*
* @memberof Polymer.Path
diff --git a/lib/utils/render-status.html b/lib/utils/render-status.html
index 6f44578908..151f74ebc0 100644
--- a/lib/utils/render-status.html
+++ b/lib/utils/render-status.html
@@ -85,8 +85,9 @@
*
* @memberof Polymer.RenderStatus
* @param {*} context Context object the callback function will be bound to
- * @param {function()} callback Callback function
- * @param {Array} args An array of arguments to call the callback function with
+ * @param {function(...*):void} callback Callback function
+ * @param {!Array=} args An array of arguments to call the callback function with
+ * @return {void}
*/
beforeNextRender: function(context, callback, args) {
if (!scheduled) {
@@ -106,8 +107,9 @@
*
* @memberof Polymer.RenderStatus
* @param {*} context Context object the callback function will be bound to
- * @param {function()} callback Callback function
- * @param {Array} args An array of arguments to call the callback function with
+ * @param {function(...*):void} callback Callback function
+ * @param {!Array=} args An array of arguments to call the callback function with
+ * @return {void}
*/
afterNextRender: function(context, callback, args) {
if (!scheduled) {
@@ -121,6 +123,7 @@
* tasks.
*
* @memberof Polymer.RenderStatus
+ * @return {void}
*/
flush: flush
diff --git a/lib/utils/resolve-url.html b/lib/utils/resolve-url.html
index 357ef6a322..612847b1ce 100644
--- a/lib/utils/resolve-url.html
+++ b/lib/utils/resolve-url.html
@@ -15,7 +15,6 @@
'use strict';
let CSS_URL_RX = /(url\()([^)]*)(\))/g;
- let ABS_URL = /(^\/)|(^#)|(^[\w-\d]*:)/;
let workingURL;
let resolveDoc;
/**
@@ -27,9 +26,6 @@
* @return {string} resolved URL
*/
function resolveUrl(url, baseURI) {
- if (url && ABS_URL.test(url)) {
- return url;
- }
// Lazy feature detection.
if (workingURL === undefined) {
workingURL = false;
diff --git a/lib/utils/settings.html b/lib/utils/settings.html
index 7d5163e848..5b0dc42039 100644
--- a/lib/utils/settings.html
+++ b/lib/utils/settings.html
@@ -17,24 +17,20 @@
'use strict';
/**
- * Legacy settings.
+ * Sets the global, legacy settings.
+ *
+ * @deprecated
* @namespace
* @memberof Polymer
*/
- const settings = Polymer.Settings || {};
- settings.useShadow = !(window.ShadyDOM);
- settings.useNativeCSSProperties =
+ Polymer.Settings = Polymer.Settings || {};
+
+ Polymer.Settings.useShadow = !(window.ShadyDOM);
+ Polymer.Settings.useNativeCSSProperties =
Boolean(!window.ShadyCSS || window.ShadyCSS.nativeCss);
- settings.useNativeCustomElements =
+ Polymer.Settings.useNativeCustomElements =
!(window.customElements.polyfillWrapFlushCallback);
- /**
- * Sets the global, legacy settings.
- *
- * @deprecated
- * @memberof Polymer
- */
- Polymer.Settings = settings;
/**
* Globally settable property that is automatically assigned to
@@ -57,6 +53,7 @@
*
* @memberof Polymer
* @param {string} path The new root path
+ * @return {void}
*/
Polymer.setRootPath = function(path) {
Polymer.rootPath = path;
@@ -89,6 +86,7 @@
*
* @memberof Polymer
* @param {(function(*,string,string,Node):*)|undefined} newSanitizeDOMValue the global sanitizeDOMValue callback
+ * @return {void}
*/
Polymer.setSanitizeDOMValue = function(newSanitizeDOMValue) {
Polymer.sanitizeDOMValue = newSanitizeDOMValue;
@@ -111,6 +109,7 @@
*
* @memberof Polymer
* @param {boolean} usePassive enable or disable passive touch gestures globally
+ * @return {void}
*/
Polymer.setPassiveTouchGestures = function(usePassive) {
Polymer.passiveTouchGestures = usePassive;
diff --git a/lib/utils/style-gather.html b/lib/utils/style-gather.html
index a48ab2915f..a2bb6feda1 100644
--- a/lib/utils/style-gather.html
+++ b/lib/utils/style-gather.html
@@ -14,6 +14,7 @@
const MODULE_STYLE_LINK_SELECTOR = 'link[rel=import][type~=css]';
const INCLUDE_ATTR = 'include';
+ const SHADY_UNSCOPED_ATTR = 'shady-unscoped';
function importModule(moduleId) {
const /** Polymer.DomModule */ PolymerDomModule = customElements.get('dom-module');
@@ -23,6 +24,18 @@
return PolymerDomModule.import(moduleId);
}
+ function styleForImport(importDoc) {
+ // NOTE: polyfill affordance.
+ // under the HTMLImports polyfill, there will be no 'body',
+ // but the import pseudo-doc can be used directly.
+ let container = importDoc.body ? importDoc.body : importDoc;
+ const importCss = Polymer.ResolveUrl.resolveCss(container.textContent,
+ importDoc.baseURI);
+ const style = document.createElement('style');
+ style.textContent = importCss;
+ return style;
+ }
+
/** @typedef {{assetpath: string}} */
let templateWithAssetPath; // eslint-disable-line no-unused-vars
@@ -37,15 +50,139 @@
const StyleGather = {
/**
+ * Returns a list of
+ ${this.is}
+ ${this.headerTemplate}
+ [[myProp.stuffThatGoesHere]]
+ ${this.footerTemplate}
+ `;
+ }
+ static get headerTemplate() { return html`Header
`; }
+ static get footerTemplate() { return html`Footer
`; }
+ }
+ customElements.define(SuperClass.is, SuperClass);
+ class SubClass extends SuperClass {
+ static get is() {return 'sub-class';}
+ static get template() {
+ return html`
+
+ ${super.template}
+ \
+ `;
+ }
+ constructor() {
+ super();
+ this.myProp = {stuffThatGoesHere: '!stuff that goes here!'};
+ }
+ static get headerTemplate() { return html`Sub-header
`; }
+ static get footerTemplate() { return html`Sub-footer
`; }
+ }
+ customElements.define(SubClass.is, SubClass);
+
+
+
+
+
+