Skip to content

Commit

Permalink
make the entire runtime run in node
Browse files Browse the repository at this point in the history
Working towards numbas/numbas-lti-provider#110.

This changes the script queueing stuff to add module.exports from each
script to the `window` and `global` objects, if they exist.

Now the entire Numbas runtime can run unmodified in node.js, if the
`browser-env` package is loaded first and you set `Numbas.display =
null` before trying to load an exam.

This commit also changes the compiler so it adds a file
'numbas-manifest.json' to the package, with the Numbas version and a
dict of features that could be added to over time, so a tool can
automatically work out if a package supports the feature it wants
without trying to run the JS.
  • Loading branch information
christianp committed Nov 9, 2020
1 parent 1382cb8 commit d9bbe41
Show file tree
Hide file tree
Showing 12 changed files with 109 additions and 60 deletions.
19 changes: 19 additions & 0 deletions bin/numbas.py
Expand Up @@ -33,6 +33,9 @@
import jinja2


NUMBAS_VERSION = '5.2'


namespaces = {
'': 'http://www.imsglobal.org/xsd/imscp_v1p1',
'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
Expand Down Expand Up @@ -152,6 +155,8 @@ def compile(self):

self.add_source()

self.add_manifest()

if self.options.scorm:
self.add_scorm()

Expand Down Expand Up @@ -403,6 +408,20 @@ def add_source(self):
"""
self.files[os.path.join('.','source.exam')] = io.StringIO(self.options.source)

def add_manifest(self):
features = {
'run_headless': True,
'scorm': self.options.scorm,
'has_index_html': self.options.expect_index_html,
}
manifest = {
'Numbas_version': NUMBAS_VERSION,
'source_url': self.options.source_url,
'locale': self.options.locale,
'features': features,
}
self.files[os.path.join('.','numbas-manifest.json')] = io.StringIO(json.dumps(manifest))

def minify(self):
"""
Minify all javascript files in the package
Expand Down
6 changes: 2 additions & 4 deletions runtime/scripts/decimal/decimal.js

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion runtime/scripts/es6-promise/es6-promise.js
@@ -1,4 +1,7 @@
Numbas.queueScript('es6-promise',[],function(module) {
if(typeof Promise!=='undefined') {
return;
}
/*!
* @overview es6-promise - a tiny implementation of Promises/A+.
* @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
Expand Down Expand Up @@ -793,4 +796,4 @@ Numbas.queueScript('es6-promise',[],function(module) {
}
lib$es6$promise$polyfill$$default();
}).call(this);
});
});
5 changes: 3 additions & 2 deletions runtime/scripts/i18next/i18next.js

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion runtime/scripts/jquery/jquery.js

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion runtime/scripts/knockout/knockout.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions runtime/scripts/localisation.js
@@ -1,4 +1,4 @@
Numbas.queueScript('localisation',['i18next','localisation-resources'],function() {
Numbas.queueScript('localisation',['i18next','localisation-resources'],function(module) {
i18next.init({
lng: Numbas.locale.preferred_locale,
lowerCaseLng: true,
Expand All @@ -14,5 +14,5 @@ Numbas.queueScript('localisation',['i18next','localisation-resources'],function(
},
resources: Numbas.locale.resources
});
window.R = function(){{ return i18next.t.apply(i18next,arguments) }};
});
module.exports.R = function(){{ return i18next.t.apply(i18next,arguments) }};
});
27 changes: 17 additions & 10 deletions runtime/scripts/numbas.js
Expand Up @@ -15,16 +15,16 @@ Copyright 2011-14 Newcastle University
* Creates the global {@link Numbas} object, inside which everything else is stored, so as not to conflict with anything else that might be running in the page.
*/
(function() {
try {
window;
} catch(e) {
try {
global.window = global;
global.alert = function(m) { console.error(m); }
} catch(e) {
if(typeof window=='undefined') {
if(typeof global!=='undefined') {
window = global.window = global;
global.alert = function(m) { console.error(m); }
}
}
if(!window.Numbas) { window.Numbas = {} }
if(typeof global!=='undefined') {
global.Numbas = window.Numbas;
}
}
if(!window.Numbas) { window.Numbas = {} }
/** @namespace Numbas */
/** Extensions should add objects to this so they can be accessed */
Numbas.extensions = {};
Expand Down Expand Up @@ -131,7 +131,14 @@ RequireScript.prototype = {
var dependencies_executed = this.fdeps.every(function(r){ return scriptreqs[r].executed; });
if(dependencies_executed) {
if(this.callback) {
this.callback.apply(window,[{exports:window}]);
var module = { exports: {} };
this.callback.apply(window,[module]);
for(var x in module.exports) {
window[x] = module.exports[x];
if(typeof global!=='undefined') {
global[x] = module.exports[x];
}
}
}
this.executed = true;
this.backdeps.forEach(function(r) {
Expand Down
2 changes: 1 addition & 1 deletion runtime/scripts/question.js
Expand Up @@ -522,7 +522,7 @@ Question.prototype = /** @lends Numbas.Question.prototype */
switch(q.partsMode) {
case 'all':
parts.forEach(function(pd,i) {
var p = Numbas.createPartFromJSON(pd, 'p'+i, q, q.store);
var p = Numbas.createPartFromJSON(pd, 'p'+i, q, null, q.store);
q.addPart(p,i);
});
break;
Expand Down
43 changes: 25 additions & 18 deletions tests/jme-runtime.js

Large diffs are not rendered by default.

45 changes: 26 additions & 19 deletions tests/numbas-runtime.js

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions themes/default/files/scripts/mathjax.js
@@ -1,4 +1,7 @@
Numbas.queueScript('mathjax-hooks',['display-base','jme','jme-display'],function() {
if(typeof MathJax=='undefined') {
return;
}
var jme = Numbas.jme;
Numbas.display.MathJaxQueue = MathJax.Hub.queue;
MathJax.Hub.Register.MessageHook("Math Processing Error",function(message){
Expand Down

0 comments on commit d9bbe41

Please sign in to comment.