forked from Open-CT/openct-tasks
255 lines
8.6 KiB
JavaScript
255 lines
8.6 KiB
JavaScript
(function () {
|
|
|
|
'use strict';
|
|
|
|
/*
|
|
* Same domain task proxy implementation for Bebras task API - v1.0 - 08/2014
|
|
*
|
|
* Depends on jQuery.
|
|
*
|
|
*/
|
|
|
|
var functionsToTrigger = {load: true, unload:true, reloadAnswer:true, showViews: true, reloadState: true};
|
|
|
|
function taskCaller(task, request, content, error) {
|
|
if (!error) {
|
|
error = function() {};
|
|
}
|
|
// TODO: handle case where iframe_loaded is false and caller expects a result...
|
|
if (!task.iframe_loaded) {
|
|
setTimeout(function() {
|
|
taskCaller(task, request, content);
|
|
}, 100);
|
|
} else {
|
|
if (task.distantTask && typeof task.distantTask[request] === 'function') {
|
|
if (typeof content === 'string' || (typeof content === 'object' && Object.prototype.toString.call(content) !== '[object Array]')) {
|
|
content = [content];
|
|
}
|
|
var askedCallbackIdx = (typeof content[content.length - 2] === 'function') ? content.length - 2 : content.length - 1;
|
|
if (typeof content[askedCallbackIdx] !== 'function') {
|
|
error('calls to task must contain a callback');
|
|
return;
|
|
}
|
|
var oldCallback = content[askedCallbackIdx];
|
|
var timeout = window.setTimeout(function() {
|
|
error('timeout reached for '+request);
|
|
}, 15000);
|
|
var newCallback = function() {
|
|
window.clearTimeout(timeout);
|
|
if (functionsToTrigger[request]) {
|
|
task.distantPlatform.trigger(request, content);
|
|
}
|
|
oldCallback(arguments[0], arguments[1], arguments[3]);
|
|
};
|
|
content[askedCallbackIdx] = newCallback;
|
|
if (typeof window.taskPrNoCatch !== 'undefined') {
|
|
task.distantTask[request].apply(task.distantTask, content);
|
|
} else {
|
|
try {
|
|
task.distantTask[request].apply(task.distantTask, content);
|
|
} catch (e) {
|
|
window.clearTimeout(timeout);
|
|
error(e);
|
|
}
|
|
}
|
|
} else if (task.distantTask) {
|
|
error("Task "+task.Id+" doesn't implement "+request);
|
|
} else {
|
|
error('call to '+request+' on task with no distant task');
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Task object, created from an iframe DOM element
|
|
*/
|
|
function Task(iframe, callback) {
|
|
this.iframe = iframe;
|
|
this.iframe_loaded = false;
|
|
this.distantTask = null;
|
|
this.Id = iframe.attr('id');
|
|
this.elementsLoaded = false;
|
|
this.platform = null;
|
|
var that = this;
|
|
this.setPlatform = function(platform) {
|
|
this.platform = platform;
|
|
if (this.iframe_loaded) {
|
|
this.distantPlatform.setPlatform(platform);
|
|
}
|
|
};
|
|
this.iframeLoaded = function() {
|
|
if (that.iframe_loaded) {
|
|
return;
|
|
}
|
|
that.iframe_loaded = true;
|
|
that.distantTask = that.iframe[0].contentWindow.task;
|
|
that.distantPlatform = that.iframe[0].contentWindow.platform;
|
|
that.iframe[0].contentWindow.platform.parentLoadedFlag = true;
|
|
if (that.platform) {
|
|
that.distantPlatform.setPlatform(that.platform);
|
|
}
|
|
callback();
|
|
};
|
|
// checking if platform is already available
|
|
var iframeDoc = that.iframe[0].contentDocument || that.iframe[0].contentWindow.document;
|
|
if (iframeDoc && iframeDoc.readyState == 'complete' && that.iframe[0].contentWindow.platform && !that.iframe[0].contentWindow.platform.parentLoadedFlag) {
|
|
that.iframe[0].contentWindow.platform.initCallback(that.iframeLoaded);
|
|
} else {
|
|
if(document.addEventListener) { // ie > 8
|
|
$(that.iframe).on("load", function() {
|
|
that.iframe[0].contentWindow.platform.initCallback(that.iframeLoaded);
|
|
});
|
|
} else {
|
|
setTimeout(function() {
|
|
that.iframeLoaded();
|
|
}, 100);
|
|
}
|
|
}
|
|
}
|
|
|
|
Task.prototype.getSourceId = function() {
|
|
return this.Id;
|
|
};
|
|
|
|
Task.prototype.getTargetUrl = function() {
|
|
return this.iframe.attr('src');
|
|
};
|
|
|
|
Task.prototype.getTarget = function() {
|
|
return this.iframe[0].contentWindow;
|
|
};
|
|
|
|
Task.prototype.getDomain = function() {
|
|
var url = this.getTargetUrl();
|
|
return url.substr(0, url.indexOf('/', 7));
|
|
};
|
|
|
|
/**
|
|
* Task API functions
|
|
*/
|
|
Task.prototype.load = function(views, success, error) {
|
|
return taskCaller(this, 'load', [views, success, error], error);
|
|
};
|
|
Task.prototype.unload = function(success, error) {
|
|
return taskCaller(this, 'unload', [success, error], error);
|
|
};
|
|
Task.prototype.getHeight = function(success, error) {
|
|
return taskCaller(this, 'getHeight', [success, error], error);
|
|
};
|
|
Task.prototype.updateToken = function(token, success, error) {
|
|
return taskCaller(this, 'updateToken', [token, success, error], error);
|
|
};
|
|
Task.prototype.getAnswer = function(success, error) {
|
|
return taskCaller(this, 'getAnswer', [success, error], error);
|
|
};
|
|
Task.prototype.reloadAnswer = function(answer, success, error) {
|
|
return taskCaller(this, 'reloadAnswer', [answer, success, error], error);
|
|
};
|
|
Task.prototype.getState = function(success, error) {
|
|
return taskCaller(this, 'getState', [success, error], error);
|
|
};
|
|
Task.prototype.reloadState = function(state, success, error) {
|
|
return taskCaller(this, 'reloadState', [state, success, error], error);
|
|
};
|
|
Task.prototype.getViews = function(success, error) {
|
|
return taskCaller(this, 'getViews', [success, error], error);
|
|
};
|
|
Task.prototype.getMetaData = function(success, error) {
|
|
return taskCaller(this, 'getMetaData', [success, error], error);
|
|
};
|
|
Task.prototype.showViews = function(views, success, error) {
|
|
return taskCaller(this, 'showViews', [views, success, error], error);
|
|
};
|
|
// TODO: put error back in argument list, for this 2015 tasks must be changed
|
|
Task.prototype.gradeAnswer = function(answer, answerToken, success, error) {
|
|
return taskCaller(this, 'gradeAnswer', [answer, answerToken, success], error);
|
|
};
|
|
Task.prototype.getResources = function(success, error) {
|
|
return taskCaller(this, 'getResources', [success, error], error);
|
|
};
|
|
// for grader.gradeTask
|
|
// TODO: put error back in argument list, for this 2015 tasks must be changed
|
|
Task.prototype.gradeTask = function(answer, answerToken, success, error) {
|
|
return taskCaller(this, 'gradeTask', [answer, answerToken, success], error);
|
|
};
|
|
|
|
window.TaskProxyManager = {
|
|
tasks: {},
|
|
platforms: {},
|
|
getTaskProxy: function(idFrame, callback, force) {
|
|
if (!force && TaskProxyManager.tasks[idFrame]) {
|
|
callback(TaskProxyManager.tasks[idFrame]);
|
|
} else {
|
|
if (force) {
|
|
TaskProxyManager.deleteTaskProxy(idFrame);
|
|
}
|
|
$('#'+idFrame).each(function() {
|
|
TaskProxyManager.tasks[idFrame] = new Task($(this), function() {setTimeout(function() {
|
|
if (idFrame in TaskProxyManager.platforms) {
|
|
TaskProxyManager.tasks[idFrame].setPlatform(TaskProxyManager.platforms[idFrame]);
|
|
}
|
|
callback(TaskProxyManager.tasks[idFrame]);
|
|
});});
|
|
});
|
|
}
|
|
},
|
|
setPlatform: function(task, platform) {
|
|
TaskProxyManager.platforms[task.Id] = platform;
|
|
TaskProxyManager.tasks[task.Id].setPlatform(platform);
|
|
},
|
|
deleteTaskProxy: function(idFrame) {
|
|
delete(TaskProxyManager.tasks[idFrame]);
|
|
delete(TaskProxyManager.platforms[idFrame]);
|
|
},
|
|
getUrl: function(taskUrl, sToken, sPlatform, prefix) {
|
|
return taskUrl+'?sToken='+encodeURIComponent(sToken)+'&sPlatform='+encodeURIComponent(sPlatform);
|
|
}
|
|
};
|
|
|
|
window.TaskProxyManager.getGraderProxy = TaskProxyManager.getTaskProxy;
|
|
|
|
}());
|
|
|
|
/*
|
|
* Platform object definition, created from a Task object (see below)
|
|
*/
|
|
|
|
function Platform(task) {
|
|
this.task = task;
|
|
}
|
|
Platform.prototype.getTask = function() {
|
|
return this.task;
|
|
};
|
|
|
|
/*
|
|
* Simple prototypes for platform API functions, to be overriden by your
|
|
* platform's specific functions (for each platform object)
|
|
*/
|
|
|
|
Platform.prototype.validate = function(mode) {};
|
|
Platform.prototype.showView = function(views) {};
|
|
Platform.prototype.askHint = function(platformToken) {};
|
|
Platform.prototype.updateHeight = function(height) { this.updateDisplay({height: height}); }; // Legacy
|
|
Platform.prototype.updateDisplay = function(data) {
|
|
if(data.height) {
|
|
this.task.iframe.height(parseInt(height)+40);
|
|
}
|
|
};
|
|
Platform.prototype.getTaskParams = function(key, defaultValue, success, error) {
|
|
var res = {minScore: -3, maxScore: 10, randomSeed: 0, noScore: 0, readOnly: false, options: {}};
|
|
if (key) {
|
|
if (key !== 'options' && key in res) {
|
|
res = res[key];
|
|
} else if (res.options && key in res.options) {
|
|
res = res.options[key];
|
|
} else {
|
|
res = (typeof defaultValue !== 'undefined') ? defaultValue : null;
|
|
}
|
|
}
|
|
success(res);
|
|
};
|
|
|
|
Platform.prototype.openUrl = function(url) {
|
|
// TODO
|
|
};
|