summaryrefslogtreecommitdiff
path: root/js/codeq.js
diff options
context:
space:
mode:
authorAleš Smodiš <aless@guru.si>2015-07-13 17:56:49 +0200
committerAleš Smodiš <aless@guru.si>2015-07-13 17:56:49 +0200
commit5f8015714f94a7d1785cf148c257d3be72d1e6c9 (patch)
treed28b2b6bc0941db81d1dff943408a6339f621a8b /js/codeq.js
Initial commit: bare page for Prolog tasks with editor and command prompt, lightweight task definition parser of pythonic assignment statements.
Diffstat (limited to 'js/codeq.js')
-rw-r--r--js/codeq.js742
1 files changed, 742 insertions, 0 deletions
diff --git a/js/codeq.js b/js/codeq.js
new file mode 100644
index 0000000..3a30823
--- /dev/null
+++ b/js/codeq.js
@@ -0,0 +1,742 @@
+// introduce the namespace object for codeq
+window.codeq = {};
+window.siteDefinition = { logLevel: 'debug' }; // for debug purposes
+
+(function () {
+
+ // regular expressions for the templating function, the logging system, etc.
+ var regexpQuote = new RegExp('"', 'g'),
+ regexpBackslash = new RegExp('\\\\', 'g'),
+ regexpWhiteSpaceStart = new RegExp('^[ \r\n\t]+'),
+ regexpWhiteSpaceEnd = new RegExp('[ \r\n\t]+$'),
+ regexpWhiteSpaceNonPrintable = new RegExp('[\r\n\t]', 'g'),
+ regexpWhiteSpaceBeforeTag = new RegExp('[ \r\n\t]+(?=<)', 'g'),
+ regexpWhiteSpaceAfterTag = new RegExp('>[ \r\n\t]+', 'g'),
+ regexpIKeyMarker = new RegExp('(?:^|\\s)(ikey-marker.*)(?:$|\\s)'),
+ regexpWhiteSpace = new RegExp('[ \\r\\n\\t]+');
+
+ // ================================================================================
+ // The log module: contains methods for logging, sending logs to the server
+ // ================================================================================
+
+ var jsonize; // JSONization function
+
+ if (JSON && JSON.stringify) {
+ jsonize = JSON.stringify;
+ }
+ else {
+ jsonize = function (obj) {
+ var t, buffer, i, isFirst;
+ if (null === obj) return 'null';
+ t = typeof obj;
+ if (t === 'string') {
+ return '"' + obj.replace(regexpBackslash, '\\\\').replace(regexpQuote, '\\"') + '"';
+ }
+ if (t === 'number') {
+ if (isFinite(obj)) return obj.toString();
+ throw new Error('Cannot jsonize a non-finite number: ' + obj.toString());
+ }
+ if (t === 'boolean') {
+ if (obj) return 'true';
+ return 'false';
+ }
+ if (t === 'object') {
+ if (obj instanceof String) return jsonize(obj.valueOf());
+ if (obj instanceof Number) return jsonize(obj.valueOf());
+ if (obj instanceof Boolean) return jsonize(obj.valueOf());
+ if (obj instanceof Array) {
+ buffer = [ '[' ];
+ isFirst = true;
+ for (i = 0; i < obj.length; i++) {
+ if (isFirst) isFirst = false;
+ else buffer.push(',');
+ buffer.push(jsonize(obj[i]));
+ }
+ buffer.push(']');
+ return buffer.join('');
+ }
+ buffer = [ '{' ];
+ isFirst = true;
+ for (i in obj) {
+ if (isFirst) isFirst = false;
+ else buffer.push(',');
+ buffer.push(jsonize(i), ':', jsonize(obj[i]));
+ }
+ buffer.push('}');
+ return buffer.join('');
+ }
+ throw new Error('Cannot jsonize ' + t);
+ };
+ }
+
+ codeq.log = {};
+ (function () {
+ var assembleOutput = function (stuff, e) {
+ var lines = [ stuff ];
+ if (e && e.stack) lines.push(e.stack);
+ return lines.join('\n');
+ };
+
+ if (window.siteDefinition && window.siteDefinition.logService) {
+ var url = window.siteDefinition.logService,
+ logs = [],
+ storeLog = function (level, stuff, e) {
+ logs.push({
+ 't': Date.now(),
+ 'l': level,
+ 'm': assembleOutput(stuff, e)
+ });
+ };
+ if (window.siteDefinition && (window.siteDefinition.logLevel == 'debug')) {
+ codeq.log.debug = function (stuff, e) { storeLog('debug', stuff, e); };
+ }
+ else codeq.log.debug = function () {};
+
+ if (window.siteDefinition && ((window.siteDefinition.logLevel == 'info') || (window.siteDefinition.logLevel == 'debug'))) {
+ codeq.log.info = function (stuff, e) { storeLog('info', stuff, e); };
+ }
+ else codeq.log.info = function () {};
+
+ codeq.log.error = function (stuff, e) { storeLog('error', stuff, e); };
+
+ setInterval(function () {
+ var copyOfLogs;
+ if (logs.length < 1) return;
+ copyOfLogs = jsonize({'logs': logs});
+ logs = [];
+ $.ajax({
+ contentType: 'application/json',
+ dataType: 'application/json',
+ type: 'POST',
+ url: url,
+ data: copyOfLogs,
+ error: function (jqXHR, textStatus, errorThrown) {
+ if (window.console && console.log) console.log(assembleOutput('Posting of logs to ' + url + ' failed: ' + textStatus, errorThrown));
+ else dump(assembleOutput('Posting of logs to ' + url + ' failed: ' + textStatus, errorThrown));
+ },
+ success: function (data, textStatus, jqXHR) {
+ }
+ });
+ }, 1000);
+ }
+ else if (window.console && console.log) {
+ if (window.siteDefinition && (window.siteDefinition.logLevel == 'debug')) {
+ codeq.log.debug = function (stuff, e) { console.log(assembleOutput('DEBUG: ' + stuff, e)); };
+ }
+ else codeq.log.debug = function () {};
+
+ if (window.siteDefinition && ((window.siteDefinition.logLevel == 'info') || (window.siteDefinition.logLevel == 'debug'))) {
+ codeq.log.info = function (stuff, e) { console.log(assembleOutput('INFO: ' + stuff, e)); };
+ }
+ else codeq.log.info = function () {};
+
+ codeq.log.error = function (stuff, e) { console.log(assembleOutput('ERROR: ' + stuff, e)); };
+ }
+ else {
+ if (window.siteDefinition && (window.siteDefinition.logLevel == 'debug')) {
+ codeq.log.debug = function (stuff, e) { dump(assembleOutput('DEBUG: ' + stuff, e)); };
+ }
+ else codeq.log.debug = function () {};
+
+ if (window.siteDefinition && ((window.siteDefinition.logLevel == 'info') || (window.siteDefinition.logLevel == 'debug'))) {
+ codeq.log.info = function (stuff, e) { dump(assembleOutput('INFO: ' + stuff, e)); };
+ }
+ else codeq.log.info = function () {};
+
+ codeq.log.error = function (stuff, e) { dump(assembleOutput('ERROR: ' + stuff, e)); };
+ }
+ })();
+
+ // ================================================================================
+ // The system module: contains essential methods for the operation of the app
+ // ================================================================================
+
+ // --------------------------------------------------------------------------------
+ // The templating part: the createTemplate() and its utility functions
+ // --------------------------------------------------------------------------------
+
+ // jQuery extension
+ jQuery.fn.makeUnselectable = function () {
+ this.attr("unselectable", "on").attr("draggable", "false");
+ this.find("*").attr("unselectable", "on").attr("draggable", "false");
+ return this;
+ };
+
+ var
+ emptyConstObject = {}; // for use as a default read-only parameter in various methods, so we don't instantiate empty objects for no reason
+
+ // convert a string into its definition
+ var stringToDef = function (str) {
+ return str.replace(regexpBackslash, '\\\\').replace(regexpQuote, '\\"').replace(regexpWhiteSpaceNonPrintable, ' ');
+ };
+
+ // given a HTML source, remove whitespace among tags
+ var cleanHtml = function (html) {
+ // JavaScript doesn't support lookbehind, so we use the split-join trick
+ return html.replace(regexpWhiteSpaceBeforeTag, '').split(regexpWhiteSpaceAfterTag).join('>');
+ };
+
+ var trailingBackslashCount = function (s) {
+ var n = 0, i = s.length - 1;
+ while ((i >= 0) && (s.charAt(i) === '\\')) {
+ n++;
+ i--;
+ }
+ return n;
+ };
+
+ /**
+ * Takes a string of "argName=argValue" arguments separated with a comma.
+ * Creates and returns an array of arguments, where each argument is
+ * represented as an object in the form { name: "argName", value: "argValue" }.
+ * Heading and trailing whitespace is auto-removed.
+ */
+ var splitComponentArguments = function (s) {
+ var commaParts = s.split(','),
+ args = [], // array of arguments, an argument is an object with the properties name and value (atomL and atomR)
+ doubleParts, singleParts, i, atom, j, k, l,
+ doublePart, singlePart, doubleLastIndex, singleLastIndex,
+ equalsParts, atomL, atomR,
+ singleOpen = false, doubleOpen = false;
+
+ atom = []; // substrings of the currently assembling atom
+ atomL = false; // the left-side atom
+ atomR = false; // the right-side atom, between them is an equals sign
+ for (i = 0; i < commaParts.length; i++) {
+ doubleParts = commaParts[i].split('"'); // first split after double quotes
+ doubleLastIndex = doubleParts.length - 1;
+ for (j = 0; j < doubleParts.length; j++) { // and process the parts
+ doublePart = doubleParts[j];
+ singleParts = doublePart.split("'"); // split after single quotes
+ singleLastIndex = singleParts.length - 1;
+ for (k = 0; k < singleParts.length; k++) { // process the parts delimited by single quotes
+ if (atomL || singleOpen || doubleOpen) { // left side of the assignment was already found, or quotes are active
+ atom.push(singleParts[k]); // don't search for the equals sign
+ }
+ else { // we don't have the left side of the assignment yet and no quotes are open
+ equalsParts = singleParts[k].split('='); // search for the equals sign
+ atom.push(equalsParts[0]);
+ if (equalsParts.length > 1) { // equals sign was found: we have the left side of the assignment
+ atomL = jQuery.trim(atom.join('')); // store the left side of the assignment
+ if (atomL === '') throw new Error('splitComponentArguments(): left side of the argument at index ' + args.length + ' is empty: ' + s);
+ atom = []; // and reset the atom buffer
+ atom.push(equalsParts[1]); // save the rest into the atom buffer
+ for (l = 2; l < equalsParts.length; l++) { // there may be more than 1 equals sign, store them, too
+ atom.push('=');
+ atom.push(equalsParts[l]);
+ }
+ }
+ }
+ if (k < singleLastIndex) { // the last item does not have a quote attached
+ atom.push("'");
+ if (!doubleOpen) {
+ if ((trailingBackslashCount(singleParts[k]) % 2) == 0) singleOpen = !singleOpen;
+ }
+ }
+ }
+ if (j < doubleLastIndex) { // the last item does not have a quote attached
+ atom.push('"');
+ if (!singleOpen) {
+ if ((trailingBackslashCount(doublePart) % 2) == 0) doubleOpen = !doubleOpen;
+ }
+ }
+ }
+ if (singleOpen || doubleOpen) { // a quote is still open: include the comma
+ atom.push(',');
+ }
+ else { // no open quotes, and a comma or end-of-line encoutered: means end of an atom
+ if (!atomL) throw new Error('splitComponentArguments(): the argument at index ' + args.length + ' does not contain a parameter assignment: ' + s);
+ atomR = jQuery.trim(atom.join(''));
+ args.push({ 'name': atomL, 'value': atomR });
+ atomL = false;
+ atomR = false;
+ atom = [];
+ }
+ }
+
+ if (atomL || (atom.length > 0)) throw new Error('splitComponentArguments(): premature end of the last argument: ' + s);
+
+ return args;
+ };
+
+
+ var QuotesWalker = function (s, isLongQuotes) {
+ var doubleQuotes, singleQuotes, quoteLen, iteration = 0,
+ n = s.length,
+ startCharPos = 0,
+ unescapedIndexOf = function (s, quotes, startPos) {
+ var n = s.length, pos;
+ while (startPos < n) {
+ pos = s.indexOf(quotes, startPos);
+ if (pos <= 0) return pos;
+ if (s.charAt(pos-1) != '\\') return pos;
+ startPos = pos + 1;
+ }
+ return -1;
+ };
+
+ if (isLongQuotes) {
+ doubleQuotes= '"""';
+ singleQuotes = "'''";
+ quoteLen = 3;
+ }
+ else {
+ doubleQuotes= '"';
+ singleQuotes = "'";
+ quoteLen = 1;
+ }
+
+ this.prefixString = '';
+ this.quotedString = '';
+ this.quoteType = '';
+
+ this.next = function () {
+ var doubleQuotePos, singleQuotePos, quotePos, quoteType;
+ iteration++;
+ if (startCharPos >= n) {
+ this.prefixString = '';
+ this.quotedString = '';
+ this.quoteType = '';
+ codeq.log.debug("QuotesWalker #" + iteration + ': no more data, returning false');
+ return false;
+ }
+ // with which quotes to start, single or double?
+ doubleQuotePos = unescapedIndexOf(s, doubleQuotes, startCharPos);
+ singleQuotePos = unescapedIndexOf(s, singleQuotes, startCharPos);
+ if (doubleQuotePos < 0) {
+ if (singleQuotePos < 0) {
+ // the end
+ this.prefixString = s.slice(startCharPos, n);
+ this.quotedString = '';
+ this.quoteType = '';
+ startCharPos = n;
+ codeq.log.debug("QuotesWalker #" + iteration + ': last data, remaining string: ' + this.prefixString);
+ return true;
+ }
+ quotePos = singleQuotePos;
+ quoteType = singleQuotes;
+ }
+ else if (singleQuotePos < 0) {
+ quotePos = doubleQuotePos;
+ quoteType = doubleQuotes;
+ }
+ else if (doubleQuotePos < singleQuotePos) {
+ quotePos = doubleQuotePos;
+ quoteType = doubleQuotes;
+ }
+ else {
+ quotePos = singleQuotePos;
+ quoteType = singleQuotes;
+ }
+ this.quoteType = quoteType;
+
+ this.prefixString = s.slice(startCharPos, quotePos);
+ startCharPos = quotePos + quoteLen;
+ quotePos = unescapedIndexOf(s, quoteType, startCharPos);
+ this.quotedString = s.slice(startCharPos, quotePos);
+ startCharPos = quotePos + quoteLen;
+ codeq.log.debug('QuotesWalker #' + iteration + ': quoteType=' + this.quoteType + ', data:\nprefix=' + this.prefixString + '\nquoted=' + this.quotedString);
+ return true;
+ };
+ };
+
+ var escapePythonicLongString = function (s, output) {
+ var pos = 0,
+ parts = s.split("'"),
+ n = parts.length,
+ i, part, previousPart;
+ output.push("'"); // starting quote
+
+ previousPart = parts[0];
+ output.push(previousPart.split('\r').join('\\r').split('\t').join('\\t').split('\n').join('\\n'));
+ for (i = 1; i < n; i++) {
+ part = parts[i];
+ // first escape the single quote, if required
+ if (previousPart.charAt(previousPart.length - 1) != '\\') output.push('\\');
+ // escape \r, \n, \t
+ output.push(part.split('\r').join('\\r').split('\t').join('\\t').split('\n').join('\\n'));
+ previousPart = part;
+ }
+
+ output.push("'"); // ending quote
+ };
+
+ // the "engine" of codeq
+ codeq.system = {
+ // define XML namespaces, for use in generating HTML content
+ ns: {
+ svg: 'http://www.w3.org/2000/svg'
+ },
+
+ // the method for creating a templating function from the given string template
+ createTemplate: function (str, templateName, _internalDoLog_) {
+ var f, parts, i, subparts, subpart,
+ isSvg = str.substring(0, 4) === '<svg',
+// nodeName = isSvg ? 'tspan' : 'span', // translation container node name, depends on whether this is SVG or HTML
+ src = [ 'var _result = [], _tmp, _counter = 0, echo = function (s) { _result.push(s); };\n' ],
+ componentName, atoms, j, atom, debugPrefix;
+
+ if (!templateName) templateName = 'unknown template';
+ debugPrefix = '[' + templateName + ']';
+
+ // 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(cleanHtml(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
+ src.push('_result.push(', subpart.slice(1), ');\n');
+ }
+ else if (subpart[0] === '@') { // a component directive, this gets processed in two phases
+ atoms = subpart.slice(1).replace(regexpWhiteSpaceStart, ''); // get the whole directive, remove any heading whitespace
+ componentName = atoms.split(regexpWhiteSpace, 1)[0]; // extract the component name
+ atoms = splitComponentArguments(atoms.slice(componentName.length)); // extract the atoms
+ src.push('_tmp={"name":"', stringToDef(componentName), '","params":{},"key":"image"+_counter};\n');
+ src.push('_components_.push(_tmp);\n');
+ src.push('_tmp=_tmp.params;\n');
+ for (j = 0; j < atoms.length; j++) {
+ atom = atoms[j];
+ src.push('_tmp["', stringToDef(atom.name), '"]=', atom.value, ';\n');
+ }
+// src.push('_result.push(\'<', nodeName, ' class="image\', _counter, \'"></', nodeName, '>\');\n');
+ src.push('_result.push(\'<a class="image\', _counter, \'"></a>\');\n');
+ src.push('_counter++;\n');
+ }
+ else { // a statement
+ src.push(subpart, '\n');
+ }
+ }
+ }
+ if ((subparts.length > 1) && (subparts[1].length > 0)) { // there's a trailing text
+ src.push('_result.push("', stringToDef(cleanHtml(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('_components_', src.join('')); // create a function that takes the single argument named _components_ (an array)
+ }
+ catch (e) {
+ codeq.log.error('createTemplate(): ' + debugPrefix + ' Failed to instantiate template function: ' + e + '\nfunction(_components_) {\n' + src.join('') + '\n}\n=== Created from template: ===\n' + str, e);
+ throw e;
+ }
+
+ return function () { // takes params, callback
+ var param, templateParams, callback, html, components = [], i, jq, jqContainer, processDom;
+
+ // parse arguments
+ // first set defaults
+ templateParams = false;
+ callback = false;
+ jqContainer = false;
+ for (i = arguments.length - 1; i >= 0; i--) {
+ param = arguments[i];
+ if (param instanceof Function) {
+ // set the optional callback that will be invoked with a jQuery argument representing the "compiled" template, after the template is all set up
+ if (callback) throw new Error(debugPrefix + ' More than one callback provided to a template function');
+ callback = param;
+ }
+ else if (param instanceof jQuery) {
+ // set the container that will receive the template content, the container is mandatory for SVG
+ if (jqContainer) throw new Error(debugPrefix + ' More than one jQuery container provided to a template function');
+ jqContainer = param;
+ }
+ else if (param instanceof Object) { // BEWARE: this one catches all Objects, so do testing for descendants (e.g.: Function, jQuery) before testing for Object!
+ // set the parameters to the template function, they are optional
+ if (templateParams) throw new Error(debugPrefix + ' More than one object with template parameters provided to a template function');
+ templateParams = param;
+ }
+ else throw new Error(debugPrefix + ' Unknown parameter provided to a template function: ' + typeof param);
+ }
+ // we need at least an empty object for the template function
+ if (!templateParams) templateParams = emptyConstObject;
+ // the container is mandatory for SVG
+ //if (isSvg && !jqContainer) throw new Error(debugPrefix + ' jQuery object is a mandatory parameter to the template function when the template is a SVG object');
+
+ // process DOM, after the template is instantiated
+ processDom = function () {
+ var componentDef, i, finishedIteration, finishComponent, cjq, params, key, variant, variantsCache,
+ iterationCount, currentIteration, newJq;
+
+ jq.data('templateName', templateName); // for debugging
+
+ iterationCount = 1 + components.length; // first one is the sentinel
+ currentIteration = 0; // how many iterations were processed
+ finishedIteration = function () {
+ currentIteration++;
+ if (iterationCount === currentIteration) {
+ jq.makeUnselectable();
+ if (callback) callback(jq, templateParams);
+ }
+ };
+
+ finishComponent = function (cjq, classes, params, reservedParams) {
+ var attrName;
+ if (params['class']) classes.push(params['class']);
+ cjq.attr('class', classes.join(' '));
+ for (attrName in params) {
+ if (attrName === 'class') continue; // a fixed reserved parameter
+ if (attrName in reservedParams) continue; // reserved parameters as specified by the corresponding handler
+ cjq.attr(attrName, params[attrName]); // set the attribute
+ }
+ finishedIteration();
+ };
+
+ for (i = 0; i < components.length; i++) {
+ componentDef = components[i];
+ params = componentDef.params;
+ cjq = jq.find('.' + componentDef.key);
+ if (cjq.length == 0) {
+ if (jq.hasClass(componentDef.key)) cjq = jq;
+ }
+ if (cjq.length == 0) {
+ codeq.log.error('codeq.system.createTemplate::fn(): internal error: could not obtain reference to a template component of type ' + componentDef.name + ', key=' + componentDef.key);
+ continue;
+ }
+ if (_internalDoLog_) codeq.log.debug('codeq.system.createTemplate::fn(): ' + debugPrefix + ' searching for a component with class ' + componentDef.key + ', found ' + cjq.length);
+ isSvg = 'ownerSVGElement' in cjq[0];
+ switch (componentDef.name) {
+ case 'text':
+ key = params.key;
+ if (!key) {
+ codeq.log.error('codeq.system.createTemplate::fn(): ' + debugPrefix + ' A text component is missing the key');
+ finishedIteration();
+ }
+ else {
+ if (isSvg) newJq = $(document.createElementNS(codeq.ns.svg, 'tspan'));
+ else newJq = $('<span></span>');
+ cjq.replaceWith(newJq);
+ if (jq === cjq) jq = newJq;
+ cjq = newJq;
+ cjq.attr('data-tkey', key);
+ translate(cjq);
+ if (_internalDoLog_) codeq.log.debug('codeq.system.createTemplate::fn(): ' + debugPrefix + ' Instantiated intellitext: key=' + key);
+ finishComponent(cjq, ['intellitext'], params, {'key':true});
+ }
+ break;
+ case 'image':
+ key = params.key;
+ if (isSvg) {
+ codeq.log.error('codeq.system.createTemplate::fn(): ' + debugPrefix + ' Currently there is no support for inlining images into SVG');
+ finishedIteration();
+ }
+ else if (!key) {
+ codeq.log.error('codeq.system.createTemplate::fn(): ' + debugPrefix + ' An image component is missing the key');
+ finishedIteration();
+ }
+ else {
+ newJq = $('<span></span>');
+ cjq.replaceWith(newJq);
+ if (jq === cjq) jq = newJq;
+ cjq = newJq;
+ variant = params.variant || 'normal';
+ cjq.attr('data-ikey', key); // HTML5 data
+ cjq.attr('data-ivariant', variant);
+ cjq.data['ikey'] = key; // jQuery data
+ cjq.data['ivariant'] = variant;
+ cjq.data['ivariants'] = variantsCache = {};
+ setButtonVariant(cjq, variantsCache, key, variant, (function (cjq, params, variant) {
+ return function () {
+ if (_internalDoLog_) codeq.log.debug('codeq.system.createTemplate::fn(): ' + debugPrefix + ' Instantiated image: key=' + params.key + ', variant=' + variant);
+ finishComponent(cjq, ['intellimage'], params, {'key':true, 'variant':true});
+ };
+ })(cjq, params, variant));
+ }
+ break;
+ default:
+ codeq.log.error('codeq.system.createTemplate::fn(): ' + debugPrefix + ' Invalid component name: ' + componentDef.name);
+ finishedIteration();
+ break;
+ }
+ }
+ finishedIteration(); // the sentinel
+ };
+
+ // create DOM
+
+ try {
+ html = f.apply(templateParams, [components]);
+ if (_internalDoLog_) {
+ codeq.log.debug('createTemplate(): ' + debugPrefix + ' instantiating template:\n' + html);
+ }
+ }
+ catch (e) {
+ codeq.log.error('createTemplate(): ' + debugPrefix + ' Failed to invoke template function: ' + e + '\nfunction(_components_) {\n' + src.join('') + '\n}\n=== Created from template: ===\n' + str, e);
+ throw e;
+ }
+
+ jq = $(html);
+ if (jqContainer) jqContainer.append(jq);
+ processDom();
+
+ // TODO: what follows is the code that uses SVG jQuery plugin to instantiate SVG DOM, but the created images are not always correctly sized; needs analysis of what is happening
+ /* if (isSvg) {
+ jqContainer.empty().svg({
+ 'loadURL': html,
+ 'initPath': '/js/svg/', // where to load blank.svg from if needed
+ 'changeSize': true, // get the size from the SVG markup, don't retain the existing size of the container
+ 'onLoad': function (jqSvg) {
+ // it should hold that jqContainer == jqSvg, but we ignore the parameter anyway
+ jq = $(jqContainer.children()[0]);
+ processDom();
+ }
+ });
+ }
+ else {
+ jq = $(html);
+ if (jqContainer) jqContainer.append(jq);
+ processDom();
+ }*/
+ };
+ }, // createTemplate
+
+ // --------------------------------------------------------------------------------
+ // Task info parser: converts simplified pythonic syntax to a JavaScript function
+ // --------------------------------------------------------------------------------
+
+ parseInfo: function (infoText) {
+ var parts = [],
+ n, lines, line, i, j, len, walker, fn, obj;
+ // convert pythonic long-strings to ordinary strings, escaping things as we go
+ walker = new QuotesWalker(infoText, true);
+ while (walker.next()) {
+ if (walker.prefixString.length > 0) parts.push(walker.prefixString);
+ if (walker.quotedString.length > 0) escapePythonicLongString(walker.quotedString, parts);
+ }
+
+ // split into separate lines, remove comments, add semicolons
+ lines = parts.join('').split('\n'); // split at line feed characters
+ n = lines.length;
+ for (i = 0; i < n; i++) {
+ line = lines[i];
+ len = line.length;
+ if (len > 0) {
+ // if exists: find the first python's comment character (#) that is not in a string (between two quotes)
+ parts = [];
+ walker = new QuotesWalker(line, false);
+ while (walker.next()) {
+ if (walker.prefixString.length > 0) {
+ j = walker.prefixString.indexOf('#');
+ if (j >= 0) {
+ parts.push(walker.prefixString.slice(0, j));
+ break; // commented out till the EOL
+ }
+ parts.push(walker.prefixString);
+ }
+ parts.push(walker.quoteType);
+ parts.push(walker.quotedString);
+ parts.push(walker.quoteType);
+ }
+
+ line = parts.join('').replace(regexpWhiteSpaceEnd, ''); // trim the white space at the end
+ if ((line.length > 0) && (line[line.length - 1] != ';')) line = line + ';'; // and add a semicolon
+ lines[i] = line;
+ }
+ }
+
+ // compose the function
+ lines.unshift("var description, hint;");
+ lines.push("__params__.description = description;", "__params__.hint = hint;");
+ codeq.log.debug("Creating a new parseInfo function having the body: ");
+ codeq.log.debug(lines);
+ fn = new Function("__params__", lines.join('\n'));
+ obj = {};
+ fn(obj);
+ return obj; // obj now contains "description" and "hint"
+ },
+
+ load: function (request) {
+ $.ajax({
+ contentType: request.contentType,
+ dataType: request.type,
+ type: request.data ? 'POST' : 'GET',
+ url: request.url + '?_=' + Date.now(),
+ data: request.data,
+ error: function (jqXHR, textStatus, errorThrown) {
+ codeq.log.error('Loading of ' + request.url + ' failed: ' + textStatus, errorThrown);
+ try {
+ if (request.callback) request.callback(null, 'Error: ' + (errorThrown ? '' + errorThrown : textStatus), request.url);
+ }
+ catch (e) {
+ codeq.log.error('Callback with error failed on request ' + request.url + ': ' + e, e);
+ }
+ },
+ success: function (data, textStatus, jqXHR) {
+ try {
+ if (request.callback) request.callback(data, 'OK', request.url);
+ }
+ catch (e) {
+ codeq.log.error('Callback failed on successful request ' + request.url + ': ' + e, e);
+ }
+ }
+ });
+ }
+
+ }; // codeq.system = {
+
+ window.start = function () {
+// var s = location.hash;
+// if (s.length == 0) return; // empty hash
+// if (s.charAt(0) == '#') s = s.substring(1);
+// if (s.length == 0) return; // empty hash
+ var editor = CodeMirror.fromTextArea(document.getElementById('program'), { cursorHeight: 0.85, lineNumbers: true, matchBrackets: true });
+ editor.setValue('sister(X, Y) :-\n female(X),\n parent(Z, X),\n parent(Z, Y),\n X \\== Y.');
+
+/* $('#console').terminal(function (command, term) {
+ term.echo('Not implemented.');
+ }, {
+ prompt: '?- ',
+ history: false,
+ greetings: 'Prolog terminal',
+ outputLimit: 7,
+ exit: false,
+ name: 'prolog_cmd',
+ width: '100%'
+ });*/
+
+ var controller = $('#console').console({
+ promptLabel: '?- ',
+ commandValidate: function (line) {
+ return !!line;
+ },
+ commandHandle: function (line) {
+ return [{msg:'Not implemented.', className:'console-response'}];
+ },
+ autofocus: false,
+ animateScroll: false,
+ promptHistory: false,
+ welcomeMessage: 'Prolog REPL.'
+ });
+
+ codeq.system.load({
+ type: 'text',
+ url: 'sister.py',
+ callback: function (data, status, url) {
+ if (!data) return;
+ var info = codeq.system.parseInfo(data);
+ $('#description').html(info.description);
+ }
+ });
+ };
+})();