canvas-lms/public/javascripts/quiz_history.js

470 lines
16 KiB
JavaScript

/*
* Copyright (C) 2012 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import $ from 'jquery'
import I18n from 'i18n!quizzes'
import numberHelper from 'jsx/shared/helpers/numberHelper'
import './jquery.instructure_misc_plugins' /* fragmentChange */
import './jquery.templateData'
import './vendor/jquery.scrollTo'
import 'compiled/behaviors/quiz_selectmenu'
var parentWindow = {
exists: function(){
return (window.parent && window.parent.INST);
},
respondsTo: function(funcName){
return (parentWindow.exists() && $.isFunction(window.parent.INST[funcName]));
},
hasProperty: function(propName){
return (parentWindow.exists() && window.parent.INST[propName]);
},
set: function(propName, value){
if(parentWindow.exists()){
window.parent.INST[propName] = value;
}
},
get: function(propName){
if(parentWindow.hasProperty(propName)){
return window.parent.INST[propName];
}
}
};
// end parentWindow object
var data = $("#submission_details").getTemplateData({textValues: ['version_number', 'user_id']});
var scoringSnapshot = {
snapshot: {
user_id: data.user_id || null,
version_number: data.version_number,
last_question_touched: null,
question_updates: {},
fudge_points: 0
},
$quizBody: null,
jumpPosition: function(question_id) {
var $question = $("#question_" + question_id);
if($question.length > 0) {
return $question.offset().top - 110;
} else {
return 0;
}
},
checkQuizBody: function() {
if(scoringSnapshot.$quizBody === null){
scoringSnapshot.$quizBody = $('html,body');
}
},
// Animates scrolling to question if there is no page reload
jumpToQuestion: function(question_id) {
var top = scoringSnapshot.jumpPosition(question_id);
scoringSnapshot.checkQuizBody();
scoringSnapshot.$quizBody.stop();
scoringSnapshot.$quizBody.clearQueue();
scoringSnapshot.$quizBody.animate({scrollTop: top}, 500);
},
// Jumps directly to question upon a page reload
jumpDirectlyToQuestion: function(question_id) {
var top = scoringSnapshot.jumpPosition(question_id);
scoringSnapshot.checkQuizBody();
scoringSnapshot.$quizBody.scrollTop(top);
},
externallySet: false,
setSnapshot: function(data, cancelIfAlreadyExternallySet) {
if(data) {
if(cancelIfAlreadyExternallySet && scoringSnapshot.externallySet) { return; }
scoringSnapshot.externallySet = true;
scoringSnapshot.snapshot = data;
for(var idx in data.question_updates) {
var question = data.question_updates[idx];
var $question = $("#question_" + idx);
if (!ENV.GRADE_BY_QUESTION) {
$question.addClass('modified_but_not_saved');
}
$question
.find("#question_input_hidden").val(question.points).end()
.find(".user_points :text").val(I18n.n(question.points)).end()
.find(".question_neutral_comment .question_comment_text textarea").val(question.comments);
}
if(parentWindow.hasProperty('lastQuestionTouched') && !ENV.GRADE_BY_QUESTION) {
scoringSnapshot.jumpToQuestion(window.parent.INST.lastQuestionTouched);
} else if(scoringSnapshot.snapshot.last_question_touched && !ENV.GRADE_BY_QUESTION) {
scoringSnapshot.jumpToQuestion(scoringSnapshot.snapshot.last_question_touched);
}
} else if(cancelIfAlreadyExternallySet) {
if(parentWindow.hasProperty('lastQuestionTouched') && !ENV.GRADE_BY_QUESTION) {
scoringSnapshot.jumpToQuestion(window.parent.INST.lastQuestionTouched);
}
}
if(scoringSnapshot.externallySet || cancelIfAlreadyExternallySet) {
$("#feel_free_to_toggle_message").show();
}
if(parentWindow.respondsTo('refreshQuizSubmissionSnapshot')) {
window.parent.INST.refreshQuizSubmissionSnapshot(scoringSnapshot.snapshot);
}
},
update: function(question_id, data){
scoringSnapshot.snapshot.question_updates[question_id] = data;
scoringSnapshot.snapshot.last_question_touched = question_id;
scoringSnapshot.setSnapshot();
}
}
//end of scoringSnapshot object
var gradingForm = {
ensureSelectEventsFire: function(){
$("input[type=text]").focus(function() {
$(this).select();
});
},
scrollToUpdatedQuestion: function(event, hash) {
if(hash.indexOf("#question") == 0) {
var id = hash.substring(10);
scoringSnapshot.jumpToQuestion(id);
}
},
updateSnapshotFor: function($question){
var question_id = $question.attr('id').substring(9) || null;
if(question_id) {
var data = {};
if (!ENV.GRADE_BY_QUESTION) {
$question.addClass('modified_but_not_saved');
}
data.points = numberHelper.parse($question.find(".user_points :text").val());
data.comments = $question.find(".question_neutral_comment .question_comment_text textarea").val() || "";
scoringSnapshot.update(question_id, data);
}
$(document).triggerHandler('score_changed');
},
addFudgePoints: function(points){
if(points || points === 0) {
scoringSnapshot.snapshot.fudge_points = points;
scoringSnapshot.setSnapshot();
}
$(document).triggerHandler('score_changed');
},
setInitialSnapshot: function(data){
$("#feel_free_to_toggle_message").show();
if(data) {
scoringSnapshot.setSnapshot(data);
} else {
scoringSnapshot.setSnapshot(null, true);
}
},
onScoreChanged: function(){
var $total = $("#after_fudge_points_total");
var total = 0;
$(".display_question .user_points:visible").each(function() {
var points = numberHelper.parse($(this).find("input.question_input").val()) || 0;
points = Math.round(points * 100.0) / 100.0;
total = total + points;
});
var fudge = (numberHelper.parse($("#fudge_points_entry").val()) || 0);
fudge = Math.round(fudge * 100.0) / 100.0;
total = total + fudge;
$total.text(I18n.n(total) || "0");
},
questions: function(){
return $('.question_holder').map(function(index, el) {
return $(el).position().top - 320;
}).toArray();
},
onScroll: function(){
var qNum = quizNavBar.activateCorrectLink();
quizNavBar.toggleDropShadow();
},
onWindowResize: function(){
//Add padding to the bottom of the last question
var winHeight = $(window).innerHeight();
var lastHeight = $('div.question_holder:last-child').outerHeight();
var fixedButtonHeight = $('#speed_update_scores_container').outerHeight();
var paddingHeight = Math.max(winHeight - lastHeight - 150, fixedButtonHeight);
$('#update_history_form .quiz-submission.headless').css('marginBottom', paddingHeight + 'px');
}
};
//end of gradingForm object
var quizNavBar = {
index: 0,
windowSize: 10,
minWidth: 66,
startingLeftPos: 32,
navItemWidth: 34,
initialize: function(){
$('.user_points > .question_input').each(function(index){
quizNavBar.updateStatusFor($(this));
});
if (ENV.GRADE_BY_QUESTION) {
var questionIndex = parseInt(parentWindow.get('active_question_index'));
var questionId = $('.q' + questionIndex).data('id');
if(!isNaN(questionId)){
scoringSnapshot.jumpDirectlyToQuestion(questionId);
}
}
quizNavBar.updateWindowSize();
quizNavBar.setScrollWindowPosition(0);
},
size: function(){
return $('.question-nav-link').length;
},
tooBig: function(){
return quizNavBar.size() > quizNavBar.windowSize;
},
updateWindowSize: function(){
var fullWidth = $('.quiz-nav, .quiz-nav-fullpage').width();
var minPadding = 10;
var maxWidth = fullWidth - (minPadding * 2);
var itemCount = Math.floor((maxWidth - quizNavBar.minWidth) / quizNavBar.navItemWidth);
quizNavBar.windowSize = itemCount;
var actualWidth = (itemCount * quizNavBar.navItemWidth) + quizNavBar.minWidth;
$('.quiz-nav .nav, .quiz-nav-fullpage .nav').animate({width: actualWidth + 'px'}, 10);
},
navArrowCache: null,
$navArrows: function(){
if(quizNavBar.navArrowCache === null){
quizNavBar.navArrowCache = $('.quiz-nav .nav-arrow, .quiz-nav-fullpage .nav-arrow');
}
return quizNavBar.navArrowCache;
},
navWrapperCache: null,
$navWrapper: function(){
if(quizNavBar.navWrapperCache === null){
quizNavBar.navWrapperCache = $('#quiz-nav-inner-wrapper');
}
return quizNavBar.navWrapperCache;
},
updateArrows: function(){
if(quizNavBar.tooBig()){
quizNavBar.$navArrows().show();
quizNavBar.$navWrapper().css({position: 'absolute'});
} else {
quizNavBar.$navArrows().hide();
quizNavBar.$navWrapper().css({position: 'relative'});
}
},
toggleDropShadow: function(){
//Add shadow to top bar
$('.quiz-nav').toggleClass('drshadow', ($(document).scrollTop() > 0));
},
updateStatusFor: function($scoreInput){
try{
var questionId = $scoreInput.attr('data-question-id');
var scoreValue = numberHelper.parse($scoreInput.val());
$('#quiz_nav_' + questionId).toggleClass('complete', (!isNaN(scoreValue)));
} catch(err) {
// do nothing; if there's no status to update, continue with other execution
}
},
activateLink: function(index){
$('.quiz-nav li').removeClass('active');
$('.q' + index).addClass('active');
},
activateCorrectLink: function(){
var qNum = 1;
var qArray = gradingForm.questions();
var docScroll = $(document).scrollTop();
var $questions = $('.question')
for(var t = 0; t <= qArray.length; t++) {
var $question = $($questions[t])
var currentQuestionNum = t + 1;
if ( (docScroll > qArray[t] && docScroll < qArray[t+1]) || ( t == (qArray.length - 1) && docScroll > qArray[t])) {
qNum = currentQuestionNum;
parentWindow.set('active_question_index', currentQuestionNum);
quizNavBar.activateLink(currentQuestionNum);
$question.addClass('selected_single_question');
} else {
$('.q'+ currentQuestionNum).removeClass('active');
$question.removeClass('selected_single_question');
}
}
quizNavBar.setScrollWindowPosition(qNum);
return qNum;
},
showQuestionsInWindow: function(startingIndex, endingIndex){
var $navWrapper = $('#quiz-nav-inner-wrapper');
var leftPosition = quizNavBar.startingLeftPos - (startingIndex * quizNavBar.navItemWidth);
var newPos = '' + leftPosition + 'px';
var currentPos = $navWrapper.css('left');
if(newPos !== currentPos){
$navWrapper.stop();
$navWrapper.clearQueue();
$navWrapper.animate({left: leftPosition + 'px'}, 300);
}
},
windowScrollLength: function(){
return Math.floor(quizNavBar.windowSize/2.0);
},
setScrollWindowPosition: function(currentIndex){
if(isNaN(currentIndex)){
currentIndex = 0;
}
quizNavBar.index = currentIndex;
quizNavBar.updateArrows();
if(quizNavBar.tooBig()){
var startingIndex = currentIndex - quizNavBar.windowScrollLength();
var maxStartingIndex = quizNavBar.size() - quizNavBar.windowSize;
if(startingIndex < 0){
startingIndex = 0;
quizNavBar.index = 0;
}else if(startingIndex > maxStartingIndex){
startingIndex = maxStartingIndex;
quizNavBar.index = maxStartingIndex + quizNavBar.windowScrollLength();
}
var endingIndex = startingIndex + quizNavBar.windowSize - 1;
quizNavBar.showQuestionsInWindow(startingIndex, endingIndex);
}
},
previousQuestionBlock: function(){
quizNavBar.setScrollWindowPosition(quizNavBar.index - quizNavBar.windowSize);
},
nextQuestionBlock: function(){
quizNavBar.setScrollWindowPosition(quizNavBar.index + quizNavBar.windowSize);
}
};
//End of quizNavBar object
$(document).ready(function() {
gradingForm.ensureSelectEventsFire();
if (ENV.GRADE_BY_QUESTION) {
$(document).scroll(gradingForm.onScroll);
gradingForm.onWindowResize();
$('.question_holder').click(function() {
$('.quiz-nav li').removeClass('active');
$('.question').removeClass('selected_single_question');
var $questions = $('.question')
var $question = $(this).find('.question');
var questionIndex = $questions.index($question) + 1;
parentWindow.set('active_question_index', questionIndex);
$('.q' + questionIndex).addClass('active');
$question.addClass('selected_single_question');
});
}
quizNavBar.initialize();
$(document).fragmentChange(gradingForm.scrollToUpdatedQuestion);
if(parentWindow.respondsTo('getQuizSubmissionSnapshot')) {
var data = window.parent.INST.getQuizSubmissionSnapshot(scoringSnapshot.snapshot.user_id, scoringSnapshot.snapshot.version_number);
gradingForm.setInitialSnapshot(data);
}
$(".question_holder .user_points .question_input,.question_holder .question_neutral_comment .question_comment_text textarea").change(function() {
var $question = $(this).parents(".display_question");
var questionId = $question.attr('id');
gradingForm.updateSnapshotFor($question);
if($(this).hasClass('question_input')){
const parsed = numberHelper.parse($(this).val())
const hiddenVal = Number.isNaN(parsed) ? '' : parsed
$question.find('.question_input_hidden').val(hiddenVal)
quizNavBar.updateStatusFor($(this));
}
});
$("#fudge_points_entry").change(function() {
var points = numberHelper.parse($(this).val());
const parsed = numberHelper.parse($(this).val())
const hiddenVal = Number.isNaN(parsed) ? '' : parsed
$("#fudge_points_input").val(hiddenVal);
gradingForm.addFudgePoints(points);
});
$(document).bind('score_changed', gradingForm.onScoreChanged);
$('.question-nav-link').click(function(e) {
e.preventDefault();
var questionId = $(this).attr('data-id');
scoringSnapshot.jumpToQuestion(questionId);
});
$('#nav-prev').click(function(e){
e.preventDefault();
quizNavBar.previousQuestionBlock();
});
$('#nav-next').click(function(e){
e.preventDefault();
quizNavBar.nextQuestionBlock();
});
$(window).resize(function () {
quizNavBar.updateWindowSize();
quizNavBar.setScrollWindowPosition(quizNavBar.index);
gradingForm.onWindowResize();
});
});
if (ENV.SCORE_UPDATED) {
$(document).ready(function() {
if(parentWindow.respondsTo('refreshGrades')) {
window.parent.INST.refreshGrades();
}
if(parentWindow.respondsTo('clearQuizSubmissionSnapshot')) {
window.parent.INST.clearQuizSubmissionSnapshot(scoringSnapshot.snapshot);
}
});
}