Commit 113aec25 by cahrens

eslint corrections

parent 0fb37cee
// Generated by CoffeeScript 1.6.1 /* global CodeMirror, _, XModule, PrettyPrint */
// no-useless-escape disabled because of warnings in regexp expressions within the
// "toXML" code. When the "useless escapes" were removed, some of the unit tests
// failed, but only in Jenkins, indicating browser-specific behavior.
/* eslint no-useless-escape: 0 */
(function() { (function() {
var _this = this, 'use strict';
__hasProp = {}.hasOwnProperty, var hasPropsHelper = {}.hasOwnProperty,
__extends = function(child, parent) { extendsHelper = function(child, parent) {
for (var key in parent) { // This helper method was generated by CoffeeScript. Suppressing eslint warnings.
if (__hasProp.call(parent, key)) child[key] = parent[key]; var key;
for (key in parent) { // eslint-disable-line no-restricted-syntax
if (hasPropsHelper.call(parent, key)) {
child[key] = parent[key]; // eslint-disable-line no-param-reassign
}
} }
function ctor() { function ctor() {
this.constructor = child; this.constructor = child;
} }
ctor.prototype = parent.prototype; ctor.prototype = parent.prototype;
child.prototype = new ctor(); child.prototype = new ctor(); // eslint-disable-line no-param-reassign
child.__super__ = parent.prototype; child.__super__ = parent.prototype; // eslint-disable-line no-param-reassign, no-underscore-dangle
return child; return child;
}; };
this.MarkdownEditingDescriptor = (function(_super) { this.MarkdownEditingDescriptor = (function(_super) {
// The style of these declarations come from CoffeeScript. Rather than rewriting them,
// the eslint warnings are being suppressed.
extendsHelper(MarkdownEditingDescriptor, _super); // eslint-disable-line no-use-before-define
__extends(MarkdownEditingDescriptor, _super); MarkdownEditingDescriptor.multipleChoiceTemplate = '( ) ' + // eslint-disable-line no-use-before-define
(gettext('incorrect')) + '\n( ) ' + (gettext('incorrect')) + '\n(x) ' + (gettext('correct')) + '\n';
MarkdownEditingDescriptor.multipleChoiceTemplate = "( ) " + (gettext('incorrect')) + "\n( ) " + (gettext('incorrect')) + "\n(x) " + (gettext('correct')) + "\n"; MarkdownEditingDescriptor.checkboxChoiceTemplate = '[x] ' + // eslint-disable-line no-use-before-define
(gettext('correct')) + '\n[ ] incorrect\n[x] correct\n';
MarkdownEditingDescriptor.checkboxChoiceTemplate = "[x] " + (gettext('correct')) + "\n[ ] incorrect\n[x] correct\n"; MarkdownEditingDescriptor.stringInputTemplate = '= ' + // eslint-disable-line no-use-before-define
(gettext('answer')) + '\n';
MarkdownEditingDescriptor.stringInputTemplate = "= " + (gettext('answer')) + "\n"; MarkdownEditingDescriptor.numberInputTemplate = '= ' + // eslint-disable-line no-use-before-define
(gettext('answer')) + ' +- 0.001%\n';
MarkdownEditingDescriptor.numberInputTemplate = "= " + (gettext('answer')) + " +- 0.001%\n"; MarkdownEditingDescriptor.selectTemplate = '[[' + // eslint-disable-line no-use-before-define
(gettext('incorrect')) + ', (' + (gettext('correct')) + '), ' + (gettext('incorrect')) + ']]\n';
MarkdownEditingDescriptor.selectTemplate = "[[" + (gettext('incorrect')) + ", (" + (gettext('correct')) + "), " + (gettext('incorrect')) + "]]\n"; MarkdownEditingDescriptor.headerTemplate = '' + // eslint-disable-line no-use-before-define
(gettext('Header')) + '\n=====\n';
MarkdownEditingDescriptor.headerTemplate = "" + (gettext('Header')) + "\n=====\n"; MarkdownEditingDescriptor.explanationTemplate = '[explanation]\n' + // eslint-disable-line no-use-before-define
(gettext('Short explanation')) + '\n[explanation]\n';
MarkdownEditingDescriptor.explanationTemplate = "[explanation]\n" + (gettext('Short explanation')) + "\n[explanation]\n";
function MarkdownEditingDescriptor(element) { function MarkdownEditingDescriptor(element) {
var _this = this; var that = this;
this.toggleCheatsheetVisibility = function() { this.toggleCheatsheetVisibility = function() {
return MarkdownEditingDescriptor.prototype.toggleCheatsheetVisibility.apply(_this, arguments); return MarkdownEditingDescriptor.prototype.toggleCheatsheetVisibility.apply(that, arguments);
}; };
this.toggleCheatsheet = function(e) { this.toggleCheatsheet = function() {
return MarkdownEditingDescriptor.prototype.toggleCheatsheet.apply(_this, arguments); return MarkdownEditingDescriptor.prototype.toggleCheatsheet.apply(that, arguments);
}; };
this.onToolbarButton = function(e) { this.onToolbarButton = function() {
return MarkdownEditingDescriptor.prototype.onToolbarButton.apply(_this, arguments); return MarkdownEditingDescriptor.prototype.onToolbarButton.apply(that, arguments);
}; };
this.onShowXMLButton = function(e) { this.onShowXMLButton = function() {
return MarkdownEditingDescriptor.prototype.onShowXMLButton.apply(_this, arguments); return MarkdownEditingDescriptor.prototype.onShowXMLButton.apply(that, arguments);
}; };
this.element = element; this.element = element;
if ($(".markdown-box", this.element).length !== 0) { if ($('.markdown-box', this.element).length !== 0) {
this.markdown_editor = CodeMirror.fromTextArea($(".markdown-box", element)[0], { this.markdown_editor = CodeMirror.fromTextArea($('.markdown-box', element)[0], {
lineWrapping: true, lineWrapping: true,
mode: null mode: null
}); });
this.setCurrentEditor(this.markdown_editor); this.setCurrentEditor(this.markdown_editor);
// Add listeners for toolbar buttons (only present for markdown editor)
this.element.on('click', '.xml-tab', this.onShowXMLButton); this.element.on('click', '.xml-tab', this.onShowXMLButton);
this.element.on('click', '.format-buttons button', this.onToolbarButton); this.element.on('click', '.format-buttons button', this.onToolbarButton);
this.element.on('click', '.cheatsheet-toggle', this.toggleCheatsheet); this.element.on('click', '.cheatsheet-toggle', this.toggleCheatsheet);
// Hide the XML text area
$(this.element.find('.xml-box')).hide(); $(this.element.find('.xml-box')).hide();
} else { } else {
this.createXMLEditor(); this.createXMLEditor();
...@@ -70,11 +89,9 @@ ...@@ -70,11 +89,9 @@
text: optional argument to override the text passed in via the HTML template text: optional argument to override the text passed in via the HTML template
*/ */
MarkdownEditingDescriptor.prototype.createXMLEditor = function(text) { MarkdownEditingDescriptor.prototype.createXMLEditor = function(text) {
this.xml_editor = CodeMirror.fromTextArea($(".xml-box", this.element)[0], { this.xml_editor = CodeMirror.fromTextArea($('.xml-box', this.element)[0], {
mode: "xml", mode: 'xml',
lineNumbers: true, lineNumbers: true,
lineWrapping: true lineWrapping: true
}); });
...@@ -82,16 +99,15 @@ ...@@ -82,16 +99,15 @@
this.xml_editor.setValue(text); this.xml_editor.setValue(text);
} }
this.setCurrentEditor(this.xml_editor); this.setCurrentEditor(this.xml_editor);
$(this.xml_editor.getWrapperElement()).toggleClass("CodeMirror-advanced"); $(this.xml_editor.getWrapperElement()).toggleClass('CodeMirror-advanced');
return this.xml_editor.refresh(); // Need to refresh to get line numbers to display properly.
this.xml_editor.refresh();
}; };
/* /*
User has clicked to show the XML editor. Before XML editor is swapped in, User has clicked to show the XML editor. Before XML editor is swapped in,
the user will need to confirm the one-way conversion. the user will need to confirm the one-way conversion.
*/ */
MarkdownEditingDescriptor.prototype.onShowXMLButton = function(e) { MarkdownEditingDescriptor.prototype.onShowXMLButton = function(e) {
e.preventDefault(); e.preventDefault();
if (this.cheatsheet && this.cheatsheet.hasClass('shown')) { if (this.cheatsheet && this.cheatsheet.hasClass('shown')) {
...@@ -101,7 +117,8 @@ ...@@ -101,7 +117,8 @@
if (this.confirmConversionToXml()) { if (this.confirmConversionToXml()) {
this.createXMLEditor(MarkdownEditingDescriptor.markdownToXml(this.markdown_editor.getValue())); this.createXMLEditor(MarkdownEditingDescriptor.markdownToXml(this.markdown_editor.getValue()));
this.xml_editor.setCursor(0); this.xml_editor.setCursor(0);
return $(this.element.find('.editor-bar')).hide(); // Hide markdown-specific toolbar buttons
$(this.element.find('.editor-bar')).hide();
} }
}; };
...@@ -109,58 +126,54 @@ ...@@ -109,58 +126,54 @@
Have the user confirm the one-way conversion to XML. Have the user confirm the one-way conversion to XML.
Returns true if the user clicked OK, else false. Returns true if the user clicked OK, else false.
*/ */
MarkdownEditingDescriptor.prototype.confirmConversionToXml = function() { MarkdownEditingDescriptor.prototype.confirmConversionToXml = function() {
return confirm(gettext("If you use the Advanced Editor, this problem will be converted to XML and you will not be able to return to the Simple Editor Interface.\n\nProceed to the Advanced Editor and convert this problem to XML?")); return confirm(gettext('If you use the Advanced Editor, this problem will be converted to XML and you will not be able to return to the Simple Editor Interface.\n\nProceed to the Advanced Editor and convert this problem to XML?')); // eslint-disable-line max-len, no-alert
}; };
/* /*
Event listener for toolbar buttons (only possible when markdown editor is visible). Event listener for toolbar buttons (only possible when markdown editor is visible).
*/ */
MarkdownEditingDescriptor.prototype.onToolbarButton = function(e) { MarkdownEditingDescriptor.prototype.onToolbarButton = function(e) {
var revisedSelection, selection; var revisedSelection, selection;
e.preventDefault(); e.preventDefault();
selection = this.markdown_editor.getSelection(); selection = this.markdown_editor.getSelection();
revisedSelection = null; revisedSelection = null;
switch ($(e.currentTarget).attr('class')) { switch ($(e.currentTarget).attr('class')) {
case "multiple-choice-button": case 'multiple-choice-button':
revisedSelection = MarkdownEditingDescriptor.insertMultipleChoice(selection); revisedSelection = MarkdownEditingDescriptor.insertMultipleChoice(selection);
break; break;
case "string-button": case 'string-button':
revisedSelection = MarkdownEditingDescriptor.insertStringInput(selection); revisedSelection = MarkdownEditingDescriptor.insertStringInput(selection);
break; break;
case "number-button": case 'number-button':
revisedSelection = MarkdownEditingDescriptor.insertNumberInput(selection); revisedSelection = MarkdownEditingDescriptor.insertNumberInput(selection);
break; break;
case "checks-button": case 'checks-button':
revisedSelection = MarkdownEditingDescriptor.insertCheckboxChoice(selection); revisedSelection = MarkdownEditingDescriptor.insertCheckboxChoice(selection);
break; break;
case "dropdown-button": case 'dropdown-button':
revisedSelection = MarkdownEditingDescriptor.insertSelect(selection); revisedSelection = MarkdownEditingDescriptor.insertSelect(selection);
break; break;
case "header-button": case 'header-button':
revisedSelection = MarkdownEditingDescriptor.insertHeader(selection); revisedSelection = MarkdownEditingDescriptor.insertHeader(selection);
break; break;
case "explanation-button": case 'explanation-button':
revisedSelection = MarkdownEditingDescriptor.insertExplanation(selection); revisedSelection = MarkdownEditingDescriptor.insertExplanation(selection);
break; break;
default:
break;
} }
if (revisedSelection !== null) { if (revisedSelection !== null) {
this.markdown_editor.replaceSelection(revisedSelection); this.markdown_editor.replaceSelection(revisedSelection);
return this.markdown_editor.focus(); this.markdown_editor.focus();
} }
}; };
/* /*
Event listener for toggling cheatsheet (only possible when markdown editor is visible). Event listener for toggling cheatsheet (only possible when markdown editor is visible).
*/ */
MarkdownEditingDescriptor.prototype.toggleCheatsheet = function(e) { MarkdownEditingDescriptor.prototype.toggleCheatsheet = function(e) {
var _this = this; var that = this;
e.preventDefault(); e.preventDefault();
if (!$(this.markdown_editor.getWrapperElement()).find('.simple-editor-cheatsheet')[0]) { if (!$(this.markdown_editor.getWrapperElement()).find('.simple-editor-cheatsheet')[0]) {
this.cheatsheet = $($('#simple-editor-cheatsheet').html()); this.cheatsheet = $($('#simple-editor-cheatsheet').html());
...@@ -168,15 +181,13 @@ ...@@ -168,15 +181,13 @@
} }
this.toggleCheatsheetVisibility(); this.toggleCheatsheetVisibility();
return setTimeout((function() { return setTimeout((function() {
return _this.cheatsheet.toggleClass('shown'); return that.cheatsheet.toggleClass('shown');
}), 10); }), 10);
}; };
/* /*
Function to toggle cheatsheet visibility. Function to toggle cheatsheet visibility.
*/ */
MarkdownEditingDescriptor.prototype.toggleCheatsheetVisibility = function() { MarkdownEditingDescriptor.prototype.toggleCheatsheetVisibility = function() {
return $('.modal-content').toggleClass('cheatsheet-is-shown'); return $('.modal-content').toggleClass('cheatsheet-is-shown');
}; };
...@@ -184,8 +195,6 @@ ...@@ -184,8 +195,6 @@
/* /*
Stores the current editor and hides the one that is not displayed. Stores the current editor and hides the one that is not displayed.
*/ */
MarkdownEditingDescriptor.prototype.setCurrentEditor = function(editor) { MarkdownEditingDescriptor.prototype.setCurrentEditor = function(editor) {
if (this.current_editor) { if (this.current_editor) {
$(this.current_editor.getWrapperElement()).hide(); $(this.current_editor.getWrapperElement()).hide();
...@@ -200,8 +209,6 @@ ...@@ -200,8 +209,6 @@
result in a new instance of the descriptor. Note that this is NOT the case for cancel-- result in a new instance of the descriptor. Note that this is NOT the case for cancel--
when cancel is called the instance of the descriptor is reused if edit is selected again. when cancel is called the instance of the descriptor is reused if edit is selected again.
*/ */
MarkdownEditingDescriptor.prototype.save = function() { MarkdownEditingDescriptor.prototype.save = function() {
this.element.off('click', '.xml-tab', this.changeEditor); this.element.off('click', '.xml-tab', this.changeEditor);
this.element.off('click', '.format-buttons button', this.onToolbarButton); this.element.off('click', '.format-buttons button', this.onToolbarButton);
...@@ -222,23 +229,30 @@ ...@@ -222,23 +229,30 @@
}; };
MarkdownEditingDescriptor.insertMultipleChoice = function(selectedText) { MarkdownEditingDescriptor.insertMultipleChoice = function(selectedText) {
return MarkdownEditingDescriptor.insertGenericChoice(selectedText, '(', ')', MarkdownEditingDescriptor.multipleChoiceTemplate); return MarkdownEditingDescriptor.insertGenericChoice(selectedText, '(', ')',
MarkdownEditingDescriptor.multipleChoiceTemplate
);
}; };
MarkdownEditingDescriptor.insertCheckboxChoice = function(selectedText) { MarkdownEditingDescriptor.insertCheckboxChoice = function(selectedText) {
return MarkdownEditingDescriptor.insertGenericChoice(selectedText, '[', ']', MarkdownEditingDescriptor.checkboxChoiceTemplate); return MarkdownEditingDescriptor.insertGenericChoice(selectedText, '[', ']',
MarkdownEditingDescriptor.checkboxChoiceTemplate
);
}; };
MarkdownEditingDescriptor.insertGenericChoice = function(selectedText, choiceStart, choiceEnd, template) { MarkdownEditingDescriptor.insertGenericChoice = function(selectedText, choiceStart, choiceEnd, template) {
var cleanSelectedText, line, lines, revisedLines, _i, _len; var cleanSelectedText, line, lines, revisedLines, i, len;
if (selectedText.length > 0) { if (selectedText.length > 0) {
// Replace adjacent newlines with a single newline, strip any trailing newline
cleanSelectedText = selectedText.replace(/\n+/g, '\n').replace(/\n$/, ''); cleanSelectedText = selectedText.replace(/\n+/g, '\n').replace(/\n$/, '');
lines = cleanSelectedText.split('\n'); lines = cleanSelectedText.split('\n');
revisedLines = ''; revisedLines = '';
for (_i = 0, _len = lines.length; _i < _len; _i++) { for (i = 0, len = lines.length; i < len; i++) {
line = lines[_i]; line = lines[i];
revisedLines += choiceStart; revisedLines += choiceStart;
// a stand alone x before other text implies that this option is "correct"
if (/^\s*x\s+(\S)/i.test(line)) { if (/^\s*x\s+(\S)/i.test(line)) {
// Remove the x and any initial whitespace as long as there's more text on the line
line = line.replace(/^\s*x\s+(\S)/i, '$1'); line = line.replace(/^\s*x\s+(\S)/i, '$1');
revisedLines += 'x'; revisedLines += 'x';
} else { } else {
...@@ -253,23 +267,33 @@ ...@@ -253,23 +267,33 @@
}; };
MarkdownEditingDescriptor.insertStringInput = function(selectedText) { MarkdownEditingDescriptor.insertStringInput = function(selectedText) {
return MarkdownEditingDescriptor.insertGenericInput(selectedText, '= ', '', MarkdownEditingDescriptor.stringInputTemplate); return MarkdownEditingDescriptor.insertGenericInput(selectedText, '= ', '',
MarkdownEditingDescriptor.stringInputTemplate
);
}; };
MarkdownEditingDescriptor.insertNumberInput = function(selectedText) { MarkdownEditingDescriptor.insertNumberInput = function(selectedText) {
return MarkdownEditingDescriptor.insertGenericInput(selectedText, '= ', '', MarkdownEditingDescriptor.numberInputTemplate); return MarkdownEditingDescriptor.insertGenericInput(selectedText, '= ', '',
MarkdownEditingDescriptor.numberInputTemplate
);
}; };
MarkdownEditingDescriptor.insertSelect = function(selectedText) { MarkdownEditingDescriptor.insertSelect = function(selectedText) {
return MarkdownEditingDescriptor.insertGenericInput(selectedText, '[[', ']]', MarkdownEditingDescriptor.selectTemplate); return MarkdownEditingDescriptor.insertGenericInput(selectedText, '[[', ']]',
MarkdownEditingDescriptor.selectTemplate
);
}; };
MarkdownEditingDescriptor.insertHeader = function(selectedText) { MarkdownEditingDescriptor.insertHeader = function(selectedText) {
return MarkdownEditingDescriptor.insertGenericInput(selectedText, '', '\n====\n', MarkdownEditingDescriptor.headerTemplate); return MarkdownEditingDescriptor.insertGenericInput(selectedText, '', '\n====\n',
MarkdownEditingDescriptor.headerTemplate
);
}; };
MarkdownEditingDescriptor.insertExplanation = function(selectedText) { MarkdownEditingDescriptor.insertExplanation = function(selectedText) {
return MarkdownEditingDescriptor.insertGenericInput(selectedText, '[explanation]\n', '\n[explanation]', MarkdownEditingDescriptor.explanationTemplate); return MarkdownEditingDescriptor.insertGenericInput(selectedText, '[explanation]\n', '\n[explanation]',
MarkdownEditingDescriptor.explanationTemplate
);
}; };
MarkdownEditingDescriptor.insertGenericInput = function(selectedText, lineStart, lineEnd, template) { MarkdownEditingDescriptor.insertGenericInput = function(selectedText, lineStart, lineEnd, template) {
...@@ -281,11 +305,12 @@ ...@@ -281,11 +305,12 @@
}; };
MarkdownEditingDescriptor.markdownToXml = function(markdown) { MarkdownEditingDescriptor.markdownToXml = function(markdown) {
var demandHintTags, demandHints, finalXml, responseTypesMarkdown, responseTypesXML, toXml; var demandHintTags = [],
demandHintTags = []; finalDemandHints, finalXml, responseTypesMarkdown, responseTypesXML, toXml;
toXml = function(markdown) { toXml = function(partialMarkdown) {
var xml = markdown, var xml = partialMarkdown,
i, splits, makeParagraph; i, splits, makeParagraph, serializer, responseType, $xml, responseTypesSelector,
inputtype, beforeInputtype, extractHint, demandhints;
var responseTypes = [ var responseTypes = [
'optionresponse', 'multiplechoiceresponse', 'stringresponse', 'numericalresponse', 'choiceresponse' 'optionresponse', 'multiplechoiceresponse', 'stringresponse', 'numericalresponse', 'choiceresponse'
]; ];
...@@ -302,23 +327,24 @@ ...@@ -302,23 +327,24 @@
// <label>question</label> <description>description</description> // <label>question</label> <description>description</description>
xml = xml.replace(/>>([^]+?)<</gm, function(match, questionText) { xml = xml.replace(/>>([^]+?)<</gm, function(match, questionText) {
var result = questionText.split('||'), var result = questionText.split('||'),
label = '<label>' + result[0] + '</label>' + '\n'; label = '<label>' + result[0] + '</label>\n';
// don't add empty <description> tag // don't add empty <description> tag
if (result.length === 1 || !result[1]) { if (result.length === 1 || !result[1]) {
return label; return label;
} }
return label + '<description>' + result[1] + '</description>\n' return label + '<description>' + result[1] + '</description>\n';
}) });
// Pull out demand hints, || a hint || // Pull out demand hints, || a hint ||
var demandhints = ''; demandhints = '';
xml = xml.replace(/(^\s*\|\|.*?\|\|\s*$\n?)+/gm, function(match) { // $\n xml = xml.replace(/(^\s*\|\|.*?\|\|\s*$\n?)+/gm, function(match) { // $\n
var options = match.split('\n'); var inner,
options = match.split('\n');
for (i = 0; i < options.length; i += 1) { for (i = 0; i < options.length; i += 1) {
var inner = /\s*\|\|(.*?)\|\|/.exec(options[i]); inner = /\s*\|\|(.*?)\|\|/.exec(options[i]);
if (inner) { if (inner) {
//safe-lint: disable=javascript-concat-html // safe-lint: disable=javascript-concat-html
demandhints += ' <hint>' + inner[1].trim() + '</hint>\n'; demandhints += ' <hint>' + inner[1].trim() + '</hint>\n';
} }
} }
...@@ -336,16 +362,18 @@ ...@@ -336,16 +362,18 @@
// Returns a little hash with various parts of the hint: // Returns a little hash with various parts of the hint:
// hint: the hint or empty, nothint: the rest // hint: the hint or empty, nothint: the rest
// labelassign: javascript assignment of label attribute, or empty // labelassign: javascript assignment of label attribute, or empty
extractHint = function(text, detectParens) { extractHint = function(inputText, detectParens) {
var curly = /\s*{{(.*?)}}/.exec(text); var text = inputText,
var hint = ''; curly = /\s*{{(.*?)}}/.exec(text),
var label = ''; hint = '',
var parens = false; label = '',
var labelassign = ''; parens = false,
labelassign = '',
labelmatch;
if (curly) { if (curly) {
text = text.replace(curly[0], ''); text = text.replace(curly[0], '');
hint = curly[1].trim(); hint = curly[1].trim();
var labelmatch = /^(.*?)::/.exec(hint); labelmatch = /^(.*?)::/.exec(hint);
if (labelmatch) { if (labelmatch) {
hint = hint.replace(labelmatch[0], '').trim(); hint = hint.replace(labelmatch[0], '').trim();
label = labelmatch[1].trim(); label = labelmatch[1].trim();
...@@ -353,19 +381,19 @@ ...@@ -353,19 +381,19 @@
} }
} }
if (detectParens) { if (detectParens) {
if (text.length >= 2 && text[0] == '(' && text[text.length - 1] == ')') { if (text.length >= 2 && text[0] === '(' && text[text.length - 1] === ')') {
text = text.substring(1, text.length - 1) text = text.substring(1, text.length - 1);
parens = true; parens = true;
} }
} }
return { return {
'nothint': text, nothint: text,
'hint': hint, hint: hint,
'label': label, label: label,
'parens': parens, parens: parens,
'labelassign': labelassign labelassign: labelassign
}; };
} };
// replace selects // replace selects
...@@ -377,18 +405,22 @@ ...@@ -377,18 +405,22 @@
// ]] // ]]
// <optionresponse> // <optionresponse>
// <optioninput> // <optioninput>
// <option correct="True">AAA<optionhint label="Good Job">Yes, multiple choice is the right answer.</optionhint> // <option correct="True">AAA<optionhint label="Good Job">
// Yes, multiple choice is the right answer.
// </optionhint>
// Note: part of the option-response syntax looks like multiple-choice, so it must be processed first. // Note: part of the option-response syntax looks like multiple-choice, so it must be processed first.
xml = xml.replace(/\[\[((.|\n)+?)\]\]/g, function(match, group1) { xml = xml.replace(/\[\[((.|\n)+?)\]\]/g, function(match, group1) {
var textHint, options, optiontag, correct, lines, optionlines, line, correctstr, hintstr, label;
// decide if this is old style or new style // decide if this is old style or new style
if (match.indexOf('\n') == -1) { // OLD style, [[ .... ]] on one line if (match.indexOf('\n') === -1) { // OLD style, [[ .... ]] on one line
var options = group1.split(/\,\s*/g); options = group1.split(/\,\s*/g);
var optiontag = ' <optioninput options="('; optiontag = ' <optioninput options="(';
for (i = 0; i < options.length; i += 1) { for (i = 0; i < options.length; i += 1) {
optiontag += "'" + options[i].replace(/(?:^|,)\s*\((.*?)\)\s*(?:$|,)/g, '$1') + "'" + (i < options.length - 1 ? ',' : ''); optiontag += "'" + options[i].replace(/(?:^|,)\s*\((.*?)\)\s*(?:$|,)/g, '$1') + "'" +
(i < options.length - 1 ? ',' : '');
} }
optiontag += ')" correct="'; optiontag += ')" correct="';
var correct = /(?:^|,)\s*\((.*?)\)\s*(?:$|,)/g.exec(group1); correct = /(?:^|,)\s*\((.*?)\)\s*(?:$|,)/g.exec(group1);
if (correct) { if (correct) {
optiontag += correct[1]; optiontag += correct[1];
} }
...@@ -397,42 +429,44 @@ ...@@ -397,42 +429,44 @@
} }
// new style [[ many-lines ]] // new style [[ many-lines ]]
var lines = group1.split('\n'); lines = group1.split('\n');
var optionlines = '' optionlines = '';
for (i = 0; i < lines.length; i++) { for (i = 0; i < lines.length; i++) {
var line = lines[i].trim(); line = lines[i].trim();
if (line.length > 0) { if (line.length > 0) {
var textHint = extractHint(line, true); textHint = extractHint(line, true);
var correctstr = ' correct="' + (textHint.parens ? 'True' : 'False') + '"'; correctstr = ' correct="' + (textHint.parens ? 'True' : 'False') + '"';
var hintstr = ''; hintstr = '';
if (textHint.hint) { if (textHint.hint) {
var label = textHint.label; label = textHint.label;
if (label) { if (label) {
label = ' label="' + label + '"'; label = ' label="' + label + '"';
} }
hintstr = ' <optionhint' + label + '>' + textHint.hint + '</optionhint>'; hintstr = ' <optionhint' + label + '>' + textHint.hint + '</optionhint>';
} }
optionlines += ' <option' + correctstr + '>' + textHint.nothint + hintstr + '</option>\n' optionlines += ' <option' + correctstr + '>' + textHint.nothint + hintstr +
'</option>\n';
} }
} }
return '\n<optionresponse>\n <optioninput>\n' + optionlines + ' </optioninput>\n</optionresponse>\n\n'; return '\n<optionresponse>\n <optioninput>\n' + optionlines +
' </optioninput>\n</optionresponse>\n\n';
}); });
//_____________________________________________________________________
//
// multiple choice questions // multiple choice questions
// //
xml = xml.replace(/(^\s*\(.{0,3}\).*?$\n*)+/gm, function(match, p) { xml = xml.replace(/(^\s*\(.{0,3}\).*?$\n*)+/gm, function(match) {
var choices = ''; var choices = '',
var shuffle = false; shuffle = false,
var options = match.split('\n'); options = match.split('\n'),
for (var i = 0; i < options.length; i++) { value, inparens, correct,
fixed, hint, result;
for (i = 0; i < options.length; i++) {
options[i] = options[i].trim(); // trim off leading/trailing whitespace options[i] = options[i].trim(); // trim off leading/trailing whitespace
if (options[i].length > 0) { if (options[i].length > 0) {
var value = options[i].split(/^\s*\(.{0,3}\)\s*/)[1]; value = options[i].split(/^\s*\(.{0,3}\)\s*/)[1];
var inparens = /^\s*\((.{0,3})\)\s*/.exec(options[i])[1]; inparens = /^\s*\((.{0,3})\)\s*/.exec(options[i])[1];
var correct = /x/i.test(inparens); correct = /x/i.test(inparens);
var fixed = ''; fixed = '';
if (/@/.test(inparens)) { if (/@/.test(inparens)) {
fixed = ' fixed="true"'; fixed = ' fixed="true"';
} }
...@@ -440,7 +474,7 @@ ...@@ -440,7 +474,7 @@
shuffle = true; shuffle = true;
} }
var hint = extractHint(value); hint = extractHint(value);
if (hint.hint) { if (hint.hint) {
value = hint.nothint; value = hint.nothint;
value = value + ' <choicehint' + hint.labelassign + '>' + hint.hint + '</choicehint>'; value = value + ' <choicehint' + hint.labelassign + '>' + hint.hint + '</choicehint>';
...@@ -448,7 +482,7 @@ ...@@ -448,7 +482,7 @@
choices += ' <choice correct="' + correct + '"' + fixed + '>' + value + '</choice>\n'; choices += ' <choice correct="' + correct + '"' + fixed + '>' + value + '</choice>\n';
} }
} }
var result = '<multiplechoiceresponse>\n'; result = '<multiplechoiceresponse>\n';
if (shuffle) { if (shuffle) {
result += ' <choicegroup type="MultipleChoice" shuffle="true">\n'; result += ' <choicegroup type="MultipleChoice" shuffle="true">\n';
} else { } else {
...@@ -464,11 +498,11 @@ ...@@ -464,11 +498,11 @@
// [.] with {{...}} lines mixed in // [.] with {{...}} lines mixed in
xml = xml.replace(/(^\s*((\[.?\])|({{.*?}})).*?$\n*)+/gm, function(match) { xml = xml.replace(/(^\s*((\[.?\])|({{.*?}})).*?$\n*)+/gm, function(match) {
var groupString = '<choiceresponse>\n', var groupString = '<choiceresponse>\n',
options, value, correct; options = match.split('\n'),
value, correct, abhint, endHints, hintbody,
hint, inner, select, hints;
groupString += ' <checkboxgroup>\n'; groupString += ' <checkboxgroup>\n';
options = match.split('\n');
endHints = ''; // save these up to emit at the end endHints = ''; // save these up to emit at the end
for (i = 0; i < options.length; i += 1) { for (i = 0; i < options.length; i += 1) {
...@@ -476,31 +510,37 @@ ...@@ -476,31 +510,37 @@
// detect the {{ ((A*B)) ...}} case first // detect the {{ ((A*B)) ...}} case first
// emits: <compoundhint value="A*B">AB hint</compoundhint> // emits: <compoundhint value="A*B">AB hint</compoundhint>
var abhint = /^\s*{{\s*\(\((.*?)\)\)(.*?)}}/.exec(options[i]); abhint = /^\s*{{\s*\(\((.*?)\)\)(.*?)}}/.exec(options[i]);
if (abhint) { if (abhint) {
// lone case of hint text processing outside of extractHint, since syntax here is unique // lone case of hint text processing outside of extractHint, since syntax here is unique
var hintbody = abhint[2]; hintbody = abhint[2];
hintbody = hintbody.replace('&lf;', '\n').trim() hintbody = hintbody.replace('&lf;', '\n').trim();
endHints += ' <compoundhint value="' + abhint[1].trim() + '">' + hintbody + '</compoundhint>\n'; endHints += ' <compoundhint value="' + abhint[1].trim() + '">' + hintbody +
'</compoundhint>\n';
continue; // bail continue; // bail
} }
value = options[i].split(/^\s*\[.?\]\s*/)[1]; value = options[i].split(/^\s*\[.?\]\s*/)[1];
correct = /^\s*\[x\]/i.test(options[i]); correct = /^\s*\[x\]/i.test(options[i]);
hints = ''; hints = '';
// {{ selected: You’re right that apple is a fruit. }, {unselected: Remember that apple is also a fruit.}} // {{ selected: You’re right that apple is a fruit. },
var hint = extractHint(value); // {unselected: Remember that apple is also a fruit.}}
hint = extractHint(value);
if (hint.hint) { if (hint.hint) {
var inner = '{' + hint.hint + '}'; // parsing is easier if we put outer { } back inner = '{' + hint.hint + '}'; // parsing is easier if we put outer { } back
var select = /{\s*(s|selected):((.|\n)*?)}/i.exec(inner); // include \n since we are downstream of extractHint()
// include \n since we are downstream of extractHint()
select = /{\s*(s|selected):((.|\n)*?)}/i.exec(inner);
// checkbox choicehints get their own line, since there can be two of them // checkbox choicehints get their own line, since there can be two of them
// <choicehint selected="true">You’re right that apple is a fruit.</choicehint> // <choicehint selected="true">You’re right that apple is a fruit.</choicehint>
if (select) { if (select) {
hints += '\n <choicehint selected="true">' + select[2].trim() + '</choicehint>'; hints += '\n <choicehint selected="true">' + select[2].trim() +
'</choicehint>';
} }
var select = /{\s*(u|unselected):((.|\n)*?)}/i.exec(inner); select = /{\s*(u|unselected):((.|\n)*?)}/i.exec(inner);
if (select) { if (select) {
hints += '\n <choicehint selected="false">' + select[2].trim() + '</choicehint>'; hints += '\n <choicehint selected="false">' + select[2].trim() +
'</choicehint>';
} }
// Blank out the original text only if the specific "selected" syntax is found // Blank out the original text only if the specific "selected" syntax is found
...@@ -527,16 +567,17 @@ ...@@ -527,16 +567,17 @@
// Line split here, trim off leading xxx= in each function // Line split here, trim off leading xxx= in each function
var answersList = p.split('\n'), var answersList = p.split('\n'),
processNumericalResponse = function(value) { processNumericalResponse = function(val) {
var params, answer, string, textHint, hintLine, value;
// Numeric case is just a plain leading = with a single answer // Numeric case is just a plain leading = with a single answer
value = value.replace(/^\=\s*/, ''); value = val.replace(/^\=\s*/, '');
var params, answer, string;
var textHint = extractHint(value); textHint = extractHint(value);
var hintLine = ''; hintLine = '';
if (textHint.hint) { if (textHint.hint) {
value = textHint.nothint; value = textHint.nothint;
hintLine = ' <correcthint' + textHint.labelassign + '>' + textHint.hint + '</correcthint>\n' hintLine = ' <correcthint' + textHint.labelassign + '>' + textHint.hint +
'</correcthint>\n';
} }
if (_.contains(['[', '('], value[0]) && _.contains([']', ')'], value[value.length - 1])) { if (_.contains(['[', '('], value[0]) && _.contains([']', ')'], value[value.length - 1])) {
...@@ -573,35 +614,39 @@ ...@@ -573,35 +614,39 @@
}, },
processStringResponse = function(values) { processStringResponse = function(values) {
var firstAnswer, textHint, typ, string, orMatch, notMatch;
// First string case is s?= // First string case is s?=
var firstAnswer = values.shift(), string; firstAnswer = values.shift();
firstAnswer = firstAnswer.replace(/^s?\=\s*/, ''); firstAnswer = firstAnswer.replace(/^s?\=\s*/, '');
var textHint = extractHint(firstAnswer); textHint = extractHint(firstAnswer);
firstAnswer = textHint.nothint; firstAnswer = textHint.nothint;
var typ = ' type="ci"'; typ = ' type="ci"';
if (firstAnswer[0] == '|') { // this is regexp case if (firstAnswer[0] === '|') { // this is regexp case
typ = ' type="ci regexp"'; typ = ' type="ci regexp"';
firstAnswer = firstAnswer.slice(1).trim(); firstAnswer = firstAnswer.slice(1).trim();
} }
string = '<stringresponse answer="' + firstAnswer + '"' + typ + ' >\n'; string = '<stringresponse answer="' + firstAnswer + '"' + typ + ' >\n';
if (textHint.hint) { if (textHint.hint) {
string += ' <correcthint' + textHint.labelassign + '>' + textHint.hint + '</correcthint>\n'; string += ' <correcthint' + textHint.labelassign + '>' +
textHint.hint + '</correcthint>\n';
} }
// Subsequent cases are not= or or= // Subsequent cases are not= or or=
for (i = 0; i < values.length; i += 1) { for (i = 0; i < values.length; i += 1) {
var textHint = extractHint(values[i]); textHint = extractHint(values[i]);
var notMatch = /^not\=\s*(.*)/.exec(textHint.nothint); notMatch = /^not\=\s*(.*)/.exec(textHint.nothint);
if (notMatch) { if (notMatch) {
string += ' <stringequalhint answer="' + notMatch[1] + '"' + textHint.labelassign + '>' + textHint.hint + '</stringequalhint>\n'; string += ' <stringequalhint answer="' + notMatch[1] + '"' +
textHint.labelassign + '>' + textHint.hint + '</stringequalhint>\n';
continue; continue;
} }
var orMatch = /^or\=\s*(.*)/.exec(textHint.nothint); orMatch = /^or\=\s*(.*)/.exec(textHint.nothint);
if (orMatch) { if (orMatch) {
// additional_answer with answer= attribute // additional_answer with answer= attribute
string += ' <additional_answer answer="' + orMatch[1] + '">'; string += ' <additional_answer answer="' + orMatch[1] + '">';
if (textHint.hint) { if (textHint.hint) {
string += '<correcthint' + textHint.labelassign + '>' + textHint.hint + '</correcthint>'; string += '<correcthint' + textHint.labelassign + '>' +
textHint.hint + '</correcthint>';
} }
string += '</additional_answer>\n'; string += '</additional_answer>\n';
} }
...@@ -618,16 +663,13 @@ ...@@ -618,16 +663,13 @@
// replace explanations // replace explanations
xml = xml.replace(/\[explanation\]\n?([^\]]*)\[\/?explanation\]/gmi, function(match, p1) { xml = xml.replace(/\[explanation\]\n?([^\]]*)\[\/?explanation\]/gmi, function(match, p1) {
var selectString = '<solution>\n<div class="detailed-solution">\n' + gettext('Explanation') + '\n\n' + p1 + '\n</div>\n</solution>'; return '<solution>\n<div class="detailed-solution">\n' +
gettext('Explanation') + '\n\n' + p1 + '\n</div>\n</solution>';
return selectString;
}); });
// replace code blocks // replace code blocks
xml = xml.replace(/\[code\]\n?([^\]]*)\[\/?code\]/gmi, function(match, p1) { xml = xml.replace(/\[code\]\n?([^\]]*)\[\/?code\]/gmi, function(match, p1) {
var selectString = '<pre><code>' + p1 + '</code></pre>'; return '<pre><code>' + p1 + '</code></pre>';
return selectString;
}); });
// split scripts and preformatted sections, and wrap paragraphs // split scripts and preformatted sections, and wrap paragraphs
...@@ -662,20 +704,20 @@ ...@@ -662,20 +704,20 @@
} }
// make selector to search responsetypes in xml // make selector to search responsetypes in xml
var responseTypesSelector = responseTypes.join(', '); responseTypesSelector = responseTypes.join(', ');
// make temporary xml // make temporary xml
// safe-lint: disable=javascript-concat-html // safe-lint: disable=javascript-concat-html
var $xml = $($.parseXML('<prob>' + xml + '</prob>')); $xml = $($.parseXML('<prob>' + xml + '</prob>'));
responseType = $xml.find(responseTypesSelector); responseType = $xml.find(responseTypesSelector);
// convert if there is only one responsetype // convert if there is only one responsetype
if (responseType.length === 1) { if (responseType.length === 1) {
var inputtype = responseType[0].firstElementChild inputtype = responseType[0].firstElementChild;
// used to decide whether an element should be placed before or after an inputtype // used to decide whether an element should be placed before or after an inputtype
var beforeInputtype = true; beforeInputtype = true;
_.each($xml.find('prob').children(), function(child, index) { _.each($xml.find('prob').children(), function(child) {
// we don't want to add the responsetype again into new xml // we don't want to add the responsetype again into new xml
if (responseType[0].nodeName === child.nodeName) { if (responseType[0].nodeName === child.nodeName) {
beforeInputtype = false; beforeInputtype = false;
...@@ -688,8 +730,8 @@ ...@@ -688,8 +730,8 @@
} else { } else {
responseType[0].appendChild(child); responseType[0].appendChild(child);
} }
}) });
var serializer = new XMLSerializer(); serializer = new XMLSerializer();
xml = serializer.serializeToString(responseType[0]); xml = serializer.serializeToString(responseType[0]);
...@@ -707,21 +749,22 @@ ...@@ -707,21 +749,22 @@
}; };
responseTypesXML = []; responseTypesXML = [];
responseTypesMarkdown = markdown.split(/\n\s*---\s*\n/g); responseTypesMarkdown = markdown.split(/\n\s*---\s*\n/g);
_.each(responseTypesMarkdown, function(responseTypeMarkdown, index) { _.each(responseTypesMarkdown, function(responseTypeMarkdown) {
if (responseTypeMarkdown.trim().length > 0) { if (responseTypeMarkdown.trim().length > 0) {
return responseTypesXML.push(toXml(responseTypeMarkdown)); responseTypesXML.push(toXml(responseTypeMarkdown));
} }
}); });
demandHints = ''; finalDemandHints = '';
if (demandHintTags.length) { if (demandHintTags.length) {
demandHints = '\n<demandhint>\n' + demandHintTags.join('') + '</demandhint>'; // safe-lint: disable=javascript-concat-html
finalDemandHints = '\n<demandhint>\n' + demandHintTags.join('') + '</demandhint>';
} }
finalXml = '<problem>' + responseTypesXML.join('\n\n') + demandHints + '</problem>'; // make all responsetypes descendants of a single problem element
// safe-lint: disable=javascript-concat-html
finalXml = '<problem>' + responseTypesXML.join('\n\n') + finalDemandHints + '</problem>';
return PrettyPrint.xml(finalXml); return PrettyPrint.xml(finalXml);
}; };
return MarkdownEditingDescriptor; return MarkdownEditingDescriptor;
}(XModule.Descriptor));
})(XModule.Descriptor);
}).call(this); }).call(this);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment