mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from vscode 8c426f9f3b6b18935cc6c2ec8aa6d45ccd88021e
This commit is contained in:
@@ -34,5 +34,5 @@ export interface IContextMenuDelegate {
|
||||
actionRunner?: IActionRunner;
|
||||
autoSelectFirstItem?: boolean;
|
||||
anchorAlignment?: AnchorAlignment;
|
||||
anchorAsContainer?: boolean;
|
||||
domForShadowRoot?: HTMLElement;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
.monaco-action-bar {
|
||||
text-align: right;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ function initialize() {
|
||||
delayer.schedule();
|
||||
}
|
||||
|
||||
function formatRule(c: Codicon) {
|
||||
export function formatRule(c: Codicon) {
|
||||
let def = c.definition;
|
||||
while (def instanceof Codicon) {
|
||||
def = def.definition;
|
||||
|
||||
@@ -10,6 +10,12 @@ import { IDisposable, toDisposable, Disposable, DisposableStore } from 'vs/base/
|
||||
import { Range } from 'vs/base/common/range';
|
||||
import { BrowserFeatures } from 'vs/base/browser/canIUse';
|
||||
|
||||
export const enum ContextViewDOMPosition {
|
||||
ABSOLUTE = 1,
|
||||
FIXED,
|
||||
FIXED_SHADOW
|
||||
}
|
||||
|
||||
export interface IAnchor {
|
||||
x: number;
|
||||
y: number;
|
||||
@@ -105,32 +111,62 @@ export class ContextView extends Disposable {
|
||||
private container: HTMLElement | null = null;
|
||||
private view: HTMLElement;
|
||||
private useFixedPosition: boolean;
|
||||
private useShadowDOM: boolean;
|
||||
private delegate: IDelegate | null = null;
|
||||
private toDisposeOnClean: IDisposable = Disposable.None;
|
||||
private toDisposeOnSetContainer: IDisposable = Disposable.None;
|
||||
private shadowRoot: ShadowRoot | null = null;
|
||||
private shadowRootHostElement: HTMLElement | null = null;
|
||||
|
||||
constructor(container: HTMLElement, useFixedPosition: boolean) {
|
||||
constructor(container: HTMLElement, domPosition: ContextViewDOMPosition) {
|
||||
super();
|
||||
|
||||
this.view = DOM.$('.context-view');
|
||||
this.useFixedPosition = false;
|
||||
this.useShadowDOM = false;
|
||||
|
||||
DOM.hide(this.view);
|
||||
|
||||
this.setContainer(container, useFixedPosition);
|
||||
this.setContainer(container, domPosition);
|
||||
|
||||
this._register(toDisposable(() => this.setContainer(null, false)));
|
||||
this._register(toDisposable(() => this.setContainer(null, ContextViewDOMPosition.ABSOLUTE)));
|
||||
}
|
||||
|
||||
setContainer(container: HTMLElement | null, useFixedPosition: boolean): void {
|
||||
setContainer(container: HTMLElement | null, domPosition: ContextViewDOMPosition): void {
|
||||
if (this.container) {
|
||||
this.toDisposeOnSetContainer.dispose();
|
||||
this.container.removeChild(this.view);
|
||||
|
||||
if (this.shadowRoot) {
|
||||
this.shadowRoot.removeChild(this.view);
|
||||
this.shadowRoot = null;
|
||||
DOM.removeNode(this.shadowRootHostElement!);
|
||||
this.shadowRootHostElement = null;
|
||||
} else {
|
||||
this.container.removeChild(this.view);
|
||||
}
|
||||
|
||||
this.container = null;
|
||||
}
|
||||
if (container) {
|
||||
this.container = container;
|
||||
this.container.appendChild(this.view);
|
||||
|
||||
this.useFixedPosition = domPosition !== ContextViewDOMPosition.ABSOLUTE;
|
||||
this.useShadowDOM = domPosition === ContextViewDOMPosition.FIXED_SHADOW;
|
||||
|
||||
if (this.useShadowDOM) {
|
||||
this.shadowRootHostElement = DOM.$('.shadow-root-host');
|
||||
this.container.appendChild(this.shadowRootHostElement);
|
||||
this.shadowRoot = this.shadowRootHostElement.attachShadow({ mode: 'closed' });
|
||||
this.shadowRoot.innerHTML = `
|
||||
<style>
|
||||
${SHADOW_ROOT_CSS}
|
||||
</style>
|
||||
`;
|
||||
this.shadowRoot.appendChild(this.view);
|
||||
this.shadowRoot.appendChild(DOM.$('slot'));
|
||||
} else {
|
||||
this.container.appendChild(this.view);
|
||||
}
|
||||
|
||||
const toDisposeOnSetContainer = new DisposableStore();
|
||||
|
||||
@@ -148,8 +184,6 @@ export class ContextView extends Disposable {
|
||||
|
||||
this.toDisposeOnSetContainer = toDisposeOnSetContainer;
|
||||
}
|
||||
|
||||
this.useFixedPosition = useFixedPosition;
|
||||
}
|
||||
|
||||
show(delegate: IDelegate): void {
|
||||
@@ -162,6 +196,7 @@ export class ContextView extends Disposable {
|
||||
this.view.className = 'context-view';
|
||||
this.view.style.top = '0px';
|
||||
this.view.style.left = '0px';
|
||||
this.view.style.zIndex = '2500';
|
||||
this.view.style.position = this.useFixedPosition ? 'fixed' : 'absolute';
|
||||
DOM.show(this.view);
|
||||
|
||||
@@ -301,3 +336,45 @@ export class ContextView extends Disposable {
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
let SHADOW_ROOT_CSS = /* css */ `
|
||||
:host {
|
||||
all: initial; /* 1st rule so subsequent properties are reset. */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "codicon";
|
||||
src: url("./codicon.ttf?5d4d76ab2ce5108968ad644d591a16a6") format("truetype");
|
||||
}
|
||||
|
||||
.codicon[class*='codicon-'] {
|
||||
font: normal normal normal 16px/1 codicon;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
text-rendering: auto;
|
||||
text-align: center;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
|
||||
:host-context(.mac) { font-family: -apple-system, BlinkMacSystemFont, sans-serif; }
|
||||
:host-context(.mac:lang(zh-Hans)) { font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", sans-serif; }
|
||||
:host-context(.mac:lang(zh-Hant)) { font-family: -apple-system, BlinkMacSystemFont, "PingFang TC", sans-serif; }
|
||||
:host-context(.mac:lang(ja)) { font-family: -apple-system, BlinkMacSystemFont, "Hiragino Kaku Gothic Pro", sans-serif; }
|
||||
:host-context(.mac:lang(ko)) { font-family: -apple-system, BlinkMacSystemFont, "Nanum Gothic", "Apple SD Gothic Neo", "AppleGothic", sans-serif; }
|
||||
|
||||
:host-context(.windows) { font-family: "Segoe WPC", "Segoe UI", sans-serif; }
|
||||
:host-context(.windows:lang(zh-Hans)) { font-family: "Segoe WPC", "Segoe UI", "Microsoft YaHei", sans-serif; }
|
||||
:host-context(.windows:lang(zh-Hant)) { font-family: "Segoe WPC", "Segoe UI", "Microsoft Jhenghei", sans-serif; }
|
||||
:host-context(.windows:lang(ja)) { font-family: "Segoe WPC", "Segoe UI", "Yu Gothic UI", "Meiryo UI", sans-serif; }
|
||||
:host-context(.windows:lang(ko)) { font-family: "Segoe WPC", "Segoe UI", "Malgun Gothic", "Dotom", sans-serif; }
|
||||
|
||||
:host-context(.mac).linux) { font-family: system-ui, "Ubuntu", "Droid Sans", sans-serif; }
|
||||
:host-context(.mac).linux:lang(zh-Hans)) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans SC", "Source Han Sans CN", "Source Han Sans", sans-serif; }
|
||||
:host-context(.mac).linux:lang(zh-Hant)) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans TC", "Source Han Sans TW", "Source Han Sans", sans-serif; }
|
||||
:host-context(.mac).linux:lang(ja)) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", sans-serif; }
|
||||
:host-context(.mac).linux:lang(ko)) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans K", "Source Han Sans JR", "Source Han Sans", "UnDotum", "FBaekmuk Gulim", sans-serif; }
|
||||
`;
|
||||
|
||||
@@ -270,7 +270,7 @@ export class DropdownMenu extends BaseDropdown {
|
||||
onHide: () => this.onHide(),
|
||||
actionRunner: this.menuOptions ? this.menuOptions.actionRunner : undefined,
|
||||
anchorAlignment: this.menuOptions ? this.menuOptions.anchorAlignment : AnchorAlignment.LEFT,
|
||||
anchorAsContainer: this.menuAsChild
|
||||
domForShadowRoot: this.menuAsChild ? this.element : undefined
|
||||
});
|
||||
}
|
||||
|
||||
@@ -297,15 +297,17 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem {
|
||||
private _onDidChangeVisibility = this._register(new Emitter<boolean>());
|
||||
readonly onDidChangeVisibility = this._onDidChangeVisibility.event;
|
||||
|
||||
constructor(action: IAction, menuActions: ReadonlyArray<IAction>, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment, menuAsChild?: boolean);
|
||||
constructor(action: IAction, actionProvider: IActionProvider, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment, menuAsChild?: boolean);
|
||||
constructor(action: IAction, menuActionsOrProvider: ReadonlyArray<IAction> | IActionProvider, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment, menuAsChild?: boolean) {
|
||||
constructor(action: IAction, menuActions: ReadonlyArray<IAction>, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner | undefined, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment, menuAsChild?: boolean);
|
||||
constructor(action: IAction, actionProvider: IActionProvider, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner | undefined, keybindings: ((action: IAction) => ResolvedKeybinding) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment, menuAsChild?: boolean);
|
||||
constructor(action: IAction, menuActionsOrProvider: ReadonlyArray<IAction> | IActionProvider, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner | undefined, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment, menuAsChild?: boolean) {
|
||||
super(null, action);
|
||||
|
||||
this.menuActionsOrProvider = menuActionsOrProvider;
|
||||
this.contextMenuProvider = contextMenuProvider;
|
||||
this.actionViewItemProvider = actionViewItemProvider;
|
||||
this.actionRunner = actionRunner;
|
||||
if (actionRunner) {
|
||||
this.actionRunner = actionRunner;
|
||||
}
|
||||
this.keybindings = keybindings;
|
||||
this.clazz = clazz;
|
||||
this.anchorAlignmentProvider = anchorAlignmentProvider;
|
||||
|
||||
@@ -1,225 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical {
|
||||
margin-left: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .actions-container {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item {
|
||||
padding: 0;
|
||||
transform: none;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item.active {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-menu-item {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
height: 2em;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label {
|
||||
flex: 1 1 auto;
|
||||
text-decoration: none;
|
||||
padding: 0 1em;
|
||||
background: none;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .keybinding,
|
||||
.monaco-menu .monaco-action-bar.vertical .submenu-indicator {
|
||||
display: inline-block;
|
||||
flex: 2 1 auto;
|
||||
padding: 0 1em;
|
||||
text-align: right;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .submenu-indicator {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .submenu-indicator.codicon {
|
||||
font-size: 16px !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .submenu-indicator.codicon::before {
|
||||
margin-left: auto;
|
||||
margin-right: -20px;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item.disabled .keybinding,
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item.disabled .submenu-indicator {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label:not(.separator) {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item {
|
||||
position: static;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item .monaco-submenu {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label.separator {
|
||||
padding: 0.5em 0 0 0;
|
||||
margin-bottom: 0.5em;
|
||||
width: 100%;
|
||||
height: 0px !important;
|
||||
margin-left: .8em !important;
|
||||
margin-right: .8em !important;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label.separator.text {
|
||||
padding: 0.7em 1em 0.1em 1em;
|
||||
font-weight: bold;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label:hover {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .menu-item-check {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
width: 1em;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-menu-item.checked .menu-item-check {
|
||||
visibility: visible;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Context Menu */
|
||||
|
||||
.context-view.monaco-menu-container {
|
||||
outline: 0;
|
||||
border: none;
|
||||
animation: fadeIn 0.083s linear;
|
||||
}
|
||||
|
||||
.context-view.monaco-menu-container :focus,
|
||||
.context-view.monaco-menu-container .monaco-action-bar.vertical:focus,
|
||||
.context-view.monaco-menu-container .monaco-action-bar.vertical :focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item {
|
||||
border: thin solid transparent; /* prevents jumping behaviour on hover or focus */
|
||||
}
|
||||
|
||||
|
||||
/* High Contrast Theming */
|
||||
.hc-black .context-view.monaco-menu-container {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.hc-black .monaco-menu .monaco-action-bar.vertical .action-item.focused {
|
||||
background: none;
|
||||
}
|
||||
|
||||
/* Menubar styles */
|
||||
|
||||
.menubar {
|
||||
display: flex;
|
||||
flex-shrink: 1;
|
||||
box-sizing: border-box;
|
||||
height: 30px;
|
||||
overflow: hidden;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.fullscreen .menubar:not(.compact) {
|
||||
margin: 0px;
|
||||
padding: 0px 5px;
|
||||
}
|
||||
|
||||
.menubar > .menubar-menu-button {
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
padding: 0px 8px;
|
||||
cursor: default;
|
||||
-webkit-app-region: no-drag;
|
||||
zoom: 1;
|
||||
white-space: nowrap;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.menubar.compact {
|
||||
flex-shrink: 0;
|
||||
overflow: visible; /* to avoid the compact menu to be repositioned when clicking */
|
||||
}
|
||||
|
||||
.menubar.compact > .menubar-menu-button {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.menubar .menubar-menu-items-holder {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
opacity: 1;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.menubar .menubar-menu-items-holder.monaco-menu-container {
|
||||
outline: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.menubar .menubar-menu-items-holder.monaco-menu-container :focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.menubar .toolbar-toggle-more {
|
||||
width: 20px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.menubar.compact .toolbar-toggle-more {
|
||||
position: relative;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.menubar .toolbar-toggle-more {
|
||||
padding: 0;
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
.menubar.compact .toolbar-toggle-more::before {
|
||||
content: "\eb94" !important;
|
||||
}
|
||||
@@ -3,13 +3,12 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./menu';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { IActionRunner, IAction, Action } from 'vs/base/common/actions';
|
||||
import { ActionBar, IActionViewItemProvider, ActionsOrientation, Separator, ActionViewItem, IActionViewItemOptions, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { ResolvedKeybinding, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { addClass, EventType, EventHelper, EventLike, removeTabIndexAndUpdateFocus, isAncestor, hasClass, addDisposableListener, removeClass, append, $, addClasses, removeClasses, clearNode } from 'vs/base/browser/dom';
|
||||
import { addClass, EventType, EventHelper, EventLike, removeTabIndexAndUpdateFocus, isAncestor, hasClass, addDisposableListener, removeClass, append, $, addClasses, removeClasses, clearNode, createStyleSheet, isInShadowDOM } from 'vs/base/browser/dom';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
@@ -20,6 +19,7 @@ import { Event } from 'vs/base/common/event';
|
||||
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { isLinux, isMacintosh } from 'vs/base/common/platform';
|
||||
import { Codicon, registerIcon, stripCodicons } from 'vs/base/common/codicons';
|
||||
import { formatRule } from 'vs/base/browser/ui/codicons/codiconStyles';
|
||||
|
||||
export const MENU_MNEMONIC_REGEX = /\(&([^\s&])\)|(^|[^&])&([^\s&])/;
|
||||
export const MENU_ESCAPED_MNEMONIC_REGEX = /(&)?(&)([^\s&])/g;
|
||||
@@ -71,6 +71,8 @@ export class Menu extends ActionBar {
|
||||
private readonly menuDisposables: DisposableStore;
|
||||
private scrollableElement: DomScrollableElement;
|
||||
private menuElement: HTMLElement;
|
||||
static globalStyleSheet: HTMLStyleElement;
|
||||
protected styleSheet: HTMLStyleElement | undefined;
|
||||
|
||||
constructor(container: HTMLElement, actions: ReadonlyArray<IAction>, options: IMenuOptions = {}) {
|
||||
addClass(container, 'monaco-menu-container');
|
||||
@@ -96,6 +98,8 @@ export class Menu extends ActionBar {
|
||||
|
||||
this.menuDisposables = this._register(new DisposableStore());
|
||||
|
||||
this.initializeStyleSheet(container);
|
||||
|
||||
addDisposableListener(menuElement, EventType.KEY_DOWN, (e) => {
|
||||
const event = new StandardKeyboardEvent(e);
|
||||
|
||||
@@ -215,6 +219,20 @@ export class Menu extends ActionBar {
|
||||
});
|
||||
}
|
||||
|
||||
private initializeStyleSheet(container: HTMLElement): void {
|
||||
if (isInShadowDOM(container)) {
|
||||
this.styleSheet = createStyleSheet(container);
|
||||
this.styleSheet.innerHTML = MENU_WIDGET_CSS;
|
||||
} else {
|
||||
if (!Menu.globalStyleSheet) {
|
||||
Menu.globalStyleSheet = createStyleSheet();
|
||||
Menu.globalStyleSheet.innerHTML = MENU_WIDGET_CSS;
|
||||
}
|
||||
|
||||
this.styleSheet = Menu.globalStyleSheet;
|
||||
}
|
||||
}
|
||||
|
||||
style(style: IMenuStyles): void {
|
||||
const container = this.getContainer();
|
||||
|
||||
@@ -877,3 +895,298 @@ export function cleanMnemonic(label: string): string {
|
||||
|
||||
return label.replace(regex, mnemonicInText ? '$2$3' : '').trim();
|
||||
}
|
||||
|
||||
let MENU_WIDGET_CSS: string = /* css */`
|
||||
.monaco-menu {
|
||||
font-size: 13px;
|
||||
|
||||
}
|
||||
|
||||
${formatRule(menuSelectionIcon)}
|
||||
${formatRule(menuSubmenuIcon)}
|
||||
|
||||
.monaco-action-bar {
|
||||
text-align: right;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.monaco-action-bar .actions-container {
|
||||
display: flex;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.monaco-action-bar.vertical .actions-container {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.monaco-action-bar.reverse .actions-container {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
transition: transform 50ms ease;
|
||||
position: relative; /* DO NOT REMOVE - this is the key to preventing the ghosting icon bug in Chrome 42 */
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item.disabled {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.monaco-action-bar.animated .action-item.active {
|
||||
transform: scale(1.272019649, 1.272019649); /* 1.272019649 = √φ */
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item .icon,
|
||||
.monaco-action-bar .action-item .codicon {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item .codicon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-label {
|
||||
font-size: 11px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item.disabled .action-label,
|
||||
.monaco-action-bar .action-item.disabled .action-label:hover {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
/* Vertical actions */
|
||||
|
||||
.monaco-action-bar.vertical {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.monaco-action-bar.vertical .action-item {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.monaco-action-bar.vertical .action-label.separator {
|
||||
display: block;
|
||||
border-bottom: 1px solid #bbb;
|
||||
padding-top: 1px;
|
||||
margin-left: .8em;
|
||||
margin-right: .8em;
|
||||
}
|
||||
|
||||
.monaco-action-bar.animated.vertical .action-item.active {
|
||||
transform: translate(5px, 0);
|
||||
}
|
||||
|
||||
.secondary-actions .monaco-action-bar .action-label {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
/* Action Items */
|
||||
.monaco-action-bar .action-item.select-container {
|
||||
overflow: hidden; /* somehow the dropdown overflows its container, we prevent it here to not push */
|
||||
flex: 1;
|
||||
max-width: 170px;
|
||||
min-width: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical {
|
||||
margin-left: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .actions-container {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item {
|
||||
padding: 0;
|
||||
transform: none;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item.active {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-menu-item {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
height: 2em;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label {
|
||||
flex: 1 1 auto;
|
||||
text-decoration: none;
|
||||
padding: 0 1em;
|
||||
background: none;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .keybinding,
|
||||
.monaco-menu .monaco-action-bar.vertical .submenu-indicator {
|
||||
display: inline-block;
|
||||
flex: 2 1 auto;
|
||||
padding: 0 1em;
|
||||
text-align: right;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .submenu-indicator {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .submenu-indicator.codicon {
|
||||
font-size: 16px !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .submenu-indicator.codicon::before {
|
||||
margin-left: auto;
|
||||
margin-right: -20px;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item.disabled .keybinding,
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item.disabled .submenu-indicator {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label:not(.separator) {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item {
|
||||
position: static;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item .monaco-submenu {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label.separator {
|
||||
padding: 0.5em 0 0 0;
|
||||
margin-bottom: 0.5em;
|
||||
width: 100%;
|
||||
height: 0px !important;
|
||||
margin-left: .8em !important;
|
||||
margin-right: .8em !important;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label.separator.text {
|
||||
padding: 0.7em 1em 0.1em 1em;
|
||||
font-weight: bold;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label:hover {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .menu-item-check {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
width: 1em;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-menu-item.checked .menu-item-check {
|
||||
visibility: visible;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Context Menu */
|
||||
|
||||
.context-view.monaco-menu-container {
|
||||
outline: 0;
|
||||
border: none;
|
||||
animation: fadeIn 0.083s linear;
|
||||
}
|
||||
|
||||
.context-view.monaco-menu-container :focus,
|
||||
.context-view.monaco-menu-container .monaco-action-bar.vertical:focus,
|
||||
.context-view.monaco-menu-container .monaco-action-bar.vertical :focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item {
|
||||
border: thin solid transparent; /* prevents jumping behaviour on hover or focus */
|
||||
}
|
||||
|
||||
|
||||
/* High Contrast Theming */
|
||||
.hc-black .context-view.monaco-menu-container {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.hc-black .monaco-menu .monaco-action-bar.vertical .action-item.focused {
|
||||
background: none;
|
||||
}
|
||||
|
||||
/* Vertical Action Bar Styles */
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical {
|
||||
padding: .5em 0;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-menu-item {
|
||||
height: 1.8em;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label:not(.separator),
|
||||
.monaco-menu .monaco-action-bar.vertical .keybinding {
|
||||
font-size: inherit;
|
||||
padding: 0 2em;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .menu-item-check {
|
||||
font-size: inherit;
|
||||
width: 2em;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label.separator {
|
||||
font-size: inherit;
|
||||
padding: 0.2em 0 0 0;
|
||||
margin-bottom: 0.2em;
|
||||
}
|
||||
|
||||
linux .monaco-menu .monaco-action-bar.vertical .action-label.separator {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .submenu-indicator {
|
||||
font-size: 60%;
|
||||
padding: 0 1.8em;
|
||||
}
|
||||
|
||||
:host-context(.linux) .monaco-menu .monaco-action-bar.vertical .submenu-indicator {
|
||||
height: 100%;
|
||||
mask-size: 10px 10px;
|
||||
-webkit-mask-size: 10px 10px;
|
||||
}
|
||||
|
||||
.monaco-menu .action-item {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
83
src/vs/base/browser/ui/menu/menubar.css
Normal file
83
src/vs/base/browser/ui/menu/menubar.css
Normal file
@@ -0,0 +1,83 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* Menubar styles */
|
||||
|
||||
.menubar {
|
||||
display: flex;
|
||||
flex-shrink: 1;
|
||||
box-sizing: border-box;
|
||||
height: 30px;
|
||||
overflow: hidden;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.fullscreen .menubar:not(.compact) {
|
||||
margin: 0px;
|
||||
padding: 0px 5px;
|
||||
}
|
||||
|
||||
.menubar > .menubar-menu-button {
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
padding: 0px 8px;
|
||||
cursor: default;
|
||||
-webkit-app-region: no-drag;
|
||||
zoom: 1;
|
||||
white-space: nowrap;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.menubar.compact {
|
||||
flex-shrink: 0;
|
||||
overflow: visible; /* to avoid the compact menu to be repositioned when clicking */
|
||||
}
|
||||
|
||||
.menubar.compact > .menubar-menu-button {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.menubar .menubar-menu-items-holder {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
opacity: 1;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.menubar .menubar-menu-items-holder.monaco-menu-container {
|
||||
outline: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.menubar .menubar-menu-items-holder.monaco-menu-container :focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.menubar .toolbar-toggle-more {
|
||||
width: 20px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.menubar.compact .toolbar-toggle-more {
|
||||
position: relative;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.menubar .toolbar-toggle-more {
|
||||
padding: 0;
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
.menubar.compact .toolbar-toggle-more::before {
|
||||
content: "\eb94" !important;
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./menubar';
|
||||
import * as browser from 'vs/base/browser/browser';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { regExpFlags } from 'vs/base/common/strings';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
export function stringify(obj: any): string {
|
||||
return JSON.stringify(obj, replacer);
|
||||
@@ -44,10 +45,23 @@ export function revive(obj: any, depth = 0): any {
|
||||
case 2: return new RegExp(obj.source, obj.flags);
|
||||
}
|
||||
|
||||
// walk object (or array)
|
||||
for (let key in obj) {
|
||||
if (Object.hasOwnProperty.call(obj, key)) {
|
||||
obj[key] = revive(obj[key], depth + 1);
|
||||
if (
|
||||
obj instanceof VSBuffer
|
||||
|| obj instanceof Uint8Array
|
||||
) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
for (let i = 0; i < obj.length; ++i) {
|
||||
obj[i] = revive(obj[i], depth + 1);
|
||||
}
|
||||
} else {
|
||||
// walk object
|
||||
for (const key in obj) {
|
||||
if (Object.hasOwnProperty.call(obj, key)) {
|
||||
obj[key] = revive(obj[key], depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ export interface ISocket extends IDisposable {
|
||||
onEnd(listener: () => void): IDisposable;
|
||||
write(buffer: VSBuffer): void;
|
||||
end(): void;
|
||||
drain(): Promise<void>;
|
||||
}
|
||||
|
||||
let emptyBuffer: VSBuffer | null = null;
|
||||
@@ -277,6 +278,11 @@ class ProtocolWriter {
|
||||
this._isDisposed = true;
|
||||
}
|
||||
|
||||
public drain(): Promise<void> {
|
||||
this.flush();
|
||||
return this._socket.drain();
|
||||
}
|
||||
|
||||
public flush(): void {
|
||||
// flush
|
||||
this._writeNow();
|
||||
@@ -372,6 +378,10 @@ export class Protocol extends Disposable implements IMessagePassingProtocol {
|
||||
this._register(this._socket.onClose(() => this._onClose.fire()));
|
||||
}
|
||||
|
||||
drain(): Promise<void> {
|
||||
return this._socketWriter.drain();
|
||||
}
|
||||
|
||||
getSocket(): ISocket {
|
||||
return this._socket;
|
||||
}
|
||||
@@ -619,6 +629,10 @@ export class PersistentProtocol implements IMessagePassingProtocol {
|
||||
this._socketDisposables = dispose(this._socketDisposables);
|
||||
}
|
||||
|
||||
drain(): Promise<void> {
|
||||
return this._socketWriter.drain();
|
||||
}
|
||||
|
||||
sendDisconnect(): void {
|
||||
const msg = new ProtocolMessage(ProtocolMessageType.Disconnect, 0, 0, getEmptyBuffer());
|
||||
this._socketWriter.write(msg);
|
||||
|
||||
@@ -70,6 +70,10 @@ interface IHandler {
|
||||
export interface IMessagePassingProtocol {
|
||||
send(buffer: VSBuffer): void;
|
||||
onMessage: Event<VSBuffer>;
|
||||
/**
|
||||
* Wait for the write buffer (if applicable) to become empty.
|
||||
*/
|
||||
drain?(): Promise<void>;
|
||||
}
|
||||
|
||||
enum State {
|
||||
@@ -482,10 +486,7 @@ export class ChannelClient implements IChannelClient, IDisposable {
|
||||
return e(errors.canceled());
|
||||
}
|
||||
|
||||
let uninitializedPromise: CancelablePromise<void> | null = createCancelablePromise(_ => this.whenInitialized());
|
||||
uninitializedPromise.then(() => {
|
||||
uninitializedPromise = null;
|
||||
|
||||
const doRequest = () => {
|
||||
const handler: IHandler = response => {
|
||||
switch (response.type) {
|
||||
case ResponseType.PromiseSuccess:
|
||||
@@ -510,7 +511,18 @@ export class ChannelClient implements IChannelClient, IDisposable {
|
||||
|
||||
this.handlers.set(id, handler);
|
||||
this.sendRequest(request);
|
||||
});
|
||||
};
|
||||
|
||||
let uninitializedPromise: CancelablePromise<void> | null = null;
|
||||
if (this.state === State.Idle) {
|
||||
doRequest();
|
||||
} else {
|
||||
uninitializedPromise = createCancelablePromise(_ => this.whenInitialized());
|
||||
uninitializedPromise.then(() => {
|
||||
uninitializedPromise = null;
|
||||
doRequest();
|
||||
});
|
||||
}
|
||||
|
||||
const cancel = () => {
|
||||
if (uninitializedPromise) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { ISocket, Protocol, Client, ChunkStream } from 'vs/base/parts/ipc/common/ipc.net';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
|
||||
export class NodeSocket implements ISocket {
|
||||
public readonly socket: Socket;
|
||||
@@ -57,12 +58,47 @@ export class NodeSocket implements ISocket {
|
||||
// > https://nodejs.org/api/stream.html#stream_writable_write_chunk_encoding_callback
|
||||
// > However, the false return value is only advisory and the writable stream will unconditionally
|
||||
// > accept and buffer chunk even if it has not been allowed to drain.
|
||||
this.socket.write(<Buffer>buffer.buffer);
|
||||
try {
|
||||
this.socket.write(<Buffer>buffer.buffer);
|
||||
} catch (err) {
|
||||
if (err.code === 'EPIPE') {
|
||||
// An EPIPE exception at the wrong time can lead to a renderer process crash
|
||||
// so ignore the error since the socket will fire the close event soon anyways:
|
||||
// > https://nodejs.org/api/errors.html#errors_common_system_errors
|
||||
// > EPIPE (Broken pipe): A write on a pipe, socket, or FIFO for which there is no
|
||||
// > process to read the data. Commonly encountered at the net and http layers,
|
||||
// > indicative that the remote side of the stream being written to has been closed.
|
||||
return;
|
||||
}
|
||||
onUnexpectedError(err);
|
||||
}
|
||||
}
|
||||
|
||||
public end(): void {
|
||||
this.socket.end();
|
||||
}
|
||||
|
||||
public drain(): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
if (this.socket.bufferSize === 0) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
const finished = () => {
|
||||
this.socket.off('close', finished);
|
||||
this.socket.off('end', finished);
|
||||
this.socket.off('error', finished);
|
||||
this.socket.off('timeout', finished);
|
||||
this.socket.off('drain', finished);
|
||||
resolve();
|
||||
};
|
||||
this.socket.on('close', finished);
|
||||
this.socket.on('end', finished);
|
||||
this.socket.on('error', finished);
|
||||
this.socket.on('timeout', finished);
|
||||
this.socket.on('drain', finished);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const enum Constants {
|
||||
@@ -229,6 +265,10 @@ export class WebSocketNodeSocket extends Disposable implements ISocket {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public drain(): Promise<void> {
|
||||
return this.socket.drain();
|
||||
}
|
||||
}
|
||||
|
||||
function unmask(buffer: VSBuffer, mask: number): void {
|
||||
|
||||
Reference in New Issue
Block a user