mirror of
https://github.com/coder/code-server.git
synced 2026-05-06 12:31:58 +02:00
chore(vscode): update to 1.55.2
This commit is contained in:
@@ -383,6 +383,7 @@ export class SelectActionViewItem extends BaseActionViewItem {
|
||||
super(ctx, action);
|
||||
|
||||
this.selectBox = new SelectBox(options, selected, contextViewProvider, undefined, selectBoxOptions);
|
||||
this.selectBox.setFocusable(false);
|
||||
|
||||
this._register(this.selectBox);
|
||||
this.registerListeners();
|
||||
@@ -406,6 +407,10 @@ export class SelectActionViewItem extends BaseActionViewItem {
|
||||
return option;
|
||||
}
|
||||
|
||||
setFocusable(focusable: boolean): void {
|
||||
this.selectBox.setFocusable(focusable);
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
if (this.selectBox) {
|
||||
this.selectBox.focus();
|
||||
|
||||
@@ -20,10 +20,6 @@
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.monaco-action-bar.reverse .actions-container {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
|
||||
@@ -28,9 +28,7 @@ export interface IActionViewItemProvider {
|
||||
|
||||
export const enum ActionsOrientation {
|
||||
HORIZONTAL,
|
||||
HORIZONTAL_REVERSE,
|
||||
VERTICAL,
|
||||
VERTICAL_REVERSE,
|
||||
}
|
||||
|
||||
export interface ActionTrigger {
|
||||
@@ -135,21 +133,11 @@ export class ActionBar extends Disposable implements IActionRunner {
|
||||
previousKeys = [KeyCode.LeftArrow];
|
||||
nextKeys = [KeyCode.RightArrow];
|
||||
break;
|
||||
case ActionsOrientation.HORIZONTAL_REVERSE:
|
||||
previousKeys = [KeyCode.RightArrow];
|
||||
nextKeys = [KeyCode.LeftArrow];
|
||||
this.domNode.className += ' reverse';
|
||||
break;
|
||||
case ActionsOrientation.VERTICAL:
|
||||
previousKeys = [KeyCode.UpArrow];
|
||||
nextKeys = [KeyCode.DownArrow];
|
||||
this.domNode.className += ' vertical';
|
||||
break;
|
||||
case ActionsOrientation.VERTICAL_REVERSE:
|
||||
previousKeys = [KeyCode.DownArrow];
|
||||
nextKeys = [KeyCode.UpArrow];
|
||||
this.domNode.className += ' vertical reverse';
|
||||
break;
|
||||
}
|
||||
|
||||
this._register(DOM.addDisposableListener(this.domNode, DOM.EventType.KEY_DOWN, e => {
|
||||
@@ -163,8 +151,12 @@ export class ActionBar extends Disposable implements IActionRunner {
|
||||
eventHandled = this.focusNext();
|
||||
} else if (event.equals(KeyCode.Escape) && this.cancelHasListener) {
|
||||
this._onDidCancel.fire();
|
||||
} else if (event.equals(KeyCode.Home)) {
|
||||
eventHandled = this.focusFirst();
|
||||
} else if (event.equals(KeyCode.End)) {
|
||||
eventHandled = this.focusLast();
|
||||
} else if (event.equals(KeyCode.Tab) && focusedItem instanceof BaseActionViewItem && focusedItem.trapsArrowNavigation) {
|
||||
this.focusNext();
|
||||
eventHandled = this.focusNext();
|
||||
} else if (this.isTriggerKeyEvent(event)) {
|
||||
// Staying out of the else branch even if not triggered
|
||||
if (this._triggerKeys.keyDown) {
|
||||
@@ -425,9 +417,21 @@ export class ActionBar extends Disposable implements IActionRunner {
|
||||
}
|
||||
}
|
||||
|
||||
private focusFirst(): boolean {
|
||||
this.focusedItem = this.length() > 1 ? 1 : 0;
|
||||
return this.focusPrevious();
|
||||
}
|
||||
|
||||
private focusLast(): boolean {
|
||||
this.focusedItem = this.length() < 2 ? 0 : this.length() - 2;
|
||||
return this.focusNext();
|
||||
}
|
||||
|
||||
protected focusNext(): boolean {
|
||||
if (typeof this.focusedItem === 'undefined') {
|
||||
this.focusedItem = this.viewItems.length - 1;
|
||||
} else if (this.viewItems.length <= 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const startIndex = this.focusedItem;
|
||||
@@ -450,6 +454,8 @@ export class ActionBar extends Disposable implements IActionRunner {
|
||||
protected focusPrevious(): boolean {
|
||||
if (typeof this.focusedItem === 'undefined') {
|
||||
this.focusedItem = 0;
|
||||
} else if (this.viewItems.length <= 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const startIndex = this.focusedItem;
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.monaco-text-button:focus {
|
||||
outline-offset: 2px !important;
|
||||
}
|
||||
|
||||
.monaco-text-button:hover {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -20,4 +20,5 @@ export interface IHoverDelegateOptions {
|
||||
|
||||
export interface IHoverDelegate {
|
||||
showHover(options: IHoverDelegateOptions): IDisposable | undefined;
|
||||
delay: number;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import { IMatch } from 'vs/base/common/filters';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Range } from 'vs/base/common/range';
|
||||
import { equals } from 'vs/base/common/objects';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { IHoverDelegate, IHoverDelegateOptions, IHoverDelegateTarget } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';
|
||||
import { AnchorPosition } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
@@ -218,9 +217,6 @@ export class IconLabel extends Disposable {
|
||||
htmlElement.removeAttribute('title');
|
||||
let tooltip = this.getTooltipForCustom(markdownTooltip);
|
||||
|
||||
// Testing has indicated that on Windows and Linux 500 ms matches the native hovers most closely.
|
||||
// On Mac, the delay is 1500.
|
||||
const hoverDelay = isMacintosh ? 1500 : 500;
|
||||
let hoverOptions: IHoverDelegateOptions | undefined;
|
||||
let mouseX: number | undefined;
|
||||
let isHovering = false;
|
||||
@@ -232,9 +228,12 @@ export class IconLabel extends Disposable {
|
||||
}
|
||||
tokenSource = new CancellationTokenSource();
|
||||
function mouseLeaveOrDown(this: HTMLElement, e: MouseEvent): any {
|
||||
if ((e.type === dom.EventType.MOUSE_DOWN) || (<any>e).fromElement === htmlElement) {
|
||||
const isMouseDown = e.type === dom.EventType.MOUSE_DOWN;
|
||||
if (isMouseDown) {
|
||||
hoverDisposable?.dispose();
|
||||
hoverDisposable = undefined;
|
||||
}
|
||||
if (isMouseDown || (<any>e).fromElement === htmlElement) {
|
||||
isHovering = false;
|
||||
hoverOptions = undefined;
|
||||
tokenSource.dispose(true);
|
||||
@@ -282,7 +281,7 @@ export class IconLabel extends Disposable {
|
||||
|
||||
}
|
||||
mouseMoveDisposable.dispose();
|
||||
}, hoverDelay);
|
||||
}, hoverDelegate.delay);
|
||||
}
|
||||
const mouseOverDisposable = this._register(domEvent(htmlElement, dom.EventType.MOUSE_OVER, true)(mouseOver.bind(htmlElement)));
|
||||
this.customHovers.set(htmlElement, mouseOverDisposable);
|
||||
|
||||
@@ -27,6 +27,7 @@ const $ = dom.$;
|
||||
|
||||
export interface IInputOptions extends IInputBoxStyles {
|
||||
readonly placeholder?: string;
|
||||
readonly tooltip?: string;
|
||||
readonly ariaLabel?: string;
|
||||
readonly type?: string;
|
||||
readonly validationOptions?: IInputValidationOptions;
|
||||
@@ -95,6 +96,7 @@ export class InputBox extends Widget {
|
||||
private options: IInputOptions;
|
||||
private message: IMessage | null;
|
||||
private placeholder: string;
|
||||
private tooltip: string;
|
||||
private ariaLabel: string;
|
||||
private validation?: IInputValidator;
|
||||
private state: 'idle' | 'open' | 'closed' = 'idle';
|
||||
@@ -133,6 +135,7 @@ export class InputBox extends Widget {
|
||||
mixin(this.options, defaultOpts, false);
|
||||
this.message = null;
|
||||
this.placeholder = this.options.placeholder || '';
|
||||
this.tooltip = this.options.tooltip ?? (this.placeholder || '');
|
||||
this.ariaLabel = this.options.ariaLabel || '';
|
||||
|
||||
this.inputBackground = this.options.inputBackground;
|
||||
@@ -207,6 +210,10 @@ export class InputBox extends Widget {
|
||||
this.setPlaceHolder(this.placeholder);
|
||||
}
|
||||
|
||||
if (this.tooltip) {
|
||||
this.setTooltip(this.tooltip);
|
||||
}
|
||||
|
||||
this.oninput(this.input, () => this.onValueChange());
|
||||
this.onblur(this.input, () => this.onBlur());
|
||||
this.onfocus(this.input, () => this.onFocus());
|
||||
@@ -235,7 +242,11 @@ export class InputBox extends Widget {
|
||||
public setPlaceHolder(placeHolder: string): void {
|
||||
this.placeholder = placeHolder;
|
||||
this.input.setAttribute('placeholder', placeHolder);
|
||||
this.input.title = placeHolder;
|
||||
}
|
||||
|
||||
public setTooltip(tooltip: string): void {
|
||||
this.tooltip = tooltip;
|
||||
this.input.title = tooltip;
|
||||
}
|
||||
|
||||
public setAriaLabel(label: string): void {
|
||||
|
||||
@@ -226,6 +226,14 @@ export class PagedList<T> implements IThemable, IDisposable {
|
||||
this.list.scrollLeft = scrollLeft;
|
||||
}
|
||||
|
||||
setAnchor(index: number | undefined): void {
|
||||
this.list.setAnchor(index);
|
||||
}
|
||||
|
||||
getAnchor(): number | undefined {
|
||||
return this.list.getAnchor();
|
||||
}
|
||||
|
||||
setFocus(indexes: number[]): void {
|
||||
this.list.setFocus(indexes);
|
||||
}
|
||||
@@ -238,12 +246,20 @@ export class PagedList<T> implements IThemable, IDisposable {
|
||||
this.list.focusPrevious(n, loop);
|
||||
}
|
||||
|
||||
focusNextPage(): void {
|
||||
this.list.focusNextPage();
|
||||
focusNextPage(): Promise<void> {
|
||||
return this.list.focusNextPage();
|
||||
}
|
||||
|
||||
focusPreviousPage(): void {
|
||||
this.list.focusPreviousPage();
|
||||
focusPreviousPage(): Promise<void> {
|
||||
return this.list.focusPreviousPage();
|
||||
}
|
||||
|
||||
focusLast(): void {
|
||||
this.list.focusLast();
|
||||
}
|
||||
|
||||
focusFirst(): void {
|
||||
this.list.focusFirst();
|
||||
}
|
||||
|
||||
getFocus(): number[] {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import 'vs/css!./list';
|
||||
import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { isNumber } from 'vs/base/common/types';
|
||||
import { range, binarySearch } from 'vs/base/common/arrays';
|
||||
import { range, binarySearch, firstOrDefault } from 'vs/base/common/arrays';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { Gesture } from 'vs/base/browser/touch';
|
||||
@@ -27,6 +27,7 @@ import { IDragAndDropData } from 'vs/base/browser/dnd';
|
||||
import { alert } from 'vs/base/browser/ui/aria/aria';
|
||||
import { IThemable } from 'vs/base/common/styler';
|
||||
import { createStyleSheet } from 'vs/base/browser/dom';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
|
||||
interface ITraitChangeEvent {
|
||||
indexes: number[];
|
||||
@@ -617,27 +618,25 @@ export class MouseController<T> implements IDisposable {
|
||||
return;
|
||||
}
|
||||
|
||||
let reference = this.list.getFocus()[0];
|
||||
const selection = this.list.getSelection();
|
||||
reference = reference === undefined ? selection[0] : reference;
|
||||
|
||||
const focus = e.index;
|
||||
|
||||
if (typeof focus === 'undefined') {
|
||||
this.list.setFocus([], e.browserEvent);
|
||||
this.list.setSelection([], e.browserEvent);
|
||||
this.list.setAnchor(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.multipleSelectionSupport && this.isSelectionRangeChangeEvent(e)) {
|
||||
return this.changeSelection(e, reference);
|
||||
return this.changeSelection(e);
|
||||
}
|
||||
|
||||
if (this.multipleSelectionSupport && this.isSelectionChangeEvent(e)) {
|
||||
return this.changeSelection(e, reference);
|
||||
return this.changeSelection(e);
|
||||
}
|
||||
|
||||
this.list.setFocus([focus], e.browserEvent);
|
||||
this.list.setAnchor(focus);
|
||||
|
||||
if (!isMouseRightClick(e.browserEvent)) {
|
||||
this.list.setSelection([focus], e.browserEvent);
|
||||
@@ -659,15 +658,16 @@ export class MouseController<T> implements IDisposable {
|
||||
this.list.setSelection(focus, e.browserEvent);
|
||||
}
|
||||
|
||||
private changeSelection(e: IListMouseEvent<T> | IListTouchEvent<T>, reference: number | undefined): void {
|
||||
private changeSelection(e: IListMouseEvent<T> | IListTouchEvent<T>): void {
|
||||
const focus = e.index!;
|
||||
const anchor = this.list.getAnchor();
|
||||
|
||||
if (this.isSelectionRangeChangeEvent(e) && reference !== undefined) {
|
||||
const min = Math.min(reference, focus);
|
||||
const max = Math.max(reference, focus);
|
||||
if (this.isSelectionRangeChangeEvent(e) && typeof anchor === 'number') {
|
||||
const min = Math.min(anchor, focus);
|
||||
const max = Math.max(anchor, focus);
|
||||
const rangeSelection = range(min, max + 1);
|
||||
const selection = this.list.getSelection();
|
||||
const contiguousRange = getContiguousRangeContaining(disjunction(selection, [reference]), reference);
|
||||
const contiguousRange = getContiguousRangeContaining(disjunction(selection, [anchor]), anchor);
|
||||
|
||||
if (contiguousRange.length === 0) {
|
||||
return;
|
||||
@@ -675,12 +675,14 @@ export class MouseController<T> implements IDisposable {
|
||||
|
||||
const newSelection = disjunction(rangeSelection, relativeComplement(selection, contiguousRange));
|
||||
this.list.setSelection(newSelection, e.browserEvent);
|
||||
this.list.setFocus([focus], e.browserEvent);
|
||||
|
||||
} else if (this.isSelectionSingleChangeEvent(e)) {
|
||||
const selection = this.list.getSelection();
|
||||
const newSelection = selection.filter(i => i !== focus);
|
||||
|
||||
this.list.setFocus([focus]);
|
||||
this.list.setAnchor(focus);
|
||||
|
||||
if (selection.length === newSelection.length) {
|
||||
this.list.setSelection([...newSelection, focus], e.browserEvent);
|
||||
@@ -1130,8 +1132,9 @@ export interface IListOptionsUpdate extends IListViewOptionsUpdate {
|
||||
|
||||
export class List<T> implements ISpliceable<T>, IThemable, IDisposable {
|
||||
|
||||
private focus: Trait<T>;
|
||||
private focus = new Trait<T>('focused');
|
||||
private selection: Trait<T>;
|
||||
private anchor = new Trait<T>('anchor');
|
||||
private eventBufferer = new EventBufferer();
|
||||
protected view: ListView<T>;
|
||||
private spliceable: ISpliceable<T>;
|
||||
@@ -1223,7 +1226,6 @@ export class List<T> implements ISpliceable<T>, IThemable, IDisposable {
|
||||
) {
|
||||
const role = this._options.accessibilityProvider && this._options.accessibilityProvider.getWidgetRole ? this._options.accessibilityProvider?.getWidgetRole() : 'list';
|
||||
this.selection = new SelectionTrait(role !== 'listbox');
|
||||
this.focus = new Trait('focused');
|
||||
|
||||
mixin(_options, defaultStyles, false);
|
||||
|
||||
@@ -1259,11 +1261,13 @@ export class List<T> implements ISpliceable<T>, IThemable, IDisposable {
|
||||
this.spliceable = new CombinedSpliceable([
|
||||
new TraitSpliceable(this.focus, this.view, _options.identityProvider),
|
||||
new TraitSpliceable(this.selection, this.view, _options.identityProvider),
|
||||
new TraitSpliceable(this.anchor, this.view, _options.identityProvider),
|
||||
this.view
|
||||
]);
|
||||
|
||||
this.disposables.add(this.focus);
|
||||
this.disposables.add(this.selection);
|
||||
this.disposables.add(this.anchor);
|
||||
this.disposables.add(this.view);
|
||||
this.disposables.add(this._onDidDispose);
|
||||
|
||||
@@ -1436,6 +1440,23 @@ export class List<T> implements ISpliceable<T>, IThemable, IDisposable {
|
||||
return this.getSelection().map(i => this.view.element(i));
|
||||
}
|
||||
|
||||
setAnchor(index: number | undefined): void {
|
||||
if (typeof index === 'undefined') {
|
||||
this.anchor.set([]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (index < 0 || index >= this.length) {
|
||||
throw new ListError(this.user, `Invalid index ${index}`);
|
||||
}
|
||||
|
||||
this.anchor.set([index]);
|
||||
}
|
||||
|
||||
getAnchor(): number | undefined {
|
||||
return firstOrDefault(this.anchor.get(), undefined);
|
||||
}
|
||||
|
||||
setFocus(indexes: number[], browserEvent?: UIEvent): void {
|
||||
for (const index of indexes) {
|
||||
if (index < 0 || index >= this.length) {
|
||||
@@ -1468,7 +1489,7 @@ export class List<T> implements ISpliceable<T>, IThemable, IDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
focusNextPage(browserEvent?: UIEvent, filter?: (element: T) => boolean): void {
|
||||
async focusNextPage(browserEvent?: UIEvent, filter?: (element: T) => boolean): Promise<void> {
|
||||
let lastPageIndex = this.view.indexAt(this.view.getScrollTop() + this.view.renderHeight);
|
||||
lastPageIndex = lastPageIndex === 0 ? 0 : lastPageIndex - 1;
|
||||
const lastPageElement = this.view.element(lastPageIndex);
|
||||
@@ -1490,12 +1511,13 @@ export class List<T> implements ISpliceable<T>, IThemable, IDisposable {
|
||||
this.setFocus([]);
|
||||
|
||||
// Let the scroll event listener run
|
||||
setTimeout(() => this.focusNextPage(browserEvent, filter), 0);
|
||||
await timeout(0);
|
||||
await this.focusNextPage(browserEvent, filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
focusPreviousPage(browserEvent?: UIEvent, filter?: (element: T) => boolean): void {
|
||||
async focusPreviousPage(browserEvent?: UIEvent, filter?: (element: T) => boolean): Promise<void> {
|
||||
let firstPageIndex: number;
|
||||
const scrollTop = this.view.getScrollTop();
|
||||
|
||||
@@ -1524,7 +1546,8 @@ export class List<T> implements ISpliceable<T>, IThemable, IDisposable {
|
||||
this.setFocus([]);
|
||||
|
||||
// Let the scroll event listener run
|
||||
setTimeout(() => this.focusPreviousPage(browserEvent, filter), 0);
|
||||
await timeout(0);
|
||||
await this.focusPreviousPage(browserEvent, filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,3 +85,11 @@
|
||||
.menubar.compact .toolbar-toggle-more::before {
|
||||
content: "\eb94" !important;
|
||||
}
|
||||
|
||||
/* Match behavior of outline for activity bar icons */
|
||||
.menubar.compact > .menubar-menu-button.open,
|
||||
.menubar.compact > .menubar-menu-button:focus,
|
||||
.menubar.compact > .menubar-menu-button:hover {
|
||||
outline-width: 1px !important;
|
||||
outline-offset: -8px !important;
|
||||
}
|
||||
|
||||
@@ -976,7 +976,7 @@ export class MenuBar extends Disposable {
|
||||
menuHolder.style.right = `${this.container.clientWidth}px`;
|
||||
menuHolder.style.left = 'auto';
|
||||
} else {
|
||||
menuHolder.style.top = `${this.container.clientHeight}px`;
|
||||
menuHolder.style.top = `${buttonBoundingRect.bottom}px`;
|
||||
menuHolder.style.left = `${buttonBoundingRect.left}px`;
|
||||
}
|
||||
|
||||
|
||||
@@ -85,27 +85,42 @@
|
||||
}
|
||||
|
||||
.monaco-sash.vertical > .orthogonal-drag-handle.start {
|
||||
left: calc(var(--sash-size) / -2);
|
||||
left: calc(var(--sash-size) * -0.5);
|
||||
top: calc(var(--sash-size) * -1);
|
||||
}
|
||||
.monaco-sash.vertical > .orthogonal-drag-handle.end {
|
||||
left: calc(var(--sash-size) / -2);
|
||||
left: calc(var(--sash-size) * -0.5);
|
||||
bottom: calc(var(--sash-size) * -1);
|
||||
}
|
||||
.monaco-sash.horizontal > .orthogonal-drag-handle.start {
|
||||
top: calc(var(--sash-size) / -2);
|
||||
top: calc(var(--sash-size) * -0.5);
|
||||
left: calc(var(--sash-size) * -1);
|
||||
}
|
||||
.monaco-sash.horizontal > .orthogonal-drag-handle.end {
|
||||
top: calc(var(--sash-size) / -2);
|
||||
top: calc(var(--sash-size) * -0.5);
|
||||
right: calc(var(--sash-size) * -1);
|
||||
}
|
||||
|
||||
.monaco-sash {
|
||||
.monaco-sash:before {
|
||||
content: '';
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: background-color 0.1s ease-out;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.monaco-sash.vertical:before {
|
||||
width: var(--sash-hover-size);
|
||||
left: calc(50% - (var(--sash-hover-size) / 2));
|
||||
}
|
||||
|
||||
.monaco-sash.horizontal:before {
|
||||
height: var(--sash-hover-size);
|
||||
top: calc(50% - (var(--sash-hover-size) / 2));
|
||||
}
|
||||
|
||||
/** Debug **/
|
||||
|
||||
.monaco-sash.debug {
|
||||
|
||||
@@ -81,6 +81,13 @@ export function setGlobalSashSize(size: number): void {
|
||||
onDidChangeGlobalSize.fire(size);
|
||||
}
|
||||
|
||||
let globalHoverDelay = 300;
|
||||
const onDidChangeHoverDelay = new Emitter<number>();
|
||||
export function setGlobalHoverDelay(size: number): void {
|
||||
globalHoverDelay = size;
|
||||
onDidChangeHoverDelay.fire(size);
|
||||
}
|
||||
|
||||
export class Sash extends Disposable {
|
||||
|
||||
private el: HTMLElement;
|
||||
@@ -88,7 +95,8 @@ export class Sash extends Disposable {
|
||||
private hidden: boolean;
|
||||
private orientation!: Orientation;
|
||||
private size: number;
|
||||
private hoverDelayer = this._register(new Delayer(300));
|
||||
private hoverDelay = globalHoverDelay;
|
||||
private hoverDelayer = this._register(new Delayer(this.hoverDelay));
|
||||
|
||||
private _state: SashState = SashState.Enabled;
|
||||
get state(): SashState { return this._state; }
|
||||
@@ -221,6 +229,8 @@ export class Sash extends Disposable {
|
||||
}));
|
||||
}
|
||||
|
||||
this._register(onDidChangeHoverDelay.event(delay => this.hoverDelay = delay));
|
||||
|
||||
this.hidden = false;
|
||||
this.layoutProvider = layoutProvider;
|
||||
|
||||
@@ -403,7 +413,7 @@ export class Sash extends Disposable {
|
||||
sash.hoverDelayer.cancel();
|
||||
sash.el.classList.add('hover');
|
||||
} else {
|
||||
sash.hoverDelayer.trigger(() => sash.el.classList.add('hover'));
|
||||
sash.hoverDelayer.trigger(() => sash.el.classList.add('hover'), sash.hoverDelay).then(undefined, () => { });
|
||||
}
|
||||
|
||||
if (!fromLinkedSash && sash.linkedSash) {
|
||||
|
||||
@@ -29,6 +29,7 @@ export interface ISelectBoxDelegate extends IDisposable {
|
||||
setAriaLabel(label: string): void;
|
||||
focus(): void;
|
||||
blur(): void;
|
||||
setFocusable(focus: boolean): void;
|
||||
|
||||
// Delegated Widget interface
|
||||
render(container: HTMLElement): void;
|
||||
@@ -93,41 +94,43 @@ export class SelectBox extends Widget implements ISelectBoxDelegate {
|
||||
|
||||
// Public SelectBox Methods - routed through delegate interface
|
||||
|
||||
public get onDidSelect(): Event<ISelectData> {
|
||||
get onDidSelect(): Event<ISelectData> {
|
||||
return this.selectBoxDelegate.onDidSelect;
|
||||
}
|
||||
|
||||
public setOptions(options: ISelectOptionItem[], selected?: number): void {
|
||||
setOptions(options: ISelectOptionItem[], selected?: number): void {
|
||||
this.selectBoxDelegate.setOptions(options, selected);
|
||||
}
|
||||
|
||||
public select(index: number): void {
|
||||
select(index: number): void {
|
||||
this.selectBoxDelegate.select(index);
|
||||
}
|
||||
|
||||
public setAriaLabel(label: string): void {
|
||||
setAriaLabel(label: string): void {
|
||||
this.selectBoxDelegate.setAriaLabel(label);
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
focus(): void {
|
||||
this.selectBoxDelegate.focus();
|
||||
}
|
||||
|
||||
public blur(): void {
|
||||
blur(): void {
|
||||
this.selectBoxDelegate.blur();
|
||||
}
|
||||
|
||||
// Public Widget Methods - routed through delegate interface
|
||||
setFocusable(focusable: boolean): void {
|
||||
this.selectBoxDelegate.setFocusable(focusable);
|
||||
}
|
||||
|
||||
public render(container: HTMLElement): void {
|
||||
render(container: HTMLElement): void {
|
||||
this.selectBoxDelegate.render(container);
|
||||
}
|
||||
|
||||
public style(styles: ISelectBoxStyles): void {
|
||||
style(styles: ISelectBoxStyles): void {
|
||||
this.selectBoxDelegate.style(styles);
|
||||
}
|
||||
|
||||
public applyStyles(): void {
|
||||
applyStyles(): void {
|
||||
this.selectBoxDelegate.applyStyles();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,16 +293,22 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
|
||||
|
||||
public focus(): void {
|
||||
if (this.selectElement) {
|
||||
this.selectElement.tabIndex = 0;
|
||||
this.selectElement.focus();
|
||||
}
|
||||
}
|
||||
|
||||
public blur(): void {
|
||||
if (this.selectElement) {
|
||||
this.selectElement.tabIndex = -1;
|
||||
this.selectElement.blur();
|
||||
}
|
||||
}
|
||||
|
||||
public setFocusable(focusable: boolean): void {
|
||||
this.selectElement.tabIndex = focusable ? 0 : -1;
|
||||
}
|
||||
|
||||
public render(container: HTMLElement): void {
|
||||
this.container = container;
|
||||
container.classList.add('select-container');
|
||||
|
||||
@@ -132,16 +132,22 @@ export class SelectBoxNative extends Disposable implements ISelectBoxDelegate {
|
||||
|
||||
public focus(): void {
|
||||
if (this.selectElement) {
|
||||
this.selectElement.tabIndex = 0;
|
||||
this.selectElement.focus();
|
||||
}
|
||||
}
|
||||
|
||||
public blur(): void {
|
||||
if (this.selectElement) {
|
||||
this.selectElement.tabIndex = -1;
|
||||
this.selectElement.blur();
|
||||
}
|
||||
}
|
||||
|
||||
public setFocusable(focusable: boolean): void {
|
||||
this.selectElement.tabIndex = focusable ? 0 : -1;
|
||||
}
|
||||
|
||||
public render(container: HTMLElement): void {
|
||||
container.classList.add('select-container');
|
||||
container.appendChild(this.selectElement);
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: inherit;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.monaco-pane-view .pane > .pane-header .monaco-action-bar .action-item.select-container {
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
.monaco-table-tr {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-table-th {
|
||||
@@ -35,18 +36,12 @@
|
||||
.monaco-table-th,
|
||||
.monaco-table-td {
|
||||
box-sizing: border-box;
|
||||
padding-left: 10px;
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.monaco-table-th[data-col-index="0"],
|
||||
.monaco-table-td[data-col-index="0"] {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.monaco-table > .monaco-split-view2 .monaco-sash.vertical::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
|
||||
@@ -250,7 +250,10 @@ export class Table<TRow> implements ISpliceable<TRow>, IThemable, IDisposable {
|
||||
|
||||
this.cachedHeight = height;
|
||||
this.splitview.layout(width);
|
||||
this.list.layout(height - this.virtualDelegate.headerRowHeight, width);
|
||||
|
||||
const listHeight = height - this.virtualDelegate.headerRowHeight;
|
||||
this.list.getHTMLElement().style.height = `${listHeight}px`;
|
||||
this.list.layout(listHeight, width);
|
||||
}
|
||||
|
||||
toggleKeyboardNavigation(): void {
|
||||
@@ -273,6 +276,14 @@ export class Table<TRow> implements ISpliceable<TRow>, IThemable, IDisposable {
|
||||
this.list.domFocus();
|
||||
}
|
||||
|
||||
setAnchor(index: number | undefined): void {
|
||||
this.list.setAnchor(index);
|
||||
}
|
||||
|
||||
getAnchor(): number | undefined {
|
||||
return this.list.getAnchor();
|
||||
}
|
||||
|
||||
getSelectedElements(): TRow[] {
|
||||
return this.list.getSelectedElements();
|
||||
}
|
||||
@@ -297,12 +308,12 @@ export class Table<TRow> implements ISpliceable<TRow>, IThemable, IDisposable {
|
||||
this.list.focusPrevious(n, loop, browserEvent);
|
||||
}
|
||||
|
||||
focusNextPage(browserEvent?: UIEvent): void {
|
||||
this.list.focusNextPage(browserEvent);
|
||||
focusNextPage(browserEvent?: UIEvent): Promise<void> {
|
||||
return this.list.focusNextPage(browserEvent);
|
||||
}
|
||||
|
||||
focusPreviousPage(browserEvent?: UIEvent): void {
|
||||
this.list.focusPreviousPage(browserEvent);
|
||||
focusPreviousPage(browserEvent?: UIEvent): Promise<void> {
|
||||
return this.list.focusPreviousPage(browserEvent);
|
||||
}
|
||||
|
||||
focusFirst(browserEvent?: UIEvent): void {
|
||||
@@ -317,6 +328,10 @@ export class Table<TRow> implements ISpliceable<TRow>, IThemable, IDisposable {
|
||||
return this.list.getFocus();
|
||||
}
|
||||
|
||||
getFocusedElements(): TRow[] {
|
||||
return this.list.getFocusedElements();
|
||||
}
|
||||
|
||||
reveal(index: number, relativeTop?: number): void {
|
||||
this.list.reveal(index, relativeTop);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { ITreeModel, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeFilter, ITreeNavigator, ICollapseStateChangeEvent, ITreeDragAndDrop, TreeDragOverBubble, TreeVisibility, TreeFilterResult, ITreeModelSpliceEvent, TreeMouseEventTarget } from 'vs/base/browser/ui/tree/tree';
|
||||
import { ISpliceable } from 'vs/base/common/sequence';
|
||||
import { IDragAndDropData, StaticDND, DragAndDropData } from 'vs/base/browser/dnd';
|
||||
import { range, equals, distinctES6 } from 'vs/base/common/arrays';
|
||||
import { range, equals, distinctES6, firstOrDefault } from 'vs/base/common/arrays';
|
||||
import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { fuzzyScore, FuzzyScore } from 'vs/base/common/filters';
|
||||
@@ -683,6 +683,7 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
|
||||
if (typeof options.filterOnType !== 'undefined') {
|
||||
this._filterOnType = !!options.filterOnType;
|
||||
this.filterOnTypeDomNode.checked = this._filterOnType;
|
||||
this.updateFilterOnTypeTitleAndIcon();
|
||||
}
|
||||
|
||||
if (typeof options.automaticKeyboardNavigation !== 'undefined') {
|
||||
@@ -1168,6 +1169,7 @@ class TreeNodeList<T, TFilterData, TRef> extends List<ITreeNode<T, TFilterData>>
|
||||
renderers: IListRenderer<any /* TODO@joao */, any>[],
|
||||
private focusTrait: Trait<T>,
|
||||
private selectionTrait: Trait<T>,
|
||||
private anchorTrait: Trait<T>,
|
||||
options: ITreeNodeListOptions<T, TFilterData, TRef>
|
||||
) {
|
||||
super(user, container, virtualDelegate, renderers, options);
|
||||
@@ -1186,6 +1188,7 @@ class TreeNodeList<T, TFilterData, TRef> extends List<ITreeNode<T, TFilterData>>
|
||||
|
||||
const additionalFocus: number[] = [];
|
||||
const additionalSelection: number[] = [];
|
||||
let anchor: number | undefined;
|
||||
|
||||
elements.forEach((node, index) => {
|
||||
if (this.focusTrait.has(node)) {
|
||||
@@ -1195,6 +1198,10 @@ class TreeNodeList<T, TFilterData, TRef> extends List<ITreeNode<T, TFilterData>>
|
||||
if (this.selectionTrait.has(node)) {
|
||||
additionalSelection.push(start + index);
|
||||
}
|
||||
|
||||
if (this.anchorTrait.has(node)) {
|
||||
anchor = start + index;
|
||||
}
|
||||
});
|
||||
|
||||
if (additionalFocus.length > 0) {
|
||||
@@ -1204,6 +1211,10 @@ class TreeNodeList<T, TFilterData, TRef> extends List<ITreeNode<T, TFilterData>>
|
||||
if (additionalSelection.length > 0) {
|
||||
super.setSelection(distinctES6([...super.getSelection(), ...additionalSelection]));
|
||||
}
|
||||
|
||||
if (typeof anchor === 'number') {
|
||||
super.setAnchor(anchor);
|
||||
}
|
||||
}
|
||||
|
||||
setFocus(indexes: number[], browserEvent?: UIEvent, fromAPI = false): void {
|
||||
@@ -1221,6 +1232,18 @@ class TreeNodeList<T, TFilterData, TRef> extends List<ITreeNode<T, TFilterData>>
|
||||
this.selectionTrait.set(indexes.map(i => this.element(i)), browserEvent);
|
||||
}
|
||||
}
|
||||
|
||||
setAnchor(index: number | undefined, fromAPI = false): void {
|
||||
super.setAnchor(index);
|
||||
|
||||
if (!fromAPI) {
|
||||
if (typeof index === 'undefined') {
|
||||
this.anchorTrait.set([]);
|
||||
} else {
|
||||
this.anchorTrait.set([this.element(index)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable {
|
||||
@@ -1230,6 +1253,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
|
||||
protected model: ITreeModel<T, TFilterData, TRef>;
|
||||
private focus: Trait<T>;
|
||||
private selection: Trait<T>;
|
||||
private anchor: Trait<T>;
|
||||
private eventBufferer = new EventBufferer();
|
||||
private typeFilterController?: TypeFilterController<T, TFilterData>;
|
||||
private focusNavigationFilter: ((node: ITreeNode<T, TFilterData>) => boolean) | undefined;
|
||||
@@ -1298,7 +1322,8 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
|
||||
|
||||
this.focus = new Trait(_options.identityProvider);
|
||||
this.selection = new Trait(_options.identityProvider);
|
||||
this.view = new TreeNodeList(user, container, treeDelegate, this.renderers, this.focus, this.selection, { ...asListOptions(() => this.model, _options), tree: this });
|
||||
this.anchor = new Trait(_options.identityProvider);
|
||||
this.view = new TreeNodeList(user, container, treeDelegate, this.renderers, this.focus, this.selection, this.anchor, { ...asListOptions(() => this.model, _options), tree: this });
|
||||
|
||||
this.model = this.createModel(user, this.view, _options);
|
||||
onDidChangeCollapseStateRelay.input = this.model.onDidChangeCollapseState;
|
||||
@@ -1552,6 +1577,25 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
|
||||
this.model.refilter();
|
||||
}
|
||||
|
||||
setAnchor(element: TRef | undefined): void {
|
||||
if (typeof element === 'undefined') {
|
||||
return this.view.setAnchor(undefined);
|
||||
}
|
||||
|
||||
const node = this.model.getNode(element);
|
||||
this.anchor.set([node]);
|
||||
|
||||
const index = this.model.getListIndex(element);
|
||||
|
||||
if (index > -1) {
|
||||
this.view.setAnchor(index, true);
|
||||
}
|
||||
}
|
||||
|
||||
getAnchor(): T | undefined {
|
||||
return firstOrDefault(this.anchor.get(), undefined);
|
||||
}
|
||||
|
||||
setSelection(elements: TRef[], browserEvent?: UIEvent): void {
|
||||
const nodes = elements.map(e => this.model.getNode(e));
|
||||
this.selection.set(nodes, browserEvent);
|
||||
@@ -1580,12 +1624,12 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
|
||||
this.view.focusPrevious(n, loop, browserEvent, filter);
|
||||
}
|
||||
|
||||
focusNextPage(browserEvent?: UIEvent, filter = this.focusNavigationFilter): void {
|
||||
this.view.focusNextPage(browserEvent, filter);
|
||||
focusNextPage(browserEvent?: UIEvent, filter = this.focusNavigationFilter): Promise<void> {
|
||||
return this.view.focusNextPage(browserEvent, filter);
|
||||
}
|
||||
|
||||
focusPreviousPage(browserEvent?: UIEvent, filter = this.focusNavigationFilter): void {
|
||||
this.view.focusPreviousPage(browserEvent, filter);
|
||||
focusPreviousPage(browserEvent?: UIEvent, filter = this.focusNavigationFilter): Promise<void> {
|
||||
return this.view.focusPreviousPage(browserEvent, filter);
|
||||
}
|
||||
|
||||
focusLast(browserEvent?: UIEvent, filter = this.focusNavigationFilter): void {
|
||||
|
||||
@@ -616,7 +616,7 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
|
||||
return this.tree.isCollapsible(this.getDataNode(element));
|
||||
}
|
||||
|
||||
isCollapsed(element: T): boolean {
|
||||
isCollapsed(element: TInput | T): boolean {
|
||||
return this.tree.isCollapsed(this.getDataNode(element));
|
||||
}
|
||||
|
||||
@@ -628,6 +628,15 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
|
||||
this.tree.refilter();
|
||||
}
|
||||
|
||||
setAnchor(element: T | undefined): void {
|
||||
this.tree.setAnchor(typeof element === 'undefined' ? undefined : this.getDataNode(element));
|
||||
}
|
||||
|
||||
getAnchor(): T | undefined {
|
||||
const node = this.tree.getAnchor();
|
||||
return node?.element as T;
|
||||
}
|
||||
|
||||
setSelection(elements: T[], browserEvent?: UIEvent): void {
|
||||
const nodes = elements.map(e => this.getDataNode(e));
|
||||
this.tree.setSelection(nodes, browserEvent);
|
||||
@@ -651,12 +660,12 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
|
||||
this.tree.focusPrevious(n, loop, browserEvent);
|
||||
}
|
||||
|
||||
focusNextPage(browserEvent?: UIEvent): void {
|
||||
this.tree.focusNextPage(browserEvent);
|
||||
focusNextPage(browserEvent?: UIEvent): Promise<void> {
|
||||
return this.tree.focusNextPage(browserEvent);
|
||||
}
|
||||
|
||||
focusPreviousPage(browserEvent?: UIEvent): void {
|
||||
this.tree.focusPreviousPage(browserEvent);
|
||||
focusPreviousPage(browserEvent?: UIEvent): Promise<void> {
|
||||
return this.tree.focusPreviousPage(browserEvent);
|
||||
}
|
||||
|
||||
focusLast(browserEvent?: UIEvent): void {
|
||||
|
||||
@@ -8,7 +8,6 @@ import { IndexTreeModel, IIndexTreeModelOptions, IList, IIndexTreeModelSpliceOpt
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { ITreeModel, ITreeNode, ITreeElement, ITreeSorter, ICollapseStateChangeEvent, ITreeModelSpliceEvent, TreeError } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IIdentityProvider } from 'vs/base/browser/ui/list/list';
|
||||
import { mergeSort } from 'vs/base/common/arrays';
|
||||
|
||||
export type ITreeNodeCallback<T, TFilterData> = (node: ITreeNode<T, TFilterData>) => void;
|
||||
|
||||
@@ -130,7 +129,7 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
||||
|
||||
private preserveCollapseState(elements: Iterable<ITreeElement<T>> = Iterable.empty()): Iterable<ITreeElement<T>> {
|
||||
if (this.sorter) {
|
||||
elements = mergeSort([...elements], this.sorter.compare.bind(this.sorter));
|
||||
elements = [...elements].sort(this.sorter.compare.bind(this.sorter));
|
||||
}
|
||||
|
||||
return Iterable.map(elements, treeElement => {
|
||||
@@ -185,7 +184,7 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
||||
let childrenNodes = [...node.children] as ITreeNode<T, TFilterData>[];
|
||||
|
||||
if (recursive || first) {
|
||||
childrenNodes = mergeSort(childrenNodes, this.sorter!.compare.bind(this.sorter));
|
||||
childrenNodes = childrenNodes.sort(this.sorter!.compare.bind(this.sorter));
|
||||
}
|
||||
|
||||
return Iterable.map<ITreeNode<T | null, TFilterData>, ITreeElement<T>>(childrenNodes, node => ({
|
||||
|
||||
Reference in New Issue
Block a user