222 строки
6.7 KiB
JavaScript
222 строки
6.7 KiB
JavaScript
/*
|
|
* Copyright 2015 Google Inc. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
* use this file except in compliance with the License. You may obtain a copy of
|
|
* the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations under
|
|
* the License.
|
|
*/
|
|
|
|
|
|
void function() {
|
|
|
|
/**
|
|
* Sends a tab event on this document. Note that this is a copy of
|
|
* dispatchTabEvent from the polyfill source.
|
|
*
|
|
* @param {boolean=} opt_shiftKey whether to send this tab with shiftKey
|
|
*/
|
|
function sendTab(opt_shiftKey) {
|
|
let ev = null;
|
|
try {
|
|
ev = new KeyboardEvent('keydown', {
|
|
keyCode: 9,
|
|
which: 9,
|
|
key: 'Tab',
|
|
code: 'Tab',
|
|
keyIdentifier: 'U+0009',
|
|
shiftKey: !!opt_shiftKey,
|
|
bubbles: true
|
|
});
|
|
} catch (e) {
|
|
try {
|
|
// Internet Explorer
|
|
ev = document.createEvent('KeyboardEvent');
|
|
ev.initKeyboardEvent(
|
|
'keydown',
|
|
true,
|
|
true,
|
|
window,
|
|
'Tab',
|
|
0,
|
|
opt_shiftKey ? 'Shift' : '',
|
|
false,
|
|
'en'
|
|
)
|
|
} catch (e) {}
|
|
}
|
|
if (ev) {
|
|
try {
|
|
Object.defineProperty(ev, 'keyCode', { value: 9 });
|
|
} catch (e) {}
|
|
document.dispatchEvent(ev);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates a text input element and adds it to <body>.
|
|
*
|
|
* @param {string=} opt_text to use as placeholder
|
|
* @return {!HTMLInputElement} added to page
|
|
*/
|
|
function createInput(opt_text) {
|
|
const input = document.createElement('input');
|
|
input.type = 'text';
|
|
input.placeholder = opt_text || '';
|
|
holder.appendChild(input);
|
|
return input;
|
|
}
|
|
|
|
let holder; // global holder for all tests
|
|
setup(function() {
|
|
holder = document.createElement('div');
|
|
document.body.appendChild(holder);
|
|
});
|
|
teardown(function() {
|
|
holder.parentNode && holder.parentNode.removeChild(holder);
|
|
});
|
|
|
|
test('normal input should get focus', function() {
|
|
const div = document.createElement('div');
|
|
const input = document.createElement('input');
|
|
input.type = 'text';
|
|
input.value = 'dummy';
|
|
div.appendChild(input);
|
|
holder.appendChild(div);
|
|
|
|
input.focus();
|
|
|
|
assert.equal(document.activeElement, input);
|
|
|
|
// TODO(samthor): If focus is prevented, Firefox shows an odd state: highlighted, with a
|
|
// selection defined on the input, but without a caret visible. It's weird. Can we test for it?
|
|
|
|
});
|
|
test('no programatic focus', function() {
|
|
const div = document.createElement('div');
|
|
div.setAttribute('inert', '');
|
|
holder.appendChild(div);
|
|
|
|
const input = createInput('test inert');
|
|
div.appendChild(input);
|
|
|
|
// TODO: fails when developer console is open, even though focus doesn't go
|
|
// anywhere
|
|
input.focus();
|
|
assert.notEqual(document.activeElement, input, 'element should not be focusable');
|
|
|
|
div.tabIndex = 1;
|
|
div.focus();
|
|
assert.notEqual(document.activeElement, div, 'inert element itself unavailable');
|
|
});
|
|
test('support inert property', function() {
|
|
const div = document.createElement('div');
|
|
|
|
div.inert = true;
|
|
assert(div.hasAttribute('inert'));
|
|
div.inert = false;
|
|
assert(!div.hasAttribute('inert'));
|
|
|
|
div.setAttribute('inert', '');
|
|
assert(div.inert);
|
|
div.removeAttribute('inert');
|
|
assert(!div.inert);
|
|
});
|
|
test('click prevented', function() {
|
|
let clickCount = 0;
|
|
const div = document.createElement('div');
|
|
holder.appendChild(div);
|
|
|
|
const button = document.createElement('button');
|
|
button.addEventListener('click', function() {
|
|
++clickCount;
|
|
});
|
|
div.appendChild(button);
|
|
button.click();
|
|
assert.equal(clickCount, 1, 'programatic click once');
|
|
|
|
div.setAttribute('inert', '');
|
|
button.click();
|
|
assert.equal(clickCount, 1, 'programatic click disabled via inert');
|
|
});
|
|
test('focused click prevented', function() {
|
|
let clickCount = 0;
|
|
const div = document.createElement('div');
|
|
holder.appendChild(div);
|
|
|
|
const input = document.createElement('input');
|
|
input.type = 'text';
|
|
input.addEventListener('click', function() {
|
|
++clickCount;
|
|
});
|
|
div.appendChild(input);
|
|
input.focus();
|
|
assert.equal(document.activeElement, input);
|
|
input.click();
|
|
assert.equal(clickCount, 1, 'programatic click once');
|
|
|
|
div.setAttribute('inert', '');
|
|
input.click();
|
|
assert.equal(clickCount, 1, 'programatic click, even while ? focused, disabled via inert');
|
|
});
|
|
test('tab-over works', function() {
|
|
const beforeInput = createInput('before');
|
|
const duringInputInert = createInput('during');
|
|
const afterInput = createInput('after');
|
|
|
|
duringInputInert.setAttribute('inert', '');
|
|
|
|
beforeInput.focus();
|
|
assert.equal(document.activeElement, beforeInput, 'sanity check before input focused');
|
|
|
|
sendTab();
|
|
if (document.activeElement == beforeInput) {
|
|
// TODO: work around Firefox not actually acting on tab
|
|
console.warn('manual focus after tab');
|
|
duringInputInert.focus();
|
|
}
|
|
assert.equal(document.activeElement, afterInput, 'tab-over inert works');
|
|
|
|
sendTab(true);
|
|
if (document.activeElement == afterInput) {
|
|
// TODO: work around Firefox not actually acting on tab
|
|
console.warn('manual focus after shift-tab');
|
|
duringInputInert.focus();
|
|
}
|
|
assert.equal(document.activeElement, beforeInput, 'tab-over (reverse) inert works');
|
|
});
|
|
|
|
const testEl = document.createElement('div');
|
|
if (testEl.createShadowRoot || testEl.attachShadow) {
|
|
// test this
|
|
test('inert within shadow root', function() {
|
|
const el = document.createElement('div');
|
|
holder.appendChild(el);
|
|
const root = el.createShadowRoot ? el.createShadowRoot() : el.attachShadow({mode: 'open'});
|
|
|
|
const button = document.createElement('button');
|
|
root.appendChild(button);
|
|
button.focus();
|
|
assert.equal(document.activeElement, el, 'shadow host itself is focused');
|
|
assert.equal(root.activeElement, button, 'button within shadow is focused');
|
|
|
|
const inertButton = document.createElement('button');
|
|
inertButton.setAttribute('inert', '');
|
|
root.appendChild(inertButton);
|
|
inertButton.focus();
|
|
assert.notEqual(root.activeElement, inertButton, 'shadow root button inert');
|
|
|
|
inertButton.click();
|
|
assert.notEqual(root.activeElement, inertButton, 'shadow root button inert when clicked');
|
|
});
|
|
}
|
|
|
|
}();
|