提交 acff3d07 编写于 作者: A Alex Dima

Move text area creation to TextAreaHandler

上级 de797d87
......@@ -14,15 +14,17 @@ import { Configuration } from 'vs/editor/browser/config/configuration';
import { ViewContext } from 'vs/editor/common/view/viewContext';
import { HorizontalRange } from 'vs/editor/common/view/renderingContext';
import * as viewEvents from 'vs/editor/common/view/viewEvents';
import { FastDomNode } from 'vs/base/browser/fastDomNode';
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
import { VerticalRevealType } from 'vs/editor/common/controller/cursorEvents';
import { ViewController } from 'vs/editor/browser/view/viewController';
import { EndOfLinePreference } from "vs/editor/common/editorCommon";
import { IKeyboardEvent } from "vs/base/browser/keyboardEvent";
import { PartFingerprints, PartFingerprint } from "vs/editor/browser/view/viewPart";
import { Margin } from "vs/editor/browser/viewParts/margin/margin";
import { LineNumbersOverlay } from "vs/editor/browser/viewParts/lineNumbers/lineNumbers";
export interface IKeyboardHandlerHelper {
export interface ITextAreaHandlerHelper {
viewDomNode: FastDomNode<HTMLElement>;
textArea: FastDomNode<HTMLTextAreaElement>;
visibleRangeForPositionRelativeToEditor(lineNumber: number, column: number): HorizontalRange;
getVerticalOffsetForLineNumber(lineNumber: number): number;
}
......@@ -44,12 +46,11 @@ export const enum TextAreaStrategy {
NVDA
}
export class KeyboardHandler extends ViewEventHandler {
export class TextAreaHandler extends ViewEventHandler {
private readonly _context: ViewContext;
private readonly _viewController: ViewController;
private readonly _textArea: FastDomNode<HTMLTextAreaElement>;
private readonly _viewHelper: IKeyboardHandlerHelper;
private readonly _viewHelper: ITextAreaHandlerHelper;
private _contentLeft: number;
private _contentWidth: number;
......@@ -61,15 +62,15 @@ export class KeyboardHandler extends ViewEventHandler {
private _lastCopiedValue: string;
private _lastCopiedValueIsFromEmptySelection: boolean;
public readonly textArea: FastDomNode<HTMLTextAreaElement>;
public readonly textAreaCover: FastDomNode<HTMLElement>;
private readonly _textAreaInput: TextAreaInput;
constructor(context: ViewContext, viewController: ViewController, viewHelper: IKeyboardHandlerHelper) {
constructor(context: ViewContext, viewController: ViewController, viewHelper: ITextAreaHandlerHelper) {
super();
this._context = context;
this._viewController = viewController;
this._textArea = viewHelper.textArea;
Configuration.applyFontInfo(this._textArea, this._context.configuration.editor.fontInfo);
this._viewHelper = viewHelper;
this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft;
......@@ -82,6 +83,43 @@ export class KeyboardHandler extends ViewEventHandler {
this._lastCopiedValue = null;
this._lastCopiedValueIsFromEmptySelection = false;
// Text Area (The focus will always be in the textarea when the cursor is blinking)
this.textArea = createFastDomNode(document.createElement('textarea'));
PartFingerprints.write(this.textArea, PartFingerprint.TextArea);
this.textArea.setClassName('inputarea');
this.textArea.setAttribute('wrap', 'off');
this.textArea.setAttribute('autocorrect', 'off');
this.textArea.setAttribute('autocapitalize', 'off');
this.textArea.setAttribute('spellcheck', 'false');
this.textArea.setAttribute('aria-label', this._context.configuration.editor.viewInfo.ariaLabel);
this.textArea.setAttribute('role', 'textbox');
this.textArea.setAttribute('aria-multiline', 'true');
this.textArea.setAttribute('aria-haspopup', 'false');
this.textArea.setAttribute('aria-autocomplete', 'both');
this.textArea.setTop(0);
this.textArea.setLeft(0);
Configuration.applyFontInfo(this.textArea, this._context.configuration.editor.fontInfo);
// On top of the text area, we position a dom node to cover it up
// (there have been reports of tiny blinking cursors)
// (in WebKit the textarea is 1px by 1px because it cannot handle input to a 0x0 textarea)
this.textAreaCover = createFastDomNode(document.createElement('div'));
if (this._context.configuration.editor.viewInfo.glyphMargin) {
this.textAreaCover.setClassName('monaco-editor-background ' + Margin.CLASS_NAME + ' ' + 'textAreaCover');
} else {
if (this._context.configuration.editor.viewInfo.renderLineNumbers) {
this.textAreaCover.setClassName('monaco-editor-background ' + LineNumbersOverlay.CLASS_NAME + ' ' + 'textAreaCover');
} else {
this.textAreaCover.setClassName('monaco-editor-background ' + 'textAreaCover');
}
}
this.textAreaCover.setPosition('absolute');
this.textAreaCover.setWidth(1);
this.textAreaCover.setHeight(1);
this.textAreaCover.setTop(0);
this.textAreaCover.setLeft(0);
const simpleModel: ISimpleModel = {
getLineCount: (): number => {
return this._context.model.getLineCount();
......@@ -136,7 +174,7 @@ export class KeyboardHandler extends ViewEventHandler {
}
};
this._textAreaInput = this._register(new TextAreaInput(textAreaInputHost, this._textArea));
this._textAreaInput = this._register(new TextAreaInput(textAreaInputHost, this.textArea));
this._register(this._textAreaInput.onKeyDown((e: IKeyboardEvent) => {
this._viewController.emitKeyDown(e);
......@@ -184,12 +222,12 @@ export class KeyboardHandler extends ViewEventHandler {
this._viewHelper.getVerticalOffsetForLineNumber(lineNumber),
visibleRange.left
);
this._textArea.setTop(this._visiblePosition.top - this._scrollTop);
this._textArea.setLeft(this._contentLeft + this._visiblePosition.left - this._scrollLeft);
this.textArea.setTop(this._visiblePosition.top - this._scrollTop);
this.textArea.setLeft(this._contentLeft + this._visiblePosition.left - this._scrollLeft);
}
// Show the textarea
this._textArea.setHeight(this._context.configuration.editor.lineHeight);
this.textArea.setHeight(this._context.configuration.editor.lineHeight);
this._viewHelper.viewDomNode.addClassName('ime-input');
this._viewController.compositionStart('keyboard');
......@@ -199,30 +237,30 @@ export class KeyboardHandler extends ViewEventHandler {
if (browser.isEdgeOrIE) {
// Due to isEdgeOrIE (where the textarea was not cleared initially)
// we cannot assume the text consists only of the composited text
this._textArea.setWidth(0);
this.textArea.setWidth(0);
} else {
// adjust width by its size
let canvasElem = <HTMLCanvasElement>document.createElement('canvas');
let context = canvasElem.getContext('2d');
let cs = dom.getComputedStyle(this._textArea.domNode);
let cs = dom.getComputedStyle(this.textArea.domNode);
if (browser.isFirefox) {
// computedStyle.font is empty in Firefox...
context.font = `${cs.fontStyle} ${cs.fontVariant} ${cs.fontWeight} ${cs.fontStretch} ${cs.fontSize} / ${cs.lineHeight} ${cs.fontFamily}`;
let metrics = context.measureText(e.data);
this._textArea.setWidth(metrics.width + 2); // +2 for Japanese...
this.textArea.setWidth(metrics.width + 2); // +2 for Japanese...
} else {
context.font = cs.font;
let metrics = context.measureText(e.data);
this._textArea.setWidth(metrics.width);
this.textArea.setWidth(metrics.width);
}
}
}));
this._register(this._textAreaInput.onCompositionEnd(() => {
this._textArea.unsetHeight();
this._textArea.unsetWidth();
this._textArea.setLeft(0);
this._textArea.setTop(0);
this.textArea.unsetHeight();
this.textArea.unsetWidth();
this.textArea.setLeft(0);
this.textArea.setTop(0);
this._viewHelper.viewDomNode.removeClassName('ime-input');
this._visiblePosition = null;
......@@ -266,7 +304,7 @@ export class KeyboardHandler extends ViewEventHandler {
public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {
// Give textarea same font size & line height as editor, for the IME case (when the textarea is visible)
if (e.fontInfo) {
Configuration.applyFontInfo(this._textArea, this._context.configuration.editor.fontInfo);
Configuration.applyFontInfo(this.textArea, this._context.configuration.editor.fontInfo);
}
if (e.viewInfo.experimentalScreenReader) {
this._textAreaInput.writeScreenReaderContent('strategy changed');
......@@ -276,7 +314,7 @@ export class KeyboardHandler extends ViewEventHandler {
this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth;
}
if (e.viewInfo.ariaLabel) {
this._textArea.setAttribute('aria-label', this._context.configuration.editor.viewInfo.ariaLabel);
this.textArea.setAttribute('aria-label', this._context.configuration.editor.viewInfo.ariaLabel);
}
return false;
}
......@@ -290,8 +328,8 @@ export class KeyboardHandler extends ViewEventHandler {
this._scrollLeft = e.scrollLeft;
this._scrollTop = e.scrollTop;
if (this._visiblePosition) {
this._textArea.setTop(this._visiblePosition.top - this._scrollTop);
this._textArea.setLeft(this._contentLeft + this._visiblePosition.left - this._scrollLeft);
this.textArea.setTop(this._visiblePosition.top - this._scrollTop);
this.textArea.setLeft(this._contentLeft + this._visiblePosition.left - this._scrollLeft);
}
return false;
}
......@@ -306,15 +344,15 @@ export class KeyboardHandler extends ViewEventHandler {
public setAriaActiveDescendant(id: string): void {
if (id) {
this._textArea.setAttribute('role', 'combobox');
if (this._textArea.getAttribute('aria-activedescendant') !== id) {
this._textArea.setAttribute('aria-haspopup', 'true');
this._textArea.setAttribute('aria-activedescendant', id);
this.textArea.setAttribute('role', 'combobox');
if (this.textArea.getAttribute('aria-activedescendant') !== id) {
this.textArea.setAttribute('aria-haspopup', 'true');
this.textArea.setAttribute('aria-activedescendant', id);
}
} else {
this._textArea.setAttribute('role', 'textbox');
this._textArea.removeAttribute('aria-activedescendant');
this._textArea.removeAttribute('aria-haspopup');
this.textArea.setAttribute('role', 'textbox');
this.textArea.removeAttribute('aria-activedescendant');
this.textArea.removeAttribute('aria-haspopup');
}
}
......
......@@ -14,7 +14,7 @@ import { Range } from 'vs/editor/common/core/range';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';
import { Configuration } from 'vs/editor/browser/config/configuration';
import { KeyboardHandler, IKeyboardHandlerHelper } from 'vs/editor/browser/controller/keyboardHandler';
import { TextAreaHandler, ITextAreaHandlerHelper } from 'vs/editor/browser/controller/textAreaHandler';
import { PointerHandler } from 'vs/editor/browser/controller/pointerHandler';
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
import { ViewController, ExecCoreEditorCommandFunc } from 'vs/editor/browser/view/viewController';
......@@ -80,16 +80,14 @@ export class View extends ViewEventHandler {
private viewCursors: ViewCursors;
private viewParts: ViewPart[];
private keyboardHandler: KeyboardHandler;
private pointerHandler: PointerHandler;
private readonly _textAreaHandler: TextAreaHandler;
private readonly pointerHandler: PointerHandler;
private outgoingEvents: ViewOutgoingEvents;
// Dom nodes
private linesContent: FastDomNode<HTMLElement>;
public domNode: FastDomNode<HTMLElement>;
private textArea: FastDomNode<HTMLTextAreaElement>;
private textAreaCover: FastDomNode<HTMLElement>;
private overflowGuardContainer: FastDomNode<HTMLElement>;
// Actual mutable state
......@@ -125,13 +123,12 @@ export class View extends ViewEventHandler {
// The view context is passed on to most classes (basically to reduce param. counts in ctors)
this._context = new ViewContext(configuration, model, this.eventDispatcher);
this.createTextArea();
// Keyboard handler
this._textAreaHandler = new TextAreaHandler(this._context, viewController, this.createTextAreaHandlerHelper());
this.createViewParts();
this._setLayout();
// Keyboard handler
this.keyboardHandler = new KeyboardHandler(this._context, viewController, this.createKeyboardHandlerHelper());
// Pointer handler
this.pointerHandler = new PointerHandler(this._context, viewController, this.createPointerHandlerHelper());
......@@ -140,44 +137,6 @@ export class View extends ViewEventHandler {
}));
}
private createTextArea(): void {
// Text Area (The focus will always be in the textarea when the cursor is blinking)
this.textArea = createFastDomNode(document.createElement('textarea'));
PartFingerprints.write(this.textArea, PartFingerprint.TextArea);
this.textArea.setClassName('inputarea');
this.textArea.setAttribute('wrap', 'off');
this.textArea.setAttribute('autocorrect', 'off');
this.textArea.setAttribute('autocapitalize', 'off');
this.textArea.setAttribute('spellcheck', 'false');
this.textArea.setAttribute('aria-label', this._context.configuration.editor.viewInfo.ariaLabel);
this.textArea.setAttribute('role', 'textbox');
this.textArea.setAttribute('aria-multiline', 'true');
this.textArea.setAttribute('aria-haspopup', 'false');
this.textArea.setAttribute('aria-autocomplete', 'both');
this.textArea.setTop(0);
this.textArea.setLeft(0);
// On top of the text area, we position a dom node to cover it up
// (there have been reports of tiny blinking cursors)
// (in WebKit the textarea is 1px by 1px because it cannot handle input to a 0x0 textarea)
this.textAreaCover = createFastDomNode(document.createElement('div'));
if (this._context.configuration.editor.viewInfo.glyphMargin) {
this.textAreaCover.setClassName('monaco-editor-background ' + Margin.CLASS_NAME + ' ' + 'textAreaCover');
} else {
if (this._context.configuration.editor.viewInfo.renderLineNumbers) {
this.textAreaCover.setClassName('monaco-editor-background ' + LineNumbersOverlay.CLASS_NAME + ' ' + 'textAreaCover');
} else {
this.textAreaCover.setClassName('monaco-editor-background ' + 'textAreaCover');
}
}
this.textAreaCover.setPosition('absolute');
this.textAreaCover.setWidth(1);
this.textAreaCover.setHeight(1);
this.textAreaCover.setTop(0);
this.textAreaCover.setLeft(0);
}
private createViewParts(): void {
// These two dom nodes must be constructed up front, since references are needed in the layout provider (scrolling & co.)
this.linesContent = createFastDomNode(document.createElement('div'));
......@@ -268,8 +227,8 @@ export class View extends ViewEventHandler {
this.overflowGuardContainer.appendChild(this._scrollbar.getDomNode());
this.overflowGuardContainer.appendChild(scrollDecoration.getDomNode());
this.overflowGuardContainer.appendChild(this.overlayWidgets.getDomNode());
this.overflowGuardContainer.appendChild(this.textArea);
this.overflowGuardContainer.appendChild(this.textAreaCover);
this.overflowGuardContainer.appendChild(this._textAreaHandler.textArea);
this.overflowGuardContainer.appendChild(this._textAreaHandler.textAreaCover);
this.overflowGuardContainer.appendChild(minimap.getDomNode());
this.domNode.appendChild(this.overflowGuardContainer);
this.domNode.appendChild(this.contentWidgets.overflowingContentWidgetsDomNode);
......@@ -341,10 +300,9 @@ export class View extends ViewEventHandler {
};
}
private createKeyboardHandlerHelper(): IKeyboardHandlerHelper {
private createTextAreaHandlerHelper(): ITextAreaHandlerHelper {
return {
viewDomNode: this.domNode,
textArea: this.textArea,
visibleRangeForPositionRelativeToEditor: (lineNumber: number, column: number) => {
this._flushAccumulatedAndRenderNow();
let visibleRanges = this.viewLines.visibleRangesForRange2(new Range(lineNumber, column, lineNumber, column));
......@@ -435,7 +393,7 @@ export class View extends ViewEventHandler {
this.eventDispatcher.removeEventHandler(this);
this.outgoingEvents.dispose();
this.keyboardHandler.dispose();
this._textAreaHandler.dispose();
this.pointerHandler.dispose();
this.viewLines.dispose();
......@@ -492,7 +450,7 @@ export class View extends ViewEventHandler {
if (!this.viewLines.shouldRender() && viewPartsToRender.length === 0) {
// Nothing to render
this.keyboardHandler.writeToTextArea();
this._textAreaHandler.writeToTextArea();
return;
}
......@@ -503,14 +461,14 @@ export class View extends ViewEventHandler {
if (this.viewLines.shouldRender()) {
this.viewLines.renderText(viewportData, () => {
this.keyboardHandler.writeToTextArea();
this._textAreaHandler.writeToTextArea();
});
this.viewLines.onDidRender();
// Rendering of viewLines might cause scroll events to occur, so collect view parts to render again
viewPartsToRender = this._getViewPartsToRender();
} else {
this.keyboardHandler.writeToTextArea();
this._textAreaHandler.writeToTextArea();
}
let renderingContext = new RenderingContext(this.layoutProvider, viewportData, this.viewLines);
......@@ -667,7 +625,7 @@ export class View extends ViewEventHandler {
}
public setAriaActiveDescendant(id: string): void {
this.keyboardHandler.setAriaActiveDescendant(id);
this._textAreaHandler.setAriaActiveDescendant(id);
}
public saveState(): editorCommon.IViewState {
......@@ -679,11 +637,11 @@ export class View extends ViewEventHandler {
}
public focus(): void {
this.keyboardHandler.focusTextArea();
this._textAreaHandler.focusTextArea();
}
public isFocused(): boolean {
return this.keyboardHandler.isFocused();
return this._textAreaHandler.isFocused();
}
public addContentWidget(widgetData: IContentWidgetData): void {
......
......@@ -10,7 +10,7 @@ import { Range, IRange } from 'vs/editor/common/core/range';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { createFastDomNode } from 'vs/base/browser/fastDomNode';
import * as browser from 'vs/base/browser/browser';
import { TextAreaStrategy } from "vs/editor/browser/controller/keyboardHandler";
import { TextAreaStrategy } from "vs/editor/browser/controller/textAreaHandler";
// To run this test, open imeTester.html
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册