Fix extension unload cases (#712)

* Add _invokeSafe function to silently ignore extension unload errors

* Remove "Api" from function names

* Add invokeSafe to Popup

* Don't redundantly set content type to 'unloaded'
This commit is contained in:
toasted-nutbread 2020-08-02 21:51:51 -04:00 committed by GitHub
parent a81d69d6c1
commit b253cdc92e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 36 deletions

View File

@ -60,24 +60,20 @@ class PopupProxy extends EventDispatcher {
return true; return true;
} }
async setOptionsContext(optionsContext, source) { setOptionsContext(optionsContext, source) {
return await this._invoke('setOptionsContext', {id: this._id, optionsContext, source}); return this._invokeSafe('setOptionsContext', {id: this._id, optionsContext, source});
} }
hide(changeFocus) { hide(changeFocus) {
this._invoke('hide', {id: this._id, changeFocus}); return this._invokeSafe('hide', {id: this._id, changeFocus});
} }
async isVisible() { isVisible() {
try { return this._invokeSafe('isVisible', {id: this._id}, false);
return await this._invoke('isVisible', {id: this._id});
} catch (e) {
return false;
}
} }
setVisibleOverride(visible) { setVisibleOverride(visible) {
this._invoke('setVisibleOverride', {id: this._id, visible}); return this._invokeSafe('setVisibleOverride', {id: this._id, visible});
} }
async containsPoint(x, y) { async containsPoint(x, y) {
@ -85,7 +81,7 @@ class PopupProxy extends EventDispatcher {
await this._updateFrameOffset(); await this._updateFrameOffset();
[x, y] = this._applyFrameOffset(x, y); [x, y] = this._applyFrameOffset(x, y);
} }
return await this._invoke('containsPoint', {id: this._id, x, y}); return await this._invokeSafe('containsPoint', {id: this._id, x, y}, false);
} }
async showContent(details, displayDetails) { async showContent(details, displayDetails) {
@ -98,23 +94,19 @@ class PopupProxy extends EventDispatcher {
} }
details.elementRect = {x, y, width, height}; details.elementRect = {x, y, width, height};
} }
return await this._invoke('showContent', {id: this._id, details, displayDetails}); return await this._invokeSafe('showContent', {id: this._id, details, displayDetails});
} }
setCustomCss(css) { setCustomCss(css) {
this._invoke('setCustomCss', {id: this._id, css}); return this._invokeSafe('setCustomCss', {id: this._id, css});
} }
async clearAutoPlayTimer() { clearAutoPlayTimer() {
try { return this._invokeSafe('clearAutoPlayTimer', {id: this._id});
await this._invoke('clearAutoPlayTimer', {id: this._id});
} catch (e) {
// NOP
}
} }
setContentScale(scale) { setContentScale(scale) {
this._invoke('setContentScale', {id: this._id, scale}); return this._invokeSafe('setContentScale', {id: this._id, scale});
} }
// Private // Private
@ -123,6 +115,15 @@ class PopupProxy extends EventDispatcher {
return api.crossFrame.invoke(this._parentFrameId, action, params); return api.crossFrame.invoke(this._parentFrameId, action, params);
} }
async _invokeSafe(action, params={}, defaultReturnValue) {
try {
return await this._invoke(action, params);
} catch (e) {
if (!yomichan.isExtensionUnloaded) { throw e; }
return defaultReturnValue;
}
}
async _updateFrameOffset() { async _updateFrameOffset() {
const now = Date.now(); const now = Date.now();
const firstRun = this._frameOffsetUpdatedAt === null; const firstRun = this._frameOffsetUpdatedAt === null;

View File

@ -97,7 +97,7 @@ class Popup {
this._options = await api.optionsGet(optionsContext); this._options = await api.optionsGet(optionsContext);
this.updateTheme(); this.updateTheme();
this._invokeApi('setOptionsContext', {optionsContext}); this._invokeSafe('setOptionsContext', {optionsContext});
} }
hide(changeFocus) { hide(changeFocus) {
@ -146,25 +146,21 @@ class Popup {
} }
if (displayDetails !== null) { if (displayDetails !== null) {
this._invokeApi('setContent', {details: displayDetails}); this._invokeSafe('setContent', {details: displayDetails});
} }
} }
setCustomCss(css) { setCustomCss(css) {
this._invokeApi('setCustomCss', {css}); this._invokeSafe('setCustomCss', {css});
} }
async clearAutoPlayTimer() { clearAutoPlayTimer() {
try { this._invokeSafe('clearAutoPlayTimer');
await this._invokeApi('clearAutoPlayTimer');
} catch (e) {
// NOP
}
} }
setContentScale(scale) { setContentScale(scale) {
this._contentScale = scale; this._contentScale = scale;
this._invokeApi('setContentScale', {scale}); this._invokeSafe('setContentScale', {scale});
} }
// Popup-only public functions // Popup-only public functions
@ -266,7 +262,7 @@ class Popup {
await frameClient.connect(this._frame, this._targetOrigin, this._frameId, setupFrame); await frameClient.connect(this._frame, this._targetOrigin, this._frameId, setupFrame);
// Configure // Configure
await this._invokeApi('configure', { await this._invokeSafe('configure', {
frameId: this._frameId, frameId: this._frameId,
ownerFrameId: this._ownerFrameId, ownerFrameId: this._ownerFrameId,
popupId: this._id, popupId: this._id,
@ -448,7 +444,7 @@ class Popup {
return dark ? 'dark' : 'light'; return dark ? 'dark' : 'light';
} }
async _invokeApi(action, params={}) { async _invoke(action, params={}) {
const contentWindow = this._frame.contentWindow; const contentWindow = this._frame.contentWindow;
if (this._frameClient === null || !this._frameClient.isConnected() || contentWindow === null) { return; } if (this._frameClient === null || !this._frameClient.isConnected() || contentWindow === null) { return; }
@ -456,7 +452,16 @@ class Popup {
return await api.crossFrame.invoke(this._frameClient.frameId, 'popupMessage', message); return await api.crossFrame.invoke(this._frameClient.frameId, 'popupMessage', message);
} }
_invokeWindowApi(action, params={}) { async _invokeSafe(action, params={}, defaultReturnValue) {
try {
return await this._invoke(action, params);
} catch (e) {
if (!yomichan.isExtensionUnloaded) { throw e; }
return defaultReturnValue;
}
}
_invokeWindow(action, params={}) {
const contentWindow = this._frame.contentWindow; const contentWindow = this._frame.contentWindow;
if (this._frameClient === null || !this._frameClient.isConnected() || contentWindow === null) { return; } if (this._frameClient === null || !this._frameClient.isConnected() || contentWindow === null) { return; }
@ -465,7 +470,7 @@ class Popup {
} }
_onExtensionUnloaded() { _onExtensionUnloaded() {
this._invokeWindowApi('extensionUnloaded'); this._invokeWindow('extensionUnloaded');
} }
_getFrameParentElement() { _getFrameParentElement() {

View File

@ -69,6 +69,7 @@ class Display extends EventDispatcher {
this._historyChangeIgnore = false; this._historyChangeIgnore = false;
this._historyHasChanged = false; this._historyHasChanged = false;
this._navigationHeader = document.querySelector('#navigation-header'); this._navigationHeader = document.querySelector('#navigation-header');
this._contentType = 'clear';
this._defaultTitle = 'Yomichan Search'; this._defaultTitle = 'Yomichan Search';
this._defaultTitleMaxLength = 1000; this._defaultTitleMaxLength = 1000;
this._fullQuery = ''; this._fullQuery = '';
@ -393,6 +394,7 @@ class Display extends EventDispatcher {
let asigned = false; let asigned = false;
const eventArgs = {type, urlSearchParams, token}; const eventArgs = {type, urlSearchParams, token};
this._historyHasChanged = true; this._historyHasChanged = true;
this._contentType = type;
this._mediaLoader.unloadAll(); this._mediaLoader.unloadAll();
switch (type) { switch (type) {
case 'terms': case 'terms':
@ -416,8 +418,10 @@ class Display extends EventDispatcher {
const stale = (this._setContentToken !== token); const stale = (this._setContentToken !== token);
if (!stale) { if (!stale) {
if (!asigned) { if (!asigned) {
type = 'clear';
this._contentType = type;
const {content} = this._history; const {content} = this._history;
eventArgs.type = 'clear'; eventArgs.type = type;
eventArgs.content = content; eventArgs.content = content;
this.trigger('contentUpdating', eventArgs); this.trigger('contentUpdating', eventArgs);
this._clearContent(); this._clearContent();
@ -451,10 +455,12 @@ class Display extends EventDispatcher {
} }
_onExtensionUnloaded() { _onExtensionUnloaded() {
const type = 'unloaded';
if (this._contentType === type) { return; }
const details = { const details = {
focus: false, focus: false,
history: false, history: false,
params: {type: 'unloaded'}, params: {type},
state: {}, state: {},
content: {} content: {}
}; };