mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 09:08:48 +01:00
fixes #53217
also just a clean up so there is one source for mnemoic regex
This commit is contained in:
@@ -17,6 +17,9 @@ import { $, Builder } from 'vs/base/browser/builder';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
export const MENU_MNEMONIC_REGEX: RegExp = /\(&{1,2}(\w)\)|&{1,2}(\w)/;
|
||||
export const MENU_ESCAPED_MNEMONIC_REGEX: RegExp = /(?:&){1,2}(\w)/;
|
||||
|
||||
export interface IMenuOptions {
|
||||
context?: any;
|
||||
actionItemProvider?: IActionItemProvider;
|
||||
@@ -208,9 +211,6 @@ interface IMenuItemOptions extends IActionItemOptions {
|
||||
}
|
||||
|
||||
class MenuActionItem extends BaseActionItem {
|
||||
static MNEMONIC_REGEX: RegExp = /&&(.)/;
|
||||
static ESCAPED_MNEMONIC_REGEX: RegExp = /&&(.)/;
|
||||
|
||||
public container: HTMLElement;
|
||||
protected $e: Builder;
|
||||
protected $label: Builder;
|
||||
@@ -232,9 +232,9 @@ class MenuActionItem extends BaseActionItem {
|
||||
if (this.options.label && options.enableMnemonics) {
|
||||
let label = this.getAction().label;
|
||||
if (label) {
|
||||
let matches = MenuActionItem.MNEMONIC_REGEX.exec(label);
|
||||
if (matches && matches.length === 2) {
|
||||
this.mnemonic = KeyCodeUtils.fromString(matches[1].toLocaleLowerCase());
|
||||
let matches = MENU_MNEMONIC_REGEX.exec(label);
|
||||
if (matches) {
|
||||
this.mnemonic = KeyCodeUtils.fromString((!!matches[1] ? matches[1] : matches[2]).toLocaleLowerCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,10 +257,10 @@ class MenuActionItem extends BaseActionItem {
|
||||
}
|
||||
|
||||
this.$check = $('span.menu-item-check').attr({ 'role': 'none' }).appendTo(this.$e);
|
||||
this.$label = $('span.action-label').attr({ 'role': 'none' }).appendTo(this.$e);
|
||||
this.$label = $('span.action-label').appendTo(this.$e);
|
||||
|
||||
if (this.options.label && this.options.keybinding) {
|
||||
$('span.keybinding').attr({ 'role': 'none' }).text(this.options.keybinding).appendTo(this.$e);
|
||||
$('span.keybinding').text(this.options.keybinding).appendTo(this.$e);
|
||||
}
|
||||
|
||||
this._updateClass();
|
||||
@@ -278,30 +278,23 @@ class MenuActionItem extends BaseActionItem {
|
||||
_updateLabel(): void {
|
||||
if (this.options.label) {
|
||||
let label = this.getAction().label;
|
||||
let mnemonic: string;
|
||||
if (label) {
|
||||
let matches = MenuActionItem.MNEMONIC_REGEX.exec(label);
|
||||
if (matches && matches.length === 2) {
|
||||
mnemonic = matches[1];
|
||||
|
||||
let ariaLabel = label.replace(MenuActionItem.MNEMONIC_REGEX, mnemonic);
|
||||
|
||||
this.mnemonic = KeyCodeUtils.fromString(mnemonic.toLocaleLowerCase());
|
||||
|
||||
this.$label.attr('aria-label', ariaLabel);
|
||||
} else {
|
||||
this.$label.attr('aria-label', label);
|
||||
const cleanLabel = cleanMnemonic(label);
|
||||
if (!this.options.enableMnemonics) {
|
||||
label = cleanLabel;
|
||||
}
|
||||
|
||||
if (this.options.enableMnemonics && mnemonic) {
|
||||
label = strings.escape(label).replace(MenuActionItem.ESCAPED_MNEMONIC_REGEX, '<u>$1</u>');
|
||||
this.$e.attr({ 'aria-keyshortcuts': mnemonic.toLocaleLowerCase() });
|
||||
} else {
|
||||
label = strings.escape(label).replace(MenuActionItem.ESCAPED_MNEMONIC_REGEX, '$1');
|
||||
this.$label.attr('aria-label', cleanLabel);
|
||||
|
||||
const matches = MENU_MNEMONIC_REGEX.exec(label);
|
||||
|
||||
if (matches) {
|
||||
label = strings.escape(label).replace(MENU_ESCAPED_MNEMONIC_REGEX, '<u aria-hidden="true">$1</u>');
|
||||
this.$e.attr({ 'aria-keyshortcuts': (!!matches[1] ? matches[1] : matches[2]).toLocaleLowerCase() });
|
||||
}
|
||||
}
|
||||
|
||||
this.$label.innerHtml(label);
|
||||
this.$label.innerHtml(label.trim());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,3 +517,16 @@ class SubmenuActionItem extends MenuActionItem {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function cleanMnemonic(label: string): string {
|
||||
const regex = MENU_MNEMONIC_REGEX;
|
||||
|
||||
const matches = regex.exec(label);
|
||||
if (!matches) {
|
||||
return label;
|
||||
}
|
||||
|
||||
const mnemonicInText = matches[0].charAt(0) === '&';
|
||||
|
||||
return label.replace(regex, mnemonicInText ? '$2' : '').trim();
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as browser from 'vs/base/browser/browser';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { IMenubarMenu, IMenubarMenuItemAction, IMenubarMenuItemSubmenu, IMenubarKeybinding } from 'vs/platform/menubar/common/menubar';
|
||||
import { IMenuService, MenuId, IMenu, SubmenuItemAction } from 'vs/platform/actions/common/actions';
|
||||
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
||||
@@ -17,7 +18,7 @@ import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { Menu, IMenuOptions, SubmenuAction } from 'vs/base/browser/ui/menu/menu';
|
||||
import { Menu, IMenuOptions, SubmenuAction, MENU_MNEMONIC_REGEX, cleanMnemonic, MENU_ESCAPED_MNEMONIC_REGEX } from 'vs/base/browser/ui/menu/menu';
|
||||
import { KeyCode, KeyCodeUtils } from 'vs/base/common/keyCodes';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
|
||||
@@ -523,7 +524,7 @@ export class MenubarControl extends Disposable {
|
||||
break;
|
||||
}
|
||||
|
||||
return this.currentEnableMenuBarMnemonics ? label : label.replace(/&&(.)/g, '$1');
|
||||
return label;
|
||||
}
|
||||
|
||||
private createOpenRecentMenuAction(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | URI, commandId: string, isFile: boolean): IAction {
|
||||
@@ -657,10 +658,12 @@ export class MenubarControl extends Disposable {
|
||||
for (let menuTitle of Object.keys(this.topLevelMenus)) {
|
||||
const menu: IMenu = this.topLevelMenus[menuTitle];
|
||||
let menuIndex = idx++;
|
||||
const cleanMenuLabel = cleanMnemonic(this.topLevelTitles[menuTitle]);
|
||||
|
||||
// Create the top level menu button element
|
||||
if (firstTimeSetup) {
|
||||
const buttonElement = $('div.menubar-menu-button', { 'role': 'menuitem', 'tabindex': 0, 'aria-label': this.topLevelTitles[menuTitle].replace(/&&(.)/g, '$1'), 'aria-haspopup': true });
|
||||
|
||||
const buttonElement = $('div.menubar-menu-button', { 'role': 'menuitem', 'tabindex': 0, 'aria-label': cleanMenuLabel, 'aria-haspopup': true });
|
||||
const titleElement = $('div.menubar-menu-title', { 'role': 'none', 'aria-hidden': true });
|
||||
|
||||
buttonElement.appendChild(titleElement);
|
||||
@@ -674,18 +677,22 @@ export class MenubarControl extends Disposable {
|
||||
}
|
||||
|
||||
// Update the button label to reflect mnemonics
|
||||
let displayTitle = this.topLevelTitles[menuTitle].replace(/&&(.)/g, this.currentEnableMenuBarMnemonics ? '<mnemonic aria-hidden="true">$1</mnemonic>' : '$1');
|
||||
this.customMenus[menuIndex].titleElement.innerHTML = displayTitle;
|
||||
this.customMenus[menuIndex].titleElement.innerHTML = this.currentEnableMenuBarMnemonics ?
|
||||
strings.escape(this.topLevelTitles[menuTitle]).replace(MENU_ESCAPED_MNEMONIC_REGEX, '<mnemonic aria-hidden="true">$1</mnemonic>') :
|
||||
cleanMenuLabel;
|
||||
|
||||
let mnemonicMatches = MENU_MNEMONIC_REGEX.exec(this.topLevelTitles[menuTitle]);
|
||||
|
||||
// Register mnemonics
|
||||
let mnemonic = (/&&(.)/g).exec(this.topLevelTitles[menuTitle]);
|
||||
if (mnemonic && mnemonic[1]) {
|
||||
if (mnemonicMatches) {
|
||||
let mnemonic = !!mnemonicMatches[1] ? mnemonicMatches[1] : mnemonicMatches[2];
|
||||
|
||||
if (firstTimeSetup) {
|
||||
this.registerMnemonic(menuIndex, mnemonic[1]);
|
||||
this.registerMnemonic(menuIndex, mnemonic);
|
||||
}
|
||||
|
||||
if (this.currentEnableMenuBarMnemonics) {
|
||||
this.customMenus[menuIndex].buttonElement.setAttribute('aria-keyshortcuts', 'Alt+' + mnemonic[1].toLocaleLowerCase());
|
||||
this.customMenus[menuIndex].buttonElement.setAttribute('aria-keyshortcuts', 'Alt+' + mnemonic.toLocaleLowerCase());
|
||||
} else {
|
||||
this.customMenus[menuIndex].buttonElement.removeAttribute('aria-keyshortcuts');
|
||||
}
|
||||
@@ -1028,7 +1035,7 @@ export class MenubarControl extends Disposable {
|
||||
let menuOptions: IMenuOptions = {
|
||||
getKeyBinding: (action) => this.keybindingService.lookupKeybinding(action.id),
|
||||
actionRunner: this.actionRunner,
|
||||
enableMnemonics: this.mnemonicsInUse,
|
||||
enableMnemonics: this.mnemonicsInUse && this.currentEnableMenuBarMnemonics,
|
||||
ariaLabel: customMenu.buttonElement.attributes['aria-label'].value
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user