(function ($) {
$.fn.changeElementType = function (newType) {
var attrs = {};
$.each(this[0].attributes, function (idx, attr) {
attrs[attr.nodeName] = attr.nodeValue;
});
this.replaceWith(function () {
return $('<' + newType + '/>', attrs).append($(this).contents());
});
};
})(jQuery);
// stuff that can be done immediately
(function () {
//$('[data-type="chapter"]').changeElementType('main');
$('#manuscript').changeElementType('main');
var $h1 = $('h1.section-title');
var h1_text = $h1.find('[data-type="title"]').text();
$h1.text(h1_text);
$h1.addClass('fixed');
$('[data-type="question"]').each(function () {
var $h3 = $(this).find('h3');
var number = $h3.find('[data-type="number"]').text();
$h3.text('Question ' + number);
$h3.changeElementType('h2');
});
//$('body').append('
')
$('br.clear').remove();
})();
var Activity_subtype = Activity.extend({
update_question_action_div: function (question_index) {
return;
/*
var question = this.questions[question_index];
// calculate points_awarded and points_possible
var points_awarded = 0;
var points_possible = 0;
var points_provisional = false;
for (var i = 0; i < question.queries.length; ++i) {
var query = question.queries[i];
points_awarded += query.getPointsAwarded();
points_possible += query.getPointsPossible();
if (query.pointsAreProvisional() == true) {
points_provisional = true;
}
}
// round to at most two decimal places
points_awarded = Math.round(points_awarded * 100) / 100;
points_possible = Math.round(points_possible * 100) / 100;
// hide submit button (and any other similar buttons that might be added by subtypes), but show points earned
var jq = $("#question_action_div_" + question.index);
jq.find(".question_submit_button").hide();
var points_html = "
Points awarded: " + points_awarded + " out of " + points_possible;
if (points_provisional) {
points_html += " (provisional)";
points_html += "
";
}
var jq = $("#question_action_div_" + question.index);
jq.find(".points_awarded_div").remove();
if (jq.find(".question_feedback").length > 0) {
jq.find(".question_feedback").after(points_html);
} else {
jq.prepend(points_html);
}
*/
},
restore_saved_answers: function () {
// skip page queries (questions[0])
for (var i = 1; i < this.questions.length; ++i) {
var question = this.questions[i];
// prepare for question_report_text questions
var query_responses;
if (question.md_set("question_report_text")) {
query_responses = "" + Get_ARGA_QuestionData(this.get_question_number(question))
query_responses = query_responses.split(this.query_responses_separator);
}
var restored_all_answers = true;
var all_answers_correct = true;
for (var j = 0; j < question.queries.length; ++j) {
var query = question.queries[j];
var saved_answer, saved_grade;
// get saved answer and grade out of the questionData for question_report_text questions
if (question.md_set("question_report_text")) {
if (query_responses[j] != null) {
var arr = query_responses[j].split(this.query_responses_grade_separator);
saved_answer = arr[0];
saved_grade = arr[1];
} else {
saved_grade = saved_answer = "";
}
// or out of learnerResponse / questionData for single-query questions
} else {
var ARGA_question_number = this.get_query_number(question, j);
saved_answer = Get_ARGA_LearnerResponse(ARGA_question_number);
// we stored the original grade in questionData
saved_grade = Get_ARGA_QuestionData(ARGA_question_number)
}
// if we found a grade...
if (saved_grade !== "" && saved_grade >= 0) {
// restore the answer
query.restoreAnswerFromARGA(saved_answer);
query.setGrade(saved_grade);
// then re-render the query in review mode
query.jq.html(query.getHTML("review"));
if (query.isCorrect() == false) {
all_answers_correct = false;
}
} else {
restored_all_answers = false;
}
}
if (restored_all_answers) {
// update the submit div for the question
this.update_question_action_div(i);
// Show appropriate feedback. If the question responses were submitted,
// the student must have finished the question, so we don't have to worry
// about hints.
this.show_question_feedback(question, all_answers_correct, false);
// if the item is in a sequence, show the next question
this.show_next_question(question);
// NEED TO CHECK TO MAKE SURE THIS IS WORKING PROPERLY
// If the question is in a sequence and the sequence is complete, call show_closing_material
var qs = question.question_sequence;
if (qs != null && qs.sequence_complete == "partial") {
this.show_closing_material(qs.index);
}
// update section status
player.update_section_status();
// remove Submit button
$('#question_submit_button_' + i).remove();
}
}
},
ARGA_initialization_alert: function () {
// This overrides the standard ARGA initialization message, which doesn't
// tell the user he/she can resubmit (or tell him his grade)
var grade = Get_ARGA_Grade();
var due_date_passed = (Get_ARGA_Data("due_date_has_passed") == "1");
var msg_title = "";
var msg_text = "";
var buttons;
due_date_passed = false;
if (grade != "" && grade != null && grade >= 0) {
// if resubmissions are allowed...
/*
if (player.md.allow_resubmission == "true") {
// if due date has not passed, give the student the option of resubmitting or reviewing
if (!due_date_passed) {
msg_title = "You have completed this activity."
msg_text = "
Your grade (" + grade + "%) has been submitted. Would you like to:
"
+ "
Keep your current grade and review your previous answers
"
+ "
Or reset your submission and try the activity again?
You have completed this activity, and your grade (" + grade + "%) has been submitted. Since the due date for the activity has now passed, you cannot re-submit answers to the activity questions.
"
buttons = [{ text: "OK", click: player.activity.ARGA_initialization_final }];
}
// resubmissions are not allowed
}
else {
*/
msg_title = "You have completed this activity.";
msg_text = "Please refer to the grade book for your final score.";
/*
buttons = [{ text: "OK", click: player.activity.ARGA_initialization_final }];
*/
//}
// grade has not been submitted
}
else {
// if due date has passed, tell the user "tough luck". Otherwise show nothing.
/*
if (due_date_passed) {
msg = "
The due date for this activity has passed. You can still review the activity, but no answers will be submitted and no grade will be recorded.
"
;
buttons = [{ text: "OK", click: player.activity.ARGA_initialization_final }];
}
*/
}
// if we need a message, show it in a jquery UI dialog
if (msg_title !== "") {
/*
msg = "
" + msg + "
";
$("body").append(msg);
$("#arga_init_dialog").dialog({ title: "Please Note", width: 450, modal: true, buttons: buttons });
*/
ARIAmodal.openModal(
{
modalId: 'verify_submit',
top: player.getModalTop(),
title: msg_title,
text: msg_text,
buttons: [
{
text: 'OK', onClick: function () {
player.activity.ARGA_initialization_final();
document.getElementById('manuscript').click();
player.setFocus(document.body);
//document.body.focus();
}
}
],
onEsc: function () {
player.activity.ARGA_initialization_final();
document.getElementById('manuscript').click();
player.setFocus(document.body);
//document.body.focus();
}
}
);
} else {
player.activity.ARGA_initialization_final();
}
},
question_submit_button: function (q) {
// define question_submit_button_label as a variable so it can be overridden
var button_html = "";
return button_html;
},
add_question: function (index, element) {
var a = player.activity; // this fn gets called within the scope of a jquery each, so we can't refer to "this"
var jq = $(element);
// see if we're in a question_pool or question_sequence block
var qs_parent = jq.parents("[data-block_type=question_sequence], [data-block_type=question_sequence_one_at_a_time]");
var q = a.questions[a.questions.length] = new Question({
"index": a.questions.length
, "number": jQuery.trim($("[data-type='number']", jq).html())
, "title": jQuery.trim($("[data-type='title']", jq).html())
, "jq": jq
, "points_possible": 0
});
// store the question index in the DOM too
jq.attr("data-question_index", q.index);
// get question queries
a.question_being_initialized = q;
$("[data-type='query']", jq).each(a.add_query);
// if the question has queries, add bling to the bottom
if (q.queries.length > 0) {
var html = "
";
var submit_handler;
// add a submit button if we're supposed to have one
// (image map and matching questions, which should contain one and only one query, don't have submit buttons)
if (q.queries[0].hasSubmitButton === true) {
// "answer_one" pool mode (yet to be fully implemented...)
if (q.pool_mode == 'answer_one') {
html += "";
submit_handler = player.activity.Show_Submit;
} else {
html += a.question_submit_button(q);
submit_handler = player.activity.submit_question;
}
}
// add a "give up" button if we're supposed to have one
// (image map questions, which should contain one and only one query, should have this button)
if (q.queries[0].hasGiveUpButton === true) {
html += "";
submit_handler = player.activity.give_up_question;
}
html += "
";
jq.append(html);
// bind the submit_handler function to the button, passing in the question_index
//$("#question_submit_button_" + q.index).click({ question_index: q.index }, submit_handler);
$("#question_submit_button_" + q.index).click(function (event) {
event.preventDefault();
event.stopPropagation();
submit_handler(q.index, event);
});
// float instructor controls to right of action button
jq.prepend(a.instructor_question_controls(q));
// also, determine question points and weight at this time
for (var i = 0; i < q.queries.length; ++i) {
q.points_possible += q.queries[i].getPointsPossible();
}
// round to two decimal places, in case there are decimals
q.points_possible = Math.round(q.points_possible * 100) / 100;
}
// now that the question has been created, deal with sequences and pools
if (qs_parent.length > 0) {
// get sequence index and item
var qs_index = qs_parent.attr("question_sequence_index") * 1;
var qs = a.question_sequences[qs_index];
// place in sequence
var sequence_num = qs.questions.length;
qs.questions[sequence_num] = q;
// place reference to sequence in question
q.question_sequence = qs;
q.question_sequence_index = sequence_num;
// if this isn't #1, hide the question
if (sequence_num > 0) {
jq.hide();
}
// update the sequence navigator if it's there
$("#question_sequence_max_index_" + qs.index).html(sequence_num + 1);
}
},
submit_question: function (question_index) {
// the arg may be a number or an event object; in the latter case...
if (typeof question_index == "object") {
// extract the question_index from the object
question_index = question_index.data.question_index;
}
$('.essay_question_evaluation_feedback').each(function () {
$(this).removeClass('show').text('');
});
var t = player.activity;
var question = t.questions[question_index];
var all_answers_correct = true;
// for each query in the question...
for (var i = 0; i < question.queries.length; ++i) {
var query = question.queries[i];
// evaluate the answer. If evaluateAnswer returns false, the answer isn't submittable at this time --
// most likely because it's a free-response answer that needs to be evaluated via MAVE.
var answer_submittable = query.evaluateAnswer(question_index);
if (answer_submittable === false) {
// as soon as we get an unsubmittable answer, we return. submit_question
// will be called again, either by the callback fn of MAVE or because the student
// resubmits. At that point we'll catch any additional free-response answers that need
// checking, or we'll finish this loop here and move on.
return;
}
all_answers_correct = all_answers_correct && query.isCorrect();
}
ARIAmodal.openModal(
{
modalId: 'verify_submit',
top: player.getModalTop(),
title: 'Really submit answer?',
buttons: [
{
text: 'Submit', onClick: function() {
player.activity.submit_essay_question(question_index);
}
},
{
text: 'Cancel', onClick: function () {
player.setFocus('question_submit_button_' + question_index);
}
}
],
closeFocus: 'question_submit_button_' + question_index
}
);
return;
/*
// if we made it to here, we're at least going to show which items are correct and incorrect
// we might overwrite with review mode below, but that's OK
for (var i = 0; i < question.queries.length; ++i) {
var query = question.queries[i];
query.jq.html(query.getHTML("review_correct_incorrect"));
}
// update question tries
++question.tries;
// if answer is incorrect, and max_tries is set, and # of tries is less than max_tries
// (and the user didn't just give up)
if ((!all_answers_correct && question.md.max_tries != null && question.tries < question.md.max_tries) && question.gave_up != true) {
// tell user he can try again
t.show_question_feedback(question, false, true);
return;
} else {
t.show_question_feedback(question, all_answers_correct, false);
}
// if we make it to here we need to set ARGA info for the question, and show queries in review mode
// if md.question_report_text is set, we submit the question as a whole, rather than as individual queries
var query_correct_answers = "";
var query_responses = "";
var query_responses_for_questionData = "";
var query_grade_sum = 0;
// for each query in the question...
for (var i = 0; i < question.queries.length; ++i) {
var query = question.queries[i];
// establish a question number to use
var query_number = t.get_query_number(question, i);
// get a query weight
var query_weight = question.get_weight();
// if the question has more than one query, divide weight accordingly
if (question.queries.length > 1) {
query_weight = Math.round(query_weight / question.queries.length);
}
// if credit_after_max_tries is set, give at least that credit now, as long as the student tried
if (question.md.credit_after_max_tries != null) {
var query_grade = query.getGradeForARGA();
if (query_grade >= 0 && query_grade < question.md.credit_after_max_tries) {
query.overrideGrade(question.md.credit_after_max_tries * 1);
}
}
// set the ARGA response, unless we're saving one response for the whole question
if (!question.md_set("question_report_text")) {
t.ARGA_set_query_response(query, query_number, query_weight);
// otherwise compose query roll-ups
} else {
if (query_correct_answers != "") {
query_correct_answers += " / ";
query_responses += " / ";
query_responses_for_questionData += t.query_responses_separator;
}
query_correct_answers += query.getCorrectAnswerForARGA();
query_responses += query.getUserAnswerForARGA();
// see restore_saved_answers for how this is used later
query_responses_for_questionData += query.getUserAnswerForARGA()
+ t.query_responses_grade_separator
+ query.getOriginalGrade();
query_grade_sum += query.getGradeForARGA() * 1;
}
// show in review mode, unless question metadata says not to show correct answers
if (question.md.show_correct_answers != "false") {
query.jq.html(query.getHTML("review"));
}
}
// if we're saving one response for the whole question, save here
if (question.md_set("question_report_text")) {
var question_grade = Math.round(query_grade_sum / question.queries.length);
t.ARGA_set_question_response(question, query_correct_answers, query_responses, question_grade, query_responses_for_questionData);
}
// grade the activity
t.grade_activity();
// then if ARGA is running, submit data; show_grade_saved_message will be called on completion.
if (player.ARGA_running) {
t.ARGA_submit_data();
}
// update the question_action_div
t.update_question_action_div(question_index);
// if the item is in a sequence, show the next question
t.show_next_question(question);
// update section status
player.update_section_status();
*/
},
show_grade_saved_message: function () {
// Only do the below if we are in PX
if (!player.inPX()) {
return;
}
if (player.activity.answered_all_queries && !player.user_has_received_completion_alert) {
/*
setTimeout('Standard_Dialog.alert("You have completed the activity, and your grade has been submitted.");', 20);
*/
// if all questions have been answered, show completed pop-up
setTimeout(function () {
ARIAmodal.openModal(
{
modalId: 'verify_submit',
top: player.getModalTop(),
title: 'You have completed this activity.',
text: 'You will receive full credit now. Your instructor will review your answers and adjust your score if needed.',
buttons: [
{
text: 'OK', onClick: function () {
player.setFocus(document.body);
//document.body.focus();
}
}
]
}
);
}, 500);
player.user_has_received_completion_alert = true;
}
},
show_grade_saved_message_new: function () {
// Only do the following if we are NOT in PX
if (player.inPX()) {
return;
}
// if the user has answered all queries AND the user hasn't been told this already,
// tell them now
if (player.activity.answered_all_queries && !player.user_has_received_completion_alert) {
/*
setTimeout('Standard_Dialog.alert("You have completed the activity, and your grade has been submitted.");', 20);
*/
// if all questions have been answered, show completed pop-up
setTimeout(function () {
ARIAmodal.openModal(
{
modalId: 'verify_submit',
top: player.getModalTop(),
title: 'You have completed this activity.',
text: 'You will receive full credit now. Your instructor will review your answers and adjust your score if needed.',
buttons: [
{
text: 'OK', onClick: function () {
player.setFocus(document.body);
//document.body.focus();
}
}
]
}
);
}, 100);
player.user_has_received_completion_alert = true;
}
},
submit_essay_question: function(question_index) {
var t = player.activity;
var question = t.questions[question_index];
// if we make it to here we need to set ARGA info for the question, and show queries in review mode
// if md.question_report_text is set, we submit the question as a whole, rather than as individual queries
var query_correct_answers = "";
var query_responses = "";
var query_responses_for_questionData = "";
var query_grade_sum = 0;
// for each query in the question...
for (var i = 0; i < question.queries.length; ++i) {
var query = question.queries[i];
// establish a question number to use
var query_number = t.get_query_number(question, i);
// get a query weight
var query_weight = question.get_weight();
// if the question has more than one query, divide weight accordingly
if (question.queries.length > 1) {
query_weight = Math.round(query_weight / question.queries.length);
}
// if credit_after_max_tries is set, give at least that credit now, as long as the student tried
if (question.md.credit_after_max_tries != null) {
var query_grade = query.getGradeForARGA();
if (query_grade >= 0 && query_grade < question.md.credit_after_max_tries) {
query.overrideGrade(question.md.credit_after_max_tries * 1);
}
}
// set the ARGA response, unless we're saving one response for the whole question
if (!question.md_set("question_report_text")) {
t.ARGA_set_query_response(query, query_number, query_weight);
// otherwise compose query roll-ups
}
else {
if (query_correct_answers != "") {
query_correct_answers += " / ";
query_responses += " / ";
query_responses_for_questionData += t.query_responses_separator;
}
query_correct_answers += query.getCorrectAnswerForARGA();
query_responses += query.getUserAnswerForARGA();
// see restore_saved_answers for how this is used later
query_responses_for_questionData += query.getUserAnswerForARGA()
+ t.query_responses_grade_separator
+ query.getOriginalGrade();
query_grade_sum += query.getGradeForARGA() * 1;
}
// show in review mode, unless question metadata says not to show correct answers
if (question.md.show_correct_answers != "false") {
query.jq.html(query.getHTML("review"));
}
}
// if we're saving one response for the whole question, save here
if (question.md_set("question_report_text")) {
var question_grade = Math.round(query_grade_sum / question.queries.length);
t.ARGA_set_question_response(question, query_correct_answers, query_responses, question_grade, query_responses_for_questionData);
}
// remove Submit button for this question
$('#question_submit_button_' + question_index).remove();
// grade the activity
t.grade_activity();
// then if ARGA is running, submit data; show_grade_saved_message will be called on completion.
if (player.ARGA_running) {
t.ARGA_submit_data();
}
// update the question_action_div
t.update_question_action_div(question_index);
// if the item is in a sequence, show the next question
t.show_next_question(question);
// update section status
player.update_section_status();
if (!player.activity.answered_all_queries) {
player.setFocus('query_answer_' + question_index);
//$('#query_answer_' + question_index).focus();
}
t.show_grade_saved_message_new();
/*
// if all questions have been answered, show completed pop-up
ARIAmodal.openModal(
{
modalId: 'verify_submit',
buttons: [
{
text: 'OK', onClick: function () {
document.body.focus();
}
}
]
}
);
*/
},
});
var Player_subtype = Player.extend({
ACTIVITY_COMPLETED: false,
DUE_DATE_HAS_PASSED: false,
setFocus(arg) {
if (typeof arg === 'string') {
arg = document.getElementById(arg);
}
setTimeout(function () {
try {
arg.focus();
}
catch (err) {
console.log('setFocus: ' + err.message);
}
}, 250);
},
inPX: function () {
if (typeof window.PX !== 'undefined') {
return true;
}
if (typeof window.parent.PX !== 'undefined') {
return true;
}
return false;
},
initialize: function (id) {
this._super();
this.activity = new Activity_subtype();
},
initialize2: function () {
this._super();
if (player.ARGA_running) {
try {
var dejs_arr = ARGA_API.dejs_data;
for (var i = 0; i < dejs_arr.length; i++) {
if (dejs_arr[i].name === 'cmi.completion_status') {
this.ACTIVITY_COMPLETED = (ARGA_API.dejs_data[i].value == 'completed');
break;
}
}
}
catch (err) {
safe_log('initialize2: Can\'t get cmi.completion_status: ' + err);
}
if (Get_ARGA_Data('due_date_has_passed') == 1) {
this.DUE_DATE_HAS_PASSED = true;
}
}
// brb: If the due date has passed and the activity has not been
// completed then remove all submit buttons, disable all radio buttons
// and give user message
if (this.DUE_DATE_HAS_PASSED && !this.ACTIVITY_COMPLETED) {
$('button.question_submit_button').each(function () {
var $this = $(this);
$this.remove();
});
// disable all questions
$('[data-type="question"]').each(function () {
var $this = $(this);
//$this.find('input[type="radio"]').attr("disabled", true);
$this.find('textarea').attr("disabled", true);
//$this.find('input').attr("disabled", true);
//$this.find('select').attr("disabled", true);
});
ARIAmodal.openModal(
{
modalId: 'verify_submit',
top: player.getModalTop(),
title: 'The due date for this assignment has now passed.',
text: 'You will not be able to submit answers for a grade. '
+ 'Please contact your instructor for further information.',
buttons: [
{
text: 'OK', onClick: function () {
//player.activity.ARGA_initialization_final();
document.getElementById('manuscript').click();
player.setFocus(document.body);
//document.body.focus();
}
}
],
onEsc: function () {
//player.activity.ARGA_initialization_final();
document.getElementById('manuscript').click();
player.setFocus(document.body);
//document.body.focus();
}
}
);
return;
}
},
show_navigation: function () {
return;
/*
var html = "
"
$("#manuscript").prepend(html);
$("#section_navigation").show();
*/
},
getModalTop: function () {
var fneContent = window.parent.document.getElementById('fne-content');
if (fneContent === null || fneContent === undefined) {
return undefined;
}
var fneHeight = fneContent.clientHeight;
var scrollTop = fneContent.scrollTop;
return scrollTop + (fneHeight / 2);
},
/* brb: Overriding this method in order to keep the activity from
updating ARGA if the activity has been completed or hasn't and is passed due date
so that it doesn't overwrite a manual grade change in the grade book (see JIRA LP-127) */
update_section_status: function () {
if (this.section_currently_showing != null && this.last_available_section <= this.section_currently_showing) {
var s = this.get_current_section();
s.all_questions_answered = true;
// if the current section has any questions, see if they've all been answered
var qs_to_check = [];
s.jq.find("[data-type=question]").each(function (index, element) {
var q_index = $(element).attr("data-question_index");
var question = player.activity.questions[q_index];
s.all_questions_answered = s.all_questions_answered && question.is_complete();
if (question.question_sequence != null) {
for (var i = 0; i < qs_to_check.length; ++i) {
if (qs_to_check[i] == question.question_sequence) break;
}
if (i == qs_to_check.length) {
qs_to_check.push(question.question_sequence);
}
}
});
// now check question sequences to make sure they're done too
s.all_question_sequences_completed = true;
for (var i = 0; i < qs_to_check.length; ++i) {
s.all_question_sequences_completed = s.all_question_sequences_completed && (qs_to_check[i].sequence_complete == "complete");
}
if (s.all_questions_answered && s.all_question_sequences_completed) {
this.last_available_section = this.section_currently_showing + 1;
}
}
this.fill_in_previous_query_responses();
// if ARGA is initialized and we need to restore the user to his last position when he returns,
if (this.ARGA_running && player.md.restore_last_viewed_section == "true") {
// if we're viewing a page other than the one currently saved as LVS (last-viewed section)
var lvs = Get_ARGA_Data("LVSX");
if (this.section_currently_showing != null && this.section_currently_showing != lvs) {
// store LVS/LAS to register the last-viewed/last-available page,
// and save ARGA so it gets registered
Set_ARGA_Data("LVSX", this.section_currently_showing);
Set_ARGA_Data("LASX", this.last_available_section);
/* brb: If the activity has not been completed then save LVSX, but if
it has been completed then do not save LVSX because that will also
send the grade to the PX grade book again, overwriting any manual
grade changes the instructor may have made. */
/* brb: also don't want to do this if the due date has passed */
if (!this.ACTIVITY_COMPLETED && !this.DUE_DATE_HAS_PASSED) {
this.activity.ARGA_submit_data(false);
}
}
}
},
});
player = new Player_subtype();
var Essay_Query = Essay_Query.extend({
getUserAnswerForARGA: function () {
if (this.user_answer == null || this.user_answer == "") {
return "Not answered";
}
else {
var sanitizedAnswer = sanitizeHtml(this.user_answer, {
allowedTags: ['br'],
allowedAttributes: {},
disallowedTagsMode: 'recursiveEscape'
});
//return this.user_answer;
return sanitizedAnswer;
}
},
set_evaluation_feedback: function (html) {
$('#essay_question_evaluation_feedback_' + this.query_index).addClass('show').html(html);
},
query_text_html: function (query_index, question_number, mode) {
if (this.query_text != "" && this.md._hide_query_text != "true") {
// replace newlines with
var qt = jQuery.trim(this.query_text).replace(/\n/g, " ")
if (mode === 'review') {
return "
Question: " + qt + "
";
}
else {
return "";
}
}
else {
return "";
}
},
getHTML: function(mode) {
// start with the query text, if there
var html = this.query_text_html(this.query_index, this.parent_question.index, mode);
var val, disabled;
if (!this.userHasAnswered() || mode == 'preview') {
val = "";
disabled = "";
// otherwise we have an answer, so fill it in
}
else {
// make sure we convert double quotes to " for placement in 'value="xxx"' attributes
val = sanitizeHtml(this.user_answer, {
allowedTags: [],
allowedAttributes: {},
disallowedTagsMode: 'recursiveEscape'
});
// convert breaks to newlines
val = val.replace(/<br \/>/g, ' ');
val = val.replace(/<br\/>/g, " ");
val = val.replace(/<br>/g, " ");
// also disable the input if we're not in review_correct_incorrect mode
if (mode != "review_correct_incorrect") {
disabled = "disabled";
}
}
if (mode === 'review') {
html += "
"
+ "Your answer: "
+ val + "
";
}
else {
html += "";
html += '';
}
// if answer was just entered and grade is 100, also show the "provisional" message
// (unless for this question it isn't provisional)
/*
if (this.answer_was_just_entered && this.grade == 100 && this.md.points_are_provisional == "true") {
html += "
Your answer has been provisionally accepted. You'll get full credit for now, but your instructor may update your grade later after evaluating it.
";
}
*/
return html;
},
evaluateAnswer: function (question_index) {
// if user_answer_is_submittable is true, we're already ready to proceed
if (this.user_answer_is_submittable == true) {
return true;
}
// otherwise, get the user's answer
var raw_answer = $.trim($("#query_answer_" + this.query_index).val());
// replace newlines with breaks in recorded answer
this.user_answer = raw_answer.replace(/\n/g, " ");
// if answer is blank and author didn't explicitly say to accept answers, make them enter something.
if (raw_answer == "" && this.md.accept_blank_answers != "true") {
this.set_evaluation_feedback("Please enter an answer before submitting.");
//this.focus_user_input();
// return false, to say that we can't yet evaluate the answer.
return false;
// else check with MAVE if specified
} else if (this.md.mave_question_id != null) {
var t = this;
MAVE.validate_answer(this.md.mave_question_id, raw_answer, {
callback_fn: function (x) {
t.MAVE_callback(x);
}
, max_similarity_score: this.md.max_similarity_score
, min_valid_score: this.md.min_valid_score
, max_question_text_score: this.md.max_question_text_score
, validity_criterion: this.md.validity_criterion
, plagiarism_criterion: this.md.plagiarism_criterion
});
// store the question_index, so we'll be able to re-call player.submit_question on callback
this.question_index = question_index;
// return false, to say that we can't yet evaluate the answer.
return false;
// otherwise evaluate here...
} else {
// if we have a min word count, compare to it
if (this.md.min_word_count != null) {
// If the answer has fewer than x unique words, it's not submittable
var word_count = this.unique_word_count(this.user_answer);
if (word_count < this.md.min_word_count * 1) {
this.set_evaluation_feedback("Your answer is not long enough. Please elaborate and resubmit.");
this.focus_user_input();
// return false, to say that we can't yet evaluate the answer.
return false;
}
}
// If we make it to here, assume anything is OK.
this.setGrade(100);
this.answer_was_just_entered = true;
this.user_answer_is_submittable = true;
return true;
}
},
});
var KEY_CODES = {
ESC: 27,
TAB: 9
};
var Standard_Dialog_old = function () {
var $manuscript = $('#manuscript');
var $body = $('body');
var $dialog, $content;
var options = {};
return {
open: function (html, opt) {
// Extend default options
options = $.extend(true, (opt || {}), {
width: 450,
modal: true,
draggable: false,
resizable: false
});
// Set buttons
if (options.buttons === 'none') {
options.buttons = null;
}
else if (options.buttons === 'OK' || !options.buttons) {
options.buttons = [{ text: 'OK', click: Standard_Dialog.close }];
}
// Remove previous dialog
$('#standard_dialog_div').dialog('close').remove();
if (options.modal) {
$body.css('overflow', 'hidden');
}
// Hide other content from reader for mobile devices
$manuscript.attr('aria-hidden', 'true');
$dialog = $('');
$content = $('
' + (html || '') + '
');
$dialog.append($content);
$dialog.dialog(options);
// If we open toc we use as description only instruction in the top of dialog and not links
var isMenu = $content.find('#toc_head').length;
var labelledBy = isMenu ? 'toc_head' : 'standard_dialog_div';
var $parentDialog = $dialog.parent().attr({
'tabindex': '0',
'role': 'dialog',
'aria-labelledby': 'ui-dialog-title-standard_dialog_div ' + labelledBy
});
$parentDialog.find('#ui-dialog-title-standard_dialog_div').attr({
'role': 'heading',
'aria-level': '1'
});
// Remove close btn
$('.ui-dialog-titlebar-close').remove();
var $lastBtn = $parentDialog.find('button').last();
var $firstBtn = $parentDialog.find('button').first();
// Attach events
$parentDialog.bind('keydown', function (e) {
var code = e.keyCode || e.which;
if (code === KEY_CODES.ESC) {
Standard_Dialog.close(true);
}
if (e.target === this && e.shiftKey && code === KEY_CODES.TAB) {
e.preventDefault();
$lastBtn.focus();
}
});
$lastBtn.bind('keydown', function (e) {
var code = e.keyCode || e.which;
if (!e.shiftKey && code === KEY_CODES.TAB) {
$parentDialog.focus();
e.preventDefault();
}
});
$firstBtn.focus();
},
// for now alert is just like any other dialog; we could change that later.
wait: function (html, opt) {
options = opt || {};
options.buttons = 'none';
Standard_Dialog.open(html, options);
},
alert: function (html, opt) {
Standard_Dialog.open(html, opt);
},
close: function () {
// Show other content
$manuscript.removeAttr('aria-hidden');
if ($dialog) {
$dialog.dialog('close').remove();
}
else {
$("#standard_dialog_div").remove();
}
if (options.from) {
//console.log('setting focus to ', options.from);
options.from.focus();
}
if (options.modal) {
$body.css('overflow', 'auto');
}
if (typeof options.onClose === 'function') {
options.onClose();
}
}
};
}();