提交 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
import {ExtensionsService} from 'vs/workbench/parts/extensions/node/extensionsService';
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
*/
......
......@@ -24,6 +24,7 @@ import {BaseTextEditorModel} from 'vs/workbench/common/editor/textEditorModel';
import {HtmlInput} from 'vs/workbench/parts/html/common/htmlInput';
import {IThemeService} from 'vs/workbench/services/themes/common/themeService';
import {KeybindingsRegistry} from 'vs/platform/keybinding/common/keybindingsRegistry';
import {IOpenerService} from 'vs/platform/opener/common/opener';
KeybindingsRegistry.registerCommandDesc({
id: '_webview.openDevTools',
......@@ -62,7 +63,7 @@ class ManagedWebview {
private _ready: TPromise<this>;
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.style.zIndex = '1';
this._webview.style.position = 'absolute';
......@@ -88,6 +89,12 @@ class ManagedWebview {
}),
addDisposableListener(this._webview, 'crashed', function () {
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 {
private _editorService: IWorkbenchEditorService;
private _themeService: IThemeService;
private _openerService: IOpenerService;
private _webview: ManagedWebview;
private _container: HTMLDivElement;
......@@ -203,12 +211,14 @@ export class HtmlPreviewPart extends BaseEditor {
@ITelemetryService telemetryService: ITelemetryService,
@IWorkbenchEditorService editorService: IWorkbenchEditorService,
@IThemeService themeService: IThemeService,
@IOpenerService openerService: IOpenerService,
@IWorkspaceContextService contextService: IWorkspaceContextService
) {
super(HtmlPreviewPart.ID, telemetryService);
this._editorService = editorService;
this._themeService = themeService;
this._openerService = openerService;
this._baseUrl = contextService.toResource('/');
}
......@@ -232,7 +242,8 @@ export class HtmlPreviewPart extends BaseEditor {
if (!this._webview) {
this._webview = new ManagedWebview(document.getElementById('workbench.main.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();
}
......
......@@ -66,6 +66,17 @@
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
target.contentDocument.open('text/html', 'replace');
target.contentDocument.write(newDocument.documentElement.innerHTML);
......@@ -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
// unknown reason
setTimeout(function() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册