diff --git a/lib/utils/gestures.html b/lib/utils/gestures.html
index ca38ec3173..2a05daa462 100644
--- a/lib/utils/gestures.html
+++ b/lib/utils/gestures.html
@@ -101,7 +101,7 @@
/** @type {!Array} */
const clickedLabels = [];
- /** @type {!Map} */
+ /** @type {!Object} */
const labellable = {
'button': true,
'input': true,
@@ -126,13 +126,12 @@
* @return {!Array} Relevant label for `el`
*/
function matchingLabels(el) {
- /** @type {!Array} */
- let labels = el.labels;
+ let labels = [...(/** @type {HTMLInputElement} */(el).labels || [])];
// IE doesn't have `labels` and Safari doesn't populate `labels`
// if element is in a shadowroot.
// In this instance, finding the non-ancestor labels is enough,
// as the mouseCancellor code will handle ancstor labels
- if (!labels || !labels.length) {
+ if (!labels.length) {
labels = [];
let root = el.getRootNode();
// if there is an id on `el`, check for all labels with a matching `for` attribute
@@ -1059,7 +1058,7 @@
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) {
+ if (!t || t.disabled) {
return;
}
// dx,dy can be NaN if `click` has been simulated and there was no `down` for `start`
diff --git a/test/smoke/disabled-attr-gestures.html b/test/smoke/disabled-attr-gestures.html
new file mode 100644
index 0000000000..e33cf34e1a
--- /dev/null
+++ b/test/smoke/disabled-attr-gestures.html
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/unit/gestures-elements.html b/test/unit/gestures-elements.html
index 534b4edfbf..15b7abeb1a 100644
--- a/test/unit/gestures-elements.html
+++ b/test/unit/gestures-elements.html
@@ -229,17 +229,39 @@
-
-
-
-
-
\ No newline at end of file
+ }
+ customElements.define(XNativeLabelNested.is, XNativeLabelNested);
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/unit/gestures.html b/test/unit/gestures.html
index 30866d06fa..b1a001bdd4 100644
--- a/test/unit/gestures.html
+++ b/test/unit/gestures.html
@@ -587,10 +587,9 @@
assert.equal(el.$.check.checked, true, 'checkbox should be checked');
document.body.removeChild(el);
});
- });
- test('label click with nested element', function() {
- let el = document.createElement('x-native-label-nested');
+ test('label click with nested element', function() {
+ let el = document.createElement('x-native-label-nested');
document.body.appendChild(el);
let target = el.$.label;
// simulate the event sequence of a touch on the screen
@@ -613,6 +612,47 @@
// check that the mouse click on the label will activate the checkbox
assert.equal(el.$.check.checked, true, 'checkbox should be checked');
document.body.removeChild(el);
+ });
+ });
+
+ test('disabled elements don\'t fire taps', function() {
+ let el = document.createElement('x-disabled-tap');
+ document.body.appendChild(el);
+ // tap an element with disabled attribute
+ let target = el.$.disabled;
+ // simulate the event sequence of a touch on the screen
+ let touches = [{
+ clientX: 0,
+ clientY: 0,
+ identifier: 1,
+ // target is set to the element with `addEventListener`, which is `target`
+ target
+ }];
+ let touchstart = new CustomEvent('touchstart', {bubbles: true, composed: true});
+ touchstart.changedTouches = touchstart.touches = touches;
+ target.dispatchEvent(touchstart);
+ let touchend = new CustomEvent('touchend', {bubbles: true, composed: true});
+ touchend.touches = touchend.changedTouches = touches;
+ target.dispatchEvent(touchend);
+ assert.equal(el.taps.length, 0);
+ // tap an element with a disabled ancestor
+ target = el.$.nested;
+ // simulate the event sequence of a touch on the screen
+ touches = [{
+ clientX: 0,
+ clientY: 0,
+ identifier: 1,
+ // target is set to the element with `addEventListener`, which is `target`
+ target
+ }];
+ touchstart = new CustomEvent('touchstart', {bubbles: true, composed: true});
+ touchstart.changedTouches = touchstart.touches = touches;
+ target.dispatchEvent(touchstart);
+ touchend = new CustomEvent('touchend', {bubbles: true, composed: true});
+ touchend.touches = touchend.changedTouches = touches;
+ target.dispatchEvent(touchend);
+ assert.equal(el.taps.length, 1);
+ document.body.removeChild(el);
});
});