mirror of
https://github.com/Polymer/polymer.git
synced 2025-02-25 18:55:30 -06:00
@@ -112,6 +112,20 @@ const labellable = {
|
||||
'select': true
|
||||
};
|
||||
|
||||
// Defined at https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#enabling-and-disabling-form-controls:-the-disabled-attribute
|
||||
/** @type {!Object<boolean>} */
|
||||
const canBeDisabled = {
|
||||
'button': true,
|
||||
'command': true,
|
||||
'fieldset': true,
|
||||
'input': true,
|
||||
'keygen': true,
|
||||
'optgroup': true,
|
||||
'option': true,
|
||||
'select': true,
|
||||
'textarea': true
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} el Element to check labelling status
|
||||
* @return {boolean} element can have labels
|
||||
@@ -1051,7 +1065,7 @@ register({
|
||||
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 || t.disabled) {
|
||||
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`
|
||||
|
||||
@@ -12,6 +12,7 @@ import { Polymer } from '../../lib/legacy/polymer-fn.js';
|
||||
import { html } from '../../lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '../../polymer-element.js';
|
||||
import { GestureEventListeners } from '../../lib/mixins/gesture-event-listeners.js';
|
||||
import { addListener } from '../../lib/utils/gestures.js';
|
||||
Polymer({
|
||||
_template: html`
|
||||
<style>
|
||||
@@ -196,23 +197,88 @@ class XNativeLabelNested extends PolymerElement {
|
||||
}
|
||||
}
|
||||
customElements.define(XNativeLabelNested.is, XNativeLabelNested);
|
||||
class XDisabled extends GestureEventListeners(PolymerElement) {
|
||||
static get template() {
|
||||
return html`
|
||||
<button id="disabled" on-tap="tap" disabled=""></button>
|
||||
<div disabled="">
|
||||
<button id="nested" on-tap="tap"></button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
class XDisabled extends PolymerElement {
|
||||
static get is() {
|
||||
return 'x-disabled';
|
||||
}
|
||||
static get properties() {
|
||||
return {
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
reflectToAttribute: true
|
||||
}
|
||||
};
|
||||
}
|
||||
constructor() {
|
||||
super();
|
||||
this.disabled = true;
|
||||
}
|
||||
}
|
||||
customElements.define(XDisabled.is, XDisabled);
|
||||
|
||||
class XDisabledTap extends GestureEventListeners(PolymerElement) {
|
||||
constructor() {
|
||||
super();
|
||||
this.taps = [];
|
||||
}
|
||||
static get is() {return 'x-disabled-tap';}
|
||||
static get template() {
|
||||
return html`
|
||||
<button id="disabled" on-tap="tap" disabled></button>
|
||||
<div disabled>
|
||||
<button id="nested" on-tap="tap"></button>
|
||||
</div>
|
||||
<x-disabled id="disabledEl" on-tap="tap"></x-disabled>`
|
||||
}
|
||||
static get is() {
|
||||
return 'x-disabled-tap';
|
||||
}
|
||||
tap(e) {
|
||||
this.taps.push(e.id);
|
||||
const target = e.target;
|
||||
this.taps.push(`${target.localName}${target.id ? '#' + target.id : ''}`);
|
||||
}
|
||||
}
|
||||
customElements.define(XDisabled.is, XDisabled);
|
||||
customElements.define(XDisabledTap.is, XDisabledTap);
|
||||
|
||||
|
||||
class AllDisabled extends GestureEventListeners(PolymerElement) {
|
||||
static get is() {
|
||||
return 'all-disabled';
|
||||
}
|
||||
static get template() {
|
||||
return html`
|
||||
<button></button>
|
||||
<!-- MDN lists as obsolete -->
|
||||
<!-- <command></command> -->
|
||||
<fieldset></fieldset>
|
||||
<input>
|
||||
<!-- MDN lists as obsolete -->
|
||||
<!-- <keygen> -->
|
||||
<select>
|
||||
<optgroup>
|
||||
<option></option>
|
||||
</optgroup>
|
||||
</select>
|
||||
<textarea></textarea>`;
|
||||
}
|
||||
constructor() {
|
||||
super();
|
||||
this.taps = [];
|
||||
}
|
||||
tap(e) {
|
||||
this.taps.push(e.target.localName);
|
||||
}
|
||||
ready() {
|
||||
super.ready();
|
||||
this.shadowRoot.querySelectorAll('*').forEach((el) => {
|
||||
el.setAttribute('disabled', '');
|
||||
addListener(el, 'tap', (e) => this.tap(e));
|
||||
});
|
||||
}
|
||||
tapAll() {
|
||||
this.shadowRoot.querySelectorAll('*').forEach((el) => {
|
||||
el.click();
|
||||
});
|
||||
}
|
||||
}
|
||||
customElements.define(AllDisabled.is, AllDisabled);
|
||||
@@ -619,44 +619,111 @@ suite('Regression Testing', function() {
|
||||
});
|
||||
});
|
||||
|
||||
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);
|
||||
suite('disabled', function() {
|
||||
let shouldSkip = true;
|
||||
|
||||
suiteSetup(function() {
|
||||
/*
|
||||
* IE 11 does not dispatch events to elements with `disabled` attribute
|
||||
* This is different from all other browsers, so skip these tests in IE 11
|
||||
*/
|
||||
const div = document.createElement('div');
|
||||
div.setAttribute('disabled', '');
|
||||
document.body.appendChild(div);
|
||||
div.addEventListener('click', () => {
|
||||
shouldSkip = false;
|
||||
});
|
||||
div.click();
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
setup(function() {
|
||||
gestures.resetMouseCanceller();
|
||||
});
|
||||
|
||||
test('click() function works as expected on disabled elements', function() {
|
||||
if (shouldSkip) {
|
||||
this.skip();
|
||||
}
|
||||
let el = document.createElement('x-disabled-tap');
|
||||
document.body.appendChild(el);
|
||||
el.$.disabled.click();
|
||||
el.$.nested.click();
|
||||
el.$.disabledEl.click();
|
||||
assert.deepEqual(el.taps, ['button#nested', 'x-disabled#disabledEl']);
|
||||
document.body.removeChild(el);
|
||||
});
|
||||
|
||||
test('disabled elements don\'t fire taps', function() {
|
||||
if (shouldSkip) {
|
||||
this.skip();
|
||||
}
|
||||
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.deepEqual(el.taps, []);
|
||||
|
||||
// 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.deepEqual(el.taps, ['button#nested']);
|
||||
|
||||
gestures.resetMouseCanceller();
|
||||
|
||||
// tap a custom element with a `disabled` property
|
||||
target = el.$.disabledEl;
|
||||
// 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.deepEqual(el.taps, ['button#nested', 'x-disabled#disabledEl']);
|
||||
document.body.removeChild(el);
|
||||
});
|
||||
|
||||
test('test all "disableable" elements', function() {
|
||||
const el = document.createElement('all-disabled');
|
||||
document.body.appendChild(el);
|
||||
el.tapAll();
|
||||
assert.deepEqual(el.taps, []);
|
||||
document.body.removeChild(el);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user