renameInputField.ts 4.6 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

J
Johannes Rieken 已提交
8
import 'vs/css!./renameInputField';
9
import {localize} from 'vs/nls';
A
Alex Dima 已提交
10
import {canceled} from 'vs/base/common/errors';
J
Joao Moreno 已提交
11
import {IDisposable, dispose} from 'vs/base/common/lifecycle';
E
Erich Gamma 已提交
12 13
import {TPromise} from 'vs/base/common/winjs.base';
import {Range} from 'vs/editor/common/core/range';
A
Alex Dima 已提交
14
import {IPosition, IRange} from 'vs/editor/common/editorCommon';
A
Alex Dima 已提交
15
import {ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition} from 'vs/editor/browser/editorBrowser';
E
Erich Gamma 已提交
16

A
Alex Dima 已提交
17
export default class RenameInputField implements IContentWidget, IDisposable {
E
Erich Gamma 已提交
18

A
Alex Dima 已提交
19 20
	private _editor: ICodeEditor;
	private _position: IPosition;
E
Erich Gamma 已提交
21 22 23 24 25
	private _domNode: HTMLElement;
	private _inputField: HTMLInputElement;
	private _visible: boolean;

	// Editor.IContentWidget.allowEditorOverflow
26
	public allowEditorOverflow: boolean = true;
E
Erich Gamma 已提交
27

A
Alex Dima 已提交
28
	constructor(editor: ICodeEditor) {
E
Erich Gamma 已提交
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
		this._editor = editor;
		this._editor.addContentWidget(this);
	}

	public dispose(): void {
		this._editor.removeContentWidget(this);
	}

	public getId(): string {
		return '__renameInputWidget';
	}

	public getDomNode(): HTMLElement {
		if (!this._domNode) {
			this._inputField = document.createElement('input');
			this._inputField.className = 'rename-input';
45
			this._inputField.type = 'text';
46
			this._inputField.setAttribute('aria-label', localize('renameAriaLabel', "Rename input. Type new name and press Enter to commit."));
E
Erich Gamma 已提交
47 48 49 50 51 52 53 54
			this._domNode = document.createElement('div');
			this._domNode.style.height = `${this._editor.getConfiguration().lineHeight}px`;
			this._domNode.className = 'monaco-editor rename-box';
			this._domNode.appendChild(this._inputField);
		}
		return this._domNode;
	}

A
Alex Dima 已提交
55
	public getPosition(): IContentWidgetPosition {
E
Erich Gamma 已提交
56
		return this._visible
A
Alex Dima 已提交
57
			? { position: this._position, preference: [ContentWidgetPositionPreference.BELOW, ContentWidgetPositionPreference.ABOVE] }
E
Erich Gamma 已提交
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
			: null;
	}

	private _currentAcceptInput: () => void = null;
	private _currentCancelInput: () => void = null;

	public acceptInput(): void {
		if (this._currentAcceptInput) {
			this._currentAcceptInput();
		}
	}

	public cancelInput(): void {
		if (this._currentCancelInput) {
			this._currentCancelInput();
		}
	}

A
Alex Dima 已提交
76
	public getInput(where: IRange, value: string, selectionStart: number, selectionEnd: number): TPromise<string> {
E
Erich Gamma 已提交
77 78 79 80 81 82 83

		this._position = { lineNumber: where.startLineNumber, column: where.startColumn };
		this._inputField.value = value;
		this._inputField.setAttribute('selectionStart', selectionStart.toString());
		this._inputField.setAttribute('selectionEnd', selectionEnd.toString());
		this._inputField.size = Math.max((where.endColumn - where.startColumn) * 1.1, 20);

A
Alex Dima 已提交
84
		let disposeOnDone: IDisposable[] = [],
E
Erich Gamma 已提交
85 86 87
			always: Function;

		always = () => {
J
Joao Moreno 已提交
88
			dispose(disposeOnDone);
E
Erich Gamma 已提交
89 90 91 92 93 94 95 96
			this._hide();
		};

		return new TPromise<string>((c, e) => {

			this._currentCancelInput = () => {
				this._currentAcceptInput = null;
				this._currentCancelInput = null;
A
Alex Dima 已提交
97
				e(canceled());
E
Erich Gamma 已提交
98 99 100 101 102 103 104 105 106 107 108 109 110
				return true;
			};

			this._currentAcceptInput = () => {
				if (this._inputField.value.trim().length === 0 || this._inputField.value === value) {
					// empty or whitespace only or not changed
					this._currentCancelInput();
					return;
				}

				this._currentAcceptInput = null;
				this._currentCancelInput = null;
				c(this._inputField.value);
A
tslint  
Alex Dima 已提交
111
			};
E
Erich Gamma 已提交
112

113
			let onCursorChanged = () => {
E
Erich Gamma 已提交
114 115 116 117 118
				if (!Range.containsPosition(where, this._editor.getPosition())) {
					this._currentCancelInput();
				}
			};

A
Alex Dima 已提交
119 120
			disposeOnDone.push(this._editor.onDidCursorSelectionChange(onCursorChanged));
			disposeOnDone.push(this._editor.onDidEditorBlur(this._currentCancelInput));
E
Erich Gamma 已提交
121 122 123

			this._show();

124
		}, this._currentCancelInput).then(newValue => {
E
Erich Gamma 已提交
125
			always();
126
			return newValue;
E
Erich Gamma 已提交
127 128 129 130 131 132
		}, err => {
			always();
			return TPromise.wrapError(err);
		});
	}

133 134
	private _show(): void {
		this._editor.revealLineInCenterIfOutsideViewport(this._position.lineNumber);
E
Erich Gamma 已提交
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
		this._visible = true;
		this._editor.layoutContentWidget(this);

		setTimeout(() => {
			this._inputField.focus();
			this._inputField.setSelectionRange(
				parseInt(this._inputField.getAttribute('selectionStart')),
				parseInt(this._inputField.getAttribute('selectionEnd')));
		}, 25);
	}

	private _hide(): void {
		this._visible = false;
		this._editor.layoutContentWidget(this);
	}
}