diff --git a/src/sql/base/browser/ui/editableDropdown/actions.ts b/src/sql/base/parts/editableDropdown/browser/actions.ts similarity index 100% rename from src/sql/base/browser/ui/editableDropdown/actions.ts rename to src/sql/base/parts/editableDropdown/browser/actions.ts diff --git a/src/sql/base/browser/ui/editableDropdown/dropdown.ts b/src/sql/base/parts/editableDropdown/browser/dropdown.ts similarity index 87% rename from src/sql/base/browser/ui/editableDropdown/dropdown.ts rename to src/sql/base/parts/editableDropdown/browser/dropdown.ts index 7ae3e4851c..8a1568ea63 100644 --- a/src/sql/base/browser/ui/editableDropdown/dropdown.ts +++ b/src/sql/base/parts/editableDropdown/browser/dropdown.ts @@ -8,7 +8,7 @@ import 'vs/css!./media/dropdownList'; import { ToggleDropdownAction } from './actions'; import { DropdownDataSource, DropdownFilter, DropdownModel, DropdownRenderer, DropdownController } from './dropdownTree'; -import { IContextViewProvider, ContextView } from 'vs/base/browser/ui/contextview/contextview'; +import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; import { mixin } from 'vs/base/common/objects'; import { InputBox, IInputBoxStyles } from 'sql/base/browser/ui/inputBox/inputBox'; import { IMessage, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; @@ -21,7 +21,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; -import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; +import { ITree } from 'vs/base/parts/tree/browser/tree'; export interface IDropdownOptions extends IDropdownStyles { /** @@ -78,11 +78,9 @@ export class Dropdown extends Disposable { private _inputContainer: HTMLElement; private _treeContainer: HTMLElement; private _input: InputBox; - private _tree: Tree; + private _tree: ITree; private _options: IDropdownOptions; private _toggleAction: ToggleDropdownAction; - // we have to create our own contextview since otherwise inputbox will override ours - private _contextView: ContextView; private _dataSource = new DropdownDataSource(); private _filter = new DropdownFilter(); private _renderer = new DropdownRenderer(); @@ -100,12 +98,10 @@ export class Dropdown extends Disposable { constructor( container: HTMLElement, - contextViewService: IContextViewProvider, - readonly layoutService: ILayoutService, + private readonly contextViewService: IContextViewProvider, opt?: IDropdownOptions ) { super(); - this._contextView = new ContextView(layoutService.container); this._options = opt || Object.create(null); mixin(this._options, defaults, false); this._el = DOM.append(container, DOM.$('.monaco-dropdown')); @@ -124,7 +120,7 @@ export class Dropdown extends Disposable { this._input = new InputBox(this._inputContainer, contextViewService, { validationOptions: { // @SQLTODO - //showMessage: false, + // showMessage: false, validation: v => this._inputValidator(v) }, placeholder: this._options.placeholder, @@ -140,21 +136,18 @@ export class Dropdown extends Disposable { this._showList(); })); - this._register(DOM.addDisposableListener(this._input.inputElement, DOM.EventType.BLUR, () => { + const inputTracker = this._register(DOM.trackFocus(this._input.inputElement)); + inputTracker.onDidBlur(() => { if (!this._tree.isDOMFocused()) { this._onBlur.fire(); } - })); + }); this._register(DOM.addStandardDisposableListener(this._input.inputElement, DOM.EventType.KEY_DOWN, (e: StandardKeyboardEvent) => { switch (e.keyCode) { case KeyCode.Enter: - if (this._contextView.isVisible()) { - if (this._input.validate()) { - this._onValueChange.fire(this._input.value); - } - } else { - this._showList(); + if (this._input.validate()) { + this._onValueChange.fire(this._input.value); } e.stopPropagation(); break; @@ -162,14 +155,14 @@ export class Dropdown extends Disposable { if (this._treeContainer.parentElement) { this._input.validate(); this._onBlur.fire(); - this._contextView.hide(); + this.contextViewService.hideContextView(); e.stopPropagation(); } break; case KeyCode.Tab: this._input.validate(); this._onBlur.fire(); - this._contextView.hide(); + this.contextViewService.hideContextView(); e.stopPropagation(); break; case KeyCode.DownArrow: @@ -191,18 +184,26 @@ export class Dropdown extends Disposable { controller: this._controller }, { paddingOnRow: false, indentPixels: 0, twistiePixels: 0 }); + const treeTracker = this._register(DOM.trackFocus(this._tree.getHTMLElement())); + + treeTracker.onDidBlur(() => { + if (!this._input.hasFocus()) { + this._onBlur.fire(); + } + }); + this.values = this._options.values; this._controller.onSelectionChange(e => { this.value = e.value; this._onValueChange.fire(e.value); this._input.focus(); - this._contextView.hide(); + this.contextViewService.hideContextView(); }); this._controller.onDropdownEscape(() => { this._input.focus(); - this._contextView.hide(); + this.contextViewService.hideContextView(); }); this._input.onDidChange(e => { @@ -216,29 +217,30 @@ export class Dropdown extends Disposable { } }); - this._register(this._contextView); + this.onBlur(() => { + this.contextViewService.hideContextView(); + }); + this._register(this._tree); this._register(this._input); - this._register(this._contextView); } private _showList(): void { if (this._input.isEnabled) { this._onFocus.fire(); this._filter.filterString = ''; - this._contextView.show({ + this.contextViewService.showContextView({ getAnchor: () => this._inputContainer, render: container => { DOM.append(container, this._treeContainer); this._layoutTree(); - return { dispose: () => { } }; - }, - onDOMEvent: e => { - if (!DOM.isAncestor((e.srcElement), this._el) && !DOM.isAncestor((e.srcElement), this._treeContainer)) { - this._input.validate(); - this._onBlur.fire(); - this._contextView.hide(); - } + return { + dispose: () => { + // when we dispose we want to remove treecontainer so that it doesn't have a parent + // we often use the presense of a parent to detect if the tree is being shown + this._treeContainer.remove(); + } + }; } }); } @@ -288,7 +290,7 @@ export class Dropdown extends Disposable { public blur() { this._input.blur(); - this._contextView.hide(); + this.contextViewService.hideContextView(); } style(style: IListStyles & IInputBoxStyles & IDropdownStyles) { diff --git a/src/sql/base/browser/ui/editableDropdown/dropdownTree.ts b/src/sql/base/parts/editableDropdown/browser/dropdownTree.ts similarity index 100% rename from src/sql/base/browser/ui/editableDropdown/dropdownTree.ts rename to src/sql/base/parts/editableDropdown/browser/dropdownTree.ts diff --git a/src/sql/base/browser/ui/editableDropdown/media/dropdownList.css b/src/sql/base/parts/editableDropdown/browser/media/dropdownList.css similarity index 100% rename from src/sql/base/browser/ui/editableDropdown/media/dropdownList.css rename to src/sql/base/parts/editableDropdown/browser/media/dropdownList.css diff --git a/src/sql/base/browser/ui/editableDropdown/media/dropdownarrow.svg b/src/sql/base/parts/editableDropdown/browser/media/dropdownarrow.svg similarity index 100% rename from src/sql/base/browser/ui/editableDropdown/media/dropdownarrow.svg rename to src/sql/base/parts/editableDropdown/browser/media/dropdownarrow.svg diff --git a/src/sql/base/browser/ui/editableDropdown/media/dropdownarrow_inverse.svg b/src/sql/base/parts/editableDropdown/browser/media/dropdownarrow_inverse.svg similarity index 100% rename from src/sql/base/browser/ui/editableDropdown/media/dropdownarrow_inverse.svg rename to src/sql/base/parts/editableDropdown/browser/media/dropdownarrow_inverse.svg diff --git a/src/sql/platform/dialog/dialog.module.ts b/src/sql/platform/dialog/dialog.module.ts index 2d6c598aae..5e6cc58621 100644 --- a/src/sql/platform/dialog/dialog.module.ts +++ b/src/sql/platform/dialog/dialog.module.ts @@ -22,7 +22,7 @@ import { IBootstrapParams, ISelector, providerIterator } from 'sql/platform/boot import { CommonServiceInterface } from 'sql/platform/bootstrap/node/commonServiceInterface.service'; import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox.component'; import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox.component'; -import { EditableDropDown } from 'sql/base/browser/ui/editableDropdown/editableDropdown.component'; +import { EditableDropDown } from 'sql/platform/electron-browser/editableDropdown/editableDropdown.component'; import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox.component'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; diff --git a/src/sql/base/browser/ui/editableDropdown/editableDropdown.component.ts b/src/sql/platform/electron-browser/editableDropdown/editableDropdown.component.ts similarity index 79% rename from src/sql/base/browser/ui/editableDropdown/editableDropdown.component.ts rename to src/sql/platform/electron-browser/editableDropdown/editableDropdown.component.ts index 7c08996a23..e7c03ffc20 100644 --- a/src/sql/base/browser/ui/editableDropdown/editableDropdown.component.ts +++ b/src/sql/platform/electron-browser/editableDropdown/editableDropdown.component.ts @@ -8,13 +8,12 @@ import { Output, OnChanges, SimpleChanges, EventEmitter } from '@angular/core'; -import { Dropdown, IDropdownOptions } from 'sql/base/browser/ui/editableDropdown/dropdown'; +import { Dropdown, IDropdownOptions } from 'sql/base/parts/editableDropdown/browser/dropdown'; import { AngularDisposable } from 'sql/base/node/lifecycle'; import { attachEditableDropdownStyler } from 'sql/platform/theme/common/styler'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; @Component({ selector: 'editable-select-box', @@ -32,10 +31,9 @@ export class EditableDropDown extends AngularDisposable implements OnInit, OnCha private _previousVal: string; constructor( - @Inject(forwardRef(() => ElementRef)) private _el: ElementRef, - @Inject(IThemeService) private themeService: IThemeService, - @Inject(IContextViewService) private contextViewService: IContextViewService, - @Inject(ILayoutService) private layoutService: ILayoutService + @Inject(forwardRef(() => ElementRef)) private readonly _el: ElementRef, + @Inject(IThemeService) private readonly themeService: IThemeService, + @Inject(IContextViewService) private readonly contextViewService: IContextViewService ) { super(); } @@ -49,7 +47,7 @@ export class EditableDropDown extends AngularDisposable implements OnInit, OnCha ariaLabel: '', actionLabel: '' }; - this._selectbox = new Dropdown(this._el.nativeElement, this.contextViewService, this.layoutService, dropdownOptions); + this._selectbox = new Dropdown(this._el.nativeElement, this.contextViewService, dropdownOptions); this._selectbox.values = this.options; this._selectbox.value = this.selectedOption; diff --git a/src/sql/workbench/electron-browser/modelComponents/dropdown.component.ts b/src/sql/workbench/electron-browser/modelComponents/dropdown.component.ts index 0f78fa3377..6e2aae1b71 100644 --- a/src/sql/workbench/electron-browser/modelComponents/dropdown.component.ts +++ b/src/sql/workbench/electron-browser/modelComponents/dropdown.component.ts @@ -12,7 +12,7 @@ import * as azdata from 'azdata'; import { ComponentBase } from 'sql/workbench/electron-browser/modelComponents/componentBase'; import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/workbench/electron-browser/modelComponents/interfaces'; -import { Dropdown, IDropdownOptions } from 'sql/base/browser/ui/editableDropdown/dropdown'; +import { Dropdown, IDropdownOptions } from 'sql/base/parts/editableDropdown/browser/dropdown'; import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox'; import { attachEditableDropdownStyler } from 'sql/platform/theme/common/styler'; import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler'; @@ -63,7 +63,7 @@ export default class DropDownComponent extends ComponentBase implements ICompone ariaLabel: '', actionLabel: '' }; - this._editableDropdown = new Dropdown(this._editableDropDownContainer.nativeElement, this.contextViewService, this.layoutService, + this._editableDropdown = new Dropdown(this._editableDropDownContainer.nativeElement, this.contextViewService, dropdownOptions); this._register(this._editableDropdown); diff --git a/src/sql/workbench/parts/dashboard/dashboard.module.ts b/src/sql/workbench/parts/dashboard/dashboard.module.ts index 82bfb6a27e..65cbfedd0f 100644 --- a/src/sql/workbench/parts/dashboard/dashboard.module.ts +++ b/src/sql/workbench/parts/dashboard/dashboard.module.ts @@ -57,7 +57,7 @@ import { OperatorsViewComponent } from 'sql/workbench/parts/jobManagement/electr import { ProxiesViewComponent } from 'sql/workbench/parts/jobManagement/electron-browser/proxiesView.component'; import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox.component'; import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox.component'; -import { EditableDropDown } from 'sql/base/browser/ui/editableDropdown/editableDropdown.component'; +import { EditableDropDown } from 'sql/platform/electron-browser/editableDropdown/editableDropdown.component'; import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox.component'; import LoadingSpinner from 'sql/workbench/electron-browser/modelComponents/loadingSpinner.component'; diff --git a/src/sql/workbench/parts/notebook/notebook.module.ts b/src/sql/workbench/parts/notebook/notebook.module.ts index 572d6bff79..ecbe6c1944 100644 --- a/src/sql/workbench/parts/notebook/notebook.module.ts +++ b/src/sql/workbench/parts/notebook/notebook.module.ts @@ -16,7 +16,7 @@ import { IBootstrapParams, ISelector, providerIterator } from 'sql/platform/boot import { CommonServiceInterface } from 'sql/platform/bootstrap/node/commonServiceInterface.service'; import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox.component'; import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox.component'; -import { EditableDropDown } from 'sql/base/browser/ui/editableDropdown/editableDropdown.component'; +import { EditableDropDown } from 'sql/platform/electron-browser/editableDropdown/editableDropdown.component'; import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox.component'; import { NotebookComponent } from 'sql/workbench/parts/notebook/notebook.component'; diff --git a/src/sql/workbench/parts/query/browser/queryActions.ts b/src/sql/workbench/parts/query/browser/queryActions.ts index 943d886539..af7d2b445a 100644 --- a/src/sql/workbench/parts/query/browser/queryActions.ts +++ b/src/sql/workbench/parts/query/browser/queryActions.ts @@ -27,7 +27,7 @@ import { IQueryModelService } from 'sql/platform/query/common/queryModel'; import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox'; import { attachEditableDropdownStyler, attachSelectBoxStyler } from 'sql/platform/theme/common/styler'; import { EventEmitter } from 'sql/base/common/eventEmitter'; -import { Dropdown } from 'sql/base/browser/ui/editableDropdown/dropdown'; +import { Dropdown } from 'sql/base/parts/editableDropdown/browser/dropdown'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; /** @@ -464,7 +464,7 @@ export class ListDatabasesActionItem extends EventEmitter implements IActionItem this._databaseSelectBox.disable(); } else { - this._dropdown = new Dropdown(this._databaseListDropdown, contextViewProvider, layoutService, { + this._dropdown = new Dropdown(this._databaseListDropdown, contextViewProvider, { strictSelection: true, placeholder: this._selectDatabaseString, ariaLabel: this._selectDatabaseString, diff --git a/src/sql/workbench/parts/query/modelViewTab/queryModelViewTab.module.ts b/src/sql/workbench/parts/query/modelViewTab/queryModelViewTab.module.ts index 24067b141b..00cfa7254a 100644 --- a/src/sql/workbench/parts/query/modelViewTab/queryModelViewTab.module.ts +++ b/src/sql/workbench/parts/query/modelViewTab/queryModelViewTab.module.ts @@ -18,7 +18,7 @@ import { IBootstrapParams, ISelector, providerIterator } from 'sql/platform/boot import { CommonServiceInterface } from 'sql/platform/bootstrap/node/commonServiceInterface.service'; import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox.component'; import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox.component'; -import { EditableDropDown } from 'sql/base/browser/ui/editableDropdown/editableDropdown.component'; +import { EditableDropDown } from 'sql/platform/electron-browser/editableDropdown/editableDropdown.component'; import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox.component'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; diff --git a/src/sql/workbench/parts/restore/browser/restoreDialog.ts b/src/sql/workbench/parts/restore/browser/restoreDialog.ts index 583d965458..473e1d481c 100644 --- a/src/sql/workbench/parts/restore/browser/restoreDialog.ts +++ b/src/sql/workbench/parts/restore/browser/restoreDialog.ts @@ -37,7 +37,7 @@ import * as TelemetryKeys from 'sql/platform/telemetry/telemetryKeys'; import * as BackupConstants from 'sql/workbench/parts/backup/common/constants'; import { RestoreViewModel, RestoreOptionParam, SouceDatabaseNamesParam } from 'sql/workbench/parts/restore/browser/restoreViewModel'; import * as FileValidationConstants from 'sql/workbench/services/fileBrowser/common/fileValidationServiceConstants'; -import { Dropdown } from 'sql/base/browser/ui/editableDropdown/dropdown'; +import { Dropdown } from 'sql/base/parts/editableDropdown/browser/dropdown'; import { TabbedPanel, PanelTabIdentifier } from 'sql/base/browser/ui/panel/panel'; import { ServiceOptionType } from 'sql/workbench/api/common/sqlExtHostTypes'; import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService'; @@ -211,7 +211,7 @@ export class RestoreDialog extends Modal { // Get the bootstrap params and perform the bootstrap dropdownContainer.style.width = '100%'; - this._databaseDropdown = new Dropdown(dropdownContainer, this._contextViewService, this.layoutService, + this._databaseDropdown = new Dropdown(dropdownContainer, this._contextViewService, { strictSelection: false, ariaLabel: LocalizedStrings.TARGETDATABASE, diff --git a/src/sql/workbench/services/connection/browser/cmsConnectionWidget.ts b/src/sql/workbench/services/connection/browser/cmsConnectionWidget.ts index ee8bbe664b..51a3cef215 100644 --- a/src/sql/workbench/services/connection/browser/cmsConnectionWidget.ts +++ b/src/sql/workbench/services/connection/browser/cmsConnectionWidget.ts @@ -5,20 +5,15 @@ import 'vs/css!./media/sqlConnection'; -import { Button } from 'sql/base/browser/ui/button/button'; import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox'; -import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox'; import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox'; import * as DialogHelper from 'sql/workbench/browser/modal/dialogHelper'; import { IConnectionComponentCallbacks } from 'sql/workbench/services/connection/browser/connectionDialogService'; import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes'; import * as Constants from 'sql/platform/connection/common/constants'; -import { ConnectionProfileGroup, IConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup'; -import { Dropdown } from 'sql/base/browser/ui/editableDropdown/dropdown'; import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement'; import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; -import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; import * as styler from 'sql/platform/theme/common/styler'; import { IAccountManagementService } from 'sql/platform/accounts/common/interfaces'; @@ -161,4 +156,4 @@ export class CmsConnectionWidget extends ConnectionWidget { } return validInputs; } -} \ No newline at end of file +} diff --git a/src/sql/workbench/services/connection/browser/connectionWidget.ts b/src/sql/workbench/services/connection/browser/connectionWidget.ts index f9811ec256..c15a0bf0c0 100644 --- a/src/sql/workbench/services/connection/browser/connectionWidget.ts +++ b/src/sql/workbench/services/connection/browser/connectionWidget.ts @@ -15,7 +15,7 @@ import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes'; import * as Constants from 'sql/platform/connection/common/constants'; import { ConnectionProfileGroup, IConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup'; -import { Dropdown } from 'sql/base/browser/ui/editableDropdown/dropdown'; +import { Dropdown } from 'sql/base/parts/editableDropdown/browser/dropdown'; import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement'; import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; @@ -249,7 +249,7 @@ export class ConnectionWidget { let databaseOption = this._optionsMaps[ConnectionOptionSpecialType.databaseName]; if (databaseOption) { let databaseName = DialogHelper.appendRow(this._tableContainer, databaseOption.displayName, 'connection-label', 'connection-input'); - this._databaseNameInputBox = new Dropdown(databaseName, this._contextViewService, this._layoutService, { + this._databaseNameInputBox = new Dropdown(databaseName, this._contextViewService, { values: [this._defaultDatabaseName, this._loadingDatabaseName], strictSelection: false, placeholder: this._defaultDatabaseName,