Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 1 addition & 68 deletions core/flyout_base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,9 @@ import * as eventUtils from './events/utils.js';
import {FlyoutItem} from './flyout_item.js';
import {FlyoutMetricsManager} from './flyout_metrics_manager.js';
import {FlyoutSeparator, SeparatorAxis} from './flyout_separator.js';
import {getFocusManager} from './focus_manager.js';
import {IAutoHideable} from './interfaces/i_autohideable.js';
import type {IFlyout} from './interfaces/i_flyout.js';
import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js';
import {IFocusableNode} from './interfaces/i_focusable_node.js';
import {IFocusableTree} from './interfaces/i_focusable_tree.js';
import type {Options} from './options.js';
import * as registry from './registry.js';
import * as renderManagement from './render_management.js';
Expand All @@ -46,7 +43,7 @@ import {WorkspaceSvg} from './workspace_svg.js';
*/
export abstract class Flyout
extends DeleteArea
implements IAutoHideable, IFlyout, IFocusableNode
implements IAutoHideable, IFlyout
{
/**
* Position the flyout.
Expand Down Expand Up @@ -306,7 +303,6 @@ export abstract class Flyout
// hide/show code will set up proper visibility and size later.
this.svgGroup_ = dom.createSvgElement(tagName, {
'class': 'blocklyFlyout',
'tabindex': '0',
});
this.svgGroup_.style.display = 'none';
this.svgBackground_ = dom.createSvgElement(
Expand All @@ -321,9 +317,6 @@ export abstract class Flyout
this.workspace_
.getThemeManager()
.subscribe(this.svgBackground_, 'flyoutOpacity', 'fill-opacity');

getFocusManager().registerTree(this);

return this.svgGroup_;
}

Expand Down Expand Up @@ -405,7 +398,6 @@ export abstract class Flyout
if (this.svgGroup_) {
dom.removeNode(this.svgGroup_);
}
getFocusManager().unregisterTree(this);
}

/**
Expand Down Expand Up @@ -969,63 +961,4 @@ export abstract class Flyout

return null;
}

/** See IFocusableNode.getFocusableElement. */
getFocusableElement(): HTMLElement | SVGElement {
if (!this.svgGroup_) throw new Error('Flyout DOM is not yet created.');
return this.svgGroup_;
}

/** See IFocusableNode.getFocusableTree. */
getFocusableTree(): IFocusableTree {
return this;
}

/** See IFocusableNode.onNodeFocus. */
onNodeFocus(): void {}

/** See IFocusableNode.onNodeBlur. */
onNodeBlur(): void {}

/** See IFocusableTree.getRootFocusableNode. */
getRootFocusableNode(): IFocusableNode {
return this;
}

/** See IFocusableTree.getRestoredFocusableNode. */
getRestoredFocusableNode(
_previousNode: IFocusableNode | null,
): IFocusableNode | null {
return null;
}

/** See IFocusableTree.getNestedTrees. */
getNestedTrees(): Array<IFocusableTree> {
return [this.workspace_];
}

/** See IFocusableTree.lookUpFocusableNode. */
lookUpFocusableNode(_id: string): IFocusableNode | null {
// No focusable node needs to be returned since the flyout's subtree is a
// workspace that will manage its own focusable state.
return null;
}

/** See IFocusableTree.onTreeFocus. */
onTreeFocus(
_node: IFocusableNode,
_previousTree: IFocusableTree | null,
): void {}

/** See IFocusableTree.onTreeBlur. */
onTreeBlur(nextTree: IFocusableTree | null): void {
const toolbox = this.targetWorkspace.getToolbox();
// If focus is moving to either the toolbox or the flyout's workspace, do
// not close the flyout. For anything else, do close it since the flyout is
// no longer focused.
if (toolbox && nextTree === toolbox) return;
if (nextTree == this.workspace_) return;
if (toolbox) toolbox.clearSelection();
this.autoHide(false);
}
}
3 changes: 1 addition & 2 deletions core/interfaces/i_flyout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,12 @@ import type {Coordinate} from '../utils/coordinate.js';
import type {Svg} from '../utils/svg.js';
import type {FlyoutDefinition} from '../utils/toolbox.js';
import type {WorkspaceSvg} from '../workspace_svg.js';
import {IFocusableTree} from './i_focusable_tree.js';
import type {IRegistrable} from './i_registrable.js';

