Commit 612f381e by Mike Chen

GeneralResponse in Wiki syntax and formularesponse rendering

parent d256b929
/* null_ is used in JSON parser */
{
null_ = new Object();
}
start start
= sections:(Image / = sections:(Image /
GeneralResponse /
NumericalOrStringResponse / NumericalOrStringResponse /
NumericalResponse / NumericalResponse /
MultipleChoice / MultipleChoice /
Paragraph / Paragraph
PreservedLinebreaks)+ )+
/* GeneralResponse */
KeyValueString
= QuotedString
/ chars:[^: \n]+
{
return chars.join("");
}
KeyValuePair
= key:KeyValueString _ ':' _ value:KeyValueString
{
return {'key': key, 'value': value};
}
InlineGeneralResponse
= CorrectAnswerIdentifier pairs:(' '+ KeyValuePair)+ Linebreak
{
ret = {};
pairs = pairs.map(function (x) { return x[1]; });
for (var i = 0; i < pairs.length; i++) {
console.log(pairs);
if (ret[pairs[i].key] == undefined)
ret[pairs[i].key] = pairs[i].value;
else
throw new SyntaxError("Key " + pairs[i].key + " was used more than once. " );
}
return ret;
}
GeneralResponseValue
= InlineGeneralResponse / JSONDictionary
GeneralResponse
= dic:GeneralResponseValue
{
if (dic.type == undefined) {
throw new SyntaxError("Please define 'type' in response. ")
}
return dic;
}
/* Image */ /* Image */
ImageLink ImageLink
= DoubleQuotedString = QuotedString
/ chars:( (!')' [^\n])+) / chars:( (!')' [^\n])+)
{ {
return $.trim(chars.map(function(element) { return element[1]; }).join("")); return $.trim(chars.map(function(element) { return element[1]; }).join(""));
...@@ -22,7 +70,7 @@ ImageTitle ...@@ -22,7 +70,7 @@ ImageTitle
} }
Image Image
= ImageIdentifier title:ImageTitle? OptionalSpaces '(' OptionalSpaces url:ImageLink ')' OptionalSpaces Linebreak = ImageIdentifier title:ImageTitle? _ '(' _ url:ImageLink ')' ' '* Linebreak
{ {
return {'type': 'image', 'url': url, 'title': title}; return {'type': 'image', 'url': url, 'title': title};
} }
...@@ -38,19 +86,19 @@ ChoiceIdentifier ...@@ -38,19 +86,19 @@ ChoiceIdentifier
ImageIdentifier ImageIdentifier
= '!' = '!'
StudentProducedResponseIdentifier CorrectAnswerIdentifier
= '=' = '='
/* StringResponse */ /* StringResponse */
StringResponse StringResponse
= StudentProducedResponseIdentifier OptionalSpaces !'(' value:Text Linebreak = CorrectAnswerIdentifier _ !'(' value:(QuotedString / Text) Linebreak
{ {
return {'type': 'string', 'answer': $.trim(value)}; return {'type': 'string', 'answer': $.trim(value)};
} }
NumericalOrStringResponse NumericalOrStringResponse
= StudentProducedResponseIdentifier OptionalSpaces value:NumericalValue OptionalSpaces tolerance:NumericalTolerance? OptionalSpaces Linebreak = CorrectAnswerIdentifier _ value:NumericalValue _ tolerance:NumericalTolerance? _ Linebreak
{ {
if (tolerance == "") if (tolerance == "")
tolerance = "5%" tolerance = "5%"
...@@ -79,9 +127,11 @@ MultipleChoice ...@@ -79,9 +127,11 @@ MultipleChoice
} }
/* Paragraph */ /* Paragraph */
LineOrLinebreak
= Line / Linebreak
ParagraphTextLine ParagraphTextLine
= !ImageIdentifier !ChoiceIdentifier !StudentProducedResponseIdentifier line:Line = !JSONDictionary !ImageIdentifier !ChoiceIdentifier !CorrectAnswerIdentifier line:LineOrLinebreak
{ {
return line; return line;
} }
...@@ -89,7 +139,7 @@ ParagraphTextLine ...@@ -89,7 +139,7 @@ ParagraphTextLine
Paragraph Paragraph
= lines:ParagraphTextLine+ = lines:ParagraphTextLine+
{ {
return {'type': 'paragraph', 'text': lines.join("")}; return {'type': 'text', 'text': lines.join("")};
} }
/* Base symbols */ /* Base symbols */
...@@ -106,49 +156,165 @@ Text ...@@ -106,49 +156,165 @@ Text
return chars.join(""); return chars.join("");
} }
OptionalSpacesAndLines _AndLines
= (' ' / '\n' / '\t')* = (' ' / '\n' / '\t')*
OptionalSpaces _
= (' ' / '\t')* = (' ' / '\t')*
PreservedLinebreaks
= terminators:('\n')+
{
return {'type': 'linebreaks', 'count': terminators.length}
}
Linebreak Linebreak
= ('\n') = ('\n')
QuotedString
= DoubleQuotedString / SingleQuotedString
DoubleQuotedString DoubleQuotedString
= "\"\"" { return ""; } = "\"\"" { return ""; }
/ "\"" str:(!UnescapedQuote .)* last:UnescapedQuote { / "\"" str:(!UnescapedDoubleQuote .)* last:UnescapedDoubleQuote {
return str.map(function(element) { return element[1]; }).join("") + last; return str.map(function(element) { return element[1]; }).join("") + last;
} }
UnescapedQuote UnescapedDoubleQuote
= last:[^\\] "\"" {return last;} = last:[^\\] "\"" {return last;}
SingleQuotedString
= "''" { return ""; }
/ "'" str:(!UnescapedSingleQuote .)* last:UnescapedSingleQuote {
return str.map(function(element) { return element[1]; }).join("") + last;
}
UnescapedSingleQuote
= last:[^\\] "'" {return last;}
AlphanumericalText AlphanumericalText
= chars:[a-zA-Z0-9]+ = chars:[a-zA-Z0-9]+
{ {
return chars.join(""); return chars.join("");
} }
/* JSON */
/* JSON parser based on the grammar described at http://json.org/. */
JSONDictionary
= _ o:object { return o; }
object
= "{" _ "}" _ { return {}; }
/ "{" _ members:members "}" _ { return members; }
members
= head:pair tail:("," _ pair)* {
var result = {};
result[head[0]] = (head[1] === null_ ? null : head[1]);
for (var i = 0; i < tail.length; i++) {
result[tail[i][2][0]] = (tail[i][2][1] === null_ ? null : tail[i][2][1]);
}
return result;
}
pair
= name:string ":" _ value:value { return [name, value]; }
array
= "[" _ "]" _ { return []; }
/ "[" _ elements:elements "]" _ { return elements; }
elements
= head:value tail:("," _ value)* {
var result = [head === null_ ? null : head];
for (var i = 0; i < tail.length; i++) {
result.push(tail[i][2] === null_ ? null : tail[i][2]);
}
return result;
}
value
= string
/ number
/ object
/ array
/ "true" _ { return true; }
/ "false" _ { return false; }
/ "null" _ { return null_; }
string "string"
= '"' '"' _ { return ""; }
/ '"' chars:chars '"' _ { return chars; }
chars
= chars:char+ { return chars.join(""); }
char
// In the original JSON grammar: "any-Unicode-character-except-"-or-\-or-control-character"
= [^"\\\0-\x1F\x7f]
/ '\\"' { return '"'; }
/ "\\\\" { return "\\"; }
/ "\\/" { return "/"; }
/ "\\b" { return "\b"; }
/ "\\f" { return "\f"; }
/ "\\n" { return "\n"; }
/ "\\r" { return "\r"; }
/ "\\t" { return "\t"; }
/ "\\u" h1:hexDigit h2:hexDigit h3:hexDigit h4:hexDigit {
return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4));
}
number "number"
= int_:int frac:frac exp:exp _ { return parseFloat(int_ + frac + exp); }
/ int_:int frac:frac _ { return parseFloat(int_ + frac); }
/ int_:int exp:exp _ { return parseFloat(int_ + exp); }
/ int_:int _ { return parseFloat(int_); }
int
= digit19:digit19 digits:digits { return digit19 + digits; }
/ digit:digit
/ "-" digit19:digit19 digits:digits { return "-" + digit19 + digits; }
/ "-" digit:digit { return "-" + digit; }
frac
= "." digits:digits { return "." + digits; }
exp
= e:e digits:digits { return e + digits; }
digits
= digits:digit+ { return digits.join(""); }
e
= e:[eE] sign:[+-]? { return e + sign; }
digit
= [0-9]
digit19
= [1-9]
hexDigit
= [0-9a-fA-F]
_ "whitespace"
= whitespace*
// Whitespace is undefined in the original JSON grammar, so I assume a simple
// conventional definition consistent with ECMA-262, 5th ed.
whitespace
= [ \t\n\r]
/* NumericalResponse */ /* NumericalResponse */
NumericalToleranceValueType NumericalToleranceValueType
= decimal / percentage / integer = decimal / percentage / integer
NumericalTolerance NumericalTolerance
= '+-' OptionalSpaces value:NumericalToleranceValueType OptionalSpaces = '+-' _ value:NumericalToleranceValueType _
{ {
return value; return value;
} }
NumericalResponse NumericalResponse
= StudentProducedResponseIdentifier OptionalSpaces '(' OptionalSpaces value:NumericalValue OptionalSpaces tolerance:NumericalTolerance? ')' OptionalSpaces Linebreak = CorrectAnswerIdentifier _ '(' _ value:NumericalValue _ tolerance:NumericalTolerance? ')' _ Linebreak
{ {
if (tolerance == "") if (tolerance == "")
tolerance = "5%" tolerance = "5%"
...@@ -183,4 +349,4 @@ integer "integer" ...@@ -183,4 +349,4 @@ integer "integer"
= sign:[+-]? digits:[0-9]+ { return parseInt(sign + digits.join(""), 10); } = sign:[+-]? digits:[0-9]+ { return parseInt(sign + digits.join(""), 10); }
percentage "percentage" percentage "percentage"
= digits:[0-9]+ '%' { return parseInt(digits.join(""), 10) + '%'; } = digits:[0-9]+ '%' { return parseInt(digits.join(""), 10) + '%'; }
\ No newline at end of file
class @CapaDescriptor class @CapaDescriptor
constructor: (@element) -> constructor: (@element) ->
@problem_text = ""
@edit_box = $(".edit-box.capa-box", @element) @edit_box = $(".edit-box.capa-box", @element)
@source_box = $(".edit-box.source-box", @element) @source_box = $(".edit-box.source-box", @element)
@message_box = $(".parser-message-box", @element) @message_box = $(".parser-message-box", @element)
@buildParser() @buildParser()
@throttledAutoSave = _.throttle(@autoSave, 0);
@source_box.keyup => @source_box.keyup =>
@parse() @parse()
...@@ -20,6 +22,19 @@ class @CapaDescriptor ...@@ -20,6 +22,19 @@ class @CapaDescriptor
"Line " + e.line + ", column " + e.column + ": " + e.message "Line " + e.line + ", column " + e.column + ": " + e.message
else e.message else e.message
checkAutoSaveTimeout: ->
@auto_save_timer = null
@throttledAutoSave()
checkAutoSave: ->
callback = _.bind(@checkAutoSaveTimeout, this)
if @auto_save_timer
@auto_save_timer = window.clearTimeout(@auto_save_timer)
@auto_save_timer = window.setTimeout(callback, 1000)
autoSave: (event) ->
$(".save-update").click();
parse: -> parse: ->
try try
source = @source_box.val() + "\n" source = @source_box.val() + "\n"
...@@ -34,25 +49,27 @@ class @CapaDescriptor ...@@ -34,25 +49,27 @@ class @CapaDescriptor
outputXML: (parsed) -> outputXML: (parsed) ->
@edit_box.val @buildXML(parsed) @edit_box.val @buildXML(parsed)
@checkAutoSave()
dom2capa: (node) -> dom2capa: (node) ->
capa = new XMLSerializer().serializeToString(node) serializer = new XMLSerializer()
capa = capa + "" capa = serializer.serializeToString(node)
return capa.replace(/<startouttext>/g, '<startouttext />')
.replace(/<\/startouttext>/g, '<endouttext />')
buildXML: (parsed) -> buildXML: (parsed) ->
dom_parser = new DOMParser() dom_parser = new DOMParser()
doc = dom_parser.parseFromString("<problem></problem>", "text/xml"); doc = dom_parser.parseFromString("<problem />", "text/xml");
problem = $(doc.getElementsByTagName('problem')[0]) problem = $(doc).find('problem')
create_text_element = (content) -> create_text_element = (content) ->
el = $(doc.createElement('startouttext')) el = $(doc.createElement('text'))
el.text content for line in content.split('\n')
el.append doc.createTextNode(line)
el.append doc.createElement('br')
el.children().last().remove()
return el return el
for section in parsed for section in parsed
if section.type == 'paragraph' if section.type == 'text'
newel = create_text_element(section.text) newel = create_text_element(section.text)
problem.append(newel) problem.append(newel)
...@@ -103,6 +120,8 @@ class @CapaDescriptor ...@@ -103,6 +120,8 @@ class @CapaDescriptor
tolerance = $(doc.createElement('responseparam')) tolerance = $(doc.createElement('responseparam'))
tolerance.attr 'type', 'tolerance' tolerance.attr 'type', 'tolerance'
if section.tolerance == undefined
section.tolerance = "5%"
tolerance.attr 'default', section.tolerance tolerance.attr 'default', section.tolerance
tolerance.attr 'name', 'tol' tolerance.attr 'name', 'tol'
tolerance.attr 'description', 'Numerical Tolerance' tolerance.attr 'description', 'Numerical Tolerance'
...@@ -117,6 +136,27 @@ class @CapaDescriptor ...@@ -117,6 +136,27 @@ class @CapaDescriptor
newel.append doc.createElement('textline') newel.append doc.createElement('textline')
problem.append(newel) problem.append(newel)
else if section.type == 'formula'
formularesponse = $(doc.createElement("formularesponse"))
formularesponse.attr 'samples', section.samples
formularesponse.attr 'answer', section.answer
formularesponse.attr 'type', 'cs'
tolerance = $(doc.createElement('responseparam'))
tolerance.attr 'type', 'tolerance'
if section.tolerance == undefined
section.tolerance = "5%"
tolerance.attr 'default', section.tolerance
tolerance.attr 'name', 'tol'
tolerance.attr 'description', 'Numerical Tolerance'
formularesponse.append tolerance
formularesponse.append doc.createElement('textline')
problem.append(formularesponse)
else
throw new SyntaxError("unexpected section type " + section.type)
capa = @dom2capa(doc) capa = @dom2capa(doc)
console.log capa
return capa return capa
\ No newline at end of file
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