mirror of
https://github.com/google/blockly.git
synced 2026-01-08 01:20:12 +01:00
feat!: Introduce new focus tree/node functions.
This introduces new callback methods for IFocusableTree and IFocusableNode for providing a basis of synchronizing domain state with focus changes. It also introduces support for implementations of IFocusableTree to better manage initial state cases, especially when a tree is focused using tab navigation. FocusManager has also been updated to ensure functional parity between tab-navigating to a tree and using focusTree() on that tree. This means that tab navigating to a tree will actually restore focus back to that tree's previous focused node rather than the root (unless the root is navigated to from within the tree itself). This is meant to provide better consistency between tab and non-tab keyboard navigation. Note that these changes originally came from #8875 and are required for later PRs that will introduce IFocusableNode and IFocusableTree implementations.
This commit is contained in:
@@ -27,6 +27,10 @@ class FocusableNodeImpl {
|
||||
getFocusableTree() {
|
||||
return this.tree;
|
||||
}
|
||||
|
||||
onNodeFocus() {}
|
||||
|
||||
onNodeBlur() {}
|
||||
}
|
||||
|
||||
class FocusableTreeImpl {
|
||||
@@ -46,6 +50,10 @@ class FocusableTreeImpl {
|
||||
return this.rootNode;
|
||||
}
|
||||
|
||||
getRestoredFocusableNode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
getNestedTrees() {
|
||||
return this.nestedTrees;
|
||||
}
|
||||
@@ -53,6 +61,10 @@ class FocusableTreeImpl {
|
||||
lookUpFocusableNode(id) {
|
||||
return this.idToNodeMap[id];
|
||||
}
|
||||
|
||||
onTreeFocus() {}
|
||||
|
||||
onTreeBlur() {}
|
||||
}
|
||||
|
||||
suite('FocusManager', function () {
|
||||
@@ -2067,7 +2079,7 @@ suite('FocusManager', function () {
|
||||
);
|
||||
});
|
||||
|
||||
test('registered tree focus()ed other tree node passively focused tree root now has active property', function () {
|
||||
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').focus();
|
||||
@@ -2075,26 +2087,27 @@ suite('FocusManager', function () {
|
||||
|
||||
document.getElementById('testFocusableTree1').focus();
|
||||
|
||||
// This differs from the behavior of focusTree() since directly focusing a tree's root will
|
||||
// coerce it to now have 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(
|
||||
rootElem.classList,
|
||||
nodeElem.classList,
|
||||
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
||||
);
|
||||
assert.notIncludesClass(
|
||||
rootElem.classList,
|
||||
nodeElem.classList,
|
||||
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
||||
);
|
||||
assert.notIncludesClass(
|
||||
nodeElem.classList,
|
||||
rootElem.classList,
|
||||
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
||||
);
|
||||
assert.notIncludesClass(
|
||||
nodeElem.classList,
|
||||
rootElem.classList,
|
||||
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
||||
);
|
||||
});
|
||||
@@ -3879,7 +3892,7 @@ suite('FocusManager', function () {
|
||||
);
|
||||
});
|
||||
|
||||
test('registered tree focus()ed other tree node passively focused tree root now has active property', function () {
|
||||
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').focus();
|
||||
@@ -3887,26 +3900,27 @@ suite('FocusManager', function () {
|
||||
|
||||
document.getElementById('testFocusableGroup1').focus();
|
||||
|
||||
// This differs from the behavior of focusTree() since directly focusing a tree's root will
|
||||
// coerce it to now have 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(
|
||||
rootElem.classList,
|
||||
nodeElem.classList,
|
||||
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
||||
);
|
||||
assert.notIncludesClass(
|
||||
rootElem.classList,
|
||||
nodeElem.classList,
|
||||
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
||||
);
|
||||
assert.notIncludesClass(
|
||||
nodeElem.classList,
|
||||
rootElem.classList,
|
||||
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
||||
);
|
||||
assert.notIncludesClass(
|
||||
nodeElem.classList,
|
||||
rootElem.classList,
|
||||
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -25,6 +25,10 @@ class FocusableNodeImpl {
|
||||
getFocusableTree() {
|
||||
return this.tree;
|
||||
}
|
||||
|
||||
onNodeFocus() {}
|
||||
|
||||
onNodeBlur() {}
|
||||
}
|
||||
|
||||
class FocusableTreeImpl {
|
||||
@@ -44,6 +48,10 @@ class FocusableTreeImpl {
|
||||
return this.rootNode;
|
||||
}
|
||||
|
||||
getRestoredFocusableNode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
getNestedTrees() {
|
||||
return this.nestedTrees;
|
||||
}
|
||||
@@ -51,6 +59,10 @@ class FocusableTreeImpl {
|
||||
lookUpFocusableNode(id) {
|
||||
return this.idToNodeMap[id];
|
||||
}
|
||||
|
||||
onTreeFocus() {}
|
||||
|
||||
onTreeBlur() {}
|
||||
}
|
||||
|
||||
suite('FocusableTreeTraverser', function () {
|
||||
|
||||
Reference in New Issue
Block a user