/**
* Interface for a flyout.
*/
export interface IFlyout extends IRegistrable, IFocusableTree {
export interface IFlyout extends IRegistrable {
/** Whether the flyout is laid out horizontally or not. */
horizontalLayout: boolean;

Expand Down
3 changes: 1 addition & 2 deletions core/interfaces/i_toolbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@
import type {ToolboxInfo} from '../utils/toolbox.js';
import type {WorkspaceSvg} from '../workspace_svg.js';
import type {IFlyout} from './i_flyout.js';
import type {IFocusableTree} from './i_focusable_tree.js';
import type {IRegistrable} from './i_registrable.js';
import type {IToolboxItem} from './i_toolbox_item.js';

/**
* Interface for a toolbox.
*/
export interface IToolbox extends IRegistrable, IFocusableTree {
export interface IToolbox extends IRegistrable {
/** Initializes the toolbox. */
init(): void;

Expand Down
4 changes: 1 addition & 3 deletions core/interfaces/i_toolbox_item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@

// Former goog.module ID: Blockly.IToolboxItem

import type {IFocusableNode} from './i_focusable_node.js';

/**
* Interface for an item in the toolbox.
*/
export interface IToolboxItem extends IFocusableNode {
export interface IToolboxItem {
/**
* Initializes the toolbox item.
* This includes creating the DOM and updating the state of any items based
Expand Down
2 changes: 0 additions & 2 deletions core/toolbox/category.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,6 @@ export class ToolboxCategory
*/
protected createContainer_(): HTMLDivElement {
const container = document.createElement('div');
container.tabIndex = -1;
container.id = this.getId();
const className = this.cssConfig_['container'];
if (className) {
dom.addClass(container, className);
Expand Down
2 changes: 0 additions & 2 deletions core/toolbox/separator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ export class ToolboxSeparator extends ToolboxItem {
*/
protected createDom_(): HTMLDivElement {
const container = document.createElement('div');
container.tabIndex = -1;
container.id = this.getId();
const className = this.cssConfig_['container'];
if (className) {
dom.addClass(container, className);
Expand Down
77 changes: 2 additions & 75 deletions core/toolbox/toolbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,11 @@ import {DeleteArea} from '../delete_area.js';
import '../events/events_toolbox_item_select.js';
import {EventType} from '../events/type.js';
import * as eventUtils from '../events/utils.js';
import {getFocusManager} from '../focus_manager.js';
import type {IAutoHideable} from '../interfaces/i_autohideable.js';
import type {ICollapsibleToolboxItem} from '../interfaces/i_collapsible_toolbox_item.js';
import {isDeletable} from '../interfaces/i_deletable.js';
import type {IDraggable} from '../interfaces/i_draggable.js';
import type {IFlyout} from '../interfaces/i_flyout.js';
import type {IFocusableNode} from '../interfaces/i_focusable_node.js';
import type {IFocusableTree} from '../interfaces/i_focusable_tree.js';
import type {IKeyboardAccessible} from '../interfaces/i_keyboard_accessible.js';
import type {ISelectableToolboxItem} from '../interfaces/i_selectable_toolbox_item.js';
import {isSelectableToolboxItem} from '../interfaces/i_selectable_toolbox_item.js';
Expand All @@ -54,12 +51,7 @@ import {CollapsibleToolboxCategory} from './collapsible_category.js';
*/
export class Toolbox
extends DeleteArea
implements
IAutoHideable,
IKeyboardAccessible,
IStyleable,
IToolbox,
IFocusableNode
implements IAutoHideable, IKeyboardAccessible, IStyleable, IToolbox
{
/**
* The unique ID for this component that is used to register with the
Expand Down Expand Up @@ -171,7 +163,6 @@ export class Toolbox
ComponentManager.Capability.DRAG_TARGET,
],
});
getFocusManager().registerTree(this);
}

/**
Expand All @@ -186,6 +177,7 @@ export class Toolbox
const container = this.createContainer_();

this.contentsDiv_ = this.createContentsContainer_();
this.contentsDiv_.tabIndex = 0;
aria.setRole(this.contentsDiv_, aria.Role.TREE);
container.appendChild(this.contentsDiv_);

Expand All @@ -202,7 +194,6 @@ export class Toolbox
*/
protected createContainer_(): HTMLDivElement {
const toolboxContainer = document.createElement('div');
toolboxContainer.tabIndex = 0;
toolboxContainer.setAttribute('layout', this.isHorizontal() ? 'h' : 'v');
dom.addClass(toolboxContainer, 'blocklyToolbox');
toolboxContainer.setAttribute('dir', this.RTL ? 'RTL' : 'LTR');
Expand Down Expand Up @@ -1086,71 +1077,7 @@ export class Toolbox
this.workspace_.getThemeManager().unsubscribe(this.HtmlDiv);
dom.removeNode(this.HtmlDiv);
}

getFocusManager().unregisterTree(this);
}

/** See IFocusableNode.getFocusableElement. */
getFocusableElement(): HTMLElement | SVGElement {
if (!this.HtmlDiv) throw Error('Toolbox DOM has not yet been created.');
return this.HtmlDiv;
}

/** See IFocusableNode.getFocusableTree. */
getFocusableTree(): IFocusableTree {
return this;
}

/** See IFocusableNode.onNodeFocus. */
onNodeFocus(): void {}

/** See IFocusableNode.onNodeBlur. */
onNodeBlur(): void {}

/** See IFocusableTree.getRootFocusableNode. */
getRootFocusableNode(): IFocusableNode {
return this;
}

/** See IFocusableTree.getRestoredFocusableNode. */
getRestoredFocusableNode(
previousNode: IFocusableNode | null,
): IFocusableNode | null {
// Always try to select the first selectable toolbox item rather than the
// root of the toolbox.
if (!previousNode || previousNode === this) {
return this.getToolboxItems().find((item) => item.isSelectable()) ?? null;
}
return null;
}

/** See IFocusableTree.getNestedTrees. */
getNestedTrees(): Array<IFocusableTree> {
return [];
}

/** See IFocusableTree.lookUpFocusableNode. */
lookUpFocusableNode(id: string): IFocusableNode | null {
return this.getToolboxItemById(id) as IFocusableNode;
}

/** See IFocusableTree.onTreeFocus. */
onTreeFocus(
node: IFocusableNode,
_previousTree: IFocusableTree | null,
): void {
if (node !== this) {
// Only select the item if it isn't already selected so as to not toggle.
if (this.getSelectedItem() !== node) {
this.setSelectedItem(node as IToolboxItem);
}
} else {
this.clearSelection();
}
}

/** See IFocusableTree.onTreeBlur. */
onTreeBlur(_nextTree: IFocusableTree | null): void {}
}

/** CSS for Toolbox. See css.js for use. */
Expand Down
24 changes: 0 additions & 24 deletions core/toolbox/toolbox_item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
// Former goog.module ID: Blockly.ToolboxItem

import type {ICollapsibleToolboxItem} from '../interfaces/i_collapsible_toolbox_item.js';
import type {IFocusableTree} from '../interfaces/i_focusable_tree.js';
import type {IToolbox} from '../interfaces/i_toolbox.js';
import type {IToolboxItem} from '../interfaces/i_toolbox_item.js';
import * as idGenerator from '../utils/idgenerator.js';
Expand Down Expand Up @@ -149,28 +148,5 @@ export class ToolboxItem implements IToolboxItem {
* @param _isVisible True if category should be visible.
*/
setVisible_(_isVisible: boolean) {}

/** See IFocusableNode.getFocusableElement. */
getFocusableElement(): HTMLElement | SVGElement {
const div = this.getDiv();
if (!div) {
throw Error('Trying to access toolbox item before DOM is initialized.');
}
if (!(div instanceof HTMLElement)) {
throw Error('Toolbox item div is unexpectedly not an HTML element.');
}
return div as HTMLElement;
}

/** See IFocusableNode.getFocusableTree. */
getFocusableTree(): IFocusableTree {
return this.parentToolbox_;
}

/** See IFocusableNode.onNodeFocus. */
onNodeFocus(): void {}

/** See IFocusableNode.onNodeBlur. */
onNodeBlur(): void {}
}
// nop by default
14 changes: 1 addition & 13 deletions core/workspace_svg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2690,19 +2690,7 @@ export class WorkspaceSvg
): void {}

/** See IFocusableTree.onTreeBlur. */
onTreeBlur(nextTree: IFocusableTree | null): void {
// If the flyout loses focus, make sure to close it.
if (this.isFlyout && this.targetWorkspace) {
// Only hide the flyout if the flyout's workspace is losing focus and that
// focus isn't returning to the flyout itself or the toolbox.
const flyout = this.targetWorkspace.getFlyout();
const toolbox = this.targetWorkspace.getToolbox();
if (flyout && nextTree === flyout) return;
if (toolbox && nextTree === toolbox) return;
if (toolbox) toolbox.clearSelection();
if (flyout && flyout instanceof Flyout) flyout.autoHide(false);
}
}
onTreeBlur(_nextTree: IFocusableTree | null): void {}
}

/**
Expand Down
3 changes: 0 additions & 3 deletions tests/mocha/toolbox_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ suite('Toolbox', function () {
const themeManagerSpy = sinon.spy(themeManager, 'subscribe');
const componentManager = this.toolbox.workspace_.getComponentManager();
sinon.stub(componentManager, 'addComponent');
this.toolbox.dispose(); // Dispose of the old toolbox so that it can be reinited.
this.toolbox.init();
sinon.assert.calledWith(
themeManagerSpy,
Expand All @@ -73,14 +72,12 @@ suite('Toolbox', function () {
const renderSpy = sinon.spy(this.toolbox, 'render');
const componentManager = this.toolbox.workspace_.getComponentManager();
sinon.stub(componentManager, 'addComponent');
this.toolbox.dispose(); // Dispose of the old toolbox so that it can be reinited.
this.toolbox.init();
sinon.assert.calledOnce(renderSpy);
});
test('Init called -> Flyout is initialized', function () {
const componentManager = this.toolbox.workspace_.getComponentManager();
sinon.stub(componentManager, 'addComponent');
this.toolbox.dispose(); // Dispose of the old toolbox so that it can be reinited.
this.toolbox.init();
assert.isDefined(this.toolbox.getFlyout());
});
Expand Down
Loading