blob: 1da48e27a1e2b9212548ee44d4597ede67a1c7f5 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {Navigator} from '../navigator.js';
import {SAConstants, SwitchAccessMenuAction} from '../switch_access_constants.js';
import {BackButtonNode} from './back_button_node.js';
import {BasicNode, BasicRootNode} from './basic_node.js';
import {SAChildNode, SARootNode} from './switch_access_node.js';
const AutomationNode = chrome.automation.AutomationNode;
/**
* This class handles the behavior of tab nodes at the top level (i.e. as
* groups).
*/
export class TabNode extends BasicNode {
/**
* @param {!AutomationNode} node The node in the automation
* tree
* @param {?SARootNode} parent
* @param {!SARootNode} tabAsRoot A pre-calculated object for exploring the
* parts of tab (i.e. choosing whether to open the tab or close it).
*/
constructor(node, parent, tabAsRoot) {
super(node, parent);
/** @private {!SARootNode} */
this.tabAsRoot_ = tabAsRoot;
}
// ================= Getters and setters =================
/** @override */
get actions() {
return [SwitchAccessMenuAction.SELECT];
}
// ================= General methods =================
/** @override */
asRootNode() {
return this.tabAsRoot_;
}
/** @override */
isGroup() {
return true;
}
/** @override */
performAction(action) {
if (action !== SwitchAccessMenuAction.SELECT) {
return SAConstants.ActionResponse.NO_ACTION_TAKEN;
}
Navigator.instance.enterGroup();
return SAConstants.ActionResponse.CLOSE_MENU;
}
// ================= Static methods =================
/** @override */
static create(tabNode, parent) {
const tabAsRoot = new BasicRootNode(tabNode);
let closeButton;
for (const child of tabNode.children) {
if (child.role === chrome.automation.RoleType.BUTTON) {
closeButton = new BasicNode(child, tabAsRoot);
break;
}
}
if (!closeButton) {
// Pinned tabs have no close button, and so can be treated as just
// actionable.
return new ActionableTabNode(tabNode, parent, null);
}
const tabToSelect = new ActionableTabNode(tabNode, tabAsRoot, closeButton);
const backButton = new BackButtonNode(tabAsRoot);
tabAsRoot.children = [tabToSelect, closeButton, backButton];
return new TabNode(tabNode, parent, tabAsRoot);
}
}
/** This class handles the behavior of tabs as actionable elements */
class ActionableTabNode extends BasicNode {
/**
* @param {!AutomationNode} node
* @param {?SARootNode} parent
* @param {?SAChildNode} closeButton
*/
constructor(node, parent, closeButton) {
super(node, parent);
/** @private {?SAChildNode} */
this.closeButton_ = closeButton;
}
// ================= Getters and setters =================
/** @override */
get actions() {
return [SwitchAccessMenuAction.SELECT];
}
/** @override */
get location() {
if (!this.closeButton_) {
return super.location;
}
return RectUtil.difference(super.location, this.closeButton_.location);
}
// ================= General methods =================
/** @override */
asRootNode() {
return null;
}
/** @override */
isGroup() {
return false;
}
}
BasicNode.creators.push({
predicate: baseNode => baseNode.role === chrome.automation.RoleType.TAB &&
baseNode.root.role === chrome.automation.RoleType.DESKTOP,
creator: TabNode.create
});