mirror of
https://github.com/Microsoft/vscode
synced 2024-09-19 18:48:00 +00:00
Handle mnemonic escaping (#68196)
* handle mnemonic escapes * Update src/vs/workbench/electron-browser/main.contribution.ts * update custom menu and recent items list to support escaped mnemonics * remove need for &&& * qfix
This commit is contained in:
parent
ba304fe32c
commit
e5b1616d77
|
@ -20,8 +20,8 @@ import { Event, Emitter } from 'vs/base/common/event';
|
|||
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { isLinux } from 'vs/base/common/platform';
|
||||
|
||||
export const MENU_MNEMONIC_REGEX: RegExp = /\(&{1,2}(.)\)|&{1,2}(.)/;
|
||||
export const MENU_ESCAPED_MNEMONIC_REGEX: RegExp = /(?:&){1,2}(.)/;
|
||||
export const MENU_MNEMONIC_REGEX: RegExp = /\(&(\w)\)|(?<!&)&(\w)/;
|
||||
export const MENU_ESCAPED_MNEMONIC_REGEX: RegExp = /(?<!&)(?:&)(\w)/;
|
||||
|
||||
export interface IMenuOptions {
|
||||
context?: any;
|
||||
|
@ -440,13 +440,16 @@ class MenuActionItem extends BaseActionItem {
|
|||
label = cleanLabel;
|
||||
}
|
||||
|
||||
this.label.setAttribute('aria-label', cleanLabel);
|
||||
this.label.setAttribute('aria-label', cleanLabel.replace(/&&/g, '&'));
|
||||
|
||||
const matches = MENU_MNEMONIC_REGEX.exec(label);
|
||||
|
||||
if (matches) {
|
||||
label = strings.escape(label).replace(MENU_ESCAPED_MNEMONIC_REGEX, '<u aria-hidden="true">$1</u>');
|
||||
label = label.replace(/&&/g, '&');
|
||||
this.item.setAttribute('aria-keyshortcuts', (!!matches[1] ? matches[1] : matches[2]).toLocaleLowerCase());
|
||||
} else {
|
||||
label = label.replace(/&&/g, '&');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -457,8 +457,8 @@ export class MenuBar extends Disposable {
|
|||
|
||||
// Update the button label to reflect mnemonics
|
||||
titleElement.innerHTML = this.options.enableMnemonics ?
|
||||
strings.escape(label).replace(MENU_ESCAPED_MNEMONIC_REGEX, '<mnemonic aria-hidden="true">$1</mnemonic>') :
|
||||
cleanMenuLabel;
|
||||
strings.escape(label).replace(MENU_ESCAPED_MNEMONIC_REGEX, '<mnemonic aria-hidden="true">$1</mnemonic>').replace(/&&/g, '&') :
|
||||
cleanMenuLabel.replace(/&&/g, '&');
|
||||
|
||||
let mnemonicMatches = MENU_MNEMONIC_REGEX.exec(label);
|
||||
|
||||
|
|
|
@ -356,10 +356,10 @@ export function template(template: string, values: { [key: string]: string | ISe
|
|||
*/
|
||||
export function mnemonicMenuLabel(label: string, forceDisableMnemonics?: boolean): string {
|
||||
if (isMacintosh || forceDisableMnemonics) {
|
||||
return label.replace(/\(&&\w\)|&&/g, '');
|
||||
return label.replace(/\(&&\w\)|&&/g, '').replace(/&/g, isMacintosh ? '&' : '&&');
|
||||
}
|
||||
|
||||
return label.replace(/&&/g, '&');
|
||||
return label.replace(/&&|&/g, m => m === '&' ? '&&' : '&');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -32,6 +32,7 @@ import { MenuBar } from 'vs/base/browser/ui/menu/menubar';
|
|||
import { SubmenuAction } from 'vs/base/browser/ui/menu/menu';
|
||||
import { attachMenuStyler } from 'vs/platform/theme/common/styler';
|
||||
import { assign } from 'vs/base/common/objects';
|
||||
import { mnemonicMenuLabel, unmnemonicLabel } from 'vs/base/common/labels';
|
||||
import { getAccessibilitySupport } from 'vs/base/browser/browser';
|
||||
|
||||
export class MenubarControl extends Disposable {
|
||||
|
@ -375,6 +376,8 @@ export class MenubarControl extends Disposable {
|
|||
typeHint = 'file';
|
||||
}
|
||||
|
||||
label = unmnemonicLabel(label);
|
||||
|
||||
const ret: IAction = new Action(commandId, label, undefined, undefined, (event) => {
|
||||
const openInNewWindow = event && ((!isMacintosh && (event.ctrlKey || event.shiftKey)) || (isMacintosh && (event.metaKey || event.altKey)));
|
||||
|
||||
|
@ -517,10 +520,10 @@ export class MenubarControl extends Disposable {
|
|||
const submenu = this.menuService.createMenu(action.item.submenu, this.contextKeyService);
|
||||
const submenuActions: SubmenuAction[] = [];
|
||||
updateActions(submenu, submenuActions);
|
||||
target.push(new SubmenuAction(action.label, submenuActions));
|
||||
target.push(new SubmenuAction(mnemonicMenuLabel(action.label), submenuActions));
|
||||
submenu.dispose();
|
||||
} else {
|
||||
action.label = this.calculateActionLabel(action);
|
||||
action.label = mnemonicMenuLabel(this.calculateActionLabel(action));
|
||||
target.push(action);
|
||||
}
|
||||
}
|
||||
|
@ -537,7 +540,7 @@ export class MenubarControl extends Disposable {
|
|||
this._register(menu.onDidChange(() => {
|
||||
const actions = [];
|
||||
updateActions(menu, actions);
|
||||
this.menubar.updateMenu({ actions: actions, label: this.topLevelTitles[title] });
|
||||
this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) });
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -545,9 +548,9 @@ export class MenubarControl extends Disposable {
|
|||
updateActions(menu, actions);
|
||||
|
||||
if (!firstTime) {
|
||||
this.menubar.updateMenu({ actions: actions, label: this.topLevelTitles[title] });
|
||||
this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) });
|
||||
} else {
|
||||
this.menubar.push({ actions: actions, label: this.topLevelTitles[title] });
|
||||
this.menubar.push({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue