mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from vscode 2b0b9136329c181a9e381463a1f7dc3a2d105a34 (#4880)
This commit is contained in:
@@ -3,56 +3,104 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
// @ts-check
|
||||
(function () {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
// @ts-ignore
|
||||
const ipcRenderer = require('electron').ipcRenderer;
|
||||
/**
|
||||
* Use polling to track focus of main webview and iframes within the webview
|
||||
*
|
||||
* @param {Object} handlers
|
||||
* @param {() => void} handlers.onFocus
|
||||
* @param {() => void} handlers.onBlur
|
||||
*/
|
||||
const trackFocus = ({ onFocus, onBlur }) => {
|
||||
const interval = 50;
|
||||
let isFocused = document.hasFocus();
|
||||
setInterval(() => {
|
||||
const isCurrentlyFocused = document.hasFocus();
|
||||
if (isCurrentlyFocused === isFocused) {
|
||||
return;
|
||||
}
|
||||
isFocused = isCurrentlyFocused;
|
||||
if (isCurrentlyFocused) {
|
||||
onFocus();
|
||||
} else {
|
||||
onBlur();
|
||||
}
|
||||
}, interval);
|
||||
};
|
||||
|
||||
const registerVscodeResourceScheme = (function () {
|
||||
let hasRegistered = false;
|
||||
return () => {
|
||||
if (hasRegistered) {
|
||||
return;
|
||||
}
|
||||
const getActiveFrame = () => {
|
||||
return /** @type {HTMLIFrameElement} */ (document.getElementById('active-frame'));
|
||||
};
|
||||
|
||||
hasRegistered = true;
|
||||
const getPendingFrame = () => {
|
||||
return /** @type {HTMLIFrameElement} */ (document.getElementById('pending-frame'));
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
require('electron').webFrame.registerURLSchemeAsPrivileged('vscode-resource', {
|
||||
secure: true,
|
||||
bypassCSP: false,
|
||||
allowServiceWorkers: false,
|
||||
supportFetchAPI: true,
|
||||
corsEnabled: true
|
||||
});
|
||||
};
|
||||
}());
|
||||
const defaultCssRules = `
|
||||
body {
|
||||
background-color: var(--vscode-editor-background);
|
||||
color: var(--vscode-editor-foreground);
|
||||
font-family: var(--vscode-editor-font-family);
|
||||
font-weight: var(--vscode-editor-font-weight);
|
||||
font-size: var(--vscode-editor-font-size);
|
||||
margin: 0;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use polling to track focus of main webview and iframes within the webview
|
||||
*
|
||||
* @param {Object} handlers
|
||||
* @param {() => void} handlers.onFocus
|
||||
* @param {() => void} handlers.onBlur
|
||||
*/
|
||||
const trackFocus = ({ onFocus, onBlur }) => {
|
||||
const interval = 50;
|
||||
let isFocused = document.hasFocus();
|
||||
setInterval(() => {
|
||||
const isCurrentlyFocused = document.hasFocus();
|
||||
if (isCurrentlyFocused === isFocused) {
|
||||
return;
|
||||
}
|
||||
isFocused = isCurrentlyFocused;
|
||||
if (isCurrentlyFocused) {
|
||||
onFocus();
|
||||
} else {
|
||||
onBlur();
|
||||
}
|
||||
}, interval);
|
||||
};
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--vscode-textLink-foreground);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--vscode-textLink-activeForeground);
|
||||
}
|
||||
|
||||
a:focus,
|
||||
input:focus,
|
||||
select:focus,
|
||||
textarea:focus {
|
||||
outline: 1px solid -webkit-focus-ring-color;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
code {
|
||||
color: var(--vscode-textPreformat-foreground);
|
||||
}
|
||||
|
||||
blockquote {
|
||||
background: var(--vscode-textBlockQuote-background);
|
||||
border-color: var(--vscode-textBlockQuote-border);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: var(--vscode-scrollbarSlider-background);
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background-color: var(--vscode-scrollbarSlider-hoverBackground);
|
||||
}
|
||||
::-webkit-scrollbar-thumb:active {
|
||||
background-color: var(--vscode-scrollbarSlider-activeBackground);
|
||||
}`;
|
||||
|
||||
/**
|
||||
* @typedef {{ postMessage: (channel: string, data?: any) => void, onMessage: (channel: string, handler: any) => void }} HostCommunications
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {HostCommunications} host
|
||||
*/
|
||||
module.exports = function createWebviewManager(host) {
|
||||
// state
|
||||
let firstLoad = true;
|
||||
let loadTimeout;
|
||||
@@ -82,14 +130,6 @@
|
||||
}
|
||||
};
|
||||
|
||||
const getActiveFrame = () => {
|
||||
return /** @type {HTMLIFrameElement} */ (document.getElementById('active-frame'));
|
||||
};
|
||||
|
||||
const getPendingFrame = () => {
|
||||
return /** @type {HTMLIFrameElement} */ (document.getElementById('pending-frame'));
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
@@ -111,7 +151,7 @@
|
||||
scrollTarget.scrollIntoView();
|
||||
}
|
||||
} else {
|
||||
ipcRenderer.sendToHost('did-click-link', node.href);
|
||||
host.postMessage('did-click-link', node.href);
|
||||
}
|
||||
event.preventDefault();
|
||||
break;
|
||||
@@ -124,7 +164,7 @@
|
||||
* @param {KeyboardEvent} e
|
||||
*/
|
||||
const handleInnerKeydown = (e) => {
|
||||
ipcRenderer.sendToHost('did-keydown', {
|
||||
host.postMessage('did-keydown', {
|
||||
key: e.key,
|
||||
keyCode: e.keyCode,
|
||||
code: e.code,
|
||||
@@ -137,7 +177,7 @@
|
||||
};
|
||||
|
||||
const onMessage = (message) => {
|
||||
ipcRenderer.sendToHost(message.data.command, message.data.data);
|
||||
host.postMessage(message.data.command, message.data.data);
|
||||
};
|
||||
|
||||
let isHandlingScroll = false;
|
||||
@@ -154,7 +194,7 @@
|
||||
isHandlingScroll = true;
|
||||
window.requestAnimationFrame(() => {
|
||||
try {
|
||||
ipcRenderer.sendToHost('did-scroll', progress);
|
||||
host.postMessage('did-scroll', progress);
|
||||
} catch (e) {
|
||||
// noop
|
||||
}
|
||||
@@ -163,11 +203,7 @@
|
||||
};
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
ipcRenderer.on('baseUrl', (_event, value) => {
|
||||
initData.baseUrl = value;
|
||||
});
|
||||
|
||||
ipcRenderer.on('styles', (_event, variables, activeTheme) => {
|
||||
host.onMessage('styles', (_event, variables, activeTheme) => {
|
||||
initData.styles = variables;
|
||||
initData.activeTheme = activeTheme;
|
||||
|
||||
@@ -180,7 +216,7 @@
|
||||
});
|
||||
|
||||
// propagate focus
|
||||
ipcRenderer.on('focus', () => {
|
||||
host.onMessage('focus', () => {
|
||||
const target = getActiveFrame();
|
||||
if (target) {
|
||||
target.contentWindow.focus();
|
||||
@@ -188,11 +224,9 @@
|
||||
});
|
||||
|
||||
// update iframe-contents
|
||||
ipcRenderer.on('content', (_event, data) => {
|
||||
host.onMessage('content', (_event, data) => {
|
||||
const options = data.options;
|
||||
|
||||
registerVscodeResourceScheme();
|
||||
|
||||
const text = data.contents;
|
||||
const newDocument = new DOMParser().parseFromString(text, 'text/html');
|
||||
|
||||
@@ -202,13 +236,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
// set base-url if applicable
|
||||
if (initData.baseUrl && newDocument.head.getElementsByTagName('base').length === 0) {
|
||||
const baseElement = newDocument.createElement('base');
|
||||
baseElement.href = initData.baseUrl;
|
||||
newDocument.head.appendChild(baseElement);
|
||||
}
|
||||
|
||||
// apply default script
|
||||
if (options.allowScripts) {
|
||||
const defaultScript = newDocument.createElement('script');
|
||||
@@ -299,7 +326,7 @@
|
||||
newFrame.contentWindow.addEventListener('keydown', handleInnerKeydown);
|
||||
newFrame.contentWindow.onbeforeunload = () => {
|
||||
if (isInDevelopmentMode) { // Allow reloads while developing a webview
|
||||
ipcRenderer.sendToHost('do-reload');
|
||||
host.postMessage('do-reload');
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -361,11 +388,11 @@
|
||||
newFrame.contentDocument.write(newDocument.documentElement.innerHTML);
|
||||
newFrame.contentDocument.close();
|
||||
|
||||
ipcRenderer.sendToHost('did-set-content');
|
||||
host.postMessage('did-set-content', undefined);
|
||||
});
|
||||
|
||||
// Forward message to the embedded iframe
|
||||
ipcRenderer.on('message', (_event, data) => {
|
||||
host.onMessage('message', (_event, data) => {
|
||||
const pending = getPendingFrame();
|
||||
if (!pending) {
|
||||
const target = getActiveFrame();
|
||||
@@ -377,79 +404,23 @@
|
||||
pendingMessages.push(data);
|
||||
});
|
||||
|
||||
ipcRenderer.on('initial-scroll-position', (_event, progress) => {
|
||||
host.onMessage('initial-scroll-position', (_event, progress) => {
|
||||
initData.initialScrollProgress = progress;
|
||||
});
|
||||
|
||||
ipcRenderer.on('devtools-opened', () => {
|
||||
host.onMessage('devtools-opened', () => {
|
||||
isInDevelopmentMode = true;
|
||||
});
|
||||
|
||||
trackFocus({
|
||||
onFocus: () => { ipcRenderer.sendToHost('did-focus'); },
|
||||
onBlur: () => { ipcRenderer.sendToHost('did-blur'); }
|
||||
onFocus: () => host.postMessage('did-focus'),
|
||||
onBlur: () => host.postMessage('did-blur')
|
||||
});
|
||||
|
||||
// Forward messages from the embedded iframe
|
||||
window.onmessage = onMessage;
|
||||
|
||||
// signal ready
|
||||
ipcRenderer.sendToHost('webview-ready', process.pid);
|
||||
host.postMessage('webview-ready', process.pid);
|
||||
});
|
||||
|
||||
const defaultCssRules = `
|
||||
body {
|
||||
background-color: var(--vscode-editor-background);
|
||||
color: var(--vscode-editor-foreground);
|
||||
font-family: var(--vscode-editor-font-family);
|
||||
font-weight: var(--vscode-editor-font-weight);
|
||||
font-size: var(--vscode-editor-font-size);
|
||||
margin: 0;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--vscode-textLink-foreground);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--vscode-textLink-activeForeground);
|
||||
}
|
||||
|
||||
a:focus,
|
||||
input:focus,
|
||||
select:focus,
|
||||
textarea:focus {
|
||||
outline: 1px solid -webkit-focus-ring-color;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
code {
|
||||
color: var(--vscode-textPreformat-foreground);
|
||||
}
|
||||
|
||||
blockquote {
|
||||
background: var(--vscode-textBlockQuote-background);
|
||||
border-color: var(--vscode-textBlockQuote-border);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: var(--vscode-scrollbarSlider-background);
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background-color: var(--vscode-scrollbarSlider-hoverBackground);
|
||||
}
|
||||
::-webkit-scrollbar-thumb:active {
|
||||
background-color: var(--vscode-scrollbarSlider-activeBackground);
|
||||
}`;
|
||||
}());
|
||||
};
|
||||
138
src/vs/workbench/contrib/webview/browser/webview.contribution.ts
Normal file
138
src/vs/workbench/contrib/webview/browser/webview.contribution.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { localize } from 'vs/nls';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { EditorDescriptor, Extensions as EditorExtensions, IEditorRegistry } from 'vs/workbench/browser/editor';
|
||||
import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
|
||||
import { Extensions as EditorInputExtensions, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor';
|
||||
import { WebviewEditorInputFactory } from 'vs/workbench/contrib/webview/browser/webviewEditorInputFactory';
|
||||
import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { CopyWebviewEditorCommand, CutWebviewEditorCommand, HideWebViewEditorFindCommand, OpenWebviewDeveloperToolsAction, PasteWebviewEditorCommand, RedoWebviewEditorCommand, ReloadWebviewAction, SelectAllWebviewEditorCommand, ShowWebViewEditorFindWidgetCommand, UndoWebviewEditorCommand } from '../browser/webviewCommands';
|
||||
import { WebviewEditor } from '../browser/webviewEditor';
|
||||
import { WebviewEditorInput } from '../browser/webviewEditorInput';
|
||||
import { IWebviewEditorService, WebviewEditorService } from '../browser/webviewEditorService';
|
||||
|
||||
(Registry.as<IEditorRegistry>(EditorExtensions.Editors)).registerEditor(new EditorDescriptor(
|
||||
WebviewEditor,
|
||||
WebviewEditor.ID,
|
||||
localize('webview.editor.label', "webview editor")),
|
||||
[new SyncDescriptor(WebviewEditorInput)]);
|
||||
|
||||
Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(
|
||||
WebviewEditorInputFactory.ID,
|
||||
WebviewEditorInputFactory);
|
||||
|
||||
registerSingleton(IWebviewEditorService, WebviewEditorService, true);
|
||||
|
||||
|
||||
const webviewDeveloperCategory = localize('developer', "Developer");
|
||||
|
||||
const actionRegistry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
|
||||
export function registerWebViewCommands(editorId: string): void {
|
||||
const contextKeyExpr = ContextKeyExpr.and(ContextKeyExpr.equals('activeEditor', editorId), ContextKeyExpr.not('editorFocus') /* https://github.com/Microsoft/vscode/issues/58668 */);
|
||||
|
||||
const showNextFindWidgetCommand = new ShowWebViewEditorFindWidgetCommand({
|
||||
id: ShowWebViewEditorFindWidgetCommand.ID,
|
||||
precondition: contextKeyExpr,
|
||||
kbOpts: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_F,
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
});
|
||||
showNextFindWidgetCommand.register();
|
||||
|
||||
(new HideWebViewEditorFindCommand({
|
||||
id: HideWebViewEditorFindCommand.ID,
|
||||
precondition: ContextKeyExpr.and(
|
||||
contextKeyExpr,
|
||||
KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE),
|
||||
kbOpts: {
|
||||
primary: KeyCode.Escape,
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
})).register();
|
||||
|
||||
(new SelectAllWebviewEditorCommand({
|
||||
id: SelectAllWebviewEditorCommand.ID,
|
||||
precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)),
|
||||
kbOpts: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_A,
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
})).register();
|
||||
|
||||
// These commands are only needed on MacOS where we have to disable the menu bar commands
|
||||
if (isMacintosh) {
|
||||
(new CopyWebviewEditorCommand({
|
||||
id: CopyWebviewEditorCommand.ID,
|
||||
precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)),
|
||||
kbOpts: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_C,
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
})).register();
|
||||
|
||||
(new PasteWebviewEditorCommand({
|
||||
id: PasteWebviewEditorCommand.ID,
|
||||
precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)),
|
||||
kbOpts: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_V,
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
})).register();
|
||||
|
||||
|
||||
(new CutWebviewEditorCommand({
|
||||
id: CutWebviewEditorCommand.ID,
|
||||
precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)),
|
||||
kbOpts: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_X,
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
})).register();
|
||||
|
||||
(new UndoWebviewEditorCommand({
|
||||
id: UndoWebviewEditorCommand.ID,
|
||||
precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)),
|
||||
kbOpts: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_Z,
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
})).register();
|
||||
|
||||
(new RedoWebviewEditorCommand({
|
||||
id: RedoWebviewEditorCommand.ID,
|
||||
precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)),
|
||||
kbOpts: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_Y,
|
||||
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z],
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z },
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
})).register();
|
||||
}
|
||||
}
|
||||
|
||||
registerWebViewCommands(WebviewEditor.ID);
|
||||
|
||||
actionRegistry.registerWorkbenchAction(
|
||||
new SyncActionDescriptor(OpenWebviewDeveloperToolsAction, OpenWebviewDeveloperToolsAction.ID, OpenWebviewDeveloperToolsAction.LABEL),
|
||||
'Webview Tools',
|
||||
webviewDeveloperCategory);
|
||||
|
||||
actionRegistry.registerWorkbenchAction(
|
||||
new SyncActionDescriptor(ReloadWebviewAction, ReloadWebviewAction.ID, ReloadWebviewAction.LABEL),
|
||||
'Reload Webview',
|
||||
webviewDeveloperCategory);
|
||||
@@ -8,7 +8,7 @@ import { Command } from 'vs/editor/browser/editorExtensions';
|
||||
import * as nls from 'vs/nls';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { WebviewEditor } from 'vs/workbench/contrib/webview/electron-browser/webviewEditor';
|
||||
import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEditor';
|
||||
|
||||
export class ShowWebViewEditorFindWidgetCommand extends Command {
|
||||
public static readonly ID = 'editor.action.webvieweditor.showFind';
|
||||
@@ -8,8 +8,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
@@ -17,19 +16,15 @@ import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { WebviewEditorInput } from 'vs/workbench/contrib/webview/electron-browser/webviewEditorInput';
|
||||
import { WebviewEditorInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput';
|
||||
import { IWebviewService, Webview, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { WebviewElement } from './webviewElement';
|
||||
|
||||
/** A context key that is set when the find widget in a webview is visible. */
|
||||
export const KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE = new RawContextKey<boolean>('webviewFindWidgetVisible', false);
|
||||
|
||||
|
||||
export class WebviewEditor extends BaseEditor {
|
||||
|
||||
protected _webview: WebviewElement | undefined;
|
||||
protected _webview: Webview | undefined;
|
||||
protected findWidgetVisible: IContextKey<boolean>;
|
||||
|
||||
public static readonly ID = 'WebviewEditor';
|
||||
@@ -50,9 +45,8 @@ export class WebviewEditor extends BaseEditor {
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IContextKeyService private _contextKeyService: IContextKeyService,
|
||||
@IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService,
|
||||
@IWebviewService private readonly _webviewService: IWebviewService,
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@IWindowService private readonly _windowService: IWindowService,
|
||||
@IStorageService storageService: IStorageService
|
||||
@@ -130,11 +124,11 @@ export class WebviewEditor extends BaseEditor {
|
||||
}
|
||||
|
||||
public reload() {
|
||||
this.withWebviewElement(webview => webview.reload());
|
||||
this.withWebview(webview => webview.reload());
|
||||
}
|
||||
|
||||
public layout(_dimension: DOM.Dimension): void {
|
||||
this.withWebviewElement(webview => {
|
||||
this.withWebview(webview => {
|
||||
this.doUpdateContainer();
|
||||
webview.layout();
|
||||
});
|
||||
@@ -151,34 +145,34 @@ export class WebviewEditor extends BaseEditor {
|
||||
}
|
||||
});
|
||||
}
|
||||
this.withWebviewElement(webview => webview.focus());
|
||||
this.withWebview(webview => webview.focus());
|
||||
}
|
||||
|
||||
public selectAll(): void {
|
||||
this.withWebviewElement(webview => webview.selectAll());
|
||||
this.withWebview(webview => webview.selectAll());
|
||||
}
|
||||
|
||||
public copy(): void {
|
||||
this.withWebviewElement(webview => webview.copy());
|
||||
this.withWebview(webview => webview.copy());
|
||||
}
|
||||
|
||||
public paste(): void {
|
||||
this.withWebviewElement(webview => webview.paste());
|
||||
this.withWebview(webview => webview.paste());
|
||||
}
|
||||
|
||||
public cut(): void {
|
||||
this.withWebviewElement(webview => webview.cut());
|
||||
this.withWebview(webview => webview.cut());
|
||||
}
|
||||
|
||||
public undo(): void {
|
||||
this.withWebviewElement(webview => webview.undo());
|
||||
this.withWebview(webview => webview.undo());
|
||||
}
|
||||
|
||||
public redo(): void {
|
||||
this.withWebviewElement(webview => webview.redo());
|
||||
this.withWebview(webview => webview.redo());
|
||||
}
|
||||
|
||||
private withWebviewElement(f: (element: WebviewElement) => void): void {
|
||||
private withWebview(f: (element: Webview) => void): void {
|
||||
if (this._webview) {
|
||||
f(this._webview);
|
||||
}
|
||||
@@ -264,7 +258,7 @@ export class WebviewEditor extends BaseEditor {
|
||||
return rootPaths;
|
||||
}
|
||||
|
||||
private getWebview(input: WebviewEditorInput): WebviewElement {
|
||||
private getWebview(input: WebviewEditorInput): Webview {
|
||||
if (this._webview) {
|
||||
return this._webview;
|
||||
}
|
||||
@@ -279,14 +273,12 @@ export class WebviewEditor extends BaseEditor {
|
||||
this.findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(this._contextKeyService);
|
||||
}
|
||||
|
||||
this._webview = this._instantiationService.createInstance(WebviewElement,
|
||||
this._layoutService.getContainer(Parts.EDITOR_PART),
|
||||
this._webview = this._webviewService.createWebview(
|
||||
{
|
||||
allowSvgs: true,
|
||||
extension: input.extension,
|
||||
enableFindWidget: input.options.enableFindWidget
|
||||
},
|
||||
{});
|
||||
}, {});
|
||||
this._webview.mountTo(this._webviewContent);
|
||||
input.webview = this._webview;
|
||||
|
||||
@@ -11,7 +11,7 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { EditorInput, EditorModel, GroupIdentifier, IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { WebviewEvents, WebviewInputOptions } from './webviewEditorService';
|
||||
import { WebviewElement, WebviewOptions } from './webviewElement';
|
||||
import { Webview, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview';
|
||||
|
||||
export class WebviewEditorInput extends EditorInput {
|
||||
private static handlePool = 0;
|
||||
@@ -57,7 +57,7 @@ export class WebviewEditorInput extends EditorInput {
|
||||
private _currentWebviewHtml: string = '';
|
||||
public _events: WebviewEvents | undefined;
|
||||
private _container?: HTMLElement;
|
||||
private _webview: WebviewElement | undefined;
|
||||
private _webview?: Webview;
|
||||
private _webviewOwner: any;
|
||||
private _webviewDisposables: IDisposable[] = [];
|
||||
private _group?: GroupIdentifier;
|
||||
@@ -72,7 +72,6 @@ export class WebviewEditorInput extends EditorInput {
|
||||
|
||||
constructor(
|
||||
public readonly viewType: string,
|
||||
id: number | undefined,
|
||||
name: string,
|
||||
options: WebviewInputOptions,
|
||||
state: any,
|
||||
@@ -85,12 +84,7 @@ export class WebviewEditorInput extends EditorInput {
|
||||
) {
|
||||
super();
|
||||
|
||||
if (typeof id === 'number') {
|
||||
this._id = id;
|
||||
WebviewEditorInput.handlePool = Math.max(id, WebviewEditorInput.handlePool) + 1;
|
||||
} else {
|
||||
this._id = WebviewEditorInput.handlePool++;
|
||||
}
|
||||
this._id = WebviewEditorInput.handlePool++;
|
||||
|
||||
this._name = name;
|
||||
this._options = options;
|
||||
@@ -103,10 +97,6 @@ export class WebviewEditorInput extends EditorInput {
|
||||
return WebviewEditorInput.typeId;
|
||||
}
|
||||
|
||||
public getId(): number {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
private readonly _onDidChangeIcon = this._register(new Emitter<void>());
|
||||
public readonly onDidChangeIcon = this._onDidChangeIcon.event;
|
||||
|
||||
@@ -161,7 +151,7 @@ export class WebviewEditorInput extends EditorInput {
|
||||
}
|
||||
|
||||
public matches(other: IEditorInput): boolean {
|
||||
return other === this || (other instanceof WebviewEditorInput && other._id === this._id);
|
||||
return other === this;
|
||||
}
|
||||
|
||||
public get group(): GroupIdentifier | undefined {
|
||||
@@ -234,11 +224,11 @@ export class WebviewEditorInput extends EditorInput {
|
||||
return this._container;
|
||||
}
|
||||
|
||||
public get webview(): WebviewElement | undefined {
|
||||
public get webview(): Webview | undefined {
|
||||
return this._webview;
|
||||
}
|
||||
|
||||
public set webview(value: WebviewElement | undefined) {
|
||||
public set webview(value: Webview | undefined) {
|
||||
this._webviewDisposables = dispose(this._webviewDisposables);
|
||||
|
||||
this._webview = value;
|
||||
@@ -272,6 +262,7 @@ export class WebviewEditorInput extends EditorInput {
|
||||
}
|
||||
|
||||
public claimWebview(owner: any) {
|
||||
|
||||
this._webviewOwner = owner;
|
||||
}
|
||||
|
||||
@@ -315,7 +306,6 @@ export class RevivedWebviewEditorInput extends WebviewEditorInput {
|
||||
|
||||
constructor(
|
||||
viewType: string,
|
||||
id: number | undefined,
|
||||
name: string,
|
||||
options: WebviewInputOptions,
|
||||
state: any,
|
||||
@@ -324,10 +314,10 @@ export class RevivedWebviewEditorInput extends WebviewEditorInput {
|
||||
readonly location: URI;
|
||||
readonly id: ExtensionIdentifier
|
||||
},
|
||||
public readonly reviver: (input: WebviewEditorInput) => Promise<void>,
|
||||
private readonly reviver: (input: WebviewEditorInput) => Promise<void>,
|
||||
@IWorkbenchLayoutService partService: IWorkbenchLayoutService,
|
||||
) {
|
||||
super(viewType, id, name, options, state, events, extension, partService);
|
||||
super(viewType, name, options, state, events, extension, partService);
|
||||
}
|
||||
|
||||
public async resolve(): Promise<IEditorModel> {
|
||||
@@ -17,7 +17,6 @@ interface SerializedIconPath {
|
||||
|
||||
interface SerializedWebview {
|
||||
readonly viewType: string;
|
||||
readonly id: number;
|
||||
readonly title: string;
|
||||
readonly options: WebviewInputOptions;
|
||||
readonly extensionLocation: string | UriComponents | undefined;
|
||||
@@ -44,7 +43,6 @@ export class WebviewEditorInputFactory implements IEditorInputFactory {
|
||||
|
||||
const data: SerializedWebview = {
|
||||
viewType: input.viewType,
|
||||
id: input.getId(),
|
||||
title: input.getName(),
|
||||
options: input.options,
|
||||
extensionLocation: input.extension ? input.extension.location : undefined,
|
||||
@@ -69,7 +67,7 @@ export class WebviewEditorInputFactory implements IEditorInputFactory {
|
||||
const extensionLocation = reviveUri(data.extensionLocation);
|
||||
const extensionId = data.extensionId ? new ExtensionIdentifier(data.extensionId) : undefined;
|
||||
const iconPath = reviveIconPath(data.iconPath);
|
||||
return this._webviewService.reviveWebview(data.viewType, data.id, data.title, iconPath, data.state, data.options, extensionLocation ? {
|
||||
return this._webviewService.reviveWebview(data.viewType, data.title, iconPath, data.state, data.options, extensionLocation ? {
|
||||
location: extensionLocation,
|
||||
id: extensionId
|
||||
} : undefined, data.group);
|
||||
@@ -39,7 +39,6 @@ export interface IWebviewEditorService {
|
||||
|
||||
reviveWebview(
|
||||
viewType: string,
|
||||
id: number,
|
||||
title: string,
|
||||
iconPath: { light: URI, dark: URI } | undefined,
|
||||
state: any,
|
||||
@@ -143,7 +142,7 @@ export class WebviewEditorService implements IWebviewEditorService {
|
||||
},
|
||||
events: WebviewEvents
|
||||
): WebviewEditorInput {
|
||||
const webviewInput = this._instantiationService.createInstance(WebviewEditorInput, viewType, undefined, title, options, {}, events, extension);
|
||||
const webviewInput = this._instantiationService.createInstance(WebviewEditorInput, viewType, title, options, {}, events, extension);
|
||||
this._editorService.openEditor(webviewInput, { pinned: true, preserveFocus: showOptions.preserveFocus }, showOptions.group);
|
||||
return webviewInput;
|
||||
}
|
||||
@@ -165,7 +164,6 @@ export class WebviewEditorService implements IWebviewEditorService {
|
||||
|
||||
public reviveWebview(
|
||||
viewType: string,
|
||||
id: number,
|
||||
title: string,
|
||||
iconPath: { light: URI, dark: URI } | undefined,
|
||||
state: any,
|
||||
@@ -176,7 +174,7 @@ export class WebviewEditorService implements IWebviewEditorService {
|
||||
},
|
||||
group: number | undefined,
|
||||
): WebviewEditorInput {
|
||||
const webviewInput = this._instantiationService.createInstance(RevivedWebviewEditorInput, viewType, id, title, options, state, {}, extension, async (webview: WebviewEditorInput): Promise<void> => {
|
||||
const webviewInput = this._instantiationService.createInstance(RevivedWebviewEditorInput, viewType, title, options, state, {}, extension, async (webview: WebviewEditorInput): Promise<void> => {
|
||||
const didRevive = await this.tryRevive(webview);
|
||||
if (didRevive) {
|
||||
return Promise.resolve(undefined);
|
||||
@@ -220,7 +218,7 @@ export class WebviewEditorService implements IWebviewEditorService {
|
||||
|
||||
// Revived webviews may not have an actively registered reviver but we still want to presist them
|
||||
// since a reviver should exist when it is actually needed.
|
||||
return !(webview instanceof RevivedWebviewEditorInput);
|
||||
return webview instanceof RevivedWebviewEditorInput;
|
||||
}
|
||||
|
||||
private async tryRevive(
|
||||
@@ -4,52 +4,45 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { SimpleFindWidget } from 'vs/editor/contrib/find/simpleFindWidget';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { WebviewElement } from './webviewElement';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
|
||||
export interface WebviewFindDelegate {
|
||||
find(value: string, previous: boolean): void;
|
||||
startFind(value: string): void;
|
||||
stopFind(keepSelection?: boolean): void;
|
||||
focus(): void;
|
||||
}
|
||||
|
||||
export class WebviewFindWidget extends SimpleFindWidget {
|
||||
|
||||
constructor(
|
||||
private _webview: WebviewElement | undefined,
|
||||
private readonly _delegate: WebviewFindDelegate,
|
||||
@IContextViewService contextViewService: IContextViewService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
) {
|
||||
super(contextViewService, contextKeyService);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._webview = undefined;
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public find(previous: boolean) {
|
||||
if (!this._webview) {
|
||||
return;
|
||||
}
|
||||
const val = this.inputValue;
|
||||
if (val) {
|
||||
this._webview.find(val, { findNext: true, forward: !previous });
|
||||
this._delegate.find(val, previous);
|
||||
}
|
||||
}
|
||||
|
||||
public hide() {
|
||||
super.hide();
|
||||
if (this._webview) {
|
||||
this._webview.stopFind(true);
|
||||
this._webview.focus();
|
||||
}
|
||||
this._delegate.stopFind(true);
|
||||
this._delegate.focus();
|
||||
}
|
||||
|
||||
public onInputChanged() {
|
||||
if (!this._webview) {
|
||||
return;
|
||||
}
|
||||
const val = this.inputValue;
|
||||
if (val) {
|
||||
this._webview.startFind(val);
|
||||
this._delegate.startFind(val);
|
||||
} else {
|
||||
this._webview.stopFind(false);
|
||||
this._delegate.stopFind(false);
|
||||
}
|
||||
}
|
||||
|
||||
88
src/vs/workbench/contrib/webview/common/webview.ts
Normal file
88
src/vs/workbench/contrib/webview/common/webview.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
|
||||
/**
|
||||
* Set when the find widget in a webview is visible.
|
||||
*/
|
||||
export const KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE = new RawContextKey<boolean>('webviewFindWidgetVisible', false);
|
||||
|
||||
export const IWebviewService = createDecorator<IWebviewService>('webviewService');
|
||||
|
||||
/**
|
||||
* Handles the creation of webview elements.
|
||||
*/
|
||||
export interface IWebviewService {
|
||||
_serviceBrand: any;
|
||||
|
||||
createWebview(
|
||||
options: WebviewOptions,
|
||||
contentOptions: WebviewContentOptions,
|
||||
): Webview;
|
||||
}
|
||||
|
||||
export interface WebviewPortMapping {
|
||||
readonly port: number;
|
||||
readonly resolvedPort: number;
|
||||
}
|
||||
|
||||
export interface WebviewOptions {
|
||||
readonly allowSvgs?: boolean;
|
||||
readonly extension?: {
|
||||
readonly location: URI;
|
||||
readonly id?: ExtensionIdentifier;
|
||||
};
|
||||
readonly enableFindWidget?: boolean;
|
||||
}
|
||||
|
||||
export interface WebviewContentOptions {
|
||||
readonly allowScripts?: boolean;
|
||||
readonly svgWhiteList?: string[];
|
||||
readonly localResourceRoots?: ReadonlyArray<URI>;
|
||||
readonly portMappings?: ReadonlyArray<WebviewPortMapping>;
|
||||
}
|
||||
|
||||
export interface Webview {
|
||||
|
||||
contents: string;
|
||||
options: WebviewContentOptions;
|
||||
initialScrollProgress: number;
|
||||
state: string | undefined;
|
||||
|
||||
readonly onDidFocus: Event<void>;
|
||||
readonly onDidClickLink: Event<URI>;
|
||||
readonly onDidScroll: Event<{ scrollYPercentage: number }>;
|
||||
readonly onDidUpdateState: Event<string | undefined>;
|
||||
readonly onMessage: Event<any>;
|
||||
|
||||
sendMessage(data: any): void;
|
||||
update(
|
||||
value: string,
|
||||
options: WebviewContentOptions,
|
||||
retainContextWhenHidden: boolean
|
||||
): void;
|
||||
|
||||
layout(): void;
|
||||
mountTo(parent: HTMLElement): void;
|
||||
focus(): void;
|
||||
dispose(): void;
|
||||
|
||||
|
||||
reload(): void;
|
||||
selectAll(): void;
|
||||
copy(): void;
|
||||
paste(): void;
|
||||
cut(): void;
|
||||
undo(): void;
|
||||
redo(): void;
|
||||
|
||||
showFind(): void;
|
||||
hideFind(): void;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
// @ts-check
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
const registerVscodeResourceScheme = (function () {
|
||||
let hasRegistered = false;
|
||||
return () => {
|
||||
if (hasRegistered) {
|
||||
return;
|
||||
}
|
||||
hasRegistered = true;
|
||||
|
||||
// @ts-ignore
|
||||
require('electron').webFrame.registerURLSchemeAsPrivileged('vscode-resource', {
|
||||
secure: true,
|
||||
bypassCSP: false,
|
||||
allowServiceWorkers: false,
|
||||
supportFetchAPI: true,
|
||||
corsEnabled: true
|
||||
});
|
||||
};
|
||||
}());
|
||||
|
||||
// @ts-ignore
|
||||
const ipcRenderer = require('electron').ipcRenderer;
|
||||
|
||||
require('../../browser/pre/main')({
|
||||
postMessage: (channel, data) => {
|
||||
ipcRenderer.sendToHost(channel, data);
|
||||
},
|
||||
onMessage: (channel, handler) => {
|
||||
ipcRenderer.on(channel, handler);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
registerVscodeResourceScheme();
|
||||
});
|
||||
}());
|
||||
@@ -3,135 +3,8 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { localize } from 'vs/nls';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { EditorDescriptor, Extensions as EditorExtensions, IEditorRegistry } from 'vs/workbench/browser/editor';
|
||||
import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
|
||||
import { Extensions as EditorInputExtensions, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor';
|
||||
import { WebviewEditorInputFactory } from 'vs/workbench/contrib/webview/electron-browser/webviewEditorInputFactory';
|
||||
import { HideWebViewEditorFindCommand, OpenWebviewDeveloperToolsAction, ReloadWebviewAction, ShowWebViewEditorFindWidgetCommand, SelectAllWebviewEditorCommand, CopyWebviewEditorCommand, PasteWebviewEditorCommand, CutWebviewEditorCommand, UndoWebviewEditorCommand, RedoWebviewEditorCommand } from './webviewCommands';
|
||||
import { WebviewEditor, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE } from './webviewEditor';
|
||||
import { WebviewEditorInput } from './webviewEditorInput';
|
||||
import { IWebviewEditorService, WebviewEditorService } from './webviewEditorService';
|
||||
import { InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { IWebviewService } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { WebviewService } from 'vs/workbench/contrib/webview/electron-browser/webviewService';
|
||||
|
||||
(Registry.as<IEditorRegistry>(EditorExtensions.Editors)).registerEditor(new EditorDescriptor(
|
||||
WebviewEditor,
|
||||
WebviewEditor.ID,
|
||||
localize('webview.editor.label', "webview editor")),
|
||||
[new SyncDescriptor(WebviewEditorInput)]);
|
||||
|
||||
Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(
|
||||
WebviewEditorInputFactory.ID,
|
||||
WebviewEditorInputFactory);
|
||||
|
||||
registerSingleton(IWebviewEditorService, WebviewEditorService, true);
|
||||
|
||||
|
||||
const webviewDeveloperCategory = localize('developer', "Developer");
|
||||
|
||||
const actionRegistry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
|
||||
export function registerWebViewCommands(editorId: string): void {
|
||||
const contextKeyExpr = ContextKeyExpr.and(ContextKeyExpr.equals('activeEditor', editorId), ContextKeyExpr.not('editorFocus') /* https://github.com/Microsoft/vscode/issues/58668 */);
|
||||
|
||||
const showNextFindWidgetCommand = new ShowWebViewEditorFindWidgetCommand({
|
||||
id: ShowWebViewEditorFindWidgetCommand.ID,
|
||||
precondition: contextKeyExpr,
|
||||
kbOpts: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_F,
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
});
|
||||
showNextFindWidgetCommand.register();
|
||||
|
||||
(new HideWebViewEditorFindCommand({
|
||||
id: HideWebViewEditorFindCommand.ID,
|
||||
precondition: ContextKeyExpr.and(
|
||||
contextKeyExpr,
|
||||
KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE),
|
||||
kbOpts: {
|
||||
primary: KeyCode.Escape,
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
})).register();
|
||||
|
||||
(new SelectAllWebviewEditorCommand({
|
||||
id: SelectAllWebviewEditorCommand.ID,
|
||||
precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)),
|
||||
kbOpts: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_A,
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
})).register();
|
||||
|
||||
// These commands are only needed on MacOS where we have to disable the menu bar commands
|
||||
if (isMacintosh) {
|
||||
(new CopyWebviewEditorCommand({
|
||||
id: CopyWebviewEditorCommand.ID,
|
||||
precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)),
|
||||
kbOpts: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_C,
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
})).register();
|
||||
|
||||
(new PasteWebviewEditorCommand({
|
||||
id: PasteWebviewEditorCommand.ID,
|
||||
precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)),
|
||||
kbOpts: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_V,
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
})).register();
|
||||
|
||||
|
||||
(new CutWebviewEditorCommand({
|
||||
id: CutWebviewEditorCommand.ID,
|
||||
precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)),
|
||||
kbOpts: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_X,
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
})).register();
|
||||
|
||||
(new UndoWebviewEditorCommand({
|
||||
id: UndoWebviewEditorCommand.ID,
|
||||
precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)),
|
||||
kbOpts: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_Z,
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
})).register();
|
||||
|
||||
(new RedoWebviewEditorCommand({
|
||||
id: RedoWebviewEditorCommand.ID,
|
||||
precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)),
|
||||
kbOpts: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_Y,
|
||||
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z],
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z },
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
})).register();
|
||||
}
|
||||
}
|
||||
|
||||
registerWebViewCommands(WebviewEditor.ID);
|
||||
|
||||
actionRegistry.registerWorkbenchAction(
|
||||
new SyncActionDescriptor(OpenWebviewDeveloperToolsAction, OpenWebviewDeveloperToolsAction.ID, OpenWebviewDeveloperToolsAction.LABEL),
|
||||
'Webview Tools',
|
||||
webviewDeveloperCategory);
|
||||
|
||||
actionRegistry.registerWorkbenchAction(
|
||||
new SyncActionDescriptor(ReloadWebviewAction, ReloadWebviewAction.ID, ReloadWebviewAction.LABEL),
|
||||
'Reload Webview',
|
||||
webviewDeveloperCategory);
|
||||
registerSingleton(IWebviewService, WebviewService, true);
|
||||
|
||||
@@ -17,36 +17,12 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import * as colorRegistry from 'vs/platform/theme/common/colorRegistry';
|
||||
import { DARK, ITheme, IThemeService, LIGHT } from 'vs/platform/theme/common/themeService';
|
||||
import { registerFileProtocol, WebviewProtocol } from 'vs/workbench/contrib/webview/electron-browser/webviewProtocols';
|
||||
import { areWebviewInputOptionsEqual } from './webviewEditorService';
|
||||
import { WebviewFindWidget } from './webviewFindWidget';
|
||||
import { areWebviewInputOptionsEqual } from '../browser/webviewEditorService';
|
||||
import { WebviewFindWidget } from '../browser/webviewFindWidget';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { WebviewContentOptions, WebviewPortMapping, WebviewOptions, Webview } from 'vs/workbench/contrib/webview/common/webview';
|
||||
|
||||
export interface WebviewPortMapping {
|
||||
readonly port: number;
|
||||
readonly resolvedPort: number;
|
||||
}
|
||||
|
||||
export interface WebviewPortMapping {
|
||||
readonly port: number;
|
||||
readonly resolvedPort: number;
|
||||
}
|
||||
|
||||
export interface WebviewOptions {
|
||||
readonly allowSvgs?: boolean;
|
||||
readonly extension?: {
|
||||
readonly location: URI;
|
||||
readonly id?: ExtensionIdentifier;
|
||||
};
|
||||
readonly enableFindWidget?: boolean;
|
||||
}
|
||||
|
||||
export interface WebviewContentOptions {
|
||||
readonly allowScripts?: boolean;
|
||||
readonly svgWhiteList?: string[];
|
||||
readonly localResourceRoots?: ReadonlyArray<URI>;
|
||||
readonly portMappings?: ReadonlyArray<WebviewPortMapping>;
|
||||
}
|
||||
|
||||
interface IKeydownEvent {
|
||||
key: string;
|
||||
@@ -316,7 +292,7 @@ class WebviewKeyboardHandler extends Disposable {
|
||||
}
|
||||
|
||||
|
||||
export class WebviewElement extends Disposable {
|
||||
export class WebviewElement extends Disposable implements Webview {
|
||||
private _webview: Electron.WebviewTag;
|
||||
private _ready: Promise<void>;
|
||||
|
||||
@@ -350,7 +326,7 @@ export class WebviewElement extends Disposable {
|
||||
this._webview.style.height = '0';
|
||||
this._webview.style.outline = '0';
|
||||
|
||||
this._webview.preload = require.toUrl('./webview-pre.js');
|
||||
this._webview.preload = require.toUrl('./pre/electron-index.js');
|
||||
this._webview.src = 'data:text/html;charset=utf-8,%3C%21DOCTYPE%20html%3E%0D%0A%3Chtml%20lang%3D%22en%22%20style%3D%22width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3Chead%3E%0D%0A%09%3Ctitle%3EVirtual%20Document%3C%2Ftitle%3E%0D%0A%3C%2Fhead%3E%0D%0A%3Cbody%20style%3D%22margin%3A%200%3B%20overflow%3A%20hidden%3B%20width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3C%2Fbody%3E%0D%0A%3C%2Fhtml%3E';
|
||||
|
||||
this._ready = new Promise(resolve => {
|
||||
@@ -539,10 +515,6 @@ export class WebviewElement extends Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
public set baseUrl(value: string) {
|
||||
this._send('baseUrl', value);
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
this._webview.focus();
|
||||
this._send('focus');
|
||||
@@ -641,12 +613,13 @@ export class WebviewElement extends Disposable {
|
||||
*
|
||||
* @param value The string to search for. Empty strings are ignored.
|
||||
*/
|
||||
public find(value: string, options?: Electron.FindInPageOptions): void {
|
||||
public find(value: string, previous: boolean): void {
|
||||
// Searching with an empty value will throw an exception
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
|
||||
const options = { findNext: true, forward: !previous };
|
||||
if (!this._findStarted) {
|
||||
this.startFind(value, options);
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IWebviewService, WebviewOptions, WebviewContentOptions, Webview } from 'vs/workbench/contrib/webview/common/webview';
|
||||
|
||||
export class WebviewService implements IWebviewService {
|
||||
_serviceBrand: any;
|
||||
|
||||
constructor(
|
||||
@IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
) { }
|
||||
|
||||
createWebview(
|
||||
options: WebviewOptions,
|
||||
contentOptions: WebviewContentOptions
|
||||
): Webview {
|
||||
const element = this._instantiationService.createInstance(WebviewElement,
|
||||
this._layoutService.getContainer(Parts.EDITOR_PART),
|
||||
options,
|
||||
contentOptions);
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user