UNPKG

stemcstudio-tunnel

Version:

Allows STEMCstudio programs to post and receive messages when embedded in an IFrame and an LTI 1.3 LMS.

430 lines (413 loc) 12.3 kB
/** * stemcstudio-tunnel 1.2.3 * (c) David Geo Holmes david.geo.holmes@gmail.com * Released under the MIT License. */ /** * @hidden */ function disposableFromFunction(f) { return { dispose: () => { f(); } }; } /** * @hidden */ class DefaultTunnel { $window; constructor($window) { this.$window = $window; this.setWindow($window); } setWindow($window) { if ($window) { this.$window = $window; } else { throw new Error("window must be defined."); } } subscribe(handler) { this.$window.addEventListener('message', handler); return disposableFromFunction(() => { this.$window.removeEventListener('message', handler); }); } postMessage(message, transfer) { try { const targetOrigin = typeof document !== 'undefined' ? document.location.origin : ""; // console.lg(`targetOrigin=>${targetOrigin}`); this.$window.parent.postMessage(message, targetOrigin, transfer); } catch (e) { console.error(`${JSON.stringify(message)}`); console.error(`Cause: ${e}`); } } } /** * @hidden */ function isCreateItemResponse(message) { const duck = message; if (duck.data.type && duck.data.type === '@stemcstudio/gradebook:create-item-response') { return true; } else { return false; } } /** * @hidden */ function isGetItemsResponse(message) { const duck = message; if (duck.data.type && duck.data.type === '@stemcstudio/gradebook:get-items-response') { return true; } else { return false; } } /** * @hidden */ function isGetResultsResponse(message) { const duck = message; if (duck.data.type && duck.data.type === '@stemcstudio/gradebook:get-results-response') { return true; } else { return false; } } /** * @hidden */ function isSubmitScoreResponse(message) { const duck = message; if (duck.data.type && duck.data.type === '@stemcstudio/gradebook:submit-score-response') { return true; } else { return false; } } /** * @hidden */ function isCorrelated(response, id) { const responseId = response.id; return responseId === id; } /** * @hidden */ function generateCorrelationId() { return Math.random(); } /** * @hidden */ class TunnelGradebook { tunnel; constructor(tunnel) { this.tunnel = tunnel; } createItem(item) { return new Promise((resolve, reject) => { const id = generateCorrelationId(); const subscription = this.tunnel.subscribe(function (message) { if (isCreateItemResponse(message)) { const response = message.data; if (isCorrelated(response, id)) { if (!response.err) { resolve(response.value); } else { reject(response.err); } subscription.dispose(); } } }); this.tunnel.postMessage({ type: '@stemcstudio/gradebook:create-item', id, item }); }); } getItems() { return new Promise((resolve, reject) => { const id = generateCorrelationId(); const subscription = this.tunnel.subscribe(function (message) { if (isGetItemsResponse(message)) { const response = message.data; if (isCorrelated(response, id)) { if (!response.err) { resolve(response.value); } else { reject(response.err); } subscription.dispose(); } } }); this.tunnel.postMessage({ type: '@stemcstudio/gradebook:get-items', id }); }); } getResults(itemId) { return new Promise((resolve, reject) => { const id = generateCorrelationId(); const subscription = this.tunnel.subscribe(function (message) { if (isGetResultsResponse(message)) { const response = message.data; if (isCorrelated(response, id)) { if (!response.err) { resolve(response.value); } else { reject(response.err); } subscription.dispose(); } } }); this.tunnel.postMessage({ type: '@stemcstudio/gradebook:get-results', id, itemId }); }); } submitScore(itemId, score) { return new Promise((resolve, reject) => { const id = generateCorrelationId(); const subscription = this.tunnel.subscribe(function (message) { if (isSubmitScoreResponse(message)) { const response = message.data; if (isCorrelated(response, id)) { if (!response.err) { resolve(); } else { reject(response.err); } subscription.dispose(); } } }); this.tunnel.postMessage({ type: '@stemcstudio/gradebook:submit-score', id, itemId, score }); }); } } /** * @hidden */ function isAlertResponse(message) { const duck = message; if (duck.data.type && duck.data.type === '@stemcstudio/modal-dialog-service:alert-response') { return true; } else { return false; } } /** * @hidden */ function createConfirmRequest(title, message, actionButtonText, cancelButtonText) { const id = generateCorrelationId(); return { type: '@stemcstudio/modal-dialog-service:confirm', id, title: title, message: message, actionButtonText: actionButtonText, cancelButtonText: cancelButtonText }; } /** * @hidden */ function isConfirmResponse(message) { const duck = message; if (duck.data.type && duck.data.type === '@stemcstudio/modal-dialog-service:confirm-response') { return true; } else { return false; } } /** * @hidden */ function createPromptRequest(title, message, text, label, hint, actionButtonText, cancelButtonText) { const id = generateCorrelationId(); return { type: '@stemcstudio/modal-dialog-service:prompt', id, title, message, text, label, hint, actionButtonText: actionButtonText, cancelButtonText: cancelButtonText }; } /** * @hidden */ function isPromptResponse(message) { const duck = message; if (duck.data.type && duck.data.type === '@stemcstudio/modal-dialog-service:prompt-response') { return true; } else { return false; } } /** * @hidden */ class TunnelModalDialogService { tunnel; constructor(tunnel) { this.tunnel = tunnel; } alert(options) { return new Promise((resolve, reject) => { const id = generateCorrelationId(); const subscription = this.tunnel.subscribe(function (message) { if (isAlertResponse(message)) { const response = message.data; if (isCorrelated(response, id)) { if (!response.err) { resolve(response.value); } else { reject(response.err); } subscription.dispose(); } } }); this.tunnel.postMessage({ type: '@stemcstudio/modal-dialog-service:alert', id, title: options.title, message: options.message }); }); } confirm(options) { return new Promise((resolve, reject) => { const request = createConfirmRequest(options.title, options.message, options.actionButtonText, options.cancelButtonText); const subscription = this.tunnel.subscribe(function (message) { if (isConfirmResponse(message)) { const response = message.data; if (isCorrelated(response, request.id)) { if (!response.err) { resolve(response.value); } else { reject(response.err); } subscription.dispose(); } } }); this.tunnel.postMessage(request); }); } prompt(options) { return new Promise((resolve, reject) => { const request = createPromptRequest(options.title, options.message, options.text, options.label, options.hint, options.actionButtonText, options.cancelButtonText); const subscription = this.tunnel.subscribe(function (message) { if (isPromptResponse(message)) { const response = message.data; if (isCorrelated(response, request.id)) { if (!response.err) { resolve(response.value); } else { reject(response.err); } subscription.dispose(); } } }); this.tunnel.postMessage(request); }); } } /** * @hidden */ function isGetMembersResponse(message) { const duck = message; if (duck.data.type && duck.data.type === '@stemcstudio/organization:get-members-response') { return true; } else { return false; } } /** * @hidden */ class TunnelOrganization { tunnel; constructor(tunnel) { this.tunnel = tunnel; } getMembers() { return new Promise((resolve, reject) => { const id = generateCorrelationId(); const subscription = this.tunnel.subscribe(function (message) { if (isGetMembersResponse(message)) { const response = message.data; if (isCorrelated(response, id)) { if (!response.err) { resolve(response.value); } else { reject(response.err); } subscription.dispose(); } } }); this.tunnel.postMessage({ type: '@stemcstudio/organization:get-members', id }); }); } } /** * Support for testing. * Stops the DefaultTunnel from complaining. */ class FauxWindow { parent; addEventListener(type, handler) { throw new Error(`addEventListener(type=${type}, handler=${typeof handler}) method is not implemented.`); } removeEventListener(type, handler) { throw new Error(`removeEventListener(type=${type}, handler=${typeof handler}) method is not implemented.`); } } /** * Singleton instance of Tunnel for communicating with the host web page. */ const tunnel = (typeof window !== 'undefined') ? new DefaultTunnel(window) : new DefaultTunnel(new FauxWindow()); /** * The current Gradebook instance. */ const gradebook = new TunnelGradebook(tunnel); /** * The current Organization instance. */ const cohort = new TunnelOrganization(tunnel); /** * The Modal Dialog Service instance provided by the STEMCstudio parent window. */ const user = new TunnelModalDialogService(tunnel); export { cohort, gradebook, tunnel, user }; //# sourceMappingURL=index.js.map