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

import 'vs/css!./findInput';

A
Alex Dima 已提交
9 10 11 12 13 14 15 16
import * as nls from 'vs/nls';
import * as dom from 'vs/base/browser/dom';
import {IMessage as InputBoxMessage, IInputValidator, InputBox} from 'vs/base/browser/ui/inputbox/inputBox';
import {Checkbox} from 'vs/base/browser/ui/checkbox/checkbox';
import {IContextViewProvider} from 'vs/base/browser/ui/contextview/contextview';
import {Widget} from 'vs/base/browser/ui/widget';
import Event, {Emitter} from 'vs/base/common/event';
import {StandardKeyboardEvent} from 'vs/base/browser/keyboardEvent';
A
Alex Dima 已提交
17
import {StandardMouseEvent} from 'vs/base/browser/mouseEvent';
E
Erich Gamma 已提交
18

A
Alex Dima 已提交
19
export interface IFindInputOptions {
E
Erich Gamma 已提交
20 21
	placeholder?:string;
	width?:number;
A
Alex Dima 已提交
22
	validation?:IInputValidator;
E
Erich Gamma 已提交
23
	label:string;
24 25 26 27

	appendCaseSensitiveLabel?: string;
	appendWholeWordsLabel?: string;
	appendRegexLabel?: string;
E
Erich Gamma 已提交
28 29
}

A
Alex Dima 已提交
30 31 32 33 34 35
export interface IMatchCountState {
	count: string;
	isVisible: boolean;
	title: string;
}

36 37 38 39 40
const NLS_REGEX_CHECKBOX_LABEL = nls.localize('regexDescription', "Use Regular Expression");
const NLS_WHOLE_WORD_CHECKBOX_LABEL = nls.localize('wordsDescription', "Match Whole Word");
const NLS_CASE_SENSITIVE_CHECKBOX_LABEL = nls.localize('caseDescription', "Match Case");
const NLS_DEFAULT_LABEL = nls.localize('defaultLabel', "input");

A
Alex Dima 已提交
41
export class FindInput extends Widget {
E
Erich Gamma 已提交
42 43 44

	static OPTION_CHANGE:string = 'optionChange';

A
Alex Dima 已提交
45
	private contextViewProvider: IContextViewProvider;
E
Erich Gamma 已提交
46 47
	private width:number;
	private placeholder:string;
A
Alex Dima 已提交
48
	private validation:IInputValidator;
E
Erich Gamma 已提交
49 50
	private label:string;

A
Alex Dima 已提交
51 52 53
	private regex:Checkbox;
	private wholeWords:Checkbox;
	private caseSensitive:Checkbox;
A
Alex Dima 已提交
54
	private matchCount: MatchCount;
E
Erich Gamma 已提交
55
	public domNode: HTMLElement;
A
Alex Dima 已提交
56
	public inputBox:InputBox;
E
Erich Gamma 已提交
57

A
Alex Dima 已提交
58 59 60 61 62 63 64 65 66
	private _onDidOptionChange = this._register(new Emitter<void>());
	public onDidOptionChange: Event<void> = this._onDidOptionChange.event;

	private _onKeyDown = this._register(new Emitter<StandardKeyboardEvent>());
	public onKeyDown: Event<StandardKeyboardEvent> = this._onKeyDown.event;

	private _onKeyUp = this._register(new Emitter<StandardKeyboardEvent>());
	public onKeyUp: Event<StandardKeyboardEvent> = this._onKeyUp.event;

67 68 69
	private _onCaseSensitiveKeyDown = this._register(new Emitter<StandardKeyboardEvent>());
	public onCaseSensitiveKeyDown: Event<StandardKeyboardEvent> = this._onCaseSensitiveKeyDown.event;

A
Alex Dima 已提交
70 71
	constructor(parent:HTMLElement, contextViewProvider: IContextViewProvider, options?:IFindInputOptions) {
		super();
E
Erich Gamma 已提交
72 73 74 75
		this.contextViewProvider = contextViewProvider;
		this.width = options.width || 100;
		this.placeholder = options.placeholder || '';
		this.validation = options.validation;
76
		this.label = options.label || NLS_DEFAULT_LABEL;
E
Erich Gamma 已提交
77 78 79 80 81 82 83

		this.regex = null;
		this.wholeWords = null;
		this.caseSensitive = null;
		this.domNode = null;
		this.inputBox = null;

84
		this.buildDomNode(options.appendCaseSensitiveLabel || '', options.appendWholeWordsLabel || '', options.appendRegexLabel || '');
E
Erich Gamma 已提交
85 86 87 88 89

		if(Boolean(parent)) {
			parent.appendChild(this.domNode);
		}

A
Alex Dima 已提交
90 91
		this.onkeydown(this.inputBox.inputElement, (e) => this._onKeyDown.fire(e));
		this.onkeyup(this.inputBox.inputElement, (e) => this._onKeyUp.fire(e));
E
Erich Gamma 已提交
92 93 94
	}

