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:
SteVen Batten 2019-02-19 17:47:50 +01:00 committed by GitHub
parent ba304fe32c
commit e5b1616d77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 18 additions and 12 deletions

View file

@ -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 = /(?<!&amp;)(?:&amp;)(\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(/&amp;&amp;/g, '&amp;');
this.item.setAttribute('aria-keyshortcuts', (!!matches[1] ? matches[1] : matches[2]).toLocaleLowerCase());
} else {
label = label.replace(/&&/g, '&');
}
}

View file

@ -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(/&amp;&amp;/g, '&amp;') :
cleanMenuLabel.replace(/&&/g, '&');
let mnemonicMatches = MENU_MNEMONIC_REGEX.exec(label);

View file

@ -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 === '&' ? '&&' : '&');
}
/**

View file

@ -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]) });
}
}
}