Ben/probable-bobcat (#239286)

* Should not change values in environmentService
(fix #171707)

* dialogs - remove `closeOnLinkClick` option

Closing a dialog from anything but a button click is rather unexpected and there is usage of this anymore.

* Code duplication for text input actions (fix #239187)
This commit is contained in:
Benjamin Pasero
2025-01-31 09:18:46 +01:00
committed by GitHub
parent f9c927cf7a
commit f2b5597595
8 changed files with 57 additions and 127 deletions

View File

@@ -37,7 +37,6 @@ export interface IDialogOptions {
readonly icon?: ThemeIcon;
readonly buttonDetails?: string[];
readonly disableCloseAction?: boolean;
readonly closeOnLinkClick?: boolean;
readonly disableDefaultAction?: boolean;
readonly buttonStyles: IButtonStyles;
readonly checkboxStyles: ICheckboxStyles;
@@ -212,20 +211,6 @@ export class Dialog extends Disposable {
return;
};
if (this.options.closeOnLinkClick) {
for (const el of this.messageContainer.getElementsByTagName('a')) {
this._register(addDisposableListener(el, EventType.CLICK, () => {
setTimeout(close); // HACK to ensure the link action is triggered before the dialog is closed
}));
this._register(addDisposableListener(el, EventType.KEY_DOWN, (e: KeyboardEvent) => {
const evt = new StandardKeyboardEvent(e);
if (evt.equals(KeyCode.Enter)) {
setTimeout(close); // HACK to ensure the link action is triggered before the dialog is closed
}
}));
}
}
const buttonBar = this.buttonBar = this._register(new ButtonBar(this.buttonsContainer));
const buttonMap = this.rearrangeButtons(this.buttons, this.options.cancelId);

View File

@@ -278,7 +278,6 @@ export interface ICustomDialogOptions {
readonly classes?: string[];
readonly icon?: ThemeIcon;
readonly disableCloseAction?: boolean;
readonly closeOnLinkClick?: boolean;
}
export interface ICustomDialogMarkdown {

View File

@@ -252,7 +252,7 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron
return undefined;
}
editSessionId: string | undefined = this.args['editSessionId'];
get editSessionId(): string | undefined { return this.args['editSessionId']; }
get continueOn(): string | undefined {
return this.args['continueOn'];

View File

@@ -16,11 +16,53 @@ import { StandardMouseEvent } from '../../../base/browser/mouseEvent.js';
import { Event as BaseEvent } from '../../../base/common/event.js';
import { Lazy } from '../../../base/common/lazy.js';
export function createTextInputActions(clipboardService: IClipboardService): IAction[] {
return [
// Undo/Redo
new Action('undo', localize('undo', "Undo"), undefined, true, async () => getActiveDocument().execCommand('undo')),
new Action('redo', localize('redo', "Redo"), undefined, true, async () => getActiveDocument().execCommand('redo')),
new Separator(),
// Cut / Copy / Paste
new Action('editor.action.clipboardCutAction', localize('cut', "Cut"), undefined, true, async () => getActiveDocument().execCommand('cut')),
new Action('editor.action.clipboardCopyAction', localize('copy', "Copy"), undefined, true, async () => getActiveDocument().execCommand('copy')),
new Action('editor.action.clipboardPasteAction', localize('paste', "Paste"), undefined, true, async element => {
// Native: paste is supported
if (isNative) {
getActiveDocument().execCommand('paste');
}
// Web: paste is not supported due to security reasons
else {
const clipboardText = await clipboardService.readText();
if (
isHTMLTextAreaElement(element) ||
isHTMLInputElement(element)
) {
const selectionStart = element.selectionStart || 0;
const selectionEnd = element.selectionEnd || 0;
element.value = `${element.value.substring(0, selectionStart)}${clipboardText}${element.value.substring(selectionEnd, element.value.length)}`;
element.selectionStart = selectionStart + clipboardText.length;
element.selectionEnd = element.selectionStart;
element.dispatchEvent(new Event('input', { bubbles: true, cancelable: true }));
}
}
}),
new Separator(),
// Select All
new Action('editor.action.selectAll', localize('selectAll', "Select All"), undefined, true, async () => getActiveDocument().execCommand('selectAll'))
];
}
export class TextInputActionsProvider extends Disposable implements IWorkbenchContribution {
static readonly ID = 'workbench.contrib.textInputActionsProvider';
private readonly textInputActions = new Lazy<IAction[]>(() => this.createActions());
private readonly textInputActions = new Lazy<IAction[]>(() => createTextInputActions(this.clipboardService));
constructor(
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
@@ -32,48 +74,6 @@ export class TextInputActionsProvider extends Disposable implements IWorkbenchCo
this.registerListeners();
}
private createActions(): IAction[] {
return [
// Undo/Redo
new Action('undo', localize('undo', "Undo"), undefined, true, async () => getActiveDocument().execCommand('undo')),
new Action('redo', localize('redo', "Redo"), undefined, true, async () => getActiveDocument().execCommand('redo')),
new Separator(),
// Cut / Copy / Paste
new Action('editor.action.clipboardCutAction', localize('cut', "Cut"), undefined, true, async () => getActiveDocument().execCommand('cut')),
new Action('editor.action.clipboardCopyAction', localize('copy', "Copy"), undefined, true, async () => getActiveDocument().execCommand('copy')),
new Action('editor.action.clipboardPasteAction', localize('paste', "Paste"), undefined, true, async element => {
// Native: paste is supported
if (isNative) {
getActiveDocument().execCommand('paste');
}
// Web: paste is not supported due to security reasons
else {
const clipboardText = await this.clipboardService.readText();
if (
isHTMLTextAreaElement(element) ||
isHTMLInputElement(element)
) {
const selectionStart = element.selectionStart || 0;
const selectionEnd = element.selectionEnd || 0;
element.value = `${element.value.substring(0, selectionStart)}${clipboardText}${element.value.substring(selectionEnd, element.value.length)}`;
element.selectionStart = selectionStart + clipboardText.length;
element.selectionEnd = element.selectionStart;
element.dispatchEvent(new Event('input', { bubbles: true, cancelable: true }));
}
}
}),
new Separator(),
// Select All
new Action('editor.action.selectAll', localize('selectAll', "Select All"), undefined, true, async () => getActiveDocument().execCommand('selectAll'))
];
}
private registerListeners(): void {
// Context menu support in input/textarea

View File

@@ -137,7 +137,6 @@ export class BrowserDialogHandler extends AbstractDialogHandler {
renderBody,
icon: customOptions?.icon,
disableCloseAction: customOptions?.disableCloseAction,
closeOnLinkClick: customOptions?.closeOnLinkClick,
buttonDetails: customOptions?.buttonDetails,
checkboxLabel: checkbox?.label,
checkboxChecked: checkbox?.checked,

View File

@@ -15,11 +15,12 @@ import { IKeybindingService } from '../../../../../platform/keybinding/common/ke
import { Event } from '../../../../../base/common/event.js';
import type { ISearchOptions } from '@xterm/addon-search';
import { IClipboardService } from '../../../../../platform/clipboard/common/clipboardService.js';
import { openContextMenu } from './textInputContextMenu.js';
import { IDisposable } from '../../../../../base/common/lifecycle.js';
import { IHoverService } from '../../../../../platform/hover/browser/hover.js';
import { TerminalFindCommandId } from '../common/terminal.find.js';
import { TerminalClipboardContribution } from '../../clipboard/browser/terminal.clipboard.contribution.js';
import { StandardMouseEvent } from '../../../../../base/browser/mouseEvent.js';
import { createTextInputActions } from '../../../../browser/actions/textInputActions.js';
const TERMINAL_FIND_WIDGET_INITIAL_WIDTH = 419;
@@ -74,7 +75,15 @@ export class TerminalFindWidget extends SimpleFindWidget {
}
const findInputDomNode = this.getFindInputDomNode();
this._register(dom.addDisposableListener(findInputDomNode, 'contextmenu', (event) => {
openContextMenu(dom.getWindow(findInputDomNode), event, clipboardService, contextMenuService);
const targetWindow = dom.getWindow(findInputDomNode);
const standardEvent = new StandardMouseEvent(targetWindow, event);
const actions = createTextInputActions(clipboardService);
contextMenuService.showContextMenu({
getAnchor: () => standardEvent,
getActions: () => actions,
getActionsContext: () => event.target,
});
event.stopPropagation();
}));
this._register(themeService.onDidColorThemeChange(() => {

View File

@@ -1,63 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { getActiveWindow, isHTMLInputElement, isHTMLTextAreaElement } from '../../../../../base/browser/dom.js';
import { StandardMouseEvent } from '../../../../../base/browser/mouseEvent.js';
import { Action, IAction, Separator } from '../../../../../base/common/actions.js';
import { isNative } from '../../../../../base/common/platform.js';
import { localize } from '../../../../../nls.js';
import { IClipboardService } from '../../../../../platform/clipboard/common/clipboardService.js';
import { IContextMenuService } from '../../../../../platform/contextview/browser/contextView.js';
export function openContextMenu(targetWindow: Window, event: MouseEvent, clipboardService: IClipboardService, contextMenuService: IContextMenuService): void {
const standardEvent = new StandardMouseEvent(targetWindow, event);
// Actions from workbench/browser/actions/textInputActions
const actions: IAction[] = [];
actions.push(
// Undo/Redo
new Action('undo', localize('undo', "Undo"), undefined, true, async () => getActiveWindow().document.execCommand('undo')),
new Action('redo', localize('redo', "Redo"), undefined, true, async () => getActiveWindow().document.execCommand('redo')),
new Separator(),
// Cut / Copy / Paste
new Action('editor.action.clipboardCutAction', localize('cut', "Cut"), undefined, true, async () => getActiveWindow().document.execCommand('cut')),
new Action('editor.action.clipboardCopyAction', localize('copy', "Copy"), undefined, true, async () => getActiveWindow().document.execCommand('copy')),
new Action('editor.action.clipboardPasteAction', localize('paste', "Paste"), undefined, true, async element => {
// Native: paste is supported
if (isNative) {
getActiveWindow().document.execCommand('paste');
}
// Web: paste is not supported due to security reasons
else {
const clipboardText = await clipboardService.readText();
if (
isHTMLTextAreaElement(element) ||
isHTMLInputElement(element)
) {
const selectionStart = element.selectionStart || 0;
const selectionEnd = element.selectionEnd || 0;
element.value = `${element.value.substring(0, selectionStart)}${clipboardText}${element.value.substring(selectionEnd, element.value.length)}`;
element.selectionStart = selectionStart + clipboardText.length;
element.selectionEnd = element.selectionStart;
}
}
}),
new Separator(),
// Select All
new Action('editor.action.selectAll', localize('selectAll', "Select All"), undefined, true, async () => getActiveWindow().document.execCommand('selectAll'))
);
contextMenuService.showContextMenu({
getAnchor: () => standardEvent,
getActions: () => actions,
getActionsContext: () => event.target,
});
}

View File

@@ -259,7 +259,8 @@ export class BrowserWorkbenchEnvironmentService implements IBrowserWorkbenchEnvi
@memoize
get profile(): string | undefined { return this.payload?.get('profile'); }
editSessionId: string | undefined = this.options.editSessionId;
@memoize
get editSessionId(): string | undefined { return this.options.editSessionId; }
private payload: Map<string, string> | undefined;