Skip to content

Commit 2bca0ee

Browse files
committed
Only disable tabs for "disablable" elements
Fixes #5190
1 parent 5f5d2c2 commit 2bca0ee

3 files changed

Lines changed: 164 additions & 43 deletions

File tree

lib/utils/gestures.html

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,19 @@
113113
'select': true
114114
};
115115

116+
/** @type {!Object<boolean>} */
117+
const canBeDisabled = {
118+
'button': true,
119+
'command': true,
120+
'fieldset': true,
121+
'input': true,
122+
'keygen': true,
123+
'optgroup': true,
124+
'option': true,
125+
'select': true,
126+
'textarea': true
127+
};
128+
116129
/**
117130
* @param {HTMLElement} el Element to check labelling status
118131
* @return {boolean} element can have labels
@@ -1058,7 +1071,7 @@
10581071
let dy = Math.abs(e.clientY - this.info.y);
10591072
// find original target from `preventer` for TouchEvents, or `e` for MouseEvents
10601073
let t = Gestures._findOriginalTarget(/** @type {Event} */(preventer || e));
1061-
if (!t || t.disabled) {
1074+
if (!t || (canBeDisabled[t.localName] && t.disabled)) {
10621075
return;
10631076
}
10641077
// dx,dy can be NaN if `click` has been simulated and there was no `down` for `start`

test/unit/gestures-elements.html

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -244,24 +244,92 @@
244244
</script>
245245
</dom-module>
246246

247+
<script>
248+
class XDisabled extends Polymer.Element {
249+
static get is() {
250+
return 'x-disabled';
251+
}
252+
static get properties() {
253+
return {
254+
disabled: Boolean
255+
};
256+
}
257+
constructor() {
258+
super();
259+
this.disabled = true;
260+
}
261+
}
262+
customElements.define(XDisabled.is, XDisabled);
263+
</script>
264+
247265
<dom-module id="x-disabled-tap">
248266
<template>
249267
<button id="disabled" on-tap="tap" disabled></button>
250268
<div disabled>
251269
<button id="nested" on-tap="tap"></button>
252270
</div>
271+
<x-disabled id="disabledEl" on-tap="tap"></x-disabled>
272+
</template>
273+
<script>
274+
class XDisabledTap extends Polymer.GestureEventListeners(Polymer.Element) {
275+
constructor() {
276+
super();
277+
this.taps = [];
278+
}
279+
static get is() {
280+
return 'x-disabled-tap';
281+
}
282+
tap(e) {
283+
const target = e.target;
284+
this.taps.push(`${target.localName}${target.id ? '#' + target.id : ''}`);
285+
}
286+
}
287+
customElements.define(XDisabledTap.is, XDisabledTap);
288+
</script>
289+
</dom-module>
290+
291+
<dom-module id="all-disabled">
292+
<template>
293+
<button></button>
294+
<!-- MDN lists as obsolete -->
295+
<!-- <command></command> -->
296+
<fieldset></fieldset>
297+
<input>
298+
<!-- MDN lists as obsolete -->
299+
<!-- <keygen> -->
300+
<select>
301+
<optgroup>
302+
<option></option>
303+
</optgroup>
304+
</select>
305+
<textarea></textarea>
306+
<div></div>
253307
</template>
254308
<script>
255-
class XDisabled extends Polymer.GestureEventListeners(Polymer.Element) {
309+
class AllDisabled extends Polymer.GestureEventListeners(Polymer.Element) {
310+
static get is() {
311+
return 'all-disabled';
312+
}
256313
constructor() {
257314
super();
258315
this.taps = [];
259316
}
260-
static get is() {return 'x-disabled-tap';}
261317
tap(e) {
262-
this.taps.push(e.id);
318+
this.taps.push(e.target.localName);
319+
}
320+
ready() {
321+
super.ready();
322+
this.shadowRoot.querySelectorAll('*').forEach((el) => {
323+
el.setAttribute('disabled', '');
324+
Polymer.Gestures.addListener(el, 'tap', (e) => this.tap(e));
325+
});
326+
}
327+
tapAll() {
328+
this.shadowRoot.querySelectorAll('*').forEach((el) => {
329+
el.click();
330+
});
263331
}
264332
}
265-
customElements.define(XDisabled.is, XDisabled);
333+
customElements.define(AllDisabled.is, AllDisabled);
266334
</script>
267335
</dom-module>

test/unit/gestures.html

Lines changed: 78 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -615,44 +615,84 @@
615615
});
616616
});
617617

