(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);
// We need to do this immediately so we can use this for adding
// descriptions to MC legends
$('[data-pid]').each(function () {
var $this = $(this);
var pid = $this.attr('data-pid');
$this.find('p').attr('id', pid);
$this.removeAttr('data-pid');
});
$('[data-id]').each(function () {
var $this = $(this);
var id = $this.attr('data-id');
$this.attr('id', id);
$this.removeAttr('data-id');
});
// Detect platform with https://github.com/bestiejs/platform.js
var iOS = platform.os.family === 'iOS'; //detect iOS (VoiceOver)
var isMac = platform.os.family === 'OS X'; //detect MacOS (VoiceOver)
var isAndroid = platform.os.family === 'Android'; //detect Android (TalkBack)
var isFirefox = platform.name === 'Firefox'; //detect Firefox (NVDA)
var isIE = platform.name === 'IE'; //detect IE (Jaws)
/*
This is the standard template you should add to your book JS file before
customizing.
Uncomment any of the configuration options to change the default behavior (see
https://macmillanhighered.atlassian.net/wiki/display/MP/Player+Configuration+Options
for descriptions of the options).
*/
/***********************************************
REQUIRED: Set this to the DF book ID (Subtype)
***********************************************/
xBookUtils.bookID = "journalism_accessible";
/*
The discipline is not required any more since we no longer use the HTML Quiz
question delivery method. You do not need to fill in these values. This has
been commented out and kept around for historical value only.
*/
/*
xBookUtils.discipline = {
dev: 0,
qa: 0,
pr: 0,
www: 0
}
*/
var Activity_journalism = Activity_manuscript_type.extend({
update_question_action_div: function (question_index) {
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);
$('#question_action_div_' + question.index).focus();
jq.find(".question_submit_button").remove();
/*
var submit_button = jq.find(".question_submit_button");
submit_button.attr('disabled', 'disabled');
submit_button.attr('aria-disabled', 'true');
submit_button.unbind('click');
*/
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);
}
},
show_question_feedback: function (question, is_correct, try_again) {
// remove prior feedback if there
//$("#question_feedback_" + question.index).remove();
// if we don't have any feedback at all, return
if (question.md.feedback == null && question.md.feedback_correct == null && question.md.feedback_incorrect == null && question.md.feedback_hint == null) {
return;
}
var questionType = "Question";
if (player.md.question_stem_type) {
questionType = player.md.question_stem_type;
}
var html = "
"
+ "
"
+ "Feeback
";
// include general feedback if there
if (question.md.feedback != null) {
html += "
" + question.md.feedback + "
";
$('#question_feedback_' + question.index).html("Feedback: " + question.md.feedback);
}
// include correct feedback if there and the answer is correct
if (is_correct && question.md.feedback_correct != null) {
html += "
" + question.md.feedback_correct + "
";
}
// include incorrect or hint feedback if there and the answer is incorrect
if (!is_correct) {
var found_feedback_string = false;
// if user gets to try again...
if (try_again) {
// check for feedback_conditional's
if (question.md.feedback_conditional.length > 0) {
for (var i in question.md.feedback_conditional) {
var fbc = question.check_conditional(question.md.feedback_conditional[i]);
if (fbc != "") {
html += "
" + fbc + "
";
found_feedback_string = true;
break;
}
}
}
// if we didn't find a feedback string to use above, check for feedback_hint
if (!found_feedback_string && question.md.feedback_hint != null) {
html += "
" + question.md.feedback_hint + "
";
found_feedback_string = true;
}
}
// if we didn't find a feedback string to use above, check for feedback_incorrect
if (!found_feedback_string && question.md.feedback_incorrect != null) {
html += "
" + question.md.feedback_incorrect + "
";
}
}
// close question_feedback div
html += "
";
// append the div, then fade it in
$("#question_action_div_" + question.index).prepend(html);
$("#question_feedback_" + question.index).fadeIn("fast", function () {
// What I'd like to do here is check to make sure the feedback is all showing on the screen,
// and scroll if necessary so that the feedback is all visible. But just doing "scrollTo"
// isn't working properly in all situations.
// $(window).scrollTo($(this), 0);
});
},
submit_question: function (question_index) {
// if we don't have grid data then do nothing
// We don't want to do this check for the tutorial
var q_idx = question_index;
if (typeof question_index == 'object') {
// extract the question_index from the object
q_idx = question_index.data.question_index;
}
$('#question_action_div_' + q_idx + ' .alert').remove();
// if the question has not been answered then
// do nothing
if (!player.questionAnswerChecked(q_idx)) {
//$('#question_submit_button_' + q_idx).attr('aria-disabled', 'true');
var answerType = 'choose an answer';
if (player.activity.questions[q_idx].queries[0].getQueryTypeForARGA() === 'essay') {
answerType = 'enter an answer';
}
player.setLiveText(
'You must ' + answerType + ' before submitting'
);
$('#question_action_div_' + q_idx).prepend('
You must ' + answerType + ' before submitting
');
return;
}
this._super(question_index);
//player.progress_bar.update();
/*
setTimeout(function () {
$('#question_action_div_' + q_idx).focus();
}, 500);
*/
var questionType = 'Question';
if (player.md.question_stem_type) {
questionType = player.md.question_stem_type;
}
if (player.activity.allQuestionsAnswered()) {
var finalHtml = '
Your score
';
if (player.activity.hasEssayQuestion()) {
finalHtml += '
Your answers have '
+ 'been submitted to the grade book for your '
+ 'instructor to review. Please check the grade book '
+ 'for your final score.
';
}
else {
finalHtml += '
Total points awarded for this activity: '
+ player.activity.getFinalScore() + ' out of '
+ (player.activity.questions.length - 1)
+ '
';
}
$('#digfir_section_0').append(finalHtml);
console.log('setting live text');
setTimeout(function () {
player.setLiveText(finalHtml);
}, 1000);
}
//if (!player.activity.hasEssayQuestion()) {
//$('#question_feedback_' + q_idx).focus();
player.activity.setLiveQuestionFeedback(q_idx, questionType);
//}
// We don't need to disable the submit button after
// answering a question because it automatically gets
// changed to a Next button and the submit handler is
// removed.
//player.activity.disableSubmitButton(q_idx);
if ($('#closing_material_button_0').length > 0) {
$('#closing_material_button_0').focus();
player.menu.update();
}
else {
$('#question_submit_button_' + q_idx).focus();
}
},
hasEssayQuestion() {
var questions = player.activity.questions;
for (var i = 1; i < questions.length; i++) {
if (questions[i].queries[0].getQueryTypeForARGA() === 'essay') {
return true;
}
}
return false;
},
getFinalScore() {
var questions = player.activity.questions;
var score = 0;
for (var i = 1; i < questions.length; i++) {
if (questions[i].queries[0].grade === 100) {
score++;
}
}
return score;
},
setLiveQuestionFeedback: function (q_num, questionType, feedbackText) {
//$('#question_feedback_' + q_num).focus();
return;
var fb =
'Feedback for ' + questionType + ' ' +
q_num +
': ';
if (typeof feedbackText === 'string') {
fb += feedbackText;
}
else {
var feedbackHtml = $('#question_feedback_' + q_num).html();
if (feedbackHtml !== null) {
feedbackHtml = feedbackHtml.replace(/
]+>.*?<\/h3>/g, '');
feedbackHtml = feedbackHtml.replace(/<[^>]+>(.*?)<\/[^>]+>/g, "$1");
//fb += $('#question_feedback_' + q_num).text();
fb += feedbackHtml;
}
}
if (player.activity.allQuestionsAnswered()) {
fb += ' ' + $('#final-score').text();
}
player.setLiveText(fb);
},
allQuestionsAnswered: function () {
var questions = player.activity.questions;
for (var i = 1; i < questions.length; i++) {
var grade = questions[i].queries[0].grade;
if (grade !== 0 && grade !== 100) {
return false;
}
}
return true;
}
});
var Player_subtype = Player_manuscript_type.extend({
//cfg_removeRawHtmlDivs: "on",
//cfg_showAnswer: "on",
//cfg_showAnswerAutoWrapThis: "off",
//cfg_Box_moveTitle: "all",
//cfg_Box_moveTitleExclude: "",
//cfg_Figures_targetDefault: "_blank",
//cfg_Figures_resizeDivWidth: "off",
//cfg_Figures_autoHtml: "on",
//cfg_LH_autoHtml: "on",
//cfg_LH_externalTargetDefault: "_pop",
//cfg_LH_internalTargetDefault: "_pop",
//cfg_LH_ebookTargetDefault: "_pop",
//cfg_LH_imageTargetDefault: "_blank",
//cfg_LH_useOpenContent: "on",
//cfg_LH_useLinksFile: "on",
//cfg_Glossary_hoverTerms: "on",
//cfg_Glossary_useStickyDiv: "on",
//cfg_Glossary_hoverTermsNoClick: "",
ACTIVITY_COMPLETED: false,
DUE_DATE_HAS_PASSED: false,
liveFeedback: undefined,
setLiveText: function (text) {
if (this.liveFeedback !== undefined) {
text = text.replace(/<[^>]+>/g, ' ');
text = text.replace("Your score", '');
this.liveFeedback.text(text);
}
},
// brb: some questions have multiple queries
questionAnswerChecked: function (q_num) {
console.log('questionAnswerChecked: ', this.activity.questions[q_num]);
var all_questions_answered = true;
var i;
for (i = 0; i < this.activity.questions[q_num].queries.length; i++) {
console.log('checking query ' + i);
if (!this.activity.questions[q_num].queries[i].user_has_answered()) {
console.log('not answered');
all_questions_answered = false;
}
else {
console.log('answered');
}
}
/*
if (this.activity.questions[q_num].queries[0].user_has_answered()) {
return true;
}
*/
return all_questions_answered;
},
initialize_sections: function() {
// Do not delete this
this._super();
// Add custom JS code below. Anything that needs to be done before
// the page displays should be done here.
}, // end initialize_sections
/*
You will most likely not make any changes to the initialize method.
*/
initialize: function(id) {
// Do not delete this
this._super(id);
// Don't delete these unless you know exactly what you are doing :-)
this.xrefs = new XRefs_manuscript_subtype();
this.glossary = new Glossary_manuscript_subtype({terms: false});
this.figures = new Figures_manuscript_subtype();
this.tables = new Tables_manuscript_subtype();
this.activity = new Activity_journalism();
}, // end initialize
initialize2: function() {
// Do not delete this
this._super();
if (player.ARGA_running) {
// brb: determine if activity has been completed (all ARGA answered)
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)
}
// brb: determine if due date has passed for assignment
if (player.ARGA_running) {
if (Get_ARGA_Data("due_date_has_passed") == 1) {
this.DUE_DATE_HAS_PASSED = true;
}
}
}
// You will most likely not want to delete this
var link_handler = new LinkHandler();
// Add custom JS code below. Anything that can be done after the
// page displays should be done here.
this.initLiveFeedback();
// change h2 to h1
$('h2.section-title').changeElementType('h1');
// change manuscript div to main
$('#manuscript').changeElementType('main');
// add h2 instructions header
$('h1').after('
Instructions
');
$('h1').attr('tabindex', '-1');
$('h1').attr('id', 'h1-header');
// fix h3 headings for questions
var q_num = 1;
$('[data-type="question"]>h3').each(function () {
var $this = $(this);
var questionType = 'Question';
if (player.md.question_stem_type) {
questionType = player.md.question_stem_type;
}
$this.text(questionType + " " + q_num);
$this.addClass('visually-hidden');
$this.attr('id', 'question_heading_' + q_num);
$this.changeElementType('h2');
q_num++;
});
// New feature to allow table columns to align content by character.
// This should always come after any custom JS code you add. If you
// do not have any tables that need to be aligned by character then you
// can comment this out.
this.tables.align_columns();
if (this.DUE_DATE_HAS_PASSED && !this.ACTIVITY_COMPLETED) {
$('input.question_submit_button').each(function () {
var $this = $(this);
//$this.replaceWith("
Please note: The due date for this assignment has now passed. You may review the materials in the activity but you will not be able to submit answers for a grade.
");
$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);
});
Standard_Dialog.alert("The due date for this assignment has now passed. "
+ "You may watch the video "
+ "but you will not be able to submit answers for a grade. "
+ "Please contact your instructor for further information.",
{ title: "Alert" });
return;
}
else if (this.ACTIVITY_COMPLETED) {
Standard_Dialog.alert("You have completed this activity. Please refer to the grade book for your final score.",
{ title: "Activity completed", from: document.getElementById('h1-header') });
}
$('[data-type="question"]').each(function () {
$(this).changeElementType('form');
});
$('.question_action_div').each(function () {
console.log('found question_action_div: ', this);
var $this = $(this);
var id = $this.attr('id').replace("question_action_div_", '');
console.log('id = ' + id);
$this.before('');
$this.attr('tabindex', '-1');
});
$('.question_submit_button').each(function () {
var $this = $(this);
var id = $this.attr('id');
id = id.replace("question_submit_button", "question_heading");
$this.attr('aria-describedby', id);
});
}, // end initialize2
initLiveFeedback: function () {
//var live = (isIE || isMac) ? 'assertive' : 'polite';
var live = 'polite';
this.liveFeedback = $(
''
);
$('body').append(this.liveFeedback);
},
}); // end Player_subtype
// Do not delete this
player = new Player_subtype();
Essay_Query = Essay_Query.extend({
getQueryTextForARGA: function () {
if (this.query_text_for_ARGA != null && this.query_text_for_ARGA != '') {
return this.query_text_for_ARGA;
}
else if (this.query_text != null && this.query_text != '') {
var cleaned_text = clean_query_text(this.query_text);
return cleaned_text;
}
else {
return 'see page for question context';
}
},
user_has_answered: function () {
console.log(`Essay_Query.user_has_answered:`, this);
//var answer = $('#query_answer_' + (this.parent_question.index - 1)).val().trim();
var answer = $('#query_answer_' + (this.query_index)).val().trim();
if (/\S/.test(answer)) {
return true;
}
return false;
},
query_text_for_essay: function () {
if (this.query_text != "" && this.md._hide_query_text != "true") {
// replace newlines with
var qt = jQuery.trim(this.query_text).replace(/\n/g, " ")
console.log('query_text_for_essay:' + qt);
var questionType = 'Question';
if (player.md.question_stem_type) {
questionType = player.md.question_stem_type;
}
var q_prefix = '' + questionType + ' ' + this.parent_question.index + ': ';
if (player.md.question_stem_prefix) {
q_prefix += player.md.question_stem_prefix + ': ';
}
q_prefix += "";
qt = qt.replace(/(\d+)/, "" + questionType + " $1");
qt = qt.replace(/(\d+ of \d+ )/, "$1" + q_prefix);
//console.log(qt);
return ""
} else {
return "";
}
},
getHTML: function (mode) {
// start with the query text, if there
var html = this.query_text_for_essay();
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 = this.user_answer;
// convert breaks to newlines
//val = val.replace(/ /g, "\n");
// also disable the input if we're not in review_correct_incorrect mode
if (mode != "review_correct_incorrect") {
disabled = "disabled";
}
}
/*
if (this.userHasAnswered()) {
html += "
Your answer
"
+ "
"
+ val
+ "
";
}
else {
*/
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;
}
});
MC_Query = MC_Query.extend({
getQueryTextForARGA: function () {
if (this.query_text_for_ARGA != null && this.query_text_for_ARGA != '') {
return this.query_text_for_ARGA;
}
else if (this.query_text != null && this.query_text != '') {
var cleaned_text = clean_query_text(this.query_text);
return cleaned_text;
}
else {
return 'see page for question context';
}
},
getUserAnswerForARGA: function () {
if (this.user_answer_index == null || this.choices[this.user_answer_index] == null) {
return 'Not answered';
} else {
var answer = clean_query_text(this.choices[this.user_answer_index]);
//return this.choice_ids[this.user_answer_index] + ". " + this.choices[this.user_answer_index];
return this.choice_ids[this.user_answer_index] + ". " + answer;
}
},
getQuestionText: function () {
var text = jQuery.trim(this.query_text);
var parent_q_num = String(this.parent_question.index);
if (/____/.test(text)) {
text = text.replace(/(___[_]+)/g, "$1BLANK");
if (/\d+\.<\/span>/.test(text)) {
text = text.replace(/(\d+\.<\/span>)/, "$1 Fill in the blank: ");
}
else {
text = "Fill in the blank: " + text;
}
}
if (/.*?<\/span>/.test(text)) {
var matches = text.match(/(.*?)<\/span>/);
var underline_type = 'phrase';
if (player.md.underline_type) {
underline_type = player.md.underline_type;
}
text += ' The ' + underline_type + ' "' + matches[1] + '" is underlined.';
}
if (player.md.italic_type && //.test(text)) {
var matches = text.match(/(.*?)<\/em>/);
var italic_type = player.md.italic_type;
var verb = 'is';
if (/ /.test(matches[1]) && player.md.italic_type_plural) {
italic_type = player.md.italic_type_plural;
verb = 'are';
}
text += ' The ' + italic_type + ' "' + matches[1] + '" ' + verb + ' italicized.';
}
//console.log(text);
// check if we have question intro text that should go outside of
// actual question text
/*
var q_intro_text = '';
if (/ques_intro/.test(text)) {
var match = text.match(/.*?<\/span>/);
q_intro_text = '
' + match[0] + '
';
text = text.replace(/.*?<\/span>/, "");
}
*/
var question_type = 'Question';
if (player.md.question_stem_type) {
question_type = player.md.question_stem_type;
}
text = text.replace("\"q-num\"", "\"q-num\" aria-hidden=\"true\"");
var describedby = '';
if (this.md.describedby) {
var db_text = $('#' + this.md.describedby).text();
if (db_text) {
describedby = db_text + " ";
}
}
return (
/*q_intro_text +*/
''
);
},
getHTML: function (mode) {
// we will add this last so we can add 'disabled' if the question
// has been answered
var html = '';
var fieldset_disabled = false;
//html += this.query_text_html();
// Build answer selection
var is_correct = false;
//var letters = new Array('A', 'B', 'C', 'D');
for (var z = 0; z < this.choices.length; z++) {
var index = this.choice_order[z];
// if this is review mode...
var checked = '';
var disabled = '';
var radio_style = 'query_mc_other_choice';
if (
mode == 'review' ||
mode == 'review_correct_incorrect' ||
mode == 'preview'
) {
// if it's the correct choice, it should be marked in green
if (index == this.correct_answer_index) {
// but only if we're *not* in review_correct_incorrect mode or this is the user's choice
if (
mode != 'review_correct_incorrect' ||
index == this.user_answer_index
) {
radio_style = 'query_mc_correct_choice';
}
// if this is what the user chose, he got it correct
if (index == this.user_answer_index) {
is_correct = true;
}
// else if it's the user's choice (and this.md.no_correct_answer is not true), it should be marked in red
}
else if (
index == this.user_answer_index &&
this.md.no_correct_answer != 'true'
) {
radio_style = 'query_mc_incorrect_user_choice';
}
// and the input should be disabled, unless we're in review_correct_incorrect mode
if (mode != 'review_correct_incorrect') {
disabled = 'disabled';
}
}
// if this is the choice the user clicked, it's checked (regardless of mode)
if (index == this.user_answer_index) {
checked = 'checked';
}
var mc_option_class = '';
var mc_answer_info = '';
var answer_info_id =
' id=answer_info' + this.query_index + '_' + index;
if (radio_style === 'query_mc_correct_choice') {
mc_option_class = ' correct_answer';
if (checked === 'checked') {
mc_answer_info =
" (Your answer, correct)';
}
else {
mc_answer_info =
" (Correct answer)';
}
}
else if (radio_style === 'query_mc_incorrect_user_choice') {
mc_option_class = ' incorrect_answer';
if (checked === 'checked') {
mc_answer_info =
" (Your answer, incorrect)';
}
else {
mc_answer_info =
" (Incorrect answer)';
}
}
var aria_disabled = '';
if (disabled === 'disabled') {
aria_disabled = " aria-disabled='true' disabled='true' ";
fieldset_disabled = true;
}
var label_elem = 'label';
if (mode == 'review') {
label_elem = 'label';
}
if (!isMac) {
// Create radio button input plus label
html +=
"