Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
fuhrmanator committed Jun 9, 2024
2 parents 5918ada + bef4cc6 commit 28a3cd0
Show file tree
Hide file tree
Showing 11 changed files with 110 additions and 56 deletions.
4 changes: 2 additions & 2 deletions GIFT.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ MatchRichText "(formatted text excluding '->')"
= format:Format? _ txt:MatchTextChar+ { return {
format:(format!==null ? format : getLastQuestionTextFormat()),
text:(
(format !== "html") ?
(format !== "html" && format !== "markdown") ?
escapedCharacterDecode(removeNewLinesDuplicateSpaces(txt.join('').trim())) :
escapedCharacterDecode(txt.join('')).replace(/\r\n/g,'\n').trim()
)}} // avoid failing tests because of Windows line breaks
Expand All @@ -298,7 +298,7 @@ RichText "(formatted text)"
= format:Format? _ txt:TextChar+ { return {
format:(format!==null ? format : getLastQuestionTextFormat()),
text:(
(format !== "html") ?
(format !== "html" && format !== "markdown") ?
escapedCharacterDecode(removeNewLinesDuplicateSpaces(txt.join('').trim())) :
escapedCharacterDecode(txt.join('')).replace(/\r\n/g,'\n').trim() // avoid failing tests because of Windows line breaks
)}}
Expand Down
96 changes: 52 additions & 44 deletions docs/editor/giftPreview.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
var converter;
var markdownToHTML;

