mirror of
https://github.com/google/blockly.git
synced 2026-01-10 18:37:09 +01:00
## The basics - [x] I [validated my changes](https://developers.google.com/blockly/guides/contribute/core#making_and_verifying_a_change) ## The details ### Resolves Fixes #8965 Fixes #8978 Fixes #8970 Fixes https://github.com/google/blockly-keyboard-experimentation/issues/523 Fixes https://github.com/google/blockly-keyboard-experimentation/issues/547 Fixes part of #8910 ### Proposed Changes Fives groups of changes are included in this PR: 1. Support for automatic tab index management for focusable trees. 2. Support for automatic tab index management for focusable nodes. 3. Support for automatically hiding the flyout when back navigating from the toolbox. 4. A fix for `FocusManager` losing DOM syncing that was introduced in #9082. 5. Some cleanups for flyout and some tests for previous behavior changes to `FocusManager`. ### Reason for Changes Infrastructure changes reasoning: - Automatically managing tab indexes for both focusable trees and roots can largely reduce the difficulty of providing focusable nodes/trees and generally interacting with `FocusManager`. This facilitates a more automated navigation experience. - The fix for losing DOM syncing is possibly not reliable, but there are at least now tests to cover for it. This may be a case where a `try{} finally{}` could be warranted, but the code will stay as-is unless requested otherwise. `Flyout` changes: - `Flyout` no longer needs to be a focusable tree, but removing that would be an API breakage. Instead, it throws for most of the normal tree/node calls as it should no longer be used as such. Instead, its workspace has been made top-level tabbable (in addition to the main workspace) which solves the extra tab stop issues and general confusing inconsistencies between the flyout, toolbox, and workspace. - `Flyout` now correctly auto-selects the first block (#9103 notwithstanding). Technically it did before, however the extra `Flyout` tabstop before its workspace caused the inconsistency (since focusing the `Flyout` itself did not auto-select, only selecting its workspace did). Important caveats: - `getAttribute` is used in place of directly fetching `.tabIndex` since the latter can apparently default to `-1` (and possibly `0`) in cases when it's not actually set. This is a very surprising behavior that leads to incorrect test results. - Sometimes tab index still needs to be introduced (such as in cases where native DOM focus is needed, e.g. via `focus()` calls or clicking). This is demonstrated both by updates to `FocusManager`'s tests as well as toolbox's category and separator. This can be slightly tricky to miss as large parts of Blockly now depend on focus to represent their state, so clicking either needs to be managed by Blockly (with corresponding `focusNode` calls) or automatic (with a tab index defined for the element that can be clicked, or which has a child that can be clicked). Note that nearly all elements used for testing focus in the test `index.html` page have had their tab indexes removed to lean on `FocusManager`'s automatic tab management (though as mentioned above there is still some manual tab index management required for `focus()`-specific tests). ### Test Coverage New tests were added for all of the updated behaviors to `FocusManager`, including a new need to explicitly provide (and reset) tab indexes for all `focus()`-esque tests. This also includes adding new tests for some behaviors introduced in past PRs (a la #8910). Note that all of the new and affected conditionals in `FocusManager` have been verified as having at least 1 test that breaks when it's removed (inverted conditions weren't thoroughly tested, but it's expected that they should also be well covered now). Additional tests to cover the actual navigation flows will be added to the keyboard experimentation plugin repository as part of https://github.com/google/blockly-keyboard-experimentation/pull/557 (this PR needs to be merged first). For manual testing, I mainly verified keyboard navigation with some cursory mouse & click testing in the simple playground. @rachel-fenichel also performed more thorough mouse & click testing (that yielded an actual issue that was fixed--see discussion below). The core webdriver tests have been verified to have seemingly the same existing failures with and without these changes. All of the following new keyboard navigation plugin tests have been verified as failing without the fixes introduced in this branch (and passing with them): - `Tab navigating to flyout should auto-select first block` - `Keyboard nav to different toolbox category should auto-select first block` - `Keyboard nav to different toolbox category and block should select different block` - `Tab navigate away from toolbox restores focus to initial element` - `Tab navigate away from toolbox closes flyout` - `Tab navigate away from flyout to toolbox and away closes flyout` - `Tabbing to the workspace after selecting flyout block should close the flyout` - `Tabbing to the workspace after selecting flyout block via workspace toolbox shortcut should close the flyout` - `Tabbing back from workspace should reopen the flyout` - `Navigation position in workspace should be retained when tabbing to flyout and back` - `Clicking outside Blockly with focused toolbox closes the flyout` - `Clicking outside Blockly with focused flyout closes the flyout` - `Clicking on toolbox category focuses it and opens flyout` ### Documentation No documentation changes are needed beyond the code doc changes included in the PR. ### Additional Information An additional PR will be introduced for the keyboard experimentation plugin repository to add tests there (see test coverage above). This description will be updated with a link to that PR once it exists.
5932 lines
232 KiB
JavaScript
5932 lines
232 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import {
|
|
FocusManager,
|
|
getFocusManager,
|
|
} from '../../build/src/core/focus_manager.js';
|
|
import {assert} from '../../node_modules/chai/chai.js';
|
|
import {
|
|
sharedTestSetup,
|
|
sharedTestTeardown,
|
|
} from './test_helpers/setup_teardown.js';
|
|
|
|
class FocusableNodeImpl {
|
|
constructor(element, tree) {
|
|
this.element = element;
|
|
this.tree = tree;
|
|
}
|
|
|
|
getFocusableElement() {
|
|
return this.element;
|
|
}
|
|
|
|
getFocusableTree() {
|
|
return this.tree;
|
|
}
|
|
|
|
onNodeFocus() {}
|
|
|
|
onNodeBlur() {}
|
|
|
|
canBeFocused() {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
class FocusableTreeImpl {
|
|
constructor(rootElement, nestedTrees) {
|
|
this.nestedTrees = nestedTrees;
|
|
this.idToNodeMap = {};
|
|
this.rootNode = this.addNode(rootElement);
|
|
this.fallbackNode = null;
|
|
}
|
|
|
|
addNode(element) {
|
|
const node = new FocusableNodeImpl(element, this);
|
|
this.idToNodeMap[element.id] = node;
|
|
return node;
|
|
}
|
|
|
|
removeNode(node) {
|
|
delete this.idToNodeMap[node.getFocusableElement().id];
|
|
}
|
|
|
|
getRootFocusableNode() {
|
|
return this.rootNode;
|
|
}
|
|
|
|
getRestoredFocusableNode() {
|
|
return this.fallbackNode;
|
|
}
|
|
|
|
getNestedTrees() {
|
|
return this.nestedTrees;
|
|
}
|
|
|
|
lookUpFocusableNode(id) {
|
|
return this.idToNodeMap[id];
|
|
}
|
|
|
|
onTreeFocus() {}
|
|
|
|
onTreeBlur() {}
|
|
}
|
|
|
|
suite('FocusManager', function () {
|
|
const ACTIVE_FOCUS_NODE_CSS_SELECTOR = `.${FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME}`;
|
|
const PASSIVE_FOCUS_NODE_CSS_SELECTOR = `.${FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME}`;
|
|
|
|
setup(function () {
|
|
sharedTestSetup.call(this);
|
|
this.focusManager = getFocusManager();
|
|
|
|
this.allFocusableTrees = [];
|
|
this.allFocusableNodes = [];
|
|
this.createFocusableTree = function (rootElementId, nestedTrees) {
|
|
const tree = new FocusableTreeImpl(
|
|
document.getElementById(rootElementId),
|
|
nestedTrees || [],
|
|
);
|
|
this.allFocusableTrees.push(tree);
|
|
return tree;
|
|
};
|
|
this.createFocusableNode = function (tree, elementId) {
|
|
const node = tree.addNode(document.getElementById(elementId));
|
|
this.allFocusableNodes.push(node);
|
|
return node;
|
|
};
|
|
|
|
this.testFocusableTree1 = this.createFocusableTree('testFocusableTree1');
|
|
this.testFocusableTree1Node1 = this.createFocusableNode(
|
|
this.testFocusableTree1,
|
|
'testFocusableTree1.node1',
|
|
);
|
|
this.testFocusableTree1Node1Child1 = this.createFocusableNode(
|
|
this.testFocusableTree1,
|
|
'testFocusableTree1.node1.child1',
|
|
);
|
|
this.testFocusableTree1Node2 = this.createFocusableNode(
|
|
this.testFocusableTree1,
|
|
'testFocusableTree1.node2',
|
|
);
|
|
this.testFocusableNestedTree4 = this.createFocusableTree(
|
|
'testFocusableNestedTree4',
|
|
);
|
|
this.testFocusableNestedTree4Node1 = this.createFocusableNode(
|
|
this.testFocusableNestedTree4,
|
|
'testFocusableNestedTree4.node1',
|
|
);
|
|
this.testFocusableNestedTree5 = this.createFocusableTree(
|
|
'testFocusableNestedTree5',
|
|
);
|
|
this.testFocusableNestedTree5Node1 = this.createFocusableNode(
|
|
this.testFocusableNestedTree5,
|
|
'testFocusableNestedTree5.node1',
|
|
);
|
|
this.testFocusableTree2 = this.createFocusableTree('testFocusableTree2', [
|
|
this.testFocusableNestedTree4,
|
|
this.testFocusableNestedTree5,
|
|
]);
|
|
this.testFocusableTree2Node1 = this.createFocusableNode(
|
|
this.testFocusableTree2,
|
|
'testFocusableTree2.node1',
|
|
);
|
|
|
|
this.testFocusableGroup1 = this.createFocusableTree('testFocusableGroup1');
|
|
this.testFocusableGroup1Node1 = this.createFocusableNode(
|
|
this.testFocusableGroup1,
|
|
'testFocusableGroup1.node1',
|
|
);
|
|
this.testFocusableGroup1Node1Child1 = this.createFocusableNode(
|
|
this.testFocusableGroup1,
|
|
'testFocusableGroup1.node1.child1',
|
|
);
|
|
this.testFocusableGroup1Node2 = this.createFocusableNode(
|
|
this.testFocusableGroup1,
|
|
'testFocusableGroup1.node2',
|
|
);
|
|
this.testFocusableNestedGroup4 = this.createFocusableTree(
|
|
'testFocusableNestedGroup4',
|
|
);
|
|
this.testFocusableNestedGroup4Node1 = this.createFocusableNode(
|
|
this.testFocusableNestedGroup4,
|
|
'testFocusableNestedGroup4.node1',
|
|
);
|
|
this.testFocusableGroup2 = this.createFocusableTree('testFocusableGroup2', [
|
|
this.testFocusableNestedGroup4,
|
|
]);
|
|
this.testFocusableGroup2Node1 = this.createFocusableNode(
|
|
this.testFocusableGroup2,
|
|
'testFocusableGroup2.node1',
|
|
);
|
|
});
|
|
|
|
teardown(function () {
|
|
sharedTestTeardown.call(this);
|
|
|
|
// Ensure all node CSS styles are reset so that state isn't leaked between tests.
|
|
const activeElems = document.querySelectorAll(
|
|
ACTIVE_FOCUS_NODE_CSS_SELECTOR,
|
|
);
|
|
const passiveElems = document.querySelectorAll(
|
|
PASSIVE_FOCUS_NODE_CSS_SELECTOR,
|
|
);
|
|
for (const elem of activeElems) {
|
|
elem.classList.remove(FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME);
|
|
}
|
|
for (const elem of passiveElems) {
|
|
elem.classList.remove(FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME);
|
|
}
|
|
|
|
// Ensure any set tab indexes are properly reset between tests.
|
|
for (const tree of this.allFocusableTrees) {
|
|
tree
|
|
.getRootFocusableNode()
|
|
.getFocusableElement()
|
|
.removeAttribute('tabindex');
|
|
}
|
|
for (const node of this.allFocusableNodes) {
|
|
node.getFocusableElement().removeAttribute('tabindex');
|
|
}
|
|
this.allFocusableTrees = [];
|
|
this.allFocusableNodes = [];
|
|
|
|
// Reset the current active element.
|
|
document.body.focus();
|
|
});
|
|
|
|
assert.includesClass = function (classList, className) {
|
|
assert.isTrue(
|
|
classList.contains(className),
|
|
'Expected class list to include: ' + className,
|
|
);
|
|
};
|
|
|
|
assert.notIncludesClass = function (classList, className) {
|
|
assert.isFalse(
|
|
classList.contains(className),
|
|
'Expected class list to not include: ' + className,
|
|
);
|
|
};
|
|
|
|
/* Basic lifecycle tests. */
|
|
|
|
suite('registerTree()', function () {
|
|
test('once does not throw', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
// The test should pass due to no exception being thrown.
|
|
});
|
|
|
|
test('twice for same tree throws error', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
const errorMsgRegex =
|
|
/Attempted to re-register already registered tree.+?/;
|
|
assert.throws(
|
|
() => this.focusManager.registerTree(this.testFocusableTree1),
|
|
errorMsgRegex,
|
|
);
|
|
});
|
|
|
|
test('twice with different trees does not throw', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
|
|
// The test shouldn't throw since two different trees were registered.
|
|
});
|
|
|
|
test('register after an unregister does not throw', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
// The second register should not fail since the tree was previously unregistered.
|
|
});
|
|
|
|
test('for unmanaged tree does not overwrite tab index', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1, false);
|
|
|
|
const rootNode = this.testFocusableTree1.getRootFocusableNode();
|
|
const rootElem = rootNode.getFocusableElement();
|
|
assert.isNull(rootElem.getAttribute('tabindex'));
|
|
});
|
|
|
|
test('for unmanaged tree with custom tab index does not overwrite tab index', function () {
|
|
const rootNode = this.testFocusableTree1.getRootFocusableNode();
|
|
const rootElem = rootNode.getFocusableElement();
|
|
rootElem.tabIndex = -1;
|
|
|
|
this.focusManager.registerTree(this.testFocusableTree1, false);
|
|
|
|
// The custom tab index shouldn't be overwritten for an unmanaged tree.
|
|
assert.strictEqual(rootElem.getAttribute('tabindex'), '-1');
|
|
});
|
|
|
|
test('for managed tree overwrites root tab index to be tab navigable', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1, true);
|
|
|
|
const rootNode = this.testFocusableTree1.getRootFocusableNode();
|
|
const rootElem = rootNode.getFocusableElement();
|
|
assert.strictEqual(rootElem.getAttribute('tabindex'), '0');
|
|
});
|
|
|
|
test('for managed tree with custom tab index overwrites root tab index to be tab navigable', function () {
|
|
const rootNode = this.testFocusableTree1.getRootFocusableNode();
|
|
const rootElem = rootNode.getFocusableElement();
|
|
rootElem.tabIndex = -1;
|
|
|
|
this.focusManager.registerTree(this.testFocusableTree1, true);
|
|
|
|
// A custom tab index should be overwritten for a managed tree.
|
|
assert.strictEqual(rootElem.getAttribute('tabindex'), '0');
|
|
});
|
|
});
|
|
|
|
suite('unregisterTree()', function () {
|
|
test('for not yet registered tree throws', function () {
|
|
const errorMsgRegex = /Attempted to unregister not registered tree.+?/;
|
|
assert.throws(
|
|
() => this.focusManager.unregisterTree(this.testFocusableTree1),
|
|
errorMsgRegex,
|
|
);
|
|
});
|
|
|
|
test('for registered tree does not throw', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Unregistering a registered tree should not fail.
|
|
});
|
|
|
|
test('twice for registered tree throws', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
const errorMsgRegex = /Attempted to unregister not registered tree.+?/;
|
|
assert.throws(
|
|
() => this.focusManager.unregisterTree(this.testFocusableTree1),
|
|
errorMsgRegex,
|
|
);
|
|
});
|
|
|
|
test('for unmanaged tree with custom tab index does not change tab index', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1, false);
|
|
const rootNode = this.testFocusableTree1.getRootFocusableNode();
|
|
const rootElem = rootNode.getFocusableElement();
|
|
rootElem.tabIndex = -1;
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Unregistering an unmanaged tree shouldn't change its tab index.
|
|
assert.strictEqual(rootElem.getAttribute('tabindex'), '-1');
|
|
});
|
|
|
|
test('for managed tree removes tab index', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1, true);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Unregistering a managed tree should remove its tab index.
|
|
const rootNode = this.testFocusableTree1.getRootFocusableNode();
|
|
const rootElem = rootNode.getFocusableElement();
|
|
assert.isNull(rootElem.getAttribute('tabindex'));
|
|
});
|
|
|
|
test('for managed tree with custom tab index removes tab index', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1, true);
|
|
const rootNode = this.testFocusableTree1.getRootFocusableNode();
|
|
const rootElem = rootNode.getFocusableElement();
|
|
rootElem.tabIndex = -1;
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Unregistering a managed tree should remove its tab index.
|
|
assert.isNull(rootElem.getAttribute('tabindex'));
|
|
});
|
|
});
|
|
|
|
suite('isRegistered()', function () {
|
|
test('for not registered tree returns false', function () {
|
|
const isRegistered = this.focusManager.isRegistered(
|
|
this.testFocusableTree1,
|
|
);
|
|
|
|
assert.isFalse(isRegistered);
|
|
});
|
|
|
|
test('for registered tree returns true', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
const isRegistered = this.focusManager.isRegistered(
|
|
this.testFocusableTree1,
|
|
);
|
|
|
|
assert.isTrue(isRegistered);
|
|
});
|
|
|
|
test('for unregistered tree returns false', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
const isRegistered = this.focusManager.isRegistered(
|
|
this.testFocusableTree1,
|
|
);
|
|
|
|
assert.isFalse(isRegistered);
|
|
});
|
|
|
|
test('for re-registered tree returns true', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
const isRegistered = this.focusManager.isRegistered(
|
|
this.testFocusableTree1,
|
|
);
|
|
|
|
assert.isTrue(isRegistered);
|
|
});
|
|
|
|
test('for unregistered tree with other registered tree returns false', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
const isRegistered = this.focusManager.isRegistered(
|
|
this.testFocusableTree1,
|
|
);
|
|
|
|
assert.isFalse(isRegistered);
|
|
});
|
|
});
|
|
|
|
suite('getFocusedTree()', function () {
|
|
test('by default returns null', function () {
|
|
const focusedTree = this.focusManager.getFocusedTree();
|
|
|
|
assert.isNull(focusedTree);
|
|
});
|
|
});
|
|
|
|
suite('getFocusedNode()', function () {
|
|
test('by default returns null', function () {
|
|
const focusedNode = this.focusManager.getFocusedNode();
|
|
|
|
assert.isNull(focusedNode);
|
|
});
|
|
|
|
test('after focusing unfocusable node returns null', function () {
|
|
this.testFocusableTree1Node1.canBeFocused = () => false;
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
const focusedNode = this.focusManager.getFocusedNode();
|
|
|
|
// Unfocusable nodes should not be focused.
|
|
assert.isNull(focusedNode);
|
|
});
|
|
});
|
|
|
|
suite('focusTree()', function () {
|
|
test('for not registered tree throws', function () {
|
|
const errorMsgRegex = /Attempted to focus unregistered tree.+?/;
|
|
assert.throws(
|
|
() => this.focusManager.focusTree(this.testFocusableTree1),
|
|
errorMsgRegex,
|
|
);
|
|
});
|
|
|
|
test('for unregistered tree throws', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
const errorMsgRegex = /Attempted to focus unregistered tree.+?/;
|
|
assert.throws(
|
|
() => this.focusManager.focusTree(this.testFocusableTree1),
|
|
errorMsgRegex,
|
|
);
|
|
});
|
|
});
|
|
|
|
test('unfocused node does not have a tab index by default', function () {
|
|
const elem = this.testFocusableTree1Node1.getFocusableElement();
|
|
|
|
// This is slightly testing the test setup, but it acts as a precondition sanity test for the
|
|
// other tab index tests below. Important: 'getAttribute' is used here since direct access to
|
|
// 'tabIndex' can default the value returned even when the tab index isn't set.
|
|
assert.isNull(elem.getAttribute('tabindex'));
|
|
});
|
|
|
|
suite('focusNode()', function () {
|
|
test('for not registered node throws', function () {
|
|
const errorMsgRegex = /Attempted to focus unregistered node.+?/;
|
|
assert.throws(
|
|
() => this.focusManager.focusNode(this.testFocusableTree1Node1),
|
|
errorMsgRegex,
|
|
);
|
|
});
|
|
|
|
test('for unregistered node throws', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
const errorMsgRegex = /Attempted to focus unregistered node.+?/;
|
|
assert.throws(
|
|
() => this.focusManager.focusNode(this.testFocusableTree1Node1),
|
|
errorMsgRegex,
|
|
);
|
|
});
|
|
|
|
test('focuses element', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
const nodeElem = this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.strictEqual(document.activeElement, nodeElem);
|
|
});
|
|
|
|
test('fires focusin event', function () {
|
|
let focusCount = 0;
|
|
const focusListener = () => focusCount++;
|
|
document.addEventListener('focusin', focusListener);
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
document.removeEventListener('focusin', focusListener);
|
|
|
|
// There should be exactly 1 focus event fired from focusNode().
|
|
assert.strictEqual(focusCount, 1);
|
|
});
|
|
|
|
test('for orphaned node returns tree root by default', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.testFocusableTree1.removeNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
// Focusing an invalid node should fall back to the tree root when it has no restoration
|
|
// fallback node.
|
|
const currentNode = this.focusManager.getFocusedNode();
|
|
const treeRoot = this.testFocusableTree1.getRootFocusableNode();
|
|
assert.strictEqual(currentNode, treeRoot);
|
|
});
|
|
|
|
test('for orphaned node returns specified fallback node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.testFocusableTree1.fallbackNode = this.testFocusableTree1Node2;
|
|
this.testFocusableTree1.removeNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
// Focusing an invalid node should fall back to the restored fallback.
|
|
const currentNode = this.focusManager.getFocusedNode();
|
|
assert.strictEqual(currentNode, this.testFocusableTree1Node2);
|
|
});
|
|
|
|
test('restores focus when element quietly loses focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
// Remove the FocusManager's listeners to simulate not receiving a focus
|
|
// event when focus is lost. This can happen in Firefox and Safari when an
|
|
// element is removed and then re-added to the DOM. This is a contrived
|
|
// setup to achieve the same outcome on all browsers. For context, see:
|
|
// https://github.com/google/blockly-keyboard-experimentation/issues/87.
|
|
for (const registeredListener of this.globalDocumentEventListeners) {
|
|
const eventType = registeredListener.type;
|
|
const eventListener = registeredListener.listener;
|
|
document.removeEventListener(eventType, eventListener);
|
|
}
|
|
document.body.focus();
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
const currentNode = this.focusManager.getFocusedNode();
|
|
const currentElem = currentNode?.getFocusableElement();
|
|
assert.strictEqual(currentNode, this.testFocusableTree1Node1);
|
|
assert.strictEqual(document.activeElement, currentElem);
|
|
});
|
|
|
|
test('restores focus when element and new node focused', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
// Remove the FocusManager's listeners to simulate not receiving a focus
|
|
// event when focus is lost. This can happen in Firefox and Safari when an
|
|
// element is removed and then re-added to the DOM. This is a contrived
|
|
// setup to achieve the same outcome on all browsers. For context, see:
|
|
// https://github.com/google/blockly-keyboard-experimentation/issues/87.
|
|
for (const registeredListener of this.globalDocumentEventListeners) {
|
|
const eventType = registeredListener.type;
|
|
const eventListener = registeredListener.listener;
|
|
document.removeEventListener(eventType, eventListener);
|
|
}
|
|
document.body.focus();
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node2);
|
|
|
|
const currentNode = this.focusManager.getFocusedNode();
|
|
const currentElem = currentNode?.getFocusableElement();
|
|
assert.strictEqual(currentNode, this.testFocusableTree1Node2);
|
|
assert.strictEqual(document.activeElement, currentElem);
|
|
});
|
|
|
|
test('for unfocused node calls onNodeFocus once', function () {
|
|
sinon.spy(this.testFocusableTree1Node1, 'onNodeFocus');
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
assert.strictEqual(this.testFocusableTree1Node1.onNodeFocus.callCount, 1);
|
|
});
|
|
|
|
test('for previously focused node calls onNodeBlur once', function () {
|
|
sinon.spy(this.testFocusableTree1Node1, 'onNodeBlur');
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node2);
|
|
|
|
assert.strictEqual(this.testFocusableTree1Node1.onNodeBlur.callCount, 1);
|
|
});
|
|
|
|
test('for unfocused tree calls onTreeFocus once', function () {
|
|
sinon.spy(this.testFocusableTree1, 'onTreeFocus');
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
assert.strictEqual(this.testFocusableTree1.onTreeFocus.callCount, 1);
|
|
});
|
|
|
|
test('for previously focused tree calls onTreeBlur once', function () {
|
|
sinon.spy(this.testFocusableTree1, 'onTreeBlur');
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
assert.strictEqual(this.testFocusableTree1.onTreeBlur.callCount, 1);
|
|
});
|
|
|
|
test('for same node twice calls onNodeFocus once', function () {
|
|
sinon.spy(this.testFocusableTree1Node1, 'onNodeFocus');
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
// Call focus for the same node a second time.
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
// Despite two calls to focus the node should only focus once.
|
|
assert.strictEqual(this.testFocusableTree1Node1.onNodeFocus.callCount, 1);
|
|
});
|
|
|
|
test('for unfocusable node does not call onNodeFocus', function () {
|
|
sinon.spy(this.testFocusableTree1Node1, 'onNodeFocus');
|
|
this.testFocusableTree1Node1.canBeFocused = () => false;
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
// Unfocusable nodes should not be focused, nor have their callbacks called.
|
|
assert.strictEqual(this.testFocusableTree1Node1.onNodeFocus.callCount, 0);
|
|
});
|
|
|
|
test('for unfocused node overwrites tab index', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
// Focusing an element should overwrite its tab index.
|
|
const elem = this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.strictEqual(elem.getAttribute('tabindex'), '-1');
|
|
});
|
|
|
|
test('for previously focused node keeps new tab index', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node2);
|
|
|
|
// The previously focused element should retain its tab index.
|
|
const elem = this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.strictEqual(elem.getAttribute('tabindex'), '-1');
|
|
});
|
|
|
|
test('for node with custom tab index does not change tab index', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
const elem = this.testFocusableTree1Node1.getFocusableElement();
|
|
elem.tabIndex = 0;
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
// If the node already has a tab index set then it should retain that index.
|
|
assert.strictEqual(elem.getAttribute('tabindex'), '0');
|
|
});
|
|
|
|
suite('for unmanaged tree', function () {
|
|
test('focused root overwrites tab index', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1, false);
|
|
const rootNode = this.testFocusableTree1.getRootFocusableNode();
|
|
|
|
this.focusManager.focusNode(rootNode);
|
|
|
|
// Focusing an unmanaged tree's root should overwrite its tab index.
|
|
const rootElem = rootNode.getFocusableElement();
|
|
assert.strictEqual(rootElem.getAttribute('tabindex'), '-1');
|
|
});
|
|
|
|
test('focused root with custom tab index does not change tab index', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1, false);
|
|
const rootNode = this.testFocusableTree1.getRootFocusableNode();
|
|
const rootElem = rootNode.getFocusableElement();
|
|
rootElem.tabIndex = 0;
|
|
|
|
this.focusManager.focusNode(rootNode);
|
|
|
|
// If the node already has a tab index set then it should retain that index.
|
|
assert.strictEqual(rootElem.getAttribute('tabindex'), '0');
|
|
});
|
|
|
|
test('focused node in a tree after unmanaged was focused should keep previous root unchanged', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1, false);
|
|
this.focusManager.registerTree(this.testFocusableTree2, false);
|
|
const rootNode = this.testFocusableTree1.getRootFocusableNode();
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
// Focusing a different tree shouldn't change the root of the previous tree if it's unmanaged.
|
|
const rootElem = rootNode.getFocusableElement();
|
|
assert.isNull(rootElem.getAttribute('tabindex'));
|
|
});
|
|
|
|
test('focused node in a tree after unmanaged was root focused should make previous root tab navigable', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1, false);
|
|
this.focusManager.registerTree(this.testFocusableTree2, false);
|
|
const rootNode = this.testFocusableTree1.getRootFocusableNode();
|
|
this.focusManager.focusTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
// The previous tree's root should be kept unchanged (since it was managed).
|
|
const rootElem = rootNode.getFocusableElement();
|
|
assert.strictEqual(rootElem.getAttribute('tabindex'), '-1');
|
|
});
|
|
});
|
|
|
|
suite('for managed tree', function () {
|
|
test('for unfocused node in managed tree overwrites tab index', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1, true);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
// Focusing an element should overwrite its tab index.
|
|
const elem = this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.strictEqual(elem.getAttribute('tabindex'), '-1');
|
|
});
|
|
|
|
test('for previously focused node in managed tree keeps new tab index', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1, true);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node2);
|
|
|
|
// The previously focused element should retain its tab index.
|
|
const elem = this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.strictEqual(elem.getAttribute('tabindex'), '-1');
|
|
});
|
|
|
|
test('focused root makes root non-tab navigable', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1, true);
|
|
const rootNode = this.testFocusableTree1.getRootFocusableNode();
|
|
|
|
this.focusManager.focusNode(rootNode);
|
|
|
|
// Focusing the root in a managed tree should make it non-tab navigable.
|
|
const rootElem = rootNode.getFocusableElement();
|
|
assert.strictEqual(rootElem.getAttribute('tabindex'), '-1');
|
|
});
|
|
|
|
test('focused root with custom tab index should overwrite tab index', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1, true);
|
|
const rootNode = this.testFocusableTree1.getRootFocusableNode();
|
|
const rootElem = rootNode.getFocusableElement();
|
|
rootElem.tabIndex = 0;
|
|
|
|
this.focusManager.focusNode(rootNode);
|
|
|
|
// Custom tab indexes are overwritten for the root in a managed tree.
|
|
assert.strictEqual(rootElem.getAttribute('tabindex'), '-1');
|
|
});
|
|
|
|
test('focused node tree root makes root non-tab navigable', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1, true);
|
|
const rootNode = this.testFocusableTree1.getRootFocusableNode();
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
// Focusing a node of a managed tree should make the root non-tab navigable.
|
|
const rootElem = rootNode.getFocusableElement();
|
|
assert.strictEqual(rootElem.getAttribute('tabindex'), '-1');
|
|
});
|
|
|
|
test('focused node root with custom tab index should overwrite tab index', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1, true);
|
|
const rootNode = this.testFocusableTree1.getRootFocusableNode();
|
|
const rootElem = rootNode.getFocusableElement();
|
|
rootElem.tabIndex = 0;
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
// Custom tab indexes are overwritten for the root in a managed tree even when a tree's node
|
|
// is focused.
|
|
assert.strictEqual(rootElem.getAttribute('tabindex'), '-1');
|
|
});
|
|
|
|
test('focused node in a tree after managed was focused should make previous root tab navigable', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1, true);
|
|
this.focusManager.registerTree(this.testFocusableTree2, false);
|
|
const rootNode = this.testFocusableTree1.getRootFocusableNode();
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
// Focusing a different tree shouldn't after a managed tree should make the managed tree tab
|
|
// navigable.
|
|
const rootElem = rootNode.getFocusableElement();
|
|
assert.strictEqual(rootElem.getAttribute('tabindex'), '0');
|
|
});
|
|
|
|
test('focused node in a tree after managed was root focused should make previous root tab navigable', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1, true);
|
|
this.focusManager.registerTree(this.testFocusableTree2, false);
|
|
const rootNode = this.testFocusableTree1.getRootFocusableNode();
|
|
this.focusManager.focusTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
// Focusing a different tree shouldn't after a managed tree should make the managed tree tab
|
|
// navigable.
|
|
const rootElem = rootNode.getFocusableElement();
|
|
assert.strictEqual(rootElem.getAttribute('tabindex'), '0');
|
|
});
|
|
});
|
|
});
|
|
|
|
suite('getFocusManager()', function () {
|
|
test('returns non-null manager', function () {
|
|
const manager = getFocusManager();
|
|
|
|
assert.isNotNull(manager);
|
|
});
|
|
|
|
test('returns the exact same instance in subsequent calls', function () {
|
|
const manager1 = getFocusManager();
|
|
const manager2 = getFocusManager();
|
|
|
|
assert.strictEqual(manager2, manager1);
|
|
});
|
|
});
|
|
|
|
/* Focus tests for HTML trees. */
|
|
|
|
suite('focus*() switching in HTML tree', function () {
|
|
suite('getFocusedTree()', function () {
|
|
test('registered tree focusTree()ed no prev focus returns tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableTree1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree1,
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed prev node focused returns tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableTree1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree1,
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed diff tree prev focused returns new tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableTree2);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree2,
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed diff tree node prev focused returns new tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableTree2);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree2,
|
|
);
|
|
});
|
|
|
|
test('registered root focusNode()ed no prev focus returns tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusNode(
|
|
this.testFocusableTree1.getRootFocusableNode(),
|
|
);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree1,
|
|
);
|
|
});
|
|
|
|
test("registered node focusNode()ed no prev focus returns node's tree", function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree1,
|
|
);
|
|
});
|
|
|
|
test("registered subnode focusNode()ed no prev focus returns node's tree", function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1Child1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree1,
|
|
);
|
|
});
|
|
|
|
test('registered node focusNode()ed after prev node focus returns same tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node2);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree1,
|
|
);
|
|
});
|
|
|
|
test("registered node focusNode()ed after prev node focus diff tree returns new node's tree", function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree2,
|
|
);
|
|
});
|
|
|
|
test("registered tree root focusNode()ed after prev node focus diff tree returns new node's tree", function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(
|
|
this.testFocusableTree2.getRootFocusableNode(),
|
|
);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree2,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focusTree()ed with no prev focus returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('unregistered tree focusNode()ed with no prev focus returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('unregistered tree focusNode()ed with prev node prior focused returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Since the more recent tree was removed, there's no tree currently focused.
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('unregistered tree focusNode()ed with prev node recently focused returns new tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Since the most recent tree still exists, it still has focus.
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree2,
|
|
);
|
|
});
|
|
|
|
test('nested tree focusTree()ed with no prev focus returns nested tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
|
|
this.focusManager.focusTree(this.testFocusableNestedTree4);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableNestedTree4,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focusNode()ed with no prev focus returns nested tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
|
|
this.focusManager.focusNode(this.testFocusableNestedTree4Node1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableNestedTree4,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focusNode()ed after parent focused returns nested tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableNestedTree4Node1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableNestedTree4,
|
|
);
|
|
});
|
|
});
|
|
suite('getFocusedNode()', function () {
|
|
test('registered tree focusTree()ed no prev focus returns root node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableTree1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree1.getRootFocusableNode(),
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed prev node focused returns original node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableTree1);
|
|
|
|
// The original node retains focus since the tree already holds focus (per focusTree's
|
|
// contract).
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree1Node1,
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed diff tree prev focused returns new root node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableTree2);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree2.getRootFocusableNode(),
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed diff tree node prev focused returns new root node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableTree2);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree2.getRootFocusableNode(),
|
|
);
|
|
});
|
|
|
|
test('registered root focusNode()ed no prev focus returns root node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusNode(
|
|
this.testFocusableTree1.getRootFocusableNode(),
|
|
);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree1.getRootFocusableNode(),
|
|
);
|
|
});
|
|
|
|
test('registered node focusNode()ed no prev focus returns node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree1Node1,
|
|
);
|
|
});
|
|
|
|
test('registered subnode focusNode()ed no prev focus returns subnode', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1Child1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree1Node1Child1,
|
|
);
|
|
});
|
|
|
|
test('registered node focusNode()ed after prev node focus returns new node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node2);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree1Node2,
|
|
);
|
|
});
|
|
|
|
test('registered node focusNode()ed after prev node focus diff tree returns new node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree2Node1,
|
|
);
|
|
});
|
|
|
|
test('registered tree root focusNode()ed after prev node focus diff tree returns new root', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(
|
|
this.testFocusableTree2.getRootFocusableNode(),
|
|
);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree2.getRootFocusableNode(),
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focusTree()ed with no prev focus returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('unregistered tree focusNode()ed with no prev focus returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('unregistered tree focusNode()ed with prev node prior focused returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Since the more recent tree was removed, there's no tree currently focused.
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('unregistered tree focusNode()ed with prev node recently focused returns new node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Since the most recent tree still exists, it still has focus.
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree2Node1,
|
|
);
|
|
});
|
|
|
|
test('nested tree focusTree()ed with no prev focus returns nested root', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
|
|
this.focusManager.focusTree(this.testFocusableNestedTree4);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableNestedTree4.getRootFocusableNode(),
|
|
);
|
|
});
|
|
|
|
test('nested tree node focusNode()ed with no prev focus returns focused node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
|
|
this.focusManager.focusNode(this.testFocusableNestedTree4Node1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableNestedTree4Node1,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focusNode()ed after parent focused returns focused node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableNestedTree4Node1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableNestedTree4Node1,
|
|
);
|
|
});
|
|
|
|
test('deletion after focusNode() returns null', function () {
|
|
const rootElem = document.createElement('div');
|
|
const nodeElem = document.createElement('div');
|
|
rootElem.setAttribute('id', 'focusRoot');
|
|
rootElem.setAttribute('tabindex', '-1');
|
|
nodeElem.setAttribute('id', 'focusNode');
|
|
nodeElem.setAttribute('tabindex', '-1');
|
|
nodeElem.textContent = 'Focusable node';
|
|
rootElem.appendChild(nodeElem);
|
|
document.body.appendChild(rootElem);
|
|
const root = this.createFocusableTree('focusRoot');
|
|
const node = this.createFocusableNode(root, 'focusNode');
|
|
this.focusManager.registerTree(root);
|
|
this.focusManager.focusNode(node);
|
|
|
|
node.getFocusableElement().remove();
|
|
|
|
assert.notStrictEqual(this.focusManager.getFocusedNode(), node);
|
|
rootElem.remove(); // Cleanup.
|
|
});
|
|
});
|
|
suite('CSS classes', function () {
|
|
test('registered tree focusTree()ed no prev focus root elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableTree1);
|
|
|
|
const rootElem = this.testFocusableTree1
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed prev node focused original elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableTree1);
|
|
|
|
// The original node retains active focus since the tree already holds focus (per
|
|
// focusTree's contract).
|
|
const nodeElem = this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed diff tree prev focused new root elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableTree2);
|
|
|
|
const rootElem = this.testFocusableTree2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed diff tree node prev focused new root elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableTree2);
|
|
|
|
const rootElem = this.testFocusableTree2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered root focusNode()ed no prev focus returns root elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusNode(
|
|
this.testFocusableTree1.getRootFocusableNode(),
|
|
);
|
|
|
|
const rootElem = this.testFocusableTree1
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focusNode()ed no prev focus node elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
const nodeElem = this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focusNode()ed after prev node focus same tree old node elem has no focus property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node2);
|
|
|
|
const prevNodeElem = this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focusNode()ed after prev node focus same tree new node elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node2);
|
|
|
|
const newNodeElem = this.testFocusableTree1Node2.getFocusableElement();
|
|
assert.includesClass(
|
|
newNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
newNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focusNode()ed after prev node focus diff tree old node elem has passive property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
const prevNodeElem = this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focusNode()ed after prev node focus diff tree new node elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
const newNodeElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
newNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
newNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered tree root focusNode()ed after prev node focus diff tree new root has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.focusNode(
|
|
this.testFocusableTree2.getRootFocusableNode(),
|
|
);
|
|
|
|
const rootElem = this.testFocusableTree2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focusTree()ed with no prev focus removes focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusTree(this.testFocusableTree1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Since the tree was unregistered it no longer has focus indicators.
|
|
const rootElem = this.testFocusableTree1
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focusNode()ed with no prev focus removes focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Since the tree was unregistered it no longer has focus indicators.
|
|
const nodeElem = this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focusNode()ed with prev node prior removes focus from removed tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Since the tree was unregistered it no longer has focus indicators. However, the old node
|
|
// should still have passive indication.
|
|
const otherNodeElem =
|
|
this.testFocusableTree2Node1.getFocusableElement();
|
|
const removedNodeElem =
|
|
this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focusNode()ed with prev node recently removes focus from removed tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Since the tree was unregistered it no longer has focus indicators. However, the new node
|
|
// should still have active indication.
|
|
const otherNodeElem =
|
|
this.testFocusableTree2Node1.getFocusableElement();
|
|
const removedNodeElem =
|
|
this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('focusNode() multiple nodes in same tree with switches ensure passive focus has gone', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node2);
|
|
|
|
// When switching back to the first tree, ensure the original passive node is no longer
|
|
// passive now that the new node is active.
|
|
const node1 = this.testFocusableTree1Node1.getFocusableElement();
|
|
const node2 = this.testFocusableTree1Node2.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
node1.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
node2.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed other tree node passively focused tree node now has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableTree1);
|
|
|
|
// The original node in the tree should be moved from passive to active focus per the
|
|
// contract of focusTree). Also, the root of the tree should have no focus indication.
|
|
const nodeElem = this.testFocusableTree1Node1.getFocusableElement();
|
|
const rootElem = this.testFocusableTree1
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('focus on root, node in diff tree, then node in first tree; root should have focus gone', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusTree(this.testFocusableTree1);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
const nodeElem = this.testFocusableTree1Node1.getFocusableElement();
|
|
const rootElem = this.testFocusableTree1
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('nested tree focusTree()ed with no prev root has active focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
|
|
this.focusManager.focusTree(this.testFocusableNestedTree4);
|
|
|
|
const rootElem = this.testFocusableNestedTree4
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focusNode()ed with no prev focus node has active focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
|
|
this.focusManager.focusNode(this.testFocusableNestedTree4Node1);
|
|
|
|
const nodeElem =
|
|
this.testFocusableNestedTree4Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focusNode()ed after parent focused prev has passive node has active', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableNestedTree4Node1);
|
|
|
|
const prevNodeElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
const currNodeElem =
|
|
this.testFocusableNestedTree4Node1.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
currNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
suite('DOM focus() switching in HTML tree', function () {
|
|
suite('getFocusedTree()', function () {
|
|
test('registered root focus()ed no prev focus returns tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableTree1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree1,
|
|
);
|
|
});
|
|
|
|
test("registered node focus()ed no prev focus returns node's tree", function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree1,
|
|
);
|
|
});
|
|
|
|
test("registered subnode focus()ed no prev focus returns node's tree", function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1.node1.child1').tabIndex =
|
|
-1;
|
|
|
|
document.getElementById('testFocusableTree1.node1.child1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree1,
|
|
);
|
|
});
|
|
|
|
test('registered node focus()ed after prev node focus returns same tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node2').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
document.getElementById('testFocusableTree1.node2').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree1,
|
|
);
|
|
});
|
|
|
|
test("registered node focus()ed after prev node focus diff tree returns new node's tree", function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree2,
|
|
);
|
|
});
|
|
|
|
test("registered tree root focus()ed after prev node focus diff tree returns new node's tree", function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
document.getElementById('testFocusableTree2').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree2,
|
|
);
|
|
});
|
|
|
|
test("non-registered node subelement focus()ed returns node's tree", function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById(
|
|
'testFocusableTree1.node2.unregisteredChild1',
|
|
).tabIndex = -1;
|
|
|
|
document
|
|
.getElementById('testFocusableTree1.node2.unregisteredChild1')
|
|
.focus();
|
|
|
|
// The tree of the unregistered child element should take focus.
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree1,
|
|
);
|
|
});
|
|
|
|
test('non-registered tree focus()ed returns null', function () {
|
|
document.getElementById('testUnregisteredFocusableTree3').tabIndex = -1;
|
|
|
|
document.getElementById('testUnregisteredFocusableTree3').focus();
|
|
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('non-registered tree node focus()ed returns null', function () {
|
|
document.getElementById(
|
|
'testUnregisteredFocusableTree3.node1',
|
|
).tabIndex = -1;
|
|
|
|
document.getElementById('testUnregisteredFocusableTree3.node1').focus();
|
|
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('non-registered tree node focus()ed after registered node focused returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById(
|
|
'testUnregisteredFocusableTree3.node1',
|
|
).tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
document.getElementById('testUnregisteredFocusableTree3.node1').focus();
|
|
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('unfocusable element focus()ed after registered node focused returns original tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
document.getElementById('testUnfocusableElement').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree1,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focus()ed with no prev focus returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('unregistered tree focus()ed with no prev focus returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('unregistered tree focus()ed with prev node prior focused returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Since the more recent tree was removed, there's no tree currently focused.
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('unregistered tree focus()ed with prev node recently focused returns new tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Since the most recent tree still exists, it still has focus.
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree2,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focus()ed with prev node after unregistering returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
// Attempting to focus a now removed tree should result in nothing being
|
|
// focused since the removed tree can have DOM focus, but that focus is
|
|
// ignored by FocusManager.
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('nested tree focusTree()ed with no prev focus returns nested tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
document.getElementById('testFocusableNestedTree4').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableNestedTree4').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableNestedTree4,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focusNode()ed with no prev focus returns nested tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
document.getElementById('testFocusableNestedTree4.node1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableNestedTree4.node1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableNestedTree4,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focusNode()ed after parent focused returns nested tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableNestedTree4.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
document.getElementById('testFocusableNestedTree4.node1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableNestedTree4,
|
|
);
|
|
});
|
|
});
|
|
suite('getFocusedNode()', function () {
|
|
test('registered root focus()ed no prev focus returns root node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableTree1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree1.getRootFocusableNode(),
|
|
);
|
|
});
|
|
|
|
test('registered node focus()ed no prev focus returns node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree1Node1,
|
|
);
|
|
});
|
|
|
|
test('registered subnode focus()ed no prev focus returns subnode', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1.node1.child1').tabIndex =
|
|
-1;
|
|
|
|
document.getElementById('testFocusableTree1.node1.child1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree1Node1Child1,
|
|
);
|
|
});
|
|
|
|
test('registered node focus()ed after prev node focus returns new node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node2').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
document.getElementById('testFocusableTree1.node2').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree1Node2,
|
|
);
|
|
});
|
|
|
|
test('registered node focus()ed after prev node focus diff tree returns new node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree2Node1,
|
|
);
|
|
});
|
|
|
|
test('registered tree root focus()ed after prev node focus diff tree returns new root', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
document.getElementById('testFocusableTree2').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree2.getRootFocusableNode(),
|
|
);
|
|
});
|
|
|
|
test('non-registered node subelement focus()ed returns nearest node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById(
|
|
'testFocusableTree1.node2.unregisteredChild1',
|
|
).tabIndex = -1;
|
|
|
|
document
|
|
.getElementById('testFocusableTree1.node2.unregisteredChild1')
|
|
.focus();
|
|
|
|
// The nearest node of the unregistered child element should take focus.
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree1Node2,
|
|
);
|
|
});
|
|
|
|
test('non-registered tree focus()ed returns null', function () {
|
|
document.getElementById('testUnregisteredFocusableTree3').tabIndex = -1;
|
|
|
|
document.getElementById('testUnregisteredFocusableTree3').focus();
|
|
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('non-registered tree node focus()ed returns null', function () {
|
|
document.getElementById(
|
|
'testUnregisteredFocusableTree3.node1',
|
|
).tabIndex = -1;
|
|
|
|
document.getElementById('testUnregisteredFocusableTree3.node1').focus();
|
|
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('non-registered tree node focus()ed after registered node focused returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById(
|
|
'testUnregisteredFocusableTree3.node1',
|
|
).tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
document.getElementById('testUnregisteredFocusableTree3.node1').focus();
|
|
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('unfocusable element focus()ed after registered node focused returns original node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
document.getElementById('testUnfocusableElement').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree1Node1,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focus()ed with no prev focus returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('unregistered tree focus()ed with no prev focus returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('unregistered tree focus()ed with prev node prior focused returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Since the more recent tree was removed, there's no tree currently focused.
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('unregistered tree focus()ed with prev node recently focused returns new node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Since the most recent tree still exists, it still has focus.
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree2Node1,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focus()ed with prev node after unregistering returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
// Attempting to focus a now removed tree should result in nothing being
|
|
// focused since the removed tree can have DOM focus, but that focus is
|
|
// ignored by FocusManager.
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('nested tree focus()ed with no prev focus returns nested root', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
document.getElementById('testFocusableNestedTree4').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableNestedTree4').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableNestedTree4.getRootFocusableNode(),
|
|
);
|
|
});
|
|
|
|
test('nested tree node focus()ed with no prev focus returns focused node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
document.getElementById('testFocusableNestedTree4.node1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableNestedTree4.node1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableNestedTree4Node1,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focus()ed after parent focused returns focused node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableNestedTree4.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
document.getElementById('testFocusableNestedTree4.node1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableNestedTree4Node1,
|
|
);
|
|
});
|
|
|
|
test('deletion after focus() returns null', function () {
|
|
const rootElem = document.createElement('div');
|
|
const nodeElem = document.createElement('div');
|
|
rootElem.setAttribute('id', 'focusRoot');
|
|
rootElem.setAttribute('tabindex', '-1');
|
|
nodeElem.setAttribute('id', 'focusNode');
|
|
nodeElem.setAttribute('tabindex', '-1');
|
|
nodeElem.textContent = 'Focusable node';
|
|
rootElem.appendChild(nodeElem);
|
|
document.body.appendChild(rootElem);
|
|
const root = this.createFocusableTree('focusRoot');
|
|
const node = this.createFocusableNode(root, 'focusNode');
|
|
this.focusManager.registerTree(root);
|
|
document.getElementById('focusNode').tabIndex = -1;
|
|
document.getElementById('focusNode').focus();
|
|
|
|
node.getFocusableElement().remove();
|
|
|
|
assert.notStrictEqual(this.focusManager.getFocusedNode(), node);
|
|
rootElem.remove(); // Cleanup.
|
|
});
|
|
|
|
test('after focus() after trying to focusNode() an unfocusable node updates returns focus()ed node', function () {
|
|
this.testFocusableTree1Node1.canBeFocused = () => false;
|
|
document.getElementById('testFocusableTree1.node2').tabIndex = -1;
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
document.getElementById('testFocusableTree1.node2').focus();
|
|
|
|
// focus()ing a new node should overwrite a failed attempt to focusNode() an unfocusable
|
|
// node. This verifies that DOM focus syncing is properly reenabled by FocusManager.
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree1Node2,
|
|
);
|
|
});
|
|
|
|
test('after focus() after trying to focusNode() the same node twice returns focus()ed node', function () {
|
|
document.getElementById('testFocusableTree1.node2').tabIndex = -1;
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
// Intentionally try to focus the same node twice.
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
this.focusManager.focusNode(this.testFocusableTree1Node1);
|
|
|
|
document.getElementById('testFocusableTree1.node2').focus();
|
|
|
|
// focus()ing a new node should overwrite a failed attempt to focusNode() the same node
|
|
// twice. This verifies that DOM focus syncing is properly reenabled by FocusManager.
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree1Node2,
|
|
);
|
|
});
|
|
});
|
|
suite('CSS classes', function () {
|
|
test('registered root focus()ed no prev focus returns root elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableTree1').focus();
|
|
|
|
const rootElem = this.testFocusableTree1
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focus()ed no prev focus node elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
const nodeElem = this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focus()ed after prev node focus same tree old node elem has no focus property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node2').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
document.getElementById('testFocusableTree1.node2').focus();
|
|
|
|
const prevNodeElem = this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focus()ed after prev node focus same tree new node elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node2').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
document.getElementById('testFocusableTree1.node2').focus();
|
|
|
|
const newNodeElem = this.testFocusableTree1Node2.getFocusableElement();
|
|
assert.includesClass(
|
|
newNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
newNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focus()ed after prev node focus diff tree old node elem has passive property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
const prevNodeElem = this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focus()ed after prev node focus diff tree new node elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
const newNodeElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
newNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
newNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered tree root focus()ed after prev node focus diff tree new root has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
document.getElementById('testFocusableTree2').focus();
|
|
|
|
const rootElem = this.testFocusableTree2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('non-registered node subelement focus()ed nearest node has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById(
|
|
'testFocusableTree1.node2.unregisteredChild1',
|
|
).tabIndex = -1;
|
|
|
|
document
|
|
.getElementById('testFocusableTree1.node2.unregisteredChild1')
|
|
.focus();
|
|
|
|
// The nearest node of the unregistered child element should be actively focused.
|
|
const nodeElem = this.testFocusableTree1Node2.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('non-registered tree focus()ed has no focus', function () {
|
|
document.getElementById('testUnregisteredFocusableTree3').tabIndex = -1;
|
|
|
|
document.getElementById('testUnregisteredFocusableTree3').focus();
|
|
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
const rootElem = document.getElementById(
|
|
'testUnregisteredFocusableTree3',
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('non-registered tree node focus()ed has no focus', function () {
|
|
document.getElementById(
|
|
'testUnregisteredFocusableTree3.node1',
|
|
).tabIndex = -1;
|
|
|
|
document.getElementById('testUnregisteredFocusableTree3.node1').focus();
|
|
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
const nodeElem = document.getElementById(
|
|
'testUnregisteredFocusableTree3.node1',
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unfocsable element focus()ed after registered node focused original node has active focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
document.getElementById('testUnfocusableElement').focus();
|
|
|
|
// The original node should be unchanged, and the unregistered node should not have any
|
|
// focus indicators.
|
|
const nodeElem = document.getElementById('testFocusableTree1.node1');
|
|
const attemptedNewNodeElem = document.getElementById(
|
|
'testUnfocusableElement',
|
|
);
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
attemptedNewNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
attemptedNewNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focus()ed with no prev focus removes focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Since the tree was unregistered it no longer has focus indicators.
|
|
const rootElem = this.testFocusableTree1
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focus()ed with no prev focus removes focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Since the tree was unregistered it no longer has focus indicators.
|
|
const nodeElem = this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focus()ed with prev node prior removes focus from removed tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Since the tree was unregistered it no longer has focus indicators. However, the old node
|
|
// should still have passive indication.
|
|
const otherNodeElem =
|
|
this.testFocusableTree2Node1.getFocusableElement();
|
|
const removedNodeElem =
|
|
this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focus()ed with prev node recently removes focus from removed tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
// Since the tree was unregistered it no longer has focus indicators. However, the new node
|
|
// should still have active indication.
|
|
const otherNodeElem =
|
|
this.testFocusableTree2Node1.getFocusableElement();
|
|
const removedNodeElem =
|
|
this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focus()ed with prev node after unregistering removes active indicator', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
this.focusManager.unregisterTree(this.testFocusableTree1);
|
|
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
// Attempting to focus a now removed tree should remove active.
|
|
const otherNodeElem =
|
|
this.testFocusableTree2Node1.getFocusableElement();
|
|
const removedNodeElem =
|
|
this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('focus() multiple nodes in same tree with switches ensure passive focus has gone', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node2').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
document.getElementById('testFocusableTree1.node2').focus();
|
|
|
|
// When switching back to the first tree, ensure the original passive node is no longer
|
|
// passive now that the new node is active.
|
|
const node1 = this.testFocusableTree1Node1.getFocusableElement();
|
|
const node2 = this.testFocusableTree1Node2.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
node1.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
node2.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered tree focus()ed other tree node passively focused tree node now has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
document.getElementById('testFocusableTree1').focus();
|
|
|
|
// Directly refocusing a tree's root should have functional parity with focusTree(). That
|
|
// means the tree's previous node should now have active focus again and its root should
|
|
// have no focus indication.
|
|
const rootElem = this.testFocusableTree1
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
const nodeElem = this.testFocusableTree1Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('focus on root, node in diff tree, then node in first tree; root should have focus gone', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree1);
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableTree1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree1').focus();
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
document.getElementById('testFocusableTree1.node1').focus();
|
|
|
|
const nodeElem = this.testFocusableTree1Node1.getFocusableElement();
|
|
const rootElem = this.testFocusableTree1
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('nested tree focus()ed with no prev root has active focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
document.getElementById('testFocusableNestedTree4').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableNestedTree4').focus();
|
|
|
|
const rootElem = this.testFocusableNestedTree4
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focus()ed with no prev focus node has active focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
document.getElementById('testFocusableNestedTree4.node1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableNestedTree4.node1').focus();
|
|
|
|
const nodeElem =
|
|
this.testFocusableNestedTree4Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focus()ed after parent focused prev has passive node has active', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableNestedTree4.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
document.getElementById('testFocusableNestedTree4.node1').focus();
|
|
|
|
const prevNodeElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
const currNodeElem =
|
|
this.testFocusableNestedTree4Node1.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
currNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
/* Focus tests for SVG trees. */
|
|
|
|
suite('focus*() switching in SVG tree', function () {
|
|
suite('getFocusedTree()', function () {
|
|
test('registered tree focusTree()ed no prev focus returns tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableGroup1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup1,
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed prev node focused returns tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableGroup1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup1,
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed diff tree prev focused returns new tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusTree(this.testFocusableGroup1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableGroup2);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup2,
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed diff tree node prev focused returns new tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableGroup2);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup2,
|
|
);
|
|
});
|
|
|
|
test('registered root focusNode()ed no prev focus returns tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
|
|
this.focusManager.focusNode(
|
|
this.testFocusableGroup1.getRootFocusableNode(),
|
|
);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup1,
|
|
);
|
|
});
|
|
|
|
test("registered node focusNode()ed no prev focus returns node's tree", function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup1,
|
|
);
|
|
});
|
|
|
|
test("registered subnode focusNode()ed no prev focus returns node's tree", function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1Child1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup1,
|
|
);
|
|
});
|
|
|
|
test('registered node focusNode()ed after prev node focus returns same tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node2);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup1,
|
|
);
|
|
});
|
|
|
|
test("registered node focusNode()ed after prev node focus diff tree returns new node's tree", function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup2,
|
|
);
|
|
});
|
|
|
|
test("registered tree root focusNode()ed after prev node focus diff tree returns new node's tree", function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.focusNode(
|
|
this.testFocusableGroup2.getRootFocusableNode(),
|
|
);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup2,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focusTree()ed with no prev focus returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.focusTree(this.testFocusableGroup1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('unregistered tree focusNode()ed with no prev focus returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('unregistered tree focusNode()ed with prev node prior focused returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
// Since the more recent tree was removed, there's no tree currently focused.
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('unregistered tree focusNode()ed with prev node recently focused returns new tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
// Since the most recent tree still exists, it still has focus.
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup2,
|
|
);
|
|
});
|
|
|
|
test('nested tree focusTree()ed with no prev focus returns nested tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.registerTree(this.testFocusableNestedGroup4);
|
|
|
|
this.focusManager.focusTree(this.testFocusableNestedGroup4);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableNestedGroup4,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focusNode()ed with no prev focus returns nested tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.registerTree(this.testFocusableNestedGroup4);
|
|
|
|
this.focusManager.focusNode(this.testFocusableNestedGroup4Node1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableNestedGroup4,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focusNode()ed after parent focused returns nested tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.registerTree(this.testFocusableNestedGroup4);
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableNestedGroup4Node1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableNestedGroup4,
|
|
);
|
|
});
|
|
});
|
|
suite('getFocusedNode()', function () {
|
|
test('registered tree focusTree()ed no prev focus returns root node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableGroup1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup1.getRootFocusableNode(),
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed prev node focused returns original node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableGroup1);
|
|
|
|
// The original node retains focus since the tree already holds focus (per focusTree's
|
|
// contract).
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup1Node1,
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed diff tree prev focused returns new root node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusTree(this.testFocusableGroup1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableGroup2);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup2.getRootFocusableNode(),
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed diff tree node prev focused returns new root node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableGroup2);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup2.getRootFocusableNode(),
|
|
);
|
|
});
|
|
|
|
test('registered root focusNode()ed no prev focus returns root node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
|
|
this.focusManager.focusNode(
|
|
this.testFocusableGroup1.getRootFocusableNode(),
|
|
);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup1.getRootFocusableNode(),
|
|
);
|
|
});
|
|
|
|
test('registered node focusNode()ed no prev focus returns node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup1Node1,
|
|
);
|
|
});
|
|
|
|
test('registered subnode focusNode()ed no prev focus returns subnode', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1Child1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup1Node1Child1,
|
|
);
|
|
});
|
|
|
|
test('registered node focusNode()ed after prev node focus returns new node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node2);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup1Node2,
|
|
);
|
|
});
|
|
|
|
test('registered node focusNode()ed after prev node focus diff tree returns new node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup2Node1,
|
|
);
|
|
});
|
|
|
|
test('registered tree root focusNode()ed after prev node focus diff tree returns new root', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.focusNode(
|
|
this.testFocusableGroup2.getRootFocusableNode(),
|
|
);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup2.getRootFocusableNode(),
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focusTree()ed with no prev focus returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.focusTree(this.testFocusableGroup1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('unregistered tree focusNode()ed with no prev focus returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('unregistered tree focusNode()ed with prev node prior focused returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
// Since the more recent tree was removed, there's no tree currently focused.
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('unregistered tree focusNode()ed with prev node recently focused returns new node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
// Since the most recent tree still exists, it still has focus.
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup2Node1,
|
|
);
|
|
});
|
|
|
|
test('nested tree focusTree()ed with no prev focus returns nested root', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.registerTree(this.testFocusableNestedGroup4);
|
|
|
|
this.focusManager.focusTree(this.testFocusableNestedGroup4);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableNestedGroup4.getRootFocusableNode(),
|
|
);
|
|
});
|
|
|
|
test('nested tree node focusNode()ed with no prev focus returns focused node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.registerTree(this.testFocusableNestedGroup4);
|
|
|
|
this.focusManager.focusNode(this.testFocusableNestedGroup4Node1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableNestedGroup4Node1,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focusNode()ed after parent focused returns focused node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.registerTree(this.testFocusableNestedGroup4);
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableNestedGroup4Node1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableNestedGroup4Node1,
|
|
);
|
|
});
|
|
});
|
|
suite('CSS classes', function () {
|
|
test('registered tree focusTree()ed no prev focus root elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableGroup1);
|
|
|
|
const rootElem = this.testFocusableGroup1
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed prev node focused original elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableGroup1);
|
|
|
|
// The original node retains active focus since the tree already holds focus (per
|
|
// focusTree's contract).
|
|
const nodeElem = this.testFocusableGroup1Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed diff tree prev focused new root elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusTree(this.testFocusableGroup1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableGroup2);
|
|
|
|
const rootElem = this.testFocusableGroup2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed diff tree node prev focused new root elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableGroup2);
|
|
|
|
const rootElem = this.testFocusableGroup2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered root focusNode()ed no prev focus returns root elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
|
|
this.focusManager.focusNode(
|
|
this.testFocusableGroup1.getRootFocusableNode(),
|
|
);
|
|
|
|
const rootElem = this.testFocusableGroup1
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focusNode()ed no prev focus node elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
const nodeElem = this.testFocusableGroup1Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focusNode()ed after prev node focus same tree old node elem has no focus property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node2);
|
|
|
|
const prevNodeElem =
|
|
this.testFocusableGroup1Node1.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focusNode()ed after prev node focus same tree new node elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node2);
|
|
|
|
const newNodeElem = this.testFocusableGroup1Node2.getFocusableElement();
|
|
assert.includesClass(
|
|
newNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
newNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focusNode()ed after prev node focus diff tree old node elem has passive property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
const prevNodeElem =
|
|
this.testFocusableGroup1Node1.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focusNode()ed after prev node focus diff tree new node elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
const newNodeElem = this.testFocusableGroup2Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
newNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
newNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered tree root focusNode()ed after prev node focus diff tree new root has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.focusNode(
|
|
this.testFocusableGroup2.getRootFocusableNode(),
|
|
);
|
|
|
|
const rootElem = this.testFocusableGroup2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focusTree()ed with no prev focus removes focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.focusTree(this.testFocusableGroup1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
// Since the tree was unregistered it no longer has focus indicators.
|
|
const rootElem = this.testFocusableGroup1
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focusNode()ed with no prev focus removes focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
// Since the tree was unregistered it no longer has focus indicators.
|
|
const nodeElem = this.testFocusableGroup1Node1.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focusNode()ed with prev node prior removes focus from removed tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
// Since the tree was unregistered it no longer has focus indicators. However, the old node
|
|
// should still have passive indication.
|
|
const otherNodeElem =
|
|
this.testFocusableGroup2Node1.getFocusableElement();
|
|
const removedNodeElem =
|
|
this.testFocusableGroup1Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focusNode()ed with prev node recently removes focus from removed tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
// Since the tree was unregistered it no longer has focus indicators. However, the new node
|
|
// should still have active indication.
|
|
const otherNodeElem =
|
|
this.testFocusableGroup2Node1.getFocusableElement();
|
|
const removedNodeElem =
|
|
this.testFocusableGroup1Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('focusNode() multiple nodes in same tree with switches ensure passive focus has gone', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node2);
|
|
|
|
// When switching back to the first tree, ensure the original passive node is no longer
|
|
// passive now that the new node is active.
|
|
const node1 = this.testFocusableGroup1Node1.getFocusableElement();
|
|
const node2 = this.testFocusableGroup1Node2.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
node1.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
node2.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered tree focusTree()ed other tree node passively focused tree node now has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableGroup1);
|
|
|
|
// The original node in the tree should be moved from passive to active focus per the
|
|
// contract of focusTree). Also, the root of the tree should have no focus indication.
|
|
const nodeElem = this.testFocusableGroup1Node1.getFocusableElement();
|
|
const rootElem = this.testFocusableGroup1
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('focus on root, node in diff tree, then node in first tree; root should have focus gone', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusTree(this.testFocusableGroup1);
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
const nodeElem = this.testFocusableGroup1Node1.getFocusableElement();
|
|
const rootElem = this.testFocusableGroup1
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('nested tree focusTree()ed with no prev root has active focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.registerTree(this.testFocusableNestedGroup4);
|
|
|
|
this.focusManager.focusTree(this.testFocusableNestedGroup4);
|
|
|
|
const rootElem = this.testFocusableNestedGroup4
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focusNode()ed with no prev focus node has active focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.registerTree(this.testFocusableNestedGroup4);
|
|
|
|
this.focusManager.focusNode(this.testFocusableNestedGroup4Node1);
|
|
|
|
const nodeElem =
|
|
this.testFocusableNestedGroup4Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focusNode()ed after parent focused prev has passive node has active', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.registerTree(this.testFocusableNestedGroup4);
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableNestedGroup4Node1);
|
|
|
|
const prevNodeElem =
|
|
this.testFocusableGroup2Node1.getFocusableElement();
|
|
const currNodeElem =
|
|
this.testFocusableNestedGroup4Node1.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
currNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
suite('DOM focus() switching in SVG tree', function () {
|
|
suite('getFocusedTree()', function () {
|
|
test('registered root focus()ed no prev focus returns tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableGroup1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup1,
|
|
);
|
|
});
|
|
|
|
test("registered node focus()ed no prev focus returns node's tree", function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup1,
|
|
);
|
|
});
|
|
|
|
test("registered subnode focus()ed no prev focus returns node's tree", function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1.node1.child1').tabIndex =
|
|
-1;
|
|
|
|
document.getElementById('testFocusableGroup1.node1.child1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup1,
|
|
);
|
|
});
|
|
|
|
test('registered node focus()ed after prev node focus returns same tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node2').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
document.getElementById('testFocusableGroup1.node2').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup1,
|
|
);
|
|
});
|
|
|
|
test("registered node focus()ed after prev node focus diff tree returns new node's tree", function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup2,
|
|
);
|
|
});
|
|
|
|
test("registered tree root focus()ed after prev node focus diff tree returns new node's tree", function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
document.getElementById('testFocusableGroup2').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup2,
|
|
);
|
|
});
|
|
|
|
test("non-registered node subelement focus()ed returns node's tree", function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById(
|
|
'testFocusableGroup1.node2.unregisteredChild1',
|
|
).tabIndex = -1;
|
|
|
|
document
|
|
.getElementById('testFocusableGroup1.node2.unregisteredChild1')
|
|
.focus();
|
|
|
|
// The tree of the unregistered child element should take focus.
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup1,
|
|
);
|
|
});
|
|
|
|
test('non-registered tree focus()ed returns null', function () {
|
|
document.getElementById('testUnregisteredFocusableGroup3').tabIndex =
|
|
-1;
|
|
|
|
document.getElementById('testUnregisteredFocusableGroup3').focus();
|
|
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('non-registered tree node focus()ed returns null', function () {
|
|
document.getElementById(
|
|
'testUnregisteredFocusableGroup3.node1',
|
|
).tabIndex = -1;
|
|
|
|
document
|
|
.getElementById('testUnregisteredFocusableGroup3.node1')
|
|
.focus();
|
|
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('non-registered tree node focus()ed after registered node focused returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById(
|
|
'testUnregisteredFocusableGroup3.node1',
|
|
).tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
document
|
|
.getElementById('testUnregisteredFocusableGroup3.node1')
|
|
.focus();
|
|
|
|
// Attempting to focus a now removed tree should result in nothing being
|
|
// focused since the removed tree can have DOM focus, but that focus is
|
|
// ignored by FocusManager.
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('unregistered tree focus()ed with no prev focus returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('unregistered tree focus()ed with no prev focus returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('unregistered tree focus()ed with prev node prior focused returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
// Since the more recent tree was removed, there's no tree currently focused.
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('unregistered tree focus()ed with prev node recently focused returns new tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
// Since the most recent tree still exists, it still has focus.
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup2,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focus()ed with prev node after unregistering returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
// Attempting to focus a now removed tree should result in nothing being
|
|
// focused since the removed tree can have DOM focus, but that focus is
|
|
// ignored by FocusManager.
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
});
|
|
|
|
test('nested tree focusTree()ed with no prev focus returns nested tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.registerTree(this.testFocusableNestedGroup4);
|
|
document.getElementById('testFocusableNestedGroup4').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableNestedGroup4').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableNestedGroup4,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focusNode()ed with no prev focus returns nested tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.registerTree(this.testFocusableNestedGroup4);
|
|
document.getElementById('testFocusableNestedGroup4.node1').tabIndex =
|
|
-1;
|
|
|
|
document.getElementById('testFocusableNestedGroup4.node1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableNestedGroup4,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focusNode()ed after parent focused returns nested tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.registerTree(this.testFocusableNestedGroup4);
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableNestedGroup4.node1').tabIndex =
|
|
-1;
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
document.getElementById('testFocusableNestedGroup4.node1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableNestedGroup4,
|
|
);
|
|
});
|
|
});
|
|
suite('getFocusedNode()', function () {
|
|
test('registered root focus()ed no prev focus returns root node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableGroup1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup1.getRootFocusableNode(),
|
|
);
|
|
});
|
|
|
|
test('registered node focus()ed no prev focus returns node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup1Node1,
|
|
);
|
|
});
|
|
|
|
test('registered subnode focus()ed no prev focus returns subnode', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1.node1.child1').tabIndex =
|
|
-1;
|
|
|
|
document.getElementById('testFocusableGroup1.node1.child1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup1Node1Child1,
|
|
);
|
|
});
|
|
|
|
test('registered node focus()ed after prev node focus returns new node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node2').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
document.getElementById('testFocusableGroup1.node2').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup1Node2,
|
|
);
|
|
});
|
|
|
|
test('registered node focus()ed after prev node focus diff tree returns new node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup2Node1,
|
|
);
|
|
});
|
|
|
|
test('registered tree root focus()ed after prev node focus diff tree returns new root', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
document.getElementById('testFocusableGroup2').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup2.getRootFocusableNode(),
|
|
);
|
|
});
|
|
|
|
test('non-registered node subelement focus()ed returns nearest node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById(
|
|
'testFocusableGroup1.node2.unregisteredChild1',
|
|
).tabIndex = -1;
|
|
|
|
document
|
|
.getElementById('testFocusableGroup1.node2.unregisteredChild1')
|
|
.focus();
|
|
|
|
// The nearest node of the unregistered child element should take focus.
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup1Node2,
|
|
);
|
|
});
|
|
|
|
test('non-registered tree focus()ed returns null', function () {
|
|
document.getElementById('testUnregisteredFocusableGroup3').tabIndex =
|
|
-1;
|
|
|
|
document.getElementById('testUnregisteredFocusableGroup3').focus();
|
|
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('non-registered tree node focus()ed returns null', function () {
|
|
document.getElementById(
|
|
'testUnregisteredFocusableGroup3.node1',
|
|
).tabIndex = -1;
|
|
|
|
document
|
|
.getElementById('testUnregisteredFocusableGroup3.node1')
|
|
.focus();
|
|
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('non-registered tree node focus()ed after registered node focused returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById(
|
|
'testUnregisteredFocusableGroup3.node1',
|
|
).tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
document
|
|
.getElementById('testUnregisteredFocusableGroup3.node1')
|
|
.focus();
|
|
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('unfocusable element focus()ed after registered node focused returns original node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
document.getElementById('testUnfocusableElement').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup1Node1,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focus()ed with no prev focus returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('unregistered tree focus()ed with no prev focus returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('unregistered tree focus()ed with prev node prior focused returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
// Since the more recent tree was removed, there's no tree currently focused.
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('unregistered tree focus()ed with prev node recently focused returns new node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
// Since the most recent tree still exists, it still has focus.
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup2Node1,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focus()ed with prev node after unregistering returns null', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
// Attempting to focus a now removed tree should result in nothing being
|
|
// focused since the removed tree can have DOM focus, but that focus is
|
|
// ignored by FocusManager.
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
});
|
|
|
|
test('nested tree focus()ed with no prev focus returns nested root', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.registerTree(this.testFocusableNestedGroup4);
|
|
document.getElementById('testFocusableNestedGroup4').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableNestedGroup4').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableNestedGroup4.getRootFocusableNode(),
|
|
);
|
|
});
|
|
|
|
test('nested tree node focus()ed with no prev focus returns focused node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.registerTree(this.testFocusableNestedGroup4);
|
|
document.getElementById('testFocusableNestedGroup4.node1').tabIndex =
|
|
-1;
|
|
|
|
document.getElementById('testFocusableNestedGroup4.node1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableNestedGroup4Node1,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focus()ed after parent focused returns focused node', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.registerTree(this.testFocusableNestedGroup4);
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableNestedGroup4.node1').tabIndex =
|
|
-1;
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
document.getElementById('testFocusableNestedGroup4.node1').focus();
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableNestedGroup4Node1,
|
|
);
|
|
});
|
|
|
|
test('after focus() after trying to focusNode() an unfocusable node updates returns focus()ed node', function () {
|
|
this.testFocusableGroup1Node1.canBeFocused = () => false;
|
|
document.getElementById('testFocusableGroup1.node2').tabIndex = -1;
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
document.getElementById('testFocusableGroup1.node2').focus();
|
|
|
|
// focus()ing a new node should overwrite a failed attempt to focusNode() an unfocusable
|
|
// node. This verifies that DOM focus syncing is properly reenabled by FocusManager.
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup1Node2,
|
|
);
|
|
});
|
|
|
|
test('after focus() after trying to focusNode() the same node twice returns focus()ed node', function () {
|
|
document.getElementById('testFocusableGroup1.node2').tabIndex = -1;
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
// Intentionally try to focus the same node twice.
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
this.focusManager.focusNode(this.testFocusableGroup1Node1);
|
|
|
|
document.getElementById('testFocusableGroup1.node2').focus();
|
|
|
|
// focus()ing a new node should overwrite a failed attempt to focusNode() the same node
|
|
// twice. This verifies that DOM focus syncing is properly reenabled by FocusManager.
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup1Node2,
|
|
);
|
|
});
|
|
});
|
|
suite('CSS classes', function () {
|
|
test('registered root focus()ed no prev focus returns root elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableGroup1').focus();
|
|
|
|
const rootElem = this.testFocusableGroup1
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focus()ed no prev focus node elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
const nodeElem = this.testFocusableGroup1Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focus()ed after prev node focus same tree old node elem has no focus property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node2').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
document.getElementById('testFocusableGroup1.node2').focus();
|
|
|
|
const prevNodeElem =
|
|
this.testFocusableGroup1Node1.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focus()ed after prev node focus same tree new node elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node2').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
document.getElementById('testFocusableGroup1.node2').focus();
|
|
|
|
const newNodeElem = this.testFocusableGroup1Node2.getFocusableElement();
|
|
assert.includesClass(
|
|
newNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
newNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focus()ed after prev node focus diff tree old node elem has passive property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
const prevNodeElem =
|
|
this.testFocusableGroup1Node1.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered node focus()ed after prev node focus diff tree new node elem has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
const newNodeElem = this.testFocusableGroup2Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
newNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
newNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered tree root focus()ed after prev node focus diff tree new root has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
document.getElementById('testFocusableGroup2').focus();
|
|
|
|
const rootElem = this.testFocusableGroup2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('non-registered node subelement focus()ed nearest node has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById(
|
|
'testFocusableGroup1.node2.unregisteredChild1',
|
|
).tabIndex = -1;
|
|
|
|
document
|
|
.getElementById('testFocusableGroup1.node2.unregisteredChild1')
|
|
.focus();
|
|
|
|
// The nearest node of the unregistered child element should be actively focused.
|
|
const nodeElem = this.testFocusableGroup1Node2.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('non-registered tree focus()ed has no focus', function () {
|
|
document.getElementById('testUnregisteredFocusableGroup3').tabIndex =
|
|
-1;
|
|
|
|
document.getElementById('testUnregisteredFocusableGroup3').focus();
|
|
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
const rootElem = document.getElementById(
|
|
'testUnregisteredFocusableGroup3',
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('non-registered tree node focus()ed has no focus', function () {
|
|
document.getElementById(
|
|
'testUnregisteredFocusableGroup3.node1',
|
|
).tabIndex = -1;
|
|
|
|
document
|
|
.getElementById('testUnregisteredFocusableGroup3.node1')
|
|
.focus();
|
|
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
const nodeElem = document.getElementById(
|
|
'testUnregisteredFocusableGroup3.node1',
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unfocusable element focus()ed after registered node focused original node has active focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
document.getElementById('testUnfocusableElement').focus();
|
|
|
|
// The original node should be unchanged, and the unregistered node should not have any
|
|
// focus indicators.
|
|
const nodeElem = document.getElementById('testFocusableGroup1.node1');
|
|
const attemptedNewNodeElem = document.getElementById(
|
|
'testUnfocusableElement',
|
|
);
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
attemptedNewNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
attemptedNewNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focus()ed with no prev focus removes focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
// Since the tree was unregistered it no longer has focus indicators.
|
|
const rootElem = this.testFocusableGroup1
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focus()ed with no prev focus removes focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
// Since the tree was unregistered it no longer has focus indicators.
|
|
const nodeElem = this.testFocusableGroup1Node1.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focus()ed with prev node prior removes focus from removed tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
// Since the tree was unregistered it no longer has focus indicators. However, the old node
|
|
// should still have passive indication.
|
|
const otherNodeElem =
|
|
this.testFocusableGroup2Node1.getFocusableElement();
|
|
const removedNodeElem =
|
|
this.testFocusableGroup1Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focus()ed with prev node recently removes focus from removed tree', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
// Since the tree was unregistered it no longer has focus indicators. However, the new node
|
|
// should still have active indication.
|
|
const otherNodeElem =
|
|
this.testFocusableGroup2Node1.getFocusableElement();
|
|
const removedNodeElem =
|
|
this.testFocusableGroup1Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('unregistered tree focus()ed with prev node after unregistering removes active indicator', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
this.focusManager.unregisterTree(this.testFocusableGroup1);
|
|
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
// Attempting to focus a now removed tree should remove active.
|
|
const otherNodeElem =
|
|
this.testFocusableGroup2Node1.getFocusableElement();
|
|
const removedNodeElem =
|
|
this.testFocusableGroup1Node1.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
otherNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
removedNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('focus() multiple nodes in same tree with switches ensure passive focus has gone', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node2').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
document.getElementById('testFocusableGroup1.node2').focus();
|
|
|
|
// When switching back to the first tree, ensure the original passive node is no longer
|
|
// passive now that the new node is active.
|
|
const node1 = this.testFocusableGroup1Node1.getFocusableElement();
|
|
const node2 = this.testFocusableGroup1Node2.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
node1.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
node2.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('registered tree focus()ed other tree node passively focused tree node now has active property', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
document.getElementById('testFocusableGroup1').focus();
|
|
|
|
// Directly refocusing a tree's root should have functional parity with focusTree(). That
|
|
// means the tree's previous node should now have active focus again and its root should
|
|
// have no focus indication.
|
|
const rootElem = this.testFocusableGroup1
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
const nodeElem = this.testFocusableGroup1Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('focus on root, node in diff tree, then node in first tree; root should have focus gone', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup1);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup1').focus();
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
document.getElementById('testFocusableGroup1.node1').focus();
|
|
|
|
const nodeElem = this.testFocusableGroup1Node1.getFocusableElement();
|
|
const rootElem = this.testFocusableGroup1
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('nested tree focus()ed with no prev root has active focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.registerTree(this.testFocusableNestedGroup4);
|
|
document.getElementById('testFocusableNestedGroup4').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableNestedGroup4').focus();
|
|
|
|
const rootElem = this.testFocusableNestedGroup4
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focus()ed with no prev focus node has active focus', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.registerTree(this.testFocusableNestedGroup4);
|
|
document.getElementById('testFocusableNestedGroup4.node1').tabIndex =
|
|
-1;
|
|
|
|
document.getElementById('testFocusableNestedGroup4.node1').focus();
|
|
|
|
const nodeElem =
|
|
this.testFocusableNestedGroup4Node1.getFocusableElement();
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('nested tree node focus()ed after parent focused prev has passive node has active', function () {
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.registerTree(this.testFocusableNestedGroup4);
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableNestedGroup4.node1').tabIndex =
|
|
-1;
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
document.getElementById('testFocusableNestedGroup4.node1').focus();
|
|
|
|
const prevNodeElem =
|
|
this.testFocusableGroup2Node1.getFocusableElement();
|
|
const currNodeElem =
|
|
this.testFocusableNestedGroup4Node1.getFocusableElement();
|
|
assert.notIncludesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
currNodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currNodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
/* High-level focus/defocusing tests. */
|
|
suite('Defocusing and refocusing', function () {
|
|
test('Defocusing actively focused root HTML tree switches to passive highlight', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusTree(this.testFocusableTree2);
|
|
document.getElementById('testUnregisteredFocusableTree3').tabIndex = -1;
|
|
|
|
document.getElementById('testUnregisteredFocusableTree3').focus();
|
|
|
|
const rootNode = this.testFocusableTree2.getRootFocusableNode();
|
|
const rootElem = rootNode.getFocusableElement();
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('Defocusing actively focused HTML tree node switches to passive highlight', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
document.getElementById('testUnregisteredFocusableTree3').tabIndex = -1;
|
|
|
|
document.getElementById('testUnregisteredFocusableTree3').focus();
|
|
|
|
const nodeElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('Defocusing actively focused HTML subtree node switches to passive highlight', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
this.focusManager.focusNode(this.testFocusableNestedTree4Node1);
|
|
document.getElementById('testUnregisteredFocusableTree3').tabIndex = -1;
|
|
|
|
document.getElementById('testUnregisteredFocusableTree3').focus();
|
|
|
|
const nodeElem = this.testFocusableNestedTree4Node1.getFocusableElement();
|
|
assert.isNull(this.focusManager.getFocusedTree());
|
|
assert.isNull(this.focusManager.getFocusedNode());
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('Refocusing actively focused root HTML tree restores to active highlight', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusTree(this.testFocusableTree2);
|
|
document.getElementById('testUnregisteredFocusableTree3').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2').tabIndex = -1;
|
|
document.getElementById('testUnregisteredFocusableTree3').focus();
|
|
|
|
document.getElementById('testFocusableTree2').focus();
|
|
|
|
const rootNode = this.testFocusableTree2.getRootFocusableNode();
|
|
const rootElem = rootNode.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree2,
|
|
);
|
|
assert.strictEqual(this.focusManager.getFocusedNode(), rootNode);
|
|
assert.notIncludesClass(
|
|
rootElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('Refocusing actively focused HTML tree node restores to active highlight', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
document.getElementById('testUnregisteredFocusableTree3').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testUnregisteredFocusableTree3').focus();
|
|
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
const nodeElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree2,
|
|
);
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree2Node1,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('Refocusing actively focused HTML subtree node restores to active highlight', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableNestedTree4);
|
|
this.focusManager.focusNode(this.testFocusableNestedTree4Node1);
|
|
document.getElementById('testUnregisteredFocusableTree3').tabIndex = -1;
|
|
document.getElementById('testFocusableNestedTree4.node1').tabIndex = -1;
|
|
document.getElementById('testUnregisteredFocusableTree3').focus();
|
|
|
|
document.getElementById('testFocusableNestedTree4.node1').focus();
|
|
|
|
const nodeElem = this.testFocusableNestedTree4Node1.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableNestedTree4,
|
|
);
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableNestedTree4Node1,
|
|
);
|
|
assert.notIncludesClass(
|
|
nodeElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
});
|
|
|
|
/* Combined HTML/SVG tree focus tests. */
|
|
|
|
suite('HTML/SVG focus tree switching', function () {
|
|
suite('Focus HTML tree then SVG tree', function () {
|
|
test('HTML focusTree()ed then SVG focusTree()ed correctly updates getFocusedTree() and indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusTree(this.testFocusableTree2);
|
|
|
|
this.focusManager.focusTree(this.testFocusableGroup2);
|
|
|
|
const prevElem = this.testFocusableTree2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
const currElem = this.testFocusableGroup2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup2,
|
|
);
|
|
assert.strictEqual(document.activeElement, currElem);
|
|
assert.includesClass(
|
|
currElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('HTML focusTree()ed then SVG focusNode()ed correctly updates getFocusedNode() and indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusTree(this.testFocusableTree2);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
const prevElem = this.testFocusableTree2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
const currElem = this.testFocusableGroup2Node1.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup2Node1,
|
|
);
|
|
assert.strictEqual(document.activeElement, currElem);
|
|
assert.includesClass(
|
|
currElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('HTML focusTree()ed then SVG DOM focus()ed correctly updates getFocusedNode() and indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusTree(this.testFocusableTree2);
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
const prevElem = this.testFocusableTree2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
const currElem = this.testFocusableGroup2Node1.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup2Node1,
|
|
);
|
|
assert.strictEqual(document.activeElement, currElem);
|
|
assert.includesClass(
|
|
currElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('HTML focusNode()ed then SVG focusTree()ed correctly updates getFocusedTree() and indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableGroup2);
|
|
|
|
const prevElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
const currElem = this.testFocusableGroup2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup2,
|
|
);
|
|
assert.strictEqual(document.activeElement, currElem);
|
|
assert.includesClass(
|
|
currElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('HTML focusNode()ed then SVG focusNode()ed correctly updates getFocusedNode() and indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
const prevElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
const currElem = this.testFocusableGroup2Node1.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup2Node1,
|
|
);
|
|
assert.strictEqual(document.activeElement, currElem);
|
|
assert.includesClass(
|
|
currElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('HTML focusNode()ed then SVG DOM focus()ed correctly updates getFocusedNode() and indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
const prevElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
const currElem = this.testFocusableGroup2Node1.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup2Node1,
|
|
);
|
|
assert.strictEqual(document.activeElement, currElem);
|
|
assert.includesClass(
|
|
currElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('HTML DOM focus()ed then SVG focusTree()ed correctly updates getFocusedTree() and indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
this.focusManager.focusTree(this.testFocusableGroup2);
|
|
|
|
const prevElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
const currElem = this.testFocusableGroup2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup2,
|
|
);
|
|
assert.strictEqual(document.activeElement, currElem);
|
|
assert.includesClass(
|
|
currElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('HTML DOM focus()ed then SVG focusNode()ed correctly updates getFocusedNode() and indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
const prevElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
const currElem = this.testFocusableGroup2Node1.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup2Node1,
|
|
);
|
|
assert.strictEqual(document.activeElement, currElem);
|
|
assert.includesClass(
|
|
currElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('HTML DOM focus()ed then SVG DOM focus()ed correctly updates getFocusedNode() and indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
const prevElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
const currElem = this.testFocusableGroup2Node1.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup2Node1,
|
|
);
|
|
assert.strictEqual(document.activeElement, currElem);
|
|
assert.includesClass(
|
|
currElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
});
|
|
suite('Focus SVG tree then HTML tree', function () {
|
|
test('SVG focusTree()ed then HTML focusTree()ed correctly updates getFocusedTree() and indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusTree(this.testFocusableGroup2);
|
|
|
|
this.focusManager.focusTree(this.testFocusableTree2);
|
|
|
|
const prevElem = this.testFocusableGroup2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
const currElem = this.testFocusableTree2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree2,
|
|
);
|
|
assert.strictEqual(document.activeElement, currElem);
|
|
assert.includesClass(
|
|
currElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('SVG focusTree()ed then HTML focusNode()ed correctly updates getFocusedNode() and indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusTree(this.testFocusableGroup2);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
const prevElem = this.testFocusableGroup2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
const currElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree2Node1,
|
|
);
|
|
assert.strictEqual(document.activeElement, currElem);
|
|
assert.includesClass(
|
|
currElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('SVG focusTree()ed then HTML DOM focus()ed correctly updates getFocusedNode() and indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
const prevElem = this.testFocusableGroup2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
const currElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree2Node1,
|
|
);
|
|
assert.strictEqual(document.activeElement, currElem);
|
|
assert.includesClass(
|
|
currElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('SVG focusNode()ed then HTML focusTree()ed correctly updates getFocusedTree() and indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
this.focusManager.focusTree(this.testFocusableTree2);
|
|
|
|
const prevElem = this.testFocusableGroup2Node1.getFocusableElement();
|
|
const currElem = this.testFocusableTree2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree2,
|
|
);
|
|
assert.strictEqual(document.activeElement, currElem);
|
|
assert.includesClass(
|
|
currElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('SVG focusNode()ed then HTML focusNode()ed correctly updates getFocusedNode() and indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
const prevElem = this.testFocusableGroup2Node1.getFocusableElement();
|
|
const currElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree2Node1,
|
|
);
|
|
assert.strictEqual(document.activeElement, currElem);
|
|
assert.includesClass(
|
|
currElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('SVG focusNode()ed then HTML DOM focus()ed correctly updates getFocusedNode() and indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
const prevElem = this.testFocusableGroup2Node1.getFocusableElement();
|
|
const currElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree2Node1,
|
|
);
|
|
assert.strictEqual(document.activeElement, currElem);
|
|
assert.includesClass(
|
|
currElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('SVG DOM focus()ed then HTML focusTree()ed correctly updates getFocusedTree() and indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
this.focusManager.focusTree(this.testFocusableTree2);
|
|
|
|
const prevElem = this.testFocusableGroup2Node1.getFocusableElement();
|
|
const currElem = this.testFocusableTree2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableTree2,
|
|
);
|
|
assert.strictEqual(document.activeElement, currElem);
|
|
assert.includesClass(
|
|
currElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('SVG DOM focus()ed then HTML focusNode()ed correctly updates getFocusedNode() and indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
const prevElem = this.testFocusableGroup2Node1.getFocusableElement();
|
|
const currElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree2Node1,
|
|
);
|
|
assert.strictEqual(document.activeElement, currElem);
|
|
assert.includesClass(
|
|
currElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('SVG DOM focus()ed then HTML DOM focus()ed correctly updates getFocusedNode() and indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableTree2.node1').tabIndex = -1;
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
document.getElementById('testFocusableTree2.node1').focus();
|
|
|
|
const prevElem = this.testFocusableGroup2Node1.getFocusableElement();
|
|
const currElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree2Node1,
|
|
);
|
|
assert.strictEqual(document.activeElement, currElem);
|
|
assert.includesClass(
|
|
currElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
currElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.notIncludesClass(
|
|
prevElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.includesClass(
|
|
prevElem.classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
/* Ephemeral focus tests. */
|
|
|
|
suite('takeEphemeralFocus()', function () {
|
|
setup(function () {
|
|
// Ensure ephemeral-specific elements are focusable.
|
|
document.getElementById('nonTreeElementForEphemeralFocus').tabIndex = -1;
|
|
document.getElementById('nonTreeGroupForEphemeralFocus').tabIndex = -1;
|
|
});
|
|
teardown(function () {
|
|
// Ensure ephemeral-specific elements have their tab indexes reset for a clean state.
|
|
document
|
|
.getElementById('nonTreeElementForEphemeralFocus')
|
|
.removeAttribute('tabindex');
|
|
document
|
|
.getElementById('nonTreeGroupForEphemeralFocus')
|
|
.removeAttribute('tabindex');
|
|
});
|
|
|
|
test('with no focused node does not change states', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
|
|
const ephemeralElement = document.getElementById(
|
|
'nonTreeElementForEphemeralFocus',
|
|
);
|
|
this.focusManager.takeEphemeralFocus(ephemeralElement);
|
|
|
|
// Taking focus without an existing node having focus should change no focus indicators.
|
|
const activeElems = Array.from(
|
|
document.querySelectorAll(ACTIVE_FOCUS_NODE_CSS_SELECTOR),
|
|
);
|
|
const passiveElems = Array.from(
|
|
document.querySelectorAll(PASSIVE_FOCUS_NODE_CSS_SELECTOR),
|
|
);
|
|
assert.isEmpty(activeElems);
|
|
assert.isEmpty(passiveElems);
|
|
});
|
|
|
|
test('with focused node changes focused node to passive', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
|
|
const ephemeralElement = document.getElementById(
|
|
'nonTreeElementForEphemeralFocus',
|
|
);
|
|
this.focusManager.takeEphemeralFocus(ephemeralElement);
|
|
|
|
// Taking focus without an existing node having focus should change no focus indicators.
|
|
const activeElems = Array.from(
|
|
document.querySelectorAll(ACTIVE_FOCUS_NODE_CSS_SELECTOR),
|
|
);
|
|
const passiveElems = Array.from(
|
|
document.querySelectorAll(PASSIVE_FOCUS_NODE_CSS_SELECTOR),
|
|
);
|
|
assert.isEmpty(activeElems);
|
|
assert.strictEqual(passiveElems.length, 1);
|
|
assert.includesClass(
|
|
this.testFocusableTree2Node1.getFocusableElement().classList,
|
|
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
});
|
|
|
|
test('focuses provided HTML element', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
|
|
const ephemeralElement = document.getElementById(
|
|
'nonTreeElementForEphemeralFocus',
|
|
);
|
|
this.focusManager.takeEphemeralFocus(ephemeralElement);
|
|
|
|
assert.strictEqual(document.activeElement, ephemeralElement);
|
|
});
|
|
|
|
test('focuses provided SVG element', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
|
|
const ephemeralElement = document.getElementById(
|
|
'nonTreeGroupForEphemeralFocus',
|
|
);
|
|
this.focusManager.takeEphemeralFocus(ephemeralElement);
|
|
|
|
assert.strictEqual(document.activeElement, ephemeralElement);
|
|
});
|
|
|
|
test('twice for without finishing previous throws error', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
const ephemeralGroupElement = document.getElementById(
|
|
'nonTreeGroupForEphemeralFocus',
|
|
);
|
|
const ephemeralDivElement = document.getElementById(
|
|
'nonTreeElementForEphemeralFocus',
|
|
);
|
|
this.focusManager.takeEphemeralFocus(ephemeralGroupElement);
|
|
|
|
const errorMsgRegex =
|
|
/Attempted to take ephemeral focus when it's already held+?/;
|
|
assert.throws(
|
|
() => this.focusManager.takeEphemeralFocus(ephemeralDivElement),
|
|
errorMsgRegex,
|
|
);
|
|
});
|
|
|
|
test('then focusTree() changes getFocusedTree() but not active state', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusTree(this.testFocusableTree2);
|
|
const ephemeralElement = document.getElementById(
|
|
'nonTreeGroupForEphemeralFocus',
|
|
);
|
|
this.focusManager.takeEphemeralFocus(ephemeralElement);
|
|
|
|
this.focusManager.focusTree(this.testFocusableGroup2);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup2,
|
|
);
|
|
const activeElems = Array.from(
|
|
document.querySelectorAll(ACTIVE_FOCUS_NODE_CSS_SELECTOR),
|
|
);
|
|
assert.isEmpty(activeElems);
|
|
});
|
|
|
|
test('then focusNode() changes getFocusedNode() but not active state', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
const ephemeralElement = document.getElementById(
|
|
'nonTreeGroupForEphemeralFocus',
|
|
);
|
|
this.focusManager.takeEphemeralFocus(ephemeralElement);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup2Node1,
|
|
);
|
|
const activeElems = Array.from(
|
|
document.querySelectorAll(ACTIVE_FOCUS_NODE_CSS_SELECTOR),
|
|
);
|
|
assert.isEmpty(activeElems);
|
|
});
|
|
|
|
test('then DOM refocus changes getFocusedNode() but not active state', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
const ephemeralElement = document.getElementById(
|
|
'nonTreeGroupForEphemeralFocus',
|
|
);
|
|
this.focusManager.takeEphemeralFocus(ephemeralElement);
|
|
|
|
// Force focus to change via the DOM.
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
|
|
// The focus() state change will affect getFocusedNode() but it will not cause the node to now
|
|
// be active.
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup2Node1,
|
|
);
|
|
const activeElems = Array.from(
|
|
document.querySelectorAll(ACTIVE_FOCUS_NODE_CSS_SELECTOR),
|
|
);
|
|
assert.isEmpty(activeElems);
|
|
});
|
|
|
|
test('then finish ephemeral callback with no node does not change indicators', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
const ephemeralElement = document.getElementById(
|
|
'nonTreeElementForEphemeralFocus',
|
|
);
|
|
const finishFocusCallback =
|
|
this.focusManager.takeEphemeralFocus(ephemeralElement);
|
|
|
|
finishFocusCallback();
|
|
|
|
// Finishing ephemeral focus without a previously focused node should not change indicators.
|
|
const activeElems = Array.from(
|
|
document.querySelectorAll(ACTIVE_FOCUS_NODE_CSS_SELECTOR),
|
|
);
|
|
const passiveElems = Array.from(
|
|
document.querySelectorAll(PASSIVE_FOCUS_NODE_CSS_SELECTOR),
|
|
);
|
|
assert.isEmpty(activeElems);
|
|
assert.isEmpty(passiveElems);
|
|
});
|
|
|
|
test('again after finishing previous empheral focus should focus new element', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
const ephemeralGroupElement = document.getElementById(
|
|
'nonTreeGroupForEphemeralFocus',
|
|
);
|
|
const ephemeralDivElement = document.getElementById(
|
|
'nonTreeElementForEphemeralFocus',
|
|
);
|
|
const finishFocusCallback = this.focusManager.takeEphemeralFocus(
|
|
ephemeralGroupElement,
|
|
);
|
|
|
|
finishFocusCallback();
|
|
this.focusManager.takeEphemeralFocus(ephemeralDivElement);
|
|
|
|
// An exception should not be thrown and the new element should receive focus.
|
|
assert.strictEqual(document.activeElement, ephemeralDivElement);
|
|
});
|
|
|
|
test('calling ephemeral callback twice throws error', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
const ephemeralElement = document.getElementById(
|
|
'nonTreeElementForEphemeralFocus',
|
|
);
|
|
const finishFocusCallback =
|
|
this.focusManager.takeEphemeralFocus(ephemeralElement);
|
|
finishFocusCallback();
|
|
|
|
const errorMsgRegex =
|
|
/Attempted to finish ephemeral focus twice for element+?/;
|
|
assert.throws(() => finishFocusCallback(), errorMsgRegex);
|
|
});
|
|
|
|
test('then finish ephemeral callback should restore focused node', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
const ephemeralElement = document.getElementById(
|
|
'nonTreeGroupForEphemeralFocus',
|
|
);
|
|
const finishFocusCallback =
|
|
this.focusManager.takeEphemeralFocus(ephemeralElement);
|
|
|
|
finishFocusCallback();
|
|
|
|
// The original focused node should be restored.
|
|
const nodeElem = this.testFocusableTree2Node1.getFocusableElement();
|
|
const activeElems = Array.from(
|
|
document.querySelectorAll(ACTIVE_FOCUS_NODE_CSS_SELECTOR),
|
|
);
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableTree2Node1,
|
|
);
|
|
assert.strictEqual(activeElems.length, 1);
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.strictEqual(document.activeElement, nodeElem);
|
|
});
|
|
|
|
test('then focusTree() and finish ephemeral callback correctly sets new active state', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusTree(this.testFocusableTree2);
|
|
const ephemeralElement = document.getElementById(
|
|
'nonTreeGroupForEphemeralFocus',
|
|
);
|
|
const finishFocusCallback =
|
|
this.focusManager.takeEphemeralFocus(ephemeralElement);
|
|
|
|
this.focusManager.focusTree(this.testFocusableGroup2);
|
|
finishFocusCallback();
|
|
|
|
// The tree's root should now be the active element since focus changed between the start and
|
|
// end of the ephemeral flow.
|
|
const rootElem = this.testFocusableGroup2
|
|
.getRootFocusableNode()
|
|
.getFocusableElement();
|
|
const activeElems = Array.from(
|
|
document.querySelectorAll(ACTIVE_FOCUS_NODE_CSS_SELECTOR),
|
|
);
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedTree(),
|
|
this.testFocusableGroup2,
|
|
);
|
|
assert.strictEqual(activeElems.length, 1);
|
|
assert.includesClass(
|
|
rootElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.strictEqual(document.activeElement, rootElem);
|
|
});
|
|
|
|
test('then focusNode() and finish ephemeral callback correctly sets new active state', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
const ephemeralElement = document.getElementById(
|
|
'nonTreeGroupForEphemeralFocus',
|
|
);
|
|
const finishFocusCallback =
|
|
this.focusManager.takeEphemeralFocus(ephemeralElement);
|
|
|
|
this.focusManager.focusNode(this.testFocusableGroup2Node1);
|
|
finishFocusCallback();
|
|
|
|
// The tree's root should now be the active element since focus changed between the start and
|
|
// end of the ephemeral flow.
|
|
const nodeElem = this.testFocusableGroup2Node1.getFocusableElement();
|
|
const activeElems = Array.from(
|
|
document.querySelectorAll(ACTIVE_FOCUS_NODE_CSS_SELECTOR),
|
|
);
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup2Node1,
|
|
);
|
|
assert.strictEqual(activeElems.length, 1);
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.strictEqual(document.activeElement, nodeElem);
|
|
});
|
|
|
|
test('then DOM focus change and finish ephemeral callback correctly sets new active state', function () {
|
|
this.focusManager.registerTree(this.testFocusableTree2);
|
|
this.focusManager.registerTree(this.testFocusableGroup2);
|
|
this.focusManager.focusNode(this.testFocusableTree2Node1);
|
|
document.getElementById('testFocusableGroup2.node1').tabIndex = -1;
|
|
const ephemeralElement = document.getElementById(
|
|
'nonTreeGroupForEphemeralFocus',
|
|
);
|
|
const finishFocusCallback =
|
|
this.focusManager.takeEphemeralFocus(ephemeralElement);
|
|
|
|
document.getElementById('testFocusableGroup2.node1').focus();
|
|
finishFocusCallback();
|
|
|
|
// The tree's root should now be the active element since focus changed between the start and
|
|
// end of the ephemeral flow.
|
|
const nodeElem = this.testFocusableGroup2Node1.getFocusableElement();
|
|
const activeElems = Array.from(
|
|
document.querySelectorAll(ACTIVE_FOCUS_NODE_CSS_SELECTOR),
|
|
);
|
|
assert.strictEqual(
|
|
this.focusManager.getFocusedNode(),
|
|
this.testFocusableGroup2Node1,
|
|
);
|
|
assert.strictEqual(activeElems.length, 1);
|
|
assert.includesClass(
|
|
nodeElem.classList,
|
|
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
|
);
|
|
assert.strictEqual(document.activeElement, nodeElem);
|
|
});
|
|
});
|
|
});
|