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
JavaScript
/**
* 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