提交 d295bff1 编写于 作者: J Johannes Rieken

add IOpenerService and use it with webview, #3676

上级 37f6bc48
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI from 'vs/base/common/uri';
import {TPromise} from 'vs/base/common/winjs.base';
import {createDecorator} from 'vs/platform/instantiation/common/instantiation';
export const IOpenerService = createDecorator<IOpenerService>('openerService');
export interface IOpenerService {
serviceId: any;
/**
* Opens a resource, like a webadress, a document uri, or executes command.
*
* @param resource A resource
* @return A promise that resolves when the opening is done.
*/
open(resource: URI): TPromise<any>;
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {registerSingleton} from 'vs/platform/instantiation/common/extensions';
import {OpenerService} from 'vs/platform/opener/electron-browser/openerService';
import {IOpenerService} from 'vs/platform/opener/common/opener';
registerSingleton(IOpenerService, OpenerService);
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI from 'vs/base/common/uri';
import {Schemas} from 'vs/base/common/network';
import {TPromise} from 'vs/base/common/winjs.base';
import {IEditorService} from 'vs/platform/editor/common/editor';
import {IKeybindingService} from 'vs/platform/keybinding/common/keybindingService';
import {IOpenerService} from '../common/opener';
export class OpenerService implements IOpenerService {
serviceId: any;
constructor(
@IEditorService private _editorService: IEditorService,
@IKeybindingService private _keybindingService: IKeybindingService
) {
//
}
open(resource: URI): TPromise<any> {
const {scheme, path, query, fragment} = resource;
let promise: TPromise<any>;
if (scheme === Schemas.http || scheme === Schemas.https) {
// open http
window.open(resource.toString(true));
} else if (scheme === 'command' && this._keybindingService.hasCommand(path)) {
// execute as command
let args: any;
try {
args = JSON.parse(query);
} catch (e) {
//
}
promise = this._keybindingService.executeCommand(path, Array.isArray(args) ? args : [args]);
} else {
promise = this._editorService.resolveEditorModel({ resource }).then(model => {
if (!model) {
return;
}
// support file:///some/file.js#L73
let selection: {
startLineNumber: number;
startColumn: number;
};
if (/^L\d+$/.test(fragment)) {
selection = {
startLineNumber: parseInt(fragment.substr(1)),
startColumn: 1
};
}
return this._editorService.openEditor({ resource, options: { selection } });
});
}
return TPromise.as(promise).then(undefined, err => { }); // !ignores all errors
}
}
...@@ -93,6 +93,9 @@ import {IExtensionsService} from 'vs/workbench/parts/extensions/common/extension ...@@ -93,6 +93,9 @@ import {IExtensionsService} from 'vs/workbench/parts/extensions/common/extension
import {ExtensionsService} from 'vs/workbench/parts/extensions/node/extensionsService'; import {ExtensionsService} from 'vs/workbench/parts/extensions/node/extensionsService';
import {ReloadWindowAction} from 'vs/workbench/electron-browser/actions'; import {ReloadWindowAction} from 'vs/workbench/electron-browser/actions';
// self registering service
import 'vs/platform/opener/electron-browser/opener.contribution';
/** /**
* Services that we require for the Shell * Services that we require for the Shell
*/ */
......
...@@ -24,6 +24,7 @@ import {BaseTextEditorModel} from 'vs/workbench/common/editor/textEditorModel'; ...@@ -24,6 +24,7 @@ import {BaseTextEditorModel} from 'vs/workbench/common/editor/textEditorModel';
import {HtmlInput} from 'vs/workbench/parts/html/common/htmlInput'; import {HtmlInput} from 'vs/workbench/parts/html/common/htmlInput';
import {IThemeService} from 'vs/workbench/services/themes/common/themeService'; import {IThemeService} from 'vs/workbench/services/themes/common/themeService';
import {KeybindingsRegistry} from 'vs/platform/keybinding/common/keybindingsRegistry'; import {KeybindingsRegistry} from 'vs/platform/keybinding/common/keybindingsRegistry';
import {IOpenerService} from 'vs/platform/opener/common/opener';
KeybindingsRegistry.registerCommandDesc({ KeybindingsRegistry.registerCommandDesc({
id: '_webview.openDevTools', id: '_webview.openDevTools',
...@@ -62,7 +63,7 @@ class ManagedWebview { ...@@ -62,7 +63,7 @@ class ManagedWebview {
private _ready: TPromise<this>; private _ready: TPromise<this>;
private _disposables: IDisposable[]; private _disposables: IDisposable[];
constructor(private _parent: HTMLElement, private _layoutParent: HTMLElement, private _styleElement) { constructor(private _parent: HTMLElement, private _layoutParent: HTMLElement, private _styleElement, onDidClickLink:(uri:URI)=>any) {
this._webview = <Webview>document.createElement('webview'); this._webview = <Webview>document.createElement('webview');
this._webview.style.zIndex = '1'; this._webview.style.zIndex = '1';
this._webview.style.position = 'absolute'; this._webview.style.position = 'absolute';
...@@ -88,6 +89,12 @@ class ManagedWebview { ...@@ -88,6 +89,12 @@ class ManagedWebview {
}), }),
addDisposableListener(this._webview, 'crashed', function () { addDisposableListener(this._webview, 'crashed', function () {
console.error('embedded page crashed'); console.error('embedded page crashed');
}),
addDisposableListener(this._webview, 'ipc-message', (event) => {
if (event.channel === 'did-click-link') {
let [uri] = event.args;
onDidClickLink(URI.parse(uri));
}
}) })
]; ];
...@@ -190,6 +197,7 @@ export class HtmlPreviewPart extends BaseEditor { ...@@ -190,6 +197,7 @@ export class HtmlPreviewPart extends BaseEditor {
private _editorService: IWorkbenchEditorService; private _editorService: IWorkbenchEditorService;
private _themeService: IThemeService; private _themeService: IThemeService;
private _openerService: IOpenerService;
private _webview: ManagedWebview; private _webview: ManagedWebview;
private _container: HTMLDivElement; private _container: HTMLDivElement;
...@@ -203,12 +211,14 @@ export class HtmlPreviewPart extends BaseEditor { ...@@ -203,12 +211,14 @@ export class HtmlPreviewPart extends BaseEditor {
@ITelemetryService telemetryService: ITelemetryService, @ITelemetryService telemetryService: ITelemetryService,
@IWorkbenchEditorService editorService: IWorkbenchEditorService, @IWorkbenchEditorService editorService: IWorkbenchEditorService,
@IThemeService themeService: IThemeService, @IThemeService themeService: IThemeService,
@IOpenerService openerService: IOpenerService,
@IWorkspaceContextService contextService: IWorkspaceContextService @IWorkspaceContextService contextService: IWorkspaceContextService
) { ) {
super(HtmlPreviewPart.ID, telemetryService); super(HtmlPreviewPart.ID, telemetryService);
this._editorService = editorService; this._editorService = editorService;
this._themeService = themeService; this._themeService = themeService;
this._openerService = openerService;
this._baseUrl = contextService.toResource('/'); this._baseUrl = contextService.toResource('/');
} }
...@@ -232,7 +242,8 @@ export class HtmlPreviewPart extends BaseEditor { ...@@ -232,7 +242,8 @@ export class HtmlPreviewPart extends BaseEditor {
if (!this._webview) { if (!this._webview) {
this._webview = new ManagedWebview(document.getElementById('workbench.main.container'), this._webview = new ManagedWebview(document.getElementById('workbench.main.container'),
this._container, this._container,
document.querySelector('.monaco-editor-background')); document.querySelector('.monaco-editor-background'),
uri => this._openerService.open(uri));
this._webview.baseUrl = this._baseUrl && this._baseUrl.toString(); this._webview.baseUrl = this._baseUrl && this._baseUrl.toString();
} }
......
...@@ -66,6 +66,17 @@ ...@@ -66,6 +66,17 @@
newDocument.head.appendChild(defaultStyles); newDocument.head.appendChild(defaultStyles);
} }
// script to bubble out link-clicks
const defaultScripts = newDocument.createElement('script');
defaultScripts.innerHTML = `
document.body.addEventListener('click', function (event) {
if(event.target.tagName === 'A' && event.target.href) {
window.parent.postMessage({ command: 'did-click-link', data: event.target.href }, 'file://');
event.preventDefault();
}
});`
newDocument.body.appendChild(defaultScripts);
// write new content onto iframe // write new content onto iframe
target.contentDocument.open('text/html', 'replace'); target.contentDocument.open('text/html', 'replace');
target.contentDocument.write(newDocument.documentElement.innerHTML); target.contentDocument.write(newDocument.documentElement.innerHTML);
...@@ -73,6 +84,12 @@ ...@@ -73,6 +84,12 @@
}); });
// forward messages from the embedded iframe
window.onmessage = function(message) {
const { command, data} = message.data;
ipcRenderer.sendToHost(command, data);
};
// signal ready, needs a short timeout for an // signal ready, needs a short timeout for an
// unknown reason // unknown reason
setTimeout(function() { setTimeout(function() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册