@opensumi/ide-webview 2.21.13 → 2.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/lib/browser/abstract-webview.js +3 -3
  2. package/lib/browser/abstract-webview.js.map +1 -1
  3. package/lib/browser/contribution.js.map +1 -1
  4. package/lib/browser/electron-webview-webview.js.map +1 -1
  5. package/lib/browser/iframe-webview.js.map +1 -1
  6. package/lib/browser/index.js.map +1 -1
  7. package/lib/browser/plain-webview.js +3 -3
  8. package/lib/browser/plain-webview.js.map +1 -1
  9. package/lib/browser/webview-window.js.map +1 -1
  10. package/lib/browser/webview.service.d.ts +1 -1
  11. package/lib/browser/webview.service.d.ts.map +1 -1
  12. package/lib/browser/webview.service.js +38 -38
  13. package/lib/browser/webview.service.js.map +1 -1
  14. package/lib/electron-main/index.js.map +1 -1
  15. package/package.json +13 -12
  16. package/src/browser/abstract-webview.ts +231 -0
  17. package/src/browser/contribution.ts +80 -0
  18. package/src/browser/editor-webview.tsx +207 -0
  19. package/src/browser/electron-webview-webview.ts +156 -0
  20. package/src/browser/iframe-webview.ts +140 -0
  21. package/src/browser/index.ts +19 -0
  22. package/src/browser/plain-webview.ts +284 -0
  23. package/src/browser/types.ts +274 -0
  24. package/src/browser/webview-window.ts +130 -0
  25. package/src/browser/webview.service.ts +484 -0
  26. package/src/common/index.ts +1 -0
  27. package/src/electron-main/index.ts +31 -0
  28. package/src/electron-webview/host-channel.ts +64 -0
  29. package/src/electron-webview/host-preload.js +2 -0
  30. package/src/electron-webview/plain-preload.js +55 -0
  31. package/src/index.ts +1 -0
  32. package/src/webview-host/common.ts +108 -0
  33. package/src/webview-host/web-preload.ts +78 -0
  34. package/src/webview-host/webview-manager.ts +368 -0
  35. package/src/webview-host/webview.html +11 -0
