Skip to content

Commit 49406cd

Browse files
authored
Merge branch 'main' into update-gh-pages-deployment-for-screen-reader-experiment
2 parents 47b585c + 10d7bba commit 49406cd

File tree

3 files changed

+85
-68
lines changed

3 files changed

+85
-68
lines changed

src/constants.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export enum SHORTCUT_NAMES {
3535
LEFT = 'left',
3636
NEXT_STACK = 'next_stack',
3737
PREVIOUS_STACK = 'previous_stack',
38+
// Unused.
3839
INSERT = 'insert',
3940
EDIT_OR_CONFIRM = 'edit_or_confirm',
4041
DISCONNECT = 'disconnect',
@@ -52,8 +53,16 @@ export enum SHORTCUT_NAMES {
5253
CREATE_WS_CURSOR = 'to_workspace',
5354
LIST_SHORTCUTS = 'list_shortcuts',
5455
CLEAN_UP = 'clean_up_workspace',
56+
START_MOVE = 'start_move',
5557
}
5658

59+
export const SHORTCUT_NAMES_TO_DISPLAY_TEXT: Record<string, string> = {
60+
'keyboard_nav_copy': Msg['Copy'] || 'Copy',
61+
'keyboard_nav_cut': Msg['Cut'] || 'Cut',
62+
'keyboard_nav_paste': Msg['Paste'] || 'Paste',
63+
'start_move': Msg['MOVE_BLOCK'] || 'Move',
64+
};
65+
5766
/**
5867
* Types of possible messages passed into the loggingCallback in the Navigation
5968
* class.
@@ -73,7 +82,7 @@ export const SHORTCUT_CATEGORIES: Record<
7382
// Also allow undo/redo. Document the non-keyboard-nav versions of others for
7483
// better text because temporarily the name in the table is derived from
7584
// these id-like names.
76-
Array<SHORTCUT_NAMES | 'undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'delete'>
85+
Array<SHORTCUT_NAMES | 'undo' | 'redo' | 'delete'>
7786
> = {};
7887

7988
SHORTCUT_CATEGORIES[Msg['SHORTCUTS_GENERAL']] = [
@@ -86,12 +95,12 @@ SHORTCUT_CATEGORIES[Msg['SHORTCUTS_GENERAL']] = [
8695
];
8796

8897
SHORTCUT_CATEGORIES[Msg['SHORTCUTS_EDITING']] = [
89-
SHORTCUT_NAMES.INSERT,
9098
'delete',
9199
SHORTCUT_NAMES.DISCONNECT,
92-
'cut',
93-
'copy',
94-
'paste',
100+
SHORTCUT_NAMES.START_MOVE,
101+
SHORTCUT_NAMES.CUT,
102+
SHORTCUT_NAMES.COPY,
103+
SHORTCUT_NAMES.PASTE,
95104
SHORTCUT_NAMES.DUPLICATE,
96105
'undo',
97106
'redo',
@@ -104,4 +113,5 @@ SHORTCUT_CATEGORIES[Msg['SHORTCUTS_CODE_NAVIGATION']] = [
104113
SHORTCUT_NAMES.LEFT,
105114
SHORTCUT_NAMES.NEXT_STACK,
106115
SHORTCUT_NAMES.PREVIOUS_STACK,
116+
SHORTCUT_NAMES.CREATE_WS_CURSOR,
107117
];

src/keyboard_drag_strategy.ts

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ export class KeyboardDragStrategy extends dragging.BlockDragStrategy {
3636
/** Where a constrained movement should start when traversing the tree. */
3737
private searchNode: RenderedConnection | null = null;
3838

39+
/** List of all connections available on the workspace. */
40+
private allConnections: RenderedConnection[] = [];
41+
3942
constructor(
4043
private block: BlockSvg,
4144
public moveType: MoveType,
@@ -46,6 +49,22 @@ export class KeyboardDragStrategy extends dragging.BlockDragStrategy {
4649

4750
override startDrag(e?: PointerEvent) {
4851
super.startDrag(e);
52+
53+
for (const topBlock of this.block.workspace.getTopBlocks(true)) {
54+
this.allConnections.push(
55+
...topBlock
56+
.getDescendants(true)
57+
.flatMap((block: BlockSvg) => block.getConnections_(false))
58+
.sort((a: RenderedConnection, b: RenderedConnection) => {
59+
let delta = a.y - b.y;
60+
if (delta === 0) {
61+
delta = a.x - b.x;
62+
}
63+
return delta;
64+
}),
65+
);
66+
}
67+
4968
// Set position of the dragging block, so that it doesn't pop
5069
// to the top left of the workspace.
5170
// @ts-expect-error block and startLoc are private.
@@ -91,6 +110,7 @@ export class KeyboardDragStrategy extends dragging.BlockDragStrategy {
91110

92111
override endDrag(e?: PointerEvent) {
93112
super.endDrag(e);
113+
this.allConnections = [];
94114
this.block.removeIcon(MoveIcon.type);
95115
}
96116

@@ -168,31 +188,17 @@ export class KeyboardDragStrategy extends dragging.BlockDragStrategy {
168188
const connectionChecker = draggingBlock.workspace.connectionChecker;
169189
let candidateConnection: ConnectionCandidate | null = null;
170190
let potential: RenderedConnection | null = this.searchNode;
171-
const allConnections: RenderedConnection[] = [];
172-
for (const topBlock of draggingBlock.workspace.getTopBlocks(true)) {
173-
allConnections.push(
174-
...topBlock
175-
.getDescendants(true)
176-
.flatMap((block: BlockSvg) => block.getConnections_(false))
177-
.sort((a: RenderedConnection, b: RenderedConnection) => {
178-
let delta = a.y - b.y;
179-
if (delta === 0) {
180-
delta = a.x - b.x;
181-
}
182-
return delta;
183-
}),
184-
);
185-
}
186191

187192
const dir = this.currentDragDirection;
188193
while (potential && !candidateConnection) {
189-
const potentialIndex = allConnections.indexOf(potential);
194+
const potentialIndex = this.allConnections.indexOf(potential);
190195
if (dir === Direction.Up || dir === Direction.Left) {
191196
potential =
192-
allConnections[potentialIndex - 1] ??
193-
allConnections[allConnections.length - 1];
197+
this.allConnections[potentialIndex - 1] ??
198+
this.allConnections[this.allConnections.length - 1];
194199
} else if (dir === Direction.Down || dir === Direction.Right) {
195-
potential = allConnections[potentialIndex + 1] ?? allConnections[0];
200+
potential =
201+
this.allConnections[potentialIndex + 1] ?? this.allConnections[0];
196202
}
197203

198204
localConns.forEach((conn: RenderedConnection) => {

src/shortcut_dialog.ts

Lines changed: 45 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,6 @@ export class ShortcutDialog {
5252
}
5353
}
5454

55-
/**
56-
* Update the modifier key to the user's specific platform.
57-
*/
58-
updatePlatformName() {
59-
const platform = this.getPlatform();
60-
const platformEl = this.outputDiv
61-
? this.outputDiv.querySelector('.platform')
62-
: null;
63-
if (platformEl) {
64-
platformEl.textContent = platform;
65-
}
66-
}
67-
6855
toggle(workspace: Blockly.WorkspaceSvg) {
6956
clearHelpHint(workspace);
7057
this.toggleInternal();
@@ -88,54 +75,56 @@ export class ShortcutDialog {
8875
* @returns A title case version of the name.
8976
*/
9077
getReadableShortcutName(shortcutName: string) {
78+
if (Constants.SHORTCUT_NAMES_TO_DISPLAY_TEXT[shortcutName]) {
79+
return Constants.SHORTCUT_NAMES_TO_DISPLAY_TEXT[shortcutName];
80+
}
9181
return upperCaseFirst(shortcutName.replace(/_/gi, ' '));
9282
}
9383

9484
/**
9585
* List all currently registered shortcuts as a table.
9686
*/
9787
createModalContent() {
98-
let modalContents = `<div class="modal-container">
99-
<dialog class="shortcut-modal">
100-
<div class="shortcut-container" tabindex="0">
101-
<div class="header">
102-
<button class="close-modal">
103-
<span class="material-symbols-outlined">close</span>
104-
</button>
105-
<h1>Keyboard shortcuts – <span class="platform">Windows</span></h1>
106-
</div>
107-
<div class="shortcut-tables">`;
88+
let shortcutTables = ``;
10889

10990
// Display shortcuts by their categories.
11091
for (const [key, categoryShortcuts] of Object.entries(
11192
Constants.SHORTCUT_CATEGORIES,
11293
)) {
113-
modalContents += `
114-
<table class="shortcut-table">
115-
<tbody>
116-
<tr class="category"><th colspan="3"><h2>${key}</h2></th></tr>
117-
<tr>
118-
`;
119-
94+
let shortcutTableRows = ``;
12095
for (const keyboardShortcut of categoryShortcuts) {
121-
modalContents += `
122-
<td>${this.getReadableShortcutName(keyboardShortcut)}</td>
123-
<td>${this.actionShortcutsToHTML(keyboardShortcut)}</td>
124-
</tr>`;
96+
shortcutTableRows += this.getTableRowForShortcut(
97+
keyboardShortcut as string,
98+
);
12599
}
126-
modalContents += '</tr></tbody></table>';
100+
shortcutTables += `
101+
<table class="shortcut-table">
102+
<tbody>
103+
<tr class="category"><th colspan="3"><h2>${key}</h2></th></tr>
104+
${shortcutTableRows}
105+
</tbody>
106+
</table>`;
127107
}
108+
109+
const modalContents = `<div class="modal-container">
110+
<dialog class="shortcut-modal">
111+
<div class="shortcut-container" tabindex="0">
112+
<div class="header">
113+
<button class="close-modal">
114+
<span class="material-symbols-outlined">close</span>
115+
</button>
116+
<h1>${Msg['SHORTCUTS_HELP_HEADER'] || 'Keyboard shortcuts'} – <span class="platform">${this.getPlatform()}</span></h1>
117+
</div>
118+
<div class="shortcut-tables">
119+
${shortcutTables}
120+
</div>
121+
</dialog>
122+
</div>`;
128123
if (this.outputDiv) {
129-
this.outputDiv.innerHTML =
130-
modalContents +
131-
`</div>
132-
</dialog>
133-
</div>`;
124+
this.outputDiv.innerHTML = modalContents;
134125
this.modalContainer = this.outputDiv.querySelector('.modal-container');
135126
this.shortcutDialog = this.outputDiv.querySelector('.shortcut-modal');
136127
this.closeButton = this.outputDiv.querySelector('.close-modal');
137-
this.updatePlatformName();
138-
// Can we also intercept the Esc key to dismiss.
139128
if (this.closeButton) {
140129
this.closeButton.addEventListener('click', (e) => {
141130
this.toggleInternal();
@@ -144,13 +133,25 @@ export class ShortcutDialog {
144133
}
145134
}
146135

136+
private getTableRowForShortcut(keyboardShortcut: string) {
137+
const name = this.getReadableShortcutName(keyboardShortcut);
138+
const keys = this.actionShortcutsToHTML(keyboardShortcut);
139+
if (!name || !keys) return '';
140+
return `
141+
<tr>
142+
<td>${name}</td>
143+
<td>${keys}</td>
144+
</tr>`;
145+
}
146+
147147
private actionShortcutsToHTML(action: string) {
148148
const shortcuts = getLongActionShortcutsAsKeys(action);
149-
return shortcuts.map((keys) => this.actionShortcutToHTML(keys)).join(' / ');
149+
return shortcuts.map((keys) => this.keysToHTML(keys)).join(' / ');
150150
}
151151

152-
private actionShortcutToHTML(keys: string[]) {
152+
private keysToHTML(keys: string[]) {
153153
const separator = navigator.platform.startsWith('Mac') ? '' : ' + ';
154+
if (!keys || !keys.length) return '';
154155
return [
155156
`<span class="shortcut-combo">`,
156157
...keys.map((key, index) => {

0 commit comments

Comments
 (0)