Commit 0fb37cee by cahrens

Replace with JS code.

parent 337d4947
...@@ -49,7 +49,6 @@ common/lib/xmodule/xmodule/js/src/conditional/display.js ...@@ -49,7 +49,6 @@ common/lib/xmodule/xmodule/js/src/conditional/display.js
common/lib/xmodule/xmodule/js/src/discussion/display.js common/lib/xmodule/xmodule/js/src/discussion/display.js
common/lib/xmodule/xmodule/js/src/html/display.js common/lib/xmodule/xmodule/js/src/html/display.js
common/lib/xmodule/xmodule/js/src/html/edit.js common/lib/xmodule/xmodule/js/src/html/edit.js
common/lib/xmodule/xmodule/js/src/problem/edit.js
common/lib/xmodule/xmodule/js/src/raw/edit/json.js common/lib/xmodule/xmodule/js/src/raw/edit/json.js
common/lib/xmodule/xmodule/js/src/raw/edit/metadata-only.js common/lib/xmodule/xmodule/js/src/raw/edit/metadata-only.js
common/lib/xmodule/xmodule/js/src/raw/edit/xml.js common/lib/xmodule/xmodule/js/src/raw/edit/xml.js
......
...@@ -154,7 +154,7 @@ class CapaDescriptor(CapaFields, RawDescriptor): ...@@ -154,7 +154,7 @@ class CapaDescriptor(CapaFields, RawDescriptor):
show_in_read_only_mode = True show_in_read_only_mode = True
template_dir_name = 'problem' template_dir_name = 'problem'
mako_template = "widgets/problem-edit.html" mako_template = "widgets/problem-edit.html"
js = {'coffee': [resource_string(__name__, 'js/src/problem/edit.coffee')]} js = {'js': [resource_string(__name__, 'js/src/problem/edit.js')]}
js_module_name = "MarkdownEditingDescriptor" js_module_name = "MarkdownEditingDescriptor"
has_author_view = True has_author_view = True
css = { css = {
......
# Coffeescript markdown support. // Generated by CoffeeScript 1.6.1
# Most of the functionality is in the markdownToXml function, (function() {
# which in fact is regular javascript within backticks. var _this = this,
__hasProp = {}.hasOwnProperty,
class @MarkdownEditingDescriptor extends XModule.Descriptor __extends = function(child, parent) {
# TODO really, these templates should come from or also feed the cheatsheet for (var key in parent) {
@multipleChoiceTemplate : "( ) #{gettext 'incorrect'}\n( ) #{gettext 'incorrect'}\n(x) #{gettext 'correct'}\n" if (__hasProp.call(parent, key)) child[key] = parent[key];
@checkboxChoiceTemplate: "[x] #{gettext 'correct'}\n[ ] incorrect\n[x] correct\n" }
@stringInputTemplate: "= #{gettext 'answer'}\n" function ctor() {
@numberInputTemplate: "= #{gettext 'answer'} +- 0.001%\n" this.constructor = child;
@selectTemplate: "[[#{gettext 'incorrect'}, (#{gettext 'correct'}), #{gettext 'incorrect'}]]\n" }
@headerTemplate: "#{gettext 'Header'}\n=====\n"
@explanationTemplate: "[explanation]\n#{gettext 'Short explanation'}\n[explanation]\n" ctor.prototype = parent.prototype;
child.prototype = new ctor();
constructor: (element) -> child.__super__ = parent.prototype;
@element = element return child;
};
if $(".markdown-box", @element).length != 0
@markdown_editor = CodeMirror.fromTextArea($(".markdown-box", element)[0], { this.MarkdownEditingDescriptor = (function(_super) {
lineWrapping: true
__extends(MarkdownEditingDescriptor, _super);
MarkdownEditingDescriptor.multipleChoiceTemplate = "( ) " + (gettext('incorrect')) + "\n( ) " + (gettext('incorrect')) + "\n(x) " + (gettext('correct')) + "\n";
MarkdownEditingDescriptor.checkboxChoiceTemplate = "[x] " + (gettext('correct')) + "\n[ ] incorrect\n[x] correct\n";
MarkdownEditingDescriptor.stringInputTemplate = "= " + (gettext('answer')) + "\n";
MarkdownEditingDescriptor.numberInputTemplate = "= " + (gettext('answer')) + " +- 0.001%\n";
MarkdownEditingDescriptor.selectTemplate = "[[" + (gettext('incorrect')) + ", (" + (gettext('correct')) + "), " + (gettext('incorrect')) + "]]\n";
MarkdownEditingDescriptor.headerTemplate = "" + (gettext('Header')) + "\n=====\n";
MarkdownEditingDescriptor.explanationTemplate = "[explanation]\n" + (gettext('Short explanation')) + "\n[explanation]\n";
function MarkdownEditingDescriptor(element) {
var _this = this;
this.toggleCheatsheetVisibility = function() {
return MarkdownEditingDescriptor.prototype.toggleCheatsheetVisibility.apply(_this, arguments);
};
this.toggleCheatsheet = function(e) {
return MarkdownEditingDescriptor.prototype.toggleCheatsheet.apply(_this, arguments);
};
this.onToolbarButton = function(e) {
return MarkdownEditingDescriptor.prototype.onToolbarButton.apply(_this, arguments);
};
this.onShowXMLButton = function(e) {
return MarkdownEditingDescriptor.prototype.onShowXMLButton.apply(_this, arguments);
};
this.element = element;
if ($(".markdown-box", this.element).length !== 0) {
this.markdown_editor = CodeMirror.fromTextArea($(".markdown-box", element)[0], {
lineWrapping: true,
mode: null mode: null
}) });
@setCurrentEditor(@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);
@element.on('click', '.xml-tab', @onShowXMLButton) this.element.on('click', '.format-buttons button', this.onToolbarButton);
@element.on('click', '.format-buttons button', @onToolbarButton) this.element.on('click', '.cheatsheet-toggle', this.toggleCheatsheet);
@element.on('click', '.cheatsheet-toggle', @toggleCheatsheet) $(this.element.find('.xml-box')).hide();
# Hide the XML text area } else {
$(@element.find('.xml-box')).hide() this.createXMLEditor();
else }
@createXMLEditor() }
### /*
Creates the XML Editor and sets it as the current editor. If text is passed in, Creates the XML Editor and sets it as the current editor. If text is passed in,
it will replace the text present in the HTML template. it will replace the text present in the HTML template.
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
### */
createXMLEditor: (text) ->
@xml_editor = CodeMirror.fromTextArea($(".xml-box", @element)[0], {
mode: "xml" MarkdownEditingDescriptor.prototype.createXMLEditor = function(text) {
lineNumbers: true this.xml_editor = CodeMirror.fromTextArea($(".xml-box", this.element)[0], {
mode: "xml",
lineNumbers: true,
lineWrapping: true lineWrapping: true
}) });
if text if (text) {
@xml_editor.setValue(text) this.xml_editor.setValue(text);
@setCurrentEditor(@xml_editor) }
$(@xml_editor.getWrapperElement()).toggleClass("CodeMirror-advanced"); this.setCurrentEditor(this.xml_editor);
# Need to refresh to get line numbers to display properly. $(this.xml_editor.getWrapperElement()).toggleClass("CodeMirror-advanced");
@xml_editor.refresh() return 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.
### */
onShowXMLButton: (e) =>
MarkdownEditingDescriptor.prototype.onShowXMLButton = function(e) {
e.preventDefault(); e.preventDefault();
if @cheatsheet && @cheatsheet.hasClass('shown') if (this.cheatsheet && this.cheatsheet.hasClass('shown')) {
@cheatsheet.toggleClass('shown') this.cheatsheet.toggleClass('shown');
@toggleCheatsheetVisibility() this.toggleCheatsheetVisibility();
if @confirmConversionToXml() }
@createXMLEditor(MarkdownEditingDescriptor.markdownToXml(@markdown_editor.getValue())) if (this.confirmConversionToXml()) {
# Put cursor position to 0. this.createXMLEditor(MarkdownEditingDescriptor.markdownToXml(this.markdown_editor.getValue()));
@xml_editor.setCursor(0) this.xml_editor.setCursor(0);
# Hide markdown-specific toolbar buttons return $(this.element.find('.editor-bar')).hide();
$(@element.find('.editor-bar')).hide() }
};
###
/*
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.
### */
confirmConversionToXml: ->
# TODO: use something besides a JavaScript confirm dialog?
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?")
### 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?"));
};
/*
Event listener for toolbar buttons (only possible when markdown editor is visible). Event listener for toolbar buttons (only possible when markdown editor is visible).
### */
onToolbarButton: (e) =>
e.preventDefault();
selection = @markdown_editor.getSelection() MarkdownEditingDescriptor.prototype.onToolbarButton = function(e) {
revisedSelection = null var revisedSelection, selection;
switch $(e.currentTarget).attr('class')
when "multiple-choice-button" then revisedSelection = MarkdownEditingDescriptor.insertMultipleChoice(selection)
when "string-button" then revisedSelection = MarkdownEditingDescriptor.insertStringInput(selection)
when "number-button" then revisedSelection = MarkdownEditingDescriptor.insertNumberInput(selection)
when "checks-button" then revisedSelection = MarkdownEditingDescriptor.insertCheckboxChoice(selection)
when "dropdown-button" then revisedSelection = MarkdownEditingDescriptor.insertSelect(selection)
when "header-button" then revisedSelection = MarkdownEditingDescriptor.insertHeader(selection)
when "explanation-button" then revisedSelection = MarkdownEditingDescriptor.insertExplanation(selection)
else # ignore click
if revisedSelection != null
@markdown_editor.replaceSelection(revisedSelection)
@markdown_editor.focus()
###
Event listener for toggling cheatsheet (only possible when markdown editor is visible).
###
toggleCheatsheet: (e) =>
e.preventDefault(); e.preventDefault();
if !$(@markdown_editor.getWrapperElement()).find('.simple-editor-cheatsheet')[0] selection = this.markdown_editor.getSelection();
@cheatsheet = $($('#simple-editor-cheatsheet').html()) revisedSelection = null;
$(@markdown_editor.getWrapperElement()).append(@cheatsheet) switch ($(e.currentTarget).attr('class')) {
case "multiple-choice-button":
revisedSelection = MarkdownEditingDescriptor.insertMultipleChoice(selection);
break;
case "string-button":
revisedSelection = MarkdownEditingDescriptor.insertStringInput(selection);
break;
case "number-button":
revisedSelection = MarkdownEditingDescriptor.insertNumberInput(selection);
break;
case "checks-button":
revisedSelection = MarkdownEditingDescriptor.insertCheckboxChoice(selection);
break;
case "dropdown-button":
revisedSelection = MarkdownEditingDescriptor.insertSelect(selection);
break;
case "header-button":
revisedSelection = MarkdownEditingDescriptor.insertHeader(selection);
break;
case "explanation-button":
revisedSelection = MarkdownEditingDescriptor.insertExplanation(selection);
break;
}
if (revisedSelection !== null) {
this.markdown_editor.replaceSelection(revisedSelection);
return this.markdown_editor.focus();
}
};
@toggleCheatsheetVisibility() /*
Event listener for toggling cheatsheet (only possible when markdown editor is visible).
*/
setTimeout (=> @cheatsheet.toggleClass('shown')), 10
MarkdownEditingDescriptor.prototype.toggleCheatsheet = function(e) {
var _this = this;
e.preventDefault();
if (!$(this.markdown_editor.getWrapperElement()).find('.simple-editor-cheatsheet')[0]) {
this.cheatsheet = $($('#simple-editor-cheatsheet').html());
$(this.markdown_editor.getWrapperElement()).append(this.cheatsheet);
}
this.toggleCheatsheetVisibility();
return setTimeout((function() {
return _this.cheatsheet.toggleClass('shown');
}), 10);
};
### /*
Function to toggle cheatsheet visibility. Function to toggle cheatsheet visibility.
### */
toggleCheatsheetVisibility: () =>
$('.modal-content').toggleClass('cheatsheet-is-shown')
### MarkdownEditingDescriptor.prototype.toggleCheatsheetVisibility = function() {
return $('.modal-content').toggleClass('cheatsheet-is-shown');
};
/*
Stores the current editor and hides the one that is not displayed. Stores the current editor and hides the one that is not displayed.
### */
setCurrentEditor: (editor) ->
if @current_editor
$(@current_editor.getWrapperElement()).hide() MarkdownEditingDescriptor.prototype.setCurrentEditor = function(editor) {
@current_editor = editor if (this.current_editor) {
$(@current_editor.getWrapperElement()).show() $(this.current_editor.getWrapperElement()).hide();
$(@current_editor).focus(); }
this.current_editor = editor;
### $(this.current_editor.getWrapperElement()).show();
return $(this.current_editor).focus();
};
/*
Called when save is called. Listeners are unregistered because editing the block again will Called when save is called. Listeners are unregistered because editing the block again will
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.
### */
save: ->
@element.off('click', '.xml-tab', @changeEditor)
@element.off('click', '.format-buttons button', @onToolbarButton) MarkdownEditingDescriptor.prototype.save = function() {
@element.off('click', '.cheatsheet-toggle', @toggleCheatsheet) this.element.off('click', '.xml-tab', this.changeEditor);
if @current_editor == @markdown_editor this.element.off('click', '.format-buttons button', this.onToolbarButton);
{ this.element.off('click', '.cheatsheet-toggle', this.toggleCheatsheet);
data: MarkdownEditingDescriptor.markdownToXml(@markdown_editor.getValue()) if (this.current_editor === this.markdown_editor) {
metadata: markdown: @markdown_editor.getValue() return {
} data: MarkdownEditingDescriptor.markdownToXml(this.markdown_editor.getValue()),
else metadata: {
{ markdown: this.markdown_editor.getValue()
data: @xml_editor.getValue() }
};
} else {
return {
data: this.xml_editor.getValue(),
nullout: ['markdown'] nullout: ['markdown']
};
}
};
MarkdownEditingDescriptor.insertMultipleChoice = function(selectedText) {
return MarkdownEditingDescriptor.insertGenericChoice(selectedText, '(', ')', MarkdownEditingDescriptor.multipleChoiceTemplate);
};
MarkdownEditingDescriptor.insertCheckboxChoice = function(selectedText) {
return MarkdownEditingDescriptor.insertGenericChoice(selectedText, '[', ']', MarkdownEditingDescriptor.checkboxChoiceTemplate);
};
MarkdownEditingDescriptor.insertGenericChoice = function(selectedText, choiceStart, choiceEnd, template) {
var cleanSelectedText, line, lines, revisedLines, _i, _len;
if (selectedText.length > 0) {
cleanSelectedText = selectedText.replace(/\n+/g, '\n').replace(/\n$/, '');
lines = cleanSelectedText.split('\n');
revisedLines = '';
for (_i = 0, _len = lines.length; _i < _len; _i++) {
line = lines[_i];
revisedLines += choiceStart;
if (/^\s*x\s+(\S)/i.test(line)) {
line = line.replace(/^\s*x\s+(\S)/i, '$1');
revisedLines += 'x';
} else {
revisedLines += ' ';
}
revisedLines += choiceEnd + ' ' + line + '\n';
}
return revisedLines;
} else {
return template;
} }
};
MarkdownEditingDescriptor.insertStringInput = function(selectedText) {
return MarkdownEditingDescriptor.insertGenericInput(selectedText, '= ', '', MarkdownEditingDescriptor.stringInputTemplate);
};
MarkdownEditingDescriptor.insertNumberInput = function(selectedText) {
return MarkdownEditingDescriptor.insertGenericInput(selectedText, '= ', '', MarkdownEditingDescriptor.numberInputTemplate);
};
MarkdownEditingDescriptor.insertSelect = function(selectedText) {
return MarkdownEditingDescriptor.insertGenericInput(selectedText, '[[', ']]', MarkdownEditingDescriptor.selectTemplate);
};
MarkdownEditingDescriptor.insertHeader = function(selectedText) {
return MarkdownEditingDescriptor.insertGenericInput(selectedText, '', '\n====\n', MarkdownEditingDescriptor.headerTemplate);
};
MarkdownEditingDescriptor.insertExplanation = function(selectedText) {
return MarkdownEditingDescriptor.insertGenericInput(selectedText, '[explanation]\n', '\n[explanation]', MarkdownEditingDescriptor.explanationTemplate);
};
MarkdownEditingDescriptor.insertGenericInput = function(selectedText, lineStart, lineEnd, template) {
if (selectedText.length > 0) {
return lineStart + selectedText + lineEnd;
} else {
return template;
}
};
@insertMultipleChoice: (selectedText) -> MarkdownEditingDescriptor.markdownToXml = function(markdown) {
return MarkdownEditingDescriptor.insertGenericChoice(selectedText, '(', ')', MarkdownEditingDescriptor.multipleChoiceTemplate) var demandHintTags, demandHints, finalXml, responseTypesMarkdown, responseTypesXML, toXml;
@insertCheckboxChoice: (selectedText) ->
return MarkdownEditingDescriptor.insertGenericChoice(selectedText, '[', ']', MarkdownEditingDescriptor.checkboxChoiceTemplate)
@insertGenericChoice: (selectedText, choiceStart, choiceEnd, template) ->
if selectedText.length > 0
# Replace adjacent newlines with a single newline, strip any trailing newline
cleanSelectedText = selectedText.replace(/\n+/g, '\n').replace(/\n$/,'')
lines = cleanSelectedText.split('\n')
revisedLines = ''
for line in lines
revisedLines += choiceStart
# a stand alone x before other text implies that this option is "correct"
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')
revisedLines += 'x'
else
revisedLines += ' '
revisedLines += choiceEnd + ' ' + line + '\n'
return revisedLines
else
return template
@insertStringInput: (selectedText) ->
return MarkdownEditingDescriptor.insertGenericInput(selectedText, '= ', '', MarkdownEditingDescriptor.stringInputTemplate)
@insertNumberInput: (selectedText) ->
return MarkdownEditingDescriptor.insertGenericInput(selectedText, '= ', '', MarkdownEditingDescriptor.numberInputTemplate)
@insertSelect: (selectedText) ->
return MarkdownEditingDescriptor.insertGenericInput(selectedText, '[[', ']]', MarkdownEditingDescriptor.selectTemplate)
@insertHeader: (selectedText) ->
return MarkdownEditingDescriptor.insertGenericInput(selectedText, '', '\n====\n', MarkdownEditingDescriptor.headerTemplate)
@insertExplanation: (selectedText) ->
return MarkdownEditingDescriptor.insertGenericInput(selectedText, '[explanation]\n', '\n[explanation]', MarkdownEditingDescriptor.explanationTemplate)
@insertGenericInput: (selectedText, lineStart, lineEnd, template) ->
if selectedText.length > 0
# TODO: should this insert a newline afterwards?
return lineStart + selectedText + lineEnd
else
return template
@markdownToXml: (markdown)->
# it will contain <hint>...</hint> tags
demandHintTags = []; demandHintTags = [];
toXml = `function (markdown) { toXml = function(markdown) {
var xml = markdown, var xml = markdown,
i, splits, makeParagraph; i, splits, makeParagraph;
var responseTypes = [ var responseTypes = [
...@@ -265,12 +353,18 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor ...@@ -265,12 +353,18 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
} }
} }
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 {'nothint': text, 'hint': hint, 'label': label, 'parens': parens, 'labelassign': labelassign}; return {
'nothint': text,
'hint': hint,
'label': label,
'parens': parens,
'labelassign': labelassign
};
} }
...@@ -291,7 +385,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor ...@@ -291,7 +385,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
var options = group1.split(/\,\s*/g); var options = group1.split(/\,\s*/g);
var optiontag = ' <optioninput options="('; var 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); var correct = /(?:^|,)\s*\((.*?)\)\s*(?:$|,)/g.exec(group1);
...@@ -309,7 +403,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor ...@@ -309,7 +403,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
var line = lines[i].trim(); var line = lines[i].trim();
if (line.length > 0) { if (line.length > 0) {
var textHint = extractHint(line, true); var textHint = extractHint(line, true);
var correctstr = ' correct="' + (textHint.parens?'True':'False') + '"'; var correctstr = ' correct="' + (textHint.parens ? 'True' : 'False') + '"';
var hintstr = ''; var hintstr = '';
if (textHint.hint) { if (textHint.hint) {
var label = textHint.label; var label = textHint.label;
...@@ -332,17 +426,17 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor ...@@ -332,17 +426,17 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
var choices = ''; var choices = '';
var shuffle = false; var shuffle = false;
var options = match.split('\n'); var options = match.split('\n');
for(var i = 0; i < options.length; i++) { for (var 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]; var value = options[i].split(/^\s*\(.{0,3}\)\s*/)[1];
var inparens = /^\s*\((.{0,3})\)\s*/.exec(options[i])[1]; var inparens = /^\s*\((.{0,3})\)\s*/.exec(options[i])[1];
var correct = /x/i.test(inparens); var correct = /x/i.test(inparens);
var fixed = ''; var fixed = '';
if(/@/.test(inparens)) { if (/@/.test(inparens)) {
fixed = ' fixed="true"'; fixed = ' fixed="true"';
} }
if(/!/.test(inparens)) { if (/!/.test(inparens)) {
shuffle = true; shuffle = true;
} }
...@@ -355,7 +449,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor ...@@ -355,7 +449,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
} }
} }
var result = '<multiplechoiceresponse>\n'; var result = '<multiplechoiceresponse>\n';
if(shuffle) { if (shuffle) {
result += ' <choicegroup type="MultipleChoice" shuffle="true">\n'; result += ' <choicegroup type="MultipleChoice" shuffle="true">\n';
} else { } else {
result += ' <choicegroup type="MultipleChoice">\n'; result += ' <choicegroup type="MultipleChoice">\n';
...@@ -378,7 +472,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor ...@@ -378,7 +472,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
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) {
if(options[i].trim().length > 0) { if (options[i].trim().length > 0) {
// 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>
...@@ -387,7 +481,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor ...@@ -387,7 +481,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
// 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]; var 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
} }
...@@ -415,7 +509,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor ...@@ -415,7 +509,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
value = hint.nothint; value = hint.nothint;
} }
} }
groupString += ' <choice correct="' + correct + '">' + value + hints +'</choice>\n'; groupString += ' <choice correct="' + correct + '">' + value + hints + '</choice>\n';
} }
} }
...@@ -433,7 +527,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor ...@@ -433,7 +527,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
// 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(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 = value.replace(/^\=\s*/, '');
var params, answer, string; var params, answer, string;
...@@ -445,7 +539,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor ...@@ -445,7 +539,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
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])) {
// [5, 7) or (5, 7), or (1.2345 * (2+3), 7*4 ] - range tolerance case // [5, 7) or (5, 7), or (1.2345 * (2+3), 7*4 ] - range tolerance case
// = (5*2)*3 should not be used as range tolerance // = (5*2)*3 should not be used as range tolerance
string = '<numericalresponse answer="' + value + '">\n'; string = '<numericalresponse answer="' + value + '">\n';
...@@ -462,7 +556,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor ...@@ -462,7 +556,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
// Tries to extract parameters from string like 'expr +- tolerance' // Tries to extract parameters from string like 'expr +- tolerance'
params = /(.*?)\+\-\s*(.*?$)/.exec(value); params = /(.*?)\+\-\s*(.*?$)/.exec(value);
if(params) { if (params) {
answer = params[1].replace(/\s+/g, ''); // support inputs like 5*2 +- 10 answer = params[1].replace(/\s+/g, ''); // support inputs like 5*2 +- 10
string = '<numericalresponse answer="' + answer + '">\n'; string = '<numericalresponse answer="' + answer + '">\n';
string += ' <responseparam type="tolerance" default="' + params[2] + '" />\n'; string += ' <responseparam type="tolerance" default="' + params[2] + '" />\n';
...@@ -478,7 +572,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor ...@@ -478,7 +572,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
return string; return string;
}, },
processStringResponse = function (values) { processStringResponse = function(values) {
// First string case is s?= // First string case is s?=
var firstAnswer = values.shift(), string; var firstAnswer = values.shift(), string;
firstAnswer = firstAnswer.replace(/^s?\=\s*/, ''); firstAnswer = firstAnswer.replace(/^s?\=\s*/, '');
...@@ -581,7 +675,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor ...@@ -581,7 +675,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
// 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; var beforeInputtype = true;
_.each($xml.find('prob').children(), function(child, index){ _.each($xml.find('prob').children(), function(child, index) {
// 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;
...@@ -610,22 +704,24 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor ...@@ -610,22 +704,24 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
// remove class attribute added on <p> tag for question title // remove class attribute added on <p> tag for question title
xml = xml.replace(/\sclass=\'qtitle\'/gi, ''); xml = xml.replace(/\sclass=\'qtitle\'/gi, '');
return xml; return xml;
}` };
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, (responseTypeMarkdown, index) -> if (responseTypeMarkdown.trim().length > 0) {
if responseTypeMarkdown.trim().length > 0 return responseTypesXML.push(toXml(responseTypeMarkdown));
responseTypesXML.push toXml(responseTypeMarkdown) }
});
# combine demandhints demandHints = '';
demandHints = '' if (demandHintTags.length) {
if demandHintTags.length demandHints = '\n<demandhint>\n' + demandHintTags.join('') + '</demandhint>';
## safe-lint: disable=javascript-concat-html }
demandHints = '\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
# format and return xml
finalXml = '<problem>' + responseTypesXML.join('\n\n') + demandHints + '</problem>'
return PrettyPrint.xml(finalXml); return PrettyPrint.xml(finalXml);
};
return MarkdownEditingDescriptor;
})(XModule.Descriptor);
}).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