Browse Source

Resets context keys when closing or hiding

main
Eric Amodio 2 years ago
parent
commit
307c7b6082
2 changed files with 70 additions and 21 deletions
  1. +25
    -11
      src/webviews/webviewBase.ts
  2. +45
    -10
      src/webviews/webviewViewBase.ts

+ 25
- 11
src/webviews/webviewBase.ts View File

@ -164,10 +164,18 @@ export abstract class WebviewBase implements Disposable {
this._panel.webview.html = html; this._panel.webview.html = html;
} }
private resetContextKeys() {
void setContext(`${this.contextKeyPrefix}:active`, false);
void setContext(`${this.contextKeyPrefix}:focus`, false);
void setContext(`${this.contextKeyPrefix}:inputFocus`, false);
}
private onPanelDisposed() { private onPanelDisposed() {
this.onVisibilityChanged?.(false);
this.resetContextKeys();
this.onActiveChanged?.(false); this.onActiveChanged?.(false);
this.onFocusChanged?.(false); this.onFocusChanged?.(false);
this.onVisibilityChanged?.(false);
this.isReady = false; this.isReady = false;
this._disposablePanel?.dispose(); this._disposablePanel?.dispose();
@ -193,20 +201,26 @@ export abstract class WebviewBase implements Disposable {
}) })
protected onViewStateChanged(e: WebviewPanelOnDidChangeViewStateEvent): void { protected onViewStateChanged(e: WebviewPanelOnDidChangeViewStateEvent): void {
const { active, visible } = e.webviewPanel; const { active, visible } = e.webviewPanel;
// If we are becoming active, delay it a bit to give the UI time to update
if (active) {
setTimeout(() => void setContext(`${this.contextKeyPrefix}:active`, active), 250);
if (visible) {
// If we are becoming active, delay it a bit to give the UI time to update
if (active) {
setTimeout(() => void setContext(`${this.contextKeyPrefix}:active`, active), 250);
} else {
void setContext(`${this.contextKeyPrefix}:active`, active);
}
this.onActiveChanged?.(active);
if (!active) {
this.onFocusChanged?.(false);
}
} else { } else {
void setContext(`${this.contextKeyPrefix}:active`, active);
this.resetContextKeys();
this.onActiveChanged?.(false);
this.onFocusChanged?.(false);
} }
this.onVisibilityChanged?.(visible); this.onVisibilityChanged?.(visible);
this.onActiveChanged?.(active);
if (!active) {
this.onFocusChanged?.(active);
}
} }
@debug<WebviewBase<State>['onMessageReceivedCore']>({ @debug<WebviewBase<State>['onMessageReceivedCore']>({

+ 45
- 10
src/webviews/webviewViewBase.ts View File

@ -122,7 +122,7 @@ export abstract class WebviewViewBase implements
this._disposableView = Disposable.from( this._disposableView = Disposable.from(
this._view.onDidDispose(this.onViewDisposed, this), this._view.onDidDispose(this.onViewDisposed, this),
this._view.onDidChangeVisibility(this.onViewVisibilityChanged, this),
this._view.onDidChangeVisibility(() => this.onViewVisibilityChanged(this.visible), this),
this._view.webview.onDidReceiveMessage(this.onMessageReceivedCore, this), this._view.webview.onDidReceiveMessage(this.onMessageReceivedCore, this),
window.onDidChangeWindowState(this.onWindowStateChanged, this), window.onDidChangeWindowState(this.onWindowStateChanged, this),
...(this.onInitializing?.() ?? []), ...(this.onInitializing?.() ?? []),
@ -134,13 +134,38 @@ export abstract class WebviewViewBase implements
} }
@debug() @debug()
protected async refresh(): Promise<void> {
protected async refresh(force?: boolean): Promise<void> {
if (this._view == null) return; if (this._view == null) return;
this._view.webview.html = await this.getHtml(this._view.webview);
// Mark the webview as not ready, until we know if we are changing the html
this.isReady = false;
const html = await this.getHtml(this._view.webview);
if (force) {
// Reset the html to get the webview to reload
this._view.webview.html = '';
}
// If we aren't changing the html, mark the webview as ready again
if (this._view.webview.html === html) {
this.isReady = true;
return;
}
this._view.webview.html = html;
}
private resetContextKeys() {
void setContext(`${this.contextKeyPrefix}:focus`, false);
void setContext(`${this.contextKeyPrefix}:inputFocus`, false);
} }
private onViewDisposed() { private onViewDisposed() {
this.resetContextKeys();
this.onFocusChanged?.(false);
this.onVisibilityChanged?.(false);
this.isReady = false;
this._disposableView?.dispose(); this._disposableView?.dispose();
this._disposableView = undefined; this._disposableView = undefined;
this._view = undefined; this._view = undefined;
@ -155,13 +180,14 @@ export abstract class WebviewViewBase implements
this.onFocusChanged?.(e.focused); this.onFocusChanged?.(e.focused);
} }
private async onViewVisibilityChanged() {
const visible = this.visible;
Logger.debug(`WebviewView(${this.id}).onViewVisibilityChanged`, `visible=${visible}`);
@debug()
private async onViewVisibilityChanged(visible: boolean) {
if (visible) { if (visible) {
void this.container.usage.track(`${this.trackingFeature}:shown`); void this.container.usage.track(`${this.trackingFeature}:shown`);
await this.refresh(); await this.refresh();
} else {
this.resetContextKeys();
this.onFocusChanged?.(false);
} }
this.onVisibilityChanged?.(visible); this.onVisibilityChanged?.(visible);
} }
@ -272,12 +298,21 @@ export abstract class WebviewViewBase implements
return html; return html;
} }
protected nextIpcId(): string {
return nextIpcId();
}
protected notify<T extends IpcNotificationType<any>>( protected notify<T extends IpcNotificationType<any>>(
type: T, type: T,
params: IpcMessageParams<T>, params: IpcMessageParams<T>,
completionId?: string, completionId?: string,
): Thenable<boolean> {
return this.postMessage({ id: nextIpcId(), method: type.method, params: params, completionId: completionId });
): Promise<boolean> {
return this.postMessage({
id: this.nextIpcId(),
method: type.method,
params: params,
completionId: completionId,
});
} }
@serialize() @serialize()
@ -285,7 +320,7 @@ export abstract class WebviewViewBase implements
args: { 0: m => `(id=${m.id}, method=${m.method}${m.completionId ? `, completionId=${m.completionId}` : ''})` }, args: { 0: m => `(id=${m.id}, method=${m.method}${m.completionId ? `, completionId=${m.completionId}` : ''})` },
}) })
protected postMessage(message: IpcMessage) { protected postMessage(message: IpcMessage) {
if (this._view == null) return Promise.resolve(false);
if (this._view == null || !this.isReady) return Promise.resolve(false);
// It looks like there is a bug where `postMessage` can sometimes just hang infinitely. Not sure why, but ensure we don't hang // It looks like there is a bug where `postMessage` can sometimes just hang infinitely. Not sure why, but ensure we don't hang
return Promise.race<boolean>([ return Promise.race<boolean>([

Loading…
Cancel
Save