function giftPreviewHTML(qArray, theDiv) {
converter = new showdown.Converter();
markdownToHTML = new showdown.Converter();
var html = "";
var q;
var pStemOpen = "<div class='question'>";
var pStemClose = "</div>";
for (var i=0; i<qArray.length; i++) {
for (var i = 0; i < qArray.length; i++) {
// console.log("i = " + i + " and qArray[i] is '" + qArray[i] );
q = qArray[i];
html += '<div id="question_' + i + '">';
Expand Down Expand Up @@ -37,7 +37,7 @@ function giftPreviewHTML(qArray, theDiv) {
html += formatFeedback(q.globalFeedback) + "</div>";
theDiv.append(html); html = "";
break;
case "TF":
case "TF":
html += makeTitle("True/False", q.title);
html += pStemOpen + "<em class='d-print-none'>(" + (q.isTrue ? "True" : "False") + ") </em>" + applyFormat(q.stem) + " (✓ ✘)" + pStemClose;
html += formatFeedback(q.globalFeedback) + "</div>";
Expand All @@ -54,7 +54,7 @@ function giftPreviewHTML(qArray, theDiv) {
default:
break;
}

}
// trigger the page change event
var pageChangeEvent = new CustomEvent('pageChanged');
Expand All @@ -63,20 +63,20 @@ function giftPreviewHTML(qArray, theDiv) {
}

function makeTitle(type, title) {
return "<b class='d-print-none'>" + type + (title !== null ? ' "' + title + '"' : "" ) + "</b>";
return "<b class='d-print-none'>" + type + (title !== null ? ' "' + title + '"' : "") + "</b>";
}

function formatAnswers(choices) {
var html = '<ul class="mc">';
//shuffle(choices);
for (var a=0; a<choices.length; a++) {
for (var a = 0; a < choices.length; a++) {
var answer = choices[a];
html += '<li class="' +
((answer.isCorrect || answer.weight > 0) ? 'rightAnswer' : 'wrongAnswer') +
'">' + (answer.weight !== null ? "<em class='d-print-none'>(" + answer.weight + "%) </em>" : '') +
applyFormat(answer.text) +
(answer.feedback !== null ? "<span class='d-print-none'> [" + applyFormat(answer.feedback) + "]</span>" : '') +
"</li>";
((answer.isCorrect || answer.weight > 0) ? 'rightAnswer' : 'wrongAnswer') +
'">' + (answer.weight !== null ? "<em class='d-print-none'>(" + answer.weight + "%) </em>" : '') +
applyFormat(answer.text) +
(answer.feedback !== null ? "<span class='d-print-none'> [" + applyFormat(answer.feedback, false) + "]</span>" : '') +
"</li>";
}
html += "</ul>";
return html;
Expand All @@ -85,16 +85,19 @@ function formatAnswers(choices) {
function formatMatchingAnswers(q, theDiv, qNum, html) {
var rightSideChoices = new Set();
var htmlLines = '';
for (var i=0; i<q.matchPairs.length; i++) {
for (var i = 0; i < q.matchPairs.length; i++) {
htmlLines += '<path id="line' + i + '" stroke="rgba(180,180,255,0.5)" stroke-width="5" fill="none"/>';
}
html += '<svg class="theSVG" style="position: absolute; z-index: -1;" width="100%" height="100%" z-index="-1"><g>' + htmlLines + '</g></svg>';

html +='<div class="row"><div class="col-md-6">'; // left side
for (var i=0; i<q.matchPairs.length; i++) {
html += '<div class="row"><div class="col-md-6">'; // left side
var colors = ["#FFA07A", "#7FFFD4", "#D8BFD8", "#FFD700", "#FFDEAD", "#ADFF2F", "#DB7093", "#AFEEEE", "#FA8072", "#F0E68C"];
for (var i = 0; i < q.matchPairs.length; i++) {
var color = colors[i % colors.length]; // This will cycle through the colors array
var pair = q.matchPairs[i];
html += '<div id="left' + i + '" style="background:#ddddff">';
html += '<p>' + applyFormat(pair.subquestion) + '</p>';
html += '<div id="left' + i + '" style="background:' + color + '">';
// html += '<p>' + applyFormat(pair.subquestion) + '</p>';
html += applyFormat(pair.subquestion);
html += '</div>';
rightSideChoices.add(pair.subanswer);
}
Expand All @@ -104,8 +107,11 @@ function formatMatchingAnswers(q, theDiv, qNum, html) {
html += '<div class="col-md-6">'; // right side
var rightSideArray = Array.from(rightSideChoices);
shuffle(rightSideArray);
for (var it = rightSideArray.values(), val= null; val=it.next().value;) {
html += '<div id="right_' + val.replace(/\s/g, '_') + '" style="background:#ddddff">';

for (var i = 0, it = rightSideArray.values(), val = null; val = it.next().value; i++) {
var originalIndex = q.matchPairs.findIndex(p => p.subanswer === val);
var color = colors[originalIndex % colors.length];
html += '<div id="right_' + val.replace(/\s/g, '_') + '" style="background:' + color + '">';
html += '<p>' + val + '</p>';
html += '</div>';
}
Expand All @@ -114,76 +120,78 @@ function formatMatchingAnswers(q, theDiv, qNum, html) {
theDiv.append(html); html = ""; // force the HTML into the DOM

// set the lines up - search only inside this question's div (theDiv)
for (var i=0; i<q.matchPairs.length; i++) {
for (var i = 0; i < q.matchPairs.length; i++) {
var qDiv = $("#question_" + qNum);
var pair = q.matchPairs[i];
var line = qDiv.find("#line" + i); //console.log("line" + i + ": " + line);
var leftDiv = qDiv.find("#left" + i); //console.log("leftDiv: " + leftDiv);
var subAnswerID = $.escapeSelector("right_" + pair.subanswer.replace(/\s/g, '_'));
var rightDiv = qDiv.find('#' + subAnswerID);
var rightDiv = qDiv.find('#' + subAnswerID);
var pos1 = leftDiv.offset();
var pos2 = rightDiv.offset();
var svg = qDiv.find(".theSVG").offset();
var x1 = pos1.left - svg.left + leftDiv.width();
var y1 = pos1.top + leftDiv.height()/2 - svg.top;
var y1 = pos1.top + leftDiv.height() / 2 - svg.top;
var x2 = pos2.left - svg.left;
var y2 = pos2.top + rightDiv.height()/2 - svg.top;
var y2 = pos2.top + rightDiv.height() / 2 - svg.top;
var inset = 10;
line.attr('d', "M" + x1 + "," + y1 + " C" + (x1 + inset) + "," + y1 + " " + (x2 - inset) + ',' + y2 + " " + x2 + "," + y2);
line.css('stroke', colors[i % colors.length]); // Set the color of the line
qDiv.find(".theSVG").attr('height', pos1.top + leftDiv.height() - svg.top);
}
}

function applyFormat(giftText) {
function applyFormat(giftText, separateParagraph = true) {
var html = "";
let openP = separateParagraph ? "<p>" : "";
let closeP = separateParagraph ? "</p>" : "";
var unescapedString;
console.log(`giftText.text is '${giftText.text}'`)
switch (giftText.format) {
case "html":
case "moodle":
// convert Moodle's embedded line feeds (GIFT) to HTML
unescapedString = giftText.text.replace(/\n/g, '<br\>');
html = unescapedString;
html = openP + unescapedString + closeP;
break;
case "plain":
html = giftText.text;
html = openP + giftText.text + closeP;
break;

case "markdown":
// convert Moodle's embedded line feeds (GIFT) in markdown
// unescapedString = giftText.text.replace(/\n/g, '\n');
html = converter.makeHtml(giftText.text);
html = markdownToHTML.makeHtml(giftText.text);
break;

default:
break;
}
if (html=="") html="&nbsp;"; // special case so div's aren't empty
if (html == "") html = "&nbsp;"; // special case so div's aren't empty
return html;
}

function formatFeedback(feedback) {
return feedback !== null ?
'<p style="margin-left: 40px" class="d-print-none"><em>General feedback:</em> ' +
applyFormat(feedback) + '</p>' : '';
return feedback !== null ?
'<p style="margin-left: 40px" class="d-print-none"><em>General feedback:</em> ' +
applyFormat(feedback) + '</p>' : '';
}

// https://stackoverflow.com/a/2450976/1168342
function shuffle(array) {
var currentIndex = array.length, temporaryValue, randomIndex;

// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;

// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;

// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}

return array;
}
}
4 changes: 2 additions & 2 deletions docs/editor/lib/GIFT.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ MatchRichText "(formatted text excluding '->')"
= format:Format? _ txt:MatchTextChar+ { return {
format:(format!==null ? format : getLastQuestionTextFormat()),
text:(
(format !== "html") ?
(format !== "html" && format !== "markdown") ?
escapedCharacterDecode(removeNewLinesDuplicateSpaces(txt.join('').trim())) :
escapedCharacterDecode(txt.join('')).replace(/\r\n/g,'\n').trim()
)}} // avoid failing tests because of Windows line breaks
Expand All @@ -298,7 +298,7 @@ RichText "(formatted text)"
= format:Format? _ txt:TextChar+ { return {
format:(format!==null ? format : getLastQuestionTextFormat()),
text:(
(format !== "html") ?
(format !== "html" && format !== "markdown") ?
escapedCharacterDecode(removeNewLinesDuplicateSpaces(txt.join('').trim())) :
escapedCharacterDecode(txt.join('')).replace(/\r\n/g,'\n').trim() // avoid failing tests because of Windows line breaks
)}}
Expand Down
4 changes: 2 additions & 2 deletions lib/gift-parser-globals.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/gift-parser-globals.min.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions lib/gift-parser.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/gift-parser.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pegjs-gift-globals.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pegjs-gift.js

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions tests/questions/markdown.gift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[markdown] multiline \nmarkdown

[markdown] multiline
markdown

[markdown] nested lists
- item 1
- nested item 1
- item 2

[markdown] nested lists \n- item 1\n - nested item 1\n- item 2


33 changes: 33 additions & 0 deletions tests/questions/markdown.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[{
"id": null,
"tags": null,
"type": "Description",
"title": null,
"stem": {"format":"markdown", "text":"multiline \nmarkdown"},
"hasEmbeddedAnswers": false
},
{
"id": null,
"tags": null,
"type": "Description",
"title": null,
"stem": {"format":"markdown", "text":"multiline \nmarkdown"},
"hasEmbeddedAnswers": false
},
{
"id": null,
"tags": null,
"type": "Description",
"title": null,
"stem": {"format":"markdown", "text":"nested lists \n- item 1\n - nested item 1\n- item 2"},
"hasEmbeddedAnswers": false
},
{
"id": null,
"tags": null,
"type": "Description",
"title": null,
"stem": {"format":"markdown", "text":"nested lists \n- item 1\n - nested item 1\n- item 2"},
"hasEmbeddedAnswers": false
}
]

0 comments on commit 28a3cd0

Please sign in to comment.