/* brb: New code for HTML5 brightcove video player. Processing of videos
in DF takes place in the Figures.process_media method. So we need to
rewrite it to use the new player markup and methods. */
Figures = Figures.extend({
bcVideo: {}, // holds all of the video players (by ID)
bcPlayerData: { 'accountId': '1500315202001', 'playerId': 'B1AhVYg4l' },
process_media: function() {
var context = this;
// Process each video
$("[data-mmtype='mov']").each(function() {
var $this = $(this);
var $parent = $this.parent("[data-type='figure']");
var video_mmsrc = $this.attr("data-mmsrc");
//var video_id = "vidPlayerID";
var video_id = $parent.attr("data-figure-id");
var caption = "";
var $caption = $parent.find("[data-type='caption']");
if ($caption.length == 1) {
caption = "
" + $caption.html() + "
";
}
// Replace the current figure HTML with the new HTML5 video HTML
playerHTML = '
' + caption + '
';
$parent.before(playerHTML);
$parent.remove();
// instantiate the player
bc(document.getElementById(video_id));
// create player instance and set up cuepoints
safe_log("creating video player");
videojs(video_id).ready(function() {
context.bcVideo[video_id] = this;
// reset the video to the beginning after it ends
context.bcVideo[video_id].on("ended", function() {
context.bcVideo[video_id].currentTime(0);
context.bcVideo[video_id].pause();
//$("#" + video_id).removeClass("vjs-has-started");
// Is there a check answer button on the page?
$check_answer = $("#digfir_section_" + player.section_currently_showing).find("button.check");
// Is there a submit button on the page?
$submit_button = $("#digfir_section_" + player.section_currently_showing).find("button.submit_btn");
// also, enable the next button for the page
if (player.section_currently_showing == player.last_available_section) {
if ($check_answer.length == 0 && $submit_button.length == 0) {
player.last_available_section = player.section_currently_showing + 1;
$('.next_button').addClass("active");
}
if (window.player.ARGA_running) {
var las = Get_ARGA_Data("LASX");
// only do this if there are no 'check answer'
// buttons on the page (e.g. Depth Cues slides
// 18 and 19)
if ($check_answer.length == 0 && $submit_button.length == 0) {
if (las <= player.section_currently_showing) {
safe_log("updating LASX to " + (player.section_currently_showing+1));
Set_ARGA_Data("LVSX", player.section_currently_showing);
Set_ARGA_Data("LASX", (player.section_currently_showing+1));
player.activity.ARGA_submit_data(false);
}
}
}
}
});
context.bcVideo[video_id].on("play", function() {
//$("#" + video_id).addClass("vjs-has-started");
});
}); //end ready
});
}
});
// Constants
var APPLICATION_WIDTH = 1044;
var APPLICATION_HEIGHT = 792;
var KEYCODES = {
ENTER: 13,
TAB: 9,
ESC: 27,
SPACE: 32
};
var setResizable = function (element, defaultWidth, defaultHeight) {
'use strict';
element.style.width = defaultWidth + "px";
element.style.height = defaultHeight + "px";
element.style.marginLeft = "0";
element.style.marginRight = "0";
var parentDiv = document.createElement('div');
parentDiv.style.display = 'inline-block';
parentDiv.style.overflow = 'hidden';
parentDiv.style.position = 'relative';
element.parentNode.appendChild(parentDiv);
parentDiv.appendChild(element);
var resizeThis = function () {
var parentWidth = parentDiv.parentNode.offsetWidth;
var parentHeight = parentDiv.parentNode.offsetHeight;
var scaleFactor = Math.min(parentWidth / defaultWidth, parentHeight / defaultHeight);
var cssScale = "scale(" + scaleFactor + "," + scaleFactor + ")";
var cssOrigin = "0 0";
element.style.transformOrigin = cssOrigin;
element.style.msTransformOrigin = cssOrigin;
element.style.webkitTransformOrigin = cssOrigin;
element.style.mozTransformOrigin = cssOrigin;
element.style.transform = cssScale;
element.style.msTransform = cssScale;
element.style.webkitTransform = cssScale;
element.style.mozTransform = cssScale;
element._scaleFactor = scaleFactor;
window.player._scaleFactor = scaleFactor;
parentDiv.style.width = Math.round(defaultWidth * scaleFactor) + "px";
parentDiv.style.height = Math.round(defaultHeight * scaleFactor) + "px";
};
window.addEventListener('resize', resizeThis);
resizeThis();
};
var disableTouchZooming = function () {
'use strict';
var head = document.head || document.querySelector('head');
var firstChild = head.firstChild;
var meta = document.createElement('meta');
meta.setAttribute('name', 'viewport');
meta.setAttribute('content', 'initial-scale=1.0, maximum-scale=1.0, user-scalable=no, width=device-width');
if (firstChild) {
head.insertBefore(meta, firstChild);
}
else {
head.appendChild(meta);
}
var body = document.body || document.querySelector('body');
// Disable zoom page on mouse wheel
body.addEventListener('DOMMouseScroll', mouseWheel, false);
body.addEventListener('mousewheel', mouseWheel, false);
// Disable zoom page on keyboard
body.addEventListener('keydown', hotKeys, false);
// Disable scroll
body.addEventListener('mousemove', function (evt) {
evt.preventDefault();
});
};
var disableEvent = function (evt) {
evt.returnValue = false;
evt.preventDefault();
return false;
};
var mouseWheel = function (evt) {
if (evt.ctrlKey) {
return disableEvent(evt);
}
};
var hotKeys = function (evt) {
var keys = [107/* num + */, 109/* num - */, 187/* + */, 189/* - */];
var keyCode = evt.keyCode || evt.witch;
var pmKeysDown = keys.indexOf(keyCode) > -1;
var cmd = evt.ctrlKey || evt.metaKey;
if (cmd && pmKeysDown) {
return disableEvent(evt);
}
};
var Activity_contpract = window.Activity_manuscript_type.extend({
initialize: function () {
'use strict';
// Reserve first question for page queries
this.questions[0] = "";
$('[data-type=question]').each(this.add_question);
this.add_page_queries();
// Convert submit buttons to buttons using jquery ui
$('.question_submit_button').button();
$('.student_responses_button').button();
$('#manuscript').append("");
},
grade_activity: function () {
'use strict';
// sections are 0 based
var curr_sec = parseInt(player.section_currently_showing);
var last_sec = parseInt(player.sections.length) - 1;
// brb: If we can't determine what section we are currently in then we
// can't give a grade and thus can exit now (this happens when the user
// first opens the activity).
if (isNaN(curr_sec)) {
return;
}
// brb: We need to change the logic here. Since we aren't using ARGA to store
// answers, if the user exits the activity and comes back in later then their
// previous answers are not preserved, so we either need to force them to redo
// the whole thing or we just give them 100% credit when they have completed
// the final quiz in the activity. We are going to do the latter.
// brb: We can most likely get rid of all of the following code that adds
// up points totals because we are always giving 100% as soon as the user
// gets to the last slide. But we'll leave it for now just in case removing it
// breaks something.
// brb: Changed my mind. We'll just comment all of this out.
/*
var i;
this.answered_all_queries = true;
this.total_points_possible = 0;
this.total_points_earned = 0;
for (i = 0; i < this.queries.length; i++) {
var question = this.queries[i];
// See if the user answered at all
if ( !question.userHasAnswered() ) {
this.answered_all_queries = false;
}
// Add up points and score
this.total_points_possible += question.getPointsPossible();
this.total_points_earned += question.getPointsAwarded();
}
for (i = 0; i < window.player.sections.length; i++) {
var section = window.player.sections[i];
// See if the user answered at all
if ( section.answered_all_queries === false || section.section_completed === false ) {
this.answered_all_queries = false;
}
// Add up points and score
if ( !isNaN(section.points_possible) ) {
this.total_points_possible += section.points_possible;
}
if ( !isNaN(section.points_earned) ) {
this.total_points_earned += section.points_earned;
}
}
// If there aren't any questions, user gets 100% just for hitting the activity
if ( this.total_points_possible === 0 ) {
this.grade_percent = 100;
// else calculate grade percent, rounded to nearest whole percentage
}
else {
this.grade_percent = Math.round(( this.total_points_earned / this.total_points_possible ) * 100);
}
*/
// If all queries have been answered, do ARGA stuff
// brb: We don't care if all of the queries have been answered, we only
// care tha tthe user has reached the last quiz slide, at which time we
// will give 100% credit.
if (window.player.ARGA_running) {
//if ( this.answered_all_queries ) {
// the very last quiz slide is the Congratulations slide so we want
// the one right before that
if ((last_sec - 1) === curr_sec) {
// if we haven't already set a grade for this activity then do so now
if (Get_ARGA_Data("complete") !== "yes") {
window.Set_ARGA_Question_Response({
questionNum: '' + 1,
questionType: "Custom",
questionText: "Concept Practice Tutorial",
correctAnswer: "See activity for details",
learnerResponse: "Activity was successfully completed",
questionGrade: 100,
questionWeight: 100,
questionData: ""
});
// Set "complete" appropriately
window.Set_ARGA_Data('complete', 'yes');
// And save the grade
// brb: grade is always 100
this.grade_percent = 100;
window.Set_ARGA_Grade(this.grade_percent);
// We don't want a partial grade set on the server until
// the student is done.
window.Save_ARGA_Data();
}
}
}
},
update_question_action_div: function (question_index) {
'use strict';
this._super(question_index);
var question = this.questions[question_index];
var jq = $("#question_action_div_" + question.index);
$(".points_awarded_div").hide();
jq.find(".question_submit_button").show();
jq.find(".question_submit_button").addClass('ui-state-disabled');
jq.find(".question_submit_button").attr('disabled', 'disabled');
},
show_question_feedback: function (question, is_correct) {
'use strict';
// If we don't have any feedback at all, return
if (!question.md.feedback && !question.md.feedback_correct && !question.md.feedback_incorrect && !question.md.feedback_hint) {
return;
}
var html = "
";
// Include general feedback if there
if (question.md.feedback) {
html += "
" + question.md.feedback + "
";
}
// Include correct feedback if there and the answer is correct
if (is_correct && question.md.feedback_correct) {
html += "
" + question.md.feedback_correct + "
";
}
// Include incorrect or hint feedback if there and the answer is incorrect
if (!is_correct && question.md.feedback_incorrect) {
html += "
" + question.md.feedback_incorrect + "
";
}
// Close question_feedback div
html += "
";
window.Standard_Dialog.open(html, {
"title": "",
"width": 290
});
},
ARGA_initialization_alert: function () {
'use strict';
var grade = window.Get_ARGA_Grade();
var message = "";
var buttons;
// brb
var lvs;
var las;
if (window.player.ARGA_running) {
lvs = Get_ARGA_Data("LVSX");
las = Get_ARGA_Data("LASX");
safe_log("ARGA_initialization_alert: LVSX=" + lvs + ", LASX=" + las);
}
if (grade !== "" && grade !== null && grade >= 0) {
if (window.player.md.allow_resubmission === "true") {
// Give the student the option of resubmitting or reviewing
message = "
You have completed this activity, and 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?
";
buttons = [
{
text: "Keep current grade",
click: window.player.activity.ARGA_initialization_final
},
{
text: "Try activity again",
click: function () {
window.player.activity.ARGA_initialization_final("reset");
}
}
];
}
// Resubmissions are not allowed
else {
// brb
message = "
You have completed this activity and received a grade of 100%. You may redo any of the slides in this activity without affecting your grade.
";
buttons = [
{
text: "OK",
click: window.player.activity.ARGA_initialization_final
}
];
}
}
// if we need a message, show it in a jquery UI dialog
if (message !== "") {
message = "
" + message + "
";
window.Standard_Dialog.open(message, {
"title": "",
'buttons': buttons
});
}
// brb: if we don't show a message that means the activity has not been completed
// and we need to do ARGA_initialization_final
else {
if (window.player.ARGA_running && las >= 3) {
message = "
You have not completed this activity yet but you may go back and complete previous slides at any time.
";
window.Standard_Dialog.open(message, {
"title": "",
'buttons': buttons
});
}
else {
window.player.activity.ARGA_initialization_final();
}
}
},
ARGA_initialization_final: function (decision) {
'use strict';
// brb
var las = 0;
var lvs = 0;
if (window.player.ARGA_running) {
lvs = Get_ARGA_Data("LVSX");
las = Get_ARGA_Data("LASX");
safe_log("ARGA_initialization_final: LVSX=" + lvs + ", LASX=" + las);
}
// Close dialog if open
$("#arga_init_dialog").dialog('close');
window.Standard_Dialog.close();
// if user chose to reset the activity, reset all submitted answers and grade
if (decision === "reset") {
// PW: ARGA should really provide a function for resetting all data; for now I'll hack it
window.ARGA_API.data = [];
window.Set_ARGA_Grade(-1);
window.player.user_has_received_completion_alert = false;
window.Save_ARGA_Data({"show_progress": false});
// Start on section 0
window.player.show_section(0);
// Else if user is here for the first time...
}
// brb: added las < 2
else if (window.player.ARGA_submission_initialized === false && las < 2) {
// Initialize the questions
window.player.activity.ARGA_Initialize_Questions();
// And show the first questions
window.player.show_section(0);
// Otherwise normal re-initialization
}
else {
// If md.restore_previous_submissions is "true" (this is the default value),
// restore all saved answers
// brb: we always want to restore
//if ( window.player.md.restore_previous_submissions === "true" ) {
window.player.activity.restore_saved_answers();
//}
// Set user_has_received_completion_alert to true
// if the user has already completed the activity
if (window.Get_ARGA_Data("complete") === "yes") {
window.player.user_has_received_completion_alert = true;
}
// brb
window.player.restore_section();
/*
window.Standard_Dialog.open("
Would you like to restore the last visited page?
",
{
"buttons": [
{
text: "Yes",
click: function() {
window.Standard_Dialog.close();
window.player.restore_section();
}
},
{
text: "No",
click: function() {
window.Standard_Dialog.close();
window.player.show_section(0);
}
}
]
});
*/
}
},
restore_saved_answers: function () {
'use strict';
this._super();
window.Standard_Dialog.close();
},
is_instructor: function () {
if (player.ARGA_running && Get_ARGA_Data('user_rights') == '3_instructor' || player.instructor) {
return true;
}
else {
return false;
}
}
});
var Player_contpract = window.Player_manuscript_type.extend({
show_section_animate: function (section_to_show) {
'use strict';
// Hide currently showing section
if (this.section_currently_showing !== null) {
this.sections[this.section_currently_showing].jq.hide();
}
this.section_currently_showing = section_to_show;
var section = this.sections[section_to_show];
section.jq.fadeIn(300);
// If this is the first/last section, disabled the previous/next button
if (this.section_currently_showing === 0) {
$(".prev_button").attr({
tabindex: -1,
disabled: true,
'aria-disabled': true
});
} else {
$(".prev_button").attr({
tabindex: 0,
disabled: false,
'aria-disabled': false
});
}
if (this.section_currently_showing === ( this.sections.length - 1 )) {
$(".next_button").attr({
tabindex: -1,
disabled: true,
'aria-disabled': true
});
} else {
$(".next_button").attr({
tabindex: 0,
disabled: false,
'aria-disabled': false
});
}
if (section.md.section_type && window.mheContpract[section.md.section_type]) {
if (window.mheContpract[section.md.section_type].show) {
window.mheContpract[section.md.section_type].show(section);
}
}
if (section.md && section.md.show_glossary === 'true') {
$(".glossary_button").show();
}
else {
$(".glossary_button").hide();
}
// remove old instruction and add instruction down
$("[data-block_type=section_instructions]").remove();
if (section.instructions) {
$('.footer').html(section.instructionsHTML);
}
else {
$('.footer').text(" ");
}
if (section.md.section_type !== "hover_review") {
section.jq.find('svg').each(function (index, svgNode) {
var svgDescription = svgNode.previousElementSibling;
if (svgDescription && $(svgDescription).is('img.hidden_element')) {
setSvgDescriptionPositionAndSize(svgNode, svgDescription);
}
});
}
if (this.section_currently_showing) {
section.jq.focus();
}
},
initialize: function () {
'use strict';
// Get rid of chapter numbers in question numbers
$('[data-type=question]').find('h3').each(function () {
var html = $(this).html();
html = html.replace(/^Question/, '');
html = html.replace(/\d+\.(\d+)/, '$1.');
$(this).html(html);
});
var qs = (function (a) {
if (a == "") return {};
var b = {};
for (var i = 0; i < a.length; ++i) {
var p = a[i].split('=', 2);
if (p.length == 1)
b[p[0]] = "";
else
b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
}
return b;
})(window.location.search.substr(1).split('&'));
this.resize = qs["resize"] ? (qs["resize"] === 'true') : true;
this.instructor = (qs["role"] === 'instructor');
// Activity title is data-type="title" inside h1
this.activity_title = $('h1').find('[data-type=title]').html();
// Update message on last page
var title = this.activity_title;
var regex = /[!?.;]{1,}/g;
if (!regex.test(title)) {
title += ".";
}
$('.end_text').html('You have completed the activity ' + title);
this._super();
// Re-init activity
this.activity = new Activity_contpract();
this.glossary = new Glossary_contpract();
// Resize if need
if (this.md.activity_resizable === 'true' && this.resize) {
var chapter = document.querySelector('[data-type=chapter]');
setResizable(chapter, APPLICATION_WIDTH, APPLICATION_HEIGHT);
}
else {
window.player._scaleFactor = 1;
}
disableTouchZooming();
// Append overlay, when all assets are loaded we will remove overlay
var $chapter = $('div[data-type=chapter]');
$chapter.append('');
// Start timer for MC Player
// Was commented 20.09 by Dgrishkin, after mc bundle
//window.mheContpract.libs.timer.play();
},
initialize2: function () {
'use strict';
// brb: Need to set allowfullscreen to true on parent iframe so videos
// can go to full screen
$('#document-body-iframe', window.parent.document).attr('allowfullscreen', 'true').attr('mozallowfullscreen', 'true').attr('webkitallowfullscreen', 'true');
// ARGA should now be initialized if it's running
// If ARGA is running, note here whether or not *any* data has been saved for the user
// that is, whether a submission has been initialized
if (window.player.ARGA_running) {
// We know something has been stored if "complete" is not an empty string
if (window.Get_ARGA_Data("complete") !== "") {
this.ARGA_submission_initialized = true;
}
}
// Initialize activity (e.g. questions) and sections
this.activity.initialize();
this.show_navigation();
var callback = function () {
this.initialize_sections();
var storage = localStorage.getItem('achived_quize_index');
// if ARGA is running, do some things
if (window.player.ARGA_running) {
// Show custom initialization alert
// note that we do further initialization after that alert has been responded to;
// see ARGA_initialization_final
this.activity.ARGA_initialization_alert();
// Otherwise just show section 0
}
else {
var last_page = +localStorage.getItem('last_page');
if (localStorage.getItem('last_page') !== null) {
window.Standard_Dialog.open(
"
Not finished yet. Would you like to restore the last visited page?
",
{
"buttons": [{
text: "Yes",
click: function () {
window.Standard_Dialog.close();
window.player.last_available_section = last_page;
for (var i = 0; i <= last_page; ++i) {
window.player.sections[i].all_question_sequences_completed = true;
window.player.sections[i].all_questions_answered = true;
}
window.player.show_section(last_page);
}
}, {
text: "No",
click: function () {
window.Standard_Dialog.close();
window.player.show_section(0);
}
}
]
});
} else {
this.show_section(0);
}
}
}.bind(this);
// Loading all resources and then show section 0 or initialization alert
this.loading_resources(callback);
},
// Loading all resources and show loading progress bar
loading_resources: function (callback) {
'use strict';
var $overlay = $('.overlay.overlay-preloader');
safe_log("loading_resources...");
// Find all assets
var $images = $('img');
var $svgElements = $('.svg');
var $movieclipElements = $('.movieclip');
var $videos = $('.video');
var resourcesLoaded = 0;
// brb: we are removing videos from the preloading count because they
// aren't always loading properly from production
var length = $images.length +
$svgElements.length +
$movieclipElements.length;// +
//$videos.length;
safe_log("loading_resources: length = " + length);
safe_log("movieclips: " + $movieclipElements.length);
safe_log("svg: " + $svgElements.length);
safe_log("images: " + $images.length);
//safe_log("videos: " + $videos.length);
// Preload all assets
if (length) {
var onEnd = function (str) {
resourcesLoaded++;
safe_log("onEnd: " + str + " [" + resourcesLoaded + " resources loaded]");
if (resourcesLoaded === length) {
safe_log("onEnd: preloaded all resources, removing overlay");
callback();
$overlay.remove();
}
};
window.mheContpract.movieclips = window.mheContpract.movieclips || {};
// Preloading movieclips (SVG + JSON)
$movieclipElements.each(function () {
var $mcElement = $(this);
var url = $mcElement.text();
var name = $mcElement.data('name');
var size = $mcElement.data('size') || 1;
var altText = $mcElement.attr('alt') || $mcElement.attr('aria-label');
safe_log("loading_resources: preloading movieclip " + name);
window.mheContpract.libs.movieclip(name, url, function (mc) {
var width = parseInt(mc.node.style.width, 10);
var height = parseInt(mc.node.style.height, 10);
mc.node.setAttribute('viewBox', '0 0 ' + width + ' ' + height);
mc.node.setAttribute('focusable', 'false');
mc.node.style.width = Math.round(size * width) + 'px';
mc.node.style.height = Math.round(size * height) + 'px';
$(mc.node).find('text').attr('aria-hidden', 'true');
$mcElement.parent().append(mc.node);
mc.show();
window.mheContpract.movieclips[name] = mc;
onEnd("movieclip " + name);
});
});
// TODO move all label_svg to