618-
test('disabled elements don\'t fire taps', function() {
619-
let el = document.createElement('x-disabled-tap');
620-
document.body.appendChild(el);
621-
// tap an element with disabled attribute
622-
let target = el.$.disabled;
623-
// simulate the event sequence of a touch on the screen
624-
let touches = [{
625-
clientX: 0,
626-
clientY: 0,
627-
identifier: 1,
628-
// target is set to the element with `addEventListener`, which is `target`
629-
target
630-
}];
631-
let touchstart = new CustomEvent('touchstart', {bubbles: true, composed: true});
632-
touchstart.changedTouches = touchstart.touches = touches;
633-
target.dispatchEvent(touchstart);
634-
let touchend = new CustomEvent('touchend', {bubbles: true, composed: true});
635-
touchend.touches = touchend.changedTouches = touches;
636-
target.dispatchEvent(touchend);
637-
assert.equal(el.taps.length, 0);
638-
// tap an element with a disabled ancestor
639-
target = el.$.nested;
640-
// simulate the event sequence of a touch on the screen
641-
touches = [{
642-
clientX: 0,
643-
clientY: 0,
644-
identifier: 1,
645-
// target is set to the element with `addEventListener`, which is `target`
646-
target
647-
}];
648-
touchstart = new CustomEvent('touchstart', {bubbles: true, composed: true});
649-
touchstart.changedTouches = touchstart.touches = touches;
650-
target.dispatchEvent(touchstart);
651-
touchend = new CustomEvent('touchend', {bubbles: true, composed: true});
652-
touchend.touches = touchend.changedTouches = touches;
653-
target.dispatchEvent(touchend);
654-
assert.equal(el.taps.length, 1);
655-
document.body.removeChild(el);
618+
suite('disabled', function() {
619+
test('click() function works as expected on disabled elements', function() {
620+
Polymer.Gestures.resetMouseCanceller();
621+
let el = document.createElement('x-disabled-tap');
622+
document.body.appendChild(el);
623+
el.$.disabled.click();
624+
el.$.nested.click();
625+
el.$.disabledEl.click();
626+
assert.deepEqual(el.taps, ['button#nested', 'x-disabled#disabledEl']);
627+
document.body.removeChild(el);
628+
});
629+
630+
test('disabled elements don\'t fire taps', function() {
631+
let el = document.createElement('x-disabled-tap');
632+
document.body.appendChild(el);
633+
// tap an element with disabled attribute
634+
let target = el.$.disabled;
635+
// simulate the event sequence of a touch on the screen
636+
let touches = [{
637+
clientX: 0,
638+
clientY: 0,
639+
identifier: 1,
640+
// target is set to the element with `addEventListener`, which is `target`
641+
target
642+
}];
643+
let touchstart = new CustomEvent('touchstart', {bubbles: true, composed: true});
644+
touchstart.changedTouches = touchstart.touches = touches;
645+
target.dispatchEvent(touchstart);
646+
let touchend = new CustomEvent('touchend', {bubbles: true, composed: true});
647+
touchend.touches = touchend.changedTouches = touches;
648+
target.dispatchEvent(touchend);
649+
assert.deepEqual(el.taps, []);
650+
651+
// tap an element with a disabled ancestor
652+
target = el.$.nested;
653+
// simulate the event sequence of a touch on the screen
654+
touches = [{
655+
clientX: 0,
656+
clientY: 0,
657+
identifier: 1,
658+
// target is set to the element with `addEventListener`, which is `target`
659+
target
660+
}];
661+
touchstart = new CustomEvent('touchstart', {bubbles: true, composed: true});
662+
touchstart.changedTouches = touchstart.touches = touches;
663+
target.dispatchEvent(touchstart);
664+
touchend = new CustomEvent('touchend', {bubbles: true, composed: true});
665+
touchend.touches = touchend.changedTouches = touches;
666+
target.dispatchEvent(touchend);
667+
assert.deepEqual(el.taps, ['button#nested']);
668+
669+
// tap a custom element with a `disabled` property
670+
target = el.$.disabledEl;
671+
// simulate the event sequence of a touch on the screen
672+
touches = [{
673+
clientX: 0,
674+
clientY: 0,
675+
identifier: 1,
676+
// target is set to the element with `addEventListener`, which is `target`
677+
target
678+
}];
679+
touchstart = new CustomEvent('touchstart', {bubbles: true, composed: true});
680+
touchstart.changedTouches = touchstart.touches = touches;
681+
target.dispatchEvent(touchstart);
682+
touchend = new CustomEvent('touchend', {bubbles: true, composed: true});
683+
touchend.touches = touchend.changedTouches = touches;
684+
target.dispatchEvent(touchend);
685+
assert.deepEqual(el.taps, ['button#nested', 'x-disabled#disabledEl']);
686+
document.body.removeChild(el);
687+
});
688+
689+
test('test all "disablable" elements', function() {
690+
const el = document.createElement('all-disabled');
691+
document.body.appendChild(el);
692+
el.tapAll();
693+
assert.deepEqual(el.taps, ['div']);
694+
document.body.removeChild(el);
695+
})
656696
});
657697
});
658698
</script>

0 commit comments

Comments
 (0)