mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-04 17:23:45 -05:00
Remove custom splitview (#3467)
* working on options dialog * working through options dialog * trying to work through modifying options dialog * working on converting scrollablesplitview * fixed options working through profiler * fix profiler * fix account dialog * trying to fix problems with splitpanel * fix insights dialog * moving through * fix last list, need to verify looks and functionality * fix look of account dialog * formatting * formatting * working through scrollable bugs * working on problem with view size * fix margin issues * fix styler for dialogs * add panel styles to insights * create instantiation issues * fix test * fix test * remove unused code * formatting * working through insight dialog issues * fix table updating * remove console logs
This commit is contained in:
@@ -414,17 +414,17 @@ export abstract class Modal extends Disposable implements IThemable {
|
||||
}
|
||||
});
|
||||
this._resizeListener = DOM.addDisposableListener(window, DOM.EventType.RESIZE, (e: Event) => {
|
||||
this.layout(DOM.getTotalHeight(this._builder.getHTMLElement()));
|
||||
this.layout(DOM.getTotalHeight(this._modalBodySection));
|
||||
});
|
||||
|
||||
this.layout(DOM.getTotalHeight(this._builder.getHTMLElement()));
|
||||
this.layout(DOM.getTotalHeight(this._modalBodySection));
|
||||
TelemetryUtils.addTelemetry(this._telemetryService, TelemetryKeys.ModalDialogOpened, { name: this._name });
|
||||
}
|
||||
|
||||
/**
|
||||
* Required to be implemented so that scrolling and other functions operate correctly. Should re-layout controls in the modal
|
||||
*/
|
||||
protected abstract layout(height?: number): void;
|
||||
protected abstract layout(height: number): void;
|
||||
|
||||
/**
|
||||
* Hides the modal and removes key listeners
|
||||
|
||||
@@ -6,19 +6,20 @@
|
||||
'use strict';
|
||||
|
||||
import 'vs/css!./media/optionsDialog';
|
||||
import { Button } from 'sql/base/browser/ui/button/button';
|
||||
import { FixedCollapsibleView } from 'sql/platform/views/fixedCollapsibleView';
|
||||
import * as DialogHelper from './dialogHelper';
|
||||
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox';
|
||||
import { IModalOptions, Modal } from './modal';
|
||||
import * as OptionsDialogHelper from './optionsDialogHelper';
|
||||
import { attachButtonStyler, attachModalDialogStyler } from 'sql/common/theme/styler';
|
||||
import { attachButtonStyler, attachModalDialogStyler, attachPanelStyler } from 'sql/common/theme/styler';
|
||||
import { ServiceOptionType } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
import { ScrollableSplitView } from 'sql/base/browser/ui/scrollableSplitview/scrollableSplitview';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
@@ -26,58 +27,56 @@ import { IWorkbenchThemeService, IColorTheme } from 'vs/workbench/services/theme
|
||||
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import * as styler from 'vs/platform/theme/common/styler';
|
||||
import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { SplitView, CollapsibleState } from 'sql/base/browser/ui/splitview/splitview';
|
||||
import { Builder, $ } from 'vs/base/browser/builder';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import { ServiceOptionType } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { IViewletPanelOptions, ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
export class CategoryView extends FixedCollapsibleView {
|
||||
private _treecontainer: HTMLElement;
|
||||
private _collapsed: CollapsibleState;
|
||||
export class CategoryView extends ViewletPanel {
|
||||
|
||||
constructor(private viewTitle: string, private _bodyContainer: HTMLElement, collapsed: boolean, initialBodySize: number, headerSize: number) {
|
||||
super(
|
||||
initialBodySize,
|
||||
{
|
||||
expandedBodySize: initialBodySize,
|
||||
sizing: headerSize,
|
||||
initialState: collapsed ? CollapsibleState.COLLAPSED : CollapsibleState.EXPANDED,
|
||||
ariaHeaderLabel: viewTitle
|
||||
});
|
||||
this._collapsed = collapsed ? CollapsibleState.COLLAPSED : CollapsibleState.EXPANDED;
|
||||
constructor(
|
||||
private contentElement: HTMLElement,
|
||||
private size: number,
|
||||
options: IViewletPanelOptions,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IConfigurationService configurationService: IConfigurationService
|
||||
) {
|
||||
super(options, keybindingService, contextMenuService, configurationService);
|
||||
}
|
||||
|
||||
public renderHeader(container: HTMLElement): void {
|
||||
const titleDiv = $('div.title').appendTo(container);
|
||||
$('span').text(this.viewTitle).appendTo(titleDiv);
|
||||
// we want a fixed size, so when we render to will measure our content and set that to be our
|
||||
// minimum and max size
|
||||
protected renderBody(container: HTMLElement): void {
|
||||
container.appendChild(this.contentElement);
|
||||
this.maximumBodySize = this.size;
|
||||
this.minimumBodySize = this.size;
|
||||
}
|
||||
|
||||
public renderBody(container: HTMLElement): void {
|
||||
this._treecontainer = document.createElement('div');
|
||||
container.appendChild(this._treecontainer);
|
||||
this._treecontainer.appendChild(this._bodyContainer);
|
||||
this.changeState(this._collapsed);
|
||||
protected layoutBody(size: number): void {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
public layoutBody(size: number): void {
|
||||
this._treecontainer.style.height = size + 'px';
|
||||
}
|
||||
export interface IOptionsDialogOptions extends IModalOptions {
|
||||
cancelLabel?: string;
|
||||
}
|
||||
|
||||
export class OptionsDialog extends Modal {
|
||||
private _body: HTMLElement;
|
||||
private _optionGroups: HTMLElement;
|
||||
private _dividerBuilder: Builder;
|
||||
private _okButton: Button;
|
||||
private _closeButton: Button;
|
||||
private _optionTitle: Builder;
|
||||
private _optionDescription: Builder;
|
||||
private _optionElements: { [optionName: string]: OptionsDialogHelper.IOptionElement } = {};
|
||||
private _optionValues: { [optionName: string]: string };
|
||||
private _optionRowSize = 31;
|
||||
private _optionCategoryPadding = 30;
|
||||
private _categoryHeaderSize = 22;
|
||||
private height: number;
|
||||
private splitview: ScrollableSplitView;
|
||||
|
||||
private _onOk = new Emitter<void>();
|
||||
public onOk: Event<void> = this._onOk.event;
|
||||
@@ -85,16 +84,14 @@ export class OptionsDialog extends Modal {
|
||||
private _onCloseEvent = new Emitter<void>();
|
||||
public onCloseEvent: Event<void> = this._onCloseEvent.event;
|
||||
|
||||
public okLabel: string = localize('optionsDialog.ok', 'OK');
|
||||
public cancelLabel: string = localize('optionsDialog.cancel', 'Cancel');
|
||||
|
||||
constructor(
|
||||
title: string,
|
||||
name: string,
|
||||
options: IModalOptions,
|
||||
private options: IOptionsDialogOptions,
|
||||
@IPartService partService: IPartService,
|
||||
@IWorkbenchThemeService private _workbenchThemeService: IWorkbenchThemeService,
|
||||
@IContextViewService private _contextViewService: IContextViewService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IClipboardService clipboardService: IClipboardService
|
||||
@@ -109,14 +106,13 @@ export class OptionsDialog extends Modal {
|
||||
this.backButton.onDidClick(() => this.cancel());
|
||||
attachButtonStyler(this.backButton, this._themeService, { buttonBackground: SIDE_BAR_BACKGROUND, buttonHoverBackground: SIDE_BAR_BACKGROUND });
|
||||
}
|
||||
this._okButton = this.addFooterButton(this.okLabel, () => this.ok());
|
||||
this._closeButton = this.addFooterButton(this.cancelLabel, () => this.cancel());
|
||||
let okButton = this.addFooterButton(localize('optionsDialog.ok', 'OK'), () => this.ok());
|
||||
let closeButton = this.addFooterButton(this.options.cancelLabel || localize('optionsDialog.cancel', 'Cancel'), () => this.cancel());
|
||||
// Theme styler
|
||||
attachButtonStyler(this._okButton, this._themeService);
|
||||
attachButtonStyler(this._closeButton, this._themeService);
|
||||
let self = this;
|
||||
this._register(self._workbenchThemeService.onDidColorThemeChange(e => self.updateTheme(e)));
|
||||
self.updateTheme(self._workbenchThemeService.getColorTheme());
|
||||
attachButtonStyler(okButton, this._themeService);
|
||||
attachButtonStyler(closeButton, this._themeService);
|
||||
this._register(this._workbenchThemeService.onDidColorThemeChange(e => this.updateTheme(e)));
|
||||
this.updateTheme(this._workbenchThemeService.getColorTheme());
|
||||
}
|
||||
|
||||
protected renderBody(container: HTMLElement) {
|
||||
@@ -151,24 +147,24 @@ export class OptionsDialog extends Modal {
|
||||
}
|
||||
|
||||
private onOptionLinkClicked(optionName: string): void {
|
||||
var option = this._optionElements[optionName].option;
|
||||
let option = this._optionElements[optionName].option;
|
||||
this._optionTitle.text(option.displayName);
|
||||
this._optionDescription.text(option.description);
|
||||
}
|
||||
|
||||
private fillInOptions(container: Builder, options: sqlops.ServiceOption[]): void {
|
||||
for (var i = 0; i < options.length; i++) {
|
||||
var option: sqlops.ServiceOption = options[i];
|
||||
var rowContainer = DialogHelper.appendRow(container, option.displayName, 'optionsDialog-label', 'optionsDialog-input');
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
let option: sqlops.ServiceOption = options[i];
|
||||
let rowContainer = DialogHelper.appendRow(container, option.displayName, 'optionsDialog-label', 'optionsDialog-input');
|
||||
OptionsDialogHelper.createOptionElement(option, rowContainer, this._optionValues, this._optionElements, this._contextViewService, (name) => this.onOptionLinkClicked(name));
|
||||
}
|
||||
}
|
||||
|
||||
private registerStyling(): void {
|
||||
// Theme styler
|
||||
for (var optionName in this._optionElements) {
|
||||
var widget: Widget = this._optionElements[optionName].optionWidget;
|
||||
var option = this._optionElements[optionName].option;
|
||||
for (let optionName in this._optionElements) {
|
||||
let widget: Widget = this._optionElements[optionName].optionWidget;
|
||||
let option = this._optionElements[optionName].option;
|
||||
switch (option.valueType) {
|
||||
case ServiceOptionType.category:
|
||||
case ServiceOptionType.boolean:
|
||||
@@ -225,47 +221,51 @@ export class OptionsDialog extends Modal {
|
||||
|
||||
public open(options: sqlops.ServiceOption[], optionValues: { [name: string]: any }) {
|
||||
this._optionValues = optionValues;
|
||||
var firstOption: string;
|
||||
var containerGroup: Builder;
|
||||
var layoutSize = 0;
|
||||
var optionsContentBuilder: Builder = $().div({ class: 'optionsDialog-options-groups' }, (container) => {
|
||||
let firstOption: string;
|
||||
let containerGroup: Builder;
|
||||
let optionsContentBuilder: Builder = $().div({ class: 'optionsDialog-options-groups monaco-panel-view' }, (container) => {
|
||||
containerGroup = container;
|
||||
this._optionGroups = container.getHTMLElement();
|
||||
});
|
||||
var splitview = new SplitView(containerGroup.getHTMLElement());
|
||||
this.splitview = new ScrollableSplitView(containerGroup.getHTMLElement(), { enableResizing: false, scrollDebounce: 0 });
|
||||
let categoryMap = OptionsDialogHelper.groupOptionsByCategory(options);
|
||||
for (var category in categoryMap) {
|
||||
var serviceOptions: sqlops.ServiceOption[] = categoryMap[category];
|
||||
var bodyContainer = $().element('table', { class: 'optionsDialog-table' }, (tableContainer: Builder) => {
|
||||
for (let category in categoryMap) {
|
||||
let serviceOptions: sqlops.ServiceOption[] = categoryMap[category];
|
||||
let bodyContainer = $().element('table', { class: 'optionsDialog-table' }, (tableContainer: Builder) => {
|
||||
this.fillInOptions(tableContainer, serviceOptions);
|
||||
});
|
||||
|
||||
var viewSize = this._optionCategoryPadding + serviceOptions.length * this._optionRowSize;
|
||||
layoutSize += (viewSize + this._categoryHeaderSize);
|
||||
var categoryView = new CategoryView(category, bodyContainer.getHTMLElement(), false, viewSize, this._categoryHeaderSize);
|
||||
splitview.addView(categoryView);
|
||||
let viewSize = this._optionCategoryPadding + serviceOptions.length * this._optionRowSize;
|
||||
let categoryView = this._instantiationService.createInstance(CategoryView, bodyContainer.getHTMLElement(), viewSize, { title: category, ariaHeaderLabel: category, id: category });
|
||||
this.splitview.addView(categoryView, viewSize);
|
||||
categoryView.render();
|
||||
attachPanelStyler(categoryView, this._themeService);
|
||||
|
||||
if (!firstOption) {
|
||||
firstOption = serviceOptions[0].name;
|
||||
}
|
||||
}
|
||||
splitview.layout(layoutSize);
|
||||
if (this.height) {
|
||||
this.splitview.layout(this.height - 120);
|
||||
}
|
||||
let body = new Builder(this._body);
|
||||
body.append(optionsContentBuilder.getHTMLElement(), 0);
|
||||
this.show();
|
||||
var firstOptionWidget = this._optionElements[firstOption].optionWidget;
|
||||
let firstOptionWidget = this._optionElements[firstOption].optionWidget;
|
||||
this.registerStyling();
|
||||
firstOptionWidget.focus();
|
||||
}
|
||||
|
||||
protected layout(height?: number): void {
|
||||
// Nothing currently laid out in this class
|
||||
this.height = height;
|
||||
// account for padding and the details view
|
||||
this.splitview.layout(this.height - 120 - 20);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
for (var optionName in this._optionElements) {
|
||||
var widget: Widget = this._optionElements[optionName].optionWidget;
|
||||
for (let optionName in this._optionElements) {
|
||||
let widget: Widget = this._optionElements[optionName].optionWidget;
|
||||
widget.dispose();
|
||||
delete this._optionElements[optionName];
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { INextIterator } from 'vs/base/common/iterator';
|
||||
|
||||
export interface IView {
|
||||
id: string;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
export interface IViewItem {
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-scroll-split-view {
|
||||
.split-view-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.monaco-scroll-split-view {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
@@ -6,35 +6,49 @@
|
||||
'use strict';
|
||||
|
||||
import 'vs/css!./scrollableSplitview';
|
||||
import { HeightMap, IView as HeightIView, IViewItem as HeightIViewItem } from './heightMap';
|
||||
|
||||
import { IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { mapEvent, Emitter, Event, debounceEvent } from 'vs/base/common/event';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { clamp } from 'vs/base/common/numbers';
|
||||
import { range, firstIndex } from 'vs/base/common/arrays';
|
||||
import { range, firstIndex, pushToStart } from 'vs/base/common/arrays';
|
||||
import { Sash, Orientation, ISashEvent as IBaseSashEvent } from 'vs/base/browser/ui/sash/sash';
|
||||
import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import { HeightMap, IView as HeightIView, IViewItem as HeightIViewItem } from './heightMap';
|
||||
import { ArrayIterator } from 'vs/base/common/iterator';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { ISplitViewStyles, Sizing } from 'vs/base/browser/ui/splitview/splitview';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
export { Orientation } from 'vs/base/browser/ui/sash/sash';
|
||||
|
||||
export interface ISplitViewOptions {
|
||||
orientation?: Orientation; // default Orientation.VERTICAL
|
||||
styles?: ISplitViewStyles;
|
||||
orthogonalStartSash?: Sash;
|
||||
orthogonalEndSash?: Sash;
|
||||
inverseAltBehavior?: boolean;
|
||||
enableResizing?: boolean;
|
||||
scrollDebounce?: number;
|
||||
verticalScrollbarVisibility?: ScrollbarVisibility;
|
||||
}
|
||||
|
||||
const defaultStyles: ISplitViewStyles = {
|
||||
separatorBorder: Color.transparent
|
||||
};
|
||||
|
||||
const defaultOptions: ISplitViewOptions = {
|
||||
enableResizing: true
|
||||
};
|
||||
|
||||
export interface IView extends HeightIView {
|
||||
readonly element: HTMLElement;
|
||||
readonly minimumSize: number;
|
||||
readonly maximumSize: number;
|
||||
readonly onDidChange: Event<number | undefined>;
|
||||
render(container: HTMLElement, orientation: Orientation): void;
|
||||
layout(size: number, orientation: Orientation): void;
|
||||
onAdd?(): void;
|
||||
onRemove?(): void;
|
||||
@@ -44,6 +58,7 @@ interface ISashEvent {
|
||||
sash: Sash;
|
||||
start: number;
|
||||
current: number;
|
||||
alt: boolean;
|
||||
}
|
||||
|
||||
interface IViewItem extends HeightIViewItem {
|
||||
@@ -64,7 +79,12 @@ interface ISashItem {
|
||||
interface ISashDragState {
|
||||
index: number;
|
||||
start: number;
|
||||
current: number;
|
||||
sizes: number[];
|
||||
minDelta: number;
|
||||
maxDelta: number;
|
||||
alt: boolean;
|
||||
disposable: IDisposable;
|
||||
}
|
||||
|
||||
enum State {
|
||||
@@ -95,24 +115,28 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
||||
|
||||
private orientation: Orientation;
|
||||
private el: HTMLElement;
|
||||
private sashContainer: HTMLElement;
|
||||
private viewContainer: HTMLElement;
|
||||
private scrollable: ScrollableElement;
|
||||
private size = 0;
|
||||
private contentSize = 0;
|
||||
private proportions: undefined | number[] = undefined;
|
||||
private viewItems: IViewItem[] = [];
|
||||
private sashItems: ISashItem[] = [];
|
||||
private sashDragState: ISashDragState;
|
||||
private state: State = State.Idle;
|
||||
private scrollable: ScrollableElement;
|
||||
private inverseAltBehavior: boolean;
|
||||
|
||||
private lastRenderHeight: number;
|
||||
private lastRenderTop: number;
|
||||
|
||||
private options: ISplitViewOptions;
|
||||
|
||||
private dirtyState = false;
|
||||
|
||||
private lastRenderTop: number;
|
||||
private lastRenderHeight: number;
|
||||
|
||||
private _onDidSashChange = new Emitter<void>();
|
||||
private _onDidSashChange = new Emitter<number>();
|
||||
readonly onDidSashChange = this._onDidSashChange.event;
|
||||
private _onDidSashReset = new Emitter<void>();
|
||||
private _onDidSashReset = new Emitter<number>();
|
||||
readonly onDidSashReset = this._onDidSashReset.event;
|
||||
|
||||
private _onScroll = new Emitter<number>();
|
||||
@@ -122,15 +146,48 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
||||
return this.viewItems.length;
|
||||
}
|
||||
|
||||
get minimumSize(): number {
|
||||
return this.viewItems.reduce((r, item) => r + item.view.minimumSize, 0);
|
||||
}
|
||||
|
||||
get maximumSize(): number {
|
||||
return this.length === 0 ? Number.POSITIVE_INFINITY : this.viewItems.reduce((r, item) => r + item.view.maximumSize, 0);
|
||||
}
|
||||
|
||||
private _orthogonalStartSash: Sash | undefined;
|
||||
get orthogonalStartSash(): Sash | undefined { return this._orthogonalStartSash; }
|
||||
set orthogonalStartSash(sash: Sash | undefined) {
|
||||
for (const sashItem of this.sashItems) {
|
||||
sashItem.sash.orthogonalStartSash = sash;
|
||||
}
|
||||
|
||||
this._orthogonalStartSash = sash;
|
||||
}
|
||||
|
||||
private _orthogonalEndSash: Sash | undefined;
|
||||
get orthogonalEndSash(): Sash | undefined { return this._orthogonalEndSash; }
|
||||
set orthogonalEndSash(sash: Sash | undefined) {
|
||||
for (const sashItem of this.sashItems) {
|
||||
sashItem.sash.orthogonalEndSash = sash;
|
||||
}
|
||||
|
||||
this._orthogonalEndSash = sash;
|
||||
}
|
||||
|
||||
get sashes(): Sash[] {
|
||||
return this.sashItems.map(s => s.sash);
|
||||
}
|
||||
|
||||
constructor(container: HTMLElement, options: ISplitViewOptions = {}) {
|
||||
super();
|
||||
this.orientation = types.isUndefined(options.orientation) ? Orientation.VERTICAL : options.orientation;
|
||||
this.inverseAltBehavior = !!options.inverseAltBehavior;
|
||||
|
||||
this.options = mixin(options, defaultOptions, false);
|
||||
|
||||
this.el = document.createElement('div');
|
||||
this.scrollable = new ScrollableElement(this.el, { vertical: options.verticalScrollbarVisibility });
|
||||
debounceEvent(this.scrollable.onScroll, (l, e) => e, 25)(e => {
|
||||
debounceEvent(this.scrollable.onScroll, (l, e) => e, types.isNumber(this.options.scrollDebounce) ? this.options.scrollDebounce : 25)(e => {
|
||||
this.render(e.scrollTop, e.height);
|
||||
this.relayout();
|
||||
this._onScroll.fire(e.scrollTop);
|
||||
@@ -140,9 +197,24 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
||||
dom.addClass(domNode, 'monaco-split-view2');
|
||||
dom.addClass(domNode, this.orientation === Orientation.VERTICAL ? 'vertical' : 'horizontal');
|
||||
container.appendChild(domNode);
|
||||
|
||||
this.sashContainer = dom.append(this.el, dom.$('.sash-container'));
|
||||
this.viewContainer = dom.append(this.el, dom.$('.split-view-container'));
|
||||
|
||||
this.style(options.styles || defaultStyles);
|
||||
}
|
||||
|
||||
addViews(views: IView[], sizes: number[], index = this.viewItems.length): void {
|
||||
style(styles: ISplitViewStyles): void {
|
||||
if (styles.separatorBorder.isTransparent()) {
|
||||
dom.removeClass(this.el, 'separator-border');
|
||||
this.el.style.removeProperty('--separator-border');
|
||||
} else {
|
||||
dom.addClass(this.el, 'separator-border');
|
||||
this.el.style.setProperty('--separator-border', styles.separatorBorder.toString());
|
||||
}
|
||||
}
|
||||
|
||||
addViews(views: IView[], sizes: number[] | Sizing, index = this.viewItems.length): void {
|
||||
if (this.state !== State.Idle) {
|
||||
throw new Error('Cant modify splitview');
|
||||
}
|
||||
@@ -150,16 +222,23 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
||||
this.state = State.Busy;
|
||||
|
||||
for (let i = 0; i < views.length; i++) {
|
||||
let viewIndex = index + i;
|
||||
let view = views[i], size = sizes[i];
|
||||
|
||||
let size: number | Sizing;
|
||||
if (Array.isArray(sizes)) {
|
||||
size = sizes[i];
|
||||
} else {
|
||||
size = sizes;
|
||||
}
|
||||
const view = views[i];
|
||||
view.id = view.id || generateUuid();
|
||||
// Add view
|
||||
const container = dom.$('.split-view-view');
|
||||
|
||||
// removed default adding of the view directly to the container
|
||||
|
||||
const onChangeDisposable = view.onDidChange(size => this.onViewChange(item, size));
|
||||
const containerDisposable = toDisposable(() => {
|
||||
if (container.parentElement) {
|
||||
this.el.removeChild(container);
|
||||
this.viewContainer.removeChild(container);
|
||||
}
|
||||
this.onRemoveItems(new ArrayIterator([item.view.id]));
|
||||
});
|
||||
@@ -169,65 +248,91 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
||||
const onRemove = view.onRemove ? () => view.onRemove() : () => { };
|
||||
|
||||
const layoutContainer = this.orientation === Orientation.VERTICAL
|
||||
? size => item.container.style.height = `${item.size}px`
|
||||
: size => item.container.style.width = `${item.size}px`;
|
||||
? () => item.container.style.height = `${item.size}px`
|
||||
: () => item.container.style.width = `${item.size}px`;
|
||||
|
||||
const layout = () => {
|
||||
layoutContainer(item.size);
|
||||
layoutContainer();
|
||||
item.view.layout(item.size, this.orientation);
|
||||
};
|
||||
|
||||
size = Math.round(size);
|
||||
const item: IViewItem = { onRemove, onAdd, view, container, size, layout, disposable, height: size, top: 0, width: 0 };
|
||||
this.viewItems.splice(viewIndex, 0, item);
|
||||
let viewSize: number;
|
||||
|
||||
this.onInsertItems(new ArrayIterator([item]), viewIndex > 0 ? this.viewItems[viewIndex - 1].view.id : undefined);
|
||||
if (typeof size === 'number') {
|
||||
viewSize = size;
|
||||
} else if (size.type === 'split') {
|
||||
viewSize = this.getViewSize(size.index) / 2;
|
||||
} else {
|
||||
viewSize = view.minimumSize;
|
||||
}
|
||||
|
||||
const item: IViewItem = { onAdd, onRemove, view, container, size: viewSize, layout, disposable, height: viewSize, top: 0, width: 0 };
|
||||
this.viewItems.splice(index, 0, item);
|
||||
|
||||
this.onInsertItems(new ArrayIterator([item]), index > 0 ? this.viewItems[index - 1].view.id : undefined);
|
||||
|
||||
// Add sash
|
||||
if (this.options.enableResizing && this.viewItems.length > 1) {
|
||||
const orientation = this.orientation === Orientation.VERTICAL ? Orientation.HORIZONTAL : Orientation.VERTICAL;
|
||||
const layoutProvider = this.orientation === Orientation.VERTICAL ? { getHorizontalSashTop: sash => this.getSashPosition(sash) } : { getVerticalSashLeft: sash => this.getSashPosition(sash) };
|
||||
const sash = new Sash(this.el, layoutProvider, { orientation });
|
||||
const sash = new Sash(this.sashContainer, layoutProvider, {
|
||||
orientation,
|
||||
orthogonalStartSash: this.orthogonalStartSash,
|
||||
orthogonalEndSash: this.orthogonalEndSash
|
||||
});
|
||||
|
||||
const sashEventMapper = this.orientation === Orientation.VERTICAL
|
||||
? (e: IBaseSashEvent) => ({ sash, start: e.startY, current: e.currentY })
|
||||
: (e: IBaseSashEvent) => ({ sash, start: e.startX, current: e.currentX });
|
||||
? (e: IBaseSashEvent) => ({ sash, start: e.startY, current: e.currentY, alt: e.altKey } as ISashEvent)
|
||||
: (e: IBaseSashEvent) => ({ sash, start: e.startX, current: e.currentX, alt: e.altKey } as ISashEvent);
|
||||
|
||||
const onStart = mapEvent(sash.onDidStart, sashEventMapper);
|
||||
const onStartDisposable = onStart(this.onSashStart, this);
|
||||
const onChange = mapEvent(sash.onDidChange, sashEventMapper);
|
||||
const onSashChangeDisposable = onChange(this.onSashChange, this);
|
||||
const onEnd = mapEvent<void, void>(sash.onDidEnd, () => null);
|
||||
const onEndDisposable = onEnd(() => this._onDidSashChange.fire());
|
||||
const onDidReset = mapEvent<void, void>(sash.onDidReset, () => null);
|
||||
const onDidResetDisposable = onDidReset(() => this._onDidSashReset.fire());
|
||||
const onChangeDisposable = onChange(this.onSashChange, this);
|
||||
const onEnd = mapEvent(sash.onDidEnd, () => firstIndex(this.sashItems, item => item.sash === sash));
|
||||
const onEndDisposable = onEnd(this.onSashEnd, this);
|
||||
const onDidResetDisposable = sash.onDidReset(() => this._onDidSashReset.fire(firstIndex(this.sashItems, item => item.sash === sash)));
|
||||
|
||||
const disposable = combinedDisposable([onStartDisposable, onSashChangeDisposable, onEndDisposable, onDidResetDisposable, sash]);
|
||||
const disposable = combinedDisposable([onStartDisposable, onChangeDisposable, onEndDisposable, onDidResetDisposable, sash]);
|
||||
const sashItem: ISashItem = { sash, disposable };
|
||||
|
||||
this.sashItems.splice(viewIndex - 1, 0, sashItem);
|
||||
this.sashItems.splice(index - 1, 0, sashItem);
|
||||
}
|
||||
|
||||
view.render(container, this.orientation);
|
||||
container.appendChild(view.element);
|
||||
}
|
||||
|
||||
this.relayout();
|
||||
let highPriorityIndex: number | undefined;
|
||||
|
||||
if (!types.isArray(sizes) && sizes.type === 'split') {
|
||||
highPriorityIndex = sizes.index;
|
||||
}
|
||||
|
||||
this.relayout(index, highPriorityIndex);
|
||||
this.state = State.Idle;
|
||||
|
||||
if (!types.isArray(sizes) && sizes.type === 'distribute') {
|
||||
this.distributeViewSizes();
|
||||
}
|
||||
}
|
||||
|
||||
addView(view: IView, size: number, index = this.viewItems.length): void {
|
||||
addView(view: IView, size: number | Sizing, index = this.viewItems.length): void {
|
||||
if (this.state !== State.Idle) {
|
||||
throw new Error('Cant modify splitview');
|
||||
}
|
||||
|
||||
this.state = State.Busy;
|
||||
|
||||
view.id = view.id || generateUuid();
|
||||
// Add view
|
||||
const container = dom.$('.split-view-view');
|
||||
|
||||
// removed default adding of the view directly to the container
|
||||
|
||||
const onChangeDisposable = view.onDidChange(size => this.onViewChange(item, size));
|
||||
const containerDisposable = toDisposable(() => {
|
||||
if (container.parentElement) {
|
||||
this.el.removeChild(container);
|
||||
this.viewContainer.removeChild(container);
|
||||
}
|
||||
this.onRemoveItems(new ArrayIterator([item.view.id]));
|
||||
});
|
||||
@@ -237,16 +342,25 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
||||
const onRemove = view.onRemove ? () => view.onRemove() : () => { };
|
||||
|
||||
const layoutContainer = this.orientation === Orientation.VERTICAL
|
||||
? size => item.container.style.height = `${item.size}px`
|
||||
: size => item.container.style.width = `${item.size}px`;
|
||||
? () => item.container.style.height = `${item.size}px`
|
||||
: () => item.container.style.width = `${item.size}px`;
|
||||
|
||||
const layout = () => {
|
||||
layoutContainer(item.size);
|
||||
layoutContainer();
|
||||
item.view.layout(item.size, this.orientation);
|
||||
};
|
||||
|
||||
size = Math.round(size);
|
||||
const item: IViewItem = { onAdd, onRemove, view, container, size, layout, disposable, height: size, top: 0, width: 0 };
|
||||
let viewSize: number;
|
||||
|
||||
if (typeof size === 'number') {
|
||||
viewSize = size;
|
||||
} else if (size.type === 'split') {
|
||||
viewSize = this.getViewSize(size.index) / 2;
|
||||
} else {
|
||||
viewSize = view.minimumSize;
|
||||
}
|
||||
|
||||
const item: IViewItem = { onAdd, onRemove, view, container, size: viewSize, layout, disposable, height: viewSize, top: 0, width: 0 };
|
||||
this.viewItems.splice(index, 0, item);
|
||||
|
||||
this.onInsertItems(new ArrayIterator([item]), index > 0 ? this.viewItems[index - 1].view.id : undefined);
|
||||
@@ -255,33 +369,47 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
||||
if (this.options.enableResizing && this.viewItems.length > 1) {
|
||||
const orientation = this.orientation === Orientation.VERTICAL ? Orientation.HORIZONTAL : Orientation.VERTICAL;
|
||||
const layoutProvider = this.orientation === Orientation.VERTICAL ? { getHorizontalSashTop: sash => this.getSashPosition(sash) } : { getVerticalSashLeft: sash => this.getSashPosition(sash) };
|
||||
const sash = new Sash(this.el, layoutProvider, { orientation });
|
||||
const sash = new Sash(this.sashContainer, layoutProvider, {
|
||||
orientation,
|
||||
orthogonalStartSash: this.orthogonalStartSash,
|
||||
orthogonalEndSash: this.orthogonalEndSash
|
||||
});
|
||||
|
||||
const sashEventMapper = this.orientation === Orientation.VERTICAL
|
||||
? (e: IBaseSashEvent) => ({ sash, start: e.startY, current: e.currentY })
|
||||
: (e: IBaseSashEvent) => ({ sash, start: e.startX, current: e.currentX });
|
||||
? (e: IBaseSashEvent) => ({ sash, start: e.startY, current: e.currentY, alt: e.altKey } as ISashEvent)
|
||||
: (e: IBaseSashEvent) => ({ sash, start: e.startX, current: e.currentX, alt: e.altKey } as ISashEvent);
|
||||
|
||||
const onStart = mapEvent(sash.onDidStart, sashEventMapper);
|
||||
const onStartDisposable = onStart(this.onSashStart, this);
|
||||
const onChange = mapEvent(sash.onDidChange, sashEventMapper);
|
||||
const onSashChangeDisposable = onChange(this.onSashChange, this);
|
||||
const onEnd = mapEvent<void, void>(sash.onDidEnd, () => null);
|
||||
const onEndDisposable = onEnd(() => this._onDidSashChange.fire());
|
||||
const onDidReset = mapEvent<void, void>(sash.onDidReset, () => null);
|
||||
const onDidResetDisposable = onDidReset(() => this._onDidSashReset.fire());
|
||||
const onChangeDisposable = onChange(this.onSashChange, this);
|
||||
const onEnd = mapEvent(sash.onDidEnd, () => firstIndex(this.sashItems, item => item.sash === sash));
|
||||
const onEndDisposable = onEnd(this.onSashEnd, this);
|
||||
const onDidResetDisposable = sash.onDidReset(() => this._onDidSashReset.fire(firstIndex(this.sashItems, item => item.sash === sash)));
|
||||
|
||||
const disposable = combinedDisposable([onStartDisposable, onSashChangeDisposable, onEndDisposable, onDidResetDisposable, sash]);
|
||||
const disposable = combinedDisposable([onStartDisposable, onChangeDisposable, onEndDisposable, onDidResetDisposable, sash]);
|
||||
const sashItem: ISashItem = { sash, disposable };
|
||||
|
||||
sash.hide();
|
||||
this.sashItems.splice(index - 1, 0, sashItem);
|
||||
}
|
||||
|
||||
view.render(container, this.orientation);
|
||||
this.relayout(index);
|
||||
container.appendChild(view.element);
|
||||
|
||||
let highPriorityIndex: number | undefined;
|
||||
|
||||
if (typeof size !== 'number' && size.type === 'split') {
|
||||
highPriorityIndex = size.index;
|
||||
}
|
||||
|
||||
this.relayout(index, highPriorityIndex);
|
||||
this.state = State.Idle;
|
||||
|
||||
if (typeof size !== 'number' && size.type === 'distribute') {
|
||||
this.distributeViewSizes();
|
||||
}
|
||||
}
|
||||
|
||||
removeView(index: number): void {
|
||||
removeView(index: number, sizing?: Sizing): IView {
|
||||
if (this.state !== State.Idle) {
|
||||
throw new Error('Cant modify splitview');
|
||||
}
|
||||
@@ -289,7 +417,7 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
||||
this.state = State.Busy;
|
||||
|
||||
if (index < 0 || index >= this.viewItems.length) {
|
||||
return;
|
||||
throw new Error('Index out of bounds');
|
||||
}
|
||||
|
||||
// Remove view
|
||||
@@ -301,12 +429,16 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
||||
const sashIndex = Math.max(index - 1, 0);
|
||||
const sashItem = this.sashItems.splice(sashIndex, 1)[0];
|
||||
sashItem.disposable.dispose();
|
||||
} else {
|
||||
this.lastRenderHeight = NaN, this.lastRenderTop = NaN;
|
||||
}
|
||||
|
||||
this.relayout();
|
||||
this.state = State.Idle;
|
||||
|
||||
if (sizing && sizing.type === 'distribute') {
|
||||
this.distributeViewSizes();
|
||||
}
|
||||
|
||||
return viewItem.view;
|
||||
}
|
||||
|
||||
moveView(from: number, to: number): void {
|
||||
@@ -314,36 +446,36 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
||||
throw new Error('Cant modify splitview');
|
||||
}
|
||||
|
||||
this.state = State.Busy;
|
||||
|
||||
if (from < 0 || from >= this.viewItems.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (to < 0 || to >= this.viewItems.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (from === to) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewItem = this.viewItems.splice(from, 1)[0];
|
||||
this.viewItems.splice(to, 0, viewItem);
|
||||
|
||||
if (to + 1 < this.viewItems.length) {
|
||||
this.el.insertBefore(viewItem.container, this.viewItems[to + 1].container);
|
||||
} else {
|
||||
this.el.appendChild(viewItem.container);
|
||||
}
|
||||
|
||||
this.layoutViews();
|
||||
this.state = State.Idle;
|
||||
const size = this.getViewSize(from);
|
||||
const view = this.removeView(from);
|
||||
this.addView(view, size, to);
|
||||
}
|
||||
|
||||
private relayout(lowPriorityIndex?: number): void {
|
||||
swapViews(from: number, to: number): void {
|
||||
if (this.state !== State.Idle) {
|
||||
throw new Error('Cant modify splitview');
|
||||
}
|
||||
|
||||
if (from > to) {
|
||||
return this.swapViews(to, from);
|
||||
}
|
||||
|
||||
const fromSize = this.getViewSize(from);
|
||||
const toSize = this.getViewSize(to);
|
||||
const toView = this.removeView(to);
|
||||
const fromView = this.removeView(from);
|
||||
|
||||
this.addView(toView, fromSize, from);
|
||||
this.addView(fromView, toSize, to);
|
||||
}
|
||||
|
||||
private relayout(lowPriorityIndex?: number, highPriorityIndex?: number): void {
|
||||
const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
|
||||
this.resize(this.viewItems.length - 1, this.size - contentSize, undefined, lowPriorityIndex);
|
||||
|
||||
this.resize(this.viewItems.length - 1, this.size - contentSize, undefined, lowPriorityIndex, highPriorityIndex);
|
||||
this.distributeEmptySpace();
|
||||
this.layoutViews();
|
||||
this.saveProportions();
|
||||
}
|
||||
|
||||
public setScrollPosition(position: number) {
|
||||
@@ -351,14 +483,188 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
||||
}
|
||||
|
||||
layout(size: number): void {
|
||||
const previousSize = this.size;
|
||||
const previousSize = Math.max(this.size, this.contentSize);
|
||||
this.size = size;
|
||||
this.contentSize = 0;
|
||||
this.lastRenderHeight = undefined;
|
||||
this.lastRenderTop = undefined;
|
||||
this.resize(this.viewItems.length - 1, size - previousSize);
|
||||
|
||||
if (!this.proportions) {
|
||||
this.resize(this.viewItems.length - 1, size - previousSize);
|
||||
} else {
|
||||
for (let i = 0; i < this.viewItems.length; i++) {
|
||||
const item = this.viewItems[i];
|
||||
item.size = clamp(Math.round(this.proportions[i] * size), item.view.minimumSize, item.view.maximumSize);
|
||||
}
|
||||
}
|
||||
|
||||
this.distributeEmptySpace();
|
||||
this.layoutViews();
|
||||
}
|
||||
|
||||
private saveProportions(): void {
|
||||
if (this.contentSize > 0) {
|
||||
this.proportions = this.viewItems.map(i => i.size / this.contentSize);
|
||||
}
|
||||
}
|
||||
|
||||
private onSashStart({ sash, start, alt }: ISashEvent): void {
|
||||
const index = firstIndex(this.sashItems, item => item.sash === sash);
|
||||
|
||||
// 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))
|
||||
]);
|
||||
|
||||
const resetSashDragState = (start: number, alt: boolean) => {
|
||||
const sizes = this.viewItems.map(i => i.size);
|
||||
let minDelta = Number.NEGATIVE_INFINITY;
|
||||
let maxDelta = Number.POSITIVE_INFINITY;
|
||||
|
||||
if (this.inverseAltBehavior) {
|
||||
alt = !alt;
|
||||
}
|
||||
|
||||
if (alt) {
|
||||
// When we're using the last sash with Alt, we're resizing
|
||||
// the view to the left/up, instead of right/down as usual
|
||||
// Thus, we must do the inverse of the usual
|
||||
const isLastSash = index === this.sashItems.length - 1;
|
||||
|
||||
if (isLastSash) {
|
||||
const viewItem = this.viewItems[index];
|
||||
minDelta = (viewItem.view.minimumSize - viewItem.size) / 2;
|
||||
maxDelta = (viewItem.view.maximumSize - viewItem.size) / 2;
|
||||
} else {
|
||||
const viewItem = this.viewItems[index + 1];
|
||||
minDelta = (viewItem.size - viewItem.view.maximumSize) / 2;
|
||||
maxDelta = (viewItem.size - viewItem.view.minimumSize) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
this.sashDragState = { start, current: start, index, sizes, minDelta, maxDelta, alt, disposable };
|
||||
};
|
||||
|
||||
resetSashDragState(start, alt);
|
||||
}
|
||||
|
||||
private onSashChange({ current }: ISashEvent): void {
|
||||
const { index, start, sizes, alt, minDelta, maxDelta } = this.sashDragState;
|
||||
this.sashDragState.current = current;
|
||||
|
||||
const delta = current - start;
|
||||
const newDelta = this.resize(index, delta, sizes, undefined, undefined, minDelta, maxDelta);
|
||||
|
||||
if (alt) {
|
||||
const isLastSash = index === this.sashItems.length - 1;
|
||||
const newSizes = this.viewItems.map(i => i.size);
|
||||
const viewItemIndex = isLastSash ? index : index + 1;
|
||||
const viewItem = this.viewItems[viewItemIndex];
|
||||
const newMinDelta = viewItem.size - viewItem.view.maximumSize;
|
||||
const newMaxDelta = viewItem.size - viewItem.view.minimumSize;
|
||||
const resizeIndex = isLastSash ? index - 1 : index + 1;
|
||||
|
||||
this.resize(resizeIndex, -newDelta, newSizes, undefined, undefined, newMinDelta, newMaxDelta);
|
||||
}
|
||||
|
||||
this.distributeEmptySpace();
|
||||
this.layoutViews();
|
||||
}
|
||||
|
||||
private onSashEnd(index: number): void {
|
||||
this._onDidSashChange.fire(index);
|
||||
this.sashDragState.disposable.dispose();
|
||||
this.saveProportions();
|
||||
}
|
||||
|
||||
private onViewChange(item: IViewItem, size: number | undefined): void {
|
||||
const index = this.viewItems.indexOf(item);
|
||||
|
||||
if (index < 0 || index >= this.viewItems.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
size = typeof size === 'number' ? size : item.size;
|
||||
size = clamp(size, item.view.minimumSize, item.view.maximumSize);
|
||||
|
||||
if (this.inverseAltBehavior && index > 0) {
|
||||
// In this case, we want the view to grow or shrink both sides equally
|
||||
// so we just resize the "left" side by half and let `resize` do the clamping magic
|
||||
this.resize(index - 1, Math.floor((item.size - size) / 2));
|
||||
this.distributeEmptySpace();
|
||||
this.layoutViews();
|
||||
} else {
|
||||
item.size = size;
|
||||
this.updateSize(item.view.id, size);
|
||||
let top = item.top + item.size;
|
||||
for (let i = index + 1; i < this.viewItems.length; i++) {
|
||||
let currentItem = this.viewItems[i];
|
||||
this.updateTop(currentItem.view.id, top);
|
||||
top += currentItem.size;
|
||||
}
|
||||
this.relayout(index);
|
||||
}
|
||||
}
|
||||
|
||||
resizeView(index: number, size: number): void {
|
||||
if (this.state !== State.Idle) {
|
||||
throw new Error('Cant modify splitview');
|
||||
}
|
||||
|
||||
this.state = State.Busy;
|
||||
|
||||
if (index < 0 || index >= this.viewItems.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const item = this.viewItems[index];
|
||||
size = Math.round(size);
|
||||
size = clamp(size, item.view.minimumSize, item.view.maximumSize);
|
||||
let delta = size - item.size;
|
||||
|
||||
if (delta !== 0 && index < this.viewItems.length - 1) {
|
||||
const downIndexes = range(index + 1, this.viewItems.length);
|
||||
const collapseDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].view.minimumSize), 0);
|
||||
const expandDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - this.viewItems[i].size), 0);
|
||||
const deltaDown = clamp(delta, -expandDown, collapseDown);
|
||||
|
||||
this.resize(index, deltaDown);
|
||||
delta -= deltaDown;
|
||||
}
|
||||
|
||||
if (delta !== 0 && index > 0) {
|
||||
const upIndexes = range(index - 1, -1);
|
||||
const collapseUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].view.minimumSize), 0);
|
||||
const expandUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - this.viewItems[i].size), 0);
|
||||
const deltaUp = clamp(-delta, -collapseUp, expandUp);
|
||||
|
||||
this.resize(index - 1, deltaUp);
|
||||
}
|
||||
|
||||
this.distributeEmptySpace();
|
||||
this.layoutViews();
|
||||
this.saveProportions();
|
||||
this.state = State.Idle;
|
||||
}
|
||||
|
||||
distributeViewSizes(): void {
|
||||
const size = Math.floor(this.size / this.viewItems.length);
|
||||
|
||||
for (let i = 0; i < this.viewItems.length - 1; i++) {
|
||||
this.resizeView(i, size);
|
||||
}
|
||||
}
|
||||
|
||||
getViewSize(index: number): number {
|
||||
if (index < 0 || index >= this.viewItems.length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return this.viewItems[index].size;
|
||||
}
|
||||
|
||||
|
||||
private render(scrollTop: number, viewHeight: number): void {
|
||||
let i: number;
|
||||
let stop: number;
|
||||
@@ -398,96 +704,13 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
||||
let topItem = this.itemAtIndex(this.indexAt(renderTop));
|
||||
|
||||
if (topItem) {
|
||||
this.el.style.top = (topItem.top - renderTop) + 'px';
|
||||
this.viewContainer.style.top = (topItem.top - renderTop) + 'px';
|
||||
}
|
||||
|
||||
this.lastRenderTop = renderTop;
|
||||
this.lastRenderHeight = renderBottom - renderTop;
|
||||
}
|
||||
|
||||
private onSashStart({ sash, start }: ISashEvent): void {
|
||||
const index = firstIndex(this.sashItems, item => item.sash === sash);
|
||||
const sizes = this.viewItems.map(i => i.size);
|
||||
|
||||
// const upIndexes = range(index, -1);
|
||||
// const collapseUp = upIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].view.minimumSize), 0);
|
||||
// const expandUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - sizes[i]), 0);
|
||||
|
||||
// const downIndexes = range(index + 1, this.viewItems.length);
|
||||
// const collapseDown = downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].view.minimumSize), 0);
|
||||
// const expandDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - sizes[i]), 0);
|
||||
|
||||
// const minDelta = -Math.min(collapseUp, expandDown);
|
||||
// const maxDelta = Math.min(collapseDown, expandUp);
|
||||
|
||||
this.sashDragState = { start, index, sizes };
|
||||
}
|
||||
|
||||
private onSashChange({ sash, current }: ISashEvent): void {
|
||||
const { index, start, sizes } = this.sashDragState;
|
||||
const delta = current - start;
|
||||
|
||||
this.resize(index, delta, sizes);
|
||||
}
|
||||
|
||||
private onViewChange(item: IViewItem, size: number | undefined): void {
|
||||
const index = this.viewItems.indexOf(item);
|
||||
|
||||
if (index < 0 || index >= this.viewItems.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
size = typeof size === 'number' ? size : item.size;
|
||||
size = clamp(size, item.view.minimumSize, item.view.maximumSize);
|
||||
item.size = size;
|
||||
this.updateSize(item.view.id, size);
|
||||
let top = item.top + item.size;
|
||||
for (let i = index + 1; i < this.viewItems.length; i++) {
|
||||
let currentItem = this.viewItems[i];
|
||||
this.updateTop(currentItem.view.id, top);
|
||||
top += currentItem.size;
|
||||
}
|
||||
this.relayout(index);
|
||||
}
|
||||
|
||||
resizeView(index: number, size: number): void {
|
||||
if (this.state !== State.Idle) {
|
||||
throw new Error('Cant modify splitview');
|
||||
}
|
||||
|
||||
this.state = State.Busy;
|
||||
|
||||
if (index < 0 || index >= this.viewItems.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const item = this.viewItems[index];
|
||||
size = Math.round(size);
|
||||
size = clamp(size, item.view.minimumSize, item.view.maximumSize);
|
||||
let delta = size - item.size;
|
||||
|
||||
if (delta !== 0 && index < this.viewItems.length - 1) {
|
||||
const downIndexes = range(index + 1, this.viewItems.length);
|
||||
const collapseDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].view.minimumSize), 0);
|
||||
const expandDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - this.viewItems[i].size), 0);
|
||||
const deltaDown = clamp(delta, -expandDown, collapseDown);
|
||||
|
||||
this.resize(index, deltaDown);
|
||||
delta -= deltaDown;
|
||||
}
|
||||
|
||||
if (delta !== 0 && index > 0) {
|
||||
const upIndexes = range(index - 1, -1);
|
||||
const collapseUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].view.minimumSize), 0);
|
||||
const expandUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - this.viewItems[i].size), 0);
|
||||
const deltaUp = clamp(-delta, -collapseUp, expandUp);
|
||||
|
||||
this.resize(index - 1, deltaUp);
|
||||
}
|
||||
|
||||
this.state = State.Idle;
|
||||
}
|
||||
|
||||
// DOM changes
|
||||
|
||||
private insertItemInDOM(item: IViewItem): boolean {
|
||||
@@ -503,13 +726,13 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
||||
}
|
||||
|
||||
if (elementAfter === null) {
|
||||
this.el.appendChild(item.container);
|
||||
this.viewContainer.appendChild(item.container);
|
||||
} else {
|
||||
try {
|
||||
this.el.insertBefore(item.container, elementAfter);
|
||||
this.viewContainer.insertBefore(item.container, elementAfter);
|
||||
} catch (e) {
|
||||
// console.warn('Failed to locate previous tree element');
|
||||
this.el.appendChild(item.container);
|
||||
this.viewContainer.appendChild(item.container);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,85 +747,94 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.el.removeChild(item.container);
|
||||
this.viewContainer.removeChild(item.container);
|
||||
|
||||
item.onRemove();
|
||||
return true;
|
||||
}
|
||||
|
||||
getViewSize(index: number): number {
|
||||
private resize(
|
||||
index: number,
|
||||
delta: number,
|
||||
sizes = this.viewItems.map(i => i.size),
|
||||
lowPriorityIndex?: number,
|
||||
highPriorityIndex?: number,
|
||||
overloadMinDelta: number = Number.NEGATIVE_INFINITY,
|
||||
overloadMaxDelta: number = Number.POSITIVE_INFINITY
|
||||
): number {
|
||||
if (index < 0 || index >= this.viewItems.length) {
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return this.viewItems[index].size;
|
||||
const upIndexes = range(index, -1);
|
||||
const downIndexes = range(index + 1, this.viewItems.length);
|
||||
|
||||
if (typeof highPriorityIndex === 'number') {
|
||||
pushToStart(upIndexes, highPriorityIndex);
|
||||
pushToStart(downIndexes, highPriorityIndex);
|
||||
}
|
||||
|
||||
if (typeof lowPriorityIndex === 'number') {
|
||||
pushToEnd(upIndexes, lowPriorityIndex);
|
||||
pushToEnd(downIndexes, lowPriorityIndex);
|
||||
}
|
||||
|
||||
const upItems = upIndexes.map(i => this.viewItems[i]);
|
||||
const upSizes = upIndexes.map(i => sizes[i]);
|
||||
|
||||
const downItems = downIndexes.map(i => this.viewItems[i]);
|
||||
const downSizes = downIndexes.map(i => sizes[i]);
|
||||
|
||||
const minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.minimumSize - sizes[i]), 0);
|
||||
const maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - sizes[i]), 0);
|
||||
const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].view.minimumSize), 0);
|
||||
const minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].view.maximumSize), 0);
|
||||
const minDelta = Math.max(minDeltaUp, minDeltaDown, overloadMinDelta);
|
||||
const maxDelta = Math.min(maxDeltaDown, maxDeltaUp, overloadMaxDelta);
|
||||
|
||||
delta = clamp(delta, minDelta, maxDelta);
|
||||
|
||||
for (let i = 0, deltaUp = delta; i < upItems.length; i++) {
|
||||
const item = upItems[i];
|
||||
const size = clamp(upSizes[i] + deltaUp, item.view.minimumSize, item.view.maximumSize);
|
||||
const viewDelta = size - upSizes[i];
|
||||
|
||||
deltaUp -= viewDelta;
|
||||
item.size = size;
|
||||
this.dirtyState = true;
|
||||
}
|
||||
|
||||
for (let i = 0, deltaDown = delta; i < downItems.length; i++) {
|
||||
const item = downItems[i];
|
||||
const size = clamp(downSizes[i] - deltaDown, item.view.minimumSize, item.view.maximumSize);
|
||||
const viewDelta = size - downSizes[i];
|
||||
|
||||
deltaDown += viewDelta;
|
||||
item.size = size;
|
||||
this.dirtyState = true;
|
||||
}
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
private resize(index: number, delta: number, sizes = this.viewItems.map(i => i.size), lowPriorityIndex?: number): void {
|
||||
if (index < 0 || index >= this.viewItems.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (delta !== 0) {
|
||||
let upIndexes = range(index, -1);
|
||||
let downIndexes = range(index + 1, this.viewItems.length);
|
||||
|
||||
if (typeof lowPriorityIndex === 'number') {
|
||||
upIndexes = pushToEnd(upIndexes, lowPriorityIndex);
|
||||
downIndexes = pushToEnd(downIndexes, lowPriorityIndex);
|
||||
}
|
||||
|
||||
const upItems = upIndexes.map(i => this.viewItems[i]);
|
||||
const upSizes = upIndexes.map(i => sizes[i]);
|
||||
|
||||
const downItems = downIndexes.map(i => this.viewItems[i]);
|
||||
const downSizes = downIndexes.map(i => sizes[i]);
|
||||
|
||||
for (let i = 0, deltaUp = delta; deltaUp !== 0 && i < upItems.length; i++) {
|
||||
const item = upItems[i];
|
||||
const size = clamp(upSizes[i] + deltaUp, item.view.minimumSize, item.view.maximumSize);
|
||||
const viewDelta = size - upSizes[i];
|
||||
|
||||
deltaUp -= viewDelta;
|
||||
item.size = size;
|
||||
this.dirtyState = true;
|
||||
}
|
||||
|
||||
for (let i = 0, deltaDown = delta; deltaDown !== 0 && i < downItems.length; i++) {
|
||||
const item = downItems[i];
|
||||
const size = clamp(downSizes[i] - deltaDown, item.view.minimumSize, item.view.maximumSize);
|
||||
const viewDelta = size - downSizes[i];
|
||||
|
||||
deltaDown += viewDelta;
|
||||
item.size = size;
|
||||
this.dirtyState = true;
|
||||
}
|
||||
}
|
||||
|
||||
private distributeEmptySpace(): void {
|
||||
let contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
|
||||
let emptyDelta = this.size - contentSize;
|
||||
|
||||
for (let i = this.viewItems.length - 1; emptyDelta > 0 && i >= 0; i--) {
|
||||
for (let i = this.viewItems.length - 1; emptyDelta !== 0 && i >= 0; i--) {
|
||||
const item = this.viewItems[i];
|
||||
const size = clamp(item.size + emptyDelta, item.view.minimumSize, item.view.maximumSize);
|
||||
const viewDelta = size - item.size;
|
||||
|
||||
emptyDelta -= viewDelta;
|
||||
item.size = size;
|
||||
this.dirtyState = true;
|
||||
}
|
||||
|
||||
this.contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
|
||||
|
||||
this.scrollable.setScrollDimensions({
|
||||
scrollHeight: this.contentSize,
|
||||
height: this.size
|
||||
});
|
||||
|
||||
this.layoutViews();
|
||||
}
|
||||
|
||||
private layoutViews(): void {
|
||||
// Save new content size
|
||||
this.contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
|
||||
|
||||
if (this.dirtyState) {
|
||||
for (let i = this.indexAt(this.lastRenderTop); i <= this.indexAfter(this.lastRenderTop + this.lastRenderHeight) - 1; i++) {
|
||||
this.viewItems[i].layout();
|
||||
@@ -613,27 +845,10 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
||||
this.dirtyState = false;
|
||||
}
|
||||
|
||||
// Update sashes enablement
|
||||
// let previous = false;
|
||||
// const collapsesDown = this.viewItems.map(i => previous = (i.size - i.view.minimumSize > 0) || previous);
|
||||
|
||||
// previous = false;
|
||||
// const expandsDown = this.viewItems.map(i => previous = (i.view.maximumSize - i.size > 0) || previous);
|
||||
|
||||
// const reverseViews = [...this.viewItems].reverse();
|
||||
// previous = false;
|
||||
// const collapsesUp = reverseViews.map(i => previous = (i.size - i.view.minimumSize > 0) || previous).reverse();
|
||||
|
||||
// previous = false;
|
||||
// const expandsUp = reverseViews.map(i => previous = (i.view.maximumSize - i.size > 0) || previous).reverse();
|
||||
|
||||
// this.sashItems.forEach((s, i) => {
|
||||
// if ((collapsesDown[i] && expandsUp[i + 1]) || (expandsDown[i] && collapsesUp[i + 1])) {
|
||||
// s.sash.enable();
|
||||
// } else {
|
||||
// s.sash.disable();
|
||||
// }
|
||||
// });
|
||||
this.scrollable.setScrollDimensions({
|
||||
scrollHeight: this.contentSize,
|
||||
height: this.size
|
||||
});
|
||||
}
|
||||
|
||||
private getSashPosition(sash: Sash): number {
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e8e8e8" d="M6 4v8l4-4-4-4zm1 2.414l1.586 1.586-1.586 1.586v-3.172z"/></svg>
|
||||
|
Before Width: | Height: | Size: 151 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#646465" d="M6 4v8l4-4-4-4zm1 2.414l1.586 1.586-1.586 1.586v-3.172z"/></svg>
|
||||
|
Before Width: | Height: | Size: 151 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e8e8e8" d="M11 10.07h-5.656l5.656-5.656v5.656z"/></svg>
|
||||
|
Before Width: | Height: | Size: 131 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#646465" d="M11 10.07h-5.656l5.656-5.656v5.656z"/></svg>
|
||||
|
Before Width: | Height: | Size: 131 B |
@@ -1,94 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-split-view {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.monaco-split-view > .split-view-view {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.monaco-split-view.vertical > .split-view-view {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.monaco-split-view.horizontal > .split-view-view {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-split-view > .split-view-view > .header {
|
||||
position: relative;
|
||||
line-height: 22px;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
padding-left: 20px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.monaco-split-view > .split-view-view > .header.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Bold font style does not go well with CJK fonts */
|
||||
.monaco-split-view:lang(zh-Hans) > .split-view-view > .header,
|
||||
.monaco-split-view:lang(zh-Hant) > .split-view-view > .header,
|
||||
.monaco-split-view:lang(ja) > .split-view-view > .header,
|
||||
.monaco-split-view:lang(ko) > .split-view-view > .header { font-weight: normal; }
|
||||
|
||||
.monaco-split-view > .split-view-view > .header.collapsible {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.monaco-split-view > .split-view-view > .header.collapsible {
|
||||
background-image: url('arrow-collapse.svg');
|
||||
background-position: 2px center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.monaco-split-view > .split-view-view > .header.collapsible:not(.collapsed) {
|
||||
background-image: url('arrow-expand.svg');
|
||||
background-position: 2px center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-split-view > .split-view-view > .header.collapsible {
|
||||
background-image: url('arrow-collapse-dark.svg');
|
||||
}
|
||||
|
||||
.vs-dark .monaco-split-view > .split-view-view > .header.collapsible:not(.collapsed) {
|
||||
background-image: url('arrow-expand-dark.svg');
|
||||
background-position: 2px center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
/* Animation */
|
||||
|
||||
.monaco-split-view.animated > .split-view-view {
|
||||
transition-duration: 0.15s;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-moz-transition-duration: 0.15s;
|
||||
transition-timing-function: ease-out;
|
||||
-webkit-transition-timing-function: ease-out;
|
||||
-moz-transition-timing-function: ease-out;
|
||||
}
|
||||
|
||||
.monaco-split-view.vertical.animated > .split-view-view {
|
||||
transition-property: height;
|
||||
-webkit-transition-property: height;
|
||||
-moz-transition-property: height;
|
||||
}
|
||||
|
||||
.monaco-split-view.horizontal.animated > .split-view-view {
|
||||
transition-property: width;
|
||||
-webkit-transition-property: width;
|
||||
-moz-transition-property: width;
|
||||
}
|
||||
|
||||
.hc-black .split-view-view > .header .action-label:before {
|
||||
top: 4px !important;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,148 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Table } from './table';
|
||||
import { TableDataView } from './tableDataView';
|
||||
import { View, Orientation, AbstractCollapsibleView, HeaderView, ICollapsibleViewOptions, IViewOptions, CollapsibleState } from 'sql/base/browser/ui/splitview/splitview';
|
||||
import { $ } from 'vs/base/browser/builder';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import * as lifecycle from 'vs/base/common/lifecycle';
|
||||
|
||||
export class TableBasicView<T> extends View {
|
||||
private _table: Table<T>;
|
||||
private _container: HTMLElement;
|
||||
|
||||
constructor(
|
||||
viewOpts: IViewOptions,
|
||||
data?: Array<T> | TableDataView<T>,
|
||||
columns?: Slick.Column<T>[],
|
||||
tableOpts?: Slick.GridOptions<T>
|
||||
) {
|
||||
super(undefined, viewOpts);
|
||||
this._container = document.createElement('div');
|
||||
this._container.className = 'table-view';
|
||||
this._table = new Table<T>(this._container, { dataProvider: data, columns }, tableOpts);
|
||||
}
|
||||
|
||||
public get table(): Table<T> {
|
||||
return this._table;
|
||||
}
|
||||
|
||||
render(container: HTMLElement, orientation: Orientation): void {
|
||||
container.appendChild(this._container);
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
this._table.focus();
|
||||
}
|
||||
|
||||
layout(size: number, orientation: Orientation): void {
|
||||
this._table.layout(size, orientation);
|
||||
}
|
||||
}
|
||||
|
||||
export class TableHeaderView<T> extends HeaderView {
|
||||
private _table: Table<T>;
|
||||
private _container: HTMLElement;
|
||||
|
||||
constructor(
|
||||
private _viewTitle: string,
|
||||
viewOpts: IViewOptions,
|
||||
data?: Array<T> | TableDataView<T>,
|
||||
columns?: Slick.Column<T>[],
|
||||
tableOpts?: Slick.GridOptions<T>
|
||||
) {
|
||||
super(undefined, viewOpts);
|
||||
this._container = document.createElement('div');
|
||||
this._container.className = 'table-view';
|
||||
this._table = new Table<T>(this._container, { dataProvider: data, columns }, tableOpts);
|
||||
}
|
||||
|
||||
public get table(): Table<T> {
|
||||
return this._table;
|
||||
}
|
||||
|
||||
protected renderHeader(container: HTMLElement): void {
|
||||
const titleDiv = $('div.title').appendTo(container);
|
||||
$('span').text(this._viewTitle).appendTo(titleDiv);
|
||||
}
|
||||
|
||||
protected renderBody(container: HTMLElement): void {
|
||||
container.appendChild(this._container);
|
||||
}
|
||||
|
||||
protected layoutBody(size: number): void {
|
||||
this._table.layout(size, Orientation.VERTICAL);
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
this._table.focus();
|
||||
}
|
||||
}
|
||||
|
||||
export class TableCollapsibleView<T> extends AbstractCollapsibleView {
|
||||
private _table: Table<T>;
|
||||
private _container: HTMLElement;
|
||||
private _headerTabListener: lifecycle.IDisposable;
|
||||
|
||||
constructor(
|
||||
private _viewTitle: string,
|
||||
viewOpts: ICollapsibleViewOptions,
|
||||
data?: Array<T> | TableDataView<T>,
|
||||
columns?: Slick.Column<T>[],
|
||||
tableOpts?: Slick.GridOptions<T>
|
||||
) {
|
||||
super(undefined, viewOpts);
|
||||
this._container = document.createElement('div');
|
||||
this._container.className = 'table-view';
|
||||
this._table = new Table<T>(this._container, { dataProvider: data, columns }, tableOpts);
|
||||
}
|
||||
|
||||
public render(container: HTMLElement, orientation: Orientation): void {
|
||||
super.render(container, orientation);
|
||||
this._headerTabListener = DOM.addDisposableListener(this.header, DOM.EventType.KEY_DOWN, (e) => {
|
||||
let event = new StandardKeyboardEvent(e);
|
||||
if (event.equals(KeyCode.Tab) && this.state === CollapsibleState.EXPANDED) {
|
||||
let element = this._table.getSelectedRows();
|
||||
if (!element || element.length === 0) {
|
||||
this._table.setSelectedRows([0]);
|
||||
this._table.setActiveCell(0, 1);
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (this._headerTabListener) {
|
||||
this._headerTabListener.dispose();
|
||||
this._headerTabListener = null;
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public addContainerClass(className: string) {
|
||||
this._container.classList.add(className);
|
||||
}
|
||||
|
||||
public get table(): Table<T> {
|
||||
return this._table;
|
||||
}
|
||||
|
||||
protected renderHeader(container: HTMLElement): void {
|
||||
const titleDiv = $('div.title').appendTo(container);
|
||||
$('span').text(this._viewTitle).appendTo(titleDiv);
|
||||
}
|
||||
|
||||
protected renderBody(container: HTMLElement): void {
|
||||
container.appendChild(this._container);
|
||||
}
|
||||
|
||||
protected layoutBody(size: number): void {
|
||||
this._table.layout(size, Orientation.VERTICAL);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.custom-view-tree-node-item {
|
||||
display: flex;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.custom-view-tree-node-item > .custom-view-tree-node-item-icon {
|
||||
background-size: 16px;
|
||||
background-position: left center;
|
||||
background-repeat: no-repeat;
|
||||
padding-right: 6px;
|
||||
width: 16px;
|
||||
height: 22px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.custom-view-tree-node-item > .custom-view-tree-node-item-label {
|
||||
flex: 1;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -1,303 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IThemable } from 'vs/platform/theme/common/styler';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { $ } from 'vs/base/browser/builder';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IAction, IActionRunner } from 'vs/base/common/actions';
|
||||
import { IActionItem, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { prepareActions } from 'vs/workbench/browser/actions';
|
||||
import { ITree } from 'vs/base/parts/tree/browser/tree';
|
||||
import { DelayedDragHandler } from 'vs/base/browser/dnd';
|
||||
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { AbstractCollapsibleView, CollapsibleState, IView as IBaseView, SplitView, ViewSizing } from 'sql/base/browser/ui/splitview/splitview';
|
||||
|
||||
export interface IViewOptions {
|
||||
|
||||
id: string;
|
||||
|
||||
name: string;
|
||||
|
||||
actionRunner: IActionRunner;
|
||||
|
||||
collapsed: boolean;
|
||||
|
||||
}
|
||||
|
||||
export interface IViewConstructorSignature {
|
||||
|
||||
new(initialSize: number, options: IViewOptions, ...services: { _serviceBrand: any; }[]): IView;
|
||||
|
||||
}
|
||||
|
||||
export interface IView extends IBaseView, IThemable {
|
||||
|
||||
id: string;
|
||||
|
||||
name: string;
|
||||
|
||||
getHeaderElement(): HTMLElement;
|
||||
|
||||
create(): TPromise<void>;
|
||||
|
||||
setVisible(visible: boolean): TPromise<void>;
|
||||
|
||||
isVisible(): boolean;
|
||||
|
||||
getActions(): IAction[];
|
||||
|
||||
getSecondaryActions(): IAction[];
|
||||
|
||||
getActionItem(action: IAction): IActionItem;
|
||||
|
||||
getActionsContext(): any;
|
||||
|
||||
showHeader(): boolean;
|
||||
|
||||
hideHeader(): boolean;
|
||||
|
||||
focusBody(): void;
|
||||
|
||||
isExpanded(): boolean;
|
||||
|
||||
expand(): void;
|
||||
|
||||
collapse(): void;
|
||||
|
||||
getOptimalWidth(): number;
|
||||
|
||||
shutdown(): void;
|
||||
}
|
||||
|
||||
export interface ICollapsibleViewOptions extends IViewOptions {
|
||||
|
||||
ariaHeaderLabel?: string;
|
||||
|
||||
sizing: ViewSizing;
|
||||
|
||||
initialBodySize?: number;
|
||||
|
||||
}
|
||||
|
||||
export abstract class CollapsibleView extends AbstractCollapsibleView implements IView {
|
||||
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
|
||||
protected treeContainer: HTMLElement;
|
||||
protected tree: ITree;
|
||||
protected toDispose: IDisposable[];
|
||||
protected toolBar: ToolBar;
|
||||
protected actionRunner: IActionRunner;
|
||||
protected isDisposed: boolean;
|
||||
|
||||
private _isVisible: boolean;
|
||||
|
||||
private dragHandler: DelayedDragHandler;
|
||||
|
||||
constructor(
|
||||
initialSize: number,
|
||||
options: ICollapsibleViewOptions,
|
||||
protected keybindingService: IKeybindingService,
|
||||
protected contextMenuService: IContextMenuService
|
||||
) {
|
||||
super(initialSize, {
|
||||
ariaHeaderLabel: options.ariaHeaderLabel,
|
||||
sizing: options.sizing,
|
||||
bodySize: options.initialBodySize ? options.initialBodySize : 4 * 22,
|
||||
initialState: options.collapsed ? CollapsibleState.COLLAPSED : CollapsibleState.EXPANDED,
|
||||
});
|
||||
|
||||
this.id = options.id;
|
||||
this.name = options.name;
|
||||
this.actionRunner = options.actionRunner;
|
||||
this.toDispose = [];
|
||||
}
|
||||
|
||||
protected changeState(state: CollapsibleState): void {
|
||||
this.updateTreeVisibility(this.tree, state === CollapsibleState.EXPANDED);
|
||||
|
||||
super.changeState(state);
|
||||
}
|
||||
|
||||
get draggableLabel(): string { return this.name; }
|
||||
|
||||
public create(): TPromise<void> {
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
getHeaderElement(): HTMLElement {
|
||||
return this.header;
|
||||
}
|
||||
|
||||
public renderHeader(container: HTMLElement): void {
|
||||
|
||||
// Tool bar
|
||||
this.toolBar = new ToolBar($('div.actions').appendTo(container).getHTMLElement(), this.contextMenuService, {
|
||||
orientation: ActionsOrientation.HORIZONTAL,
|
||||
actionItemProvider: (action) => this.getActionItem(action),
|
||||
ariaLabel: nls.localize('viewToolbarAriaLabel', "{0} actions", this.name),
|
||||
getKeyBinding: (action) => this.keybindingService.lookupKeybinding(action.id)
|
||||
});
|
||||
this.toolBar.actionRunner = this.actionRunner;
|
||||
this.updateActions();
|
||||
|
||||
// Expand on drag over
|
||||
this.dragHandler = new DelayedDragHandler(container, () => {
|
||||
if (!this.isExpanded()) {
|
||||
this.expand();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected updateActions(): void {
|
||||
this.toolBar.setActions(prepareActions(this.getActions()), prepareActions(this.getSecondaryActions()))();
|
||||
this.toolBar.context = this.getActionsContext();
|
||||
}
|
||||
|
||||
protected renderViewTree(container: HTMLElement): HTMLElement {
|
||||
const treeContainer = document.createElement('div');
|
||||
container.appendChild(treeContainer);
|
||||
|
||||
return treeContainer;
|
||||
}
|
||||
|
||||
public getViewer(): ITree {
|
||||
return this.tree;
|
||||
}
|
||||
|
||||
public isVisible(): boolean {
|
||||
return this._isVisible;
|
||||
}
|
||||
|
||||
public setVisible(visible: boolean): TPromise<void> {
|
||||
if (this._isVisible !== visible) {
|
||||
this._isVisible = visible;
|
||||
this.updateTreeVisibility(this.tree, visible && this.state === CollapsibleState.EXPANDED);
|
||||
}
|
||||
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
public focusBody(): void {
|
||||
this.focusTree();
|
||||
}
|
||||
|
||||
protected reveal(element: any, relativeTop?: number): TPromise<void> {
|
||||
if (!this.tree) {
|
||||
return TPromise.as(null); // return early if viewlet has not yet been created
|
||||
}
|
||||
|
||||
return this.tree.reveal(element, relativeTop);
|
||||
}
|
||||
|
||||
public layoutBody(size: number): void {
|
||||
if (this.tree) {
|
||||
this.treeContainer.style.height = size + 'px';
|
||||
this.tree.layout(size);
|
||||
}
|
||||
}
|
||||
|
||||
public getActions(): IAction[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
public getSecondaryActions(): IAction[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
public getActionItem(action: IAction): IActionItem {
|
||||
return null;
|
||||
}
|
||||
|
||||
public getActionsContext(): any {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public shutdown(): void {
|
||||
// Subclass to implement
|
||||
}
|
||||
|
||||
public getOptimalWidth(): number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.isDisposed = true;
|
||||
this.treeContainer = null;
|
||||
|
||||
if (this.tree) {
|
||||
this.tree.dispose();
|
||||
}
|
||||
|
||||
if (this.dragHandler) {
|
||||
this.dragHandler.dispose();
|
||||
}
|
||||
|
||||
this.toDispose = dispose(this.toDispose);
|
||||
|
||||
if (this.toolBar) {
|
||||
this.toolBar.dispose();
|
||||
}
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private updateTreeVisibility(tree: ITree, isVisible: boolean): void {
|
||||
if (!tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isVisible) {
|
||||
$(tree.getHTMLElement()).show();
|
||||
} else {
|
||||
$(tree.getHTMLElement()).hide(); // make sure the tree goes out of the tabindex world by hiding it
|
||||
}
|
||||
|
||||
if (isVisible) {
|
||||
tree.onVisible();
|
||||
} else {
|
||||
tree.onHidden();
|
||||
}
|
||||
}
|
||||
|
||||
private focusTree(): void {
|
||||
if (!this.tree) {
|
||||
return; // return early if viewlet has not yet been created
|
||||
}
|
||||
|
||||
// Make sure the current selected element is revealed
|
||||
const selection = this.tree.getSelection();
|
||||
if (selection.length > 0) {
|
||||
this.reveal(selection[0], 0.5).done(null, errors.onUnexpectedError);
|
||||
}
|
||||
|
||||
// Pass Focus to Viewer
|
||||
this.tree.domFocus();
|
||||
}
|
||||
}
|
||||
|
||||
export interface IViewletViewOptions extends IViewOptions {
|
||||
|
||||
viewletSettings: object;
|
||||
|
||||
}
|
||||
|
||||
export interface IViewState {
|
||||
|
||||
collapsed: boolean;
|
||||
|
||||
size: number | undefined;
|
||||
|
||||
isHidden: boolean;
|
||||
|
||||
order: number;
|
||||
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { Command } from 'vs/editor/common/modes';
|
||||
|
||||
export type TreeViewItemHandleArg = {
|
||||
$treeViewId: string,
|
||||
$treeItemHandle: number
|
||||
};
|
||||
|
||||
export enum TreeItemCollapsibleState {
|
||||
None = 0,
|
||||
Collapsed = 1,
|
||||
Expanded = 2
|
||||
}
|
||||
|
||||
export interface ITreeItem {
|
||||
|
||||
handle: number;
|
||||
|
||||
label: string;
|
||||
|
||||
icon?: string;
|
||||
|
||||
iconDark?: string;
|
||||
|
||||
contextValue?: string;
|
||||
|
||||
command?: Command;
|
||||
|
||||
children?: ITreeItem[];
|
||||
|
||||
collapsibleState?: TreeItemCollapsibleState;
|
||||
}
|
||||
|
||||
export interface ITreeViewDataProvider {
|
||||
|
||||
onDidChange: Event<ITreeItem[] | undefined | null>;
|
||||
|
||||
onDispose: Event<void>;
|
||||
|
||||
getElements(): TPromise<ITreeItem[]>;
|
||||
|
||||
getChildren(element: ITreeItem): TPromise<ITreeItem[]>;
|
||||
|
||||
}
|
||||
@@ -11,7 +11,8 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import * as cr from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IThemable, attachStyler } from 'vs/platform/theme/common/styler';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { SIDE_BAR_BACKGROUND, SIDE_BAR_SECTION_HEADER_FOREGROUND, SIDE_BAR_SECTION_HEADER_BACKGROUND, SIDE_BAR_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { IPanelColors } from 'vs/workbench/browser/parts/views/panelViewlet';
|
||||
|
||||
export function attachModalDialogStyler(widget: IThemable, themeService: IThemeService, style?:
|
||||
{
|
||||
@@ -262,3 +263,12 @@ export function attachCheckboxStyler(widget: IThemable, themeService: IThemeServ
|
||||
disabledCheckboxForeground: (style && style.disabledCheckboxForeground) || sqlcolors.disabledCheckboxForeground
|
||||
}, widget);
|
||||
}
|
||||
|
||||
export function attachPanelStyler(widget: IThemable, themeService: IThemeService) {
|
||||
return attachStyler<IPanelColors>(themeService, {
|
||||
headerForeground: SIDE_BAR_SECTION_HEADER_FOREGROUND,
|
||||
headerBackground: SIDE_BAR_SECTION_HEADER_BACKGROUND,
|
||||
// headerHighContrastBorder: index === 0 ? null : contrastBorder,
|
||||
dropBackground: SIDE_BAR_DRAG_AND_DROP_BACKGROUND
|
||||
}, widget);
|
||||
}
|
||||
|
||||
@@ -8,35 +8,87 @@
|
||||
import 'vs/css!./media/accountDialog';
|
||||
import 'vs/css!sql/parts/accountManagement/common/media/accountActions';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { SplitView } from 'sql/base/browser/ui/splitview/splitview';
|
||||
import { List } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IListService, ListService } from 'vs/platform/list/browser/listService';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
||||
import { ActionRunner } from 'vs/base/common/actions';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||
import { SplitView, Sizing } from 'vs/base/browser/ui/splitview/splitview';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { values } from 'vs/base/common/map';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
|
||||
import { Button } from 'sql/base/browser/ui/button/button';
|
||||
import { Modal } from 'sql/base/browser/ui/modal/modal';
|
||||
import { attachModalDialogStyler, attachButtonStyler } from 'sql/common/theme/styler';
|
||||
import { attachModalDialogStyler, attachButtonStyler, attachPanelStyler } from 'sql/common/theme/styler';
|
||||
import { AccountViewModel } from 'sql/parts/accountManagement/accountDialog/accountViewModel';
|
||||
import { AddAccountAction } from 'sql/parts/accountManagement/common/accountActions';
|
||||
import { AccountListRenderer, AccountListDelegate } from 'sql/parts/accountManagement/common/accountListRenderer';
|
||||
import { AccountProviderAddedEventParams, UpdateAccountListEventParams } from 'sql/services/accountManagement/eventTypes';
|
||||
import { FixedListView } from 'sql/platform/views/fixedListView';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
|
||||
import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||
|
||||
class AccountPanel extends ViewletPanel {
|
||||
public index: number;
|
||||
private accountList: List<sqlops.Account>;
|
||||
|
||||
constructor(
|
||||
private options: IViewletPanelOptions,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IThemeService private themeService: IThemeService
|
||||
) {
|
||||
super(options, keybindingService, contextMenuService, configurationService);
|
||||
}
|
||||
|
||||
protected renderBody(container: HTMLElement): void {
|
||||
this.accountList = new List<sqlops.Account>(container, new AccountListDelegate(AccountDialog.ACCOUNTLIST_HEIGHT), [this.instantiationService.createInstance(AccountListRenderer)]);
|
||||
this.disposables.push(attachListStyler(this.accountList, this.themeService));
|
||||
}
|
||||
|
||||
protected layoutBody(size: number): void {
|
||||
if (this.accountList) {
|
||||
this.accountList.layout(size);
|
||||
}
|
||||
}
|
||||
|
||||
public get length(): number {
|
||||
return this.accountList.length;
|
||||
}
|
||||
|
||||
public focus() {
|
||||
this.accountList.domFocus();
|
||||
}
|
||||
|
||||
public updateAccounts(accounts: sqlops.Account[]) {
|
||||
this.accountList.splice(0, this.accountList.length, accounts);
|
||||
}
|
||||
|
||||
public setSelection(indexes: number[]) {
|
||||
this.accountList.setSelection(indexes);
|
||||
}
|
||||
|
||||
public getActions(): IAction[] {
|
||||
return [this.instantiationService.createInstance(
|
||||
AddAccountAction,
|
||||
this.options.id
|
||||
)];
|
||||
}
|
||||
}
|
||||
|
||||
export interface IProviderViewUiComponent {
|
||||
view: FixedListView<sqlops.Account>;
|
||||
view: AccountPanel;
|
||||
addAccountAction: AddAccountAction;
|
||||
}
|
||||
|
||||
@@ -46,13 +98,10 @@ export class AccountDialog extends Modal {
|
||||
public viewModel: AccountViewModel;
|
||||
|
||||
// MEMBER VARIABLES ////////////////////////////////////////////////////
|
||||
private _providerViews: { [providerId: string]: IProviderViewUiComponent } = {};
|
||||
private _providerViewsMap = new Map<string, IProviderViewUiComponent>();
|
||||
|
||||
private _closeButton: Button;
|
||||
private _addAccountButton: Button;
|
||||
private _delegate: AccountListDelegate;
|
||||
private _accountRenderer: AccountListRenderer;
|
||||
private _actionRunner: ActionRunner;
|
||||
private _splitView: SplitView;
|
||||
private _container: HTMLElement;
|
||||
private _splitViewContainer: HTMLElement;
|
||||
@@ -68,10 +117,10 @@ export class AccountDialog extends Modal {
|
||||
constructor(
|
||||
@IPartService partService: IPartService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IListService private _listService: IListService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@IContextMenuService private _contextMenuService: IContextMenuService,
|
||||
@IKeybindingService private _keybindingService: IKeybindingService,
|
||||
@IConfigurationService private _configurationService: IConfigurationService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IClipboardService clipboardService: IClipboardService
|
||||
@@ -86,11 +135,6 @@ export class AccountDialog extends Modal {
|
||||
contextKeyService,
|
||||
{ hasSpinner: true }
|
||||
);
|
||||
let self = this;
|
||||
|
||||
this._delegate = new AccountListDelegate(AccountDialog.ACCOUNTLIST_HEIGHT);
|
||||
this._accountRenderer = this._instantiationService.createInstance(AccountListRenderer);
|
||||
this._actionRunner = new ActionRunner();
|
||||
|
||||
// Setup the event emitters
|
||||
this._onAddAccountErrorEmitter = new Emitter<string>();
|
||||
@@ -98,28 +142,25 @@ export class AccountDialog extends Modal {
|
||||
|
||||
// Create the view model and wire up the events
|
||||
this.viewModel = this._instantiationService.createInstance(AccountViewModel);
|
||||
this.viewModel.addProviderEvent(arg => { self.addProvider(arg); });
|
||||
this.viewModel.removeProviderEvent(arg => { self.removeProvider(arg); });
|
||||
this.viewModel.updateAccountListEvent(arg => { self.updateProviderAccounts(arg); });
|
||||
this.viewModel.addProviderEvent(arg => { this.addProvider(arg); });
|
||||
this.viewModel.removeProviderEvent(arg => { this.removeProvider(arg); });
|
||||
this.viewModel.updateAccountListEvent(arg => { this.updateProviderAccounts(arg); });
|
||||
|
||||
// Load the initial contents of the view model
|
||||
this.viewModel.initialize()
|
||||
.then(addedProviders => {
|
||||
for (let addedProvider of addedProviders) {
|
||||
self.addProvider(addedProvider);
|
||||
this.addProvider(addedProvider);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// MODAL OVERRIDE METHODS //////////////////////////////////////////////
|
||||
protected layout(height?: number): void {
|
||||
// Ignore height as it's a subcomponent being laid out
|
||||
this._splitView.layout(DOM.getContentHeight(this._container));
|
||||
}
|
||||
|
||||
public render() {
|
||||
let self = this;
|
||||
|
||||
super.render();
|
||||
attachModalDialogStyler(this, this._themeService);
|
||||
this._closeButton = this.addFooterButton(localize('accountDialog.close', 'Close'), () => this.close());
|
||||
@@ -128,7 +169,7 @@ export class AccountDialog extends Modal {
|
||||
|
||||
protected renderBody(container: HTMLElement) {
|
||||
this._container = container;
|
||||
this._splitViewContainer = DOM.$('div.account-view');
|
||||
this._splitViewContainer = DOM.$('div.account-view.monaco-panel-view');
|
||||
DOM.append(container, this._splitViewContainer);
|
||||
this._splitView = new SplitView(this._splitViewContainer);
|
||||
|
||||
@@ -143,7 +184,7 @@ export class AccountDialog extends Modal {
|
||||
this._addAccountButton = new Button(buttonSection);
|
||||
this._addAccountButton.label = localize('accountDialog.addConnection', 'Add an account');
|
||||
this._register(this._addAccountButton.onDidClick(() => {
|
||||
(<IProviderViewUiComponent>Object.values(this._providerViews)[0]).addAccountAction.run();
|
||||
(<IProviderViewUiComponent>values(this._providerViewsMap)[0]).addAccountAction.run();
|
||||
}));
|
||||
|
||||
DOM.append(container, this._noaccountViewContainer);
|
||||
@@ -189,20 +230,19 @@ export class AccountDialog extends Modal {
|
||||
private showSplitView() {
|
||||
this._splitViewContainer.hidden = false;
|
||||
this._noaccountViewContainer.hidden = true;
|
||||
let views = this._splitView.getViews();
|
||||
if (views && views.length > 0) {
|
||||
let firstView = views[0];
|
||||
if (firstView instanceof FixedListView) {
|
||||
firstView.list.setSelection([0]);
|
||||
firstView.list.domFocus();
|
||||
if (values(this._providerViewsMap).length > 0) {
|
||||
let firstView = values(this._providerViewsMap)[0];
|
||||
if (firstView instanceof AccountPanel) {
|
||||
firstView.setSelection([0]);
|
||||
firstView.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private isEmptyLinkedAccount(): boolean {
|
||||
for (var providerId in this._providerViews) {
|
||||
var listView = this._providerViews[providerId].view;
|
||||
if (listView && listView.list.length > 0) {
|
||||
for (let provider of values(this._providerViewsMap)) {
|
||||
let listView = provider.view;
|
||||
if (listView && listView.length > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -211,23 +251,21 @@ export class AccountDialog extends Modal {
|
||||
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
for (let key in this._providerViews) {
|
||||
if (this._providerViews[key].addAccountAction) {
|
||||
this._providerViews[key].addAccountAction.dispose();
|
||||
for (let provider of values(this._providerViewsMap)) {
|
||||
if (provider.addAccountAction) {
|
||||
provider.addAccountAction.dispose();
|
||||
}
|
||||
if (this._providerViews[key].view) {
|
||||
this._providerViews[key].view.dispose();
|
||||
if (provider.view) {
|
||||
provider.view.dispose();
|
||||
}
|
||||
delete this._providerViews[key];
|
||||
}
|
||||
}
|
||||
|
||||
// PRIVATE HELPERS /////////////////////////////////////////////////////
|
||||
private addProvider(newProvider: AccountProviderAddedEventParams) {
|
||||
let self = this;
|
||||
|
||||
// Skip adding the provider if it already exists
|
||||
if (this._providerViews[newProvider.addedProvider.id]) {
|
||||
if (this._providerViewsMap.get(newProvider.addedProvider.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -237,37 +275,35 @@ export class AccountDialog extends Modal {
|
||||
AddAccountAction,
|
||||
newProvider.addedProvider.id
|
||||
);
|
||||
addAccountAction.addAccountCompleteEvent(() => { self.hideSpinner(); });
|
||||
addAccountAction.addAccountErrorEvent(msg => { self._onAddAccountErrorEmitter.fire(msg); });
|
||||
addAccountAction.addAccountStartEvent(() => { self.showSpinner(); });
|
||||
addAccountAction.addAccountCompleteEvent(() => { this.hideSpinner(); });
|
||||
addAccountAction.addAccountErrorEvent(msg => { this._onAddAccountErrorEmitter.fire(msg); });
|
||||
addAccountAction.addAccountStartEvent(() => { this.showSpinner(); });
|
||||
|
||||
// Create a fixed list view for the account provider
|
||||
let providerViewContainer = DOM.$('.provider-view');
|
||||
let accountList = new List<sqlops.Account>(providerViewContainer, this._delegate, [this._accountRenderer]);
|
||||
let providerView = new FixedListView<sqlops.Account>(
|
||||
undefined,
|
||||
false,
|
||||
newProvider.addedProvider.displayName,
|
||||
accountList,
|
||||
providerViewContainer,
|
||||
22,
|
||||
[addAccountAction],
|
||||
this._actionRunner,
|
||||
this._contextMenuService,
|
||||
let providerView = new AccountPanel(
|
||||
{
|
||||
id: newProvider.addedProvider.id,
|
||||
title: newProvider.addedProvider.displayName,
|
||||
ariaHeaderLabel: newProvider.addedProvider.displayName
|
||||
},
|
||||
this._keybindingService,
|
||||
this._contextMenuService,
|
||||
this._configurationService,
|
||||
this._instantiationService,
|
||||
this._themeService
|
||||
);
|
||||
|
||||
// Append the list view to the split view
|
||||
this._splitView.addView(providerView);
|
||||
this._register(attachListStyler(accountList, this._themeService));
|
||||
attachPanelStyler(providerView, this._themeService);
|
||||
|
||||
const insertIndex = this._splitView.length;
|
||||
// Append the list view to the split view
|
||||
this._splitView.addView(providerView, Sizing.Distribute, insertIndex);
|
||||
providerView.render();
|
||||
providerView.index = insertIndex;
|
||||
|
||||
let listService = <ListService>this._listService;
|
||||
this._register(listService.register(accountList));
|
||||
this._splitView.layout(DOM.getContentHeight(this._container));
|
||||
|
||||
// Set the initial items of the list
|
||||
providerView.updateList(newProvider.initialAccounts);
|
||||
providerView.updateAccounts(newProvider.initialAccounts);
|
||||
|
||||
if (newProvider.initialAccounts.length > 0 && this._splitViewContainer.hidden) {
|
||||
this.showSplitView();
|
||||
@@ -276,31 +312,31 @@ export class AccountDialog extends Modal {
|
||||
this.layout();
|
||||
|
||||
// Store the view for the provider and action
|
||||
this._providerViews[newProvider.addedProvider.id] = { view: providerView, addAccountAction: addAccountAction };
|
||||
this._providerViewsMap.set(newProvider.addedProvider.id, { view: providerView, addAccountAction: addAccountAction });
|
||||
}
|
||||
|
||||
private removeProvider(removedProvider: sqlops.AccountProviderMetadata) {
|
||||
// Skip removing the provider if it doesn't exist
|
||||
let providerView = this._providerViews[removedProvider.id];
|
||||
let providerView = this._providerViewsMap.get(removedProvider.id);
|
||||
if (!providerView || !providerView.view) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the list view from the split view
|
||||
this._splitView.removeView(providerView.view);
|
||||
this._splitView.removeView(providerView.view.index);
|
||||
this._splitView.layout(DOM.getContentHeight(this._container));
|
||||
|
||||
// Remove the list view from our internal map
|
||||
delete this._providerViews[removedProvider.id];
|
||||
this._providerViewsMap.delete(removedProvider.id);
|
||||
this.layout();
|
||||
}
|
||||
|
||||
private updateProviderAccounts(args: UpdateAccountListEventParams) {
|
||||
let providerMapping = this._providerViews[args.providerId];
|
||||
let providerMapping = this._providerViewsMap.get(args.providerId);
|
||||
if (!providerMapping || !providerMapping.view) {
|
||||
return;
|
||||
}
|
||||
providerMapping.view.updateList(args.accountList);
|
||||
providerMapping.view.updateAccounts(args.accountList);
|
||||
|
||||
if (args.accountList.length > 0 && this._splitViewContainer.hidden) {
|
||||
this.showSplitView();
|
||||
|
||||
@@ -13,8 +13,6 @@ import { localize } from 'vs/nls';
|
||||
import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||
|
||||
export class AdvancedPropertiesController {
|
||||
private _container: HTMLElement;
|
||||
|
||||
private _advancedDialog: OptionsDialog;
|
||||
private _options: { [name: string]: any };
|
||||
|
||||
@@ -30,7 +28,6 @@ export class AdvancedPropertiesController {
|
||||
|
||||
public showDialog(providerOptions: sqlops.ConnectionOption[], container: HTMLElement, options: { [name: string]: any }): void {
|
||||
this._options = options;
|
||||
this._container = container;
|
||||
var serviceOptions = providerOptions.map(option => AdvancedPropertiesController.connectionOptionToServiceOption(option));
|
||||
this.advancedDialog.open(serviceOptions, this._options);
|
||||
}
|
||||
@@ -38,8 +35,7 @@ export class AdvancedPropertiesController {
|
||||
public get advancedDialog() {
|
||||
if (!this._advancedDialog) {
|
||||
this._advancedDialog = this._instantiationService.createInstance(
|
||||
OptionsDialog, localize('connectionAdvancedProperties', 'Advanced Properties'), TelemetryKeys.ConnectionAdvancedProperties, { hasBackButton: true });
|
||||
this._advancedDialog.cancelLabel = localize('advancedProperties.discard', 'Discard');
|
||||
OptionsDialog, localize('connectionAdvancedProperties', 'Advanced Properties'), TelemetryKeys.ConnectionAdvancedProperties, { hasBackButton: true, cancelLabel: localize('advancedProperties.discard', 'Discard') });
|
||||
this._advancedDialog.onCloseEvent(() => this._onCloseAdvancedProperties());
|
||||
this._advancedDialog.onOk(() => this.handleOnOk());
|
||||
this._advancedDialog.render();
|
||||
|
||||
@@ -27,9 +27,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { Button } from 'sql/base/browser/ui/button/button';
|
||||
import { Modal } from 'sql/base/browser/ui/modal/modal';
|
||||
import { attachModalDialogStyler, attachButtonStyler } from 'sql/common/theme/styler';
|
||||
import { FixedListView } from 'sql/platform/views/fixedListView';
|
||||
import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||
import { Orientation } from 'sql/base/browser/ui/splitview/splitview';
|
||||
import { NewDashboardTabViewModel, IDashboardUITab } from 'sql/parts/dashboard/newDashboardTabDialog/newDashboardTabViewModel';
|
||||
import { IDashboardTab } from 'sql/platform/dashboard/common/dashboardRegistry';
|
||||
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
|
||||
@@ -104,8 +102,6 @@ export class NewDashboardTabDialog extends Modal {
|
||||
private _addNewTabButton: Button;
|
||||
private _cancelButton: Button;
|
||||
private _extensionList: List<IDashboardUITab>;
|
||||
private _extensionTabView: FixedListView<IDashboardUITab>;
|
||||
private _container: HTMLElement;
|
||||
private _extensionViewContainer: HTMLElement;
|
||||
private _noExtensionViewContainer: HTMLElement;
|
||||
|
||||
@@ -121,10 +117,6 @@ export class NewDashboardTabDialog extends Modal {
|
||||
constructor(
|
||||
@IPartService partService: IPartService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IListService private _listService: IListService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@IContextMenuService private _contextMenuService: IContextMenuService,
|
||||
@IKeybindingService private _keybindingService: IKeybindingService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IClipboardService clipboardService: IClipboardService
|
||||
@@ -150,7 +142,7 @@ export class NewDashboardTabDialog extends Modal {
|
||||
|
||||
// MODAL OVERRIDE METHODS //////////////////////////////////////////////
|
||||
protected layout(height?: number): void {
|
||||
// Nothing currently laid out in this class
|
||||
this._extensionList.layout(height);
|
||||
}
|
||||
|
||||
public render() {
|
||||
@@ -163,7 +155,6 @@ export class NewDashboardTabDialog extends Modal {
|
||||
}
|
||||
|
||||
protected renderBody(container: HTMLElement) {
|
||||
this._container = container;
|
||||
this._extensionViewContainer = DOM.$('div.extension-view');
|
||||
DOM.append(container, this._extensionViewContainer);
|
||||
|
||||
@@ -182,19 +173,6 @@ export class NewDashboardTabDialog extends Modal {
|
||||
let delegate = new ExtensionListDelegate(NewDashboardTabDialog.EXTENSIONLIST_HEIGHT);
|
||||
let extensionTabRenderer = new ExtensionListRenderer();
|
||||
this._extensionList = new List<IDashboardUITab>(extensionTabViewContainer, delegate, [extensionTabRenderer]);
|
||||
this._extensionTabView = new FixedListView<IDashboardUITab>(
|
||||
undefined,
|
||||
false,
|
||||
localize('allFeatures', 'All features'),
|
||||
this._extensionList,
|
||||
extensionTabViewContainer,
|
||||
22,
|
||||
[],
|
||||
undefined,
|
||||
this._contextMenuService,
|
||||
this._keybindingService,
|
||||
this._themeService
|
||||
);
|
||||
|
||||
this._extensionList.onMouseDblClick(e => this.onAccept());
|
||||
this._extensionList.onKeyDown(e => {
|
||||
@@ -206,13 +184,9 @@ export class NewDashboardTabDialog extends Modal {
|
||||
}
|
||||
});
|
||||
|
||||
this._extensionTabView.render(container, Orientation.VERTICAL);
|
||||
this._extensionTabView.hideHeader();
|
||||
DOM.append(container, extensionTabViewContainer);
|
||||
|
||||
this._register(attachListStyler(this._extensionList, this._themeService));
|
||||
|
||||
let listService = <ListService>this._listService;
|
||||
this._register(listService.register(this._extensionList));
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
@@ -252,7 +226,7 @@ export class NewDashboardTabDialog extends Modal {
|
||||
}
|
||||
|
||||
private onUpdateTabList(tabs: IDashboardUITab[]) {
|
||||
this._extensionTabView.updateList(tabs);
|
||||
this._extensionList.splice(0, this._extensionList.length, tabs);
|
||||
this.layout();
|
||||
if (this._extensionList.length > 0) {
|
||||
this._extensionViewContainer.hidden = false;
|
||||
|
||||
@@ -13,27 +13,25 @@ import { ListBox } from 'sql/base/browser/ui/listBox/listBox';
|
||||
import { ModalFooterStyle } from 'sql/base/browser/ui/modal/modal';
|
||||
import { CategoryView } from 'sql/base/browser/ui/modal/optionsDialog';
|
||||
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox';
|
||||
import { SplitView } from 'sql/base/browser/ui/splitview/splitview';
|
||||
import { attachButtonStyler, attachListBoxStyler, attachInputBoxStyler, attachSelectBoxStyler, attachCheckboxStyler } from 'sql/common/theme/styler';
|
||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
import * as BackupConstants from 'sql/parts/disasterRecovery/backup/constants';
|
||||
import { IBackupService, IBackupUiService, TaskExecutionMode } from 'sql/parts/disasterRecovery/backup/common/backupService';
|
||||
import FileValidationConstants = require('sql/parts/fileBrowser/common/fileValidationServiceConstants');
|
||||
import { IDashboardComponentParams } from 'sql/services/bootstrap/bootstrapParams';
|
||||
import { IFileBrowserDialogController } from 'sql/parts/fileBrowser/common/interfaces';
|
||||
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
|
||||
import { ScrollableSplitView } from 'sql/base/browser/ui/scrollableSplitview/scrollableSplitview';
|
||||
|
||||
import { MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import * as lifecycle from 'vs/base/common/lifecycle';
|
||||
import { localize } from 'vs/nls';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
export const BACKUP_SELECTOR: string = 'backup-component';
|
||||
|
||||
@@ -207,7 +205,8 @@ export class BackupComponent {
|
||||
@Inject(IBackupUiService) private _backupUiService: IBackupUiService,
|
||||
@Inject(IBackupService) private _backupService: IBackupService,
|
||||
@Inject(IClipboardService) private clipboardService: IClipboardService,
|
||||
@Inject(IConnectionManagementService) private connectionManagementService: IConnectionManagementService
|
||||
@Inject(IConnectionManagementService) private connectionManagementService: IConnectionManagementService,
|
||||
@Inject(IInstantiationService) private instantiationService: IInstantiationService
|
||||
) {
|
||||
this._backupUiService.onShowBackupEvent((param) => this.onGetBackupConfigInfo(param));
|
||||
}
|
||||
@@ -338,10 +337,10 @@ export class BackupComponent {
|
||||
|
||||
ngAfterViewInit() {
|
||||
// Set category view for advanced options. This should be defined in ngAfterViewInit so that it correctly calculates the text height after data binding.
|
||||
var splitview = new SplitView(this.advancedOptionElement.nativeElement);
|
||||
var splitview = new ScrollableSplitView(this.advancedOptionElement.nativeElement);
|
||||
var advancedBodySize = DOM.getTotalHeight(this.advancedOptionBodyElement.nativeElement);
|
||||
var categoryView = new CategoryView(LocalizedStrings.ADVANCED_CONFIGURATION, this.advancedOptionBodyElement.nativeElement, true, advancedBodySize, this._advancedHeaderSize);
|
||||
splitview.addView(categoryView);
|
||||
var categoryView = this.instantiationService.createInstance(CategoryView, this.advancedOptionBodyElement.nativeElement, advancedBodySize, { title: LocalizedStrings.ADVANCED_CONFIGURATION, id: LocalizedStrings.ADVANCED_CONFIGURATION, ariaHeaderLabel: LocalizedStrings.ADVANCED_CONFIGURATION });
|
||||
splitview.addView(categoryView, 0);
|
||||
splitview.layout(advancedBodySize + this._advancedHeaderSize);
|
||||
|
||||
this._backupUiService.onShowBackupDialog();
|
||||
|
||||
@@ -8,25 +8,25 @@ import { Button } from 'sql/base/browser/ui/button/button';
|
||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
import { Modal } from 'sql/base/browser/ui/modal/modal';
|
||||
import { IInsightsConfigDetails } from 'sql/parts/dashboard/widgets/insights/interfaces';
|
||||
import { attachButtonStyler, attachModalDialogStyler, attachTableStyler } from 'sql/common/theme/styler';
|
||||
import { attachButtonStyler, attachModalDialogStyler, attachTableStyler, attachPanelStyler } from 'sql/common/theme/styler';
|
||||
import { TaskRegistry } from 'sql/platform/tasks/common/tasks';
|
||||
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
|
||||
import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||
import { IInsightsDialogModel, ListResource, IInsightDialogActionContext, insertValueRegex } from 'sql/parts/insights/common/interfaces';
|
||||
import { TableCollapsibleView } from 'sql/base/browser/ui/table/tableView';
|
||||
import { TableDataView } from 'sql/base/browser/ui/table/tableDataView';
|
||||
import { RowSelectionModel } from 'sql/base/browser/ui/table/plugins/rowSelectionModel.plugin';
|
||||
import { error } from 'sql/base/common/log';
|
||||
import { Table } from 'sql/base/browser/ui/table/table';
|
||||
import { CopyInsightDialogSelectionAction } from 'sql/parts/insights/common/insightDialogActions';
|
||||
import { SplitView, ViewSizing } from 'sql/base/browser/ui/splitview/splitview';
|
||||
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
|
||||
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
|
||||
import { IDisposableDataProvider } from 'sql/base/browser/ui/table/interfaces';
|
||||
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IListService } from 'vs/platform/list/browser/listService';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
@@ -38,12 +38,45 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { MenuRegistry, ExecuteCommandAction } from 'vs/platform/actions/common/actions';
|
||||
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
|
||||
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
|
||||
import { SplitView, Orientation, Sizing } from 'vs/base/browser/ui/splitview/splitview';
|
||||
import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
|
||||
const labelDisplay = nls.localize("insights.item", "Item");
|
||||
const valueDisplay = nls.localize("insights.value", "Value");
|
||||
|
||||
class InsightTableView<T> extends ViewletPanel {
|
||||
private _table: Table<T>;
|
||||
public get table(): Table<T> {
|
||||
return this._table;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private columns: Slick.Column<T>[],
|
||||
private data: IDisposableDataProvider<T> | Array<T>,
|
||||
private tableOptions: Slick.GridOptions<T>,
|
||||
options: IViewletPanelOptions,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IConfigurationService configurationService: IConfigurationService
|
||||
) {
|
||||
super(options, keybindingService, contextMenuService, configurationService);
|
||||
}
|
||||
|
||||
protected renderBody(container: HTMLElement): void {
|
||||
this._table = new Table(container, {
|
||||
columns: this.columns,
|
||||
dataProvider: this.data
|
||||
}, this.tableOptions);
|
||||
}
|
||||
|
||||
protected layoutBody(size: number): void {
|
||||
this._table.layout(size, Orientation.VERTICAL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function stateFormatter(row: number, cell: number, value: any, columnDef: Slick.Column<ListResource>, resource: ListResource): string {
|
||||
// template
|
||||
const icon = DOM.$('span.icon-span');
|
||||
@@ -126,7 +159,6 @@ export class InsightsDialogView extends Modal {
|
||||
private _model: IInsightsDialogModel,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IListService private _listService: IListService,
|
||||
@IPartService partService: IPartService,
|
||||
@IContextMenuService private _contextMenuService: IContextMenuService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@@ -167,6 +199,7 @@ export class InsightsDialogView extends Modal {
|
||||
|
||||
protected renderBody(container: HTMLElement) {
|
||||
this._container = container;
|
||||
container.classList.add('monaco-panel-view');
|
||||
|
||||
this._splitView = new SplitView(container);
|
||||
|
||||
@@ -175,11 +208,14 @@ export class InsightsDialogView extends Modal {
|
||||
|
||||
this._topTableData = new TableDataView();
|
||||
this._bottomTableData = new TableDataView();
|
||||
let topTableView = new TableCollapsibleView(itemsHeaderTitle, { sizing: ViewSizing.Flexible, ariaHeaderLabel: itemsHeaderTitle }, this._topTableData, this._topColumns, { forceFitColumns: true });
|
||||
let topTableView = this._instantiationService.createInstance(InsightTableView, this._topColumns, this._topTableData, { forceFitColumns: true }, { id: 'insights.top', title: itemsHeaderTitle, ariaHeaderLabel: itemsHeaderTitle }) as InsightTableView<ListResource>;
|
||||
topTableView.render();
|
||||
attachPanelStyler(topTableView, this._themeService);
|
||||
this._topTable = topTableView.table;
|
||||
topTableView.addContainerClass('insights');
|
||||
this._topTable.setSelectionModel(new RowSelectionModel<ListResource>());
|
||||
let bottomTableView = new TableCollapsibleView(itemsDetailHeaderTitle, { sizing: ViewSizing.Flexible, ariaHeaderLabel: itemsDetailHeaderTitle }, this._bottomTableData, this._bottomColumns, { forceFitColumns: true });
|
||||
let bottomTableView = this._instantiationService.createInstance(InsightTableView, this._bottomColumns, this._bottomTableData, { forceFitColumns: true }, { id: 'insights.bottom', title: itemsDetailHeaderTitle, ariaHeaderLabel: itemsDetailHeaderTitle }) as InsightTableView<ListResource>;
|
||||
bottomTableView.render();
|
||||
attachPanelStyler(bottomTableView, this._themeService);
|
||||
this._bottomTable = bottomTableView.table;
|
||||
this._bottomTable.setSelectionModel(new RowSelectionModel<ListResource>());
|
||||
|
||||
@@ -193,12 +229,9 @@ export class InsightsDialogView extends Modal {
|
||||
|
||||
this._bottomTableData.clear();
|
||||
this._bottomTableData.push(resourceArray);
|
||||
// this table view has to be collapsed and expanded
|
||||
// because the initial expand doesn't have the
|
||||
// loaded data
|
||||
if (bottomTableView.isExpanded()) {
|
||||
bottomTableView.collapse();
|
||||
bottomTableView.expand();
|
||||
bottomTableView.setExpanded(false);
|
||||
bottomTableView.setExpanded(true);
|
||||
}
|
||||
this._enableTaskButtons(true);
|
||||
} else {
|
||||
@@ -224,8 +257,8 @@ export class InsightsDialogView extends Modal {
|
||||
});
|
||||
}));
|
||||
|
||||
this._splitView.addView(topTableView);
|
||||
this._splitView.addView(bottomTableView);
|
||||
this._splitView.addView(topTableView, Sizing.Distribute);
|
||||
this._splitView.addView(bottomTableView, Sizing.Distribute);
|
||||
|
||||
this._register(attachTableStyler(this._topTable, this._themeService));
|
||||
this._register(attachTableStyler(this._bottomTable, this._themeService));
|
||||
@@ -344,7 +377,6 @@ export class InsightsDialogView extends Modal {
|
||||
this.hide();
|
||||
dispose(this._taskButtonDisposables);
|
||||
this._taskButtonDisposables = [];
|
||||
this.dispose();
|
||||
}
|
||||
|
||||
protected onClose(e: StandardKeyboardEvent) {
|
||||
|
||||
@@ -129,7 +129,7 @@ export class InsightsDialogController {
|
||||
} catch (e) {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
this._queryRunner = this._instantiationService.createInstance(QueryRunner, this._connectionUri, undefined);
|
||||
this._queryRunner = this._instantiationService.createInstance(QueryRunner, this._connectionUri);
|
||||
this.addQueryEventListeners(this._queryRunner);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ProfilerInput } from './profilerInput';
|
||||
|
||||
import { TabbedPanel } from 'sql/base/browser/ui/panel/panel';
|
||||
import { Table } from 'sql/base/browser/ui/table/table';
|
||||
import { TableDataView } from 'sql/base/browser/ui/table/tableDataView';
|
||||
@@ -17,15 +16,8 @@ import * as Actions from 'sql/parts/profiler/contrib/profilerActions';
|
||||
import { CONTEXT_PROFILER_EDITOR, PROFILER_TABLE_COMMAND_SEARCH } from './interfaces';
|
||||
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox';
|
||||
import { textFormatter } from 'sql/parts/grid/services/sharedServices';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IWorkbenchThemeService, VS_DARK_THEME, VS_HC_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ProfilerResourceEditor } from './profilerResourceEditor';
|
||||
import { SplitView, View, Orientation, IViewOptions } from 'sql/base/browser/ui/splitview/splitview';
|
||||
|
||||
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
@@ -39,59 +31,77 @@ import { Command } from 'vs/editor/browser/editorExtensions';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { ContextKeyExpr, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { CommonFindController, FindStartFocusAction } from 'vs/editor/contrib/find/findController';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
|
||||
import { DARK, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IView, SplitView, Sizing } from 'vs/base/browser/ui/splitview/splitview';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IWorkbenchThemeService, VS_DARK_THEME, VS_HC_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { clamp } from 'vs/base/common/numbers';
|
||||
|
||||
class BasicView extends View {
|
||||
private _previousSize: number;
|
||||
private _collapsed: boolean;
|
||||
public headerSize: number;
|
||||
class BasicView implements IView {
|
||||
public get element(): HTMLElement {
|
||||
return this._element;
|
||||
}
|
||||
private _onDidChange = new Emitter<number>();
|
||||
public readonly onDidChange: Event<number> = this._onDidChange.event;
|
||||
|
||||
private _collapsed = false;
|
||||
private size: number;
|
||||
private previousSize: number;
|
||||
private _minimumSize: number;
|
||||
public get minimumSize(): number {
|
||||
return this._minimumSize;
|
||||
}
|
||||
|
||||
private _maximumSize: number;
|
||||
public get maximumSize(): number {
|
||||
return this._maximumSize;
|
||||
}
|
||||
|
||||
constructor(
|
||||
initialSize: number,
|
||||
private _defaultMinimumSize: number,
|
||||
private _defaultMaximumSize: number,
|
||||
private _layout: (size: number) => void,
|
||||
private _element: HTMLElement,
|
||||
private _focus: () => void,
|
||||
private _layout: (size: number, orientation: Orientation) => void,
|
||||
opts: IViewOptions
|
||||
private options: { headersize?: number } = {}
|
||||
) {
|
||||
super(initialSize, opts);
|
||||
this._previousSize = initialSize;
|
||||
this._minimumSize = _defaultMinimumSize;
|
||||
this._maximumSize = _defaultMaximumSize;
|
||||
}
|
||||
|
||||
render(container: HTMLElement, orientation: Orientation): void {
|
||||
container.appendChild(this._element);
|
||||
public layout(size: number): void {
|
||||
this.size = size;
|
||||
this._layout(size);
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
this._focus();
|
||||
}
|
||||
|
||||
layout(size: number, orientation: Orientation): void {
|
||||
if (!this.collapsed) {
|
||||
this._previousSize = size;
|
||||
}
|
||||
this._layout(size, orientation);
|
||||
}
|
||||
|
||||
set collapsed(val: boolean) {
|
||||
this._collapsed = val === false ? false : true;
|
||||
if (this.collapsed) {
|
||||
this._previousSize = this.size;
|
||||
this.setFixed(this.headerSize);
|
||||
} else {
|
||||
// Enforce the min height for the view when user is doing expand operation,
|
||||
// to make sure the view has a reasonable height.
|
||||
const minHeight = 200;
|
||||
this.setFlexible(Math.max(this._previousSize, minHeight));
|
||||
public set collapsed(val: boolean) {
|
||||
if (val !== this._collapsed && this.options.headersize) {
|
||||
this._collapsed = val;
|
||||
if (this.collapsed) {
|
||||
this.previousSize = this.size;
|
||||
this._minimumSize = this.options.headersize;
|
||||
this._maximumSize = this.options.headersize;
|
||||
this._onDidChange.fire();
|
||||
} else {
|
||||
this._maximumSize = this._defaultMaximumSize;
|
||||
this._minimumSize = this._defaultMinimumSize;
|
||||
this._onDidChange.fire(clamp(this.previousSize, this.minimumSize, this.maximumSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get collapsed(): boolean {
|
||||
public get collapsed(): boolean {
|
||||
return this._collapsed;
|
||||
}
|
||||
}
|
||||
@@ -146,14 +156,13 @@ export class ProfilerEditor extends BaseEditor {
|
||||
@IProfilerService private _profilerService: IProfilerService,
|
||||
@IContextKeyService private _contextKeyService: IContextKeyService,
|
||||
@IContextViewService private _contextViewService: IContextViewService,
|
||||
@IEditorGroupsService private _editorGroupService: IEditorGroupsService,
|
||||
@IEditorService private _editorService: IEditorService
|
||||
@IEditorService editorService: IEditorService
|
||||
) {
|
||||
super(ProfilerEditor.ID, telemetryService, themeService);
|
||||
this._profilerEditorContextKey = CONTEXT_PROFILER_EDITOR.bindTo(this._contextKeyService);
|
||||
|
||||
if (_editorService) {
|
||||
_editorService.overrideOpenEditor((editor, options, group) => {
|
||||
if (editorService) {
|
||||
editorService.overrideOpenEditor((editor, options, group) => {
|
||||
if (this.isVisible() && (editor !== this.input || group !== this.group)) {
|
||||
this.saveEditorViewState();
|
||||
}
|
||||
@@ -178,21 +187,19 @@ export class ProfilerEditor extends BaseEditor {
|
||||
let paneContainer = this._createProfilerPane();
|
||||
this._splitView.addView(new BasicView(
|
||||
300,
|
||||
tableContainer,
|
||||
() => this._profilerTableEditor.focus(),
|
||||
Number.POSITIVE_INFINITY,
|
||||
size => this._profilerTableEditor.layout(new DOM.Dimension(parseFloat(DOM.getComputedStyle(this._body).width), size)),
|
||||
{}
|
||||
));
|
||||
tableContainer
|
||||
), Sizing.Distribute);
|
||||
|
||||
this._panelView = new BasicView(
|
||||
300,
|
||||
paneContainer,
|
||||
() => this._tabbedPanel.focus(),
|
||||
Number.POSITIVE_INFINITY,
|
||||
size => this._tabbedPanel.layout(new DOM.Dimension(DOM.getTotalWidth(this._body), size)),
|
||||
{ minimumSize: 35 }
|
||||
paneContainer,
|
||||
{ headersize: 35 }
|
||||
);
|
||||
this._panelView.headerSize = 35;
|
||||
this._splitView.addView(this._panelView);
|
||||
this._splitView.addView(this._panelView, Sizing.Distribute);
|
||||
}
|
||||
|
||||
private _createHeader(): void {
|
||||
@@ -426,7 +433,6 @@ export class ProfilerEditor extends BaseEditor {
|
||||
isPanelCollapsed: true
|
||||
});
|
||||
this._profilerTableEditor.updateState();
|
||||
this._splitView.layout();
|
||||
this._profilerTableEditor.focus();
|
||||
if (savedViewState) {
|
||||
this._profilerTableEditor.restoreViewState(savedViewState);
|
||||
|
||||
@@ -33,7 +33,7 @@ export class ProfilerState implements IDisposable {
|
||||
private _isPaused: boolean;
|
||||
private _isStopped: boolean;
|
||||
private _autoscroll: boolean;
|
||||
private _isPanelCollapsed: boolean;
|
||||
private _isPanelCollapsed = true;
|
||||
private _eventEmitter: EventEmitter;
|
||||
|
||||
public get isConnected(): boolean { return this._isConnected; }
|
||||
|
||||
@@ -10,7 +10,7 @@ import { attachTableStyler } from 'sql/common/theme/styler';
|
||||
import QueryRunner from 'sql/parts/query/execution/queryRunner';
|
||||
import { VirtualizedCollection, AsyncDataProvider } from 'sql/base/browser/ui/table/asyncDataView';
|
||||
import { Table } from 'sql/base/browser/ui/table/table';
|
||||
import { ScrollableSplitView } from 'sql/base/browser/ui/scrollableSplitview/scrollableSplitview';
|
||||
import { ScrollableSplitView, IView } from 'sql/base/browser/ui/scrollableSplitview/scrollableSplitview';
|
||||
import { MouseWheelSupport } from 'sql/base/browser/ui/table/plugins/mousewheelTableScroll.plugin';
|
||||
import { AutoColumnSize } from 'sql/base/browser/ui/table/plugins/autoSizeColumns.plugin';
|
||||
import { SaveFormat } from 'sql/parts/grid/common/interfaces';
|
||||
@@ -34,7 +34,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet';
|
||||
import { isUndefinedOrNull } from 'vs/base/common/types';
|
||||
import { range } from 'vs/base/common/arrays';
|
||||
import { Orientation, IView } from 'vs/base/browser/ui/splitview/splitview';
|
||||
import { Orientation } from 'vs/base/browser/ui/splitview/splitview';
|
||||
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { $ } from 'vs/base/browser/builder';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
@@ -476,10 +476,6 @@ class GridTable<T> extends Disposable implements IView {
|
||||
this.scrolled = false;
|
||||
}
|
||||
|
||||
public render(container: HTMLElement, orientation: Orientation): void {
|
||||
container.appendChild(this.container);
|
||||
}
|
||||
|
||||
private build(): void {
|
||||
let tableContainer = document.createElement('div');
|
||||
tableContainer.style.display = 'inline-block';
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import types = require('vs/base/common/types');
|
||||
import objects = require('vs/base/common/objects');
|
||||
|
||||
import {
|
||||
ICollapsibleViewOptions, AbstractCollapsibleView, ViewSizing, CollapsibleState
|
||||
} from 'sql/base/browser/ui/splitview/splitview';
|
||||
|
||||
export interface IFixedCollapsibleViewOptions extends ICollapsibleViewOptions {
|
||||
expandedBodySize?: number;
|
||||
}
|
||||
|
||||
export abstract class FixedCollapsibleView extends AbstractCollapsibleView {
|
||||
private _expandedBodySize: number;
|
||||
|
||||
constructor(initialSize: number, opts: IFixedCollapsibleViewOptions) {
|
||||
super(initialSize, objects.mixin({ sizing: ViewSizing.Fixed }, opts));
|
||||
this._expandedBodySize = types.isUndefined(opts.expandedBodySize) ? 22 : opts.expandedBodySize;
|
||||
}
|
||||
|
||||
get fixedSize(): number { return this.state === CollapsibleState.EXPANDED ? this.expandedSize : this.headerSize; }
|
||||
private get expandedSize(): number { return this.expandedBodySize + this.headerSize; }
|
||||
|
||||
get expandedBodySize(): number { return this._expandedBodySize; }
|
||||
set expandedBodySize(size: number) {
|
||||
this._expandedBodySize = size;
|
||||
this.setFixed(this.fixedSize);
|
||||
}
|
||||
|
||||
protected changeState(state: CollapsibleState): void {
|
||||
super.changeState(state);
|
||||
this.setFixed(this.fixedSize);
|
||||
|
||||
if (this.body) {
|
||||
if (state === CollapsibleState.COLLAPSED) {
|
||||
// make sure the body goes out of the tabindex world by hiding it
|
||||
$(this.body).hide();
|
||||
} else {
|
||||
$(this.body).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { CollapsibleView, ICollapsibleViewOptions } from 'sql/base/browser/ui/views/browser/views';
|
||||
import { List } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IAction, ActionRunner } from 'vs/base/common/actions';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { $ } from 'vs/base/browser/builder';
|
||||
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { attachBadgeStyler } from 'vs/platform/theme/common/styler';
|
||||
import { CollapsibleState } from 'sql/base/browser/ui/splitview/splitview';
|
||||
|
||||
export class FixedListView<T> extends CollapsibleView {
|
||||
private _badge: CountBadge;
|
||||
private _disposables: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
initialSize: number,
|
||||
initiallyCollapsed: boolean,
|
||||
private _viewTitle: string,
|
||||
private _list: List<T>,
|
||||
private _bodyContainer: HTMLElement,
|
||||
headerSize: number,
|
||||
private _actions: IAction[],
|
||||
actionRunner: ActionRunner,
|
||||
contextMenuService: IContextMenuService,
|
||||
keybindingService: IKeybindingService,
|
||||
private _themeService: IThemeService
|
||||
) {
|
||||
super(initialSize, <ICollapsibleViewOptions>{
|
||||
id: _viewTitle,
|
||||
name: _viewTitle,
|
||||
actionRunner: actionRunner,
|
||||
collapsed: initiallyCollapsed,
|
||||
ariaHeaderLabel: _viewTitle,
|
||||
sizing: headerSize,
|
||||
initialBodySize: undefined
|
||||
}, keybindingService, contextMenuService);
|
||||
}
|
||||
|
||||
// RENDER METHODS //////////////////////////////////////////////////////
|
||||
public renderBody(container: HTMLElement): void {
|
||||
container.appendChild(this._bodyContainer);
|
||||
}
|
||||
|
||||
public renderHeader(container: HTMLElement): void {
|
||||
const titleDiv = $('div.title').appendTo(container);
|
||||
$('span').text(this._viewTitle).appendTo(titleDiv);
|
||||
super.renderHeader(container);
|
||||
|
||||
// show the badge
|
||||
this._badge = new CountBadge($('.count-badge-wrapper').appendTo(container).getHTMLElement());
|
||||
this._disposables.push(attachBadgeStyler(this._badge, this._themeService));
|
||||
}
|
||||
|
||||
public updateList(content: T[]) {
|
||||
this._list.splice(0, this._list.length, content);
|
||||
this._badge.setCount(this._list.length);
|
||||
this._list.layout(this._list.contentHeight);
|
||||
this.setFixed(this.fixedSize);
|
||||
}
|
||||
|
||||
public get list(): List<T> {
|
||||
return this._list;
|
||||
}
|
||||
|
||||
public listContentHeight(): number {
|
||||
return this._list.contentHeight;
|
||||
}
|
||||
|
||||
public get fixedSize(): number {
|
||||
return this.state === CollapsibleState.EXPANDED ? this.expandedSize : this.headerSize;
|
||||
}
|
||||
|
||||
private get expandedSize(): number {
|
||||
if (this._list && this._list.contentHeight) {
|
||||
return this._list.contentHeight + this.headerSize;
|
||||
}
|
||||
|
||||
return this.headerSize;
|
||||
}
|
||||
|
||||
protected changeState(state: CollapsibleState): void {
|
||||
super.changeState(state);
|
||||
this.setFixed(this.fixedSize);
|
||||
if (this.list) {
|
||||
this.list.getHTMLElement().hidden = (state === CollapsibleState.COLLAPSED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return actions for the view
|
||||
*/
|
||||
public getActions(): IAction[] {
|
||||
return this._actions;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._disposables = dispose(this._disposables);
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user