Skip to content

Commit

Permalink
[webview] fix #5647: restore webviews
Browse files Browse the repository at this point in the history
Signed-off-by: Anton Kosyakov <anton.kosyakov@typefox.io>
  • Loading branch information
akosyakov committed Oct 29, 2019
1 parent 9601c73 commit 3f30d36
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 110 deletions.
93 changes: 74 additions & 19 deletions packages/plugin-ext/src/main/browser/webview/webview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,17 @@
********************************************************************************/

import { injectable, inject, postConstruct } from 'inversify';
import { WebviewOptions, WebviewPanelOptions } from '@theia/plugin';
import { BaseWidget, Message } from '@theia/core/lib/browser/widgets/widget';
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
// TODO: get rid of dependencies to the mini browser
import { MiniBrowserContentStyle } from '@theia/mini-browser/lib/browser/mini-browser-content-style';
import { ApplicationShellMouseTracker } from '@theia/core/lib/browser/shell/application-shell-mouse-tracker';
import { StatefulWidget } from '@theia/core/lib/browser/shell/shell-layout-restorer';
import { WebviewPanelViewState } from '../../../common/plugin-api-rpc';

// tslint:disable:no-any

export interface WebviewWidgetOptions {
readonly allowScripts?: boolean;
}

export interface WebviewEvents {
onMessage?(message: any): void;
onKeyboardEvent?(e: KeyboardEvent): void;
Expand All @@ -39,12 +38,11 @@ export class WebviewWidgetIdentifier {
}

@injectable()
export class WebviewWidget extends BaseWidget {
export class WebviewWidget extends BaseWidget implements StatefulWidget {

static FACTORY_ID = 'plugin-webview';

private iframe: HTMLIFrameElement;
private state: { [key: string]: any } | undefined = undefined;
private loadTimeout: number | undefined;
private scrollY: number;
private readyToReceiveMessage: boolean = false;
Expand All @@ -53,12 +51,24 @@ export class WebviewWidget extends BaseWidget {
protected readonly transparentOverlay: HTMLElement;

@inject(WebviewWidgetIdentifier)
protected readonly identifier: WebviewWidgetIdentifier;
readonly identifier: WebviewWidgetIdentifier;

@inject(ApplicationShellMouseTracker)
protected readonly mouseTracker: ApplicationShellMouseTracker;

private options: WebviewWidgetOptions = {};
viewState: WebviewPanelViewState = {
visible: false,
active: false,
position: 0
};

viewType: string;
state: { [key: string]: any } | undefined = undefined;

options: WebviewPanelOptions = {};

private contentOptions: WebviewOptions = {};

eventDelegate: WebviewEvents = {};

constructor() {
Expand Down Expand Up @@ -97,6 +107,7 @@ export class WebviewWidget extends BaseWidget {
break;
case 'do-update-state':
this.state = message.data;
// TODO: review other messages in VS Code for missing functionality in Theia
}
}

Expand All @@ -106,15 +117,15 @@ export class WebviewWidget extends BaseWidget {
this.iframe.contentWindow!.postMessage(message, '*');
}

setOptions(options: WebviewWidgetOptions): void {
if (this.options.allowScripts === options.allowScripts) {
setContentOptions(contentOptions: WebviewOptions): void {
if (WebviewWidget.areWebviewOptionsEqual(this.contentOptions, contentOptions)) {
return;
}
this.options = options;
this.contentOptions = contentOptions;
if (!this.iframe) {
return;
}
this.updateSandboxAttribute(this.iframe, options.allowScripts);
this.updateSandboxAttribute(this.iframe);
this.reloadFrame();
}

Expand Down Expand Up @@ -235,19 +246,19 @@ export class WebviewWidget extends BaseWidget {
this.setHTML(this.iframe.contentDocument.documentElement.innerHTML);
}

private updateSandboxAttribute(element: HTMLElement, isAllowScript?: boolean): void {
private updateSandboxAttribute(element: HTMLElement): void {
if (!element) {
return;
}
const allowScripts = isAllowScript !== undefined ? isAllowScript : this.options.allowScripts;
const allowScripts = !!this.contentOptions.enableScripts;
element.setAttribute('sandbox', allowScripts ? 'allow-scripts allow-forms allow-same-origin' : 'allow-same-origin');
}

private updateApiScript(contentDocument: Document, isAllowScript?: boolean): void {
private updateApiScript(contentDocument: Document): void {
if (!contentDocument) {
return;
}
const allowScripts = isAllowScript !== undefined ? isAllowScript : this.options.allowScripts;
const allowScripts = !!this.contentOptions.enableScripts;
const scriptId = 'webview-widget-codeApi';
if (!allowScripts) {
const script = contentDocument.getElementById(scriptId);
Expand Down Expand Up @@ -339,12 +350,56 @@ export class WebviewWidget extends BaseWidget {
this.waitReceiveMessage(this, resolve);
});
}
}

storeState(): WebviewWidget.State {
return {
viewType: this.viewType,
title: this.title.label,
options: this.options,
contentOptions: this.contentOptions,
state: this.state
};
}

restoreState(oldState: WebviewWidget.State): void {
const { viewType, title, options, contentOptions, state } = oldState;
this.viewType = viewType;
this.title.label = title;
this.options = options;
this.contentOptions = contentOptions;
this.state = state;
}

}
export namespace WebviewWidget {
export namespace Styles {

export const WEBVIEW = 'theia-webview';

}
export interface State {
viewType: string
title: string
options: WebviewPanelOptions
// TODO serialize/revive URIs
contentOptions: WebviewOptions
state: any
// TODO: preserve icon class
}
export function areWebviewOptionsEqual(a: WebviewOptions, b: WebviewOptions): boolean {
if (a.enableCommandUris !== b.enableCommandUris) {
return false;
}
if (a.enableScripts !== b.enableScripts) {
return false;
}
if (a.localResourceRoots === b.localResourceRoots) {
return true;
}
if (!a.localResourceRoots || !b.localResourceRoots) {
return false;
}
if (a.localResourceRoots.length !== b.localResourceRoots.length) {
return false;
}
return a.localResourceRoots.every((uri, index) => uri.toString() === b.localResourceRoots![index].toString());
}
}
Loading

0 comments on commit 3f30d36

Please sign in to comment.