UNPKG

quizzer

Version:

Quizzer is a webserver for collaborative writing lab support. Based on a _fail early, fail often? approach to written language, the tool is particularly suited to second-language learners. The workflow (essay - error - quiz - exam) treats mistakes as an o

459 lines (414 loc) 18 kB
var classID = getParameterByName('classid'); var studentID = getParameterByName('studentid'); var studentKey = getParameterByName('studentkey'); var quizNumber = getParameterByName('quizno'); var pageData = {}; function runResult () { var quizErrors = apiRequest( '/?cmd=myquizresult&classid=' + classID + '&studentid=' + studentID + '&studentkey=' + studentKey + '&quizno=' + quizNumber); if (false === quizErrors) return; var resultList = document.getElementById("result-list"); resultList.innerHTML = ""; if (!quizErrors.length) { var congratsText = document.createTextNode(i18nStrings["congratulations-100"]); var congrats = document.createElement("div"); congrats.setAttribute('class','congratuations'); congrats.appendChild(congratsText); resultList.appendChild(congrats); } else { for (var i=0,ilen=quizErrors.length;i<ilen;i+=1) { var rubric = document.createElement("div"); rubric.setAttribute("class", "rubric"); rubric.innerHTML = markdown(quizErrors[i].rubric); var answerPair = document.createElement('div'); answerPair.setAttribute("class", "answer-pair"); var wrongAnswer = document.createElement('div'); wrongAnswer.setAttribute("class", "wrong-answer"); wrongAnswer.innerHTML = markdown(quizErrors[i].wrong); var rightAnswer = document.createElement('div'); rightAnswer.setAttribute("class", "right-answer"); rightAnswer.innerHTML = markdown(quizErrors[i].right); answerPair.appendChild(rubric); answerPair.appendChild(rightAnswer); resultList.appendChild(answerPair); if (quizErrors[i].goodAnswerStudents.length) { var lst = quizErrors[i].goodAnswerStudents; var studentsPair = document.createElement('div'); studentsPair.setAttribute("class","students-container"); var studentsLabel = document.createElement('div'); studentsLabel.innerHTML = i18nStrings["correct-students-label"]; console.log("XX "+JSON.stringify(i18nStrings,null,2)); studentsPair.appendChild(studentsLabel); var studentsList = document.createElement('div'); studentsList.innerHTML = lst.join(", "); studentsList.setAttribute("class", "correct-students-list"); studentsPair.appendChild(studentsList); answerPair.appendChild(studentsPair); } answerPair.appendChild(wrongAnswer); for (var j=0,jlen=quizErrors[i].comments.length;j<jlen;j+=1) { var commentObj = quizErrors[i].comments[j]; var commentDiv = buildComment(commentObj.commenter,commentObj.comment); answerPair.appendChild(commentDiv); } for (var j=0,jlen=quizErrors[i].rules.length;j<jlen;j+=1) { var rule = quizErrors[i].rules[j]; var ruleContainer = document.createElement('div'); ruleContainer.setAttribute('class','rule-container'); ruleContainer.innerHTML = '<div class="rule-text">' + markdown(rule.ruleText) + '</div>' if (rule.ruleGloss) { ruleContainer.innerHTML += '<div class="rule-gloss">' + markdown(rule.ruleGloss) + '</div>' } answerPair.appendChild(ruleContainer); } } } MathJax.Hub.Queue(["Typeset",MathJax.Hub]); } function buildComment (commenter,comment) { var commentContainer = document.createElement('div'); commentContainer.setAttribute('class', 'comment-container'); commenterDiv = document.createElement('div'); commenterDiv.setAttribute('class', 'commenter-name'); commenterDiv.innerHTML = commenter; commentDiv = document.createElement('div'); commentDiv.innerHTML = markdown(comment); commentContainer.appendChild(commenterDiv); commentContainer.appendChild(commentDiv); return commentContainer; } /* Rules */ function setRuleButtons () { var ruleLangButtons = document.getElementsByClassName('rule-lang-buttons'); // API call var rows = apiRequest( '/?cmd=readrulelangs&classid=' + classID + '&studentid=' + studentID + '&studentkey=' + studentKey ); if (false === rows) return; var ruleLangButtons = document.getElementById('rule-lang-buttons'); for (var i=0,ilen=ruleLangButtons.childNodes.length;i<ilen;i+=1) { ruleLangButtons.removeChild(ruleLangButtons.childNodes[0]); } // Only show buttons if the student has open rules. for (var i=0,ilen=rows.length;i<ilen;i+=1) { var row = rows[i]; var button = document.createElement('input'); button.setAttribute('type', 'button'); button.setAttribute('class', 'button rule-lang-buttons'); button.setAttribute('onclick', 'setButtonMode("' + row.lang + '","' + row.langName + '")'); button.value = 'Glosses: ' + row.langName; ruleLangButtons.appendChild(button); } } function setButtonMode (mode,langName) { var ruleLangButtons = document.getElementsByClassName('rule-lang-buttons'); var returnToMainDisplayButton = document.getElementById('return-to-main-display-button'); var mainDisplay = document.getElementsByClassName('main-display'); var rulesDisplay = document.getElementsByClassName('rules-display'); var studentLanguage = document.getElementsByClassName('student-language'); //var mainDisplayTitle = document.getElementById('main-display-title'); //var rulesDisplayTitle = document.getElementById('rules-display-title'); if (mode) { pageData.lang = mode; pageData.langName = langName; buildRulesList(mode,langName); setNodesDisplay(ruleLangButtons,false); setNodesDisplay(mainDisplay,false); setNodesDisplay(rulesDisplay,true); setNodesInnerHtml(studentLanguage,langName); returnToMainDisplayButton.style.display = 'inline'; } else { setNodesDisplay(ruleLangButtons,true); setNodesDisplay(mainDisplay,true); setNodesDisplay(rulesDisplay,false); returnToMainDisplayButton.style.display = 'none'; } } function setNodesDisplay (nodes,displayMode) { for (var i=0,ilen=nodes.length;i<ilen;i+=1) { var node = nodes[i]; if (!displayMode) { node.style.display = 'none'; } else if (node.tagName === 'TABLE') { node.style.display = 'table'; } else if (node.tagName === 'DIV') { node.style.display = 'block'; } else { node.style.display = 'inline'; } } }; function setNodesInnerHtml (nodes,innerHTML) { for (var i=0,ilen=nodes.length;i<ilen;i+=1) { nodes[i].innerHTML = innerHTML; } }; function buildRulesList () { var mode = pageData.lang; var langName = pageData.langName; // zzz //var ruleLanguageName = document.getElementById('rule-language'); //ruleLanguageName.innerHTML = langName; // API call for list of rules (admin user + current commenter) var classID = getParameterByName('classid'); var studentID = getParameterByName('studentid'); var studentKey = getParameterByName('studentkey'); var rulesForLang = document.getElementById('rules-for-lang'); var rows = apiRequest( '/?cmd=readrules&classid=' + classID + '&studentid=' + studentID + '&studentkey=' + studentKey , { lang:mode } ); if (false === rows) return; for (var i=0,ilen=rulesForLang.childNodes.length;i<ilen;i+=1) { rulesForLang.removeChild(rulesForLang.childNodes[0]); } for (var i=0,ilen=rows.length;i<ilen;i+=1) { var row = rows[i]; var questionIDs = row.questionIDs.split(','); var tr = document.createElement('tr'); tr.setAttribute('id','rule-' + row.ruleID); var onClick; var rowStyle; if (questionIDs.length > 1) { if (row.count) { // Study candidate, display rendered, offer to send questions onClick = ' onclick="showRule(this,true,true)"'; // Yellow border rowStyle = " study-needed-rule"; } else { // Cleared, display source, offer to edit onClick = ' onclick="openRule(this)"'; // Green border rowStyle = " cleared-rule"; } } else { // Read-only rule, display rendered onClick = ' onclick="showRule(this,true)"'; // Grey border rowStyle = ""; } tr.innerHTML = '<td class="left' + rowStyle + '"' + onClick + '><div>' + markdown(row.ruleText) + '</div></td><td class="right"><input type="button" class="button float-right" value="Save" onclick="saveRule(this)" style="display:none;"/><input type="button" class="button float-right" value="Edit" onclick="editRule(this)" style="display:none;"/><input type="button" class="button no-float" value="Del" onclick="confirmDelete(this,\'deleteRule\')" style="display:none;"/><input type="button" class="button float-right" value="Test Yourself!" onclick="window.location.href = \'' + composeRetryURL(row.questionIDs) + '\'" style="display:none;"></td>'; rulesForLang.appendChild(tr); } }; function composeRetryURL(ids) { // So what the hell does this do? // It will need access to the questionIDs reported from the call, so that string should // be set on a hidden node or an attribute. If we have that, we can generate the mail ... // and then it's up to other architecture in the system. var questionIDs = ids.split(','); // This can either send a mail out with a link, or it can immediately // open a browser tab that contains the targeted quizzlet. Immediate // opening probably makes more sense -- unless that won't play well // on cellphones, which some students will be using. // Probably the smoothest thing would be to not open a new anything. // Click the button, and the mini-quiz loads in the current // window and tab. Finish the quiz, get your feedback, then click // continue (somewhere), and the rules-list is called again, with // updated decorations. // So you'll need all of the parameters necessary to regenerate the // rules list in the reTest server call. // Need gloss language, so we can come back here. return fixPath('/?studentid=' + studentID + '&studentkey=' + studentKey + '&classid=' + classID + '&quizno=' + quizNumber + '&questionids=' + questionIDs + '&glosslang=' + pageData.lang); } function showRule (node,readOnly,offerRetest) { var rownode = node.parentNode; var testButton = rownode.childNodes[1].childNodes[3]; var ruleID = rownode.id.split('-').slice(-1)[0]; // API call var row = apiRequest( '/?cmd=readonerule&classid=' + classID + '&studentid=' + studentID + '&studentkey=' + studentKey + '&quizno=' + quizNumber ,{ ruleid:ruleID, lang:pageData.lang } ); if (false === row) return; var tr = document.createElement('tr'); setDisplaySourceView(tr,row); if (offerRetest) { testButton.style.display = 'inline'; node.setAttribute('onclick','closeRule(this,true,true);'); } else { node.setAttribute('onclick','closeRule(this,true);'); } rownode.parentNode.insertBefore(tr,rownode.nextSibling); setChildHeight(rownode.nextSibling.childNodes[1].childNodes[0]); setChildHeight(rownode.nextSibling.childNodes[0].childNodes[0]); } function openRule (node) { var rownode = node.parentNode; var ruleID = rownode.id.split('-').slice(-1)[0]; // API call var row = apiRequest( '/?cmd=readonerule&classid=' + classID + '&studentid=' + studentID + '&studentkey=' + studentKey + '&quizno=' + quizNumber ,{ ruleid:ruleID, lang:pageData.lang } ); if (false === row) return; var saveButton = rownode.childNodes[1].childNodes[0]; saveButton.style.display = 'inline'; var tr = document.createElement('tr'); setEditableSourceView(tr,row); rownode.parentNode.insertBefore(tr,rownode.nextSibling); node.setAttribute('onclick','void(0);'); //node.setAttribute('onclick','closeRule(this);'); setChildHeight(rownode.nextSibling.childNodes[1].childNodes[0]); setChildHeight(rownode.nextSibling.childNodes[0].childNodes[0]); }; function setEditableSourceView(tr,row) { tr.innerHTML = '<td class="show-box"><pre class="show-box-child">' + row.stringOrig + '</pre></td><td class="edit-box"><textarea>' + row.stringTrans + '</textarea></td>' }; function setDisplaySourceView(tr,row) { tr.innerHTML = '<td class="show-box"><div class="show-box-child">' + markdown(row.stringOrig) + '</div></td><td class="show-box"><div class="show-box-child">' + markdown(row.stringTrans) + '</div></td>' }; function saveRule (node) { var rownode = node.parentNode.parentNode; var orignode = rownode.nextSibling.childNodes[0]; var textnode = rownode.nextSibling.childNodes[1].childNodes[0]; var rulenode = rownode.childNodes[0].childNodes[0]; ruleText = rulenode.tagName === 'TEXTAREA' ? rulenode.value : null; var glossText = textnode.value; var ruleID = rownode.id.split('-').slice(-1)[0]; var saveButton = rownode.childNodes[1].childNodes[0]; var editButton = rownode.childNodes[1].childNodes[1]; var deleteButton = rownode.childNodes[1].childNodes[2]; // API call var classID = getParameterByName('classid'); var studentID = getParameterByName('studentid'); var studentKey = getParameterByName('studentkey'); var row = apiRequest( '/?cmd=saveonerule&classid=' + classID + '&studentid=' + studentID + '&studentkey=' + studentKey ,{ ruleid:ruleID, lang:pageData.lang, glosstext:glossText, ruletext:ruleText } ); if (false === row) return; if (ruleText) { var ruleTextNode = document.createElement('div'); ruleTextNode.innerHTML = markdown(row.ruleText); rulenode.parentNode.replaceChild(ruleTextNode,rulenode); ruleTextNode.parentNode.setAttribute('onclick','closeRule(this);'); } orignode.innerHTML = '<div class="show-box-child">' + markdown(row.stringOrig) + '</div>'; var renderedNode = document.createElement('div'); renderedNode.innerHTML = markdown(row.stringTrans); textnode.parentNode.replaceChild(renderedNode,textnode); saveButton.style.display = 'none'; editButton.style.display = 'inline'; deleteButton.style.display = 'none'; node.parentNode.previousSibling.setAttribute('onclick','closeRule(this);'); }; function editRule (node) { var rownode = node.parentNode.parentNode; var renderednode = rownode.nextSibling.childNodes[1].childNodes[0]; var ruleID = rownode.id.split('-').slice(-1)[0]; var saveButton = rownode.childNodes[1].childNodes[0]; var editButton = rownode.childNodes[1].childNodes[1]; var deleteButton = rownode.childNodes[1].childNodes[2]; // API call var row = apiRequest( '/?cmd=readonerule&classid=' + classID + '&studentid=' + studentID + '&studentkey=' + studentKey ,{ ruleid:ruleID, lang:pageData.lang } ); if (false === row) return; if (row.ruleSource) { var renderedrule = rownode.childNodes[0].childNodes[0]; var textarea = document.createElement('textarea'); textarea.innerHTML = row.ruleSource; renderedrule.parentNode.replaceChild(textarea,renderedrule); deleteButton.style.display = 'inline'; } setEditableSourceView(rownode.nextSibling,row) saveButton.style.display = 'inline'; editButton.style.display = 'none'; node.parentNode.previousSibling.setAttribute('onclick','void(0);'); setChildHeight(rownode.nextSibling.childNodes[1].childNodes[0]); setChildHeight(rownode.nextSibling.childNodes[0].childNodes[0]); }; function closeRule (node,readOnly,offerRetest) { var rownode = node.parentNode; var saveButton = rownode.childNodes[1].childNodes[0]; var editButton = rownode.childNodes[1].childNodes[1]; var deleteButton = rownode.childNodes[1].childNodes[2]; var testButton = rownode.childNodes[1].childNodes[3]; saveButton.style.display = 'none'; editButton.style.display = 'none'; deleteButton.style.display = 'none'; var contentrownode = rownode.nextSibling; contentrownode.parentNode.removeChild(contentrownode); if (offerRetest) { node.setAttribute('onclick', 'showRule(this,true,true);'); testButton.style.display = 'none'; } else if (readOnly) { node.setAttribute('onclick', 'showRule(this,true);'); } else { node.setAttribute('onclick', 'openRule(this);'); } }; function setChildHeight (textarea) { var height = textarea.parentNode.offsetHeight; textarea.style.height = height + 'px'; };