Merge from vscode 79a1f5a5ca0c6c53db617aa1fa5a2396d2caebe2

This commit is contained in:
ADS Merger
2020-05-31 19:47:51 +00:00
parent 84492049e8
commit 28be33cfea
913 changed files with 28242 additions and 15549 deletions

View File

@@ -34,4 +34,5 @@ export interface IContextMenuDelegate {
actionRunner?: IActionRunner;
autoSelectFirstItem?: boolean;
anchorAlignment?: AnchorAlignment;
anchorAsContainer?: boolean;
}

View File

@@ -16,16 +16,22 @@ import { escape } from 'vs/base/common/strings';
import { URI } from 'vs/base/common/uri';
import { Schemas } from 'vs/base/common/network';
import { renderCodicons, markdownEscapeEscapedCodicons } from 'vs/base/common/codicons';
import { resolvePath } from 'vs/base/common/resources';
export interface MarkedOptions extends marked.MarkedOptions {
baseUrl?: never;
}
export interface MarkdownRenderOptions extends FormattedTextRenderOptions {
codeBlockRenderer?: (modeId: string, value: string) => Promise<string>;
codeBlockRenderCallback?: () => void;
baseUrl?: URI;
}
/**
* Create html nodes for the given content element.
*/
export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRenderOptions = {}, markedOptions: marked.MarkedOptions = {}): HTMLElement {
export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRenderOptions = {}, markedOptions: MarkedOptions = {}): HTMLElement {
const element = createElement(options);
const _uriMassage = function (part: string): string {
@@ -82,6 +88,9 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
if (href) {
({ href, dimensions } = parseHrefAndDimensions(href));
href = _href(href, true);
if (options.baseUrl) {
href = resolvePath(options.baseUrl, href).toString();
}
attributes.push(`src="${href}"`);
}
if (text) {
@@ -101,6 +110,12 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
text = removeMarkdownEscapes(text);
}
href = _href(href, false);
if (options.baseUrl) {
const hasScheme = /^\w[\w\d+.-]*:/.test(href);
if (!hasScheme) {
href = resolvePath(options.baseUrl, href).toString();
}
}
title = removeMarkdownEscapes(title);
href = removeMarkdownEscapes(href);
if (
@@ -187,6 +202,13 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
}));
}
// Use our own sanitizer so that we can let through only spans.
// Otherwise, we'd be letting all html be rendered.
// If we want to allow markdown permitted tags, then we can delete sanitizer and sanitize.
markedOptions.sanitizer = (html: string): string => {
const match = markdown.isTrusted ? html.match(/^(<span[^<]+>)|(<\/\s*span>)$/) : undefined;
return match ? html : '';
};
markedOptions.sanitize = true;
markedOptions.renderer = renderer;
@@ -202,18 +224,32 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
markedOptions
);
function filter(token: { tag: string, attrs: { readonly [key: string]: string } }): boolean {
if (token.tag === 'span' && markdown.isTrusted) {
if (token.attrs['style'] && Object.keys(token.attrs).length === 1) {
return !!token.attrs['style'].match(/^(color\:#[0-9a-fA-F]+;)?(background-color\:#[0-9a-fA-F]+;)?$/);
}
return false;
}
return true;
}
element.innerHTML = insane(renderedMarkdown, {
allowedSchemes,
// allowedTags should included everything that markdown renders to.
// Since we have our own sanitize function for marked, it's possible we missed some tag so let insane make sure.
// HTML tags that can result from markdown are from reading https://spec.commonmark.org/0.29/
allowedTags: ['ul', 'li', 'p', 'code', 'blockquote', 'ol', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'em', 'pre', 'table', 'tr', 'td', 'div', 'del', 'a', 'strong', 'br', 'img', 'span'],
allowedAttributes: {
'a': ['href', 'name', 'target', 'data-href'],
'iframe': ['allowfullscreen', 'frameborder', 'src'],
'img': ['src', 'title', 'alt', 'width', 'height'],
'div': ['class', 'data-code'],
'span': ['class'],
'span': ['class', 'style'],
// https://github.com/microsoft/vscode/issues/95937
'th': ['align'],
'td': ['align']
}
},
filter
});
signalInnerHTML!();

View File

@@ -31,6 +31,7 @@ export interface IActionViewItem extends IDisposable {
export interface IBaseActionViewItemOptions {
draggable?: boolean;
isMenu?: boolean;
useEventAsContext?: boolean;
}
export class BaseActionViewItem extends Disposable implements IActionViewItem {
@@ -178,7 +179,7 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
onClick(event: DOM.EventLike): void {
DOM.EventHelper.stop(event, true);
const context = types.isUndefinedOrNull(this._context) ? undefined : this._context;
const context = types.isUndefinedOrNull(this._context) ? this.options?.useEventAsContext ? event : undefined : this._context;
this.actionRunner.run(this._action, context);
}
@@ -404,6 +405,7 @@ export interface IActionBarOptions {
ariaLabel?: string;
animated?: boolean;
triggerKeys?: ActionTrigger;
allowContextMenu?: boolean;
}
const defaultOptions: IActionBarOptions = {
@@ -633,9 +635,11 @@ export class ActionBar extends Disposable implements IActionRunner {
actionViewItemElement.setAttribute('role', 'presentation');
// Prevent native context menu on actions
this._register(DOM.addDisposableListener(actionViewItemElement, DOM.EventType.CONTEXT_MENU, (e: DOM.EventLike) => {
DOM.EventHelper.stop(e, true);
}));
if (!this.options.allowContextMenu) {
this._register(DOM.addDisposableListener(actionViewItemElement, DOM.EventType.CONTEXT_MENU, (e: DOM.EventLike) => {
DOM.EventHelper.stop(e, true);
}));
}
let item: IActionViewItem | undefined;

View File

@@ -7,3 +7,12 @@
position: absolute;
z-index: 2500;
}
.context-view.fixed {
all: initial;
font-family: inherit;
font-size: 13px;
position: fixed;
z-index: 2500;
color: inherit;
}

View File

@@ -38,7 +38,7 @@ export interface IDelegate {
}
export interface IContextViewProvider {
showContextView(delegate: IDelegate): void;
showContextView(delegate: IDelegate, container?: HTMLElement): void;
hideContextView(): void;
layout(): void;
}
@@ -104,23 +104,25 @@ export class ContextView extends Disposable {
private container: HTMLElement | null = null;
private view: HTMLElement;
private useFixedPosition: boolean;
private delegate: IDelegate | null = null;
private toDisposeOnClean: IDisposable = Disposable.None;
private toDisposeOnSetContainer: IDisposable = Disposable.None;
constructor(container: HTMLElement) {
constructor(container: HTMLElement, useFixedPosition: boolean) {
super();
this.view = DOM.$('.context-view');
this.useFixedPosition = false;
DOM.hide(this.view);
this.setContainer(container);
this.setContainer(container, useFixedPosition);
this._register(toDisposable(() => this.setContainer(null)));
this._register(toDisposable(() => this.setContainer(null, false)));
}
setContainer(container: HTMLElement | null): void {
setContainer(container: HTMLElement | null, useFixedPosition: boolean): void {
if (this.container) {
this.toDisposeOnSetContainer.dispose();
this.container.removeChild(this.view);
@@ -146,6 +148,8 @@ export class ContextView extends Disposable {
this.toDisposeOnSetContainer = toDisposeOnSetContainer;
}
this.useFixedPosition = useFixedPosition;
}
show(delegate: IDelegate): void {
@@ -254,10 +258,11 @@ export class ContextView extends Disposable {
DOM.removeClasses(this.view, 'top', 'bottom', 'left', 'right');
DOM.addClass(this.view, anchorPosition === AnchorPosition.BELOW ? 'bottom' : 'top');
DOM.addClass(this.view, anchorAlignment === AnchorAlignment.LEFT ? 'left' : 'right');
DOM.toggleClass(this.view, 'fixed', this.useFixedPosition);
const containerPosition = DOM.getDomNodePagePosition(this.container!);
this.view.style.top = `${top - containerPosition.top}px`;
this.view.style.left = `${left - containerPosition.left}px`;
this.view.style.top = `${top - (this.useFixedPosition ? DOM.getDomNodePagePosition(this.view).top : containerPosition.top)}px`;
this.view.style.left = `${left - (this.useFixedPosition ? DOM.getDomNodePagePosition(this.view).left : containerPosition.left)}px`;
this.view.style.width = 'initial';
}

View File

@@ -14,6 +14,7 @@ import { ResolvedKeybinding, KeyCode } from 'vs/base/common/keyCodes';
import { EventHelper, EventType, removeClass, addClass, append, $, addDisposableListener, addClasses } from 'vs/base/browser/dom';
import { IContextMenuDelegate } from 'vs/base/browser/contextmenu';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { Emitter } from 'vs/base/common/event';
export interface ILabelRenderer {
(container: HTMLElement): IDisposable | null;
@@ -29,7 +30,10 @@ export class BaseDropdown extends ActionRunner {
private boxContainer?: HTMLElement;
private _label?: HTMLElement;
private contents?: HTMLElement;
private visible: boolean | undefined;
private _onDidChangeVisibility = new Emitter<boolean>();
readonly onDidChangeVisibility = this._onDidChangeVisibility.event;
constructor(container: HTMLElement, options: IBaseDropdownOptions) {
super();
@@ -48,7 +52,7 @@ export class BaseDropdown extends ActionRunner {
}
for (const event of [EventType.CLICK, EventType.MOUSE_DOWN, GestureEventType.Tap]) {
this._register(addDisposableListener(this._label, event, e => EventHelper.stop(e, true))); // prevent default click behaviour to trigger
this._register(addDisposableListener(this.element, event, e => EventHelper.stop(e, true))); // prevent default click behaviour to trigger
}
for (const event of [EventType.MOUSE_DOWN, GestureEventType.Tap]) {
@@ -101,11 +105,17 @@ export class BaseDropdown extends ActionRunner {
}
show(): void {
this.visible = true;
if (!this.visible) {
this.visible = true;
this._onDidChangeVisibility.fire(true);
}
}
hide(): void {
this.visible = false;
if (this.visible) {
this.visible = false;
this._onDidChangeVisibility.fire(false);
}
}
isVisible(): boolean {
@@ -256,7 +266,8 @@ export class DropdownMenu extends BaseDropdown {
getMenuClassName: () => this.menuClassName,
onHide: () => this.onHide(),
actionRunner: this.menuOptions ? this.menuOptions.actionRunner : undefined,
anchorAlignment: this.menuOptions ? this.menuOptions.anchorAlignment : AnchorAlignment.LEFT
anchorAlignment: this.menuOptions ? this.menuOptions.anchorAlignment : AnchorAlignment.LEFT,
anchorAsContainer: true
});
}
@@ -303,6 +314,7 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem {
this.element.tabIndex = 0;
this.element.setAttribute('role', 'button');
this.element.setAttribute('aria-haspopup', 'true');
this.element.setAttribute('aria-expanded', 'false');
this.element.title = this._action.label || '';
return null;
@@ -321,6 +333,7 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem {
}
this.dropdownMenu = this._register(new DropdownMenu(container, options));
this._register(this.dropdownMenu.onDidChangeVisibility(visible => this.element?.setAttribute('aria-expanded', `${visible}`)));
this.dropdownMenu.menuOptions = {
actionViewItemProvider: this.actionViewItemProvider,

View File

@@ -380,7 +380,7 @@ class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
throw new Error('Invalid index');
}
this.splitview.addView(node, size, index);
this.splitview.addView(node, size, index, skipLayout);
this._addChild(node, index);
this.onDidChildrenChange();
}
@@ -791,7 +791,7 @@ function flipNode<T extends Node>(node: T, size: number, orthogonalSize: number)
newSize += size - totalSize;
}
result.addChild(flipNode(child, orthogonalSize, newSize), newSize, 0);
result.addChild(flipNode(child, orthogonalSize, newSize), newSize, 0, true);
}
return result as T;

View File

@@ -0,0 +1,130 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-hover {
cursor: default;
position: absolute;
overflow: hidden;
z-index: 50;
user-select: text;
-webkit-user-select: text;
-ms-user-select: text;
box-sizing: initial;
animation: fadein 100ms linear;
line-height: 1.5em;
}
.monaco-hover.hidden {
display: none;
}
.monaco-hover .hover-contents {
padding: 4px 8px;
}
.monaco-hover .markdown-hover > .hover-contents:not(.code-hover-contents) {
max-width: 500px;
word-wrap: break-word;
}
.monaco-hover .markdown-hover > .hover-contents:not(.code-hover-contents) hr {
/* This is a strange rule but it avoids https://github.com/microsoft/vscode/issues/96795, just 100vw on its own caused the actual hover width to increase */
min-width: calc(100% + 100vw);
}
.monaco-hover p,
.monaco-hover ul {
margin: 8px 0;
}
.monaco-hover code {
font-family: var(--monaco-monospace-font);
}
.monaco-hover hr {
margin-top: 4px;
margin-bottom: -6px;
margin-left: -10px;
margin-right: -10px;
height: 1px;
}
.monaco-hover p:first-child,
.monaco-hover ul:first-child {
margin-top: 0;
}
.monaco-hover p:last-child,
.monaco-hover ul:last-child {
margin-bottom: 0;
}
/* MarkupContent Layout */
.monaco-hover ul {
padding-left: 20px;
}
.monaco-hover ol {
padding-left: 20px;
}
.monaco-hover li > p {
margin-bottom: 0;
}
.monaco-hover li > ul {
margin-top: 0;
}
.monaco-hover code {
border-radius: 3px;
padding: 0 0.4em;
}
.monaco-hover .monaco-tokenized-source {
white-space: pre-wrap;
word-break: break-all;
}
.monaco-hover .hover-row.status-bar {
font-size: 12px;
line-height: 22px;
}
.monaco-hover .hover-row.status-bar .actions {
display: flex;
padding: 0px 8px;
}
.monaco-hover .hover-row.status-bar .actions .action-container {
margin-right: 16px;
cursor: pointer;
}
.monaco-hover .hover-row.status-bar .actions .action-container .action .icon {
padding-right: 4px;
}
.monaco-hover .markdown-hover .hover-contents .codicon {
color: inherit;
font-size: inherit;
vertical-align: middle;
}
.monaco-hover .hover-contents a.code-link:before {
content: '(';
}
.monaco-hover .hover-contents a.code-link:after {
content: ')';
}
.monaco-hover .hover-contents a.code-link {
color: inherit;
}
.monaco-hover .hover-contents a.code-link > span {
text-decoration: underline;
/** Hack to force underline to show **/
border-bottom: 1px solid transparent;
text-underline-position: under;
}

View File

@@ -0,0 +1,54 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./hover';
import * as dom from 'vs/base/browser/dom';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
const $ = dom.$;
export class HoverWidget extends Disposable {
public readonly containerDomNode: HTMLElement;
public readonly contentsDomNode: HTMLElement;
private readonly _scrollbar: DomScrollableElement;
constructor() {
super();
this.containerDomNode = document.createElement('div');
this.containerDomNode.className = 'monaco-hover';
this.containerDomNode.tabIndex = 0;
this.containerDomNode.setAttribute('role', 'tooltip');
this.contentsDomNode = document.createElement('div');
this.contentsDomNode.className = 'monaco-hover-content';
this._scrollbar = this._register(new DomScrollableElement(this.contentsDomNode, {}));
this.containerDomNode.appendChild(this._scrollbar.getDomNode());
}
public onContentsChanged(): void {
this._scrollbar.scanDomNode();
}
}
export function renderHoverAction(parent: HTMLElement, actionOptions: { label: string, iconClass?: string, run: (target: HTMLElement) => void, commandId: string }, keybindingLabel: string | null): IDisposable {
const actionContainer = dom.append(parent, $('div.action-container'));
const action = dom.append(actionContainer, $('a.action'));
action.setAttribute('href', '#');
action.setAttribute('role', 'button');
if (actionOptions.iconClass) {
dom.append(action, $(`span.icon.${actionOptions.iconClass}`));
}
const label = dom.append(action, $('span'));
label.textContent = keybindingLabel ? `${actionOptions.label} (${keybindingLabel})` : actionOptions.label;
return dom.addDisposableListener(actionContainer, dom.EventType.CLICK, e => {
e.stopPropagation();
e.preventDefault();
actionOptions.run(actionContainer);
});
}

View File

@@ -165,7 +165,7 @@ export class PagedList<T> implements IDisposable {
}
get onDidChangeFocus(): Event<IListEvent<T>> {
return Event.map(this.list.onDidChangeFocus, ({ elements, indexes }) => ({ elements: elements.map(e => this._model.get(e)), indexes }));
return Event.map(this.list.onDidChangeFocus, ({ elements, indexes, browserEvent }) => ({ elements: elements.map(e => this._model.get(e)), indexes, browserEvent }));
}
get onDidOpen(): Event<IListEvent<T>> {
@@ -173,11 +173,11 @@ export class PagedList<T> implements IDisposable {
}
get onDidChangeSelection(): Event<IListEvent<T>> {
return Event.map(this.list.onDidChangeSelection, ({ elements, indexes }) => ({ elements: elements.map(e => this._model.get(e)), indexes }));
return Event.map(this.list.onDidChangeSelection, ({ elements, indexes, browserEvent }) => ({ elements: elements.map(e => this._model.get(e)), indexes, browserEvent }));
}
get onPin(): Event<IListEvent<T>> {
return Event.map(this.list.onDidPin, ({ elements, indexes }) => ({ elements: elements.map(e => this._model.get(e)), indexes }));
return Event.map(this.list.onDidPin, ({ elements, indexes, browserEvent }) => ({ elements: elements.map(e => this._model.get(e)), indexes, browserEvent }));
}
get onContextMenu(): Event<IListContextMenuEvent<T>> {

View File

@@ -9,8 +9,8 @@ import { Gesture, EventType as TouchEventType, GestureEvent } from 'vs/base/brow
import * as DOM from 'vs/base/browser/dom';
import { Event, Emitter } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { ScrollEvent, ScrollbarVisibility, INewScrollDimensions } from 'vs/base/common/scrollable';
import { SmoothScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { ScrollEvent, ScrollbarVisibility, INewScrollDimensions, Scrollable } from 'vs/base/common/scrollable';
import { RangeMap, shift } from './rangeMap';
import { IListVirtualDelegate, IListRenderer, IListMouseEvent, IListTouchEvent, IListGestureEvent, IListDragEvent, IListDragAndDrop, ListDragOverEffect } from './list';
import { RowCache, IRow } from './rowCache';
@@ -44,11 +44,16 @@ export interface IListViewDragAndDrop<T> extends IListDragAndDrop<T> {
export interface IListViewAccessibilityProvider<T> {
getSetSize?(element: T, index: number, listLength: number): number;
getPosInSet?(element: T, index: number): number;
getRole?(element: T): string;
getRole?(element: T): string | undefined;
isChecked?(element: T): boolean | undefined;
}
export interface IListViewOptions<T> {
export interface IListViewOptionsUpdate {
readonly additionalScrollHeight?: number;
readonly smoothScrolling?: boolean;
}
export interface IListViewOptions<T> extends IListViewOptionsUpdate {
readonly dnd?: IListViewDragAndDrop<T>;
readonly useShadows?: boolean;
readonly verticalScrollMode?: ScrollbarVisibility;
@@ -58,7 +63,6 @@ export interface IListViewOptions<T> {
readonly mouseSupport?: boolean;
readonly horizontalScrolling?: boolean;
readonly accessibilityProvider?: IListViewAccessibilityProvider<T>;
readonly additionalScrollHeight?: number;
readonly transformOptimization?: boolean;
}
@@ -158,7 +162,7 @@ class ListViewAccessibilityProvider<T> implements Required<IListViewAccessibilit
readonly getSetSize: (element: any, index: number, listLength: number) => number;
readonly getPosInSet: (element: any, index: number) => number;
readonly getRole: (element: T) => string;
readonly getRole: (element: T) => string | undefined;
readonly isChecked: (element: T) => boolean | undefined;
constructor(accessibilityProvider?: IListViewAccessibilityProvider<T>) {
@@ -204,7 +208,8 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
private lastRenderHeight: number;
private renderWidth = 0;
private rowsContainer: HTMLElement;
private scrollableElement: ScrollableElement;
private scrollable: Scrollable;
private scrollableElement: SmoothScrollableElement;
private _scrollHeight: number = 0;
private scrollableElementUpdateDisposable: IDisposable | null = null;
private scrollableElementWidthDelayer = new Delayer<void>(50);
@@ -278,18 +283,20 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
this.rowsContainer = document.createElement('div');
this.rowsContainer.className = 'monaco-list-rows';
if (options.transformOptimization) {
const transformOptimization = getOrDefault(options, o => o.transformOptimization, DefaultOptions.transformOptimization);
if (transformOptimization) {
this.rowsContainer.style.transform = 'translate3d(0px, 0px, 0px)';
}
this.disposables.add(Gesture.addTarget(this.rowsContainer));
this.scrollableElement = this.disposables.add(new ScrollableElement(this.rowsContainer, {
this.scrollable = new Scrollable(getOrDefault(options, o => o.smoothScrolling, false) ? 125 : 0, cb => DOM.scheduleAtNextAnimationFrame(cb));
this.scrollableElement = this.disposables.add(new SmoothScrollableElement(this.rowsContainer, {
alwaysConsumeMouseWheel: true,
horizontal: this.horizontalScrolling ? ScrollbarVisibility.Auto : ScrollbarVisibility.Hidden,
vertical: getOrDefault(options, o => o.verticalScrollMode, DefaultOptions.verticalScrollMode),
useShadows: getOrDefault(options, o => o.useShadows, DefaultOptions.useShadows)
}));
useShadows: getOrDefault(options, o => o.useShadows, DefaultOptions.useShadows),
}, this.scrollable));
this.domNode.appendChild(this.scrollableElement.getDomNode());
container.appendChild(this.domNode);
@@ -319,6 +326,10 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
if (options.additionalScrollHeight !== undefined) {
this.additionalScrollHeight = options.additionalScrollHeight;
}
if (options.smoothScrolling !== undefined) {
this.scrollable.setSmoothScrollDuration(options.smoothScrolling ? 125 : 0);
}
}
triggerScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent) {
@@ -651,7 +662,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
if (!item.row) {
item.row = this.cache.alloc(item.templateId);
const role = this.accessibilityProvider.getRole(item.element);
const role = this.accessibilityProvider.getRole(item.element) || 'listitem';
item.row!.domNode!.setAttribute('role', role);
const checked = this.accessibilityProvider.isChecked(item.element);
if (typeof checked !== 'undefined') {

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./list';
import { localize } from 'vs/nls';
import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle';
import { isNumber } from 'vs/base/common/types';
import { range, firstIndex, binarySearch } from 'vs/base/common/arrays';
@@ -17,7 +16,7 @@ import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardE
import { Event, Emitter, EventBufferer } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
import { IListVirtualDelegate, IListRenderer, IListEvent, IListContextMenuEvent, IListMouseEvent, IListTouchEvent, IListGestureEvent, IIdentityProvider, IKeyboardNavigationLabelProvider, IListDragAndDrop, IListDragOverReaction, ListError, IKeyboardNavigationDelegate } from './list';
import { ListView, IListViewOptions, IListViewDragAndDrop, IListViewAccessibilityProvider } from './listView';
import { ListView, IListViewOptions, IListViewDragAndDrop, IListViewAccessibilityProvider, IListViewOptionsUpdate } from './listView';
import { Color } from 'vs/base/common/color';
import { mixin } from 'vs/base/common/objects';
import { ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable';
@@ -26,6 +25,7 @@ import { CombinedSpliceable } from 'vs/base/browser/ui/list/splice';
import { clamp } from 'vs/base/common/numbers';
import { matchesPrefix } from 'vs/base/common/filters';
import { IDragAndDropData } from 'vs/base/browser/dnd';
import { alert } from 'vs/base/browser/ui/aria/aria';
interface ITraitChangeEvent {
indexes: number[];
@@ -344,6 +344,7 @@ class TypeLabelController<T> implements IDisposable {
private automaticKeyboardNavigation = true;
private triggered = false;
private previouslyFocused = -1;
private readonly enabledDisposables = new DisposableStore();
private readonly disposables = new DisposableStore();
@@ -393,6 +394,7 @@ class TypeLabelController<T> implements IDisposable {
const onInput = Event.reduce<string | null, string | null>(Event.any(onChar, onClear), (r, i) => i === null ? null : ((r || '') + i));
onInput(this.onInput, this, this.enabledDisposables);
onClear(this.onClear, this, this.enabledDisposables);
this.enabled = true;
this.triggered = false;
@@ -408,6 +410,19 @@ class TypeLabelController<T> implements IDisposable {
this.triggered = false;
}
private onClear(): void {
const focus = this.list.getFocus();
if (focus.length > 0 && focus[0] === this.previouslyFocused) {
// List: re-anounce element on typing end since typed keys will interupt aria label of focused element
// Do not announce if there was a focus change at the end to prevent duplication https://github.com/microsoft/vscode/issues/95961
const ariaLabel = this.list.options.accessibilityProvider?.getAriaLabel(this.list.element(focus[0]));
if (ariaLabel) {
alert(ariaLabel);
}
}
this.previouslyFocused = -1;
}
private onInput(word: string | null): void {
if (!word) {
this.state = TypeLabelControllerState.Idle;
@@ -426,6 +441,7 @@ class TypeLabelController<T> implements IDisposable {
const labelStr = label && label.toString();
if (typeof labelStr === 'undefined' || matchesPrefix(word, labelStr)) {
this.previouslyFocused = start;
this.list.setFocus([index]);
this.list.reveal(index);
return;
@@ -1091,10 +1107,9 @@ class ListViewDragAndDrop<T> implements IListViewDragAndDrop<T> {
}
}
export interface IListOptionsUpdate {
export interface IListOptionsUpdate extends IListViewOptionsUpdate {
readonly enableKeyboardNavigation?: boolean;
readonly automaticKeyboardNavigation?: boolean;
readonly additionalScrollHeight?: number;
}
export class List<T> implements ISpliceable<T>, IDisposable {
@@ -1272,9 +1287,7 @@ export class List<T> implements ISpliceable<T>, IDisposable {
this.typeLabelController.updateOptions(this._options);
}
if (optionsUpdate.additionalScrollHeight !== undefined) {
this.view.updateOptions(optionsUpdate);
}
this.view.updateOptions(optionsUpdate);
}
get options(): IListOptions<T> {
@@ -1363,7 +1376,7 @@ export class List<T> implements ISpliceable<T>, IDisposable {
set ariaLabel(value: string) {
this._ariaLabel = value;
this.view.domNode.setAttribute('aria-label', localize('aria list', "{0}. Use the navigation keys to navigate.", value));
this.view.domNode.setAttribute('aria-label', value);
}
domFocus(): void {

View File

@@ -88,6 +88,9 @@
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 {

View File

@@ -41,6 +41,7 @@ export interface IMenuOptions {
enableMnemonics?: boolean;
anchorAlignment?: AnchorAlignment;
expandDirection?: Direction;
useEventAsContext?: boolean;
}
export interface IMenuStyles {
@@ -316,7 +317,7 @@ export class Menu extends ActionBar {
return menuActionViewItem;
} else {
const menuItemOptions: IMenuItemOptions = { enableMnemonics: options.enableMnemonics };
const menuItemOptions: IMenuItemOptions = { enableMnemonics: options.enableMnemonics, useEventAsContext: options.useEventAsContext };
if (options.getKeyBinding) {
const keybinding = options.getKeyBinding(action);
if (keybinding) {

View File

@@ -140,8 +140,8 @@ export class MenuBar extends Disposable {
eventHandled = false;
}
// Never allow default tab behavior
if (event.equals(KeyCode.Tab | KeyMod.Shift) || event.equals(KeyCode.Tab)) {
// Never allow default tab behavior when not compact
if (this.options.compactMode === undefined && (event.equals(KeyCode.Tab | KeyMod.Shift) || event.equals(KeyCode.Tab))) {
event.preventDefault();
}
@@ -315,7 +315,7 @@ export class MenuBar extends Disposable {
createOverflowMenu(): void {
const label = this.options.compactMode !== undefined ? nls.localize('mAppMenu', 'Application Menu') : nls.localize('mMore', 'More');
const title = this.options.compactMode !== undefined ? label : undefined;
const buttonElement = $('div.menubar-menu-button', { 'role': 'menuitem', 'tabindex': -1, 'aria-label': label, 'title': title, 'aria-haspopup': true });
const buttonElement = $('div.menubar-menu-button', { 'role': 'menuitem', 'tabindex': this.options.compactMode !== undefined ? 0 : -1, 'aria-label': label, 'title': title, 'aria-haspopup': true });
const titleElement = $('div.menubar-menu-title.toolbar-toggle-more' + menuBarMoreIcon.cssSelector, { 'role': 'none', 'aria-hidden': true });
buttonElement.appendChild(titleElement);
@@ -326,7 +326,7 @@ export class MenuBar extends Disposable {
let event = new StandardKeyboardEvent(e as KeyboardEvent);
let eventHandled = true;
if ((event.equals(KeyCode.DownArrow) || event.equals(KeyCode.Enter)) && !this.isOpen) {
if ((event.equals(KeyCode.DownArrow) || event.equals(KeyCode.Enter) || (this.options.compactMode !== undefined && event.equals(KeyCode.Space))) && !this.isOpen) {
this.focusedMenu = { index: MenuBar.OVERFLOW_INDEX };
this.openedViaKeyboard = true;
this.focusState = MenubarState.OPEN;
@@ -945,7 +945,8 @@ export class MenuBar extends Disposable {
actionRunner: this.actionRunner,
enableMnemonics: this.options.alwaysOnMnemonics || (this.mnemonicsInUse && this.options.enableMnemonics),
ariaLabel: withNullAsUndefined(customMenu.buttonElement.getAttribute('aria-label')),
expandDirection: this.options.compactMode !== undefined ? this.options.compactMode : Direction.Right
expandDirection: this.options.compactMode !== undefined ? this.options.compactMode : Direction.Right,
useEventAsContext: true
};
let menuWidget = this._register(new Menu(menuHolder, customMenu.actions, menuOptions));

View File

@@ -0,0 +1,14 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-mouse-cursor-text {
cursor: text;
}
/* The following selector looks a bit funny, but that is needed to cover all the workbench and the editor!! */
.vs-dark .mac .monaco-mouse-cursor-text, .hc-black .mac .monaco-mouse-cursor-text,
.vs-dark.mac .monaco-mouse-cursor-text, .hc-black.mac .monaco-mouse-cursor-text {
cursor: -webkit-image-set(url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAAL0lEQVQoz2NgCD3x//9/BhBYBWdhgFVAiVW4JBFKGIa4AqD0//9D3pt4I4tAdAMAHTQ/j5Zom30AAAAASUVORK5CYII=') 1x, url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAAz0lEQVRIx2NgYGBY/R8I/vx5eelX3n82IJ9FxGf6tksvf/8FiTMQAcAGQMDvSwu09abffY8QYSAScNk45G198eX//yev73/4///701eh//kZSARckrNBRvz//+8+6ZohwCzjGNjdgQxkAg7B9WADeBjIBqtJCbhRA0YNoIkBSNmaPEMoNmA0FkYNoFKhapJ6FGyAH3nauaSmPfwI0v/3OukVi0CIZ+F25KrtYcx/CTIy0e+rC7R1Z4KMICVTQQ14feVXIbR695u14+Ir4gwAAD49E54wc1kWAAAAAElFTkSuQmCC') 2x) 5 8, text;
}

View File

@@ -0,0 +1,8 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./mouseCursor';
export const MOUSE_CURSOR_TEXT_CSS_CLASS_NAME = `monaco-mouse-cursor-text`;

View File

@@ -13,13 +13,6 @@
pointer-events: none;
}
.monaco-sash.vertical {
cursor: ew-resize;
top: 0;
width: 4px;
height: 100%;
}
.monaco-sash.mac.vertical {
cursor: col-resize;
}
@@ -32,13 +25,6 @@
cursor: w-resize;
}
.monaco-sash.horizontal {
cursor: ns-resize;
left: 0;
width: 100%;
height: 4px;
}
.monaco-sash.mac.horizontal {
cursor: row-resize;
}
@@ -51,52 +37,11 @@
cursor: n-resize;
}
.monaco-sash:not(.disabled).orthogonal-start::before,
.monaco-sash:not(.disabled).orthogonal-end::after {
content: ' ';
height: 8px;
width: 8px;
z-index: 100;
display: block;
cursor: all-scroll;
position: absolute;
}
.monaco-sash.orthogonal-start.vertical::before {
left: -2px;
top: -4px;
}
.monaco-sash.orthogonal-end.vertical::after {
left: -2px;
bottom: -4px;
}
.monaco-sash.orthogonal-start.horizontal::before {
top: -2px;
left: -4px;
}
.monaco-sash.orthogonal-end.horizontal::after {
top: -2px;
right: -4px;
}
.monaco-sash.disabled {
cursor: default !important;
pointer-events: none !important;
}
/** Touch **/
.monaco-sash.touch.vertical {
width: 20px;
}
.monaco-sash.touch.horizontal {
height: 20px;
}
/** Debug **/
.monaco-sash.debug {
@@ -110,4 +55,4 @@
.monaco-sash.debug:not(.disabled).orthogonal-start::before,
.monaco-sash.debug:not(.disabled).orthogonal-end::after {
background: red;
}
}

View File

@@ -5,7 +5,6 @@
import 'vs/css!./sash';
import { IDisposable, dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { isIPad } from 'vs/base/browser/browser';
import { isMacintosh } from 'vs/base/common/platform';
import * as types from 'vs/base/common/types';
import { EventType, GestureEvent, Gesture } from 'vs/base/browser/touch';
@@ -39,9 +38,18 @@ export interface ISashEvent {
}
export interface ISashOptions {
orientation?: Orientation;
orthogonalStartSash?: Sash;
orthogonalEndSash?: Sash;
readonly orientation: Orientation;
readonly orthogonalStartSash?: Sash;
readonly orthogonalEndSash?: Sash;
readonly size?: number;
}
export interface IVerticalSashOptions extends ISashOptions {
readonly orientation: Orientation.VERTICAL;
}
export interface IHorizontalSashOptions extends ISashOptions {
readonly orientation: Orientation.HORIZONTAL;
}
export const enum Orientation {
@@ -56,12 +64,20 @@ export const enum SashState {
Enabled
}
let globalSize = 4;
const onDidChangeGlobalSize = new Emitter<number>();
export function setGlobalSashSize(size: number): void {
globalSize = size;
onDidChangeGlobalSize.fire(size);
}
export class Sash extends Disposable {
private el: HTMLElement;
private layoutProvider: ISashLayoutProvider;
private hidden: boolean;
private orientation!: Orientation;
private size: number;
private _state: SashState = SashState.Enabled;
get state(): SashState { return this._state; }
@@ -127,7 +143,9 @@ export class Sash extends Disposable {
this._orthogonalEndSash = sash;
}
constructor(container: HTMLElement, layoutProvider: ISashLayoutProvider, options: ISashOptions = {}) {
constructor(container: HTMLElement, layoutProvider: IVerticalSashLayoutProvider, options: ISashOptions);
constructor(container: HTMLElement, layoutProvider: IHorizontalSashLayoutProvider, options: ISashOptions);
constructor(container: HTMLElement, layoutProvider: ISashLayoutProvider, options: ISashOptions) {
super();
this.el = append(container, $('.monaco-sash'));
@@ -142,12 +160,21 @@ export class Sash extends Disposable {
this._register(Gesture.addTarget(this.el));
this._register(domEvent(this.el, EventType.Start)(this.onTouchStart, this));
if (isIPad) {
// see also https://ux.stackexchange.com/questions/39023/what-is-the-optimum-button-size-of-touch-screen-applications
addClass(this.el, 'touch');
}
if (typeof options.size === 'number') {
this.size = options.size;
this.setOrientation(options.orientation || Orientation.VERTICAL);
if (options.orientation === Orientation.VERTICAL) {
this.el.style.width = `${this.size}px`;
} else {
this.el.style.height = `${this.size}px`;
}
} else {
this.size = globalSize;
this._register(onDidChangeGlobalSize.event(size => {
this.size = size;
this.layout();
}));
}
this.hidden = false;
this.layoutProvider = layoutProvider;
@@ -155,11 +182,7 @@ export class Sash extends Disposable {
this.orthogonalStartSash = options.orthogonalStartSash;
this.orthogonalEndSash = options.orthogonalEndSash;
toggleClass(this.el, 'debug', DEBUG);
}
setOrientation(orientation: Orientation): void {
this.orientation = orientation;
this.orientation = options.orientation || Orientation.VERTICAL;
if (this.orientation === Orientation.HORIZONTAL) {
addClass(this.el, 'horizontal');
@@ -169,9 +192,9 @@ export class Sash extends Disposable {
addClass(this.el, 'vertical');
}
if (this.layoutProvider) {
this.layout();
}
toggleClass(this.el, 'debug', DEBUG);
this.layout();
}
private onMouseDown(e: MouseEvent): void {
@@ -331,11 +354,9 @@ export class Sash extends Disposable {
}
layout(): void {
const size = isIPad ? 20 : 4;
if (this.orientation === Orientation.VERTICAL) {
const verticalProvider = (<IVerticalSashLayoutProvider>this.layoutProvider);
this.el.style.left = verticalProvider.getVerticalSashLeft(this) - (size / 2) + 'px';
this.el.style.left = verticalProvider.getVerticalSashLeft(this) - (this.size / 2) + 'px';
if (verticalProvider.getVerticalSashTop) {
this.el.style.top = verticalProvider.getVerticalSashTop(this) + 'px';
@@ -346,7 +367,7 @@ export class Sash extends Disposable {
}
} else {
const horizontalProvider = (<IHorizontalSashLayoutProvider>this.layoutProvider);
this.el.style.top = horizontalProvider.getHorizontalSashTop(this) - (size / 2) + 'px';
this.el.style.top = horizontalProvider.getHorizontalSashTop(this) - (this.size / 2) + 'px';
if (horizontalProvider.getHorizontalSashLeft) {
this.el.style.left = horizontalProvider.getHorizontalSashLeft(this) + 'px';
@@ -384,15 +405,15 @@ export class Sash extends Disposable {
private getOrthogonalSash(e: MouseEvent): Sash | undefined {
if (this.orientation === Orientation.VERTICAL) {
if (e.offsetY <= 4) {
if (e.offsetY <= this.size) {
return this.orthogonalStartSash;
} else if (e.offsetY >= this.el.clientHeight - 4) {
} else if (e.offsetY >= this.el.clientHeight - this.size) {
return this.orthogonalEndSash;
}
} else {
if (e.offsetX <= 4) {
if (e.offsetX <= this.size) {
return this.orthogonalStartSash;
} else if (e.offsetX >= this.el.clientWidth - 4) {
} else if (e.offsetX >= this.el.clientWidth - this.size) {
return this.orthogonalEndSash;
}
}

View File

@@ -533,6 +533,14 @@ export class SmoothScrollableElement extends AbstractScrollableElement {
super(element, options, scrollable);
}
public setScrollPosition(update: INewScrollPosition): void {
this._scrollable.setScrollPositionNow(update);
}
public getScrollPosition(): IScrollPosition {
return this._scrollable.getCurrentScrollPosition();
}
}
export class DomScrollableElement extends ScrollableElement {

View File

@@ -6,3 +6,9 @@
.monaco-select-box {
width: 100%;
}
.monaco-select-box-dropdown-container {
font-size: 13px;
font-weight: normal;
text-transform: none;
}

View File

@@ -40,6 +40,7 @@ export interface ISelectBoxOptions {
useCustomDrawn?: boolean;
ariaLabel?: string;
minBottomMargin?: number;
optionsAsChildren?: boolean;
}
// Utilize optionItem interface to capture all option parameters

View File

@@ -90,8 +90,8 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
private _isVisible: boolean;
private selectBoxOptions: ISelectBoxOptions;
public selectElement: HTMLSelectElement; // {{SQL CARBON EDIT}}
public selectElement: HTMLSelectElement; // {{SQL CARBON EDIT}}
private container?: HTMLElement;
private options: ISelectOptionItem[] = [];
private selected: number;
private readonly _onDidSelect: Emitter<ISelectData>;
@@ -310,6 +310,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
}
public render(container: HTMLElement): void {
this.container = container;
dom.addClass(container, 'select-container');
container.appendChild(this.selectElement);
this.applyStyles();
@@ -454,7 +455,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
dom.toggleClass(this.selectElement, 'synthetic-focus', false);
},
anchorPosition: this._dropDownPosition
});
}, this.selectBoxOptions.optionsAsChildren ? this.container : undefined);
// Hide so we can relay out
this._isVisible = true;
@@ -469,7 +470,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
dom.toggleClass(this.selectElement, 'synthetic-focus', false);
},
anchorPosition: this._dropDownPosition
});
}, this.selectBoxOptions.optionsAsChildren ? this.container : undefined);
// Track initial selection the case user escape, blur
this._currentSelection = this.selected;
@@ -739,7 +740,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
mouseSupport: false,
accessibilityProvider: {
getAriaLabel: (element) => element.text,
getWidgetAriaLabel: () => localize('selectBox', "Select Box"),
getWidgetAriaLabel: () => localize({ key: 'selectBox', comment: ['Behave like native select dropdown element.'] }, "Select Box"),
getRole: () => 'option',
getWidgetRole: () => 'listbox'
}

View File

@@ -16,7 +16,12 @@
flex-direction: column;
}
.monaco-pane-view .pane.horizontal:not(.expanded) {
flex-direction: row;
}
.monaco-pane-view .pane > .pane-header {
height: 22px;
font-size: 11px;
font-weight: bold;
text-transform: uppercase;
@@ -26,6 +31,12 @@
align-items: center;
}
.monaco-pane-view .pane.horizontal:not(.expanded) > .pane-header {
flex-direction: column;
height: 100%;
width: 22px;
}
.monaco-pane-view .pane > .pane-header > .twisties {
width: 20px;
display: flex;
@@ -36,6 +47,11 @@
flex-shrink: 0;
}
.monaco-pane-view .pane.horizontal:not(.expanded) > .pane-header > .twisties {
margin-top: 2px;
margin-bottom: 2px;
}
.monaco-pane-view .pane > .pane-header.expanded > .twisties::before {
transform: rotate(90deg);
}
@@ -132,6 +148,7 @@
width: 100%;
height: 100%;
min-height: 22px;
min-width: 19px;
pointer-events: none; /* very important to not take events away from the parent */
transition: opacity 150ms ease-out;

View File

@@ -106,7 +106,7 @@ export abstract class Pane extends Disposable implements IView {
get minimumSize(): number {
const headerSize = this.headerSize;
const expanded = !this.headerVisible || this.isExpanded();
const minimumBodySize = expanded ? this.minimumBodySize : this._orientation === Orientation.HORIZONTAL ? 50 : 0;
const minimumBodySize = expanded ? this.minimumBodySize : 0;
return headerSize + minimumBodySize;
}
@@ -114,7 +114,7 @@ export abstract class Pane extends Disposable implements IView {
get maximumSize(): number {
const headerSize = this.headerSize;
const expanded = !this.headerVisible || this.isExpanded();
const maximumBodySize = expanded ? this.maximumBodySize : this._orientation === Orientation.HORIZONTAL ? 50 : 0;
const maximumBodySize = expanded ? this.maximumBodySize : 0;
return headerSize + maximumBodySize;
}
@@ -126,7 +126,7 @@ export abstract class Pane extends Disposable implements IView {
this._expanded = typeof options.expanded === 'undefined' ? true : !!options.expanded;
this._orientation = typeof options.orientation === 'undefined' ? Orientation.VERTICAL : options.orientation;
this.ariaHeaderLabel = localize('viewSection', "{0} Section", options.title);
this._minimumBodySize = typeof options.minimumBodySize === 'number' ? options.minimumBodySize : 120;
this._minimumBodySize = typeof options.minimumBodySize === 'number' ? options.minimumBodySize : this._orientation === Orientation.HORIZONTAL ? 200 : 120;
this._maximumBodySize = typeof options.maximumBodySize === 'number' ? options.maximumBodySize : Number.POSITIVE_INFINITY;
this.element = $('.pane');
@@ -141,6 +141,10 @@ export abstract class Pane extends Disposable implements IView {
return false;
}
if (this.element) {
toggleClass(this.element, 'expanded', expanded);
}
this._expanded = !!expanded;
this.updateHeader();
@@ -185,12 +189,21 @@ export abstract class Pane extends Disposable implements IView {
this._orientation = orientation;
if (this.element) {
toggleClass(this.element, 'horizontal', this.orientation === Orientation.HORIZONTAL);
toggleClass(this.element, 'vertical', this.orientation === Orientation.VERTICAL);
}
if (this.header) {
this.updateHeader();
}
}
render(): void {
toggleClass(this.element, 'expanded', this.isExpanded());
toggleClass(this.element, 'horizontal', this.orientation === Orientation.HORIZONTAL);
toggleClass(this.element, 'vertical', this.orientation === Orientation.VERTICAL);
this.header = $('.pane-header');
append(this.element, this.header);
this.header.setAttribute('tabindex', '0');
@@ -250,8 +263,6 @@ export abstract class Pane extends Disposable implements IView {
style(styles: IPaneStyles): void {
this.styles = styles;
this.element.style.borderLeft = this.styles.leftBorder && this.orientation === Orientation.HORIZONTAL ? `1px solid ${this.styles.leftBorder}` : '';
if (!this.header) {
return;
}
@@ -262,7 +273,6 @@ export abstract class Pane extends Disposable implements IView {
protected updateHeader(): void {
const expanded = !this.headerVisible || this.isExpanded();
this.header.style.height = `${this.headerSize}px`;
this.header.style.lineHeight = `${this.headerSize}px`;
toggleClass(this.header, 'hidden', !this.headerVisible);
toggleClass(this.header, 'expanded', expanded);
@@ -272,6 +282,7 @@ export abstract class Pane extends Disposable implements IView {
this.header.style.backgroundColor = this.styles.headerBackground ? this.styles.headerBackground.toString() : '';
this.header.style.borderTop = this.styles.headerBorder && this.orientation === Orientation.VERTICAL ? `1px solid ${this.styles.headerBorder}` : '';
this._dropBackground = this.styles.dropBackground;
this.element.style.borderLeft = this.styles.leftBorder && this.orientation === Orientation.HORIZONTAL ? `1px solid ${this.styles.leftBorder}` : '';
}
protected abstract renderHeader(container: HTMLElement): void;

View File

@@ -331,8 +331,8 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
}
}
addView(view: IView<TLayoutContext>, size: number | Sizing, index = this.viewItems.length): void {
this.doAddView(view, size, index, false);
addView(view: IView<TLayoutContext>, size: number | Sizing, index = this.viewItems.length, skipLayout?: boolean): void {
this.doAddView(view, size, index, skipLayout);
}
removeView(index: number, sizing?: Sizing): IView<TLayoutContext> {
@@ -689,13 +689,17 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
// Add sash
if (this.viewItems.length > 1) {
const orientation = this.orientation === Orientation.VERTICAL ? Orientation.HORIZONTAL : Orientation.VERTICAL;
const layoutProvider = this.orientation === Orientation.VERTICAL ? { getHorizontalSashTop: (sash: Sash) => this.getSashPosition(sash) } : { getVerticalSashLeft: (sash: Sash) => this.getSashPosition(sash) };
const sash = new Sash(this.sashContainer, layoutProvider, {
orientation,
orthogonalStartSash: this.orthogonalStartSash,
orthogonalEndSash: this.orthogonalEndSash
});
const sash = this.orientation === Orientation.VERTICAL
? new Sash(this.sashContainer, { getHorizontalSashTop: (sash: Sash) => this.getSashPosition(sash) }, {
orientation: Orientation.HORIZONTAL,
orthogonalStartSash: this.orthogonalStartSash,
orthogonalEndSash: this.orthogonalEndSash
})
: new Sash(this.sashContainer, { getVerticalSashLeft: (sash: Sash) => this.getSashPosition(sash) }, {
orientation: Orientation.VERTICAL,
orthogonalStartSash: this.orthogonalStartSash,
orthogonalEndSash: this.orthogonalEndSash
});
const sashEventMapper = this.orientation === Orientation.VERTICAL
? (e: IBaseSashEvent) => ({ sash, start: e.startY, current: e.currentY, alt: e.altKey })
@@ -951,7 +955,7 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
position += this.viewItems[i].size;
if (this.sashItems[i].sash === sash) {
return Math.min(position, this.contentSize - 2);
return position;
}
}

View File

@@ -707,7 +707,7 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
.map(e => new StandardKeyboardEvent(e))
.filter(this.keyboardNavigationEventFilter || (() => true))
.filter(() => this.automaticKeyboardNavigation || this.triggered)
.filter(e => this.keyboardNavigationDelegate.mightProducePrintableCharacter(e) || ((this.pattern.length > 0 || this.triggered) && ((e.keyCode === KeyCode.Escape || e.keyCode === KeyCode.Backspace) && !e.altKey && !e.ctrlKey && !e.metaKey) || (e.keyCode === KeyCode.Backspace && (isMacintosh ? (e.altKey && !e.metaKey) : e.ctrlKey) && !e.shiftKey)))
.filter(e => (this.keyboardNavigationDelegate.mightProducePrintableCharacter(e) && !(e.keyCode === KeyCode.DownArrow || e.keyCode === KeyCode.UpArrow || e.keyCode === KeyCode.LeftArrow || e.keyCode === KeyCode.RightArrow)) || ((this.pattern.length > 0 || this.triggered) && ((e.keyCode === KeyCode.Escape || e.keyCode === KeyCode.Backspace) && !e.altKey && !e.ctrlKey && !e.metaKey) || (e.keyCode === KeyCode.Backspace && (isMacintosh ? (e.altKey && !e.metaKey) : e.ctrlKey) && !e.shiftKey)))
.forEach(e => { e.stopPropagation(); e.preventDefault(); })
.event;
@@ -962,6 +962,7 @@ export interface IAbstractTreeOptionsUpdate extends ITreeRendererOptions {
readonly simpleKeyboardNavigation?: boolean;
readonly filterOnType?: boolean;
readonly openOnSingleClick?: boolean;
readonly smoothScrolling?: boolean;
}
export interface IAbstractTreeOptions<T, TFilterData = void> extends IAbstractTreeOptionsUpdate, IListOptions<T> {
@@ -1360,7 +1361,8 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
this.view.updateOptions({
enableKeyboardNavigation: this._options.simpleKeyboardNavigation,
automaticKeyboardNavigation: this._options.automaticKeyboardNavigation
automaticKeyboardNavigation: this._options.automaticKeyboardNavigation,
smoothScrolling: this._options.smoothScrolling
});
if (this.typeFilterController) {

View File

@@ -13,7 +13,7 @@ export class CollapseAllAction<TInput, T, TFilterData = void> extends Action {
super('vs.tree.collapse', nls.localize('collapse all', "Collapse All"), 'collapse-all', enabled);
}
async run(context?: any): Promise<any> {
async run(): Promise<any> {
this.viewer.collapseAll();
this.viewer.setSelection([]);
this.viewer.setFocus([]);