diff --git a/samples/sqlservices/src/controllers/mainController.ts b/samples/sqlservices/src/controllers/mainController.ts index f836ffa032..fd6073f67c 100644 --- a/samples/sqlservices/src/controllers/mainController.ts +++ b/samples/sqlservices/src/controllers/mainController.ts @@ -82,7 +82,8 @@ export default class MainController implements vscode.Disposable { tab1.registerContent(async (view) => { let inputBox = view.modelBuilder.inputBox() .withProperties({ - //width: 300 + multiline: true, + height: 100 }).component(); let inputBoxWrapper = view.modelBuilder.loadingComponent().withItem(inputBox).component(); inputBoxWrapper.loading = false; diff --git a/src/sql/base/browser/ui/inputBox/inputBox.ts b/src/sql/base/browser/ui/inputBox/inputBox.ts index e13df70934..eb10b5117d 100644 --- a/src/sql/base/browser/ui/inputBox/inputBox.ts +++ b/src/sql/base/browser/ui/inputBox/inputBox.ts @@ -67,6 +67,14 @@ export class InputBox extends vsInputBox { this.applyStyles(); } + public set rows(value: number) { + this.inputElement.setAttribute('rows', value.toString()); + } + + public set columns(value: number) { + this.inputElement.setAttribute('cols', value.toString()); + } + public disable(): void { super.disable(); this.inputBackground = this.disabledInputBackground; @@ -75,6 +83,10 @@ export class InputBox extends vsInputBox { this.applyStyles(); } + public setHeight(value: string) { + this.inputElement.style.height = value; + } + public isEnabled(): boolean { return !this.inputElement.hasAttribute('disabled'); } diff --git a/src/sql/parts/modelComponents/inputbox.component.ts b/src/sql/parts/modelComponents/inputbox.component.ts index a881731edd..f4ef757316 100644 --- a/src/sql/parts/modelComponents/inputbox.component.ts +++ b/src/sql/parts/modelComponents/inputbox.component.ts @@ -20,19 +20,23 @@ import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/work import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { Event, Emitter } from 'vs/base/common/event'; import * as nls from 'vs/nls'; +import { TextAreaInput } from 'vs/editor/browser/controller/textAreaInput'; @Component({ selector: 'modelview-inputBox', template: ` -
+
+
` }) export default class InputBoxComponent extends ComponentBase implements IComponent, OnDestroy, AfterViewInit { @Input() descriptor: IComponentDescriptor; @Input() modelStore: IModelStore; private _input: InputBox; + private _textAreaInput: InputBox; @ViewChild('input', { read: ElementRef }) private _inputContainer: ElementRef; + @ViewChild('textarea', { read: ElementRef }) private _textareaContainer: ElementRef; constructor( @Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef, @Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService, @@ -43,47 +47,71 @@ export default class InputBoxComponent extends ComponentBase implements ICompone ngOnInit(): void { this.baseInit(); - } ngAfterViewInit(): void { - if (this._inputContainer) { - let inputOptions: IInputOptions = { - placeholder: '', - ariaLabel: '', - validationOptions: { - validation: () => { - if (this.valid) { - return undefined; - } else { - return { - content: this._input.inputElement.validationMessage || nls.localize('invalidValueError', 'Invalid value'), - type: MessageType.ERROR - }; - } + let inputOptions: IInputOptions = { + placeholder: '', + ariaLabel: '', + validationOptions: { + validation: () => { + if (this.valid) { + return undefined; + } else { + return { + content: this.inputElement.inputElement.validationMessage || nls.localize('invalidValueError', 'Invalid value'), + type: MessageType.ERROR + }; } - }, - useDefaultValidation: true - }; - + } + }, + useDefaultValidation: true + }; + if (this._inputContainer) { this._input = new InputBox(this._inputContainer.nativeElement, this.contextViewService, inputOptions); - this._validations.push(() => !this._input.inputElement.validationMessage); + this.registerInput(this._input, () => !this.multiline); - this._register(this._input); - this._register(attachInputBoxStyler(this._input, this.themeService)); - this._register(this._input.onDidChange(e => { - this.value = this._input.value; - this._onEventEmitter.fire({ - eventType: ComponentEventType.onDidChange, - args: e - }); + } + if (this._textareaContainer) { + let textAreaInputOptions = Object.assign({}, inputOptions, { flexibleHeight: true }); + this._textAreaInput = new InputBox(this._textareaContainer.nativeElement, this.contextViewService, textAreaInputOptions); + this.registerInput(this._textAreaInput, () => this.multiline); + } + } + + private get inputElement(): InputBox { + return this.multiline ? this._textAreaInput : this._input; + } + + private registerInput(input: InputBox, checkOption: () => boolean): void { + if (input) { + this._validations.push(() => !input.inputElement.validationMessage); + + this._register(input); + this._register(attachInputBoxStyler(input, this.themeService)); + this._register(input.onDidChange(e => { + if (checkOption()) { + this.value = input.value; + this._onEventEmitter.fire({ + eventType: ComponentEventType.onDidChange, + args: e + }); + } })); } } + public getInputBoxDisplay(): string { + return !this.multiline ? '' : 'none'; + } + + public getTextAreaDisplay(): string { + return this.multiline ? '' : 'none'; + } + public validate(): Thenable { return super.validate().then(valid => { - this._input.validate(); + this.inputElement.validate(); return valid; }); } @@ -105,21 +133,47 @@ export default class InputBoxComponent extends ComponentBase implements ICompone public setProperties(properties: { [key: string]: any; }): void { super.setProperties(properties); - this._input.inputElement.type = this.inputType; - if (this.inputType === 'number') { - this._input.inputElement.step = 'any'; - } - this._input.value = this.value; - this._input.setAriaLabel(this.ariaLabel); - this._input.setPlaceHolder(this.placeHolder); - this._input.setEnabled(this.enabled); - if (this.width) { - this._input.width = this.width; - } - this._input.inputElement.required = this.required; + this.setInputProperties(this.inputElement); this.validate(); } + private setInputProperties(input: InputBox): void { + if (!this.multiline) { + input.inputElement.type = this.inputType; + if (this.inputType === 'number') { + input.inputElement.step = 'any'; + if (this.min) { + input.inputElement.min = this.min.toString(); + } + if (this.max) { + input.inputElement.max = this.max.toString(); + } + } + } + input.value = this.value; + input.setAriaLabel(this.ariaLabel); + input.setPlaceHolder(this.placeHolder); + input.setEnabled(this.enabled); + if (this.width) { + input.width = this.width; + } + if (this.height) { + input.setHeight(this.convertSize(this.height)); + input.layout(); + } + if (this.multiline) { + if (this.rows) { + this.inputElement.rows = this.rows; + } + if (this.columns) { + this.inputElement.columns = this.columns; + } + } + + + input.inputElement.required = this.required; + } + // CSS-bound properties public get value(): string { @@ -162,6 +216,38 @@ export default class InputBoxComponent extends ComponentBase implements ICompone this.setPropertyFromUI((props, value) => props.width = value, newValue); } + public set columns(newValue: number) { + this.setPropertyFromUI((props, value) => props.columns = value, newValue); + } + + public get rows(): number { + return this.getPropertyOrDefault((props) => props.rows, undefined); + } + + public get columns(): number { + return this.getPropertyOrDefault((props) => props.columns, undefined); + } + + public set rows(newValue: number) { + this.setPropertyFromUI((props, value) => props.rows = value, newValue); + } + + public get min(): number { + return this.getPropertyOrDefault((props) => props.min, undefined); + } + + public set min(newValue: number) { + this.setPropertyFromUI((props, value) => props.min = value, newValue); + } + + public get max(): number { + return this.getPropertyOrDefault((props) => props.max, undefined); + } + + public set max(newValue: number) { + this.setPropertyFromUI((props, value) => props.max = value, newValue); + } + public get inputType(): string { return this.getPropertyOrDefault((props) => props.inputType, 'text'); } @@ -170,6 +256,14 @@ export default class InputBoxComponent extends ComponentBase implements ICompone this.setPropertyFromUI((props, value) => props.inputType = value, newValue); } + public get multiline(): boolean { + return this.getPropertyOrDefault((props) => props.multiline, false); + } + + public set multiline(newValue: boolean) { + this.setPropertyFromUI((props, value) => props.multiline = value, newValue); + } + public get required(): boolean { return this.getPropertyOrDefault((props) => props.required, false); } diff --git a/src/sql/sqlops.proposed.d.ts b/src/sql/sqlops.proposed.d.ts index f5f6ba998b..712349874f 100644 --- a/src/sql/sqlops.proposed.d.ts +++ b/src/sql/sqlops.proposed.d.ts @@ -302,6 +302,11 @@ declare module 'sqlops' { width: number; inputType?: InputBoxInputType; required?: boolean; + multiline?: boolean; + rows?: number; + columns?: number; + min?: number; + max?: number; } export interface TableColumn { diff --git a/src/sql/workbench/api/node/extHostModelView.ts b/src/sql/workbench/api/node/extHostModelView.ts index 319b248a8d..a9ee235e3f 100644 --- a/src/sql/workbench/api/node/extHostModelView.ts +++ b/src/sql/workbench/api/node/extHostModelView.ts @@ -560,6 +560,34 @@ class InputBoxWrapper extends ComponentWrapper implements sqlops.InputBoxCompone this.setProperty('height', v); } + public get rows(): number { + return this.properties['rows']; + } + public set rows(v: number) { + this.setProperty('rows', v); + } + + public get min(): number { + return this.properties['min']; + } + public set min(v: number) { + this.setProperty('min', v); + } + + public get max(): number { + return this.properties['max']; + } + public set max(v: number) { + this.setProperty('max', v); + } + + public get columns(): number { + return this.properties['columns']; + } + public set columns(v: number) { + this.setProperty('columns', v); + } + public get width(): number { return this.properties['width']; } @@ -567,6 +595,13 @@ class InputBoxWrapper extends ComponentWrapper implements sqlops.InputBoxCompone this.setProperty('width', v); } + public get multiline(): boolean { + return this.properties['multiline']; + } + public set multiline(v: boolean) { + this.setProperty('multiline', v); + } + public get inputType(): sqlops.InputBoxInputType { return this.properties['inputType']; }