Merge from vscode 52dcb723a39ae75bee1bd56b3312d7fcdc87aeed (#6719)

This commit is contained in:
Anthony Dresser
2019-08-12 21:31:51 -07:00
committed by GitHub
parent 00250839fc
commit 7eba8c4c03
616 changed files with 9472 additions and 7087 deletions

View File

@@ -56,7 +56,7 @@ class WindowManager {
}
// --- Fullscreen
private _fullscreen: boolean;
private _fullscreen: boolean = false;
private readonly _onDidChangeFullscreen = new Emitter<void>();
public readonly onDidChangeFullscreen: Event<void> = this._onDidChangeFullscreen.event;

View File

@@ -50,8 +50,8 @@ interface IDomClassList {
const _manualClassList = new class implements IDomClassList {
private _lastStart: number;
private _lastEnd: number;
private _lastStart: number = -1;
private _lastEnd: number = -1;
private _findClassName(node: HTMLElement, className: string): void {
@@ -1200,7 +1200,7 @@ export function asDomUri(uri: URI): URI {
if (Schemas.vscodeRemote === uri.scheme) {
// rewrite vscode-remote-uris to uris of the window location
// so that they can be intercepted by the service worker
return _location.with({ path: '/vscode-resources/fetch', query: `u=${JSON.stringify(uri)}` });
return _location.with({ path: '/vscode-remote', query: JSON.stringify(uri) });
}
return uri;
}

View File

@@ -69,7 +69,7 @@ export class Gesture extends Disposable {
private static INSTANCE: Gesture;
private static HOLD_DELAY = 700;
private dispatched: boolean;
private dispatched = false;
private targets: HTMLElement[];
private handle: IDisposable | null;

View File

@@ -37,7 +37,7 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
_context: any;
_action: IAction;
private _actionRunner: IActionRunner;
private _actionRunner!: IActionRunner;
constructor(context: any, action: IAction, protected options?: IBaseActionViewItemOptions) {
super();
@@ -232,7 +232,7 @@ export interface IActionViewItemOptions extends IBaseActionViewItemOptions {
export class ActionViewItem extends BaseActionViewItem {
protected label: HTMLElement;
protected label!: HTMLElement;
protected options: IActionViewItemOptions;
private cssClass?: string;

View File

@@ -77,8 +77,8 @@ export class BreadcrumbsWidget {
private _focusedItemIdx: number = -1;
private _selectedItemIdx: number = -1;
private _pendingLayout: IDisposable;
private _dimension: dom.Dimension;
private _pendingLayout: IDisposable | undefined;
private _dimension: dom.Dimension | undefined;
constructor(
container: HTMLElement

View File

@@ -20,10 +20,12 @@ const GOLDEN_RATIO = {
rightMarginRatio: 0.1909
};
function createEmptyView(background: Color): ISplitViewView {
function createEmptyView(background: Color | undefined): ISplitViewView {
const element = $('.centered-layout-margin');
element.style.height = '100%';
element.style.backgroundColor = background.toString();
if (background) {
element.style.backgroundColor = background.toString();
}
return {
element,
@@ -53,7 +55,7 @@ export class CenteredViewLayout implements IDisposable {
private splitView?: SplitView;
private width: number = 0;
private height: number = 0;
private style: ICenteredViewStyles;
private style!: ICenteredViewStyles;
private didLayout = false;
private emptyViews: ISplitViewView[] | undefined;
private readonly splitViewDisposables = new DisposableStore();
@@ -132,7 +134,8 @@ export class CenteredViewLayout implements IDisposable {
this.splitView.layout(this.width);
this.splitView.addView(toSplitViewView(this.view, () => this.height), 0);
this.emptyViews = [createEmptyView(this.style.background), createEmptyView(this.style.background)];
const backgroundColor = this.style ? this.style.background : undefined;
this.emptyViews = [createEmptyView(backgroundColor), createEmptyView(backgroundColor)];
this.splitView.addView(this.emptyViews[0], this.state.leftMarginRatio * this.width, 0);
this.splitView.addView(this.emptyViews[1], this.state.rightMarginRatio * this.width, 2);
} else {

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 3.76345L5.80687 11.9351L5.08584 11.8927L1 7.29614L1.76345 6.61752L5.50997 10.8324L14.3214 3L15 3.76345Z" fill="#C5C5C5"/>
</svg>

After

Width:  |  Height:  |  Size: 278 B

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 3.76345L5.80687 11.9351L5.08584 11.8927L1 7.29614L1.76345 6.61752L5.50997 10.8324L14.3214 3L15 3.76345Z" fill="#424242"/>
</svg>

After

Width:  |  Height:  |  Size: 278 B

View File

@@ -39,4 +39,24 @@
.hc-black .monaco-custom-checkbox:hover {
background: none;
}
}
.monaco-custom-checkbox.monaco-simple-checkbox {
height: 18px;
width: 18px;
border: 1px solid transparent;
border-radius: 3px;
margin-right: 9px;
margin-left: 0px;
padding: 0px;
opacity: 1;
background-size: 16px !important;
}
.monaco-custom-checkbox.monaco-simple-checkbox.checked {
background: url('check-light.svg') center center no-repeat;
}
.monaco-custom-checkbox.monaco-simple-checkbox.checked {
background: url('check-dark.svg') center center no-repeat;
}

View File

@@ -25,6 +25,12 @@ export interface ICheckboxStyles {
inputActiveOptionBackground?: Color;
}
export interface ISimpleCheckboxStyles {
checkboxBackground?: Color;
checkboxBorder?: Color;
checkboxForeground?: Color;
}
const defaultOpts = {
inputActiveOptionBorder: Color.fromHex('#007ACC00'),
inputActiveOptionBackground: Color.fromHex('#0E639C50')
@@ -32,7 +38,7 @@ const defaultOpts = {
export class CheckboxActionViewItem extends BaseActionViewItem {
private checkbox: Checkbox;
private checkbox!: Checkbox;
private readonly disposables = new DisposableStore();
render(container: HTMLElement): void {
@@ -45,7 +51,7 @@ export class CheckboxActionViewItem extends BaseActionViewItem {
title: this._action.label
});
this.disposables.add(this.checkbox);
this.disposables.add(this.checkbox.onChange(() => this._action.checked = this.checkbox.checked, this));
this.disposables.add(this.checkbox.onChange(() => this._action.checked = this.checkbox!.checked, this));
this.element.appendChild(this.checkbox.domNode);
}
@@ -174,3 +180,46 @@ export class Checkbox extends Widget {
this.domNode.setAttribute('aria-disabled', String(true));
}
}
export class SimpleCheckbox extends Widget {
private checkbox: Checkbox;
private styles: ISimpleCheckboxStyles;
readonly domNode: HTMLElement;
constructor(private title: string, private isChecked: boolean) {
super();
this.checkbox = new Checkbox({ title: this.title, isChecked: this.isChecked, actionClassName: 'monaco-simple-checkbox' });
this.domNode = this.checkbox.domNode;
this.styles = {};
this.checkbox.onChange(() => {
this.applyStyles();
});
}
get checked(): boolean {
return this.checkbox.checked;
}
set checked(newIsChecked: boolean) {
this.checkbox.checked = newIsChecked;
this.applyStyles();
}
style(styles: ISimpleCheckboxStyles): void {
this.styles = styles;
this.applyStyles();
}
protected applyStyles(): void {
this.domNode.style.color = this.styles.checkboxForeground ? this.styles.checkboxForeground.toString() : null;
this.domNode.style.backgroundColor = this.styles.checkboxBackground ? this.styles.checkboxBackground.toString() : null;
this.domNode.style.borderColor = this.styles.checkboxBorder ? this.styles.checkboxBorder.toString() : null;
}
}

View File

@@ -5,7 +5,7 @@
import 'vs/css!./contextview';
import * as DOM from 'vs/base/browser/dom';
import { IDisposable, dispose, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IDisposable, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { Range } from 'vs/base/common/range';
export interface IAnchor {
@@ -100,11 +100,11 @@ export class ContextView extends Disposable {
private static readonly BUBBLE_UP_EVENTS = ['click', 'keydown', 'focus', 'blur'];
private static readonly BUBBLE_DOWN_EVENTS = ['click'];
private container: HTMLElement | null;
private container: HTMLElement | null = null;
private view: HTMLElement;
private delegate: IDelegate | null;
private toDisposeOnClean: IDisposable | null;
private toDisposeOnSetContainer: IDisposable;
private delegate: IDelegate | null = null;
private toDisposeOnClean: IDisposable = Disposable.None;
private toDisposeOnSetContainer: IDisposable = Disposable.None;
constructor(container: HTMLElement) {
super();
@@ -120,7 +120,7 @@ export class ContextView extends Disposable {
setContainer(container: HTMLElement | null): void {
if (this.container) {
dispose(this.toDisposeOnSetContainer);
this.toDisposeOnSetContainer.dispose();
this.container.removeChild(this.view);
this.container = null;
}
@@ -159,7 +159,7 @@ export class ContextView extends Disposable {
DOM.show(this.view);
// Render content
this.toDisposeOnClean = delegate.render(this.view);
this.toDisposeOnClean = delegate.render(this.view) || Disposable.None;
// Set active delegate
this.delegate = delegate;
@@ -267,10 +267,7 @@ export class ContextView extends Disposable {
delegate.onHide(data);
}
if (this.toDisposeOnClean) {
this.toDisposeOnClean.dispose();
this.toDisposeOnClean = null;
}
this.toDisposeOnClean.dispose();
DOM.hide(this.view);
}

View File

@@ -29,7 +29,7 @@ const defaultOpts = {
export class CountBadge {
private element: HTMLElement;
private count: number;
private count: number = 0;
private countFormat: string;
private titleFormat: string;

View File

@@ -149,6 +149,11 @@
outline-style: solid;
}
.monaco-workbench .dialog-box .dialog-message-row .dialog-message-container .dialog-checkbox-row {
padding: 15px 0px 0px;
display: flex;
}
/** Dialog: Buttons Row */
.monaco-workbench .dialog-box > .dialog-buttons-row {
display: flex;
@@ -175,4 +180,4 @@
margin: 4px 5px; /* allows button focus outline to be visible */
overflow: hidden;
text-overflow: ellipsis;
}
}

View File

@@ -16,15 +16,23 @@ import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action } from 'vs/base/common/actions';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { isMacintosh, isLinux } from 'vs/base/common/platform';
import { SimpleCheckbox, ISimpleCheckboxStyles } from 'vs/base/browser/ui/checkbox/checkbox';
export interface IDialogOptions {
cancelId?: number;
detail?: string;
checkboxLabel?: string;
checkboxChecked?: boolean;
type?: 'none' | 'info' | 'error' | 'question' | 'warning' | 'pending';
keyEventProcessor?: (event: StandardKeyboardEvent) => void;
}
export interface IDialogStyles extends IButtonStyles {
export interface IDialogResult {
button: number;
checkboxChecked?: boolean;
}
export interface IDialogStyles extends IButtonStyles, ISimpleCheckboxStyles {
dialogForeground?: Color;
dialogBackground?: Color;
dialogShadow?: Color;
@@ -42,6 +50,7 @@ export class Dialog extends Disposable {
private buttonsContainer: HTMLElement | undefined;
private messageDetailElement: HTMLElement | undefined;
private iconElement: HTMLElement | undefined;
private checkbox: SimpleCheckbox | undefined;
private toolbarContainer: HTMLElement | undefined;
private buttonGroup: ButtonGroup | undefined;
private styles: IDialogStyles | undefined;
@@ -68,6 +77,19 @@ export class Dialog extends Disposable {
this.messageDetailElement = messageContainer.appendChild($('.dialog-message-detail'));
this.messageDetailElement.innerText = this.options.detail ? this.options.detail : message;
if (this.options.checkboxLabel) {
const checkboxRowElement = messageContainer.appendChild($('.dialog-checkbox-row'));
this.checkbox = this._register(new SimpleCheckbox(this.options.checkboxLabel, !!this.options.checkboxChecked));
checkboxRowElement.appendChild(this.checkbox.domNode);
const checkboxMessageElement = checkboxRowElement.appendChild($('.dialog-checkbox-message'));
checkboxMessageElement.innerText = this.options.checkboxLabel;
}
const toolbarRowElement = this.element.appendChild($('.dialog-toolbar-row'));
this.toolbarContainer = toolbarRowElement.appendChild($('.dialog-toolbar'));
}
@@ -78,12 +100,12 @@ export class Dialog extends Disposable {
}
}
async show(): Promise<number> {
async show(): Promise<IDialogResult> {
this.focusToReturn = document.activeElement as HTMLElement;
return new Promise<number>((resolve) => {
return new Promise<IDialogResult>((resolve) => {
if (!this.element || !this.buttonsContainer || !this.iconElement || !this.toolbarContainer) {
resolve(0);
resolve({ button: 0 });
return;
}
@@ -112,7 +134,7 @@ export class Dialog extends Disposable {
this._register(button.onDidClick(e => {
EventHelper.stop(e);
resolve(buttonMap[index].index);
resolve({ button: buttonMap[index].index, checkboxChecked: this.checkbox ? this.checkbox.checked : undefined });
}));
});
@@ -147,7 +169,7 @@ export class Dialog extends Disposable {
const evt = new StandardKeyboardEvent(e);
if (evt.equals(KeyCode.Escape)) {
resolve(this.options.cancelId || 0);
resolve({ button: this.options.cancelId || 0, checkboxChecked: this.checkbox ? this.checkbox.checked : undefined });
}
}));
@@ -187,7 +209,7 @@ export class Dialog extends Disposable {
const actionBar = new ActionBar(this.toolbarContainer, {});
const action = new Action('dialog.close', nls.localize('dialogClose', "Close Dialog"), 'dialog-close-action', true, () => {
resolve(this.options.cancelId || 0);
resolve({ button: this.options.cancelId || 0, checkboxChecked: this.checkbox ? this.checkbox.checked : undefined });
return Promise.resolve();
});
@@ -221,6 +243,10 @@ export class Dialog extends Disposable {
if (this.buttonGroup) {
this.buttonGroup.buttons.forEach(button => button.style(style));
}
if (this.checkbox) {
this.checkbox.style(style);
}
}
}
}
@@ -261,4 +287,4 @@ export class Dialog extends Disposable {
return buttonMap;
}
}
}

View File

@@ -29,7 +29,7 @@ export class BaseDropdown extends ActionRunner {
private boxContainer?: HTMLElement;
private _label?: HTMLElement;
private contents?: HTMLElement;
private visible: boolean;
private visible: boolean | undefined;
constructor(container: HTMLElement, options: IBaseDropdownOptions) {
super();
@@ -109,7 +109,7 @@ export class BaseDropdown extends ActionRunner {
}
isVisible(): boolean {
return this.visible;
return !!this.visible;
}
protected onEvent(e: Event, activeElement: HTMLElement): void {
@@ -272,7 +272,7 @@ export class DropdownMenu extends BaseDropdown {
export class DropdownMenuActionViewItem extends BaseActionViewItem {
private menuActionsOrProvider: any;
private dropdownMenu: DropdownMenu;
private dropdownMenu: DropdownMenu | undefined;
private contextMenuProvider: IContextMenuProvider;
private actionViewItemProvider?: IActionViewItemProvider;
private keybindings?: (action: IAction) => ResolvedKeybinding | undefined;
@@ -281,7 +281,7 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem {
constructor(action: IAction, menuActions: ReadonlyArray<IAction>, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment);
constructor(action: IAction, actionProvider: IActionProvider, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment);
constructor(action: IAction, menuActionsOrProvider: any, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment) {
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) {
super(null, action);
this.menuActionsOrProvider = menuActionsOrProvider;

View File

@@ -114,7 +114,130 @@ export class FindInput extends Widget {
this.inputValidationErrorBackground = options.inputValidationErrorBackground;
this.inputValidationErrorForeground = options.inputValidationErrorForeground;
this.buildDomNode(options.appendCaseSensitiveLabel || '', options.appendWholeWordsLabel || '', options.appendRegexLabel || '', options.history || [], !!options.flexibleHeight);
const appendCaseSensitiveLabel = options.appendCaseSensitiveLabel || '';
const appendWholeWordsLabel = options.appendWholeWordsLabel || '';
const appendRegexLabel = options.appendRegexLabel || '';
const history = options.history || [];
const flexibleHeight = !!options.flexibleHeight;
this.domNode = document.createElement('div');
dom.addClass(this.domNode, 'monaco-findInput');
this.inputBox = this._register(new HistoryInputBox(this.domNode, this.contextViewProvider, {
placeholder: this.placeholder || '',
ariaLabel: this.label || '',
validationOptions: {
validation: this.validation
},
inputBackground: this.inputBackground,
inputForeground: this.inputForeground,
inputBorder: this.inputBorder,
inputValidationInfoBackground: this.inputValidationInfoBackground,
inputValidationInfoForeground: this.inputValidationInfoForeground,
inputValidationInfoBorder: this.inputValidationInfoBorder,
inputValidationWarningBackground: this.inputValidationWarningBackground,
inputValidationWarningForeground: this.inputValidationWarningForeground,
inputValidationWarningBorder: this.inputValidationWarningBorder,
inputValidationErrorBackground: this.inputValidationErrorBackground,
inputValidationErrorForeground: this.inputValidationErrorForeground,
inputValidationErrorBorder: this.inputValidationErrorBorder,
history,
flexibleHeight
}));
this.regex = this._register(new RegexCheckbox({
appendTitle: appendRegexLabel,
isChecked: false,
inputActiveOptionBorder: this.inputActiveOptionBorder,
inputActiveOptionBackground: this.inputActiveOptionBackground
}));
this._register(this.regex.onChange(viaKeyboard => {
this._onDidOptionChange.fire(viaKeyboard);
if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
this.inputBox.focus();
}
this.validate();
}));
this._register(this.regex.onKeyDown(e => {
this._onRegexKeyDown.fire(e);
}));
this.wholeWords = this._register(new WholeWordsCheckbox({
appendTitle: appendWholeWordsLabel,
isChecked: false,
inputActiveOptionBorder: this.inputActiveOptionBorder,
inputActiveOptionBackground: this.inputActiveOptionBackground
}));
this._register(this.wholeWords.onChange(viaKeyboard => {
this._onDidOptionChange.fire(viaKeyboard);
if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
this.inputBox.focus();
}
this.validate();
}));
this.caseSensitive = this._register(new CaseSensitiveCheckbox({
appendTitle: appendCaseSensitiveLabel,
isChecked: false,
inputActiveOptionBorder: this.inputActiveOptionBorder,
inputActiveOptionBackground: this.inputActiveOptionBackground
}));
this._register(this.caseSensitive.onChange(viaKeyboard => {
this._onDidOptionChange.fire(viaKeyboard);
if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
this.inputBox.focus();
}
this.validate();
}));
this._register(this.caseSensitive.onKeyDown(e => {
this._onCaseSensitiveKeyDown.fire(e);
}));
if (this._showOptionButtons) {
const paddingRight = (this.caseSensitive.width() + this.wholeWords.width() + this.regex.width()) + 'px';
this.inputBox.inputElement.style.paddingRight = paddingRight;
if (this.inputBox.mirrorElement) {
this.inputBox.mirrorElement.style.paddingRight = paddingRight;
}
}
// Arrow-Key support to navigate between options
let indexes = [this.caseSensitive.domNode, this.wholeWords.domNode, this.regex.domNode];
this.onkeydown(this.domNode, (event: IKeyboardEvent) => {
if (event.equals(KeyCode.LeftArrow) || event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Escape)) {
let index = indexes.indexOf(<HTMLElement>document.activeElement);
if (index >= 0) {
let newIndex: number = -1;
if (event.equals(KeyCode.RightArrow)) {
newIndex = (index + 1) % indexes.length;
} else if (event.equals(KeyCode.LeftArrow)) {
if (index === 0) {
newIndex = indexes.length - 1;
} else {
newIndex = index - 1;
}
}
if (event.equals(KeyCode.Escape)) {
indexes[index].blur();
} else if (newIndex >= 0) {
indexes[newIndex].focus();
}
dom.EventHelper.stop(event, true);
}
}
});
let controls = document.createElement('div');
controls.className = 'controls';
controls.style.display = this._showOptionButtons ? 'block' : 'none';
controls.appendChild(this.caseSensitive.domNode);
controls.appendChild(this.wholeWords.domNode);
controls.appendChild(this.regex.domNode);
this.domNode.appendChild(controls);
if (parent) {
parent.appendChild(this.domNode);
@@ -270,127 +393,6 @@ export class FindInput extends Widget {
dom.addClass(this.domNode, 'highlight-' + (this._lastHighlightFindOptions));
}
private buildDomNode(appendCaseSensitiveLabel: string, appendWholeWordsLabel: string, appendRegexLabel: string, history: string[], flexibleHeight: boolean): void {
this.domNode = document.createElement('div');
dom.addClass(this.domNode, 'monaco-findInput');
this.inputBox = this._register(new HistoryInputBox(this.domNode, this.contextViewProvider, {
placeholder: this.placeholder || '',
ariaLabel: this.label || '',
validationOptions: {
validation: this.validation
},
inputBackground: this.inputBackground,
inputForeground: this.inputForeground,
inputBorder: this.inputBorder,
inputValidationInfoBackground: this.inputValidationInfoBackground,
inputValidationInfoForeground: this.inputValidationInfoForeground,
inputValidationInfoBorder: this.inputValidationInfoBorder,
inputValidationWarningBackground: this.inputValidationWarningBackground,
inputValidationWarningForeground: this.inputValidationWarningForeground,
inputValidationWarningBorder: this.inputValidationWarningBorder,
inputValidationErrorBackground: this.inputValidationErrorBackground,
inputValidationErrorForeground: this.inputValidationErrorForeground,
inputValidationErrorBorder: this.inputValidationErrorBorder,
history,
flexibleHeight
}));
this.regex = this._register(new RegexCheckbox({
appendTitle: appendRegexLabel,
isChecked: false,
inputActiveOptionBorder: this.inputActiveOptionBorder,
inputActiveOptionBackground: this.inputActiveOptionBackground
}));
this._register(this.regex.onChange(viaKeyboard => {
this._onDidOptionChange.fire(viaKeyboard);
if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
this.inputBox.focus();
}
this.validate();
}));
this._register(this.regex.onKeyDown(e => {
this._onRegexKeyDown.fire(e);
}));
this.wholeWords = this._register(new WholeWordsCheckbox({
appendTitle: appendWholeWordsLabel,
isChecked: false,
inputActiveOptionBorder: this.inputActiveOptionBorder,
inputActiveOptionBackground: this.inputActiveOptionBackground
}));
this._register(this.wholeWords.onChange(viaKeyboard => {
this._onDidOptionChange.fire(viaKeyboard);
if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
this.inputBox.focus();
}
this.validate();
}));
this.caseSensitive = this._register(new CaseSensitiveCheckbox({
appendTitle: appendCaseSensitiveLabel,
isChecked: false,
inputActiveOptionBorder: this.inputActiveOptionBorder,
inputActiveOptionBackground: this.inputActiveOptionBackground
}));
this._register(this.caseSensitive.onChange(viaKeyboard => {
this._onDidOptionChange.fire(viaKeyboard);
if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
this.inputBox.focus();
}
this.validate();
}));
this._register(this.caseSensitive.onKeyDown(e => {
this._onCaseSensitiveKeyDown.fire(e);
}));
if (this._showOptionButtons) {
const paddingRight = (this.caseSensitive.width() + this.wholeWords.width() + this.regex.width()) + 'px';
this.inputBox.inputElement.style.paddingRight = paddingRight;
if (this.inputBox.mirrorElement) {
this.inputBox.mirrorElement.style.paddingRight = paddingRight;
}
}
// Arrow-Key support to navigate between options
let indexes = [this.caseSensitive.domNode, this.wholeWords.domNode, this.regex.domNode];
this.onkeydown(this.domNode, (event: IKeyboardEvent) => {
if (event.equals(KeyCode.LeftArrow) || event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Escape)) {
let index = indexes.indexOf(<HTMLElement>document.activeElement);
if (index >= 0) {
let newIndex: number = -1;
if (event.equals(KeyCode.RightArrow)) {
newIndex = (index + 1) % indexes.length;
} else if (event.equals(KeyCode.LeftArrow)) {
if (index === 0) {
newIndex = indexes.length - 1;
} else {
newIndex = index - 1;
}
}
if (event.equals(KeyCode.Escape)) {
indexes[index].blur();
} else if (newIndex >= 0) {
indexes[newIndex].focus();
}
dom.EventHelper.stop(event, true);
}
}
});
let controls = document.createElement('div');
controls.className = 'controls';
controls.style.display = this._showOptionButtons ? 'block' : 'none';
controls.appendChild(this.caseSensitive.domNode);
controls.appendChild(this.wholeWords.domNode);
controls.appendChild(this.regex.domNode);
this.domNode.appendChild(controls);
}
public validate(): void {
if (this.inputBox) {
this.inputBox.validate();

View File

@@ -277,6 +277,24 @@ export class Grid<T extends IView = IView> extends Disposable {
this._addView(newView, viewSize, location);
}
addViewAt(newView: T, size: number | DistributeSizing | InvisibleSizing, location: number[]): void {
if (this.views.has(newView)) {
throw new Error('Can\'t add same view twice');
}
let viewSize: number | GridViewSizing;
if (typeof size === 'number') {
viewSize = size;
} else if (size.type === 'distribute') {
viewSize = GridViewSizing.Distribute;
} else {
viewSize = size;
}
this._addView(newView, viewSize, location);
}
protected _addView(newView: T, size: number | GridViewSizing, location: number[]): void {
this.views.set(newView, newView.element);
this.gridview.addView(newView, size, location);
@@ -308,6 +326,26 @@ export class Grid<T extends IView = IView> extends Disposable {
}
}
moveViewTo(view: T, location: number[]): void {
const sourceLocation = this.getViewLocation(view);
const [sourceParentLocation, from] = tail(sourceLocation);
const [targetParentLocation, to] = tail(location);
if (equals(sourceParentLocation, targetParentLocation)) {
this.gridview.moveView(sourceParentLocation, from, to);
} else {
const size = this.getViewSize(view);
const orientation = getLocationOrientation(this.gridview.orientation, sourceLocation);
const cachedViewSize = this.getViewCachedVisibleSize(view);
const sizing = typeof cachedViewSize === 'undefined'
? (orientation === Orientation.HORIZONTAL ? size.width : size.height)
: Sizing.Invisible(cachedViewSize);
this.removeView(view);
this.addViewAt(view, sizing, location);
}
}
swapViews(from: T, to: T): void {
const fromLocation = this.getViewLocation(from);
const toLocation = this.getViewLocation(to);
@@ -319,11 +357,20 @@ export class Grid<T extends IView = IView> extends Disposable {
return this.gridview.resizeView(location, size);
}
getViewSize(view: T): IViewSize {
getViewSize(view?: T): IViewSize {
if (!view) {
return this.gridview.getViewSize();
}
const location = this.getViewLocation(view);
return this.gridview.getViewSize(location);
}
getViewCachedVisibleSize(view: T): number | undefined {
const location = this.getViewLocation(view);
return this.gridview.getViewCachedVisibleSize(location);
}
maximizeViewSize(view: T): void {
const location = this.getViewLocation(view);
this.gridview.maximizeViewSize(location);
@@ -373,7 +420,7 @@ export class Grid<T extends IView = IView> extends Disposable {
.map(node => node.view);
}
private getViewLocation(view: T): number[] {
getViewLocation(view: T): number[] {
const element = this.views.get(view);
if (!element) {
@@ -422,7 +469,7 @@ export interface ISerializableView extends IView {
}
export interface IViewDeserializer<T extends ISerializableView> {
fromJSON(json: object | null): T;
fromJSON(json: any): T;
}
interface InitialLayoutContext<T extends ISerializableView> {
@@ -433,7 +480,7 @@ interface InitialLayoutContext<T extends ISerializableView> {
export interface ISerializedLeafNode {
type: 'leaf';
data: object | null;
data: any;
size: number;
visible?: boolean;
}

View File

@@ -11,6 +11,7 @@ import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'
import { $ } from 'vs/base/browser/dom';
import { tail2 as tail } from 'vs/base/common/arrays';
import { Color } from 'vs/base/common/color';
import { clamp } from 'vs/base/common/numbers';
export { Sizing, LayoutPriority } from 'vs/base/browser/ui/splitview/splitview';
export { Orientation } from 'vs/base/browser/ui/sash/sash';
@@ -277,9 +278,7 @@ class BranchNode implements ISplitView, IDisposable {
throw new Error('Invalid from index');
}
if (to < 0 || to > this.children.length) {
throw new Error('Invalid to index');
}
to = clamp(to, 0, this.children.length);
if (from < to) {
to--;
@@ -300,9 +299,7 @@ class BranchNode implements ISplitView, IDisposable {
throw new Error('Invalid from index');
}
if (to < 0 || to >= this.children.length) {
throw new Error('Invalid to index');
}
to = clamp(to, 0, this.children.length);
this.splitview.swapViews(from, to);
[this.children[from].orthogonalStartSash, this.children[from].orthogonalEndSash, this.children[to].orthogonalStartSash, this.children[to].orthogonalEndSash] = [this.children[to].orthogonalStartSash, this.children[to].orthogonalEndSash, this.children[from].orthogonalStartSash, this.children[from].orthogonalEndSash];
@@ -351,6 +348,7 @@ class BranchNode implements ISplitView, IDisposable {
}
this.splitview.setViewVisible(index, visible);
this._onDidChange.fire(undefined);
}
getChildCachedVisibleSize(index: number): number | undefined {
@@ -442,9 +440,6 @@ class LeafNode implements ISplitView, IDisposable {
private _size: number = 0;
get size(): number { return this._size; }
private _cachedVisibleSize: number | undefined;
get cachedVisibleSize(): number | undefined { return this._cachedVisibleSize; }
private _orthogonalSize: number;
get orthogonalSize(): number { return this._orthogonalSize; }
@@ -553,12 +548,6 @@ class LeafNode implements ISplitView, IDisposable {
}
setVisible(visible: boolean): void {
if (visible) {
this._cachedVisibleSize = undefined;
} else {
this._cachedVisibleSize = this._size;
}
if (this.view.setVisible) {
this.view.setVisible(visible);
}
@@ -610,7 +599,7 @@ export class GridView implements IDisposable {
private styles: IGridViewStyles;
private proportionalLayout: boolean;
private _root: BranchNode;
private _root!: BranchNode;
private onDidSashResetRelay = new Relay<number[]>();
readonly onDidSashReset: Event<number[]> = this.onDidSashResetRelay.event;
@@ -765,6 +754,7 @@ export class GridView implements IDisposable {
const [, parentIndex] = tail(rest);
const sibling = parent.children[0];
const isSiblingVisible = parent.isChildVisible(0);
parent.removeChild(0);
const sizes = grandParent.children.map((_, i) => grandParent.getChildSize(i));
@@ -779,7 +769,8 @@ export class GridView implements IDisposable {
}
} else {
const newSibling = new LeafNode(sibling.view, orthogonal(sibling.orientation), this.layoutController, sibling.size);
grandParent.addChild(newSibling, sibling.orthogonalSize, parentIndex);
const sizing = isSiblingVisible ? sibling.orthogonalSize : Sizing.Invisible(sibling.orthogonalSize);
grandParent.addChild(newSibling, sizing, parentIndex);
}
for (let i = 0; i < sizes.length; i++) {
@@ -868,11 +859,26 @@ export class GridView implements IDisposable {
}
}
getViewSize(location: number[]): IViewSize {
getViewSize(location?: number[]): IViewSize {
if (!location) {
return { width: this.root.width, height: this.root.height };
}
const [, node] = this.getNode(location);
return { width: node.width, height: node.height };
}
getViewCachedVisibleSize(location: number[]): number | undefined {
const [rest, index] = tail(location);
const [, parent] = this.getNode(rest);
if (!(parent instanceof BranchNode)) {
throw new Error('Invalid location');
}
return parent.getChildCachedVisibleSize(index);
}
maximizeViewSize(location: number[]): void {
const [ancestors, node] = this.getNode(location);
@@ -929,12 +935,13 @@ export class GridView implements IDisposable {
return this._getViews(node, this.orientation, { top: 0, left: 0, width: this.width, height: this.height });
}
private _getViews(node: Node, orientation: Orientation, box: Box): GridNode {
private _getViews(node: Node, orientation: Orientation, box: Box, cachedVisibleSize?: number): GridNode {
if (node instanceof LeafNode) {
return { view: node.view, box, cachedVisibleSize: node.cachedVisibleSize };
return { view: node.view, box, cachedVisibleSize };
}
const children: GridNode[] = [];
let i = 0;
let offset = 0;
for (const child of node.children) {
@@ -942,8 +949,9 @@ export class GridView implements IDisposable {
const childBox: Box = orientation === Orientation.HORIZONTAL
? { top: box.top, left: box.left + offset, width: child.width, height: box.height }
: { top: box.top + offset, left: box.left, width: box.width, height: child.height };
const cachedVisibleSize = node.getChildCachedVisibleSize(i++);
children.push(this._getViews(child, childOrientation, childBox));
children.push(this._getViews(child, childOrientation, childBox, cachedVisibleSize));
offset += orientation === Orientation.HORIZONTAL ? child.width : child.height;
}

View File

@@ -12,7 +12,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
export interface IIconLabelCreationOptions {
supportHighlights?: boolean;
supportDescriptionHighlights?: boolean;
donotSupportOcticons?: boolean;
supportOcticons?: boolean;
}
export interface IIconLabelValueOptions {
@@ -100,13 +100,13 @@ export class IconLabel extends Disposable {
this.labelDescriptionContainer = this._register(new FastLabelNode(dom.append(this.domNode.element, dom.$('.monaco-icon-label-description-container'))));
if (options && options.supportHighlights) {
this.labelNode = new HighlightedLabel(dom.append(this.labelDescriptionContainer.element, dom.$('a.label-name')), !options.donotSupportOcticons);
this.labelNode = new HighlightedLabel(dom.append(this.labelDescriptionContainer.element, dom.$('a.label-name')), !!options.supportOcticons);
} else {
this.labelNode = this._register(new FastLabelNode(dom.append(this.labelDescriptionContainer.element, dom.$('a.label-name'))));
}
if (options && options.supportDescriptionHighlights) {
this.descriptionNodeFactory = () => new HighlightedLabel(dom.append(this.labelDescriptionContainer.element, dom.$('span.label-description')), !options.donotSupportOcticons);
this.descriptionNodeFactory = () => new HighlightedLabel(dom.append(this.labelDescriptionContainer.element, dom.$('span.label-description')), !!options.supportOcticons);
} else {
this.descriptionNodeFactory = () => this._register(new FastLabelNode(dom.append(this.labelDescriptionContainer.element, dom.$('span.label-description'))));
}

View File

@@ -58,7 +58,12 @@
.monaco-inputbox > .wrapper > textarea.input {
display: block;
overflow: hidden;
-ms-overflow-style: none; /* IE 10+ */
overflow: -moz-scrollbars-none; /* Firefox */
}
.monaco-inputbox > .wrapper > textarea.input::-webkit-scrollbar {
display: none;
}
.monaco-inputbox > .wrapper > .mirror {
@@ -116,4 +121,4 @@
background-repeat: no-repeat;
width: 16px;
height: 16px;
}
}

View File

@@ -19,6 +19,9 @@ import { Color } from 'vs/base/common/color';
import { mixin } from 'vs/base/common/objects';
import { HistoryNavigator } from 'vs/base/common/history';
import { IHistoryNavigationWidget } from 'vs/base/browser/history';
import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
import { domEvent } from 'vs/base/browser/event';
const $ = dom.$;
@@ -28,6 +31,7 @@ export interface IInputOptions extends IInputBoxStyles {
readonly type?: string;
readonly validationOptions?: IInputValidationOptions;
readonly flexibleHeight?: boolean;
readonly flexibleMaxHeight?: number;
readonly actions?: ReadonlyArray<IAction>;
@@ -93,7 +97,6 @@ export class InputBox extends Widget {
private contextViewProvider?: IContextViewProvider;
element: HTMLElement;
private input: HTMLInputElement;
private mirror: HTMLElement;
private actionbar?: ActionBar;
private options: IInputOptions;
private message: IMessage | null;
@@ -101,7 +104,12 @@ export class InputBox extends Widget {
private ariaLabel: string;
private validation?: IInputValidator;
private state: 'idle' | 'open' | 'closed' = 'idle';
private cachedHeight: number | null;
private mirror: HTMLElement | undefined;
private cachedHeight: number | undefined;
private cachedContentHeight: number | undefined;
private maxHeight: number = Number.POSITIVE_INFINITY;
private scrollableElement: ScrollableElement | undefined;
// {{SQL CARBON EDIT}} - Add showValidationMessage and set inputBackground, inputForeground, and inputBorder as protected
protected showValidationMessage: boolean;
@@ -133,7 +141,6 @@ export class InputBox extends Widget {
this.options = options || Object.create(null);
mixin(this.options, defaultOpts, false);
this.message = null;
this.cachedHeight = null;
this.placeholder = this.options.placeholder || '';
this.ariaLabel = this.options.ariaLabel || '';
@@ -171,8 +178,26 @@ export class InputBox extends Widget {
this.onblur(this.input, () => dom.removeClass(this.element, 'synthetic-focus'));
if (this.options.flexibleHeight) {
this.maxHeight = typeof this.options.flexibleMaxHeight === 'number' ? this.options.flexibleMaxHeight : Number.POSITIVE_INFINITY;
this.mirror = dom.append(wrapper, $('div.mirror'));
this.mirror.innerHTML = '&nbsp;';
this.scrollableElement = new ScrollableElement(this.element, { vertical: ScrollbarVisibility.Auto });
dom.append(container, this.scrollableElement.getDomNode());
this._register(this.scrollableElement);
// from ScrollableElement to DOM
this._register(this.scrollableElement.onScroll(e => this.input.scrollTop = e.scrollTop));
const onSelectionChange = Event.filter(domEvent(document, 'selectionchange'), () => {
const selection = document.getSelection();
return !!selection && selection.anchorNode === wrapper;
});
// from DOM to ScrollableElement
this._register(onSelectionChange(this.updateScrollDimensions, this));
this._register(this.onDidHeightChange(this.updateScrollDimensions, this));
} else {
this.input.type = this.options.type || 'text';
this.input.setAttribute('wrap', 'off');
@@ -254,7 +279,7 @@ export class InputBox extends Widget {
}
}
public get mirrorElement(): HTMLElement {
public get mirrorElement(): HTMLElement | undefined {
return this.mirror;
}
@@ -274,7 +299,7 @@ export class InputBox extends Widget {
}
public get height(): number {
return this.cachedHeight === null ? dom.getTotalHeight(this.element) : this.cachedHeight;
return typeof this.cachedHeight === 'number' ? this.cachedHeight : dom.getTotalHeight(this.element);
}
public focus(): void {
@@ -325,6 +350,19 @@ export class InputBox extends Widget {
}
}
private updateScrollDimensions(): void {
if (typeof this.cachedContentHeight !== 'number' || typeof this.cachedHeight !== 'number') {
return;
}
const scrollHeight = this.cachedContentHeight;
const height = this.cachedHeight;
const scrollTop = this.input.scrollTop;
this.scrollableElement!.setScrollDimensions({ scrollHeight, height });
this.scrollableElement!.setScrollPosition({ scrollTop });
}
public showMessage(message: IMessage, force?: boolean): void {
this.message = message;
@@ -544,12 +582,13 @@ export class InputBox extends Widget {
return;
}
const previousHeight = this.cachedHeight;
this.cachedHeight = dom.getTotalHeight(this.mirror);
const previousHeight = this.cachedContentHeight;
this.cachedContentHeight = dom.getTotalHeight(this.mirror);
if (previousHeight !== this.cachedHeight) {
if (previousHeight !== this.cachedContentHeight) {
this.cachedHeight = Math.min(this.cachedContentHeight, this.maxHeight);
this.input.style.height = this.cachedHeight + 'px';
this._onDidHeightChange.fire(this.cachedHeight);
this._onDidHeightChange.fire(this.cachedContentHeight);
}
}

View File

@@ -73,7 +73,7 @@ class PagedRenderer<TElement, TTemplateData> implements IListRenderer<number, IT
export class PagedList<T> implements IDisposable {
private list: List<number>;
private _model: IPagedModel<T>;
private _model!: IPagedModel<T>;
constructor(
container: HTMLElement,

View File

@@ -57,6 +57,7 @@ export interface IListViewOptions<T> {
readonly mouseSupport?: boolean;
readonly horizontalScrolling?: boolean;
readonly ariaProvider?: IAriaProvider<T>;
readonly additionalScrollHeight?: number;
}
const DefaultOptions = {
@@ -163,19 +164,19 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
private lastRenderTop: number;
private lastRenderHeight: number;
private renderWidth = 0;
private gesture: Gesture;
private rowsContainer: HTMLElement;
private scrollableElement: ScrollableElement;
private _scrollHeight: number;
private _scrollHeight: number = 0;
private scrollableElementUpdateDisposable: IDisposable | null = null;
private scrollableElementWidthDelayer = new Delayer<void>(50);
private splicing = false;
private dragOverAnimationDisposable: IDisposable | undefined;
private dragOverAnimationStopDisposable: IDisposable = Disposable.None;
private dragOverMouseY: number;
private dragOverMouseY: number = 0;
private setRowLineHeight: boolean;
private supportDynamicHeights: boolean;
private horizontalScrolling: boolean;
private additionalScrollHeight: number;
private ariaProvider: IAriaProvider<T>;
private scrollWidth: number | undefined;
private canUseTranslate3d: boolean | undefined = undefined;
@@ -229,6 +230,8 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
this.horizontalScrolling = getOrDefault(options, o => o.horizontalScrolling, DefaultOptions.horizontalScrolling);
DOM.toggleClass(this.domNode, 'horizontal-scrolling', this.horizontalScrolling);
this.additionalScrollHeight = typeof options.additionalScrollHeight === 'undefined' ? 0 : options.additionalScrollHeight;
this.ariaProvider = options.ariaProvider || { getSetSize: (e, i, length) => length, getPosInSet: (_, index) => index + 1 };
this.rowsContainer = document.createElement('div');
@@ -245,7 +248,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
this.domNode.appendChild(this.scrollableElement.getDomNode());
container.appendChild(this.domNode);
this.disposables = [this.rangeMap, this.gesture, this.scrollableElement, this.cache];
this.disposables = [this.rangeMap, this.scrollableElement, this.cache];
this.scrollableElement.onScroll(this.onScroll, this, this.disposables);
domEvent(this.rowsContainer, TouchEventType.Change)(this.onTouchChange, this, this.disposables);
@@ -689,7 +692,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
}
get scrollHeight(): number {
return this._scrollHeight + (this.horizontalScrolling ? 10 : 0);
return this._scrollHeight + (this.horizontalScrolling ? 10 : 0) + this.additionalScrollHeight;
}
// Events

View File

@@ -519,7 +519,7 @@ const DefaultOpenController: IOpenController = {
export class MouseController<T> implements IDisposable {
private multipleSelectionSupport: boolean;
readonly multipleSelectionController: IMultipleSelectionController<T>;
readonly multipleSelectionController: IMultipleSelectionController<T> | undefined;
private openController: IOpenController;
private mouseSupport: boolean;
private readonly disposables = new DisposableStore();
@@ -618,7 +618,7 @@ export class MouseController<T> implements IDisposable {
}
}
private onDoubleClick(e: IListMouseEvent<T>): void {
protected onDoubleClick(e: IListMouseEvent<T>): void {
if (isInputElement(e.browserEvent.target as HTMLElement)) {
return;
}

View File

@@ -20,22 +20,8 @@ import { Event, Emitter } from 'vs/base/common/event';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { isLinux, isMacintosh } from 'vs/base/common/platform';
function createMenuMnemonicRegExp() {
try {
return new RegExp('\\(&([^\\s&])\\)|(?<!&)&([^\\s&])');
} catch (err) {
return new RegExp('\uFFFF'); // never match please
}
}
export const MENU_MNEMONIC_REGEX = createMenuMnemonicRegExp();
function createMenuEscapedMnemonicRegExp() {
try {
return new RegExp('(?<!&amp;)(?:&amp;)([^\\s&])');
} catch (err) {
return new RegExp('\uFFFF'); // never match please
}
}
export const MENU_ESCAPED_MNEMONIC_REGEX: RegExp = createMenuEscapedMnemonicRegExp();
export const MENU_MNEMONIC_REGEX = /\(&([^\s&])\)|(^|[^&])&([^\s&])/;
export const MENU_ESCAPED_MNEMONIC_REGEX = /(&amp;)?(&amp;)([^\s&])/g;
export interface IMenuOptions {
context?: any;
@@ -369,6 +355,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
protected options: IMenuItemOptions;
protected item: HTMLElement;
private runOnceToEnableMouseUp: RunOnceScheduler;
private label: HTMLElement;
private check: HTMLElement;
private mnemonic: string;
@@ -390,10 +377,24 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
if (label) {
let matches = MENU_MNEMONIC_REGEX.exec(label);
if (matches) {
this.mnemonic = (!!matches[1] ? matches[1] : matches[2]).toLocaleLowerCase();
this.mnemonic = (!!matches[1] ? matches[1] : matches[3]).toLocaleLowerCase();
}
}
}
// Add mouse up listener later to avoid accidental clicks
this.runOnceToEnableMouseUp = new RunOnceScheduler(() => {
if (!this.element) {
return;
}
this._register(addDisposableListener(this.element, EventType.MOUSE_UP, e => {
EventHelper.stop(e, true);
this.onClick(e);
}));
}, 50);
this._register(this.runOnceToEnableMouseUp);
}
render(container: HTMLElement): void {
@@ -425,10 +426,8 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
append(this.item, $('span.keybinding')).textContent = this.options.keybinding;
}
this._register(addDisposableListener(this.element, EventType.MOUSE_UP, e => {
EventHelper.stop(e, true);
this.onClick(e);
}));
// Adds mouse up listener to actually run the action
this.runOnceToEnableMouseUp.schedule();
this.updateClass();
this.updateLabel();
@@ -467,9 +466,23 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
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 = strings.escape(label);
// This is global, reset it
MENU_ESCAPED_MNEMONIC_REGEX.lastIndex = 0;
let escMatch = MENU_ESCAPED_MNEMONIC_REGEX.exec(label);
// We can't use negative lookbehind so if we match our negative and skip
while (escMatch && escMatch[1]) {
escMatch = MENU_ESCAPED_MNEMONIC_REGEX.exec(label);
}
if (escMatch) {
label = `${label.substr(0, escMatch.index)}<u aria-hidden="true">${escMatch[3]}</u>${label.substr(escMatch.index + escMatch[0].length)}`;
}
label = label.replace(/&amp;&amp;/g, '&amp;');
this.item.setAttribute('aria-keyshortcuts', (!!matches[1] ? matches[1] : matches[2]).toLocaleLowerCase());
this.item.setAttribute('aria-keyshortcuts', (!!matches[1] ? matches[1] : matches[3]).toLocaleLowerCase());
} else {
label = label.replace(/&&/g, '&');
}
@@ -802,7 +815,7 @@ export function cleanMnemonic(label: string): string {
return label;
}
const mnemonicInText = matches[0].charAt(0) === '&';
const mnemonicInText = !matches[1];
return label.replace(regex, mnemonicInText ? '$2' : '').trim();
return label.replace(regex, mnemonicInText ? '$2$3' : '').trim();
}

View File

@@ -209,7 +209,7 @@ export class MenuBar extends Disposable {
// Register mnemonics
if (mnemonicMatches) {
let mnemonic = !!mnemonicMatches[1] ? mnemonicMatches[1] : mnemonicMatches[2];
let mnemonic = !!mnemonicMatches[1] ? mnemonicMatches[1] : mnemonicMatches[3];
this.registerMnemonic(this.menuCache.length, mnemonic);
}
@@ -472,15 +472,34 @@ export class MenuBar extends Disposable {
const cleanMenuLabel = cleanMnemonic(label);
// 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>').replace(/&amp;&amp;/g, '&amp;') :
cleanMenuLabel.replace(/&&/g, '&');
if (this.options.enableMnemonics) {
let innerHtml = strings.escape(label);
// This is global so reset it
MENU_ESCAPED_MNEMONIC_REGEX.lastIndex = 0;
let escMatch = MENU_ESCAPED_MNEMONIC_REGEX.exec(innerHtml);
// We can't use negative lookbehind so we match our negative and skip
while (escMatch && escMatch[1]) {
escMatch = MENU_ESCAPED_MNEMONIC_REGEX.exec(innerHtml);
}
if (escMatch) {
innerHtml = `${innerHtml.substr(0, escMatch.index)}<mnemonic aria-hidden="true">${escMatch[3]}</mnemonic>${innerHtml.substr(escMatch.index + escMatch[0].length)}`;
}
innerHtml = innerHtml.replace(/&amp;&amp;/g, '&amp;');
titleElement.innerHTML = innerHtml;
} else {
titleElement.innerHTML = cleanMenuLabel.replace(/&&/g, '&');
}
let mnemonicMatches = MENU_MNEMONIC_REGEX.exec(label);
// Register mnemonics
if (mnemonicMatches) {
let mnemonic = !!mnemonicMatches[1] ? mnemonicMatches[1] : mnemonicMatches[2];
let mnemonic = !!mnemonicMatches[1] ? mnemonicMatches[1] : mnemonicMatches[3];
if (this.options.enableMnemonics) {
buttonElement.setAttribute('aria-keyshortcuts', 'Alt+' + mnemonic.toLocaleLowerCase());

View File

@@ -61,7 +61,7 @@ export class Sash extends Disposable {
private el: HTMLElement;
private layoutProvider: ISashLayoutProvider;
private hidden: boolean;
private orientation: Orientation;
private orientation!: Orientation;
private _state: SashState = SashState.Enabled;
get state(): SashState { return this._state; }

View File

@@ -49,7 +49,7 @@ export abstract class AbstractScrollbar extends Widget {
private _mouseMoveMonitor: GlobalMouseMoveMonitor<IStandardMouseMoveEventData>;
public domNode: FastDomNode<HTMLElement>;
public slider: FastDomNode<HTMLElement>;
public slider!: FastDomNode<HTMLElement>;
protected _shouldRender: boolean;

View File

@@ -148,9 +148,9 @@ export abstract class AbstractScrollableElement extends Widget {
private readonly _horizontalScrollbar: HorizontalScrollbar;
private readonly _domNode: HTMLElement;
private readonly _leftShadowDomNode: FastDomNode<HTMLElement>;
private readonly _topShadowDomNode: FastDomNode<HTMLElement>;
private readonly _topLeftShadowDomNode: FastDomNode<HTMLElement>;
private readonly _leftShadowDomNode: FastDomNode<HTMLElement> | null;
private readonly _topShadowDomNode: FastDomNode<HTMLElement> | null;
private readonly _topLeftShadowDomNode: FastDomNode<HTMLElement> | null;
private readonly _listenOnDomNode: HTMLElement;
@@ -207,6 +207,10 @@ export abstract class AbstractScrollableElement extends Widget {
this._topLeftShadowDomNode = createFastDomNode(document.createElement('div'));
this._topLeftShadowDomNode.setClassName('shadow top-left-corner');
this._domNode.appendChild(this._topLeftShadowDomNode.domNode);
} else {
this._leftShadowDomNode = null;
this._topShadowDomNode = null;
this._topLeftShadowDomNode = null;
}
this._listenOnDomNode = this._options.listenOnDomNode || this._domNode;
@@ -430,9 +434,9 @@ export abstract class AbstractScrollableElement extends Widget {
let enableTop = scrollState.scrollTop > 0;
let enableLeft = scrollState.scrollLeft > 0;
this._leftShadowDomNode.setClassName('shadow' + (enableLeft ? ' left' : ''));
this._topShadowDomNode.setClassName('shadow' + (enableTop ? ' top' : ''));
this._topLeftShadowDomNode.setClassName('shadow top-left-corner' + (enableTop ? ' top' : '') + (enableLeft ? ' left' : ''));
this._leftShadowDomNode!.setClassName('shadow' + (enableLeft ? ' left' : ''));
this._topShadowDomNode!.setClassName('shadow' + (enableTop ? ' top' : ''));
this._topLeftShadowDomNode!.setClassName('shadow top-left-corner' + (enableTop ? ' top' : '') + (enableLeft ? ' left' : ''));
}
}

View File

@@ -8,7 +8,7 @@ import 'vs/css!./selectBox';
import { Event } from 'vs/base/common/event';
import { Widget } from 'vs/base/browser/ui/widget';
import { Color } from 'vs/base/common/color';
import { deepClone, mixin } from 'vs/base/common/objects';
import { deepClone } from 'vs/base/common/objects';
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
import { IListStyles } from 'vs/base/browser/ui/list/listWidget';
import { SelectBoxNative } from 'vs/base/browser/ui/selectBox/selectBoxNative';
@@ -77,14 +77,11 @@ export class SelectBox extends Widget implements ISelectBoxDelegate {
protected selectBackground?: Color;
protected selectForeground?: Color;
protected selectBorder?: Color;
private styles: ISelectBoxStyles;
private selectBoxDelegate: ISelectBoxDelegate;
constructor(options: ISelectOptionItem[], selected: number, contextViewProvider: IContextViewProvider, styles: ISelectBoxStyles = deepClone(defaultStyles), selectBoxOptions?: ISelectBoxOptions) {
super();
mixin(this.styles, defaultStyles, false);
// Default to native SelectBox for OSX unless overridden
if (isMacintosh && !(selectBoxOptions && selectBoxOptions.useCustomDrawn)) {
this.selectBoxDelegate = new SelectBoxNative(options, selected, styles, selectBoxOptions);

View File

@@ -93,23 +93,24 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
private _isVisible: boolean;
private selectBoxOptions: ISelectBoxOptions;
// {{SQL CARBON EDIT}}
public selectElement: HTMLSelectElement;
private options: ISelectOptionItem[];
private options: ISelectOptionItem[] = [];
private selected: number;
private readonly _onDidSelect: Emitter<ISelectData>;
private styles: ISelectBoxStyles;
private listRenderer: SelectListRenderer;
private contextViewProvider: IContextViewProvider;
private selectDropDownContainer: HTMLElement;
private styleElement: HTMLStyleElement;
private selectList: List<ISelectOptionItem>;
private selectDropDownListContainer: HTMLElement;
private widthControlElement: HTMLElement;
private _currentSelection: number;
private _dropDownPosition: AnchorPosition;
private listRenderer!: SelectListRenderer;
private contextViewProvider!: IContextViewProvider;
private selectDropDownContainer!: HTMLElement;
private styleElement!: HTMLStyleElement;
private selectList!: List<ISelectOptionItem>;
private selectDropDownListContainer!: HTMLElement;
private widthControlElement!: HTMLElement;
private _currentSelection = 0;
private _dropDownPosition!: AnchorPosition;
private _hasDetails: boolean = false;
private selectionDetailsPane: HTMLElement;
private selectionDetailsPane!: HTMLElement;
private _skipLayout: boolean = false;
private _sticky: boolean = false; // for dev purposes only
@@ -247,7 +248,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
}
public setOptions(options: ISelectOptionItem[], selected?: number): void {
if (!this.options || !arrays.equals(this.options, options)) {
if (!arrays.equals(this.options, options)) {
this.options = options;
this.selectElement.options.length = 0;
this._hasDetails = false;
@@ -272,7 +273,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
// Mirror options in drop-down
// Populate select list for non-native select mode
if (this.selectList && !!this.options) {
if (this.selectList) {
this.selectList.splice(0, this.selectList.length, this.options);
}
}
@@ -704,7 +705,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
private setWidthControlElement(container: HTMLElement): number {
let elementWidth = 0;
if (container && !!this.options) {
if (container) {
let longest = 0;
let longestLength = 0;

View File

@@ -17,7 +17,7 @@ export class SelectBoxNative extends Disposable implements ISelectBoxDelegate {
public selectElement: HTMLSelectElement;
private selectBoxOptions: ISelectBoxOptions;
private options: ISelectOptionItem[];
private selected: number;
private selected = 0;
private readonly _onDidSelect: Emitter<ISelectData>;
private styles: ISelectBoxStyles;

View File

@@ -42,8 +42,8 @@ export abstract class Panel extends Disposable implements IView {
private static readonly HEADER_SIZE = 22;
readonly element: HTMLElement;
private header: HTMLElement;
private body: HTMLElement;
private header!: HTMLElement;
private body!: HTMLElement;
protected _expanded: boolean;
@@ -109,7 +109,7 @@ export abstract class Panel extends Disposable implements IView {
return headerSize + maximumBodySize;
}
width: number;
width: number = 0;
constructor(options: IPanelOptions = {}) {
super();
@@ -371,7 +371,7 @@ export class PanelView extends Disposable {
private dndContext: IDndContext = { draggable: null };
private el: HTMLElement;
private panelItems: IPanelItem[] = [];
private width: number;
private width: number = 0;
private splitview: SplitView;
private animationTimer: number | undefined = undefined;

View File

@@ -72,4 +72,4 @@
.monaco-split-view2.separator-border.vertical > .split-view-container > .split-view-view:not(:first-child)::before {
height: 1px;
width: 100%;
}
}

View File

@@ -79,7 +79,7 @@ abstract class ViewItem {
return typeof this._cachedVisibleSize === 'undefined';
}
set visible(visible: boolean) {
setVisible(visible: boolean, size?: number): void {
if (visible === this.visible) {
return;
}
@@ -88,7 +88,7 @@ abstract class ViewItem {
this.size = clamp(this._cachedVisibleSize!, this.viewMinimumSize, this.viewMaximumSize);
this._cachedVisibleSize = undefined;
} else {
this._cachedVisibleSize = this.size;
this._cachedVisibleSize = typeof size === 'number' ? size : this.size;
this.size = 0;
}
@@ -125,7 +125,10 @@ abstract class ViewItem {
dom.addClass(container, 'visible');
}
abstract layout(): void;
layout(): void {
this.container.scrollTop = 0;
this.container.scrollLeft = 0;
}
layoutView(orientation: Orientation): void {
this.view.layout(this.size, orientation);
@@ -140,6 +143,7 @@ abstract class ViewItem {
class VerticalViewItem extends ViewItem {
layout(): void {
super.layout();
this.container.style.height = `${this.size}px`;
this.layoutView(Orientation.VERTICAL);
}
@@ -148,6 +152,7 @@ class VerticalViewItem extends ViewItem {
class HorizontalViewItem extends ViewItem {
layout(): void {
super.layout();
this.container.style.width = `${this.size}px`;
this.layoutView(Orientation.HORIZONTAL);
}
@@ -161,6 +166,7 @@ interface ISashItem {
interface ISashDragSnapState {
readonly index: number;
readonly limitDelta: number;
readonly size: number;
}
interface ISashDragState {
@@ -203,7 +209,7 @@ export class SplitView extends Disposable {
private proportions: undefined | number[] = undefined;
private viewItems: ViewItem[] = [];
private sashItems: ISashItem[] = [];
private sashDragState: ISashDragState;
private sashDragState: ISashDragState | undefined;
private state: State = State.Idle;
private inverseAltBehavior: boolean;
private proportionalLayout: boolean;
@@ -414,9 +420,10 @@ export class SplitView extends Disposable {
throw new Error('Cant modify splitview');
}
const size = this.getViewSize(from);
const cachedVisibleSize = this.getViewCachedVisibleSize(from);
const sizing = typeof cachedVisibleSize === 'undefined' ? this.getViewSize(from) : Sizing.Invisible(cachedVisibleSize);
const view = this.removeView(from);
this.addView(view, size, to);
this.addView(view, sizing, to);
}
swapViews(from: number, to: number): void {
@@ -452,10 +459,11 @@ export class SplitView extends Disposable {
}
const viewItem = this.viewItems[index];
viewItem.visible = visible;
viewItem.setVisible(visible);
this.distributeEmptySpace(index);
this.layoutViews();
this.saveProportions();
}
getViewCachedVisibleSize(index: number): number | undefined {
@@ -499,8 +507,8 @@ export class SplitView extends Disposable {
// This way, we can press Alt while we resize a sash, macOS style!
const disposable = combinedDisposable(
domEvent(document.body, 'keydown')(e => resetSashDragState(this.sashDragState.current, e.altKey)),
domEvent(document.body, 'keyup')(() => resetSashDragState(this.sashDragState.current, false))
domEvent(document.body, 'keydown')(e => resetSashDragState(this.sashDragState!.current, e.altKey)),
domEvent(document.body, 'keyup')(() => resetSashDragState(this.sashDragState!.current, false))
);
const resetSashDragState = (start: number, alt: boolean) => {
@@ -550,7 +558,8 @@ export class SplitView extends Disposable {
snapBefore = {
index: snapBeforeIndex,
limitDelta: viewItem.visible ? minDelta - halfSize : minDelta + halfSize
limitDelta: viewItem.visible ? minDelta - halfSize : minDelta + halfSize,
size: viewItem.size
};
}
@@ -560,7 +569,8 @@ export class SplitView extends Disposable {
snapAfter = {
index: snapAfterIndex,
limitDelta: viewItem.visible ? maxDelta + halfSize : maxDelta - halfSize
limitDelta: viewItem.visible ? maxDelta + halfSize : maxDelta - halfSize,
size: viewItem.size
};
}
}
@@ -572,8 +582,8 @@ export class SplitView extends Disposable {
}
private onSashChange({ current }: ISashEvent): void {
const { index, start, sizes, alt, minDelta, maxDelta, snapBefore, snapAfter } = this.sashDragState;
this.sashDragState.current = current;
const { index, start, sizes, alt, minDelta, maxDelta, snapBefore, snapAfter } = this.sashDragState!;
this.sashDragState!.current = current;
const delta = current - start;
const newDelta = this.resize(index, delta, sizes, undefined, undefined, minDelta, maxDelta, snapBefore, snapAfter);
@@ -596,7 +606,7 @@ export class SplitView extends Disposable {
private onSashEnd(index: number): void {
this._onDidSashChange.fire(index);
this.sashDragState.disposable.dispose();
this.sashDragState!.disposable.dispose();
this.saveProportions();
}
@@ -738,14 +748,14 @@ export class SplitView extends Disposable {
const snapView = this.viewItems[snapBefore.index];
const visible = delta >= snapBefore.limitDelta;
snapped = visible !== snapView.visible;
snapView.visible = visible;
snapView.setVisible(visible, snapBefore.size);
}
if (!snapped && snapAfter) {
const snapView = this.viewItems[snapAfter.index];
const visible = delta < snapAfter.limitDelta;
snapped = visible !== snapView.visible;
snapView.visible = visible;
snapView.setVisible(visible, snapAfter.size);
}
if (snapped) {

View File

@@ -33,7 +33,7 @@ export class ToolBar extends Disposable {
private actionBar: ActionBar;
private toggleMenuAction: ToggleMenuAction;
private toggleMenuActionViewItem = this._register(new MutableDisposable<DropdownMenuActionViewItem>());
private hasSecondaryActions: boolean;
private hasSecondaryActions: boolean = false;
private lookupKeybindings: boolean;
constructor(container: HTMLElement, contextMenuProvider: IContextMenuProvider, options: IToolBarOptions = { orientation: ActionsOrientation.HORIZONTAL }) {
@@ -162,6 +162,7 @@ class ToggleMenuAction extends Action {
title = title || nls.localize('moreActions', "More Actions...");
super(ToggleMenuAction.ID, title, undefined, true);
this._menuActions = [];
this.toggleDropdownMenu = toggleDropdownMenu;
}
@@ -178,4 +179,4 @@ class ToggleMenuAction extends Action {
set menuActions(actions: ReadonlyArray<IAction>) {
this._menuActions = actions;
}
}
}

View File

@@ -451,8 +451,8 @@ class TypeFilter<T> implements ITreeFilter<T, FuzzyScore>, IDisposable {
private _matchCount = 0;
get matchCount(): number { return this._matchCount; }
private _pattern: string;
private _lowercasePattern: string;
private _pattern: string = '';
private _lowercasePattern: string = '';
private disposables: IDisposable[] = [];
set pattern(pattern: string) {
@@ -543,7 +543,7 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
private _filterOnType: boolean;
get filterOnType(): boolean { return this._filterOnType; }
private _empty: boolean;
private _empty: boolean = false;
get empty(): boolean { return this._empty; }
private _onDidChangeEmptyState = new Emitter<boolean>();
@@ -897,6 +897,7 @@ export interface IAbstractTreeOptions<T, TFilterData = void> extends IAbstractTr
readonly autoExpandSingleChildren?: boolean;
readonly keyboardNavigationEventFilter?: IKeyboardNavigationEventFilter;
readonly expandOnlyOnTwistieClick?: boolean | ((e: T) => boolean);
readonly additionalScrollHeight?: number;
}
function dfs<T, TFilterData>(node: ITreeNode<T, TFilterData>, fn: (node: ITreeNode<T, TFilterData>) => void): void {
@@ -1063,6 +1064,16 @@ class TreeNodeListMouseController<T, TFilterData, TRef> extends MouseController<
super.onPointer(e);
}
protected onDoubleClick(e: IListMouseEvent<ITreeNode<T, TFilterData>>): void {
const onTwistie = hasClass(e.browserEvent.target as HTMLElement, 'monaco-tl-twistie');
if (onTwistie) {
return;
}
super.onDoubleClick(e);
}
}
interface ITreeNodeListOptions<T, TFilterData, TRef> extends IListOptions<ITreeNode<T, TFilterData>> {

View File

@@ -238,7 +238,8 @@ function asObjectTreeOptions<TInput, T, TFilterData>(options?: IAsyncDataTreeOpt
e => (options.expandOnlyOnTwistieClick as ((e: T) => boolean))(e.element as T)
)
),
ariaProvider: undefined
ariaProvider: undefined,
additionalScrollHeight: options.additionalScrollHeight
};
}

View File

@@ -17,7 +17,7 @@ export interface IObjectTreeOptions<T, TFilterData = void> extends IAbstractTree
export class CompressedObjectTree<T extends NonNullable<any>, TFilterData = void> extends AbstractTree<ICompressedTreeNode<T> | null, TFilterData, T | null> {
protected model: CompressedTreeModel<T, TFilterData>;
protected model!: CompressedTreeModel<T, TFilterData>;
get onDidChangeCollapseState(): Event<ICollapseStateChangeEvent<ICompressedTreeNode<T> | null, TFilterData>> { return this.model.onDidChangeCollapseState; }

View File

@@ -23,7 +23,7 @@ export interface IDataTreeViewState {
export class DataTree<TInput, T, TFilterData = void> extends AbstractTree<T | null, TFilterData, T | null> {
protected model: ObjectTreeModel<T, TFilterData>;
protected model!: ObjectTreeModel<T, TFilterData>;
private input: TInput | undefined;
private identityProvider: IIdentityProvider<T> | undefined;

View File

@@ -15,7 +15,7 @@ export interface IIndexTreeOptions<T, TFilterData = void> extends IAbstractTreeO
export class IndexTree<T, TFilterData = void> extends AbstractTree<T, TFilterData, number[]> {
protected model: IndexTreeModel<T, TFilterData>;
protected model!: IndexTreeModel<T, TFilterData>;
constructor(
container: HTMLElement,

View File

@@ -17,7 +17,7 @@ export interface IObjectTreeOptions<T, TFilterData = void> extends IAbstractTree
export class ObjectTree<T extends NonNullable<any>, TFilterData = void> extends AbstractTree<T | null, TFilterData, T | null> {
protected model: IObjectTreeModel<T, TFilterData>;
protected model!: IObjectTreeModel<T, TFilterData>;
get onDidChangeCollapseState(): Event<ICollapseStateChangeEvent<T | null, TFilterData>> { return this.model.onDidChangeCollapseState; }