@@ -0,0 +1,231 @@
1
+ import { Autowired, Injectable } from '@opensumi/di';
2
+ import {
3
+ Event,
4
+ URI,
5
+ Disposable,
6
+ IDisposable,
7
+ Emitter,
8
+ IEventBus,
9
+ MaybeNull,
10
+ AppConfig,
11
+ } from '@opensumi/ide-core-browser';
12
+ import { StaticResourceService } from '@opensumi/ide-static-resource/lib/browser';
13
+ import { ITheme, IThemeService } from '@opensumi/ide-theme';
14
+ import { ThemeChangedEvent } from '@opensumi/ide-theme/lib/common/event';
15
+
16
+ import { IWebview, IWebviewContentOptions, IWebviewContentScrollPosition, IWebviewService } from './types';
17
+
18
+ @Injectable({ multiple: true })
19
+ export abstract class AbstractWebviewPanel extends Disposable implements IWebview {
20
+ protected _html = '';
21
+
22
+ protected _options: IWebviewContentOptions;
23
+
24
+ initialScrollProgress: number;
25
+
26
+ state: any;
27
+
28
+ _onDidFocus: Emitter<void> = new Emitter<void>();
29
+ onDidFocus: Event<void> = this._onDidFocus.event;
30
+
31
+ _onDidBlur: Emitter<void> = new Emitter<void>();
32
+ onDidBlur: Event<void> = this._onDidFocus.event;
33
+
34
+ _onDidClickLink: Emitter<URI> = new Emitter<URI>();
35
+ onDidClickLink: Event<URI> = this._onDidClickLink.event;
36
+
37
+ _onDidScroll: Emitter<IWebviewContentScrollPosition> = new Emitter<IWebviewContentScrollPosition>();
38
+ onDidScroll: Event<IWebviewContentScrollPosition> = this._onDidScroll.event;
39
+
40
+ _onDidUpdateState: Emitter<any> = new Emitter<any>();
41
+ onDidUpdateState: Event<any> = this._onDidUpdateState.event;
42
+
43
+ _onRemove: Emitter<void> = new Emitter<void>();
44
+ onRemove: Event<void> = this._onRemove.event;
45
+
46
+ protected _isListening = true;
47
+
48
+ private _focused = false;
49
+
50
+ protected _ready: Promise<void>;
51
+
52
+ @Autowired(IWebviewService)
53
+ webviewService: IWebviewService;
54
+
55
+ @Autowired(IThemeService)
56
+ themeService: IThemeService;
57
+
58
+ @Autowired(IEventBus)
59
+ eventBus: IEventBus;
60
+
61
+ @Autowired(AppConfig)
62
+ private readonly appConfig: AppConfig;
63
+
64
+ @Autowired(StaticResourceService)
65
+ staticResourceService: StaticResourceService;
66
+
67
+ protected _keybindingDomTarget: HTMLElement | undefined = undefined;
68
+
69
+ public setKeybindingDomTarget(target) {
70
+ this._keybindingDomTarget = target;
71
+ }
72
+
73
+ constructor(public readonly id: string, options: IWebviewContentOptions = {}) {
74
+ super();
75
+ this._options = options;
76
+ }
77
+
78
+ init() {
79
+ this.prepareContainer();
80
+
81
+ this.initEvents();
82
+ }
83
+
84
+ async postMessage(message: any): Promise<void> {
85
+ return this._sendToWebview('message', message);
86
+ }
87
+
88
+ public get options() {
89
+ return this._options;
90
+ }
91
+
92
+ onMessage(listener: (message: any) => any): IDisposable {
93
+ return this._onWebviewMessage('onmessage', listener);
94
+ }
95
+
96
+ protected initEvents() {
97
+ this._onWebviewMessage('did-click-link', (data) => {
98
+ this._onDidClickLink.fire(new URI(data));
99
+ });
100
+
101
+ this._onWebviewMessage('did-scroll', (data) => {
102
+ this._onDidScroll.fire(data);
103
+ });
104
+
105
+ this._onWebviewMessage('do-reload', () => {
106
+ this.doUpdateContent();
107
+ });
108
+
109
+ this._onWebviewMessage('load-resource', () => {
110
+ // TODO: 资源相关
111
+ });
112
+
113
+ this._onWebviewMessage('load-localhost', () => {
114
+ // TODO: 好像是消息转发
115
+ });
116
+
117
+ this._onWebviewMessage('did-focus', () => {
118
+ this.handleFocusChange(true);
119
+ });
120
+
121
+ this._onWebviewMessage('did-blur', () => {
122
+ this.handleFocusChange(false);
123
+ });
124
+
125
+ this._onWebviewMessage('do-update-state', (state) => {
126
+ this.state = state;
127
+ this._onDidUpdateState.fire(state);
128
+ });
129
+
130
+ this._onWebviewMessage('did-keydown', (event) => {
131
+ // Create a fake KeyboardEvent from the data provided
132
+ const emulatedKeyboardEvent = new KeyboardEvent('keydown', event);
133
+ // Force override the target
134
+ Object.defineProperty(emulatedKeyboardEvent, 'target', {
135
+ get: () => this._keybindingDomTarget || this.getDomNode(),
136
+ });
137
+ // And re-dispatch
138
+ window.dispatchEvent(emulatedKeyboardEvent);
139
+ });
140
+
141
+ this.updateStyle();
142
+ }
143
+
144
+ protected updateStyle() {
145
+ this.style(this.themeService.getCurrentThemeSync());
146
+ this.addDispose(
147
+ this.eventBus.on(ThemeChangedEvent, (e) => {
148
+ this.style(e.payload.theme);
149
+ }),
150
+ );
151
+ }
152
+
153
+ getContent(): string {
154
+ return this._html;
155
+ }
156
+
157
+ async setContent(html: string): Promise<void> {
158
+ this._html = html;
159
+ await this.doUpdateContent();
160
+ }
161
+
162
+ protected preprocessHtml(html: string): string {
163
+ if (this.appConfig.isElectronRenderer) {
164
+ // 将vscode-resource:/User/xxx 转换为 vscode-resource:///User/xxx
165
+ return html.replace(
166
+ /(["'])vscode-resource:(\/\/|)([^\s'"]+?)(["'])/gi,
167
+ (_, startQuote, slash, path, endQuote) => `${startQuote}vscode-resource://${path}${endQuote}`,
168
+ );
169
+ }
170
+ return html.replace(
171
+ /(["'])vscode-resource:([^\s'"]+?)(["'])/gi,
172
+ (_, startQuote, path, endQuote) =>
173
+ `${startQuote}${this.staticResourceService.resolveStaticResource(URI.file(path))}${endQuote}`,
174
+ );
175
+ }
176
+
177
+ protected doUpdateContent() {
178
+ return this._sendToWebview('content', {
179
+ contents: this.preprocessHtml(this._html),
180
+ options: this._options,
181
+ state: this.state,
182
+ });
183
+ }
184
+
185
+ public abstract appendTo(container: HTMLElement);
186
+
187
+ protected abstract _sendToWebview(channel: string, data: any);
188
+
189
+ protected abstract _onWebviewMessage(channel: string, listener: (data: any) => any): IDisposable;
190
+
191
+ updateOptions(options: IWebviewContentOptions): void {
192
+ this._options = Object.assign(this._options, options);
193
+ this.doUpdateContent();
194
+ }
195
+
196
+ layout(): void {
197
+ throw new Error('Method not implemented.');
198
+ }
199
+
200
+ focus(): void {
201
+ throw new Error('Method not implemented.');
202
+ }
203
+
204
+ reload(): void {
205
+ throw new Error('Method not implemented.');
206
+ }
207
+
208
+ protected handleFocusChange(isFocused: boolean): void {
209
+ this._focused = isFocused;
210
+ if (this._focused) {
211
+ this._onDidFocus.fire();
212
+ } else {
213
+ this._onDidBlur.fire();
214
+ }
215
+ }
216
+
217
+ private style(theme: ITheme): void {
218
+ const { styles, activeTheme } = this.webviewService.getWebviewThemeData(theme);
219
+ this._sendToWebview('styles', { styles, activeTheme });
220
+ }
221
+
222
+ setListenMessages(listening: boolean): void {
223
+ this._isListening = listening;
224
+ }
225
+
226
+ abstract prepareContainer(): any;
227
+
228
+ abstract getDomNode(): MaybeNull<HTMLElement>;
229
+
230
+ abstract remove(): void;
231
+ }
@@ -0,0 +1,80 @@
1
+ /* istanbul ignore file */
2
+ import { Autowired } from '@opensumi/di';
3
+ import { Domain, URI, CommandContribution, CommandRegistry, AppConfig } from '@opensumi/ide-core-browser';
4
+ import { localize } from '@opensumi/ide-core-common';
5
+ import { ResourceService, IResource } from '@opensumi/ide-editor';
6
+ import { BrowserEditorContribution, EditorComponentRegistry } from '@opensumi/ide-editor/lib/browser';
7
+
8
+ import { EDITOR_WEBVIEW_SCHEME, IWebviewService, IEditorWebviewMetaData, isWebview } from './types';
9
+ import { WebviewServiceImpl } from './webview.service';
10
+
11
+ const WEBVIEW_DEVTOOLS_COMMAND = {
12
+ id: 'workbench.action.webview.openDeveloperTools',
13
+ label: localize('openToolsLabel', 'Open Webview Developer Tools'),
14
+ };
15
+
16
+ @Domain(BrowserEditorContribution, CommandContribution)
17
+ export class WebviewModuleContribution implements BrowserEditorContribution, CommandContribution {
18
+ @Autowired(IWebviewService)
19
+ webviewService: WebviewServiceImpl;
20
+
21
+ @Autowired(EditorComponentRegistry)
22
+ editorComponentRegistry: EditorComponentRegistry;
23
+
24
+ @Autowired(AppConfig)
25
+ private readonly appConfig: AppConfig;
26
+
27
+ registerResource(resourceService: ResourceService) {
28
+ resourceService.registerResourceProvider({
29
+ scheme: EDITOR_WEBVIEW_SCHEME,
30
+ provideResource: async (uri: URI): Promise<IResource<IEditorWebviewMetaData>> => {
31
+ const existingComponent = this.webviewService.editorWebviewComponents.get(uri.path.toString());
32
+ if (existingComponent) {
33
+ return existingComponent.resource;
34
+ } else {
35
+ // try revive, 如果无法恢复,会抛错
36
+ await this.webviewService.tryRestoredWebviewComponent(uri.path.toString());
37
+ return this.webviewService.editorWebviewComponents.get(uri.path.toString())!.resource;
38
+ }
39
+ },
40
+ shouldCloseResource: (resource: IResource<IEditorWebviewMetaData>, openedResources: IResource[][]) => {
41
+ let count = 0;
42
+ for (const resources of openedResources) {
43
+ for (const r of resources) {
44
+ if (r.uri.scheme === EDITOR_WEBVIEW_SCHEME && r.uri.toString() === resource.uri.toString()) {
45
+ count++;
46
+ }
47
+ if (count > 1) {
48
+ return true;
49
+ }
50
+ }
51
+ }
52
+ const component = this.webviewService.editorWebviewComponents.get(resource.uri.path.toString());
53
+ if (component?.webview && isWebview(component.webview)) {
54
+ // 只对类 vscode webview 进行 dispose,
55
+ // loadUrl 的 plainWebview 必须手动 dispose
56
+ this.webviewService.editorWebviewComponents.get(resource.uri.path.toString())!.clear();
57
+ }
58
+
59
+ return true;
60
+ },
61
+ });
62
+ }
63
+
64
+ registerCommands(commandRegistry: CommandRegistry) {
65
+ commandRegistry.registerCommand(WEBVIEW_DEVTOOLS_COMMAND, {
66
+ execute: () => {
67
+ const elements = document.querySelectorAll<Electron.WebviewTag>('webview');
68
+ // eslint-disable-next-line @typescript-eslint/prefer-for-of
69
+ for (let i = 0; i < elements.length; i += 1) {
70
+ try {
71
+ elements[i].openDevTools();
72
+ } catch (e) {
73
+ // noop
74
+ }
75
+ }
76
+ },
77
+ isEnabled: () => this.appConfig.isElectronRenderer,
78
+ });
79
+ }
80
+ }
@@ -0,0 +1,207 @@
1
+ import React from 'react';
2
+
3
+ import { Disposable, DomListener, useInjectable } from '@opensumi/ide-core-browser';
4
+ import { ReactEditorComponent } from '@opensumi/ide-editor/lib/browser';
5
+
6
+ import { IWebview, IPlainWebview, IEditorWebviewMetaData, IWebviewService, isWebview } from './types';
7
+ import { WebviewServiceImpl } from './webview.service';
8
+
9
+ declare const ResizeObserver: any;
10
+ declare const MutationObserver: any;
11
+
12
+ export const EditorWebviewComponentView: ReactEditorComponent<IEditorWebviewMetaData> = ({ resource }) => {
13
+ const webviewService = useInjectable(IWebviewService) as WebviewServiceImpl;
14
+ const webview = webviewService.editorWebviewComponents.get(resource.metadata!.id)?.webview;
15
+ let container: HTMLDivElement | null = null;
16
+
17
+ React.useEffect(() => {
18
+ if (webview && container) {
19
+ const mounter = new WebviewMounter(
20
+ webview,
21
+ container,
22
+ document.getElementById('workbench-editor')!,
23
+ document.getElementById('workbench-editor')!,
24
+ );
25
+ webview.onRemove(() => {
26
+ mounter.dispose();
27
+ });
28
+ return () => {
29
+ webview.remove();
30
+ };
31
+ }
32
+ });
33
+
34
+ return (
35
+ <div
36
+ style={{ height: '100%', width: '100%', position: 'relative' }}
37
+ className='editor-webview-webview-component'
38
+ ref={(el) => (container = el)}
39
+ ></div>
40
+ );
41
+ };
42
+
43
+ /**
44
+ * 同一个ID创建的webview会保存在内存以便重复使用,不要使用这个组件进行大量不同webview的创建
45
+ */
46
+ export const PlainWebview: React.ComponentType<{ id: string; renderRoot?: HTMLElement; appendToChild?: boolean }> = ({
47
+ id,
48
+ renderRoot = document.body,
49
+ appendToChild,
50
+ }) => {
51
+ let container: HTMLDivElement | null = null;
52
+ const webviewService = useInjectable(IWebviewService) as IWebviewService;
53
+
54
+ React.useEffect(() => {
55
+ const component = webviewService.getOrCreatePlainWebviewComponent(id);
56
+ if (component && container) {
57
+ if (appendToChild) {
58
+ component.webview.appendTo(container);
59
+ } else {
60
+ const mounter = new WebviewMounter(
61
+ component.webview,
62
+ container,
63
+ document.getElementById('workbench-editor')!,
64
+ renderRoot,
65
+ );
66
+ component.webview.onRemove(() => {
67
+ mounter.dispose();
68
+ });
69
+ }
70
+
71
+ return () => {
72
+ component.webview.remove();
73
+ };
74
+ }
75
+ }, []);
76
+
77
+ return <div style={{ height: '100%', width: '100%', position: 'relative' }} ref={(el) => (container = el)}></div>;
78
+ };
79
+
80
+ // 将iframe挂载在一个固定的位置,以overlay的形式覆盖在container中,
81
+ // 防止它在DOM树改变时被重载
82
+ export class WebviewMounter extends Disposable {
83
+ private mounting: number;
84
+
85
+ private _container: HTMLElement | null;
86
+
87
+ constructor(
88
+ private webview: IWebview | IPlainWebview,
89
+ private container: HTMLElement,
90
+ mutationRoot: HTMLElement,
91
+ private renderRoot: HTMLElement = document.body,
92
+ ) {
93
+ super();
94
+ if (!this.webview.getDomNode()) {
95
+ return;
96
+ }
97
+ this.webview.appendTo(this.getWebviewRealContainer());
98
+ if (isWebview(this.webview)) {
99
+ this.webview.setKeybindingDomTarget(container);
100
+ }
101
+ const resizeObserver = new ResizeObserver(this.doMount.bind(this));
102
+ const mutationObserver = new MutationObserver((mutations) => {
103
+ const ancestors: Set<HTMLElement> = new Set();
104
+ let ancestor: HTMLElement | null = this.container;
105
+ while (ancestor && ancestor !== mutationRoot) {
106
+ ancestors.add(ancestor);
107
+ ancestor = ancestor.parentElement;
108
+ }
109
+ for (const { addedNodes, removedNodes } of mutations) {
110
+ for (const node of addedNodes) {
111
+ if (ancestors.has(node)) {
112
+ this.doMount();
113
+ return;
114
+ }
115
+ }
116
+ for (const node of removedNodes) {
117
+ if (ancestors.has(node)) {
118
+ this.doMount();
119
+ return;
120
+ }
121
+ }
122
+ }
123
+ });
124
+ resizeObserver.observe(container);
125
+ mutationObserver.observe(mutationRoot, { childList: true, subtree: true });
126
+
127
+ this.doMount();
128
+
129
+ this.addDispose({
130
+ dispose: () => {
131
+ if (this._container) {
132
+ this._container.remove();
133
+ this._container = null;
134
+ this.webview = null as any;
135
+ this.container = null as any;
136
+ }
137
+ resizeObserver.disconnect();
138
+ mutationObserver.disconnect();
139
+ },
140
+ });
141
+
142
+ this.addDispose(
143
+ new DomListener(window, 'resize', () => {
144
+ this.doMount();
145
+ }),
146
+ );
147
+
148
+ // 监听滚动
149
+ let parent = container.parentElement;
150
+ while (parent) {
151
+ this.addDispose(
152
+ new DomListener(parent, 'scroll', () => {
153
+ this.doMount();
154
+ }),
155
+ );
156
+ parent = parent.parentElement;
157
+ }
158
+ }
159
+
160
+ doMount() {
161
+ if (this.mounting) {
162
+ window.cancelAnimationFrame(this.mounting);
163
+ }
164
+ this.mounting = window.requestAnimationFrame(() => {
165
+ if (!this.webview.getDomNode()) {
166
+ return;
167
+ }
168
+ const rect = this.container.getBoundingClientRect();
169
+ if (rect.height === 0 || rect.width === 0) {
170
+ this.webview.getDomNode()!.style.display = 'none';
171
+ if (isWebview(this.webview) && !this.webview.options.longLive) {
172
+ this.webview.setListenMessages(false);
173
+ }
174
+ } else {
175
+ this.webview.getDomNode()!.style.display = '';
176
+ if (isWebview(this.webview)) {
177
+ this.webview.setListenMessages(true);
178
+ }
179
+ }
180
+ const renderRootRects = this.renderRoot.getBoundingClientRect();
181
+ this.webview.getDomNode()!.style.top = rect.top - renderRootRects.top + 'px';
182
+ this.webview.getDomNode()!.style.left = rect.left - renderRootRects.left + 'px';
183
+ this.webview.getDomNode()!.style.height = rect.height + 'px';
184
+ this.webview.getDomNode()!.style.width = rect.width + 'px';
185
+ this.mounting = 0;
186
+ });
187
+ }
188
+
189
+ getWebviewRealContainer() {
190
+ if (this._container) {
191
+ return this._container;
192
+ }
193
+ let mountContainer = this.renderRoot.querySelector(':scope > div[data-webview-container=true]');
194
+ if (!mountContainer) {
195
+ const container = document.createElement('div');
196
+ container.style.zIndex = '2';
197
+ container.style.position = 'absolute';
198
+ container.setAttribute('data-webview-container', 'true');
199
+ container.style.top = '0';
200
+ this.renderRoot.appendChild(container);
201
+ mountContainer = container;
202
+ }
203
+ this._container = document.createElement('div');
204
+ mountContainer!.appendChild(this._container);
205
+ return this._container!;
206
+ }
207
+ }
@@ -0,0 +1,156 @@
1
+ import { Injectable, Autowired } from '@opensumi/di';
2
+ import {
3
+ Disposable,
4
+ DomListener,
5
+ getDebugLogger,
6
+ IDisposable,
7
+ AppConfig,
8
+ electronEnv,
9
+ } from '@opensumi/ide-core-browser';
10
+
11
+ import { WebviewScheme } from '../common';
12
+
13
+ import { AbstractWebviewPanel } from './abstract-webview';
14
+ import { IWebview, IWebviewContentOptions } from './types';
15
+
16
+ @Injectable({ multiple: true })
17
+ export class ElectronWebviewWebviewPanel extends AbstractWebviewPanel implements IWebview {
18
+ private webview: Electron.WebviewTag;
19
+
20
+ private _needReload = false;
21
+
22
+ private _iframeDisposer: Disposable | null = new Disposable();
23
+
24
+ private _isReady: boolean;
25
+
26
+ @Autowired(AppConfig)
27
+ config: AppConfig;
28
+
29
+ constructor(public readonly id: string, options: IWebviewContentOptions = {}) {
30
+ super(id, options);
31
+
32
+ this.webview = document.createElement('webview');
33
+ this.webview.src = `${WebviewScheme}://index.html`;
34
+ this.webview.preload = electronEnv.webviewPreload;
35
+ this.webview.style.border = 'none';
36
+ this.webview.style.width = '100%';
37
+ this.webview.style.position = 'absolute';
38
+ this.webview.style.height = '100%';
39
+ this.webview.style.zIndex = '2';
40
+ super.init();
41
+ }
42
+
43
+ prepareContainer() {
44
+ this.clear();
45
+ this._iframeDisposer = new Disposable();
46
+ this._ready = new Promise<void>((resolve) => {
47
+ // tslint:disable-next-line: no-unused-variable
48
+ const disposer = this._onWebviewMessage('webview-ready', () => {
49
+ if (this._isReady) {
50
+ // 这种情况一般是由于iframe在dom中的位置变动导致了重载。
51
+ // 此时我们需要重新初始化
52
+ // electronWebview不需要重新监听事件
53
+ this.updateStyle();
54
+ this.doUpdateContent();
55
+ }
56
+ this._isReady = true;
57
+ resolve();
58
+ });
59
+ });
60
+ this._needReload = false;
61
+ }
62
+
63
+ getDomNode() {
64
+ return this.webview;
65
+ }
66
+
67
+ protected _sendToWebview(channel: string, data: any) {
68
+ if (!this._isListening) {
69
+ return;
70
+ }
71
+ this._ready
72
+ .then(() => {
73
+ if (!this.webview) {
74
+ return;
75
+ }
76
+ this.webview.send(channel, data);
77
+ })
78
+ .catch((err) => {
79
+ getDebugLogger().error(err);
80
+ });
81
+ }
82
+
83
+ protected _onWebviewMessage(channel: string, listener: (data: any) => any): IDisposable {
84
+ return this._iframeDisposer!.addDispose(
85
+ new DomListener(this.webview, 'ipc-message', (e) => {
86
+ if (!this.webview) {
87
+ return;
88
+ }
89
+ if (e.channel === channel) {
90
+ if (!this._isListening) {
91
+ return;
92
+ }
93
+ listener(e.args[0]);
94
+ }
95
+ }),
96
+ );
97
+ }
98
+
99
+ appendTo(container: HTMLElement) {
100
+ if (this.webview) {
101
+ if (container.style.position === 'static' || !container.style.position) {
102
+ container.style.position = 'relative';
103
+ }
104
+ container.innerHTML = '';
105
+ container.appendChild(this.webview);
106
+ if (this._needReload) {
107
+ this.init();
108
+ this.doUpdateContent();
109
+ }
110
+ }
111
+ }
112
+
113
+ remove() {
114
+ if (this.webview) {
115
+ this.webview.remove();
116
+ this._onRemove.fire();
117
+ // remove 只是视图被销毁,但是html,state等内容保留,因此这里之前是改坏了
118
+ // this.dispose();
119
+ this.clear();
120
+ this._needReload = true;
121
+ }
122
+ }
123
+
124
+ clear() {
125
+ if (this._iframeDisposer) {
126
+ this._iframeDisposer.dispose();
127
+ this._iframeDisposer = null;
128
+ }
129
+ this._isReady = false;
130
+ }
131
+
132
+ dispose() {
133
+ super.dispose();
134
+ if (this._iframeDisposer) {
135
+ this._iframeDisposer.dispose();
136
+ }
137
+ }
138
+ }
139
+ // tslint:disable-next-line: no-unused-variable
140
+ const WebviewHTMLStr = `<!DOCTYPE html>
141
+ <html lang="en" style="width: 100%; height: 100%;">
142
+
143
+ <head>
144
+ <meta charset="UTF-8">
145
+ <meta http-equiv="Content-Security-Policy"
146
+ content="default-src 'self'; script-src 'self'; frame-src 'self'; style-src 'unsafe-inline'; worker-src 'self'; img-src * data: ; " />
147
+
148
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
149
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
150
+ <title>Webview Panel Container</title>
151
+ </head>
152
+
153
+ <body style="margin: 0; overflow: hidden; width: 100%; height: 100%">
154
+ </body>
155
+
156
+ </html>`;