Allow hidden (but persisted) webviews to recieve messages

Fixes #47534
This commit is contained in:
Matt Bierner 2019-05-22 15:23:22 -07:00
parent 71deb5b6ee
commit c2b02df9ab
2 changed files with 61 additions and 43 deletions

View file

@ -132,24 +132,7 @@ suite('Webview tests', () => {
// Open webview in same column
const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true }));
const ready = getMesssage(webview);
webview.webview.html = createHtmlDocumentWithBody(/*html*/`
<script>
const vscode = acquireVsCodeApi();
let value = 0;
window.addEventListener('message', (message) => {
switch (message.data.type) {
case 'get':
vscode.postMessage({ value });
break;
case 'add':
++value;;
vscode.postMessage({ value });
break;
}
});
vscode.postMessage({ type: 'ready' });
</script>`);
webview.webview.html = statefulWebviewHtml;
await ready;
const firstResponse = await sendRecieveMessage(webview, { type: 'add' });
@ -167,25 +150,7 @@ suite('Webview tests', () => {
const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true, retainContextWhenHidden: true }));
const ready = getMesssage(webview);
webview.webview.html = createHtmlDocumentWithBody(/*html*/`
<script>
const vscode = acquireVsCodeApi();
let value = 0;
window.addEventListener('message', (message) => {
switch (message.data.type) {
case 'get':
vscode.postMessage({ value });
break;
case 'add':
++value;;
vscode.setState({ value });
vscode.postMessage({ value });
break;
}
});
vscode.postMessage({ type: 'ready' });
</script>`);
webview.webview.html = statefulWebviewHtml;
await ready;
const firstResponse = await sendRecieveMessage(webview, { type: 'add' });
@ -244,6 +209,33 @@ suite('Webview tests', () => {
assert.strictEqual(secondResponse.value, 100);
});
conditionalTest('webviews with retainContextWhenHidden should be able to recive messages while hidden', async () => {
const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true, retainContextWhenHidden: true }));
const ready = getMesssage(webview);
webview.webview.html = statefulWebviewHtml;
await ready;
const firstResponse = await sendRecieveMessage(webview, { type: 'add' });
assert.strictEqual((await firstResponse).value, 1);
// Swap away from the webview
const doc = await vscode.workspace.openTextDocument(testDocument);
await vscode.window.showTextDocument(doc);
// Try posting a message to our hidden webview
const secondResponse = await sendRecieveMessage(webview, { type: 'add' });
assert.strictEqual((await secondResponse).value, 2);
// Now show webview again
webview.reveal(vscode.ViewColumn.One);
// We should still have old state
const thirdResponse = await sendRecieveMessage(webview, { type: 'get' });
assert.strictEqual(thirdResponse.value, 2);
});
conditionalTest('webviews should only be able to load resources from workspace by default', async () => {
const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true }));
@ -356,6 +348,27 @@ function createHtmlDocumentWithBody(body: string): string {
</html>`;
}
const statefulWebviewHtml = createHtmlDocumentWithBody(/*html*/ `
<script>
const vscode = acquireVsCodeApi();
let value = 0;
window.addEventListener('message', (message) => {
switch (message.data.type) {
case 'get':
vscode.postMessage({ value });
break;
case 'add':
++value;;
vscode.setState({ value });
vscode.postMessage({ value });
break;
}
});
vscode.postMessage({ type: 'ready' });
</script>`);
function getMesssage<R = any>(webview: vscode.WebviewPanel): Promise<R> {
return new Promise<R>(resolve => {
const sub = webview.webview.onDidReceiveMessage(message => {

View file

@ -210,11 +210,10 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
}
}
public $postMessage(handle: WebviewPanelHandle | WebviewInsetHandle, message: any): Promise<boolean> {
public async $postMessage(handle: WebviewPanelHandle | WebviewInsetHandle, message: any): Promise<boolean> {
if (typeof handle === 'number') {
this.getWebviewElement(handle).sendMessage(message);
return Promise.resolve(true);
return true;
} else {
const webview = this.getWebview(handle);
const editors = this._editorService.visibleControls
@ -222,11 +221,17 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
.map(e => e as WebviewEditor)
.filter(e => e.input!.matches(webview));
for (const editor of editors) {
editor.sendMessage(message);
if (editors.length > 0) {
editors[0].sendMessage(message);
return true;
}
return Promise.resolve(editors.length > 0);
if (webview.webview) {
webview.webview.sendMessage(message);
return true;
}
return false;
}
}