Commit 731b4b02 authored by Anastasia Helfinstein's avatar Anastasia Helfinstein Committed by Commit Bot

[Switch Access] Use new views-based Switch Access menu

This is the (hopefully) penultimate change in the process of changing
to a views-based menu for Switch Access, as part of implementing the
visual specification.

This change rewrites the menu manager to use the new menu, rather than
the old menu. A clean-up change (to remove code for the old menu) will
follow this.

AX-Relnotes: n/a
Bug: 973719
Change-Id: I596d47a8f976a531e545bc56555f9f8da80efbd7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2176611
Commit-Queue: Anastasia Helfinstein <anastasi@google.com>
Reviewed-by: default avatarDavid Tseng <dtseng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#772047}
parent 3806730b
......@@ -186,6 +186,11 @@ js_library("back_button_node") {
}
js_library("commands") {
deps = [
":auto_scan_manager",
":menu_manager",
":navigation_manager",
]
externs_list = [ "$externs_path/accessibility_private.js" ]
}
......@@ -216,6 +221,7 @@ js_library("focus_ring_manager") {
deps = [
":menu_panel_interface",
":node_wrapper",
":switch_access_constants",
":switch_access_node",
]
externs_list = [ "$externs_path/accessibility_private.js" ]
......@@ -267,22 +273,13 @@ js_library("keyboard_node") {
js_library("menu_manager") {
deps = [
":event_helper",
":menu_panel_interface",
":metrics",
":node_wrapper",
":rect_helper",
":switch_access_constants",
":switch_access_node",
":switch_access_predicate",
":text_navigation_manager",
"../common:constants",
"../common:tree_walker",
"../common:array_util",
]
externs_list = [
"$externs_path/accessibility_private.js",
"$externs_path/automation.js",
"$externs_path/clipboard.js",
]
}
......@@ -306,6 +303,7 @@ js_library("navigation_manager") {
deps = [
":desktop_node",
":focus_ring_manager",
":history",
":keyboard_node",
":menu_manager",
":menu_panel_interface",
......@@ -413,5 +411,6 @@ js_library("text_navigation_manager") {
externs_list = [
"$externs_path/accessibility_private.js",
"$externs_path/automation.js",
"$externs_path/clipboard.js",
]
}
......@@ -15,7 +15,7 @@ class Commands {
* @private {!Map<!SwitchAccessCommand, !function(): void>}
*/
this.commandMap_ = new Map([
[SwitchAccessCommand.SELECT, NavigationManager.enterMenu],
[SwitchAccessCommand.SELECT, MenuManager.enter],
[SwitchAccessCommand.NEXT, NavigationManager.moveForward],
[SwitchAccessCommand.PREVIOUS, NavigationManager.moveBackward]
]);
......
......@@ -43,15 +43,10 @@ class FocusRingManager {
* @param {!SARootNode} group
*/
setFocusNodes(primary, group) {
if (!primary.location) {
throw SwitchAccess.error(
SAConstants.ErrorType.MISSING_LOCATION,
'Cannot set focus rings if node location is undefined');
}
if (primary instanceof BackButtonNode) {
MenuManager.requestBackButtonFocusChange(true);
// The back button node handles setting its own focus, as it has special
// requirements (a round focus ring that has no gap with the edges of the
// view).
this.rings_.get(SAConstants.Focus.ID.PRIMARY).rects = [];
// Clear the dashed ring between transitions, as the animation is
// distracting.
......@@ -61,8 +56,12 @@ class FocusRingManager {
this.rings_.get(SAConstants.Focus.ID.NEXT).rects = [group.location];
this.updateFocusRings_();
return;
} else {
MenuManager.requestBackButtonFocusChange(false);
}
if (!primary.location) {
throw SwitchAccess.error(
SAConstants.ErrorType.MISSING_LOCATION,
'Cannot set focus rings if node location is undefined');
}
// If the primary node is a group, show its first child as the "next" focus.
......
......@@ -65,18 +65,19 @@ class NavigationManager {
navigator.jumpTo_(keyboard);
}
/** Unconditionally exits the current group. */
static exitGroupUnconditionally() {
NavigationManager.instance.exitGroup_();
}
/**
* Open the Switch Access menu for the currently highlighted node. If there
* are not enough actions available to trigger the menu, the current element
* is selected.
* Exits the specified node, if it is the currently focused group.
* @param {?AutomationNode|!SAChildNode|!SARootNode} node
*/
static enterMenu() {
static exitIfInGroup(node) {
const navigator = NavigationManager.instance;
const didEnter = MenuManager.enter(navigator.node_);
// If the menu does not or cannot open, select the current node.
if (!didEnter) {
navigator.selectCurrentNode();
if (navigator.group_.isEquivalentTo(node)) {
navigator.exitGroup_();
}
}
......@@ -134,18 +135,20 @@ class NavigationManager {
NavigationManager.instance = new NavigationManager(desktop);
}
/** @param {AutomationNode} menuNode */
static jumpToSwitchAccessMenu(menuNode) {
if (!menuNode) {
return;
}
const menu = RootNodeWrapper.buildTree(menuNode);
NavigationManager.instance.jumpTo_(menu, false /* shouldExitMenu */);
}
/**
* Move to the previous interesting node.
*/
static moveBackward() {
const navigator = NavigationManager.instance;
if (MenuManager.moveBackward()) {
// The menu navigation is handled separately. If we are in the menu, do
// not change the primary focus node.
return;
}
navigator.setNode_(navigator.node_.previous);
}
......@@ -159,12 +162,6 @@ class NavigationManager {
navigator.onMoveForwardForTesting_();
}
if (MenuManager.moveForward()) {
// The menu navigation is handled separately. If we are in the menu, do
// not change the primary focus node.
return;
}
navigator.setNode_(navigator.node_.next);
}
......@@ -207,54 +204,27 @@ class NavigationManager {
navigator.node_, navigator.group_);
}
// =============== Getter Methods ==============
/**
* Returns the desktop automation node object.
* @return {!AutomationNode}
* Returns the currently focused node.
* @return {!SAChildNode}
*/
static get desktopNode() {
return NavigationManager.instance.desktop_;
static get currentNode() {
NavigationManager.moveToValidNode();
return NavigationManager.instance.node_;
}
// =============== Instance Methods ==============
/**
* Selects the current node.
* Returns the desktop automation node object.
* @return {!AutomationNode}
*/
selectCurrentNode() {
if (MenuManager.selectCurrentNode()) {
// The menu navigation is handled separately. If we are in the menu, do
// not change the primary focus node.
return;
}
if (this.node_.isGroup()) {
NavigationManager.enterGroup();
return;
}
if (this.node_.hasAction(SwitchAccessMenuAction.KEYBOARD)) {
SwitchAccessMetrics.recordMenuAction(SwitchAccessMenuAction.KEYBOARD);
this.node_.performAction(SwitchAccessMenuAction.KEYBOARD);
return;
}
if (this.node_.hasAction(SwitchAccessMenuAction.SELECT)) {
SwitchAccessMetrics.recordMenuAction(SwitchAccessMenuAction.SELECT);
this.node_.performAction(SwitchAccessMenuAction.SELECT);
}
static get desktopNode() {
return NavigationManager.instance.desktop_;
}
// =============== Event Handlers ==============
/**
* Sets up the connection between the menuPanel and menuManager.
* @param {!PanelInterface} menuPanel
*/
connectMenuPanel(menuPanel) {
menuPanel.backButtonElement().addEventListener(
'click', this.exitGroup_.bind(this));
}
/**
* When focus shifts, move to the element. Find the closest interesting
* element to engage with.
......@@ -303,18 +273,12 @@ class NavigationManager {
this.group_.onFocus();
this.node_.onFocus();
if (window.menuPanel) {
this.connectMenuPanel(window.menuPanel);
}
this.desktop_.addEventListener(
chrome.automation.EventType.FOCUS, this.onFocusChange_.bind(this),
false);
this.desktop_.addEventListener(
chrome.automation.EventType.MENU_START, this.onMenuStart_.bind(this),
false);
chrome.automation.addTreeChangeObserver(
chrome.automation.TreeChangeObserverFilter.ALL_TREE_CHANGES,
this.onTreeChange_.bind(this));
......@@ -324,10 +288,13 @@ class NavigationManager {
* Jumps Switch Access focus to a specified node, such as when opening a menu
* or the keyboard. Does not modify the groups already in the group stack.
* @param {!SARootNode} group
* @param {boolean} shouldExitMenu
* @private
*/
jumpTo_(group) {
jumpTo_(group, shouldExitMenu = true) {
if (shouldExitMenu) {
MenuManager.exit();
}
this.history_.save(new FocusData(this.group_, this.node_));
this.setGroup_(group);
......
......@@ -27,7 +27,7 @@ class BackButtonNode extends SAChildNode {
/** @override */
get automationNode() {
return BackButtonNode.automationNode;
return BackButtonNode.automationNode_;
}
/** @override */
......@@ -69,28 +69,30 @@ class BackButtonNode extends SAChildNode {
/** @override */
isValidAndVisible() {
return this.automationNode !== null;
return this.automationNode !== null && !!this.location;
}
/** @override */
onFocus() {
super.onFocus();
chrome.accessibilityPrivate.setSwitchAccessMenuState(
true, this.group_.location, 0 /* num_actions */);
chrome.accessibilityPrivate.updateSwitchAccessBubble(
chrome.accessibilityPrivate.SwitchAccessBubble.BACK_BUTTON,
true /* show */, this.group_.location);
BackButtonNode.findAutomationNode_();
}
/** @override */
onUnfocus() {
super.onUnfocus();
chrome.accessibilityPrivate.setSwitchAccessMenuState(
false, RectHelper.ZERO_RECT, 0 /* num_actions */);
chrome.accessibilityPrivate.updateSwitchAccessBubble(
chrome.accessibilityPrivate.SwitchAccessBubble.BACK_BUTTON,
false /* show */);
}
/** @override */
performAction(action) {
if (action === SwitchAccessMenuAction.SELECT &&
BackButtonNode.automationNode_) {
BackButtonNode.automationNode_.doDefault();
if (action === SwitchAccessMenuAction.SELECT && this.automationNode) {
BackButtonNode.onClick_();
return SAConstants.ActionResponse.CLOSE_MENU;
}
return SAConstants.ActionResponse.NO_ACTION_TAKEN;
......@@ -106,18 +108,48 @@ class BackButtonNode extends SAChildNode {
// ================= Static methods =================
/**
* Looks for the back button node.
* @return {?AutomationNode}
* Looks for the back button automation node.
* @private
*/
static get automationNode() {
if (BackButtonNode.automationNode_) {
return BackButtonNode.automationNode_;
static findAutomationNode_() {
if (BackButtonNode.automationNode_ && BackButtonNode.automationNode_.role) {
return;
}
SwitchAccess.findNodeMatchingPredicate(
BackButtonNode.isBackButton_, BackButtonNode.saveAutomationNode_);
}
const treeWalker = new AutomationTreeWalker(
NavigationManager.desktopNode, constants.Dir.FORWARD,
{visit: (node) => node.htmlAttributes.id === SAConstants.BACK_ID});
BackButtonNode.automationNode_ = treeWalker.next().node;
return BackButtonNode.automationNode_;
/**
* Checks if the given node is the back button automation node.
* @param {!AutomationNode} node
* @return {boolean}
* @private
*/
static isBackButton_(node) {
return node.htmlAttributes.id === 'switch_access_back_button';
}
/**
* This function defines the behavior that should be taken when the back
* button is pressed.
* @private
*/
static onClick_() {
if (MenuManager.isMenuOpen()) {
MenuManager.exit();
} else {
NavigationManager.exitGroupUnconditionally();
}
}
/**
* Saves the back button automation node.
* @param {!AutomationNode} automationNode
* @private
*/
static saveAutomationNode_(automationNode) {
BackButtonNode.automationNode_ = automationNode;
BackButtonNode.automationNode_.addEventListener(
chrome.automation.EventType.CLICKED, BackButtonNode.onClick_, false);
}
}
......@@ -30,13 +30,22 @@ class EditableTextNode extends NodeWrapper {
actions.push(SwitchAccessMenuAction.KEYBOARD);
actions.push(SwitchAccessMenuAction.DICTATION);
if (SwitchAccess.instance.improvedTextInputEnabled() &&
this.automationNode.state[StateType.FOCUSED]) {
if (SwitchAccess.instance.improvedTextInputEnabled()) {
actions.push(SwitchAccessMenuAction.MOVE_CURSOR);
actions.push(SwitchAccessMenuAction.JUMP_TO_BEGINNING_OF_TEXT);
actions.push(SwitchAccessMenuAction.JUMP_TO_END_OF_TEXT);
actions.push(SwitchAccessMenuAction.MOVE_BACKWARD_ONE_CHAR_OF_TEXT);
actions.push(SwitchAccessMenuAction.MOVE_FORWARD_ONE_CHAR_OF_TEXT);
actions.push(SwitchAccessMenuAction.MOVE_BACKWARD_ONE_WORD_OF_TEXT);
actions.push(SwitchAccessMenuAction.MOVE_FORWARD_ONE_WORD_OF_TEXT);
actions.push(SwitchAccessMenuAction.MOVE_DOWN_ONE_LINE_OF_TEXT);
actions.push(SwitchAccessMenuAction.MOVE_UP_ONE_LINE_OF_TEXT);
actions.push(SwitchAccessMenuAction.START_TEXT_SELECTION);
if (TextNavigationManager.currentlySelecting()) {
actions.push(SwitchAccessMenuAction.END_TEXT_SELECTION);
}
if (TextNavigationManager.selectionExists) {
actions.push(SwitchAccessMenuAction.CUT);
actions.push(SwitchAccessMenuAction.COPY);
......@@ -45,12 +54,16 @@ class EditableTextNode extends NodeWrapper {
actions.push(SwitchAccessMenuAction.PASTE);
}
}
return actions;
}
// ================= General methods =================
/** @override */
doDefaultAction() {
this.performAction(SwitchAccessMenuAction.KEYBOARD);
}
/** @override */
performAction(action) {
switch (action) {
......@@ -60,6 +73,9 @@ class EditableTextNode extends NodeWrapper {
case SwitchAccessMenuAction.DICTATION:
chrome.accessibilityPrivate.toggleDictation();
return SAConstants.ActionResponse.CLOSE_MENU;
case SwitchAccessMenuAction.MOVE_CURSOR:
return SAConstants.ActionResponse.OPEN_TEXT_NAVIGATION_MENU;
case SwitchAccessMenuAction.CUT:
EventHelper.simulateKeyPress(EventHelper.KeyCode.X, {ctrl: true});
return SAConstants.ActionResponse.REMAIN_OPEN;
......@@ -69,6 +85,38 @@ class EditableTextNode extends NodeWrapper {
case SwitchAccessMenuAction.PASTE:
EventHelper.simulateKeyPress(EventHelper.KeyCode.V, {ctrl: true});
return SAConstants.ActionResponse.REMAIN_OPEN;
case SwitchAccessMenuAction.START_TEXT_SELECTION:
TextNavigationManager.saveSelectStart();
return SAConstants.ActionResponse.OPEN_TEXT_NAVIGATION_MENU;
case SwitchAccessMenuAction.END_TEXT_SELECTION:
TextNavigationManager.saveSelectEnd();
return SAConstants.ActionResponse.RELOAD_MAIN_MENU;
case SwitchAccessMenuAction.JUMP_TO_BEGINNING_OF_TEXT:
TextNavigationManager.jumpToBeginning();
return SAConstants.ActionResponse.REMAIN_OPEN;
case SwitchAccessMenuAction.JUMP_TO_END_OF_TEXT:
TextNavigationManager.jumpToEnd();
return SAConstants.ActionResponse.REMAIN_OPEN;
case SwitchAccessMenuAction.MOVE_BACKWARD_ONE_CHAR_OF_TEXT:
TextNavigationManager.moveBackwardOneChar();
return SAConstants.ActionResponse.REMAIN_OPEN;
case SwitchAccessMenuAction.MOVE_BACKWARD_ONE_WORD_OF_TEXT:
TextNavigationManager.moveBackwardOneWord();
return SAConstants.ActionResponse.REMAIN_OPEN;
case SwitchAccessMenuAction.MOVE_DOWN_ONE_LINE_OF_TEXT:
TextNavigationManager.moveDownOneLine();
return SAConstants.ActionResponse.REMAIN_OPEN;
case SwitchAccessMenuAction.MOVE_FORWARD_ONE_CHAR_OF_TEXT:
TextNavigationManager.moveForwardOneChar();
return SAConstants.ActionResponse.REMAIN_OPEN;
case SwitchAccessMenuAction.MOVE_UP_ONE_LINE_OF_TEXT:
TextNavigationManager.moveUpOneLine();
return SAConstants.ActionResponse.REMAIN_OPEN;
case SwitchAccessMenuAction.MOVE_FORWARD_ONE_WORD_OF_TEXT:
TextNavigationManager.moveForwardOneWord();
return SAConstants.ActionResponse.REMAIN_OPEN;
}
return super.performAction(action);
}
......
......@@ -25,7 +25,7 @@ class GroupNode extends SAChildNode {
/** @override */
get actions() {
return [];
return [SwitchAccessMenuAction.SELECT];
}
/** @override */
......
......@@ -19,9 +19,6 @@ class KeyboardNode extends NodeWrapper {
/** @override */
get actions() {
if (this.isGroup()) {
return [];
}
return [SwitchAccessMenuAction.SELECT];
}
......@@ -45,10 +42,15 @@ class KeyboardNode extends NodeWrapper {
/** @override */
performAction(action) {
if (this.isGroup() || action !== SwitchAccessMenuAction.SELECT) {
if (action !== SwitchAccessMenuAction.SELECT) {
return SAConstants.ActionResponse.NO_ACTION_TAKEN;
}
if (this.isGroup()) {
NavigationManager.enterGroup();
return SAConstants.ActionResponse.CLOSE_MENU;
}
const keyLocation = this.location;
if (!keyLocation) {
return SAConstants.ActionResponse.NO_ACTION_TAKEN;
......
......@@ -149,25 +149,25 @@ class NodeWrapper extends SAChildNode {
if (ancestor.scrollable) {
ancestor.scrollDown(() => this.parent_.refresh());
}
return SAConstants.ActionResponse.CLOSE_MENU;
return SAConstants.ActionResponse.RELOAD_MAIN_MENU;
case SwitchAccessMenuAction.SCROLL_UP:
ancestor = this.getScrollableAncestor_();
if (ancestor.scrollable) {
ancestor.scrollUp(() => this.parent_.refresh());
}
return SAConstants.ActionResponse.CLOSE_MENU;
return SAConstants.ActionResponse.RELOAD_MAIN_MENU;
case SwitchAccessMenuAction.SCROLL_RIGHT:
ancestor = this.getScrollableAncestor_();
if (ancestor.scrollable) {
ancestor.scrollRight(() => this.parent_.refresh());
}
return SAConstants.ActionResponse.CLOSE_MENU;
return SAConstants.ActionResponse.RELOAD_MAIN_MENU;
case SwitchAccessMenuAction.SCROLL_LEFT:
ancestor = this.getScrollableAncestor_();
if (ancestor.scrollable) {
ancestor.scrollLeft(() => this.parent_.refresh());
}
return SAConstants.ActionResponse.CLOSE_MENU;
return SAConstants.ActionResponse.RELOAD_MAIN_MENU;
default:
if (Object.values(chrome.automation.ActionType).includes(action)) {
this.baseNode_.performStandardAction(
......
......@@ -97,6 +97,14 @@ class SAChildNode {
*/
asRootNode() {}
/** Performs the node's default action. */
doDefaultAction() {
if (!this.isFocused_) {
return;
}
this.performAction(SwitchAccessMenuAction.SELECT);
}
/**
* @param {SAChildNode} other
* @return {boolean}
......
......@@ -25,7 +25,7 @@ class TabNode extends NodeWrapper {
/** @override */
get actions() {
return [];
return [SwitchAccessMenuAction.SELECT];
}
// ================= General methods =================
......@@ -40,6 +40,15 @@ class TabNode extends NodeWrapper {
return true;
}
/** @override */
performAction(action) {
if (action !== SwitchAccessMenuAction.SELECT) {
return SAConstants.ActionResponse.NO_ACTION_TAKEN;
}
NavigationManager.enterGroup();
return SAConstants.ActionResponse.CLOSE_MENU;
}
// ================= Static methods =================
/** @override */
......
......@@ -47,9 +47,12 @@ TEST_F('SwitchAccessTabNodeTest', 'Construction', function() {
chrome.automation.RoleType.TAB, tab.role, 'Tab node is not a tab');
assertTrue(tab.isGroup(), 'Tab node should be a group');
assertEquals(
0, tab.actions.length, 'Tab as a group should not have actions');
1, tab.actions.length, 'Tab as a group should have 1 action (select)');
assertEquals(
chrome.accessibilityPrivate.SwitchAccessMenuAction.SELECT,
tab.actions[0], 'Tab as a group should have the action SELECT');
NavigationManager.instance.selectCurrentNode();
NavigationManager.instance.node_.doDefaultAction();
const tabAsRoot = NavigationManager.instance.group_;
assertTrue(
......
......@@ -12,17 +12,20 @@ class SwitchAccess {
window.switchAccess = new SwitchAccess();
chrome.automation.getDesktop((desktop) => {
// These two must be initialized before the others.
AutoScanManager.initialize();
NavigationManager.initialize(desktop);
Commands.initialize();
KeyboardRootNode.startWatchingVisibility();
MenuManager.initialize();
SwitchAccessPreferences.initialize();
TextNavigationManager.initialize();
KeyboardRootNode.startWatchingVisibility();
});
}
// TODO(anastasi): Remove once new menu is being used.
static get instance() {
return window.switchAccess;
}
......@@ -50,21 +53,54 @@ class SwitchAccess {
return this.enableImprovedTextInput_;
}
/** TODO(anastasi): Remove this once menu migration is complete. */
connectMenuPanel() {}
/**
* Sets up the connection between the menuPanel and menuManager.
* @param {!PanelInterface} menuPanel
* Helper function to robustly find a node fitting a given predicate, even if
* that node has not yet been created.
* Used to find the menu and back button.
* @param {!function(!AutomationNode): boolean} predicate
* @param {!function(!AutomationNode): void} foundCallback
*/
connectMenuPanel(menuPanel) {
// Because this may be called before init_(), check if navigationManager_
// is initialized.
if (NavigationManager.instance) {
NavigationManager.instance.connectMenuPanel(menuPanel);
MenuManager.instance.connectMenuPanel(menuPanel);
} else {
window.menuPanel = menuPanel;
static findNodeMatchingPredicate(predicate, foundCallback) {
const desktop = NavigationManager.desktopNode;
// First, check if the node is currently in the tree.
const treeWalker = new AutomationTreeWalker(
desktop, constants.Dir.FORWARD, {visit: predicate});
treeWalker.next();
if (treeWalker.node) {
foundCallback(treeWalker.node);
return;
}
// If it's not currently in the tree, listen for changes to the desktop
// tree.
const onDesktopChildrenChanged = (event) => {
if (predicate(event.target)) {
// If the event target is the node we're looking for, we've found it.
desktop.removeEventListener(
chrome.automation.EventType.CHILDREN_CHANGED,
onDesktopChildrenChanged, false);
foundCallback(event.target);
} else if (event.target.children.length > 0) {
// Otherwise, see if one of its children is the node we're looking for.
const treeWalker = new AutomationTreeWalker(
event.target, constants.Dir.FORWARD,
{visit: predicate, root: (node) => node == event.target});
treeWalker.next();
if (treeWalker.node) {
desktop.removeEventListener(
chrome.automation.EventType.CHILDREN_CHANGED,
onDesktopChildrenChanged, false);
foundCallback(treeWalker.node);
}
}
};
desktop.addEventListener(
chrome.automation.EventType.CHILDREN_CHANGED, onDesktopChildrenChanged,
false);
}
/*
* Creates and records the specified error.
......
......@@ -50,8 +50,10 @@ const SAConstants = {
*/
ActionResponse: {
NO_ACTION_TAKEN: -1,
CLOSE_MENU: 0,
REMAIN_OPEN: 1,
REMAIN_OPEN: 0,
CLOSE_MENU: 1,
RELOAD_MAIN_MENU: 2,
OPEN_TEXT_NAVIGATION_MENU: 3,
},
/**
......
......@@ -276,6 +276,10 @@ class TextNavigationManager {
* @private
*/
manageNavigationListener_(addListener) {
if (!this.selectionStartObject_) {
return;
}
if (addListener) {
this.selectionStartObject_.addEventListener(
chrome.automation.EventType.TEXT_SELECTION_CHANGED,
......@@ -296,20 +300,21 @@ class TextNavigationManager {
onNavChange_() {
this.manageNavigationListener_(false);
if (this.currentlySelecting_) {
this.saveSelectEnd();
TextNavigationManager.saveSelectEnd();
}
}
/**
* Sets the selectionEnd variable based on the selection of the current node.
*/
saveSelectEnd() {
static saveSelectEnd() {
const manager = TextNavigationManager.instance;
chrome.automation.getFocus((focusedNode) => {
this.selectionEndObject_ = focusedNode;
this.selectionEndIndex_ = this.getSelectionIndexFromNode_(
this.selectionEndObject_,
manager.selectionEndObject_ = focusedNode;
manager.selectionEndIndex_ = manager.getSelectionIndexFromNode_(
manager.selectionEndObject_,
false /*We are not getting the start index.*/);
this.saveSelection_();
manager.saveSelection_();
});
}
......@@ -371,7 +376,10 @@ class TextNavigationManager {
*/
updateClipboardHasData_() {
this.clipboardHasData_ = true;
MenuManager.reloadMenuIfNeeded();
const node = NavigationManager.currentNode;
if (node.hasAction(SwitchAccessMenuAction.PASTE)) {
MenuManager.reloadActionsForNode(node);
}
}
}
......
......@@ -11,6 +11,7 @@
{% endif %}
"background": {
"scripts": [
"common/array_util.js",
"switch_access/auto_scan_manager.js",
"common/closure_shim.js",
"switch_access/commands.js",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment