Commit 6cf7a391 authored by Robert Knight's avatar Robert Knight

Remove temporary client configuration from frame when client is unloaded

When the client is unloaded in a guest-only iframe, remove the client
configuration that was added by the `injectClient` function. This is
necessary for subsequent reloading of the client to work, as
`injectClient` aborts if the configuration already exists in a frame.

This change allows the client to be properly de-activated and then later
re-activated in a VitalSource book.
parent f18218f7
...@@ -48,7 +48,7 @@ export class HypothesisInjector { ...@@ -48,7 +48,7 @@ export class HypothesisInjector {
} }
/** /**
* Check if the client was added to a frame by {@link injectHypothesis}. * Check if the client was added to a frame by {@link injectClient}.
* *
* @param {HTMLIFrameElement} iframe * @param {HTMLIFrameElement} iframe
*/ */
...@@ -57,6 +57,16 @@ function hasHypothesis(iframe) { ...@@ -57,6 +57,16 @@ function hasHypothesis(iframe) {
return iframeDocument.querySelector('script.js-hypothesis-config') !== null; return iframeDocument.querySelector('script.js-hypothesis-config') !== null;
} }
/**
* Remove the temporary configuration data added to a document by {@link injectClient}.
*/
export function removeTemporaryClientConfig(document_ = document) {
const tempConfigEls = Array.from(
document_.querySelectorAll('script.js-temp-config')
);
tempConfigEls.forEach(el => el.remove());
}
/** /**
* Inject Hypothesis client into a frame. * Inject Hypothesis client into a frame.
* *
...@@ -66,6 +76,10 @@ function hasHypothesis(iframe) { ...@@ -66,6 +76,10 @@ function hasHypothesis(iframe) {
* This waits for the frame to finish loading before injecting the client. * This waits for the frame to finish loading before injecting the client.
* See {@link onDocumentReady}. * See {@link onDocumentReady}.
* *
* This function does nothing if the client has already been added to the frame.
* This is determined by the presence of temporary configuration `<script>`s
* added by this function, which can be removed with {@link removeTemporaryClientConfig}.
*
* @param {HTMLIFrameElement} frame * @param {HTMLIFrameElement} frame
* @param {InjectConfig} config - * @param {InjectConfig} config -
* @param {string} [frameId] - The ID for the guest frame. If none is provided, * @param {string} [frameId] - The ID for the guest frame. If none is provided,
...@@ -100,7 +114,7 @@ export async function injectClient(frame, config, frameId) { ...@@ -100,7 +114,7 @@ export async function injectClient(frame, config, frameId) {
}; };
const configElement = document.createElement('script'); const configElement = document.createElement('script');
configElement.className = 'js-hypothesis-config'; configElement.className = 'js-hypothesis-config js-temp-config';
configElement.type = 'application/json'; configElement.type = 'application/json';
configElement.innerText = JSON.stringify(injectedConfig); configElement.innerText = JSON.stringify(injectedConfig);
......
...@@ -18,7 +18,10 @@ import { getConfig } from './config/index'; ...@@ -18,7 +18,10 @@ import { getConfig } from './config/index';
import type { NotebookConfig } from './components/NotebookModal'; import type { NotebookConfig } from './components/NotebookModal';
import { Guest } from './guest'; import { Guest } from './guest';
import type { GuestConfig } from './guest'; import type { GuestConfig } from './guest';
import { HypothesisInjector } from './hypothesis-injector'; import {
HypothesisInjector,
removeTemporaryClientConfig,
} from './hypothesis-injector';
import type { InjectConfig } from './hypothesis-injector'; import type { InjectConfig } from './hypothesis-injector';
import { import {
VitalSourceInjector, VitalSourceInjector,
...@@ -112,6 +115,10 @@ function init() { ...@@ -112,6 +115,10 @@ function init() {
// page by the boot script. // page by the boot script.
const clientAssets = document.querySelectorAll('[data-hypothesis-asset]'); const clientAssets = document.querySelectorAll('[data-hypothesis-asset]');
clientAssets.forEach(el => el.remove()); clientAssets.forEach(el => el.remove());
// If this is a guest-only frame, remove client config added by the host
// frame. This enables the client to later be re-loaded in this frame.
removeTemporaryClientConfig();
}); });
} }
......
...@@ -3,6 +3,7 @@ import { DEBOUNCE_WAIT, onNextDocumentReady } from '../../frame-observer'; ...@@ -3,6 +3,7 @@ import { DEBOUNCE_WAIT, onNextDocumentReady } from '../../frame-observer';
import { import {
HypothesisInjector, HypothesisInjector,
injectClient, injectClient,
removeTemporaryClientConfig,
$imports, $imports,
} from '../../hypothesis-injector'; } from '../../hypothesis-injector';
...@@ -72,6 +73,9 @@ describe('HypothesisInjector integration test', () => { ...@@ -72,6 +73,9 @@ describe('HypothesisInjector integration test', () => {
const configElement = frame.contentDocument.querySelector( const configElement = frame.contentDocument.querySelector(
'.js-hypothesis-config' '.js-hypothesis-config'
); );
if (!configElement) {
return null;
}
return JSON.parse(configElement.textContent); return JSON.parse(configElement.textContent);
} }
...@@ -262,4 +266,26 @@ describe('HypothesisInjector integration test', () => { ...@@ -262,4 +266,26 @@ describe('HypothesisInjector integration test', () => {
'expected dynamically added iframe to include the Hypothesis script' 'expected dynamically added iframe to include the Hypothesis script'
); );
}); });
describe('removeTemporaryClientConfig', () => {
it('removes config `<script>`s added to page by `injectClient`', async () => {
const frame = document.createElement('iframe');
container.append(frame);
// Inject client into frame. Subsequent `injectClient` calls would be
// a no-op as the client is already injected.
await injectClient(frame, { clientUrl: 'https://hyp.is' });
assert.ok(extractClientConfig(frame));
// Remove client config. This should happen if the client is unloaded from
// the frame.
removeTemporaryClientConfig(frame.contentDocument);
assert.isNull(extractClientConfig(frame));
// After removing the temporary config, `injectClient` should once again
// be able to re-inject the client into the frame.
await injectClient(frame, { clientUrl: 'https://hyp.is' });
assert.ok(extractClientConfig(frame));
});
});
}); });
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment