mirror of
https://github.com/Microsoft/vscode
synced 2024-10-30 21:06:57 +00:00
update replace input box size when resizing and display preserve case button properly
This commit is contained in:
parent
45dd218d90
commit
67145b2732
6 changed files with 476 additions and 81 deletions
|
@ -24,6 +24,7 @@ export interface IFindInputOptions extends IFindInputStyles {
|
|||
readonly validation?: IInputValidator;
|
||||
readonly label: string;
|
||||
readonly flexibleHeight?: boolean;
|
||||
readonly flexibleWidth?: boolean;
|
||||
readonly flexibleMaxHeight?: number;
|
||||
|
||||
readonly appendCaseSensitiveLabel?: string;
|
||||
|
@ -120,6 +121,7 @@ export class FindInput extends Widget {
|
|||
const appendRegexLabel = options.appendRegexLabel || '';
|
||||
const history = options.history || [];
|
||||
const flexibleHeight = !!options.flexibleHeight;
|
||||
const flexibleWidth = !!options.flexibleWidth;
|
||||
const flexibleMaxHeight = options.flexibleMaxHeight;
|
||||
|
||||
this.domNode = document.createElement('div');
|
||||
|
@ -145,6 +147,7 @@ export class FindInput extends Widget {
|
|||
inputValidationErrorBorder: this.inputValidationErrorBorder,
|
||||
history,
|
||||
flexibleHeight,
|
||||
flexibleWidth,
|
||||
flexibleMaxHeight
|
||||
}));
|
||||
|
||||
|
@ -197,11 +200,7 @@ export class FindInput extends Widget {
|
|||
}));
|
||||
|
||||
if (this._showOptionButtons) {
|
||||
const paddingRight = (this.caseSensitive.width() + this.wholeWords.width() + this.regex.width()) + 'px';
|
||||
this.inputBox.inputElement.style.paddingRight = paddingRight;
|
||||
if (this.inputBox.mirrorElement) {
|
||||
this.inputBox.mirrorElement.style.paddingRight = paddingRight;
|
||||
}
|
||||
this.inputBox.paddingRight = this.caseSensitive.width() + this.wholeWords.width() + this.regex.width();
|
||||
}
|
||||
|
||||
// Arrow-Key support to navigate between options
|
||||
|
|
378
src/vs/base/browser/ui/findinput/replaceInput.ts
Normal file
378
src/vs/base/browser/ui/findinput/replaceInput.ts
Normal file
|
@ -0,0 +1,378 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./findInput';
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { IMessage as InputBoxMessage, IInputValidator, IInputBoxStyles, HistoryInputBox } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
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 { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { ICheckboxStyles, Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';
|
||||
import { IFindInputCheckboxOpts } from 'vs/base/browser/ui/findinput/findInputCheckboxes';
|
||||
|
||||
export interface IReplaceInputOptions extends IReplaceInputStyles {
|
||||
readonly placeholder?: string;
|
||||
readonly width?: number;
|
||||
readonly validation?: IInputValidator;
|
||||
readonly label: string;
|
||||
readonly flexibleHeight?: boolean;
|
||||
readonly flexibleWidth?: boolean;
|
||||
readonly flexibleMaxHeight?: number;
|
||||
|
||||
readonly history?: string[];
|
||||
}
|
||||
|
||||
export interface IReplaceInputStyles extends IInputBoxStyles {
|
||||
inputActiveOptionBorder?: Color;
|
||||
}
|
||||
|
||||
const NLS_DEFAULT_LABEL = nls.localize('defaultLabel', "input");
|
||||
const NLS_PRESERVE_CASE_LABEL = nls.localize('label.preserveCaseCheckbox', "Preserve Case");
|
||||
|
||||
export class PreserveCaseCheckbox extends Checkbox {
|
||||
constructor(opts: IFindInputCheckboxOpts) {
|
||||
super({
|
||||
// TODO: does this need its own icon?
|
||||
actionClassName: 'monaco-case-sensitive',
|
||||
title: NLS_PRESERVE_CASE_LABEL + opts.appendTitle,
|
||||
isChecked: opts.isChecked,
|
||||
inputActiveOptionBorder: opts.inputActiveOptionBorder
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class ReplaceInput extends Widget {
|
||||
|
||||
static readonly OPTION_CHANGE: string = 'optionChange';
|
||||
|
||||
private contextViewProvider: IContextViewProvider | undefined;
|
||||
private placeholder: string;
|
||||
private validation?: IInputValidator;
|
||||
private label: string;
|
||||
private fixFocusOnOptionClickEnabled = true;
|
||||
|
||||
private inputActiveOptionBorder?: Color;
|
||||
private inputBackground?: Color;
|
||||
private inputForeground?: Color;
|
||||
private inputBorder?: Color;
|
||||
|
||||
private inputValidationInfoBorder?: Color;
|
||||
private inputValidationInfoBackground?: Color;
|
||||
private inputValidationInfoForeground?: Color;
|
||||
private inputValidationWarningBorder?: Color;
|
||||
private inputValidationWarningBackground?: Color;
|
||||
private inputValidationWarningForeground?: Color;
|
||||
private inputValidationErrorBorder?: Color;
|
||||
private inputValidationErrorBackground?: Color;
|
||||
private inputValidationErrorForeground?: Color;
|
||||
|
||||
private preserveCase: PreserveCaseCheckbox;
|
||||
private cachedOptionsWidth: number = 0;
|
||||
public domNode: HTMLElement;
|
||||
public inputBox: HistoryInputBox;
|
||||
|
||||
private readonly _onDidOptionChange = this._register(new Emitter<boolean>());
|
||||
public readonly onDidOptionChange: Event<boolean /* via keyboard */> = this._onDidOptionChange.event;
|
||||
|
||||
private readonly _onKeyDown = this._register(new Emitter<IKeyboardEvent>());
|
||||
public readonly onKeyDown: Event<IKeyboardEvent> = this._onKeyDown.event;
|
||||
|
||||
private readonly _onMouseDown = this._register(new Emitter<IMouseEvent>());
|
||||
public readonly onMouseDown: Event<IMouseEvent> = this._onMouseDown.event;
|
||||
|
||||
private readonly _onInput = this._register(new Emitter<void>());
|
||||
public readonly onInput: Event<void> = this._onInput.event;
|
||||
|
||||
private readonly _onKeyUp = this._register(new Emitter<IKeyboardEvent>());
|
||||
public readonly onKeyUp: Event<IKeyboardEvent> = this._onKeyUp.event;
|
||||
|
||||
private _onPreserveCaseKeyDown = this._register(new Emitter<IKeyboardEvent>());
|
||||
public readonly onPreserveCaseKeyDown: Event<IKeyboardEvent> = this._onPreserveCaseKeyDown.event;
|
||||
|
||||
constructor(parent: HTMLElement | null, contextViewProvider: IContextViewProvider | undefined, private readonly _showOptionButtons: boolean, options: IReplaceInputOptions) {
|
||||
super();
|
||||
this.contextViewProvider = contextViewProvider;
|
||||
this.placeholder = options.placeholder || '';
|
||||
this.validation = options.validation;
|
||||
this.label = options.label || NLS_DEFAULT_LABEL;
|
||||
|
||||
this.inputActiveOptionBorder = options.inputActiveOptionBorder;
|
||||
this.inputBackground = options.inputBackground;
|
||||
this.inputForeground = options.inputForeground;
|
||||
this.inputBorder = options.inputBorder;
|
||||
|
||||
this.inputValidationInfoBorder = options.inputValidationInfoBorder;
|
||||
this.inputValidationInfoBackground = options.inputValidationInfoBackground;
|
||||
this.inputValidationInfoForeground = options.inputValidationInfoForeground;
|
||||
this.inputValidationWarningBorder = options.inputValidationWarningBorder;
|
||||
this.inputValidationWarningBackground = options.inputValidationWarningBackground;
|
||||
this.inputValidationWarningForeground = options.inputValidationWarningForeground;
|
||||
this.inputValidationErrorBorder = options.inputValidationErrorBorder;
|
||||
this.inputValidationErrorBackground = options.inputValidationErrorBackground;
|
||||
this.inputValidationErrorForeground = options.inputValidationErrorForeground;
|
||||
|
||||
const flexibleHeight = !!options.flexibleHeight;
|
||||
const flexibleWidth = !!options.flexibleWidth;
|
||||
const flexibleMaxHeight = options.flexibleMaxHeight;
|
||||
|
||||
this.buildDomNode(options.history || [], flexibleHeight, flexibleWidth, flexibleMaxHeight);
|
||||
|
||||
if (parent) {
|
||||
parent.appendChild(this.domNode);
|
||||
}
|
||||
|
||||
this.onkeydown(this.inputBox.inputElement, (e) => this._onKeyDown.fire(e));
|
||||
this.onkeyup(this.inputBox.inputElement, (e) => this._onKeyUp.fire(e));
|
||||
this.oninput(this.inputBox.inputElement, (e) => this._onInput.fire());
|
||||
this.onmousedown(this.inputBox.inputElement, (e) => this._onMouseDown.fire(e));
|
||||
}
|
||||
|
||||
public enable(): void {
|
||||
dom.removeClass(this.domNode, 'disabled');
|
||||
this.inputBox.enable();
|
||||
this.preserveCase.enable();
|
||||
}
|
||||
|
||||
public disable(): void {
|
||||
dom.addClass(this.domNode, 'disabled');
|
||||
this.inputBox.disable();
|
||||
this.preserveCase.disable();
|
||||
}
|
||||
|
||||
public setFocusInputOnOptionClick(value: boolean): void {
|
||||
this.fixFocusOnOptionClickEnabled = value;
|
||||
}
|
||||
|
||||
public setEnabled(enabled: boolean): void {
|
||||
if (enabled) {
|
||||
this.enable();
|
||||
} else {
|
||||
this.disable();
|
||||
}
|
||||
}
|
||||
|
||||
public clear(): void {
|
||||
this.clearValidation();
|
||||
this.setValue('');
|
||||
this.focus();
|
||||
}
|
||||
|
||||
public getValue(): string {
|
||||
return this.inputBox.value;
|
||||
}
|
||||
|
||||
public setValue(value: string): void {
|
||||
if (this.inputBox.value !== value) {
|
||||
this.inputBox.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public onSearchSubmit(): void {
|
||||
this.inputBox.addToHistory();
|
||||
}
|
||||
|
||||
public style(styles: IReplaceInputStyles): void {
|
||||
this.inputActiveOptionBorder = styles.inputActiveOptionBorder;
|
||||
this.inputBackground = styles.inputBackground;
|
||||
this.inputForeground = styles.inputForeground;
|
||||
this.inputBorder = styles.inputBorder;
|
||||
|
||||
this.inputValidationInfoBackground = styles.inputValidationInfoBackground;
|
||||
this.inputValidationInfoForeground = styles.inputValidationInfoForeground;
|
||||
this.inputValidationInfoBorder = styles.inputValidationInfoBorder;
|
||||
this.inputValidationWarningBackground = styles.inputValidationWarningBackground;
|
||||
this.inputValidationWarningForeground = styles.inputValidationWarningForeground;
|
||||
this.inputValidationWarningBorder = styles.inputValidationWarningBorder;
|
||||
this.inputValidationErrorBackground = styles.inputValidationErrorBackground;
|
||||
this.inputValidationErrorForeground = styles.inputValidationErrorForeground;
|
||||
this.inputValidationErrorBorder = styles.inputValidationErrorBorder;
|
||||
|
||||
this.applyStyles();
|
||||
}
|
||||
|
||||
protected applyStyles(): void {
|
||||
if (this.domNode) {
|
||||
const checkBoxStyles: ICheckboxStyles = {
|
||||
inputActiveOptionBorder: this.inputActiveOptionBorder,
|
||||
};
|
||||
this.preserveCase.style(checkBoxStyles);
|
||||
|
||||
const inputBoxStyles: IInputBoxStyles = {
|
||||
inputBackground: this.inputBackground,
|
||||
inputForeground: this.inputForeground,
|
||||
inputBorder: this.inputBorder,
|
||||
inputValidationInfoBackground: this.inputValidationInfoBackground,
|
||||
inputValidationInfoForeground: this.inputValidationInfoForeground,
|
||||
inputValidationInfoBorder: this.inputValidationInfoBorder,
|
||||
inputValidationWarningBackground: this.inputValidationWarningBackground,
|
||||
inputValidationWarningForeground: this.inputValidationWarningForeground,
|
||||
inputValidationWarningBorder: this.inputValidationWarningBorder,
|
||||
inputValidationErrorBackground: this.inputValidationErrorBackground,
|
||||
inputValidationErrorForeground: this.inputValidationErrorForeground,
|
||||
inputValidationErrorBorder: this.inputValidationErrorBorder
|
||||
};
|
||||
this.inputBox.style(inputBoxStyles);
|
||||
}
|
||||
}
|
||||
|
||||
public select(): void {
|
||||
this.inputBox.select();
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
this.inputBox.focus();
|
||||
}
|
||||
|
||||
public getPreserveCase(): boolean {
|
||||
return this.preserveCase.checked;
|
||||
}
|
||||
|
||||
public setPreserveCase(value: boolean): void {
|
||||
this.preserveCase.checked = value;
|
||||
}
|
||||
|
||||
public focusOnPreserve(): void {
|
||||
this.preserveCase.focus();
|
||||
}
|
||||
|
||||
private _lastHighlightFindOptions: number = 0;
|
||||
public highlightFindOptions(): void {
|
||||
dom.removeClass(this.domNode, 'highlight-' + (this._lastHighlightFindOptions));
|
||||
this._lastHighlightFindOptions = 1 - this._lastHighlightFindOptions;
|
||||
dom.addClass(this.domNode, 'highlight-' + (this._lastHighlightFindOptions));
|
||||
}
|
||||
|
||||
private buildDomNode(history: string[], flexibleHeight: boolean, flexibleWidth: boolean, flexibleMaxHeight: number | undefined): void {
|
||||
this.domNode = document.createElement('div');
|
||||
dom.addClass(this.domNode, 'monaco-findInput');
|
||||
|
||||
this.inputBox = this._register(new HistoryInputBox(this.domNode, this.contextViewProvider, {
|
||||
ariaLabel: this.label || '',
|
||||
placeholder: this.placeholder || '',
|
||||
validationOptions: {
|
||||
validation: this.validation
|
||||
},
|
||||
inputBackground: this.inputBackground,
|
||||
inputForeground: this.inputForeground,
|
||||
inputBorder: this.inputBorder,
|
||||
inputValidationInfoBackground: this.inputValidationInfoBackground,
|
||||
inputValidationInfoForeground: this.inputValidationInfoForeground,
|
||||
inputValidationInfoBorder: this.inputValidationInfoBorder,
|
||||
inputValidationWarningBackground: this.inputValidationWarningBackground,
|
||||
inputValidationWarningForeground: this.inputValidationWarningForeground,
|
||||
inputValidationWarningBorder: this.inputValidationWarningBorder,
|
||||
inputValidationErrorBackground: this.inputValidationErrorBackground,
|
||||
inputValidationErrorForeground: this.inputValidationErrorForeground,
|
||||
inputValidationErrorBorder: this.inputValidationErrorBorder,
|
||||
history,
|
||||
flexibleHeight,
|
||||
flexibleWidth,
|
||||
flexibleMaxHeight
|
||||
}));
|
||||
|
||||
this.preserveCase = this._register(new PreserveCaseCheckbox({
|
||||
appendTitle: '',
|
||||
isChecked: false,
|
||||
inputActiveOptionBorder: this.inputActiveOptionBorder
|
||||
}));
|
||||
this._register(this.preserveCase.onChange(viaKeyboard => {
|
||||
this._onDidOptionChange.fire(viaKeyboard);
|
||||
if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
|
||||
this.inputBox.focus();
|
||||
}
|
||||
this.validate();
|
||||
}));
|
||||
this._register(this.preserveCase.onKeyDown(e => {
|
||||
this._onPreserveCaseKeyDown.fire(e);
|
||||
}));
|
||||
|
||||
if (this._showOptionButtons) {
|
||||
this.cachedOptionsWidth = this.preserveCase.width();
|
||||
// const paddingRight = () + 'px';
|
||||
// this.inputBox.inputElement.style.paddingRight = paddingRight;
|
||||
// if (this.inputBox.mirrorElement) {
|
||||
// this.inputBox.mirrorElement.style.paddingRight = paddingRight;
|
||||
// }
|
||||
} else {
|
||||
this.cachedOptionsWidth = 0;
|
||||
}
|
||||
|
||||
// Arrow-Key support to navigate between options
|
||||
let indexes = [this.preserveCase.domNode];
|
||||
this.onkeydown(this.domNode, (event: IKeyboardEvent) => {
|
||||
if (event.equals(KeyCode.LeftArrow) || event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Escape)) {
|
||||
let index = indexes.indexOf(<HTMLElement>document.activeElement);
|
||||
if (index >= 0) {
|
||||
let newIndex: number = -1;
|
||||
if (event.equals(KeyCode.RightArrow)) {
|
||||
newIndex = (index + 1) % indexes.length;
|
||||
} else if (event.equals(KeyCode.LeftArrow)) {
|
||||
if (index === 0) {
|
||||
newIndex = indexes.length - 1;
|
||||
} else {
|
||||
newIndex = index - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.equals(KeyCode.Escape)) {
|
||||
indexes[index].blur();
|
||||
} else if (newIndex >= 0) {
|
||||
indexes[newIndex].focus();
|
||||
}
|
||||
|
||||
dom.EventHelper.stop(event, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
let controls = document.createElement('div');
|
||||
controls.className = 'controls';
|
||||
controls.style.display = this._showOptionButtons ? 'block' : 'none';
|
||||
controls.appendChild(this.preserveCase.domNode);
|
||||
|
||||
this.domNode.appendChild(controls);
|
||||
}
|
||||
|
||||
public validate(): void {
|
||||
if (this.inputBox) {
|
||||
this.inputBox.validate();
|
||||
}
|
||||
}
|
||||
|
||||
public showMessage(message: InputBoxMessage): void {
|
||||
if (this.inputBox) {
|
||||
this.inputBox.showMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
public clearMessage(): void {
|
||||
if (this.inputBox) {
|
||||
this.inputBox.hideMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private clearValidation(): void {
|
||||
if (this.inputBox) {
|
||||
this.inputBox.hideMessage();
|
||||
}
|
||||
}
|
||||
|
||||
public set width(newWidth: number) {
|
||||
this.inputBox.paddingRight = this.cachedOptionsWidth;
|
||||
this.inputBox.width = newWidth;
|
||||
this.domNode.style.width = newWidth + 'px';
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ export interface IInputOptions extends IInputBoxStyles {
|
|||
readonly type?: string;
|
||||
readonly validationOptions?: IInputValidationOptions;
|
||||
readonly flexibleHeight?: boolean;
|
||||
readonly flexibleWidth?: boolean;
|
||||
readonly flexibleMaxHeight?: number;
|
||||
readonly actions?: ReadonlyArray<IAction>;
|
||||
}
|
||||
|
@ -173,6 +174,12 @@ export class InputBox extends Widget {
|
|||
this.mirror.innerHTML = ' ';
|
||||
|
||||
this.scrollableElement = new ScrollableElement(this.element, { vertical: ScrollbarVisibility.Auto });
|
||||
|
||||
if (this.options.flexibleWidth) {
|
||||
this.input.setAttribute('wrap', 'off');
|
||||
this.mirror.style.whiteSpace = 'pre';
|
||||
}
|
||||
|
||||
dom.append(container, this.scrollableElement.getDomNode());
|
||||
this._register(this.scrollableElement);
|
||||
|
||||
|
@ -321,12 +328,36 @@ export class InputBox extends Widget {
|
|||
}
|
||||
|
||||
public set width(width: number) {
|
||||
this.input.style.width = width + 'px';
|
||||
if (this.options.flexibleHeight && this.options.flexibleWidth) {
|
||||
// textarea with horizontal scrolling
|
||||
let horizontalPadding = 0;
|
||||
if (this.mirror) {
|
||||
const paddingLeft = parseFloat(this.mirror.style.paddingLeft || '') || 0;
|
||||
const paddingRight = parseFloat(this.mirror.style.paddingRight || '') || 0;
|
||||
horizontalPadding = paddingLeft + paddingRight;
|
||||
}
|
||||
this.input.style.width = (width - horizontalPadding) + 'px';
|
||||
} else {
|
||||
this.input.style.width = width + 'px';
|
||||
}
|
||||
|
||||
if (this.mirror) {
|
||||
this.mirror.style.width = width + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
public set paddingRight(paddingRight: number) {
|
||||
if (this.options.flexibleHeight && this.options.flexibleWidth) {
|
||||
this.input.style.width = `calc(100% - ${paddingRight}px)`;
|
||||
} else {
|
||||
this.input.style.paddingRight = paddingRight + 'px';
|
||||
}
|
||||
|
||||
if (this.mirror) {
|
||||
this.mirror.style.paddingRight = paddingRight + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
private updateScrollDimensions(): void {
|
||||
if (typeof this.cachedContentHeight !== 'number' || typeof this.cachedHeight !== 'number') {
|
||||
return;
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
min-height: 0;
|
||||
}
|
||||
|
||||
.monaco-editor .find-widget .replace-input .input {
|
||||
.monaco-editor .find-widget .monaco-findInput .input {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
|
@ -79,12 +79,8 @@
|
|||
min-height: 25px;
|
||||
}
|
||||
|
||||
.monaco-editor .find-widget > .find-part .monaco-inputbox > .wrapper > .input {
|
||||
width: 100% !important;
|
||||
padding-right: 66px;
|
||||
}
|
||||
|
||||
.monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .input {
|
||||
.monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .mirror {
|
||||
padding-right: 22px;
|
||||
}
|
||||
|
||||
|
@ -120,8 +116,7 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
.monaco-editor .find-widget .monaco-findInput .monaco-scrollable-element .scrollbar.vertical,
|
||||
.monaco-editor .find-widget .replace-input .monaco-scrollable-element .scrollbar.vertical {
|
||||
.monaco-editor .find-widget .monaco-findInput .monaco-scrollable-element .scrollbar.vertical {
|
||||
/* Hide vertical scrollbar */
|
||||
opacity: 0;
|
||||
}
|
||||
|
@ -257,15 +252,17 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
.monaco-editor .find-widget > .replace-part > .replace-input {
|
||||
.monaco-editor .find-widget > .replace-part > .monaco-findInput {
|
||||
position: relative;
|
||||
display: flex;
|
||||
display: -webkit-flex;
|
||||
vertical-align: middle;
|
||||
width: auto !important;
|
||||
flex: auto;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.monaco-editor .find-widget > .replace-part > .replace-input > .controls {
|
||||
.monaco-editor .find-widget > .replace-part > .monaco-findInput > .controls {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
right: 2px;
|
||||
|
|
|
@ -10,10 +10,9 @@ import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
|||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { FindInput, IFindInputStyles } from 'vs/base/browser/ui/findinput/findInput';
|
||||
import { HistoryInputBox, IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { IHorizontalSashLayoutProvider, ISashEvent, Orientation, Sash } from 'vs/base/browser/ui/sash/sash';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';
|
||||
import { Delayer } from 'vs/base/common/async';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
|
@ -30,9 +29,10 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c
|
|||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { contrastBorder, editorFindMatch, editorFindMatchBorder, editorFindMatchHighlight, editorFindMatchHighlightBorder, editorFindRangeHighlight, editorFindRangeHighlightBorder, editorWidgetBackground, editorWidgetBorder, editorWidgetResizeBorder, errorForeground, inputActiveOptionBorder, inputActiveOptionBackground, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { ContextScopedFindInput, ContextScopedHistoryInputBox } from 'vs/platform/browser/contextScopedHistoryWidget';
|
||||
import { ContextScopedFindInput, ContextScopedReplaceInput } from 'vs/platform/browser/contextScopedHistoryWidget';
|
||||
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { alert as alertFn } from 'vs/base/browser/ui/aria/aria';
|
||||
import { ReplaceInput } from 'vs/base/browser/ui/findinput/replaceInput';
|
||||
|
||||
export interface IFindController {
|
||||
replace(): void;
|
||||
|
@ -48,7 +48,6 @@ const NLS_TOGGLE_SELECTION_FIND_TITLE = nls.localize('label.toggleSelectionFind'
|
|||
const NLS_CLOSE_BTN_LABEL = nls.localize('label.closeButton', "Close");
|
||||
const NLS_REPLACE_INPUT_LABEL = nls.localize('label.replace', "Replace");
|
||||
const NLS_REPLACE_INPUT_PLACEHOLDER = nls.localize('placeholder.replace', "Replace");
|
||||
const NLS_PRESERVE_CASE_LABEL = nls.localize('label.preserveCaseCheckbox', "Preserve Case");
|
||||
const NLS_REPLACE_BTN_LABEL = nls.localize('label.replaceButton', "Replace");
|
||||
const NLS_REPLACE_ALL_BTN_LABEL = nls.localize('label.replaceAllButton', "Replace All");
|
||||
const NLS_TOGGLE_REPLACE_MODE_BTN_LABEL = nls.localize('label.toggleReplaceButton', "Toggle Replace mode");
|
||||
|
@ -59,7 +58,6 @@ const NLS_NO_RESULTS = nls.localize('label.noResults', "No Results");
|
|||
const FIND_WIDGET_INITIAL_WIDTH = 411;
|
||||
const PART_WIDTH = 275;
|
||||
const FIND_INPUT_AREA_WIDTH = PART_WIDTH - 54;
|
||||
const REPLACE_INPUT_AREA_WIDTH = FIND_INPUT_AREA_WIDTH;
|
||||
|
||||
let MAX_MATCHES_COUNT_WIDTH = 69;
|
||||
let FIND_ALL_CONTROLS_WIDTH = 17/** Find Input margin-left */ + (MAX_MATCHES_COUNT_WIDTH + 3 + 1) /** Match Results */ + 23 /** Button */ * 4 + 2/** sash */;
|
||||
|
@ -110,7 +108,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
private _domNode!: HTMLElement;
|
||||
private _cachedHeight: number | null;
|
||||
private _findInput!: FindInput;
|
||||
private _replaceInputBox!: HistoryInputBox;
|
||||
private _replaceInput!: ReplaceInput;
|
||||
|
||||
private _toggleReplaceBtn!: SimpleButton;
|
||||
private _matchesCount!: HTMLElement;
|
||||
|
@ -118,7 +116,6 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
private _nextBtn!: SimpleButton;
|
||||
private _toggleSelectionFind!: SimpleCheckbox;
|
||||
private _closeBtn!: SimpleButton;
|
||||
private _preserveCase!: Checkbox;
|
||||
private _replaceBtn!: SimpleButton;
|
||||
private _replaceAllBtn!: SimpleButton;
|
||||
|
||||
|
@ -218,7 +215,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
}));
|
||||
|
||||
this._replaceInputFocused = CONTEXT_REPLACE_INPUT_FOCUSED.bindTo(contextKeyService);
|
||||
this._replaceFocusTracker = this._register(dom.trackFocus(this._replaceInputBox.inputElement));
|
||||
this._replaceFocusTracker = this._register(dom.trackFocus(this._replaceInput.inputBox.inputElement));
|
||||
this._register(this._replaceFocusTracker.onDidFocus(() => {
|
||||
this._replaceInputFocused.set(true);
|
||||
this._updateSearchScope();
|
||||
|
@ -288,7 +285,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
this._updateButtons();
|
||||
}
|
||||
if (e.replaceString) {
|
||||
this._replaceInputBox.value = this._state.replaceString;
|
||||
this._replaceInput.inputBox.value = this._state.replaceString;
|
||||
}
|
||||
if (e.isRevealed) {
|
||||
if (this._state.isRevealed) {
|
||||
|
@ -301,7 +298,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
if (this._state.isReplaceRevealed) {
|
||||
if (!this._codeEditor.getConfiguration().readOnly && !this._isReplaceVisible) {
|
||||
this._isReplaceVisible = true;
|
||||
this._replaceInputBox.width = this._findInput.inputBox.width;
|
||||
this._replaceInput.width = dom.getTotalWidth(this._findInput.domNode);
|
||||
this._updateButtons();
|
||||
}
|
||||
} else {
|
||||
|
@ -358,7 +355,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
this._findInput.inputBox.addToHistory();
|
||||
}
|
||||
if (this._state.replaceString) {
|
||||
this._replaceInputBox.addToHistory();
|
||||
this._replaceInput.inputBox.addToHistory();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -423,7 +420,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
|
||||
private _updateButtons(): void {
|
||||
this._findInput.setEnabled(this._isVisible);
|
||||
this._replaceInputBox.setEnabled(this._isVisible && this._isReplaceVisible);
|
||||
this._replaceInput.setEnabled(this._isVisible && this._isReplaceVisible);
|
||||
this._updateToggleSelectionFindButton();
|
||||
this._closeBtn.setEnabled(this._isVisible);
|
||||
|
||||
|
@ -617,8 +614,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
inputValidationErrorBorder: theme.getColor(inputValidationErrorBorder),
|
||||
};
|
||||
this._findInput.style(inputStyles);
|
||||
this._replaceInputBox.style(inputStyles);
|
||||
this._preserveCase.style(inputStyles);
|
||||
this._replaceInput.style(inputStyles);
|
||||
}
|
||||
|
||||
private _tryUpdateWidgetWidth() {
|
||||
|
@ -648,7 +644,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
if (widgetWidth > FIND_WIDGET_INITIAL_WIDTH) {
|
||||
// as the widget is resized by users, we may need to change the max width of the widget as the editor width changes.
|
||||
this._domNode.style.maxWidth = `${editorWidth - 28 - minimapWidth - 15}px`;
|
||||
this._replaceInputBox.width = dom.getTotalWidth(this._findInput.inputBox.inputElement);
|
||||
this._replaceInput.width = dom.getTotalWidth(this._findInput.domNode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -675,7 +671,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
this._findInput.inputBox.layout();
|
||||
let findInputWidth = this._findInput.inputBox.width;
|
||||
if (findInputWidth > 0) {
|
||||
this._replaceInputBox.width = findInputWidth;
|
||||
this._replaceInput.width = findInputWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -693,7 +689,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
// replace input margin
|
||||
totalheight += 4;
|
||||
|
||||
totalheight += this._replaceInputBox.height + 2 /** input box border */;
|
||||
totalheight += this._replaceInput.inputBox.height + 2 /** input box border */;
|
||||
}
|
||||
|
||||
// margin bottom
|
||||
|
@ -722,9 +718,9 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
}
|
||||
|
||||
public focusReplaceInput(): void {
|
||||
this._replaceInputBox.select();
|
||||
this._replaceInput.select();
|
||||
// Edge browser requires focus() in addition to select()
|
||||
this._replaceInputBox.focus();
|
||||
this._replaceInput.focus();
|
||||
}
|
||||
|
||||
public highlightFindOptions(): void {
|
||||
|
@ -790,7 +786,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
|
||||
if (e.equals(KeyCode.Tab)) {
|
||||
if (this._isReplaceVisible) {
|
||||
this._replaceInputBox.focus();
|
||||
this._replaceInput.focus();
|
||||
} else {
|
||||
this._findInput.focusOnCaseSensitive();
|
||||
}
|
||||
|
@ -822,16 +818,16 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
}
|
||||
|
||||
if (e.equals(KeyMod.WinCtrl | KeyCode.Enter)) {
|
||||
const inputElement = this._replaceInputBox.inputElement;
|
||||
const inputElement = this._replaceInput.inputBox.inputElement;
|
||||
const start = inputElement.selectionStart;
|
||||
const end = inputElement.selectionEnd;
|
||||
const content = inputElement.value;
|
||||
|
||||
if (start && end) {
|
||||
const value = content.substr(0, start) + '\n' + content.substr(end);
|
||||
this._replaceInputBox.value = value;
|
||||
this._replaceInput.inputBox.value = value;
|
||||
inputElement.setSelectionRange(start + 1, start + 1);
|
||||
this._replaceInputBox.layout();
|
||||
this._replaceInput.inputBox.layout();
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
@ -862,11 +858,11 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
}
|
||||
|
||||
if (e.equals(KeyCode.UpArrow)) {
|
||||
return stopPropagationForMultiLineUpwards(e, this._replaceInputBox.value, this._replaceInputBox.element.querySelector('textarea'));
|
||||
return stopPropagationForMultiLineUpwards(e, this._replaceInput.inputBox.value, this._replaceInput.inputBox.element.querySelector('textarea'));
|
||||
}
|
||||
|
||||
if (e.equals(KeyCode.DownArrow)) {
|
||||
return stopPropagationForMultiLineDownwards(e, this._replaceInputBox.value, this._replaceInputBox.element.querySelector('textarea'));
|
||||
return stopPropagationForMultiLineDownwards(e, this._replaceInput.inputBox.value, this._replaceInput.inputBox.element.querySelector('textarea'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -913,6 +909,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
}
|
||||
},
|
||||
flexibleHeight: true,
|
||||
flexibleWidth: true,
|
||||
flexibleMaxHeight: 118
|
||||
}, this._contextKeyService, true));
|
||||
this._findInput.setRegex(!!this._state.isRegex);
|
||||
|
@ -935,7 +932,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
this._register(this._findInput.onCaseSensitiveKeyDown((e) => {
|
||||
if (e.equals(KeyMod.Shift | KeyCode.Tab)) {
|
||||
if (this._isReplaceVisible) {
|
||||
this._replaceInputBox.focus();
|
||||
this._replaceInput.focus();
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
@ -943,7 +940,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
this._register(this._findInput.onRegexKeyDown((e) => {
|
||||
if (e.equals(KeyCode.Tab)) {
|
||||
if (this._isReplaceVisible) {
|
||||
this._preserveCase.focus();
|
||||
this._replaceInput.focusOnPreserve();
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
@ -1034,41 +1031,30 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
actionsContainer.appendChild(this._closeBtn.domNode);
|
||||
|
||||
// Replace input
|
||||
let replaceInput = document.createElement('div');
|
||||
replaceInput.className = 'replace-input';
|
||||
replaceInput.style.width = REPLACE_INPUT_AREA_WIDTH + 'px';
|
||||
this._replaceInputBox = this._register(new ContextScopedHistoryInputBox(replaceInput, undefined, {
|
||||
ariaLabel: NLS_REPLACE_INPUT_LABEL,
|
||||
this._replaceInput = this._register(new ContextScopedReplaceInput(null, undefined, {
|
||||
label: NLS_REPLACE_INPUT_LABEL,
|
||||
placeholder: NLS_REPLACE_INPUT_PLACEHOLDER,
|
||||
history: [],
|
||||
flexibleHeight: true,
|
||||
flexibleWidth: true,
|
||||
flexibleMaxHeight: 118
|
||||
}, this._contextKeyService));
|
||||
|
||||
|
||||
this._register(dom.addStandardDisposableListener(this._replaceInputBox.inputElement, 'keydown', (e) => this._onReplaceInputKeyDown(e)));
|
||||
this._register(this._replaceInputBox.onDidChange(() => {
|
||||
this._state.change({ replaceString: this._replaceInputBox.value }, false);
|
||||
}, this._contextKeyService, true));
|
||||
this._replaceInput.setPreserveCase(!!this._state.preserveCase);
|
||||
this._register(this._replaceInput.onKeyDown((e) => this._onReplaceInputKeyDown(e)));
|
||||
this._register(this._replaceInput.inputBox.onDidChange(() => {
|
||||
this._state.change({ replaceString: this._replaceInput.inputBox.value }, false);
|
||||
}));
|
||||
this._register(this._replaceInputBox.onDidHeightChange((e) => {
|
||||
this._register(this._replaceInput.inputBox.onDidHeightChange((e) => {
|
||||
if (this._isReplaceVisible && this._tryUpdateHeight()) {
|
||||
this._showViewZone();
|
||||
}
|
||||
}));
|
||||
|
||||
this._preserveCase = this._register(new Checkbox({
|
||||
actionClassName: 'monaco-preserve-case',
|
||||
title: NLS_PRESERVE_CASE_LABEL,
|
||||
isChecked: false,
|
||||
this._register(this._replaceInput.onDidOptionChange(() => {
|
||||
this._state.change({
|
||||
preserveCase: this._replaceInput.getPreserveCase()
|
||||
}, true);
|
||||
}));
|
||||
this._preserveCase.checked = !!this._state.preserveCase;
|
||||
this._register(this._preserveCase.onChange(viaKeyboard => {
|
||||
if (!viaKeyboard) {
|
||||
this._state.change({ preserveCase: !this._state.preserveCase }, false);
|
||||
this._replaceInputBox.focus();
|
||||
}
|
||||
}));
|
||||
this._register(this._preserveCase.onKeyDown((e) => {
|
||||
this._register(this._replaceInput.onPreserveCaseKeyDown((e) => {
|
||||
if (e.equals(KeyCode.Tab)) {
|
||||
if (this._prevBtn.isEnabled()) {
|
||||
this._prevBtn.focus();
|
||||
|
@ -1082,8 +1068,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
));
|
||||
}));
|
||||
|
||||
// Replace one button
|
||||
this._replaceBtn = this._register(new SimpleButton({
|
||||
|
@ -1109,15 +1094,9 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
}
|
||||
}));
|
||||
|
||||
let controls = document.createElement('div');
|
||||
controls.className = 'controls';
|
||||
controls.style.display = 'block';
|
||||
controls.appendChild(this._preserveCase.domNode);
|
||||
replaceInput.appendChild(controls);
|
||||
|
||||
let replacePart = document.createElement('div');
|
||||
replacePart.className = 'replace-part';
|
||||
replacePart.appendChild(replaceInput);
|
||||
replacePart.appendChild(this._replaceInput.domNode);
|
||||
|
||||
const replaceActionsContainer = document.createElement('div');
|
||||
replaceActionsContainer.className = 'replace-actions';
|
||||
|
@ -1133,8 +1112,8 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
onTrigger: () => {
|
||||
this._state.change({ isReplaceRevealed: !this._isReplaceVisible }, false);
|
||||
if (this._isReplaceVisible) {
|
||||
this._replaceInputBox.width = this._findInput.inputBox.width;
|
||||
this._replaceInputBox.layout();
|
||||
this._replaceInput.width = dom.getTotalWidth(this._findInput.domNode);
|
||||
this._replaceInput.inputBox.layout();
|
||||
}
|
||||
this._showViewZone();
|
||||
}
|
||||
|
@ -1179,7 +1158,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||
this._domNode.style.width = `${width}px`;
|
||||
this._findInput.inputBox.width = inputBoxWidth;
|
||||
if (this._isReplaceVisible) {
|
||||
this._replaceInputBox.width = inputBoxWidth;
|
||||
this._replaceInput.width = dom.getTotalWidth(this._findInput.domNode);
|
||||
}
|
||||
|
||||
this._findInput.inputBox.layout();
|
||||
|
|
|
@ -10,6 +10,7 @@ import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview
|
|||
import { IHistoryNavigationWidget } from 'vs/base/browser/history';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { ReplaceInput, IReplaceInputOptions } from 'vs/base/browser/ui/findinput/replaceInput';
|
||||
|
||||
export const HistoryNavigationWidgetContext = 'historyNavigationWidget';
|
||||
export const HistoryNavigationEnablementContext = 'historyNavigationEnabled';
|
||||
|
@ -60,6 +61,16 @@ export class ContextScopedFindInput extends FindInput {
|
|||
super(container, contextViewProvider, showFindOptions, options);
|
||||
this._register(createAndBindHistoryNavigationWidgetScopedContextKeyService(contextKeyService, <IContextScopedHistoryNavigationWidget>{ target: this.inputBox.element, historyNavigator: this.inputBox }).scopedContextKeyService);
|
||||
}
|
||||
}
|
||||
|
||||
export class ContextScopedReplaceInput extends ReplaceInput {
|
||||
|
||||
constructor(container: HTMLElement | null, contextViewProvider: IContextViewProvider | undefined, options: IReplaceInputOptions,
|
||||
@IContextKeyService contextKeyService: IContextKeyService, showReplaceOptions: boolean = false
|
||||
) {
|
||||
super(container, contextViewProvider, showReplaceOptions, options);
|
||||
this._register(createAndBindHistoryNavigationWidgetScopedContextKeyService(contextKeyService, <IContextScopedHistoryNavigationWidget>{ target: this.inputBox.element, historyNavigator: this.inputBox }).scopedContextKeyService);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue