diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index fe52738840e..43ded2f2b07 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -397,6 +397,10 @@ { "name": "vs/workbench/services/gettingStarted", "project": "vscode-workbench" + }, + { + "name": "vs/workbench/services/host", + "project": "vscode-workbench" } ] } diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 58ebdb5b2c0..022fe7c0c19 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -1193,18 +1193,21 @@ export function computeScreenAwareSize(cssPx: number): number { * to change the location of the current page. * See https://mathiasbynens.github.io/rel-noopener/ */ -export function windowOpenNoOpener(url: string): void { +export function windowOpenNoOpener(url: string): boolean { if (browser.isElectron || browser.isEdgeLegacyWebView) { // In VSCode, window.open() always returns null... // The same is true for a WebView (see https://github.com/microsoft/monaco-editor/issues/628) // Also call directly window.open in sandboxed Electron (see https://github.com/microsoft/monaco-editor/issues/2220) window.open(url); + return true; } else { let newTab = window.open(); if (newTab) { (newTab as any).opener = null; newTab.location.href = url; + return true; } + return false; } } diff --git a/src/vs/workbench/browser/window.ts b/src/vs/workbench/browser/window.ts index 56782daaea3..d52927fd571 100644 --- a/src/vs/workbench/browser/window.ts +++ b/src/vs/workbench/browser/window.ts @@ -138,7 +138,13 @@ export class BrowserWindow extends Disposable { this.openerService.setDefaultExternalOpener({ openExternal: async (href: string) => { if (matchesScheme(href, Schemas.http) || matchesScheme(href, Schemas.https)) { - windowOpenNoOpener(href); + const opened = windowOpenNoOpener(href); + if (!opened) { + const showResult = await this.dialogService.show(Severity.Warning, localize('unableToOpenExternal', "The browser prevented opening of a new tab or window. You must give permission to continue."), [localize('continue', "Continue"), localize('cancel', "Cancel")], { cancelId: 1 }); + if (showResult.choice === 0) { + windowOpenNoOpener(href); + } + } } else { this.lifecycleService.withExpectedUnload(() => window.location.href = href); } diff --git a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts index 08fc6c9a192..f9c3477a8a5 100644 --- a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts @@ -570,7 +570,8 @@ export class RawDebugSession implements IDisposable { try { let result = await this.launchVsCode(request.arguments); if (!result.success) { - const showResult = await this.dialogSerivce.show(Severity.Warning, nls.localize('canNotStart', "The debugger needs to open a new tab or window for the debuggee but the browser prevented this. You must give permission to continue."), [nls.localize('continue', "Continue"), nls.localize('cancel', "Cancel")]); + const showResult = await this.dialogSerivce.show(Severity.Warning, nls.localize('canNotStart', "The debugger needs to open a new tab or window for the debuggee but the browser prevented this. You must give permission to continue."), + [nls.localize('continue', "Continue"), nls.localize('cancel', "Cancel")], { cancelId: 1 }); if (showResult.choice === 0) { result = await this.launchVsCode(request.arguments); } else { diff --git a/src/vs/workbench/services/host/browser/browserHostService.ts b/src/vs/workbench/services/host/browser/browserHostService.ts index b00b6f0f813..8a783b1d760 100644 --- a/src/vs/workbench/services/host/browser/browserHostService.ts +++ b/src/vs/workbench/services/host/browser/browserHostService.ts @@ -27,6 +27,9 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { BeforeShutdownEvent, ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; import { getWorkspaceIdentifier } from 'vs/workbench/services/workspaces/browser/workspaces'; +import { localize } from 'vs/nls'; +import Severity from 'vs/base/common/severity'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; /** * A workspace to open in the workbench can either be: @@ -102,7 +105,8 @@ export class BrowserHostService extends Disposable implements IHostService { @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IInstantiationService private readonly instantiationService: IInstantiationService, @ILifecycleService private readonly lifecycleService: ILifecycleService, - @ILogService private readonly logService: ILogService + @ILogService private readonly logService: ILogService, + @IDialogService private readonly dialogService: IDialogService ) { super(); @@ -382,7 +386,13 @@ export class BrowserHostService extends Disposable implements IHostService { this.shutdownReason = HostShutdownReason.Api; } - await this.workspaceProvider.open(workspace, options); + const opened = await this.workspaceProvider.open(workspace, options); + if (!opened) { + const showResult = await this.dialogService.show(Severity.Warning, localize('unableToOpenExternal', "The browser prevented opening of a new tab or window. You must give permission to continue."), [localize('continue', "Continue"), localize('cancel', "Cancel")], { cancelId: 1 }); + if (showResult.choice === 0) { + await this.workspaceProvider.open(workspace, options); + } + } } async toggleFullScreen(): Promise {