	public enable(): void {
A
Alex Dima 已提交
95
		dom.removeClass(this.domNode, 'disabled');
E
Erich Gamma 已提交
96 97 98 99 100 101 102
		this.inputBox.enable();
		this.regex.enable();
		this.wholeWords.enable();
		this.caseSensitive.enable();
	}

	public disable(): void {
A
Alex Dima 已提交
103
		dom.addClass(this.domNode, 'disabled');
E
Erich Gamma 已提交
104 105 106 107 108 109
		this.inputBox.disable();
		this.regex.disable();
		this.wholeWords.disable();
		this.caseSensitive.disable();
	}

110 111 112 113 114 115 116 117
	public setEnabled(enabled:boolean): void {
		if (enabled) {
			this.enable();
		} else {
			this.disable();
		}
	}

E
Erich Gamma 已提交
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
	public clear(): void {
		this.clearValidation();
		this.setValue('');
		this.focus();
	}

	public setWidth(newWidth:number): void {
		this.width = newWidth;
		this.domNode.style.width = this.width + 'px';
		this.contextViewProvider.layout();
		this.setInputWidth();
	}

	public getValue(): string {
		return this.inputBox.value;
	}

	public setValue(value:string): void {
		if (this.inputBox.value !== value) {
			this.inputBox.value = value;
		}
	}

A
Alex Dima 已提交
141 142 143 144 145
	public setMatchCountState(state:IMatchCountState): void {
		this.matchCount.setState(state);
		this.setInputWidth();
	}

E
Erich Gamma 已提交
146 147 148 149 150 151 152 153 154
	public select(): void {
		this.inputBox.select();
	}

	public focus(): void {
		this.inputBox.focus();
	}

	public getCaseSensitive():boolean {
A
Alex Dima 已提交
155
		return this.caseSensitive.checked;
E
Erich Gamma 已提交
156 157 158
	}

	public setCaseSensitive(value:boolean): void {
A
Alex Dima 已提交
159
		this.caseSensitive.checked = value;
E
Erich Gamma 已提交
160 161 162 163
		this.setInputWidth();
	}

	public getWholeWords():boolean {
A
Alex Dima 已提交
164
		return this.wholeWords.checked;
E
Erich Gamma 已提交
165 166 167
	}

	public setWholeWords(value:boolean): void {
A
Alex Dima 已提交
168
		this.wholeWords.checked = value;
E
Erich Gamma 已提交
169 170 171 172
		this.setInputWidth();
	}

	public getRegex():boolean {
A
Alex Dima 已提交
173
		return this.regex.checked;
E
Erich Gamma 已提交
174 175 176
	}

	public setRegex(value:boolean): void {
A
Alex Dima 已提交
177
		this.regex.checked = value;
E
Erich Gamma 已提交
178 179 180 181 182 183 184 185
		this.setInputWidth();
	}

	public focusOnCaseSensitive(): void {
		this.caseSensitive.focus();
	}

