/*copied from the slide_activity*/
var Player_devtk = Player_manuscript_type.extend({
check_activity_availability: function () {
//check URL. If on websterfw.com, then show content (do nothing), if not, then determine if content should show or if coming soon message should show
safe_log("checking availability");
if (document.URL.indexOf('digfir-published') == -1) {
var isViewable = $("[key=activity_is_viewable]").html();
if (isViewable != null) {
isViewable = $.trim(isViewable);
isViewable = isViewable.toLowerCase();
if (document.URL.indexOf('show_activity') == -1) {
if (isViewable == "false") {
this.show_coming_soon_message();
}
}
}
}
},
show_coming_soon_message: function () {
var message = "This activity will be available soon.";
var html = "
" + message + "
";
$("#manuscript").before(html);
},
show_completion_message: function () {
// player.activity.grade_activity will always have been called before this fn
// so we'll have access to the properly-calculated activity properties below
var html = "Congratulations! You have completed this activity."
+ "
You have received a provisional score for your essay answers, which have been submitted to your instructor."
+ "
"
+ "
Your grade has been submitted to your instructor.
"
;
// section should have a block_type=activity_report paragraph to receive this info
$("[data-block_type=activity_report]").html(html).show();
// show the grade submitted message if user_has_received_completion_alert is true
if (player.user_has_received_completion_alert == true) {
$("#grade_submitted_message").show();
}
},
addVideoPlayer: function (containerID) {
safe_log("add player");
var playerHTML = "
You must watch the video before continuing this activity.
").dialog();
player.mid_pos_dialog();
return false;
}
var sec= player.get_current_section_jq();
this._super(section_to_show);
player.mid_pos_dialog();
player.get_current_section_jq().find("[data-mmtype='mov']").each(function (index, element) {
safe_log("found a video");
var jq = $(element);
var id = jq.attr("data-figure-id");
var mmsrc = jq.attr("data-mmsrc");
var src = jq.attr("src");
var attr = jq.attr("data-attr");
var vidHeight = jq.attr("height");
var vidWidth = jq.attr("width");
if (attr == null) attr = "";
attr = attr.split(/\s*,\s*/);
var params = new Object();
for (var i = 0; i < attr.length; ++i) {
var a = attr[i].split(/\s*=\s*/);
params[a[0]] = a[1];
safe_log("added param " + a[0] + ": " + a[1]);
}
params.autoStart = jq.attr("data-autoplay");
var videoPlayerID = "";
var videoPlayerKey = "";
//if(params.showVideoControls == 'true'){
//AF: This is the video player with playback controls. We are only using this one for right now.
videoPlayerID = "1513003547001";
videoPlayerKey = "AQ~~,AAABXVHBMdE~,bnY9CM55Z1MLPZuidy4KYEC_16wi-U8Q";
//}else{
// videoPlayerID = "1504927982001";
// videoPlayerKey = "AQ~~,AAABXVHBMdE~,bnY9CM55Z1PiqOYprq-NHmUPG2yKZ4U-";
//}
videos[id] = mmsrc;
var BCL = {};
BCL.markup = function (html, data) {
var m;
var i = 0;
var match = html.match(data instanceof Array ? /{{\d+}}/g : /{{\w+}}/g) || [];
while (m = match[i++]) {
html = html.replace(m, data[m.substr(2, m.length - 4)]);
}
return html;
};
videos.templateLoad = function (e) {
//AF: For now, we are not using captions.
var vidplayer = brightcove.api.getExperience(e);
var CuePointType = brightcove.api.modules.CuePointsModule.CuePointType;
var modExp = vidplayer.getModule(brightcove.api.modules.APIModules.EXPERIENCE);
modExp.addEventListener(brightcove.api.events.ExperienceEvent.TEMPLATE_READY, function (evt) { videos.templateReady(e); });
//captionsModule.loadDFXP(player.md.video_caption_url + videos[e] + ".xml", videos[e]);
//if needed, we can use these events to trigger code upon the success or error of loading captions.
//if there is an error, it fails silently and just doesn't show captions.
//captionsModule.addEventListener(brightcove.api.events.CaptionsEvent.DFXP_LOAD_SUCCESS, onDFXPLoadSuccess);
//captionsModule.addEventListener(brightcove.api.events.CaptionsEvent.DFXP_LOAD_ERROR, onDFXPLoadError);
}
BCL.playerData = {
"playerID": videoPlayerID,
"playerKey": videoPlayerKey,
"width": jq.width(),
"height": jq.height(),
"videoID": mmsrc,
"autoStart": params.autoStart
};
BCL.playerTemplate = "";
var playerHTML = "";
playerHTML = BCL.markup(BCL.playerTemplate, BCL.playerData); //replaces placeholders with values
jq.replaceWith(playerHTML);
brightcove.createExperiences();
});
player.load_multi_video_boxes();
},
load_multi_video_boxes: function () {
player.get_current_section_jq().find("[data-block_type=multi_video_box]").each(function (index, element) {
//set the styles
var align = $(element).children().find("[data-type=metadata]").find("[key=position]").html();
$(element).attr("data-layout-border", "true").attr("data-layout-width", "medium").attr("data-layout-align", align).attr("data-type", "figure");
//insert the player
var boxID = $(element).attr("id");
var playerID = boxID + "_video_player";
player.videoIsReady[playerID] = false;
player.addVideoPlayer(boxID);
brightcove.createExperiences();
var firstVideoID = "";
var buttonsDiv = "
";
$(element).find("[data-block_type=video]").each(function (index, videoElement) {
var title = $(videoElement).find("h3").html();
var videoID = $(videoElement).find("[key=videoID]").html();
if (firstVideoID == "") {
firstVideoID = videoID;
}
var buttonHtml = "";
buttonsDiv += buttonHtml;
});
buttonsDiv += "
";
$(element).append(buttonsDiv);
player.set_video(boxID + "_video_player", firstVideoID, true);
$(element).attr("data-block_type", "multi_video_box_rendered");
$(element).find(".select_video_button").button();
});
},
set_video: function (playerID, videoID, pauseAfterLoad) {
//highlight the button
$(".select_video_button").removeClass("ui-state-focus");
$("#" + playerID + "_" + videoID).addClass("ui-state-focus");
if (!player.videoIsReady[playerID]) {
safe_log("video not ready.. going to settimeout");
setTimeout(function () { player.set_video(playerID, videoID, pauseAfterLoad) }, 100);
return false;
}
safe_log("inside load video");
var vidplayer = brightcove.api.getExperience(playerID);
var playerModule = vidplayer.getModule(brightcove.api.modules.APIModules.VIDEO_PLAYER);
safe_log("got player module");
if (pauseAfterLoad) {
playerModule.cueVideoByID(videoID);
} else {
playerModule.loadVideoByID(videoID);
}
},
videoIsReady: {},
show_navigation: function () {
var html = "
";
if (this.activity_thumbnail_src != null) {
html += "";
}
html += "
" + this.md.activity_type_title + "
"
+ "
" + this.activity_title + "
"
+ "
" //titles
+ "
"
+ "
TABLE OF CONTENTS
"
+ "
" //top_nav
+ "
" // top_banner
;
$("[data-type=chapter]").before(html);
html = "";
if (this.sections.length > 1 && this.md.hide_toolbar != "true") {
html += "
"
+ "
"
+ "
" +
"
Introduction
" +
""
+ "
" // toolbar
;
}
$("[data-type=chapter]").after(html);
/* Hiding the next button
// button at the bottom of the manuscript to go on to the next step
$("[data-type=chapter]").append(UI_Elements.get_button_html({
id: "step_button",
label: "Next",
fn: 'player.show_section("next")'
}));
*/
// icons for toolbar and next buttons...
$('#previous_button').button({
icons: {
primary: "ui-icon-circle-triangle-w"
}
});
$('#next_button').button({
icons: {
secondary: "ui-icon-circle-triangle-e"
}
});
//$('#slide_number').button({
// icons: {
// secondary: "ui-icon-circle-triangle-s"
// }
//});
$('#step_button').button({
icons: {
secondary: "ui-icon-circle-triangle-e"
}
});
// activate all other buttons
UI_Elements.activate_buttons();
/* START - remove empty
elements*/
player.remove_empty_space();
/* END - remove empty
elements*/
},
remove_empty_space: function(){
$('p').each(function(){
if($(this).text() == ''){
$(this).addClass('__hide');
}
});
},
//Krugman specific functionality
section_is_locked: false,
unlock_section: function(){
player.section_is_locked = false;
},
lock_section: function(time){
player.section_is_locked = true;
var mstime = player.convert_minutes_to_ms(time);
setTimeout(function(){player.unlock_section(time)}, mstime);
},
convert_minutes_to_ms: function(time){
//assumes time format like d+:d+
var a = time.split(":");
return ((+a[0]) * 60 + (+a[1])) * 1000;
},
initialize: function () {
var fontHTML = '';
$("body").append(fontHTML);
this._super();
//this.activity = new Activity_work_it_out();
this.check_activity_availability();
player.glossary.set_click_event_for_terms_in_section = function (sectionjq) {
safe_log("doing click event for terms");
$(sectionjq).find("[data-type='termref']").each(function (index, element) {
// opening with a click event, as in the following line, doesn't work for queries;
// in any case I think a "real" link is probably better anyway.
// $(element).click(t.open_link).css("cursor", "pointer");
var jq = $(element);
jq.unbind("click");
safe_log("found term " + jq.html());
jq.click(function () { player.glossary.show_definition(this); });
});
}
},
initialize2: function () {
this._super();
//set up Google Analytics
//get the url without the querystring parts
var url = location.pathname;
//now get user info only if ARGA is initialized
var userID = "anonymous";
if (player.ARGA_running) {
userID = Get_ARGA_Data("learner_id")
}
ga('create', 'UA-52432131-1', { 'userId': userID });
ga('set', 'page', url);
ga("send", "pageview");
},
log_section_view: function (sectionNum) {
ga("send", "event", "Navigation", "LoadSection", sectionNum);
}
});
player = new Player_devtk();
//to not show the letters for MC choices
MC_Query = MC_Query.extend({
// mode should be "delivery" or "review"; "delivery" is assumed
getHTML: function (mode) {
// initialize imagemap elements
if (this.imagemap_initialized === false) {
var question_jq = this.jq.parent();
this.im_init(question_jq);
this.imagemap_initialized = true;
}
// start with the query text, if there
var html = this.query_text_html();
// wrap answers in a p tag
html += "
";
// Build answer selection
var is_correct = false;
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";
}
// Create radio button input plus label
html += "
"
+ "
"
+ "
"
//+ "
" + this.choice_ids[z] + ".
"
+ "
"
+ "
";
}
// get a possible feedback string; this fn will take account of mode
html += this.correct_incorrect_feedback(mode, is_correct);
html += "";
return html;
}
});
function onTemplateLoaded(theID) {
safe_log("template loaded " + theID);
player.videoIsReady[theID] = true;
var vidplayer = brightcove.api.getExperience(theID);
safe_log("got player");
var playerModule = vidplayer.getModule(brightcove.api.modules.APIModules.VIDEO_PLAYER);
safe_log("god module");
playerModule.addEventListener(brightcove.api.events.MediaEvent.COMPLETE, player.onVideoComplete);
}
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date(); a = s.createElement(o),
m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
/*slide activity code end*/
/*code Added by LearningMate from Query.js*/
var Query = Class.extend({
// define and set defaults for variables
hasSubmitButton: true,
hasGiveUpButton: false,
query_source: "",
query_index: -1, // index for the query; will be supplied on initialization
query_number: "", // query number to be used for display purposes
query_data: "", // "query data" received back from ARGA
query_text: "",
query_text_for_ARGA: "", // does not necessarily need to be set
points_possible: 1, // default 1 point per query
grade: -1, // percentage; -1 means not answered
original_grade: -1, // the "original grade" can be overridden; make sure we keep it
md: null, // metadata -- has to be initialized in init
imagemap_initialized: false,
line_separator: new RegExp("\\n|\\~\\~"),
// ========================================
// initialization
init: function(source, index, jq){
this.query_source = source;
this.query_index = index;
this.jq = jq;
this.md = {};
this.parseSource();
},
parseSource: function() {
// do whatever needs to be done with query_source
},
im_init: function(jq) {
// jq coming in should refer to the *question*
// only run this if the question has imchoices in it
// get choices out of imchoice tags
var choices = [];
jq.find("[data-type=imchoice]").each(function(index, element) {
var html = $(element).html();
var c;
eval("c=" + html);
c.id = choices.length;
choices.push(c);
});
if (choices.length == 0) {
return;
}
// get the figure div; assume the figure we're dealing with here is the last one in the question
var wrap = jq.find('[data-type=figure]').last();
// wrap the figure's image in the "pic_container" div
// (also make sure the image doesn't get the pointer cursor)
var img = wrap.find("img").first().css("cursor", "default");
// make sure enclosing boxes are wide enough to fit the image
var w = img.width();
wrap.parents("[data-type=box]").width(w + 20);
// pic_container (or figure) needs to be the same size as the image
var picContainer = $("")
.addClass("pic_container")
.append(img);
wrap.prepend(picContainer);
// set up map
// Need to append timestamp to map's name attribute
// WebKit has problems if the same name is reused.
var timestamp = new Date().getTime() + "_" + this.query_index;
img.attr("usemap", '#question-map-'+timestamp);
// Most browsers use the name attr for the useMap reference
// but IE 7 & below needs to have the ID set the same
var currMap = $('";
return s;
},
// ========================================
// setters
setQueryNumber: function(qn) {
this.query_number = qn;
},
setQueryTextForARGA: function(qt) {
this.query_text_for_ARGA = qt
},
setQueryData: function(qd) {
this.query_data = qd;
},
setGrade: function(g) {
this.grade = g;
this.original_grade = this.grade;
},
overrideGrade: function(g) {
this.grade = g;
},
setPointsPossible: function(pp) {
this.points_possible = pp;
},
// this should be implemented for each query type
restoreAnswerFromARGA: function(answer) {
},
// =========================================
// getters
getQueryNumber: function() {
return this.query_number;
},
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 != "") {
return this.query_text;
} else {
return "see page for question context";
}
},
getPointsPossible: function() {
return this.points_possible * 1;
},
// return true if points awarded for this query are "provisional" -- i.e. subject to review by instructor
// by default this will be false
pointsAreProvisional: function() {
return false;
},
getPointsAwarded: function() {
if (this.grade != null && this.grade >= 0) {
return this.grade / 100 * this.points_possible;
} else {
return 0;
}
},
// return whether the student's original answer was correct (even if the grade was overridden)
isCorrect: function() {
return (this.original_grade == 100);
},
getQueryNumberForARGA: function() {
if (this.query_number == null || this.query_number == "") {
return "" + this.query_index;
} else {
return this.query_number;
}
},
// this should be implemented for each query type
getQueryTypeForARGA: function() {
return 'query type';
},
// this should return -1 if it's not answered, or the grade if we have one
getGradeForARGA: function() {
return this.grade;
},
getOriginalGrade: function() {
return this.original_grade;
},
// this should be implemented by query types
getCorrectAnswerForARGA: function() {
return "correct answer";
},
// this should be implemented by query types
getUserAnswerForARGA: function() {
return "user answer";
},
// this must be implemented by query types
// mode should be "delivery", "review", or "review_correct_incorrect"; "delivery" is assumed
getHTML: function(mode) {
return "query html; mode: " + mode;
},
// standard way to get the query text for a query
// this often won't be used.
query_text_html: function() {
if (this.query_text != "" && this.md._hide_query_text != "true") {
// replace newlines with
var qt = jQuery.trim(this.query_text).replace(/\n/g, " ")
return "
" + qt + "
"
} else {
return "";
}
},
// if grade is > -1, the user has answered
userHasAnswered: function() {
return (this.grade > -1);
},
// allow for a function that allows the user to give up
give_up: function() {
// but by default we return "false", which means the user *can't* give up...
return false;
},
// this must be implemented by query types.
// It must set this.grade to something >= 0 (if it's a graded query type)
// and must return true if the answer is OK to be submitted, false otherwise
evaluateAnswer: function() {
// what to do here is completely query-specific
return true;
}
});
// ===========================================================================
function ______MC_Query() {}
var MC_Query = Query.extend({
// ========================================
// define and set defaults for variables specific to this query type
choices: new Array(),
choice_ids: new Array(),
correct_answer_index: null,
user_answer_index: null,
// ========================================
// initialization
parseSource: function() {
// initialize vars
this.choices = new Array();
this.choices_fb = new Array();
this.choice_ids = new Array();
this.correct_answer_index = null;
this.user_answer_index = null;
// lines might start with "MC:"; if so, strip it out
var s = this.query_source.replace(/^MC:\s*/, "");
// split and go through the lines
var lines = s.split(this.line_separator);
this.query_text = "";
// the first choice has to be "a" or "A"
var choice_re = /^[\*]?([aA])[\.:\)]/;
for (var i = 0; i < lines.length; ++i) {
// get line and trim whitespace
var l = $.trim(lines[i]);
// choice
if (l.search(choice_re) > -1) {
var ident = RegExp.$1;
var choice = l.replace(/^[\*]?\w[\.:\)]\s*/, "");
ident = ident.toUpperCase();
// extract feedback for the choice, if there
var choice_text = choice.replace(/\s*\[\[(.*?)\]\]\s*$/, "");
var choice_fb = null;
if (choice != choice_text) {
choice_fb = RegExp.$1;
// if feedback is simply "correct" or "incorrect", ignore it.
if (choice_fb.toLowerCase() == 'correct' || choice_fb.toLowerCase() == 'incorrect') {
choice_fb = null;
}
}
this.choices.push(choice_text);
this.choices_fb.push(choice_fb);
this.choice_ids.push(ident);
// if line started with *, it's the correct answer
if (l.search(/^[\*]/) > -1) {
correct_choice = ident;
this.correct_answer_index = this.choice_ids.length - 1;
}
// update choice_re so that any letter is OK from here on
choice_re = /^[\*]?(\w)[\.:\)]/;
// points_possible
} else if (l.search(/^_points:\s*(\d+)/i) > -1) {
this.points_possible = RegExp.$1;
// metadata -- starts with "_[a-zA-Z]"
} else if (l.search(/^\_[a-zA-Z]/) > -1) {
this.extractMetadata(l);
// by default add it to the query text
} else {
this.query_text += l + "\n";
}
}
// if the query starts with \d\.\s*, strip it out
// *no, this version doesn't work; it also strips out "1." from "5TB-1.png"*//
// this.query_text = this.query_text.replace(/(\n?)\d+\.\s*/, "\1");
// now we should be done with the query text. Strip trailing white space
this.query_text = this.query_text.replace(/\s*$/, "");
// shuffle choices, unless md.never_scramble is true
this.choice_order = new Array();
for (var j = 0; j < this.choices.length; ++j) this.choice_order[j] = j;
if (this.md.never_scramble != "true") {
this.choice_order.shuffle();
}
// if no correct answer was given, we need to explicitly note that.
if (this.correct_answer_index == null) {
this.md.no_correct_answer = "true";
}
// replace any remaining \n's with
// NO: we're doing this in getHTML instead now
// this.query_text = this.query_text.replace(/\n/g, "
");
},
// function that returns a string to show based on whether the user got it correct
correct_incorrect_feedback: function(mode, is_correct) {
var html = "";
// get correct answer as presented to user
for (var i = 0; i < this.choices.length; ++i) {
if (this.choice_order[i] == this.correct_answer_index) {
break;
}
}
// if the question explicitly defines feedback for the user's answer, use it as the feedback
if (this.user_answer_index != null && this.choices_fb[this.user_answer_index] != null) {
html += this.choices_fb[this.user_answer_index];
}
// the correct answer will be highlighted in green, so there's no reason to say anything more.
// now, if we got any feedback, enclose it in a div
if (html != "") {
html = "
" + html + "
";
}
return html;
},
// ========================================
// extend query functions
setQueryData: function(qd) {
this._super(qd);
// for MC queries, if we get query_data, that's the user's answer index
if (qd != "" && qd != null && !isNaN(qd * 1)) {
this.user_answer_index = qd * 1;
}
},
restoreAnswerFromARGA: function(answer) {
// the choice letter should be the first character of answer (see getUserAnswerForARGA below)
var choice_id = answer.substr(0,1);
// find the choice that the user gave
for (var i = 0; i < this.choice_ids.length; ++i) {
if (this.choice_ids[i] == choice_id) {
this.user_answer_index = i;
return;
}
}
},
getQueryTypeForARGA: function() {
return 'multiple choice';
},
getCorrectAnswerForARGA: function() {
if (this.md.no_correct_answer == "true") {
return "no correct answer";
} else {
return this.choice_ids[this.correct_answer_index] + ". " + this.choices[this.correct_answer_index];
}
},
getUserAnswerForARGA: function() {
if (this.user_answer_index == null || this.choices[this.user_answer_index] == null) {
return 'Not answered';
} else {
return this.choice_ids[this.user_answer_index] + ". " + this.choices[this.user_answer_index];
}
},
// mode should be "delivery" or "review"; "delivery" is assumed
getHTML: function(mode) {
// initialize imagemap elements
if (this.imagemap_initialized === false) {
var question_jq = this.jq.parent();
this.im_init(question_jq);
this.imagemap_initialized = true;
}
// start with the query text, if there
var html = this.query_text_html();
// wrap answers in a p tag
html += "
";
// Build answer selection
var is_correct = false;
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";
}
// Create radio button input plus label
html += "
"
+ "
"
+ "
"
+ "
" + this.choice_ids[z] + ".
"
+ "
"
+ "
";
}
// get a possible feedback string; this fn will take account of mode
html += this.correct_incorrect_feedback(mode, is_correct);
html += "";
return html;
},
evaluateAnswer: function() {
// get the user's selected answer, which will be 0-based
this.user_answer_index = $('input:radio[name=query_answer_' + this.query_index + ']:checked').val() * 1;
// set grade accordingly (if this.md.no_correct_answer is true, any answer is correct)
if (this.user_answer_index == this.correct_answer_index || this.md.no_correct_answer == "true") {
this.setGrade(100);
$('.question_feedback, .question_feedback_head').css({ "color": "green" });
} else {
this.setGrade(0);
$('.question_feedback, .question_feedback_head').css({ "color": "red" });
}
return true;
}
});
function ______MA_Query() {}
var MA_Query = Query.extend({
// ========================================
// define and set defaults for variables specific to this query type
pairs: null,//new Array(), //MT (2013-10-11): need to instantiate that this with parseSource function() below see DF-152
right_side_order: new Array(),
correct_answer: "",
query_complete: false,
hasSubmitButton: false,
last_clicked_side: null,
last_clicked_index: null,
answers_correct: 0,
//choices: new Array(),
//choice_ids: new Array(),
//correct_answer_index: null,
//user_answer_index: null,
// ========================================
// initialization
parseSource: function() {
// initialize vars
// lines might start with "MA:"; if so, strip it out
var s = this.query_source.replace(/^MA:\s*/, "");
//MT (2013-10-11): need to re-instantiate a new Array with each new object/query.
this.pairs = new Array();
// split and go through the lines
var lines = s.split(this.line_separator);
this.query_text = "";
var points_explicitly_specified = false;
// the first choice has to be "a" or "A"
var choice_re = /^([aA])[\.:\)]/;
for (var i = 0; i < lines.length; ++i) {
// get line and trim whitespace
var l = $.trim(lines[i]);
// pair
if (l.search(choice_re) > -1) {
// remove opening letter
l = l.replace(/^\w[\.:\)]\s*/, "");
// split at ::
var pair = l.split(/\s*::\s*/);
if (pair.length < 0) {
pair = [l, "Bad matching pair"];
}
this.pairs.push(pair);
if (this.correct_answer != "") this.correct_answer += "; ";
this.correct_answer += pair[0] + " → " + pair[1];
// update choice_re so that any letter is OK from here on
choice_re = /^(\w)[\.:\)]/;
// points_possible
} else if (l.search(/^_points:\s*(\d+)/i) > -1) {
this.points_possible = RegExp.$1;
points_explicitly_specified = true;
// metadata -- starts with "_[a-zA-Z]"
} else if (l.search(/^\_[a-zA-Z]/) > -1) {
this.extractMetadata(l);
// by default add it to the query text
} else {
this.query_text += l + "\n";
}
}
// now we should be done with the query text. Strip trailing white space
this.query_text = this.query_text.replace(/\s*$/, "");
// shuffle right_side_order
this.right_side_order = new Array();
for (var j = 0; j < this.pairs.length; ++j) this.right_side_order[j] = j;
this.right_side_order.shuffle();
// if points weren't explicitly specified, set to the number of pairs
if (!points_explicitly_specified) {
this.points_possible = this.pairs.length;
}
},
// ========================================
// extend query functions
setQueryData: function(qd) {
this._super(qd);
// for MA queries, if we get query_data, that's whether or not the user has completed the question
if (qd != "" && qd != null) {
this.query_complete = ((qd + "") == "true");
}
},
restoreAnswerFromARGA: function(answer) {
if (answer == 'Completed') {
this.query_complete = true;
}
},
getQueryTypeForARGA: function() {
return 'matching';
},
getCorrectAnswerForARGA: function() {
// not sure what to do here...
return this.correct_answer;
},
getUserAnswerForARGA: function() {
if (this.query_complete == false) {
return 'Not complete';
} else {
return 'Completed';
}
},
// mode should be "delivery" or "review"; "delivery" is assumed
getHTML: function(mode) {
// start with the query text, if there
var html = this.query_text_html();
html += "
";
var left_column = "";
var right_column = "";
// if we're in review mode and the student has completed the query, show the answers...
if (mode == 'review' || mode == 'review_correct_incorrect' || mode == 'preview') {
html += "
"
+ "
Correct Matches:
"
+ "
"
+ "
";
/**
+ "
" + left_column + "
"
+ "
" + right_column + "
"
+ "
"
;
**/
for (var i = 0; i < this.pairs.length; ++i) {
// ADD ARROWS
html += "
"
+ "
"
+ "
" + "" + this.pairs[i][0] + "
"
+ "
"
+ "
"
+ "
" + this.pairs[i][1] + "
"
+ "
"
+ "
";
}
// otherwise show the clickable areas
} else {
for (var i = 0; i < this.pairs.length; ++i) {
left_column += "
" + this.pairs[i][0] + "
";
right_column += "
" + this.pairs[this.right_side_order[i]][1] + "
";
}
html +=
"
"
+ "
" + left_column + "
"
+ "
" + right_column + "
"
+ "
"
+ "
Correct Matches:
"
+ "
"
//+ "
"
//+ "
"
//+ "
"
//+ "
"
;
}
// close off the table and enclosing div
html += "
";
return html;
},
postInit: function() {
var qjq = $("#query_matching_div" + this.query_index);
var tq = this;
qjq.find(".query_matching_table_td_left").each(function(index, element) {
var jq = $(element);
jq.find('.query_matching_item').click(function() { tq.left_clicked(this); }).addClass("active");
// jq.find('.query_matching_item').click({"tq": tq}, tq.left_clicked(this); }).addClass("active");
});
qjq.find(".query_matching_table_td_right").each(function(index, element) {
var jq = $(element);
jq.find('.query_matching_item').click(function() { tq.right_clicked(this); });
});
},
left_clicked: function(el) {
var jq = $(el);
var left_side = jq.parent();
var right_side = jq.parent().parent().find(".query_matching_table_td_right");
// get index of this item
var answer_index = jq.attr("answer_index");
// de-highlight all left-side items and right-side items
left_side.find(".query_matching_item").removeClass("chosen");
right_side.find(".query_matching_item").not(".answered").removeClass("incorrect").addClass("active");
// highlight this item
jq.addClass("chosen");
// note that it's chosen
this.last_clicked_side = "left";
this.last_clicked_index = answer_index;
},
right_clicked: function(el) {
if (this.last_clicked_side != "left") {
Standard_Dialog.alert("Click on an item in the left column first.");
return;
}
var jq = $(el);
var right_side = jq.parent();
var left_side = jq.parent().parent().find(".query_matching_table_td_left");
// get index of this item
var answer_index = jq.attr("answer_index");
// get handle to the item on the left side
var left_side_item = left_side.find("[answer_index=" + answer_index + "]");
if (answer_index != this.last_clicked_index) {
jq.addClass("incorrect");
this.last_clicked_side = null;
this.last_clicked_index = null;
right_side.find(".query_matching_item").removeClass("active");
Standard_Dialog.alert("Incorrect! Please select the correct Answer.");
setTimeout(function() {
jq.removeClass("incorrect");
if (this.last_clicked_index == null) {
left_side.find(".query_matching_item").removeClass("chosen");
}
}, 1000);
} else {
this.last_clicked_side = "right";
// right-side items aren't active anymore and shouldn't have the "incorrect" class.
Standard_Dialog.alert("Correct!");
right_side.find(".query_matching_item").removeClass("active").removeClass("incorrect");
// this item isn't clickable ever anymore
jq.unbind();
// kill the "chosen" class on the left side; it shouldn't be clickable either
left_side_item.removeClass("chosen").unbind().removeClass("active");
// move the correct item down
var table = right_side.parent().parent();
table.find(".query_matching_table_td_correct").show();
table.find(".query_matching_table_td_left_bottom").show();
table.find(".query_matching_table_td_right_bottom").show();
var left_side_bottom = table.find(".query_matching_table_td_left_bottom");
var right_side_bottom = table.find(".query_matching_table_td_right_bottom");
var new_left = left_side_item.clone().addClass("correct");
var new_right = jq.clone().addClass("correct");
new_left.prepend("");
//left_side_bottom.append(new_left);
//right_side_bottom.append(new_right);
var new_left_2 = $('
');
new_left_2.append(new_left);
var new_right_2 = $('
');
new_right_2.append(new_right);
var new_row = $("
").append(new_left_2).append(new_right_2);
new_row.appendTo(table);
//var _height = right_side_bottom.height();
//window.alert(_height)
//left_side_bottom.height(_height);
++this.answers_correct;
// add the "answered" class to both sides
left_side_item.addClass("correct");
jq.addClass("correct");
var t = this;
setTimeout(function() {
left_side_item.removeClass("correct").addClass("answered");
jq.removeClass("correct").addClass("answered");
if (t.answers_correct == t.pairs.length) {
t.question_done(table);
}
}, 1000);
}
},
question_done: function(table) {
table.find(".query_matching_table_td_correct").css("border-top","0px");
table.find(".query_matching_table_td_left").hide();
table.find(".query_matching_table_td_right").hide();
// set query_complete to true, then call the parent question's submit function
// which will in turn call evaluateAnswer below.
this.query_complete = true;
player.activity.submit_question(this.parent_question.index);
},
evaluateAnswer: function() {
// if query_complete is still false, user hasn't finished
if (this.query_complete == true) {
this.setGrade(100);
return true;
} else {
this.setGrade(0);
return false;
}
}
});
player.show_section = function(section_to_show) {
//window.alert(section_to_show);
var direction = "right";
if (section_to_show == "previous") {
section_to_show = this.section_currently_showing - 1;
direction = "left";
} else if (section_to_show == "next") {
section_to_show = this.section_currently_showing + 1;
}
if (section_to_show == null || isNaN(section_to_show) || section_to_show < 0 || section_to_show >= this.sections.length) {
return;
}
if(section_to_show == 0) {
$('.prev_button').hide();
$('.next_button').show();
} else if(section_to_show == (this.sections.length-1)) {
$('.next_button').hide();
$('.prev_button').show();
} else {
$('.prev_button').show();
$('.next_button').show();
}
// if user has to view sections in sequence and hasn't gotten up to this one, don't allow it
if (this.md.sequenced_sections == "true" && section_to_show > this.last_available_section) {
// but let instructors through
if (player.activity.is_instructor()) {
Standard_Dialog.alert("Please note: Students need to read and complete each section of the activity before moving on to the next section. Instructors, however, can skip around between sections as they choose.");
} else {
Standard_Dialog.alert(this.md.section_sequence_message);
return;
}
}
this.show_section_animate(section_to_show, direction);
// process iframes for the section, unless all were preloaded
if (player.md.preload_all_iframes != "true") {
this.figures.process_iframes(this.get_current_section().jq); // iframes
}
this.update_section_status();
this.update_navigation();
}