diff --git a/src/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.ts b/src/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.ts index 8bcab828fb5650ab3c349b7e2007b643c7883567..583a970f69b18501e0cfbd8445079c98d486076d 100644 --- a/src/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.ts +++ b/src/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.ts @@ -9,13 +9,15 @@ import 'vs/css!./parameterHints'; import nls = require('vs/nls'); import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; -import { Builder, $ } from 'vs/base/browser/builder'; +import * as dom from 'vs/base/browser/dom'; import aria = require('vs/base/browser/ui/aria/aria'); import { ICursorSelectionChangedEvent, IConfigurationChangedEvent } from 'vs/editor/common/editorCommon'; import { SignatureHelp, SignatureInformation } from 'vs/editor/common/modes'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { IHintEvent, ParameterHintsModel } from './parameterHintsModel'; +const $ = dom.emmet; + interface ISignatureView { top: number; height: number; @@ -27,17 +29,15 @@ export class ParameterHintsWidget implements IContentWidget { private editor: ICodeEditor; private model: ParameterHintsModel; - private $el: Builder; - private $wrapper: Builder; - private $signatures: Builder; - private $overloads: Builder; + private element: HTMLElement; + private signatures: HTMLElement; + private overloads: HTMLElement; private signatureViews: ISignatureView[]; private currentSignature: number; - private isDisposed: boolean; - private isVisible: boolean; + private visible: boolean; private parameterHints: SignatureHelp; private announcedLabel: string; - private toDispose: IDisposable[]; + private disposables: IDisposable[]; private _onShown: () => void; private _onHidden: () => void; @@ -50,14 +50,12 @@ export class ParameterHintsWidget implements IContentWidget { this._onHidden = onHidden; this.editor = editor; this.model = null; - this.isVisible = false; - this.isDisposed = false; - + this.visible = false; this.model = model; - this.toDispose = []; + this.disposables = []; - this.toDispose.push(this.model.onHint((e:IHintEvent) => { + this.disposables.push(this.model.onHint((e:IHintEvent) => { this.show(); this.parameterHints = e.hints; this.render(e.hints); @@ -65,34 +63,34 @@ export class ParameterHintsWidget implements IContentWidget { this.select(this.currentSignature); })); - this.toDispose.push(this.model.onCancel(() => { - this.hide(); - })); + this.disposables.push(this.model.onCancel(() => this.hide())); - this.$el = $('.editor-widget.parameter-hints-widget').on('click', () => { + this.element = $('.editor-widget.parameter-hints-widget'); + + this.disposables.push(dom.addDisposableListener(this.element, 'click', () => { this.selectNext(); this.editor.focus(); - }); - - this.$wrapper = $('.wrapper.monaco-editor-background').appendTo(this.$el); + })); - const $buttons = $('.buttons').appendTo(this.$wrapper); + const wrapper = dom.append(this.element, $('.wrapper.monaco-editor-background')); + const buttons = dom.append(wrapper, $('.buttons')); + const previous = dom.append(buttons, $('.button.previous')); + const next = dom.append(buttons, $('.button.next')); - $('.button.previous').on('click', (e) => { + this.disposables.push(dom.addDisposableListener(previous, 'click', e => { e.preventDefault(); e.stopPropagation(); this.selectPrevious(); - }).appendTo($buttons); + })); - $('.button.next').on('click', (e) => { + this.disposables.push(dom.addDisposableListener(next, 'click', e => { e.preventDefault(); e.stopPropagation(); this.selectNext(); - }).appendTo($buttons); - - this.$overloads = $('.overloads').appendTo(this.$wrapper); + })); - this.$signatures = $('.signatures').appendTo(this.$wrapper); + this.overloads = dom.append(wrapper, $('.overloads')); + this.signatures = dom.append(wrapper, $('.signatures')); this.signatureViews = []; this.currentSignature = 0; @@ -100,14 +98,14 @@ export class ParameterHintsWidget implements IContentWidget { this.editor.addContentWidget(this); this.hide(); - this.toDispose.push(this.editor.onDidChangeCursorSelection((e: ICursorSelectionChangedEvent) => { - if (this.isVisible) { + this.disposables.push(this.editor.onDidChangeCursorSelection((e: ICursorSelectionChangedEvent) => { + if (this.visible) { this.editor.layoutContentWidget(this); } })); this.editor.applyFontInfo(this.getDomNode()); - this.toDispose.push(this.editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { + this.disposables.push(this.editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { if (e.fontInfo) { this.editor.applyFontInfo(this.getDomNode()); } @@ -115,39 +113,31 @@ export class ParameterHintsWidget implements IContentWidget { } private show(): void { - if (this.isDisposed) { - return; - } - if (this.isVisible) { + if (!this.model || this.visible) { return; } - this._onShown(); - this.isVisible = true; - TPromise.timeout(100).done(() => { - this.$el.addClass('visible'); - }); + this._onShown(); + this.visible = true; + TPromise.timeout(100).done(() => dom.addClass(this.element, 'visible')); this.editor.layoutContentWidget(this); } private hide(): void { - if (this.isDisposed) { - return; - } - if (!this.isVisible) { + if (!this.model || !this.visible) { return; } - this._onHidden(); - this.isVisible = false; + this._onHidden(); + this.visible = false; this.parameterHints = null; this.announcedLabel = null; - this.$el.removeClass('visible'); + dom.removeClass(this.element, 'visible'); this.editor.layoutContentWidget(this); } getPosition():IContentWidgetPosition { - if (this.isVisible) { + if (this.visible) { return { position: this.editor.getPosition(), preference: [ContentWidgetPositionPreference.ABOVE, ContentWidgetPositionPreference.BELOW] @@ -158,22 +148,22 @@ export class ParameterHintsWidget implements IContentWidget { private render(hints:SignatureHelp): void { if (hints.signatures.length > 1) { - this.$el.addClass('multiple'); + dom.addClass(this.element, 'multiple'); } else { - this.$el.removeClass('multiple'); + dom.removeClass(this.element, 'multiple'); } - this.$signatures.empty(); + this.signatures.innerHTML = ''; this.signatureViews = []; let height = 0; for (let i = 0, len = hints.signatures.length; i < len; i++) { const signature = hints.signatures[i]; - const $signature = this.renderSignature(this.$signatures, signature, hints.activeParameter); + const signatureElement = this.renderSignature(this.signatures, signature, hints.activeParameter); - this.renderDocumentation($signature, signature, hints.activeParameter); + this.renderDocumentation(signatureElement, signature, hints.activeParameter); - const signatureHeight = $signature.getClientArea().height; + const signatureHeight = dom.getContentHeight(signatureElement); this.signatureViews.push({ top: height, @@ -184,55 +174,76 @@ export class ParameterHintsWidget implements IContentWidget { } } - private renderSignature($el:Builder, signature:SignatureInformation, currentParameter:number):Builder { - const $signature = $('.signature').appendTo($el), - hasParameters = signature.parameters.length > 0; + private renderSignature(element: HTMLElement, signature:SignatureInformation, currentParameter:number): HTMLElement { + const signatureElement = dom.append(element, $('.signature')); + const hasParameters = signature.parameters.length > 0; if(!hasParameters) { - $signature.append($('span').text(signature.label)); + const label = dom.append(signatureElement, $('span')); + label.textContent = signature.label; + return signatureElement; + } - } else { + const parameters = $('span.parameters'); + let offset = 0; + let idx = 0; + + for (let i = 0, len = signature.parameters.length; i < len; i++) { + const parameter = signature.parameters[i]; + idx = signature.label.indexOf(parameter.label, idx); - const $parameters = $('span.parameters'); - let offset = 0; - - let idx = 0; - for (let i = 0, len = signature.parameters.length; i < len; i++) { - const parameter = signature.parameters[i]; - idx = signature.label.indexOf(parameter.label, idx); - - let signatureLabelOffset = 0; - let signatureLabelEnd = 0; - if (idx >= 0) { - signatureLabelOffset = idx; - idx += parameter.label.length; - signatureLabelEnd = idx; - } - - (i === 0 ? $signature : $parameters).append($('span').text(signature.label.substring(offset, signatureLabelOffset))); - $parameters.append($('span.parameter').addClass(i === currentParameter ? 'active' : '').text(signature.label.substring(signatureLabelOffset, signatureLabelEnd))); - offset = signatureLabelEnd; + let signatureLabelOffset = 0; + let signatureLabelEnd = 0; + + if (idx >= 0) { + signatureLabelOffset = idx; + idx += parameter.label.length; + signatureLabelEnd = idx; } - $signature.append($parameters); - $signature.append($('span').text(signature.label.substring(offset))); + const element = i === 0 ? signatureElement : parameters; + + const label = $('span'); + label.textContent = signature.label.substring(offset, signatureLabelOffset); + dom.append(element, label); + + const parameterElement = $('span.parameter'); + dom.addClass(parameterElement, i === currentParameter ? 'active' : ''); + parameterElement.textContent = signature.label.substring(signatureLabelOffset, signatureLabelEnd); + dom.append(parameters, parameterElement); + + offset = signatureLabelEnd; } - return $signature; - } + const label = $('span'); + label.textContent = signature.label.substring(offset); - private renderDocumentation($el:Builder, signature:SignatureInformation, activeParameterIdx:number): void { + dom.append(signatureElement, parameters); + dom.append(signatureElement, label); + return signatureElement; + } + + private renderDocumentation(element: HTMLElement, signature:SignatureInformation, activeParameterIdx:number): void { if(signature.documentation) { - $el.append($('.documentation').text(signature.documentation)); + const documentation = $('.documentation'); + documentation.textContent = signature.documentation; + dom.append(element, documentation); } const activeParameter = signature.parameters[activeParameterIdx]; + if(activeParameter && activeParameter.documentation) { - const $parameter = $('.documentation'); - $parameter.append($('span.parameter').text(activeParameter.label)); - $parameter.append($('span').text(activeParameter.documentation)); - $el.append($parameter); + const parameter = $('.documentation'); + const label = $('span.parameter'); + label.textContent = activeParameter.label; + + const documentation = $('span'); + documentation.textContent = activeParameter.documentation; + + dom.append(parameter, label); + dom.append(parameter, documentation); + dom.append(element, parameter); } } @@ -243,8 +254,8 @@ export class ParameterHintsWidget implements IContentWidget { return; } - this.$signatures.style({ height: signature.height + 'px' }); - this.$signatures.getHTMLElement().scrollTop = signature.top; + this.signatures.style.height = `${ signature.height }px`; + this.signatures.scrollTop = signature.top; let overloads = '' + (position + 1); @@ -252,7 +263,8 @@ export class ParameterHintsWidget implements IContentWidget { overloads += '/' + this.signatureViews.length; } - this.$overloads.text(overloads); + this.overloads.textContent = overloads; + if (this.parameterHints && this.parameterHints.signatures[position].parameters[this.parameterHints.activeParameter]) { const labelToAnnounce = this.parameterHints.signatures[position].parameters[this.parameterHints.activeParameter].label; // Select method gets called on every user type while parameter hints are visible. @@ -262,6 +274,7 @@ export class ParameterHintsWidget implements IContentWidget { this.announcedLabel = labelToAnnounce; } } + this.editor.layoutContentWidget(this); } @@ -297,7 +310,7 @@ export class ParameterHintsWidget implements IContentWidget { } getDomNode(): HTMLElement { - return this.$el.getHTMLElement(); + return this.element; } getId(): string { @@ -305,31 +318,7 @@ export class ParameterHintsWidget implements IContentWidget { } destroy(): void { - this.toDispose = dispose(this.toDispose); - + this.disposables = dispose(this.disposables); this.model = null; - - if (this.$overloads) { - this.$overloads.destroy(); - delete this.$overloads; - } - - if (this.$signatures) { - this.$signatures.destroy(); - delete this.$signatures; - } - - if (this.$wrapper) { - this.$wrapper.destroy(); - delete this.$wrapper; - } - - if (this.$el) { - this.$el.destroy(); - delete this.$el; - } - - this.isDisposed = true; } -} - +} \ No newline at end of file