mirror of
https://github.com/google/blockly.git
synced 2026-01-06 08:30:13 +01:00
refactor!: Remove old cursor and tab support. (#8803)
This commit is contained in:
@@ -34,7 +34,6 @@ import {BlockDragStrategy} from './dragging/block_drag_strategy.js';
|
||||
import type {BlockMove} from './events/events_block_move.js';
|
||||
import {EventType} from './events/type.js';
|
||||
import * as eventUtils from './events/utils.js';
|
||||
import type {Field} from './field.js';
|
||||
import {FieldLabel} from './field_label.js';
|
||||
import {IconType} from './icons/icon_types.js';
|
||||
import {MutatorIcon} from './icons/mutator_icon.js';
|
||||
@@ -46,8 +45,6 @@ import type {ICopyable} from './interfaces/i_copyable.js';
|
||||
import type {IDragStrategy, IDraggable} from './interfaces/i_draggable.js';
|
||||
import {IIcon} from './interfaces/i_icon.js';
|
||||
import * as internalConstants from './internal_constants.js';
|
||||
import {ASTNode} from './keyboard_nav/ast_node.js';
|
||||
import {TabNavigateCursor} from './keyboard_nav/tab_navigate_cursor.js';
|
||||
import {MarkerManager} from './marker_manager.js';
|
||||
import {Msg} from './msg.js';
|
||||
import * as renderManagement from './render_management.js';
|
||||
@@ -550,35 +547,6 @@ export class BlockSvg
|
||||
input.appendField(new FieldLabel(text), collapsedFieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the next (or previous) FieldTextInput.
|
||||
*
|
||||
* @param start Current field.
|
||||
* @param forward If true go forward, otherwise backward.
|
||||
*/
|
||||
tab(start: Field, forward: boolean) {
|
||||
const tabCursor = new TabNavigateCursor();
|
||||
tabCursor.setCurNode(ASTNode.createFieldNode(start)!);
|
||||
const currentNode = tabCursor.getCurNode();
|
||||
|
||||
if (forward) {
|
||||
tabCursor.next();
|
||||
} else {
|
||||
tabCursor.prev();
|
||||
}
|
||||
|
||||
const nextNode = tabCursor.getCurNode();
|
||||
if (nextNode && nextNode !== currentNode) {
|
||||
const nextField = nextNode.getLocation() as Field;
|
||||
nextField.showEditor();
|
||||
|
||||
// Also move the cursor if we're in keyboard nav mode.
|
||||
if (this.workspace.keyboardAccessibilityMode) {
|
||||
this.workspace.getCursor()!.setCurNode(nextNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a pointerdown on an SVG block.
|
||||
*
|
||||
|
||||
@@ -169,10 +169,8 @@ import {IVariableMap} from './interfaces/i_variable_map.js';
|
||||
import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js';
|
||||
import * as internalConstants from './internal_constants.js';
|
||||
import {ASTNode} from './keyboard_nav/ast_node.js';
|
||||
import {BasicCursor} from './keyboard_nav/basic_cursor.js';
|
||||
import {Cursor} from './keyboard_nav/cursor.js';
|
||||
import {Marker} from './keyboard_nav/marker.js';
|
||||
import {TabNavigateCursor} from './keyboard_nav/tab_navigate_cursor.js';
|
||||
import type {LayerManager} from './layer_manager.js';
|
||||
import * as layers from './layers.js';
|
||||
import {MarkerManager} from './marker_manager.js';
|
||||
@@ -432,7 +430,6 @@ Names.prototype.populateProcedures = function (
|
||||
// Re-export submodules that no longer declareLegacyNamespace.
|
||||
export {
|
||||
ASTNode,
|
||||
BasicCursor,
|
||||
Block,
|
||||
BlockSvg,
|
||||
BlocklyOptions,
|
||||
@@ -589,7 +586,6 @@ export {
|
||||
ScrollbarPair,
|
||||
SeparatorFlyoutInflater,
|
||||
ShortcutRegistry,
|
||||
TabNavigateCursor,
|
||||
Theme,
|
||||
ThemeManager,
|
||||
Toolbox,
|
||||
|
||||
@@ -1331,15 +1331,6 @@ export abstract class Field<T = any>
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the field is tab navigable.
|
||||
*
|
||||
* @returns True if the field is tab navigable.
|
||||
*/
|
||||
isTabNavigable(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the given keyboard shortcut.
|
||||
*
|
||||
|
||||
@@ -562,11 +562,6 @@ export abstract class FieldInput<T extends InputTypes> extends Field<
|
||||
);
|
||||
WidgetDiv.hideIfOwner(this);
|
||||
dropDownDiv.hideWithoutAnimation();
|
||||
} else if (e.key === 'Tab') {
|
||||
WidgetDiv.hideIfOwner(this);
|
||||
dropDownDiv.hideWithoutAnimation();
|
||||
(this.sourceBlock_ as BlockSvg).tab(this, !e.shiftKey);
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,15 +669,6 @@ export abstract class FieldInput<T extends InputTypes> extends Field<
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the field is tab navigable.
|
||||
*
|
||||
* @returns True if the field is tab navigable.
|
||||
*/
|
||||
override isTabNavigable(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the `getText_` developer hook to override the field's text
|
||||
* representation. When we're currently editing, return the current HTML value
|
||||
|
||||
@@ -1,222 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2019 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* The class representing a basic cursor.
|
||||
* Used to demo switching between different cursors.
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
// Former goog.module ID: Blockly.BasicCursor
|
||||
|
||||
import * as registry from '../registry.js';
|
||||
import {ASTNode} from './ast_node.js';
|
||||
import {Cursor} from './cursor.js';
|
||||
|
||||
/**
|
||||
* Class for a basic cursor.
|
||||
* This will allow the user to get to all nodes in the AST by hitting next or
|
||||
* previous.
|
||||
*/
|
||||
export class BasicCursor extends Cursor {
|
||||
/** Name used for registering a basic cursor. */
|
||||
static readonly registrationName = 'basicCursor';
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the next node in the pre order traversal.
|
||||
*
|
||||
* @returns The next node, or null if the current node is not set or there is
|
||||
* no next value.
|
||||
*/
|
||||
override next(): ASTNode | null {
|
||||
const curNode = this.getCurNode();
|
||||
if (!curNode) {
|
||||
return null;
|
||||
}
|
||||
const newNode = this.getNextNode_(curNode, this.validNode_);
|
||||
|
||||
if (newNode) {
|
||||
this.setCurNode(newNode);
|
||||
}
|
||||
return newNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* For a basic cursor we only have the ability to go next and previous, so
|
||||
* in will also allow the user to get to the next node in the pre order
|
||||
* traversal.
|
||||
*
|
||||
* @returns The next node, or null if the current node is not set or there is
|
||||
* no next value.
|
||||
*/
|
||||
override in(): ASTNode | null {
|
||||
return this.next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the previous node in the pre order traversal.
|
||||
*
|
||||
* @returns The previous node, or null if the current node is not set or there
|
||||
* is no previous value.
|
||||
*/
|
||||
override prev(): ASTNode | null {
|
||||
const curNode = this.getCurNode();
|
||||
if (!curNode) {
|
||||
return null;
|
||||
}
|
||||
const newNode = this.getPreviousNode_(curNode, this.validNode_);
|
||||
|
||||
if (newNode) {
|
||||
this.setCurNode(newNode);
|
||||
}
|
||||
return newNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* For a basic cursor we only have the ability to go next and previous, so
|
||||
* out will allow the user to get to the previous node in the pre order
|
||||
* traversal.
|
||||
*
|
||||
* @returns The previous node, or null if the current node is not set or there
|
||||
* is no previous value.
|
||||
*/
|
||||
override out(): ASTNode | null {
|
||||
return this.prev();
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses pre order traversal to navigate the Blockly AST. This will allow
|
||||
* a user to easily navigate the entire Blockly AST without having to go in
|
||||
* and out levels on the tree.
|
||||
*
|
||||
* @param node The current position in the AST.
|
||||
* @param isValid A function true/false depending on whether the given node
|
||||
* should be traversed.
|
||||
* @returns The next node in the traversal.
|
||||
*/
|
||||
protected getNextNode_(
|
||||
node: ASTNode | null,
|
||||
isValid: (p1: ASTNode | null) => boolean,
|
||||
): ASTNode | null {
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
const newNode = node.in() || node.next();
|
||||
if (isValid(newNode)) {
|
||||
return newNode;
|
||||
} else if (newNode) {
|
||||
return this.getNextNode_(newNode, isValid);
|
||||
}
|
||||
const siblingOrParent = this.findSiblingOrParent(node.out());
|
||||
if (isValid(siblingOrParent)) {
|
||||
return siblingOrParent;
|
||||
} else if (siblingOrParent) {
|
||||
return this.getNextNode_(siblingOrParent, isValid);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses the pre order traversal in order to find the previous node. This
|
||||
* will allow a user to easily navigate the entire Blockly AST without having
|
||||
* to go in and out levels on the tree.
|
||||
*
|
||||
* @param node The current position in the AST.
|
||||
* @param isValid A function true/false depending on whether the given node
|
||||
* should be traversed.
|
||||
* @returns The previous node in the traversal or null if no previous node
|
||||
* exists.
|
||||
*/
|
||||
protected getPreviousNode_(
|
||||
node: ASTNode | null,
|
||||
isValid: (p1: ASTNode | null) => boolean,
|
||||
): ASTNode | null {
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
let newNode: ASTNode | null = node.prev();
|
||||
|
||||
if (newNode) {
|
||||
newNode = this.getRightMostChild(newNode);
|
||||
} else {
|
||||
newNode = node.out();
|
||||
}
|
||||
if (isValid(newNode)) {
|
||||
return newNode;
|
||||
} else if (newNode) {
|
||||
return this.getPreviousNode_(newNode, isValid);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decides what nodes to traverse and which ones to skip. Currently, it
|
||||
* skips output, stack and workspace nodes.
|
||||
*
|
||||
* @param node The AST node to check whether it is valid.
|
||||
* @returns True if the node should be visited, false otherwise.
|
||||
*/
|
||||
protected validNode_(node: ASTNode | null): boolean {
|
||||
let isValid = false;
|
||||
const type = node && node.getType();
|
||||
if (
|
||||
type === ASTNode.types.OUTPUT ||
|
||||
type === ASTNode.types.INPUT ||
|
||||
type === ASTNode.types.FIELD ||
|
||||
type === ASTNode.types.NEXT ||
|
||||
type === ASTNode.types.PREVIOUS ||
|
||||
type === ASTNode.types.WORKSPACE
|
||||
) {
|
||||
isValid = true;
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* From the given node find either the next valid sibling or parent.
|
||||
*
|
||||
* @param node The current position in the AST.
|
||||
* @returns The parent AST node or null if there are no valid parents.
|
||||
*/
|
||||
private findSiblingOrParent(node: ASTNode | null): ASTNode | null {
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
const nextNode = node.next();
|
||||
if (nextNode) {
|
||||
return nextNode;
|
||||
}
|
||||
return this.findSiblingOrParent(node.out());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the right most child of a node.
|
||||
*
|
||||
* @param node The node to find the right most child of.
|
||||
* @returns The right most child of the given node, or the node if no child
|
||||
* exists.
|
||||
*/
|
||||
private getRightMostChild(node: ASTNode | null): ASTNode | null {
|
||||
if (!node!.in()) {
|
||||
return node;
|
||||
}
|
||||
let newNode = node!.in();
|
||||
while (newNode && newNode.next()) {
|
||||
newNode = newNode.next();
|
||||
}
|
||||
return this.getRightMostChild(newNode);
|
||||
}
|
||||
}
|
||||
|
||||
registry.register(
|
||||
registry.Type.CURSOR,
|
||||
BasicCursor.registrationName,
|
||||
BasicCursor,
|
||||
);
|
||||
@@ -1,45 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2019 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* The class representing a cursor that is used to navigate
|
||||
* between tab navigable fields.
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
// Former goog.module ID: Blockly.TabNavigateCursor
|
||||
|
||||
import type {Field} from '../field.js';
|
||||
import {ASTNode} from './ast_node.js';
|
||||
import {BasicCursor} from './basic_cursor.js';
|
||||
|
||||
/**
|
||||
* A cursor for navigating between tab navigable fields.
|
||||
*/
|
||||
export class TabNavigateCursor extends BasicCursor {
|
||||
/**
|
||||
* Skip all nodes except for tab navigable fields.
|
||||
*
|
||||
* @param node The AST node to check whether it is valid.
|
||||
* @returns True if the node should be visited, false otherwise.
|
||||
*/
|
||||
override validNode_(node: ASTNode | null): boolean {
|
||||
let isValid = false;
|
||||
const type = node && node.getType();
|
||||
if (node) {
|
||||
const location = node.getLocation() as Field;
|
||||
if (
|
||||
type === ASTNode.types.FIELD &&
|
||||
location &&
|
||||
location.isTabNavigable() &&
|
||||
location.isClickable()
|
||||
) {
|
||||
isValid = true;
|
||||
}
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user