also just a clean up so there is one source for mnemoic regex
This commit is contained in:
SteVen Batten
2018-08-26 12:32:24 -07:00
parent 387dc22611
commit 2c9408fecf
2 changed files with 49 additions and 36 deletions
+32 -26
View File
@@ -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
};