mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-06 05:38:13 +01:00
@@ -14,8 +14,6 @@ import {HtmlInput} from '../common/htmlInput';
|
||||
import {HtmlPreviewPart} from 'vs/workbench/parts/html/browser/htmlPreviewPart';
|
||||
import {Registry} from 'vs/platform/platform';
|
||||
import {EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions} from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
|
||||
|
||||
import {SyncDescriptor} from 'vs/platform/instantiation/common/descriptors';
|
||||
|
||||
// --- Register Editor
|
||||
|
||||
@@ -5,298 +5,122 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import 'vs/text!./webview.html';
|
||||
import {localize} from 'vs/nls';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import {TPromise} from 'vs/base/common/winjs.base';
|
||||
import {IModel, EventType} from 'vs/editor/common/editorCommon';
|
||||
import {Dimension, Builder} from 'vs/base/browser/builder';
|
||||
import {empty as EmptyDisposable} from 'vs/base/common/lifecycle';
|
||||
import {empty as EmptyDisposable, IDisposable, dispose} from 'vs/base/common/lifecycle';
|
||||
import {addDisposableListener} from 'vs/base/browser/dom';
|
||||
import {EditorOptions, EditorInput} from 'vs/workbench/common/editor';
|
||||
import {BaseEditor} from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import {Position} from 'vs/platform/editor/common/editor';
|
||||
import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
|
||||
import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
|
||||
import {isLightTheme} from 'vs/platform/theme/common/themes';
|
||||
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
|
||||
import {BaseTextEditorModel} from 'vs/workbench/common/editor/textEditorModel';
|
||||
import {HtmlInput} from 'vs/workbench/parts/html/common/htmlInput';
|
||||
import {isLightTheme} from 'vs/platform/theme/common/themes';
|
||||
import {IThemeService} from 'vs/workbench/services/themes/common/themeService';
|
||||
|
||||
/**
|
||||
* An implementation of editor for showing HTML content in an IFrame by leveraging the IFrameEditorInput.
|
||||
*/
|
||||
export class HtmlPreviewPart extends BaseEditor {
|
||||
declare interface Webview extends HTMLElement {
|
||||
src: string;
|
||||
autoSize: 'on';
|
||||
nodeintegration: 'on';
|
||||
disablewebsecurity: 'on';
|
||||
|
||||
static ID: string = 'workbench.editor.htmlPreviewPart';
|
||||
getURL(): string;
|
||||
getTitle(): string;
|
||||
executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any) => any);
|
||||
send(channel: string, ...args: any[]);
|
||||
openDevTools(): any;
|
||||
closeDevTools(): any;
|
||||
}
|
||||
|
||||
private _editorService: IWorkbenchEditorService;
|
||||
private _themeService: IThemeService;
|
||||
private _iFrameElement: HTMLIFrameElement;
|
||||
private _iFrameMessageSubscription = EmptyDisposable;
|
||||
private _iFrameBase: URI;
|
||||
class ManagedWebview {
|
||||
|
||||
private _model: IModel;
|
||||
private _lastModelVersion: number;
|
||||
private _modelChangeSubscription = EmptyDisposable;
|
||||
private _themeChangeSubscription = EmptyDisposable;
|
||||
private _webview: Webview;
|
||||
private _ready: TPromise<this>;
|
||||
private _disposables: IDisposable[];
|
||||
|
||||
constructor(
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IWorkbenchEditorService editorService: IWorkbenchEditorService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IThemeService themeService: IThemeService
|
||||
) {
|
||||
super(HtmlPreviewPart.ID, telemetryService);
|
||||
constructor(private _parent: HTMLElement, private _layoutParent: HTMLElement, private _styleElement) {
|
||||
this._webview = <Webview>document.createElement('webview');
|
||||
this._webview.style.zIndex = '1';
|
||||
this._webview.style.position = 'absolute';
|
||||
this._webview.style.left = '-1e10px'; // visible but far away
|
||||
this._webview.autoSize = 'on';
|
||||
this._webview.nodeintegration = 'on';
|
||||
this._webview.src = require.toUrl('./webview.html');
|
||||
|
||||
this._editorService = editorService;
|
||||
this._themeService = themeService;
|
||||
this._iFrameBase = contextService.toResource('/');
|
||||
this._ready = new TPromise<this>(resolve => {
|
||||
const subscription = addDisposableListener(this._webview, 'ipc-message', (event) => {
|
||||
if (event.channel === 'webview-ready') {
|
||||
// this._webview.openDevTools();
|
||||
// console.info('[PID Webview] ' + event.args[0]);
|
||||
subscription.dispose();
|
||||
resolve(this);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this._disposables = [
|
||||
addDisposableListener(this._webview, 'console-message', function (e: { level: number; message: string; line: number; sourceId: string; }) {
|
||||
console.log(`[Embedded Page] ${e.message}`);
|
||||
}),
|
||||
addDisposableListener(this._webview, 'crashed', function () {
|
||||
console.error('embedded page crashed');
|
||||
})
|
||||
];
|
||||
|
||||
this._parent.appendChild(this._webview);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
// remove from dom
|
||||
const element = this._iFrameElement.parentElement;
|
||||
element.parentElement.removeChild(element);
|
||||
|
||||
// unhook from model
|
||||
this._modelChangeSubscription.dispose();
|
||||
this._model = undefined;
|
||||
|
||||
this._themeChangeSubscription.dispose();
|
||||
this._disposables = dispose(this._disposables);
|
||||
this._webview.parentElement.removeChild(this._webview);
|
||||
}
|
||||
|
||||
public createEditor(parent: Builder): void {
|
||||
|
||||
// IFrame
|
||||
// this.iframeBuilder.removeProperty(IFrameEditor.RESOURCE_PROPERTY);
|
||||
this._iFrameElement = document.createElement('iframe');
|
||||
this._iFrameElement.setAttribute('frameborder', '0');
|
||||
this._iFrameElement.className = 'iframe';
|
||||
|
||||
// Container for IFrame
|
||||
const iFrameContainerElement = document.createElement('div');
|
||||
iFrameContainerElement.className = 'iframe-container monaco-editor-background'; // Inherit the background color from selected theme
|
||||
iFrameContainerElement.tabIndex = 0; // enable focus support from the editor part (do not remove)
|
||||
iFrameContainerElement.appendChild(this._iFrameElement);
|
||||
|
||||
parent.getHTMLElement().appendChild(iFrameContainerElement);
|
||||
|
||||
this._themeChangeSubscription = this._themeService.onDidThemeChange(themeId => {
|
||||
if (this.isVisible()) {
|
||||
this._updateIFrameContent(true);
|
||||
}
|
||||
});
|
||||
|
||||
this._iFrameMessageSubscription = addDisposableListener(window, 'message', e => {
|
||||
|
||||
if (e.source !== this._iFrameElement.contentWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fakeEvent = <any>document.createEvent('KeyboardEvent'); // create a keyboard event
|
||||
Object.defineProperty(fakeEvent, 'keyCode', { // we need to set some properties that Chrome wants
|
||||
get: function() {
|
||||
return e.data.keyCode;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(fakeEvent, 'which', {
|
||||
get: function() {
|
||||
return e.data.keyCode;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(fakeEvent, 'target', {
|
||||
get: function() {
|
||||
return window && window.parent.document.body;
|
||||
}
|
||||
});
|
||||
fakeEvent.initKeyboardEvent('keydown', true, true, document.defaultView, null, null,
|
||||
e.data.ctrlKey, e.data.altKey, e.data.shiftKey, e.data.metaKey); // the API shape of this method is not clear to me, but it works
|
||||
|
||||
document.dispatchEvent(fakeEvent);
|
||||
});
|
||||
private _send(channel: string, ...args: any[]): void {
|
||||
this._ready
|
||||
.then(() => this._webview.send(channel, ...args))
|
||||
.done(void 0, console.error);
|
||||
}
|
||||
|
||||
public layout(dimension: Dimension): void {
|
||||
let {width, height} = dimension;
|
||||
this._iFrameElement.parentElement.style.width = `${width}px`;
|
||||
this._iFrameElement.parentElement.style.height = `${height}px`;
|
||||
this._iFrameElement.style.width = `${width}px`;
|
||||
this._iFrameElement.style.height = `${height}px`;
|
||||
set contents(value: string[]) {
|
||||
this._send('content', value);
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
// this.iframeContainer.domFocus();
|
||||
this._iFrameElement.focus();
|
||||
set baseUrl(value: string) {
|
||||
this._send('baseUrl', value);
|
||||
}
|
||||
|
||||
// --- input
|
||||
focus(): void {
|
||||
this._send('focus');
|
||||
}
|
||||
|
||||
public getTitle(): string {
|
||||
if (!this.input) {
|
||||
return localize('iframeEditor', 'Preview Html');
|
||||
layout(): void {
|
||||
const {top, left, width, height} = this._layoutParent.getBoundingClientRect();
|
||||
this._webview.style.top = `${top}px`;
|
||||
this._webview.style.left = `${left}px`;
|
||||
this._webview.style.width = `${width}px`;
|
||||
this._webview.style.height = `${height}px`;
|
||||
|
||||
this._send('layout', width, height);
|
||||
}
|
||||
|
||||
style(themeId: string): void {
|
||||
const {color, backgroundColor, fontFamily, fontSize} = window.getComputedStyle(this._styleElement);
|
||||
|
||||
let value = `
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
return this.input.getName();
|
||||
}
|
||||
|
||||
public setVisible(visible: boolean, position?: Position): TPromise<void> {
|
||||
return super.setVisible(visible, position).then(() => {
|
||||
if (visible && this._model) {
|
||||
this._modelChangeSubscription = this._model.addListener2(EventType.ModelContentChanged2, () => this._updateIFrameContent());
|
||||
this._updateIFrameContent();
|
||||
} else {
|
||||
this._modelChangeSubscription.dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public changePosition(position: Position): void {
|
||||
super.changePosition(position);
|
||||
|
||||
// reparenting an IFRAME into another DOM element yields weird results when the contents are made
|
||||
// of a string and not a URL. to be on the safe side we reload the iframe when the position changes
|
||||
// and we do it using a timeout of 0 to reload only after the position has been changed in the DOM
|
||||
setTimeout(() => {
|
||||
this._updateIFrameContent(true);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
public setInput(input: EditorInput, options: EditorOptions): TPromise<void> {
|
||||
|
||||
this._model = undefined;
|
||||
this._modelChangeSubscription.dispose();
|
||||
this._lastModelVersion = -1;
|
||||
|
||||
if (!(input instanceof HtmlInput)) {
|
||||
return TPromise.wrapError<void>('Invalid input');
|
||||
}
|
||||
|
||||
return this._editorService.resolveEditorModel({ resource: (<HtmlInput>input).getResource() }).then(model => {
|
||||
if (model instanceof BaseTextEditorModel) {
|
||||
this._model = model.textEditorModel;
|
||||
}
|
||||
|
||||
if (!this._model) {
|
||||
return TPromise.wrapError<void>(localize('html.voidInput', "Invalid editor input."));
|
||||
}
|
||||
|
||||
this._modelChangeSubscription = this._model.addListener2(EventType.ModelContentChanged2, () => this._updateIFrameContent());
|
||||
this._updateIFrameContent();
|
||||
|
||||
return super.setInput(input, options);
|
||||
});
|
||||
}
|
||||
|
||||
private _updateIFrameContent(refresh: boolean = false): void {
|
||||
|
||||
if (!this._model || (!refresh && this._lastModelVersion === this._model.getVersionId())) {
|
||||
// nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
const html = this._model.getValue();
|
||||
const iFrameDocument = this._iFrameElement.contentDocument;
|
||||
|
||||
if (!iFrameDocument) {
|
||||
// not visible anymore
|
||||
return;
|
||||
}
|
||||
|
||||
const parser = new DOMParser();
|
||||
const newDocument = parser.parseFromString(html, 'text/html');
|
||||
// ensure styles
|
||||
const styleElement = Integration.defaultStyle(this._iFrameElement.parentElement, this._themeService.getTheme());
|
||||
if (newDocument.head.hasChildNodes()) {
|
||||
newDocument.head.insertBefore(styleElement, newDocument.head.firstChild);
|
||||
} else {
|
||||
newDocument.head.appendChild(styleElement);
|
||||
}
|
||||
// set baseurl if possible
|
||||
if (this._iFrameBase) {
|
||||
const baseElement = document.createElement('base');
|
||||
baseElement.href = this._iFrameBase.toString();
|
||||
newDocument.head.appendChild(baseElement);
|
||||
}
|
||||
// propagate key events
|
||||
newDocument.body.appendChild(Integration.bubbleKeybindings);
|
||||
|
||||
// write new content to iframe
|
||||
iFrameDocument.open('text/html', 'replace');
|
||||
iFrameDocument.write(newDocument.documentElement.innerHTML);
|
||||
iFrameDocument.close();
|
||||
|
||||
this._lastModelVersion = this._model.getVersionId();
|
||||
}
|
||||
}
|
||||
|
||||
namespace Integration {
|
||||
|
||||
'use strict';
|
||||
|
||||
// scripts
|
||||
|
||||
export const bubbleKeybindings = document.createElement('script');
|
||||
bubbleKeybindings.innerHTML = `
|
||||
var ignoredKeys = [9 /* tab */, 32 /* space */, 33 /* page up */, 34 /* page down */, 38 /* up */, 40 /* down */];
|
||||
var ignoredCtrlCmdKeys = [65 /* a */, 67 /* c */];
|
||||
var ignoredShiftKeys = [9 /* tab */];
|
||||
window.document.body.addEventListener("keydown", function(event) {
|
||||
try {
|
||||
if (!event.ctrlKey && !event.altKey && !event.shiftKey && !event.metaKey && ignoredKeys.some(function(i) {return i === event.keyCode;})) {
|
||||
return;
|
||||
}
|
||||
if ((event.ctrlKey || event.metaKey) && ignoredCtrlCmdKeys.some(function(i) { return i === event.keyCode; })) {
|
||||
return;
|
||||
}
|
||||
if (event.shiftKey && ignoredShiftKeys.some(function(i) { return i === event.keyCode; })) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
window.parent.postMessage({ which: event.which, keyCode: event.keyCode, charCode: event.charCode, metaKey: event.metaKey, altKey: event.altKey, shiftKey: event.shiftKey, ctrlKey: event.ctrlKey }, "*");
|
||||
} catch (error) { }
|
||||
});
|
||||
function defaultPreventHandler(e) { e.preventDefault(); };
|
||||
window.document.addEventListener("dragover", defaultPreventHandler);
|
||||
window.document.addEventListener("drop", defaultPreventHandler);
|
||||
window.document.body.addEventListener("dragover", defaultPreventHandler);
|
||||
window.document.body.addEventListener("drop", defaultPreventHandler);
|
||||
`;
|
||||
|
||||
// styles
|
||||
|
||||
const defaultLightScrollbarStyle = [
|
||||
'::-webkit-scrollbar-thumb {',
|
||||
' background-color: rgba(100, 100, 100, 0.4);',
|
||||
'}',
|
||||
'::-webkit-scrollbar-thumb:hover {',
|
||||
' background-color: rgba(100, 100, 100, 0.7);',
|
||||
'}',
|
||||
'::-webkit-scrollbar-thumb:active {',
|
||||
' background-color: rgba(0, 0, 0, 0.6);',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
const defaultDarkScrollbarStyle = [
|
||||
'::-webkit-scrollbar-thumb {',
|
||||
' background-color: rgba(121, 121, 121, 0.4);',
|
||||
'}',
|
||||
'::-webkit-scrollbar-thumb:hover {',
|
||||
' background-color: rgba(100, 100, 100, 0.7);',
|
||||
'}',
|
||||
'::-webkit-scrollbar-thumb:active {',
|
||||
' background-color: rgba(85, 85, 85, 0.8);',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
export function defaultStyle(element: HTMLElement, themeId: string): HTMLStyleElement {
|
||||
const styles = window.getComputedStyle(element);
|
||||
const styleElement = document.createElement('style');
|
||||
|
||||
styleElement.innerHTML = `* {
|
||||
color: ${styles.color};
|
||||
background: ${styles.background};
|
||||
font-family: ${styles.fontFamily};
|
||||
font-size: ${styles.fontSize};
|
||||
* {
|
||||
color: ${color};
|
||||
background-color: ${backgroundColor};
|
||||
font-family: ${fontFamily};
|
||||
font-size: ${fontSize};
|
||||
}
|
||||
img {
|
||||
max-width: 100%;
|
||||
@@ -311,12 +135,145 @@ namespace Integration {
|
||||
}
|
||||
::-webkit-scrollbar {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
height: 10px;
|
||||
}
|
||||
${isLightTheme(themeId)
|
||||
? defaultLightScrollbarStyle
|
||||
: defaultDarkScrollbarStyle}`;
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background-color: rgba(100, 100, 100, 0.7);
|
||||
}`;
|
||||
|
||||
return styleElement;
|
||||
if (isLightTheme(themeId)) {
|
||||
value += `
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(100, 100, 100, 0.4);
|
||||
}
|
||||
::-webkit-scrollbar-thumb:active {
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
}`;
|
||||
} else {
|
||||
value += `
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(121, 121, 121, 0.4);
|
||||
}
|
||||
::-webkit-scrollbar-thumb:active {
|
||||
background-color: rgba(85, 85, 85, 0.8);
|
||||
}`;
|
||||
}
|
||||
|
||||
this._send('styles', value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of editor for showing HTML content in an IFrame by leveraging the IFrameEditorInput.
|
||||
*/
|
||||
export class HtmlPreviewPart extends BaseEditor {
|
||||
|
||||
static ID: string = 'workbench.editor.htmlPreviewPart';
|
||||
|
||||
private _editorService: IWorkbenchEditorService;
|
||||
private _themeService: IThemeService;
|
||||
private _webview: ManagedWebview;
|
||||
private _container: HTMLDivElement;
|
||||
|
||||
private _baseUrl: URI;
|
||||
|
||||
private _model: IModel;
|
||||
private _modelChangeSubscription = EmptyDisposable;
|
||||
private _themeChangeSubscription = EmptyDisposable;
|
||||
|
||||
constructor(
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IWorkbenchEditorService editorService: IWorkbenchEditorService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService
|
||||
) {
|
||||
super(HtmlPreviewPart.ID, telemetryService);
|
||||
|
||||
this._editorService = editorService;
|
||||
this._themeService = themeService;
|
||||
this._baseUrl = contextService.toResource('/');
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
// remove from dom
|
||||
this._webview.dispose();
|
||||
|
||||
// unhook listeners
|
||||
this._themeChangeSubscription.dispose();
|
||||
this._modelChangeSubscription.dispose();
|
||||
this._model = undefined;
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public createEditor(parent: Builder): void {
|
||||
this._container = document.createElement('div');
|
||||
parent.getHTMLElement().appendChild(this._container);
|
||||
}
|
||||
|
||||
private get webview(): ManagedWebview {
|
||||
if (!this._webview) {
|
||||
this._webview = new ManagedWebview(document.getElementById('workbench.main.container'),
|
||||
this._container,
|
||||
document.querySelector('.monaco-editor-background'));
|
||||
|
||||
this._webview.baseUrl = this._baseUrl && this._baseUrl.toString();
|
||||
}
|
||||
return this._webview;
|
||||
}
|
||||
|
||||
public setVisible(visible: boolean, position?: Position): TPromise<void> {
|
||||
if (!visible) {
|
||||
this._themeChangeSubscription.dispose();
|
||||
this._modelChangeSubscription.dispose();
|
||||
this._webview.dispose();
|
||||
this._webview = undefined;
|
||||
} else {
|
||||
this._themeChangeSubscription = this._themeService.onDidThemeChange(themeId => this.webview.style(themeId));
|
||||
this.webview.style(this._themeService.getTheme());
|
||||
this.webview.layout();
|
||||
|
||||
if (this._model) {
|
||||
this._modelChangeSubscription = this._model.addListener2(EventType.ModelContentChanged2, () => this.webview.contents = this._model.getLinesContent());
|
||||
this.webview.contents = this._model.getLinesContent();
|
||||
}
|
||||
}
|
||||
return super.setVisible(visible, position);
|
||||
}
|
||||
|
||||
public layout(dimension: Dimension): void {
|
||||
const {width, height} = dimension;
|
||||
this._container.style.width = `${width}px`;
|
||||
this._container.style.height = `${height}px`;
|
||||
this.webview.layout();
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
this.webview.focus();
|
||||
}
|
||||
|
||||
public setInput(input: EditorInput, options: EditorOptions): TPromise<void> {
|
||||
|
||||
if (this.input === input) {
|
||||
return TPromise.as(undefined);
|
||||
}
|
||||
|
||||
this._model = undefined;
|
||||
this._modelChangeSubscription.dispose();
|
||||
|
||||
if (!(input instanceof HtmlInput)) {
|
||||
return TPromise.wrapError<void>('Invalid input');
|
||||
}
|
||||
|
||||
return this._editorService.resolveEditorModel({ resource: (<HtmlInput>input).getResource() }).then(model => {
|
||||
if (model instanceof BaseTextEditorModel) {
|
||||
this._model = model.textEditorModel;
|
||||
}
|
||||
if (!this._model) {
|
||||
return TPromise.wrapError<void>(localize('html.voidInput', "Invalid editor input."));
|
||||
}
|
||||
this._modelChangeSubscription = this._model.addListener2(EventType.ModelContentChanged2, () => this.webview.contents = this._model.getLinesContent());
|
||||
this.webview.contents = this._model.getLinesContent();
|
||||
return super.setInput(input, options);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Virtual Document</title>
|
||||
</head>
|
||||
<body style="margin: 0; overflow: hidden;">
|
||||
<iframe id="_target" frameborder="0"></iframe>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
const ipcRenderer = require('electron').ipcRenderer;
|
||||
const target = document.getElementById('_target');
|
||||
|
||||
let initData = {};
|
||||
|
||||
ipcRenderer.on('baseUrl', function(event, value) {
|
||||
initData.baseUrl = value;
|
||||
});
|
||||
|
||||
// forward layout calls
|
||||
ipcRenderer.on('layout', function(event, width, height) {
|
||||
document.body.style.width = target.style.width = width + 'px';
|
||||
document.body.style.height = target.style.height = height + 'px';
|
||||
});
|
||||
|
||||
ipcRenderer.on('styles', function(event, value) {
|
||||
initData.styles = value;
|
||||
const defaultStyles = target.contentDocument.getElementById('_defaultStyles');
|
||||
if(defaultStyles) {
|
||||
defaultStyles.innerHTML = value;
|
||||
}
|
||||
});
|
||||
|
||||
// propagate focus
|
||||
ipcRenderer.on('focus', function() {
|
||||
target.contentDocument.body.focus();
|
||||
});
|
||||
|
||||
// update iframe-contents
|
||||
ipcRenderer.on('content', function(event, value) {
|
||||
|
||||
const parser = new DOMParser();
|
||||
const newDocument = parser.parseFromString(value.join('\n'), 'text/html');
|
||||
|
||||
// set base-url if possible
|
||||
if(initData.baseUrl) {
|
||||
const baseElement = document.createElement('base');
|
||||
baseElement.href = initData.baseUrl;
|
||||
newDocument.head.appendChild(baseElement);
|
||||
}
|
||||
|
||||
// apply default styles
|
||||
const defaultStyles = newDocument.createElement('style');
|
||||
defaultStyles.id = '_defaultStyles';
|
||||
defaultStyles.innerHTML = initData.styles;
|
||||
if (newDocument.head.hasChildNodes()) {
|
||||
newDocument.head.insertBefore(defaultStyles, newDocument.head.firstChild);
|
||||
} else {
|
||||
newDocument.head.appendChild(defaultStyles);
|
||||
}
|
||||
|
||||
// write new content onto iframe
|
||||
target.contentDocument.open('text/html', 'replace');
|
||||
target.contentDocument.write(newDocument.documentElement.innerHTML);
|
||||
target.contentDocument.close();
|
||||
|
||||
});
|
||||
|
||||
// signal ready, needs a short timeout for an
|
||||
// unknown reason
|
||||
setTimeout(function() {
|
||||
ipcRenderer.sendToHost('webview-ready', process.pid);
|
||||
}, 10);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user