Skip to content

Commit

Permalink
[Edit Context]: Introduce text area into which code is pasted (#232806)
Browse files Browse the repository at this point in the history
introducing text area into the edit context to handle correctly the paste event
  • Loading branch information
aiday-mar authored Nov 4, 2024
1 parent 6f2d478 commit e22abe4
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ export abstract class AbstractEditContext extends ViewPart {
abstract setAriaOptions(options: IEditorAriaOptions): void;
abstract getLastRenderData(): Position | null;
abstract writeScreenReaderContent(reason: string): void;
abstract getTextAreaDomNode(): HTMLTextAreaElement;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,21 @@
text-wrap: nowrap;
}

.monaco-editor .native-edit-context-textarea {
min-width: 0;
min-height: 0;
margin: 0;
padding: 0;
position: absolute;
outline: none !important;
resize: none;
border: none;
overflow: hidden;
color: transparent;
background-color: transparent;
z-index: -10;
}

.monaco-editor .edit-context-composition-none {
background-color: transparent;
border-bottom: none;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ enum CompositionClassName {

export class NativeEditContext extends AbstractEditContext {

// Text area used to handle paste events
public readonly textArea: FastDomNode<HTMLTextAreaElement>;
public readonly domNode: FastDomNode<HTMLDivElement>;
private readonly _editContext: EditContext;
private readonly _screenReaderSupport: ScreenReaderSupport;
Expand Down Expand Up @@ -69,9 +71,12 @@ export class NativeEditContext extends AbstractEditContext {

this.domNode = new FastDomNode(document.createElement('div'));
this.domNode.setClassName(`native-edit-context`);
this.textArea = new FastDomNode(document.createElement('textarea'));
this.textArea.setClassName(`native-edit-context-textarea`);
this._updateDomAttributes();

overflowGuardContainer.appendChild(this.domNode);
overflowGuardContainer.appendChild(this.textArea);
this._parent = overflowGuardContainer.domNode;

this._selectionChangeListener = this._register(new MutableDisposable());
Expand Down Expand Up @@ -140,6 +145,10 @@ export class NativeEditContext extends AbstractEditContext {
super.dispose();
}

public getTextAreaDomNode(): HTMLTextAreaElement {
return this.textArea.domNode;
}

public setAriaOptions(): void {
this._screenReaderSupport.setAriaOptions();
}
Expand Down Expand Up @@ -176,7 +185,9 @@ export class NativeEditContext extends AbstractEditContext {
this._screenReaderSupport.writeScreenReaderContent();
}

public isFocused(): boolean { return this._focusTracker.isFocused; }
public isFocused(): boolean {
return this._focusTracker.isFocused || (getActiveWindow().document.activeElement === this.textArea.domNode);
}

public focus(): void {
this._focusTracker.focus();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,10 @@ export class TextAreaEditContext extends AbstractEditContext {
this._textAreaInput.writeNativeTextAreaContent(reason);
}

public getTextAreaDomNode(): HTMLTextAreaElement {
return this.textArea.domNode;
}

public override dispose(): void {
super.dispose();
this.textArea.domNode.remove();
Expand Down
5 changes: 5 additions & 0 deletions src/vs/editor/browser/editorBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1077,6 +1077,11 @@ export interface ICodeEditor extends editorCommon.IEditor {
*/
getContainerDomNode(): HTMLElement;

/**
* Return this editor's text area dom node
*/
getTextAreaDomNode(): HTMLTextAreaElement | undefined;

/**
* Returns the editor's dom node
*/
Expand Down
4 changes: 4 additions & 0 deletions src/vs/editor/browser/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,10 @@ export class View extends ViewEventHandler {
this._scheduleRender();
}

public getTextAreaDomNode(): HTMLTextAreaElement {
return this._editContext.getTextAreaDomNode();
}

public layoutContentWidget(widgetData: IContentWidgetData): void {
this._contentWidgets.setWidgetPosition(
widgetData.widget,
Expand Down
4 changes: 4 additions & 0 deletions src/vs/editor/browser/widget/codeEditor/codeEditorWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1399,6 +1399,10 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
return this._domElement;
}

public getTextAreaDomNode(): HTMLTextAreaElement | undefined {
return this._modelData?.view.getTextAreaDomNode();
}

public getDomNode(): HTMLElement | null {
if (!this._modelData || !this._modelData.hasRealView) {
return null;
Expand Down
18 changes: 14 additions & 4 deletions src/vs/editor/contrib/clipboard/browser/clipboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import * as browser from '../../../../base/browser/browser.js';
import { getActiveDocument } from '../../../../base/browser/dom.js';
import { getActiveDocument, getActiveWindow, isHTMLElement } from '../../../../base/browser/dom.js';
import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js';
import * as platform from '../../../../base/common/platform.js';
import * as nls from '../../../../nls.js';
Expand Down Expand Up @@ -234,11 +234,21 @@ if (PasteAction) {
const focusedEditor = codeEditorService.getFocusedCodeEditor();
if (focusedEditor && focusedEditor.hasTextFocus()) {
// execCommand(paste) does not work with edit context
const canDoDocumentExecCommand = !focusedEditor.getOption(EditorOption.experimentalEditContextEnabled);
const result = canDoDocumentExecCommand && focusedEditor.getContainerDomNode().ownerDocument.execCommand('paste');
let result: boolean;
const experimentalEditContextEnabled = focusedEditor.getOption(EditorOption.experimentalEditContextEnabled);
if (experimentalEditContextEnabled) {
const currentFocusedElement = getActiveWindow().document.activeElement;
focusedEditor.getTextAreaDomNode()?.focus();
result = focusedEditor.getContainerDomNode().ownerDocument.execCommand('paste');
if (isHTMLElement(currentFocusedElement)) {
currentFocusedElement.focus();
}
} else {
result = focusedEditor.getContainerDomNode().ownerDocument.execCommand('paste');
}
if (result) {
return CopyPasteController.get(focusedEditor)?.finishedPaste() ?? Promise.resolve();
} else if (platform.isWeb || !canDoDocumentExecCommand) {
} else if (platform.isWeb) {
// Use the clipboard service if document.execCommand('paste') was not successful
return (async () => {
const clipboardText = await clipboardService.readText();
Expand Down
4 changes: 4 additions & 0 deletions src/vs/monaco.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6062,6 +6062,10 @@ declare namespace monaco.editor {
* Returns the editor's container dom node
*/
getContainerDomNode(): HTMLElement;
/**
* Return this editor's text area dom node
*/
getTextAreaDomNode(): HTMLTextAreaElement | undefined;
/**
* Returns the editor's dom node
*/
Expand Down

0 comments on commit e22abe4

Please sign in to comment.