	private setInputWidth(): void {
A
Alex Dima 已提交
186
		let w = this.width - this.matchCount.width() - this.caseSensitive.width() - this.wholeWords.width() - this.regex.width();
E
Erich Gamma 已提交
187 188 189
		this.inputBox.width = w;
	}

190
	private buildDomNode(appendCaseSensitiveLabel:string, appendWholeWordsLabel: string, appendRegexLabel: string): void {
E
Erich Gamma 已提交
191 192
		this.domNode = document.createElement('div');
		this.domNode.style.width = this.width + 'px';
A
Alex Dima 已提交
193
		dom.addClass(this.domNode, 'monaco-findInput');
E
Erich Gamma 已提交
194

A
Alex Dima 已提交
195
		this.inputBox = this._register(new InputBox(this.domNode, this.contextViewProvider, {
E
Erich Gamma 已提交
196 197 198 199 200 201
			placeholder: this.placeholder || '',
			ariaLabel: this.label || '',
			validationOptions: {
				validation: this.validation || null,
				showMessage: true
			}
A
Alex Dima 已提交
202
		}));
E
Erich Gamma 已提交
203

A
Alex Dima 已提交
204
		this.regex = this._register(new Checkbox({
A
Alex Dima 已提交
205 206 207 208
			actionClassName: 'regex',
			title: NLS_REGEX_CHECKBOX_LABEL + appendRegexLabel,
			isChecked: false,
			onChange: () => {
A
Alex Dima 已提交
209
				this._onDidOptionChange.fire();
A
Alex Dima 已提交
210 211 212 213
				this.inputBox.focus();
				this.setInputWidth();
				this.validate();
			}
A
Alex Dima 已提交
214 215
		}));
		this.wholeWords = this._register(new Checkbox({
A
Alex Dima 已提交
216 217 218 219
			actionClassName: 'whole-word',
			title: NLS_WHOLE_WORD_CHECKBOX_LABEL + appendWholeWordsLabel,
			isChecked: false,
			onChange: () => {
A
Alex Dima 已提交
220
				this._onDidOptionChange.fire();
A
Alex Dima 已提交
221 222 223 224
				this.inputBox.focus();
				this.setInputWidth();
				this.validate();
			}
A
Alex Dima 已提交
225 226
		}));
		this.caseSensitive = this._register(new Checkbox({
A
Alex Dima 已提交
227 228 229 230
			actionClassName: 'case-sensitive',
			title: NLS_CASE_SENSITIVE_CHECKBOX_LABEL + appendCaseSensitiveLabel,
			isChecked: false,
			onChange: () => {
A
Alex Dima 已提交
231
				this._onDidOptionChange.fire();
A
Alex Dima 已提交
232 233 234
				this.inputBox.focus();
				this.setInputWidth();
				this.validate();
235 236 237
			},
			onKeyDown: (e) => {
				this._onCaseSensitiveKeyDown.fire(e);
A
Alex Dima 已提交
238
			}
A
Alex Dima 已提交
239
		}));
A
Alex Dima 已提交
240 241 242 243 244 245 246
		this.matchCount = this._register(new MatchCount({
			onClick: (e) => {
				this.inputBox.focus();
				e.preventDefault();
			}
		}));

E
Erich Gamma 已提交
247 248
		this.setInputWidth();

A
Alex Dima 已提交
249
		let controls = document.createElement('div');
E
Erich Gamma 已提交
250
		controls.className = 'controls';
A
Alex Dima 已提交
251
		controls.appendChild(this.matchCount.domNode);
E
Erich Gamma 已提交
252 253 254 255 256 257 258 259 260 261 262
		controls.appendChild(this.caseSensitive.domNode);
		controls.appendChild(this.wholeWords.domNode);
		controls.appendChild(this.regex.domNode);

		this.domNode.appendChild(controls);
	}

	public validate(): void {
		this.inputBox.validate();
	}

A
Alex Dima 已提交
263
	public showMessage(message: InputBoxMessage): void {
E
Erich Gamma 已提交
264 265 266 267 268 269 270 271 272 273 274
		this.inputBox.showMessage(message);
	}

	public clearMessage(): void {
		this.inputBox.hideMessage();
	}

	private clearValidation(): void {
		this.inputBox.hideMessage();
	}
}
A
Alex Dima 已提交
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314

interface IMatchCountOpts {
	onClick: (e:StandardMouseEvent) => void;
}

class MatchCount extends Widget {

	public domNode: HTMLElement;
	private isVisible: boolean;

	constructor(opts:IMatchCountOpts) {
		super();
		this.domNode = document.createElement('div');
		this.domNode.className = 'matchCount';

		this.setState({
			isVisible: false,
			count: '0',
			title: ''
		});
		this.onclick(this.domNode, opts.onClick);
	}

	public width(): number {
		return this.isVisible ? 30 : 0;
	}

	public setState(state:IMatchCountState): void {
		dom.clearNode(this.domNode);
		this.domNode.appendChild(document.createTextNode(state.count));
		this.domNode.title = state.title;

		this.isVisible = state.isVisible;
		if (this.isVisible) {
			this.domNode.style.display = 'block';
		} else {
			this.domNode.style.display = 'none';
		}
	}
}