diff options
Diffstat (limited to 'js/codeq/core.js')
-rw-r--r-- | js/codeq/core.js | 254 |
1 files changed, 2 insertions, 252 deletions
diff --git a/js/codeq/core.js b/js/codeq/core.js index e86b396..50322c0 100644 --- a/js/codeq/core.js +++ b/js/codeq/core.js @@ -1,5 +1,5 @@ /* CodeQ: an online programming tutor. - Copyright (C) 2015 UL FRI + Copyright (C) 2015,2016 UL FRI This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free @@ -164,22 +164,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ // regular expressions for the templating function, etc. var regexpQuote = new RegExp('"', 'g'), regexpBackslash = new RegExp('\\\\', 'g'), - regexpWhiteSpaceStart = new RegExp('^[ \r\n\t]+'), - regexpWhiteSpaceEnd = new RegExp('[ \r\n\t]+$'), - regexpWhiteSpaceTrim = new RegExp('^[ \\t\\r\\n]*(.*[^ \\t\\r\\n])[ \\t\\r\\n]*$', 'm'), regexpAmp = new RegExp('&', 'g'), regexpLt = new RegExp('<', 'g'), - regexpGt = new RegExp('>', 'g'), - regexpCR = new RegExp('\\r', 'g'), - regexpLF = new RegExp('\\n', 'g'), - regexpTab = new RegExp('\\t', 'g'); - - // convert a string into its definition (javascript literal) - var stringToDef = function (str) { - return str.replace(regexpBackslash, '\\\\').replace(regexpQuote, '\\"').replace(regexpCR, '\\r').replace(regexpLF, '\\n').replace(regexpTab, '\\t'); - }; - - var resources = {}; // resource tree, loaded from data/resources.json in the boot sequence + regexpGt = new RegExp('>', 'g'); // event dispatch var eventListeners = {}, // keyed by event name, value is an array of listeners @@ -211,144 +198,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ }, 0); }; - var tokenize = function (line) { - var result = [], - N = line.length, - i = 0, // character index into line - storedAtom = null, // the previous atom, to decide whether to store a string or an object {key:'', value:''} - atom = [], // currently parsed content - isKeyValue = false, - storeAtom = function () { - if (atom.length == 0) return; - if (storedAtom === null) storedAtom = atom.join(''); - else if (isKeyValue) { - result.push({'key': storedAtom, 'value': atom.join('')}); - storedAtom = null; - isKeyValue = false; - } - else { - result.push(storedAtom); - storedAtom = atom.join(''); - } - atom.length = 0; - }, - c, q; - - while (i < N) { - c = line[i++]; - switch (c) { - // end-of-atom characters - case ' ': - case '\r': - case '\n': - case '\t': - storeAtom(); - break; - - // escape character - case '\\': - if (i < N) atom.push(line[i++]); - break; - - // key-value delimiter character - case '=': - if (storedAtom) { - if (isKeyValue) atom.push(c); - else if (atom.length == 0) isKeyValue = true; // must have been a whitespace before "=" - else { - storeAtom(); - isKeyValue = true; - } - } - else atom.push(c); // "=" is delimiter only before the value, not before the key - break; - - // quoted string - case '"': - case "'": - stringConsume: - while (i < N) { - q = line[i++]; - switch (q) { - case '\\': - if (i < N) atom.push(line[i++]); - break; - case c: - break stringConsume; - default: - atom.push(q); - break; - } - } - break; - - default: - atom.push(c); - break; - } - } - // purge anything in cache - storeAtom(); - if (storedAtom !== null) result.push(storedAtom); - return result; - }; - - var resolveResource = function (resourceName, resourceBranches) { - var traversedPath = ['data'], // top-level directory - branch = resources, - candidate = null, - i, fragment; - if (!resourceName) { - codeq.log.error('No resource name provided; path: "' + resourceBranches.join('/') + '"'); - return null; - } - if (branch[resourceName]) candidate = 'data/' + resourceName; // top-level match - for (i = 0; i < resourceBranches.length; i++) { - fragment = resourceBranches[i]; - branch = branch[fragment]; - if (!branch) { - codeq.log.error('Resource sub-branch ' + fragment + ' does not exist; resource: "' + resourceName + '", path: "' + resourceBranches.join('/') + '"'); - break; - } - traversedPath.push(fragment); - if (branch[resourceName]) candidate = traversedPath.join('/') + '/' + resourceName; - } - if (candidate) return codeq.ajaxPrefix + candidate; - codeq.log.error('Resource ' + resourceName + ' was not found; path: "' + resourceBranches.join('/') + '"'); - return null; - }; - - var directiveHandlers = { - 'resource': function (code, tokens, templatePath) { - code.push('_result.push("', resolveResource(tokens[1], templatePath) || 'data/broken.png', '");\n'); - }, - - 'img': function (code, tokens, templatePath) { - var N = tokens.length, - attrs = [], - token, i; - for (i = 1; i < N; i++) { - token = tokens[i]; - if (!token || typeof token !== 'object') { - codeq.log.error('Invalid token at position ' + i + ' in @img'); - continue; - } - switch (token.key) { - case 'src': - attrs.push('src="' + resolveResource(token.value, templatePath) + '"'); - break; - case 'alt': - attrs.push('alt="' + codeq.escapeHtml(token.value) + '"'); - break; - case 'class': - attrs.push('class="' + token.value + '"'); - break; - } - } - code.push('_result.push("<img ', attrs.join(' ').replace(regexpQuote, '\\"'), '>");\n'); - } - }; - var makeActivityHandler = function (editor, problem_id) { var lastActivityMillis = Date.now(), deltaActivityMillis = function deltaActivityMillisFunc () { @@ -439,10 +288,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ return codeq.settings['gui_lang']; }, - 'setResources': function (newResources) { - resources = newResources; - }, - 'escapeHtml': function (s) { return ('' + s).replace(regexpAmp, '&').replace(regexpLt, '<').replace(regexpGt, '>'); }, @@ -484,101 +329,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ }); }, - 'templator': function (str, templatePath, templateName) { - var f, parts, i, subparts, subpart, - src = [ 'var _result = [], echo = function (s) { _result.push(s); };\n' ], - atoms, j, atom, debugPrefix, s, r, tokens, handler; - - if (!templateName) templateName = 'unknown template'; - debugPrefix = '[' + templateName + ']'; - if (!templatePath) templatePath = []; - - // remove comments - parts = str.split('[%--'); // break on start-of-comment - atoms = [ parts[0] ]; // first part is not a comment - for (i = 1; i < parts.length; i++) { // iterate over start-of-comments - atom = parts[i].split('--%]'); // break on end-of-comment - if (atom.length > 1) { // if end-of-comment was encountered - atoms.push(atom[1]); // add whatever is trailing it - for (j = 2; j < atom.length; j++) { // re-add even dangling end-of-comments - atoms.push('--%]'); - atoms.push(atom[j]); - } - } - } - - // start processing - parts = atoms.join('').split('[%'); - - if (parts[0].length > 0) src.push('_result.push("', stringToDef(parts[0]), '");\n'); // the first part that doesn't begin with '[%' - for (i = 1; i < parts.length; i++) { // for every part that begins with '[%' - if (parts[i].slice(0, 2) === '--') { // a comment start - subparts = parts[i].split('--%]'); // split at comment end - } - else { // a start of a statement or of a value reference - subparts = parts[i].split('%]'); // there should be only one terminating '%]', find it - subpart = subparts[0].replace(regexpWhiteSpaceStart, '').replace(regexpWhiteSpaceEnd, ''); // trim the white space - if (subpart.length > 0) { - if (subpart[0] === '=') { // a value reference - s = subpart.slice(1); - r = regexpWhiteSpaceTrim.exec(s); - r = r && r[1] || s; - src.push('_result.push(typeof this.', r, ' === \'undefined\' ? \'', r, ' missing\' : this.', r, ');\n'); - } - else if (subpart[0] === '@') { // a directive - tokens = tokenize(subpart.slice(1)); - if (tokens.length === 0) { - codeq.log.error('An empty directive in ' + templateName); - } - else { - handler = directiveHandlers[tokens[0]]; - if (!handler) { - codeq.log.error('An unknown directive in ' + templateName + ': ' + tokens[0]); - } - else { - handler(src, tokens, templatePath); - } - } - } - else { // javascript statement(s) - src.push(subpart, '\n'); - } - } - } - if ((subparts.length > 1) && (subparts[1].length > 0)) { // there's a trailing text - src.push('_result.push("', stringToDef(subparts[1]), '");\n'); - } - } - src.push('return _result.join("");'); -// if (_internalDoLog_) codeq.log.debug('createTemplate(): ' + debugPrefix + ' creating templating function:\nfunction(_components_) {\n' + src.join('') + '\n}\n=== Created from template: ===\n' + str); - try { - f = new Function(src.join('')); // create a function based on the given template - } - catch (e) { - codeq.log.error('createTemplate(): ' + debugPrefix + ' Failed to instantiate template function: ' + e + '\nfunction() {\n' + src.join('') + '\n}\n=== Created from template: ===\n' + str, e); - throw e; - } - - return function (args) { - var esc = codeq.escapeHtml, - escArgs = {}, - key; - if ((typeof args === 'object') && (args !== null)) { - for (key in args) { - if (!args.hasOwnProperty(key)) continue; - escArgs[key] = esc(args[key]); - } - } - try { - return f.apply(escArgs); - } - catch (e) { - codeq.log.error('Error evaluating template ' + templateName + ' function: ' + e + '\nfunction() {\n' + src.join('') + '\nCreated from template:\n' + str, e); - throw e; - } - }; - }, - // codeq event handling 'fire': function (eventName, args) { |