mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-26 05:07:35 +00:00
@@ -113,7 +113,7 @@ export class Menu extends ActionBar {
|
||||
const actions = this.mnemonics.get(key)!;
|
||||
|
||||
if (actions.length === 1) {
|
||||
if (actions[0] instanceof SubmenuMenuActionViewItem) {
|
||||
if (actions[0] instanceof SubmenuMenuActionViewItem && actions[0].container) {
|
||||
this.focusItemByElement(actions[0].container);
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ export class Menu extends ActionBar {
|
||||
|
||||
if (actions.length > 1) {
|
||||
const action = actions.shift();
|
||||
if (action) {
|
||||
if (action && action.container) {
|
||||
this.focusItemByElement(action.container);
|
||||
actions.push(action);
|
||||
}
|
||||
@@ -356,17 +356,17 @@ interface IMenuItemOptions extends IActionViewItemOptions {
|
||||
|
||||
class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
|
||||
public container: HTMLElement;
|
||||
public container: HTMLElement | undefined;
|
||||
|
||||
protected options: IMenuItemOptions;
|
||||
protected item: HTMLElement;
|
||||
protected item: HTMLElement | undefined;
|
||||
|
||||
private runOnceToEnableMouseUp: RunOnceScheduler;
|
||||
private label: HTMLElement;
|
||||
private check: HTMLElement;
|
||||
private mnemonic: string;
|
||||
private label: HTMLElement | undefined;
|
||||
private check: HTMLElement | undefined;
|
||||
private mnemonic: string | undefined;
|
||||
private cssClass: string;
|
||||
protected menuStyle: IMenuStyles;
|
||||
protected menuStyle: IMenuStyles | undefined;
|
||||
|
||||
constructor(ctx: any, action: IAction, options: IMenuItemOptions = {}) {
|
||||
options.isMenu = true;
|
||||
@@ -449,13 +449,19 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
|
||||
focus(): void {
|
||||
super.focus();
|
||||
this.item.focus();
|
||||
|
||||
if (this.item) {
|
||||
this.item.focus();
|
||||
}
|
||||
|
||||
this.applyStyle();
|
||||
}
|
||||
|
||||
updatePositionInSet(pos: number, setSize: number): void {
|
||||
this.item.setAttribute('aria-posinset', `${pos}`);
|
||||
this.item.setAttribute('aria-setsize', `${setSize}`);
|
||||
if (this.item) {
|
||||
this.item.setAttribute('aria-posinset', `${pos}`);
|
||||
this.item.setAttribute('aria-setsize', `${setSize}`);
|
||||
}
|
||||
}
|
||||
|
||||
updateLabel(): void {
|
||||
@@ -467,7 +473,9 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
label = cleanLabel;
|
||||
}
|
||||
|
||||
this.label.setAttribute('aria-label', cleanLabel.replace(/&&/g, '&'));
|
||||
if (this.label) {
|
||||
this.label.setAttribute('aria-label', cleanLabel.replace(/&&/g, '&'));
|
||||
}
|
||||
|
||||
const matches = MENU_MNEMONIC_REGEX.exec(label);
|
||||
|
||||
@@ -488,13 +496,17 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
|
||||
label = label.replace(/&&/g, '&');
|
||||
this.item.setAttribute('aria-keyshortcuts', (!!matches[1] ? matches[1] : matches[3]).toLocaleLowerCase());
|
||||
if (this.item) {
|
||||
this.item.setAttribute('aria-keyshortcuts', (!!matches[1] ? matches[1] : matches[3]).toLocaleLowerCase());
|
||||
}
|
||||
} else {
|
||||
label = label.replace(/&&/g, '&');
|
||||
}
|
||||
}
|
||||
|
||||
this.label.innerHTML = label.trim();
|
||||
if (this.label) {
|
||||
this.label.innerHTML = label.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -512,23 +524,23 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
if (title) {
|
||||
if (title && this.item) {
|
||||
this.item.title = title;
|
||||
}
|
||||
}
|
||||
|
||||
updateClass(): void {
|
||||
if (this.cssClass) {
|
||||
if (this.cssClass && this.item) {
|
||||
removeClasses(this.item, this.cssClass);
|
||||
}
|
||||
if (this.options.icon) {
|
||||
if (this.options.icon && this.label) {
|
||||
this.cssClass = this.getAction().class || '';
|
||||
addClass(this.label, 'icon');
|
||||
if (this.cssClass) {
|
||||
addClasses(this.label, this.cssClass);
|
||||
}
|
||||
this.updateEnabled();
|
||||
} else {
|
||||
} else if (this.label) {
|
||||
removeClass(this.label, 'icon');
|
||||
}
|
||||
}
|
||||
@@ -539,19 +551,27 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
removeClass(this.element, 'disabled');
|
||||
}
|
||||
|
||||
removeClass(this.item, 'disabled');
|
||||
this.item.tabIndex = 0;
|
||||
if (this.item) {
|
||||
removeClass(this.item, 'disabled');
|
||||
this.item.tabIndex = 0;
|
||||
}
|
||||
} else {
|
||||
if (this.element) {
|
||||
addClass(this.element, 'disabled');
|
||||
}
|
||||
|
||||
addClass(this.item, 'disabled');
|
||||
removeTabIndexAndUpdateFocus(this.item);
|
||||
if (this.item) {
|
||||
addClass(this.item, 'disabled');
|
||||
removeTabIndexAndUpdateFocus(this.item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateChecked(): void {
|
||||
if (!this.item) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.getAction().checked) {
|
||||
addClass(this.item, 'checked');
|
||||
this.item.setAttribute('role', 'menuitemcheckbox');
|
||||
@@ -563,7 +583,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
getMnemonic(): string {
|
||||
getMnemonic(): string | undefined {
|
||||
return this.mnemonic;
|
||||
}
|
||||
|
||||
@@ -577,10 +597,18 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
const bgColor = isSelected && this.menuStyle.selectionBackgroundColor ? this.menuStyle.selectionBackgroundColor : this.menuStyle.backgroundColor;
|
||||
const border = isSelected && this.menuStyle.selectionBorderColor ? `thin solid ${this.menuStyle.selectionBorderColor}` : '';
|
||||
|
||||
this.item.style.color = fgColor ? `${fgColor}` : null;
|
||||
this.check.style.backgroundColor = fgColor ? `${fgColor}` : '';
|
||||
this.item.style.backgroundColor = bgColor ? `${bgColor}` : '';
|
||||
this.container.style.border = border;
|
||||
if (this.item) {
|
||||
this.item.style.color = fgColor ? `${fgColor}` : null;
|
||||
this.item.style.backgroundColor = bgColor ? `${bgColor}` : '';
|
||||
}
|
||||
|
||||
if (this.check) {
|
||||
this.check.style.backgroundColor = fgColor ? `${fgColor}` : '';
|
||||
}
|
||||
|
||||
if (this.container) {
|
||||
this.container.style.border = border;
|
||||
}
|
||||
}
|
||||
|
||||
style(style: IMenuStyles): void {
|
||||
@@ -590,11 +618,11 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
|
||||
class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
|
||||
private mysubmenu: Menu | null;
|
||||
private mysubmenu: Menu | null = null;
|
||||
private submenuContainer: HTMLElement | undefined;
|
||||
private submenuIndicator: HTMLElement;
|
||||
private submenuIndicator: HTMLElement | undefined;
|
||||
private readonly submenuDisposables = this._register(new DisposableStore());
|
||||
private mouseOver: boolean;
|
||||
private mouseOver: boolean = false;
|
||||
private showScheduler: RunOnceScheduler;
|
||||
private hideScheduler: RunOnceScheduler;
|
||||
private expandDirection: Direction;
|
||||
@@ -631,11 +659,13 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
|
||||
return;
|
||||
}
|
||||
|
||||
addClass(this.item, 'monaco-submenu-item');
|
||||
this.item.setAttribute('aria-haspopup', 'true');
|
||||
if (this.item) {
|
||||
addClass(this.item, 'monaco-submenu-item');
|
||||
this.item.setAttribute('aria-haspopup', 'true');
|
||||
|
||||
this.submenuIndicator = append(this.item, $('span.submenu-indicator'));
|
||||
this.submenuIndicator.setAttribute('aria-hidden', 'true');
|
||||
this.submenuIndicator = append(this.item, $('span.submenu-indicator'));
|
||||
this.submenuIndicator.setAttribute('aria-hidden', 'true');
|
||||
}
|
||||
|
||||
this._register(addDisposableListener(this.element, EventType.KEY_UP, e => {
|
||||
let event = new StandardKeyboardEvent(e);
|
||||
@@ -793,7 +823,9 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
|
||||
const isSelected = this.element && hasClass(this.element, 'focused');
|
||||
const fgColor = isSelected && this.menuStyle.selectionForegroundColor ? this.menuStyle.selectionForegroundColor : this.menuStyle.foregroundColor;
|
||||
|
||||
this.submenuIndicator.style.backgroundColor = fgColor ? `${fgColor}` : '';
|
||||
if (this.submenuIndicator) {
|
||||
this.submenuIndicator.style.backgroundColor = fgColor ? `${fgColor}` : '';
|
||||
}
|
||||
|
||||
if (this.parentData.submenu) {
|
||||
this.parentData.submenu.style(this.menuStyle);
|
||||
|
||||
@@ -56,7 +56,7 @@ export class MenuBar extends Disposable {
|
||||
actions?: ReadonlyArray<IAction>;
|
||||
}[];
|
||||
|
||||
private overflowMenu: {
|
||||
private overflowMenu!: {
|
||||
buttonElement: HTMLElement;
|
||||
titleElement: HTMLElement;
|
||||
label: string;
|
||||
@@ -73,22 +73,22 @@ export class MenuBar extends Disposable {
|
||||
private menuUpdater: RunOnceScheduler;
|
||||
|
||||
// Input-related
|
||||
private _mnemonicsInUse: boolean;
|
||||
private openedViaKeyboard: boolean;
|
||||
private awaitingAltRelease: boolean;
|
||||
private ignoreNextMouseUp: boolean;
|
||||
private _mnemonicsInUse: boolean = false;
|
||||
private openedViaKeyboard: boolean = false;
|
||||
private awaitingAltRelease: boolean = false;
|
||||
private ignoreNextMouseUp: boolean = false;
|
||||
private mnemonics: Map<string, number>;
|
||||
|
||||
private updatePending: boolean;
|
||||
private updatePending: boolean = false;
|
||||
private _focusState: MenubarState;
|
||||
private actionRunner: IActionRunner;
|
||||
|
||||
private readonly _onVisibilityChange: Emitter<boolean>;
|
||||
private readonly _onFocusStateChange: Emitter<boolean>;
|
||||
|
||||
private numMenusShown: number;
|
||||
private menuStyle: IMenuStyles;
|
||||
private overflowLayoutScheduled: IDisposable | null;
|
||||
private numMenusShown: number = 0;
|
||||
private menuStyle: IMenuStyles | undefined;
|
||||
private overflowLayoutScheduled: IDisposable | null = null;
|
||||
|
||||
constructor(private container: HTMLElement, private options: IMenuBarOptions = {}) {
|
||||
super();
|
||||
@@ -930,7 +930,9 @@ export class MenuBar extends Disposable {
|
||||
};
|
||||
|
||||
let menuWidget = this._register(new Menu(menuHolder, customMenu.actions, menuOptions));
|
||||
menuWidget.style(this.menuStyle);
|
||||
if (this.menuStyle) {
|
||||
menuWidget.style(this.menuStyle);
|
||||
}
|
||||
|
||||
this._register(menuWidget.onDidCancel(() => {
|
||||
this.focusState = MenubarState.FOCUSED;
|
||||
|
||||
@@ -77,7 +77,7 @@ export abstract class MenubarControl extends Disposable {
|
||||
'Help': nls.localize({ key: 'mHelp', comment: ['&& denotes a mnemonic'] }, "&&Help")
|
||||
};
|
||||
|
||||
protected recentlyOpened: IRecentlyOpened;
|
||||
protected recentlyOpened: IRecentlyOpened = { files: [], workspaces: [] };
|
||||
|
||||
protected menuUpdater: RunOnceScheduler;
|
||||
|
||||
@@ -259,10 +259,10 @@ export abstract class MenubarControl extends Disposable {
|
||||
}
|
||||
|
||||
export class CustomMenubarControl extends MenubarControl {
|
||||
private menubar: MenuBar;
|
||||
private container: HTMLElement;
|
||||
private alwaysOnMnemonics: boolean;
|
||||
private focusInsideMenubar: boolean;
|
||||
private menubar: MenuBar | undefined;
|
||||
private container: HTMLElement | undefined;
|
||||
private alwaysOnMnemonics: boolean = false;
|
||||
private focusInsideMenubar: boolean = false;
|
||||
|
||||
private readonly _onVisibilityChange: Emitter<boolean>;
|
||||
private readonly _onFocusStateChange: Emitter<boolean>;
|
||||
@@ -518,6 +518,11 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
}
|
||||
|
||||
private setupCustomMenubar(firstTime: boolean): void {
|
||||
// If there is no container, we cannot setup the menubar
|
||||
if (!this.container) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstTime) {
|
||||
this.menubar = this._register(new MenuBar(
|
||||
this.container, {
|
||||
@@ -526,12 +531,13 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
visibility: this.currentMenubarVisibility,
|
||||
getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id),
|
||||
compactMode: this.currentCompactMenuMode
|
||||
}
|
||||
));
|
||||
}));
|
||||
|
||||
this.accessibilityService.alwaysUnderlineAccessKeys().then(val => {
|
||||
this.alwaysOnMnemonics = val;
|
||||
this.menubar.update({ enableMnemonics: this.currentEnableMenuBarMnemonics, disableAltFocus: this.currentDisableMenuBarAltFocus, visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), alwaysOnMnemonics: this.alwaysOnMnemonics, compactMode: this.currentCompactMenuMode });
|
||||
if (this.menubar) {
|
||||
this.menubar.update({ enableMnemonics: this.currentEnableMenuBarMnemonics, disableAltFocus: this.currentDisableMenuBarAltFocus, visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), alwaysOnMnemonics: this.alwaysOnMnemonics, compactMode: this.currentCompactMenuMode });
|
||||
}
|
||||
});
|
||||
|
||||
this._register(this.menubar.onFocusStateChange(focused => {
|
||||
@@ -557,7 +563,9 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
|
||||
this._register(attachMenuStyler(this.menubar, this.themeService));
|
||||
} else {
|
||||
this.menubar.update({ enableMnemonics: this.currentEnableMenuBarMnemonics, disableAltFocus: this.currentDisableMenuBarAltFocus, visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), alwaysOnMnemonics: this.alwaysOnMnemonics, compactMode: this.currentCompactMenuMode });
|
||||
if (this.menubar) {
|
||||
this.menubar.update({ enableMnemonics: this.currentEnableMenuBarMnemonics, disableAltFocus: this.currentDisableMenuBarAltFocus, visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), alwaysOnMnemonics: this.alwaysOnMnemonics, compactMode: this.currentCompactMenuMode });
|
||||
}
|
||||
}
|
||||
|
||||
// Update the menu actions
|
||||
@@ -577,7 +585,9 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
if (!this.focusInsideMenubar) {
|
||||
const actions: IAction[] = [];
|
||||
updateActions(menu, actions, topLevelTitle);
|
||||
this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[topLevelTitle]) });
|
||||
if (this.menubar) {
|
||||
this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[topLevelTitle]) });
|
||||
}
|
||||
}
|
||||
}, this));
|
||||
}
|
||||
@@ -604,7 +614,9 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
if (!this.focusInsideMenubar) {
|
||||
const actions: IAction[] = [];
|
||||
updateActions(menu, actions, title);
|
||||
this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) });
|
||||
if (this.menubar) {
|
||||
this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) });
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -614,10 +626,12 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
updateActions(menu, actions, title);
|
||||
}
|
||||
|
||||
if (!firstTime) {
|
||||
this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) });
|
||||
} else {
|
||||
this.menubar.push({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) });
|
||||
if (this.menubar) {
|
||||
if (!firstTime) {
|
||||
this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) });
|
||||
} else {
|
||||
this.menubar.push({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -628,7 +642,9 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
DOM.removeClass(this.container, 'inactive');
|
||||
} else {
|
||||
DOM.addClass(this.container, 'inactive');
|
||||
this.menubar.blur();
|
||||
if (this.menubar) {
|
||||
this.menubar.blur();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -648,7 +664,9 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
}
|
||||
|
||||
this._register(DOM.addDisposableListener(window, DOM.EventType.RESIZE, () => {
|
||||
this.menubar.blur();
|
||||
if (this.menubar) {
|
||||
this.menubar.blur();
|
||||
}
|
||||
}));
|
||||
|
||||
// Mnemonics require fullscreen in web
|
||||
|
||||
@@ -68,19 +68,19 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private title: HTMLElement;
|
||||
private dragRegion: HTMLElement;
|
||||
private windowControls: HTMLElement;
|
||||
private maxRestoreControl: HTMLElement;
|
||||
private appIcon: HTMLElement;
|
||||
private title!: HTMLElement;
|
||||
private dragRegion: HTMLElement | undefined;
|
||||
private windowControls: HTMLElement | undefined;
|
||||
private maxRestoreControl: HTMLElement | undefined;
|
||||
private appIcon: HTMLElement | undefined;
|
||||
private customMenubar: CustomMenubarControl | undefined;
|
||||
private menubar?: HTMLElement;
|
||||
private resizer: HTMLElement;
|
||||
private lastLayoutDimensions: Dimension;
|
||||
private resizer: HTMLElement | undefined;
|
||||
private lastLayoutDimensions: Dimension | undefined;
|
||||
|
||||
private pendingTitle: string;
|
||||
private pendingTitle: string | undefined;
|
||||
|
||||
private isInactive: boolean;
|
||||
private isInactive: boolean = false;
|
||||
|
||||
private readonly properties: ITitleProperties = { isPure: true, isAdmin: false };
|
||||
private readonly activeEditorListeners = this._register(new DisposableStore());
|
||||
@@ -158,8 +158,10 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
// Hide title when toggling menu bar
|
||||
if (!isWeb && this.currentMenubarVisibility === 'toggle' && visible) {
|
||||
// Hack to fix issue #52522 with layered webkit-app-region elements appearing under cursor
|
||||
hide(this.dragRegion);
|
||||
setTimeout(() => show(this.dragRegion), 50);
|
||||
if (this.dragRegion) {
|
||||
hide(this.dragRegion);
|
||||
setTimeout(() => show(this.dragRegion!), 50);
|
||||
}
|
||||
}
|
||||
|
||||
this.adjustTitleMarginToCenter();
|
||||
@@ -169,7 +171,7 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
}
|
||||
|
||||
private onMenubarFocusChanged(focused: boolean) {
|
||||
if (!isWeb && (isWindows || isLinux) && this.currentMenubarVisibility === 'compact') {
|
||||
if (!isWeb && (isWindows || isLinux) && this.currentMenubarVisibility === 'compact' && this.dragRegion) {
|
||||
if (focused) {
|
||||
hide(this.dragRegion);
|
||||
} else {
|
||||
@@ -518,9 +520,9 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
|
||||
private onUpdateAppIconDragBehavior() {
|
||||
const setting = this.configurationService.getValue('window.doubleClickIconToClose');
|
||||
if (setting) {
|
||||
if (setting && this.appIcon) {
|
||||
(this.appIcon.style as any)['-webkit-app-region'] = 'no-drag';
|
||||
} else {
|
||||
} else if (this.appIcon) {
|
||||
(this.appIcon.style as any)['-webkit-app-region'] = 'drag';
|
||||
}
|
||||
}
|
||||
@@ -576,14 +578,24 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
if ((!isWeb && isMacintosh) || this.currentMenubarVisibility === 'hidden') {
|
||||
this.title.style.zoom = `${1 / getZoomFactor()}`;
|
||||
if (!isWeb && (isWindows || isLinux)) {
|
||||
this.appIcon.style.zoom = `${1 / getZoomFactor()}`;
|
||||
this.windowControls.style.zoom = `${1 / getZoomFactor()}`;
|
||||
if (this.appIcon) {
|
||||
this.appIcon.style.zoom = `${1 / getZoomFactor()}`;
|
||||
}
|
||||
|
||||
if (this.windowControls) {
|
||||
this.windowControls.style.zoom = `${1 / getZoomFactor()}`;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.title.style.zoom = null;
|
||||
if (!isWeb && (isWindows || isLinux)) {
|
||||
this.appIcon.style.zoom = null;
|
||||
this.windowControls.style.zoom = null;
|
||||
if (this.appIcon) {
|
||||
this.appIcon.style.zoom = null;
|
||||
}
|
||||
|
||||
if (this.windowControls) {
|
||||
this.windowControls.style.zoom = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user