diff --git a/.github/workflows/moodle-ci.yml b/.github/workflows/moodle-ci.yml index 50f9d58..2dc7996 100644 --- a/.github/workflows/moodle-ci.yml +++ b/.github/workflows/moodle-ci.yml @@ -28,7 +28,7 @@ jobs: fail-fast: false matrix: php: ['7.2', '7.3', '7.4'] - moodle-branch: ['MOODLE_310_STABLE', 'MOODLE_39_STABLE'] + moodle-branch: ['MOODLE_400_STABLE', 'MOODLE_310_STABLE'] database: [pgsql, mariadb] steps: diff --git a/ajax.php b/ajax.php index 15319e9..416a4c5 100755 --- a/ajax.php +++ b/ajax.php @@ -45,7 +45,9 @@ function show_all_improvise_questions(jazzquiz $jazzquiz) { $improviser = new improviser($jazzquiz); $questionrecords = $improviser->get_all_improvised_question_definitions(); + debugging( 'show'.$questionrecords ); if (!$questionrecords) { + debugging( 'No improvisation questions' ); return [ 'status' => 'error', 'message' => 'No improvisation questions' diff --git a/amd/build/core.min.js b/amd/build/core.min.js index 2927e03..da0b0c1 100644 --- a/amd/build/core.min.js +++ b/amd/build/core.min.js @@ -1,2 +1,10 @@ -function _classCallCheck(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function _defineProperties(a,b){for(var c=0,d;c=this.countdownTimeLeft){clearInterval(this.countdownInterval);this.countdownInterval=0;this.startAttempt(a)}else if(0!==this.countdownTimeLeft){setText(Quiz.info,"question_will_start_in_x_seconds","jazzquiz",this.countdownTimeLeft)}else{setText(Quiz.info,"question_will_start_now")}}},{key:"startCountdown",value:function startCountdown(a,b){var c=this;if(0!==this.countdownInterval){return!0}a=parseInt(a);b=parseInt(b);this.countdownTimeLeft=b;if(1>b){if(0this.endTime){this.hideTimer();this.onTimerEnding()}else{var b=parseInt((this.endTime-a)/1e3);this.quiz.role.onTimerTick(b)}}},{key:"startAttempt",value:function startAttempt(a){var b=this;Quiz.hide(Quiz.info);this.refresh();this.isRunning=!0;a=parseInt(a);if(0===a){return}this.quiz.role.onTimerTick(a);this.endTime=new Date().getTime()+1e3*a;this.timerInterval=setInterval(function(){return b.onTimerTick()},1e3)}}],[{key:"box",get:function get(){return $("#jazzquiz_question_box")}},{key:"timer",get:function get(){return $("#jazzquiz_question_timer")}},{key:"form",get:function get(){return $("#jazzquiz_question_form")}},{key:"isLoaded",value:function isLoaded(){return""!==Question.box.html()}}]);return Question}(),Quiz=function(){function a(b){_classCallCheck(this,a);this.state="";this.isNewState=!1;this.question=new Question(this);this.role=new b(this);this.events={notrunning:"onNotRunning",preparing:"onPreparing",running:"onRunning",reviewing:"onReviewing",sessionclosed:"onSessionClosed",voting:"onVoting"}}_createClass(a,[{key:"changeQuizState",value:function changeQuizState(a,b){this.isNewState=this.state!==a;this.state=a;this.role.onStateChange(a);var c=this.events[a];this.role[c](b)}},{key:"poll",value:function poll(a){var b=this;Ajax.get("info",{},function(c){b.changeQuizState(c.status,c);setTimeout(function(){return b.poll(a)},a)})}}],[{key:"main",get:function get(){return $("#jazzquiz")}},{key:"info",get:function get(){return $("#jazzquiz_info_container")}},{key:"responded",get:function get(){return $("#jazzquiz_responded_container")}},{key:"responses",get:function get(){return $("#jazzquiz_responses_container")}},{key:"responseInfo",get:function get(){return $("#jazzquiz_response_info_container")}},{key:"hide",value:function hide(a){a.addClass("hidden")}},{key:"show",value:function show(a){a.removeClass("hidden")}},{key:"uncheck",value:function uncheck(a){a.children(".fa").removeClass("fa-check-square-o").addClass("fa-square-o")}},{key:"check",value:function check(a){a.children(".fa").removeClass("fa-square-o").addClass("fa-check-square-o")}},{key:"renderAllMathjax",value:function renderAllMathjax(){mEvent.notifyFilterContentUpdated(document.getElementsByClassName("jazzquiz-response-container"))}},{key:"addMathjaxElement",value:function addMathjaxElement(b,c){b.html(""+c+"");a.renderAllMathjax()}},{key:"renderMaximaEquation",value:function renderMaximaEquation(b,c){var d=document.getElementById(c);if(null===d){return}if(cache[b]!==void 0){a.addMathjaxElement($("#"+c),cache[b]);return}Ajax.get("stack",{input:encodeURIComponent(b)},function(b){cache[b.original]=b.latex;a.addMathjaxElement($("#"+c),b.latex)})}}]);return a}();function setText(a,b,c,d){c=c!==void 0?c:"jazzquiz";d=d!==void 0?d:[];$.when(mString.get_string(b,c,d)).done(function(b){return Quiz.show(a.html(b))})}return{initialize:function initialize(a,b,c,d,e){session.courseModuleId=a;session.activityId=b;session.sessionId=c;session.attemptId=d;session.sessionKey=e},Quiz:Quiz,Question:Question,Ajax:Ajax,setText:setText}}); -//# sourceMappingURL=core.min.js.map +/** + * @package mod_jazzquiz + * @author Sebastian S. Gundersen + * @copyright 2014 University of Wisconsin - Madison + * @copyright 2018 NTNU + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define("mod_jazzquiz/core",["jquery","core/config","core/str","core/yui","core/event"],(function($,mConfig,mString,Y,mEvent){let session={courseModuleId:0,activityId:0,sessionId:0,attemptId:0,sessionKey:""},cache=[];class Ajax{static request(method,url,data,success){return data.id=session.courseModuleId,data.sessionid=session.sessionId,data.attemptid=session.attemptId,data.sesskey=session.sessionKey,$.ajax({type:method,url:url,data:data,dataType:"json",success:success,error:function(xhr,status,error){}}).fail((()=>setText(Quiz.info,"error_with_request")))}static get(action,data,success){return data.action=action,Ajax.request("get","ajax.php",data,success)}static post(action,data,success){return data.action=action,Ajax.request("post","ajax.php",data,success)}}class Question{constructor(quiz){this.quiz=quiz,this.isRunning=!1,this.isSaving=!1,this.endTime=0,this.isVoteRunning=!1,this.hasVotes=!1,this.countdownTimeLeft=0,this.questionTime=0,this.countdownInterval=0,this.timerInterval=0}static get box(){return $("#jazzquiz_question_box")}static get timer(){return $("#jazzquiz_question_timer")}static get form(){return $("#jazzquiz_question_form")}refresh(){Ajax.get("get_question_form",{},(data=>{data.is_already_submitted?setText(Quiz.info,"wait_for_instructor"):(Quiz.show(Question.box.html(data.html)),eval(data.js),data.css.forEach((cssUrl=>{let head=document.getElementsByTagName("head")[0],style=document.createElement("link");style.rel="stylesheet",style.type="text/css",style.href=cssUrl,head.appendChild(style)})),this.quiz.role.onQuestionRefreshed(data),Quiz.renderAllMathjax())}))}hideTimer(){Quiz.hide(Question.timer),clearInterval(this.timerInterval),this.timerInterval=0}onCountdownTick(questionTime){this.countdownTimeLeft--,this.countdownTimeLeft<=0?(clearInterval(this.countdownInterval),this.countdownInterval=0,this.startAttempt(questionTime)):0!==this.countdownTimeLeft?setText(Quiz.info,"question_will_start_in_x_seconds","jazzquiz",this.countdownTimeLeft):setText(Quiz.info,"question_will_start_now")}startCountdown(questionTime,countdownTimeLeft){return 0!==this.countdownInterval||(questionTime=parseInt(questionTime),countdownTimeLeft=parseInt(countdownTimeLeft),this.countdownTimeLeft=countdownTimeLeft,countdownTimeLeft<1?!(questionTime>0&&countdownTimeLeft<-questionTime)&&(questionTime>1?this.startAttempt(questionTime+countdownTimeLeft):this.startAttempt(0),!0):(this.countdownInterval=setInterval((()=>this.onCountdownTick(questionTime)),1e3),!0))}onTimerEnding(){this.isRunning=!1,this.quiz.role.onTimerEnding()}onTimerTick(){const currentTime=(new Date).getTime();if(currentTime>this.endTime)this.hideTimer(),this.onTimerEnding();else{const timeLeft=parseInt((this.endTime-currentTime)/1e3);this.quiz.role.onTimerTick(timeLeft)}}startAttempt(questionTime){Quiz.hide(Quiz.info),this.refresh(),this.isRunning=!0,0!==(questionTime=parseInt(questionTime))&&(this.quiz.role.onTimerTick(questionTime),this.endTime=(new Date).getTime()+1e3*questionTime,this.timerInterval=setInterval((()=>this.onTimerTick()),1e3))}static isLoaded(){return""!==Question.box.html()}}class Quiz{constructor(Role){this.state="",this.isNewState=!1,this.question=new Question(this),this.role=new Role(this),this.events={notrunning:"onNotRunning",preparing:"onPreparing",running:"onRunning",reviewing:"onReviewing",sessionclosed:"onSessionClosed",voting:"onVoting"}}changeQuizState(state,data){this.isNewState=this.state!==state,this.state=state,this.role.onStateChange(state);const event=this.events[state];this.role[event](data)}poll(ms){Ajax.get("info",{},(data=>{this.changeQuizState(data.status,data),setTimeout((()=>this.poll(ms)),ms)}))}static get main(){return $("#jazzquiz")}static get info(){return $("#jazzquiz_info_container")}static get responded(){return $("#jazzquiz_responded_container")}static get responses(){return $("#jazzquiz_responses_container")}static get responseInfo(){return $("#jazzquiz_response_info_container")}static hide($element){$element.addClass("hidden")}static show($element){$element.removeClass("hidden")}static uncheck($element){$element.children(".fa").removeClass("fa-check-square-o").addClass("fa-square-o")}static check($element){$element.children(".fa").removeClass("fa-square-o").addClass("fa-check-square-o")}static renderAllMathjax(){mEvent.notifyFilterContentUpdated(document.getElementsByClassName("jazzquiz-response-container"))}static addMathjaxElement($target,latex){$target.html(''+latex+""),Quiz.renderAllMathjax()}static renderMaximaEquation(input,targetId){null!==document.getElementById(targetId)&&(void 0===cache[input]?Ajax.get("stack",{input:encodeURIComponent(input)},(data=>{cache[data.original]=data.latex,Quiz.addMathjaxElement($("#"+targetId),data.latex)})):Quiz.addMathjaxElement($("#"+targetId),cache[input]))}}function setText($element,key,from,args){from=void 0!==from?from:"jazzquiz",args=void 0!==args?args:[],$.when(mString.get_string(key,from,args)).done((text=>Quiz.show($element.html(text))))}return{initialize:(courseModuleId,activityId,sessionId,attemptId,sessionKey)=>{session.courseModuleId=courseModuleId,session.activityId=activityId,session.sessionId=sessionId,session.attemptId=attemptId,session.sessionKey=sessionKey},Quiz:Quiz,Question:Question,Ajax:Ajax,setText:setText}})); + +//# sourceMappingURL=core.min.js.map \ No newline at end of file diff --git a/amd/build/core.min.js.map b/amd/build/core.min.js.map index 734489b..dc48efc 100644 --- a/amd/build/core.min.js.map +++ b/amd/build/core.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/core.js"],"names":["define","$","mConfig","mString","Y","mEvent","session","courseModuleId","activityId","sessionId","attemptId","sessionKey","cache","Ajax","method","url","data","success","id","sessionid","attemptid","sesskey","ajax","type","dataType","error","fail","setText","Quiz","info","action","request","Question","quiz","isRunning","isSaving","endTime","isVoteRunning","hasVotes","countdownTimeLeft","questionTime","countdownInterval","timerInterval","get","is_already_submitted","show","box","html","eval","js","css","forEach","cssUrl","head","document","getElementsByTagName","style","createElement","rel","href","appendChild","role","onQuestionRefreshed","renderAllMathjax","hide","timer","clearInterval","startAttempt","parseInt","setInterval","onCountdownTick","onTimerEnding","currentTime","Date","getTime","hideTimer","timeLeft","onTimerTick","refresh","Role","state","isNewState","question","events","notrunning","preparing","running","reviewing","sessionclosed","voting","onStateChange","event","ms","changeQuizState","status","setTimeout","poll","$element","addClass","removeClass","children","notifyFilterContentUpdated","getElementsByClassName","$target","latex","input","targetId","target","getElementById","addMathjaxElement","encodeURIComponent","original","key","from","args","when","get_string","done","text","initialize"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * @package mod_jazzquiz\n * @author Sebastian S. Gundersen \n * @copyright 2014 University of Wisconsin - Madison\n * @copyright 2018 NTNU\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(['jquery', 'core/config', 'core/str', 'core/yui', 'core/event'], function ($, mConfig, mString, Y, mEvent) {\n\n // Contains the needed values for using the ajax script.\n let session = {\n courseModuleId: 0,\n activityId: 0, // TODO: Remove activityId? Unsure if used.\n sessionId: 0,\n attemptId: 0,\n sessionKey: ''\n };\n\n // Used for caching the latex of maxima input.\n let cache = [];\n\n // TODO: Migrate to core/ajax module?\n class Ajax {\n\n /**\n * Send a request using AJAX, with method specified.\n * @param {string} method Which HTTP method to use.\n * @param {string} url Relative to root of jazzquiz module. Does not start with /.\n * @param {Object} data Object with parameters as properties. Reserved: id, quizid, sessionid, attemptid, sesskey\n * @param {function} success Callback function for when the request was completed successfully.\n * @return {jqXHR} The jQuery XHR object\n */\n static request(method, url, data, success) {\n data.id = session.courseModuleId;\n data.sessionid = session.sessionId;\n data.attemptid = session.attemptId;\n data.sesskey = session.sessionKey;\n return $.ajax({\n type: method,\n url: url,\n data: data,\n dataType: 'json',\n success: success,\n error: function (xhr, status, error) {\n //console.error('XHR Error: ' + error + '. Status: ' + status);\n }\n }).fail(() => setText(Quiz.info, 'error_with_request'));\n }\n\n /**\n * Send a GET request using AJAX.\n * @param {string} action Which action to query.\n * @param {Object} data Object with parameters as properties. Reserved: id, quizid, sessionid, attemptid, sesskey\n * @param {function} success Callback function for when the request was completed successfully.\n * @return {jqXHR} The jQuery XHR object\n */\n static get(action, data, success) {\n data.action = action;\n return Ajax.request('get', 'ajax.php', data, success);\n }\n\n /**\n * Send a POST request using AJAX.\n * @param {string} action Which action to query.\n * @param {Object} data Object with parameters as properties. Reserved: id, quizid, sessionid, attemptid, sesskey\n * @param {function} success Callback function for when the request was completed successfully.\n * @return {jqXHR} The jQuery XHR object\n */\n static post(action, data, success) {\n data.action = action;\n return Ajax.request('post', 'ajax.php', data, success);\n }\n\n }\n\n class Question {\n\n constructor(quiz) {\n this.quiz = quiz;\n this.isRunning = false;\n this.isSaving = false;\n this.endTime = 0;\n this.isVoteRunning = false;\n this.hasVotes = false;\n this.countdownTimeLeft = 0;\n this.questionTime = 0;\n this.countdownInterval = 0;\n this.timerInterval = 0;\n }\n\n static get box() {\n return $('#jazzquiz_question_box');\n }\n\n static get timer() {\n return $('#jazzquiz_question_timer');\n }\n\n static get form() {\n return $('#jazzquiz_question_form');\n }\n\n /**\n * Request the current question form.\n */\n refresh() {\n Ajax.get('get_question_form', {}, data => {\n if (data.is_already_submitted) {\n setText(Quiz.info, 'wait_for_instructor');\n return;\n }\n Quiz.show(Question.box.html(data.html));\n eval(data.js);\n data.css.forEach(cssUrl => {\n let head = document.getElementsByTagName('head')[0];\n let style = document.createElement('link');\n style.rel = 'stylesheet';\n style.type = 'text/css';\n style.href = cssUrl;\n head.appendChild(style);\n });\n this.quiz.role.onQuestionRefreshed(data);\n Quiz.renderAllMathjax();\n });\n }\n\n /**\n * Hide the question \"ending in\" timer, and clears the interval.\n */\n hideTimer() {\n Quiz.hide(Question.timer);\n clearInterval(this.timerInterval);\n this.timerInterval = 0;\n }\n\n /**\n * Is called for every second of the question countdown.\n * @param {number} questionTime in seconds\n */\n onCountdownTick(questionTime) {\n this.countdownTimeLeft--;\n if (this.countdownTimeLeft <= 0) {\n clearInterval(this.countdownInterval);\n this.countdownInterval = 0;\n this.startAttempt(questionTime);\n } else if (this.countdownTimeLeft !== 0) {\n setText(Quiz.info, 'question_will_start_in_x_seconds', 'jazzquiz', this.countdownTimeLeft);\n } else {\n setText(Quiz.info, 'question_will_start_now');\n }\n }\n\n /**\n * Start a countdown for the question which will eventually start the question attempt.\n * The question attempt might start before this function return, depending on the arguments.\n * If a countdown has already been started, this call will return true and the current countdown will continue.\n * @param {number} questionTime\n * @param {number} countdownTimeLeft\n * @return {boolean} true if countdown is active\n */\n startCountdown(questionTime, countdownTimeLeft) {\n if (this.countdownInterval !== 0) {\n return true;\n }\n questionTime = parseInt(questionTime);\n countdownTimeLeft = parseInt(countdownTimeLeft);\n this.countdownTimeLeft = countdownTimeLeft;\n if (countdownTimeLeft < 1) {\n // Check if the question has already ended.\n if (questionTime > 0 && countdownTimeLeft < -questionTime) {\n return false;\n }\n // No need to start the countdown. Just start the question.\n if (questionTime > 1) {\n this.startAttempt(questionTime + countdownTimeLeft);\n } else {\n this.startAttempt(0);\n }\n return true;\n }\n this.countdownInterval = setInterval(() => this.onCountdownTick(questionTime), 1000);\n return true;\n }\n\n /**\n * When the question \"ending in\" timer reaches 0 seconds, this will be called.\n */\n onTimerEnding() {\n this.isRunning = false;\n this.quiz.role.onTimerEnding();\n }\n\n /**\n * Is called for every second of the \"ending in\" timer.\n */\n onTimerTick() {\n const currentTime = new Date().getTime();\n if (currentTime > this.endTime) {\n this.hideTimer();\n this.onTimerEnding();\n } else {\n const timeLeft = parseInt((this.endTime - currentTime) / 1000);\n this.quiz.role.onTimerTick(timeLeft);\n }\n }\n\n /**\n * Request the current question from the server.\n * @param {number} questionTime\n */\n startAttempt(questionTime) {\n Quiz.hide(Quiz.info);\n this.refresh();\n // Set this to true so that we don't keep calling this over and over.\n this.isRunning = true;\n questionTime = parseInt(questionTime);\n if (questionTime === 0) {\n // 0 means no timer.\n return;\n }\n this.quiz.role.onTimerTick(questionTime); // TODO: Is it worth having this line?\n this.endTime = new Date().getTime() + questionTime * 1000;\n this.timerInterval = setInterval(() => this.onTimerTick(), 1000);\n }\n\n static isLoaded() {\n return Question.box.html() !== '';\n }\n\n }\n\n class Quiz {\n\n constructor(Role) {\n this.state = '';\n this.isNewState = false;\n this.question = new Question(this);\n this.role = new Role(this);\n this.events = {\n notrunning: 'onNotRunning',\n preparing: 'onPreparing',\n running: 'onRunning',\n reviewing: 'onReviewing',\n sessionclosed: 'onSessionClosed',\n voting: 'onVoting'\n };\n }\n\n changeQuizState(state, data) {\n this.isNewState = (this.state !== state);\n this.state = state;\n this.role.onStateChange(state);\n const event = this.events[state];\n this.role[event](data);\n }\n\n /**\n * Initiate the chained session info calls to ajax.php\n * @param {number} ms interval in milliseconds\n */\n poll(ms) {\n Ajax.get('info', {}, data => {\n this.changeQuizState(data.status, data);\n setTimeout(() => this.poll(ms), ms);\n });\n }\n\n static get main() {\n return $('#jazzquiz');\n }\n\n static get info() {\n return $('#jazzquiz_info_container');\n }\n\n static get responded() {\n return $('#jazzquiz_responded_container');\n }\n\n static get responses() {\n return $('#jazzquiz_responses_container');\n }\n\n static get responseInfo() {\n return $('#jazzquiz_response_info_container');\n }\n\n static hide($element) {\n $element.addClass('hidden');\n }\n\n static show($element) {\n $element.removeClass('hidden');\n }\n\n static uncheck($element) {\n $element.children('.fa').removeClass('fa-check-square-o').addClass('fa-square-o');\n }\n\n static check($element) {\n $element.children('.fa').removeClass('fa-square-o').addClass('fa-check-square-o');\n }\n\n /**\n * Triggers a dynamic content update event, which MathJax listens to.\n */\n static renderAllMathjax() {\n mEvent.notifyFilterContentUpdated(document.getElementsByClassName('jazzquiz-response-container'));\n }\n\n /**\n * Sets the body of the target, and triggers an event letting MathJax know about the element.\n * @param {*} $target\n * @param {string} latex\n */\n static addMathjaxElement($target, latex) {\n $target.html('' + latex + '');\n Quiz.renderAllMathjax();\n }\n\n /**\n * Converts the input to LaTeX and renders it to the target with MathJax.\n * @param {string} input\n * @param {string} targetId\n */\n static renderMaximaEquation(input, targetId) {\n const target = document.getElementById(targetId);\n if (target === null) {\n //console.error('Target element #' + targetId + ' not found.');\n return;\n }\n if (cache[input] !== undefined) {\n Quiz.addMathjaxElement($('#' + targetId), cache[input]);\n return;\n }\n Ajax.get('stack', {input: encodeURIComponent(input)}, data => {\n cache[data.original] = data.latex;\n Quiz.addMathjaxElement($('#' + targetId), data.latex);\n });\n }\n\n }\n\n /**\n * Retrieve a language string that was sent along with the page.\n * @param $element\n * @param {string} key Which string in the language file we want.\n * @param {string} [from=jazzquiz] Which language file we want the string from. Default is jazzquiz.\n * @param [args] This is {$a} in the string for the key.\n */\n function setText($element, key, from, args) {\n from = (from !== undefined) ? from : 'jazzquiz';\n args = (args !== undefined) ? args : [];\n $.when(mString.get_string(key, from, args)).done(text => Quiz.show($element.html(text)));\n }\n\n return {\n initialize: (courseModuleId, activityId, sessionId, attemptId, sessionKey) => {\n session.courseModuleId = courseModuleId;\n session.activityId = activityId;\n session.sessionId = sessionId;\n session.attemptId = attemptId;\n session.sessionKey = sessionKey;\n },\n Quiz: Quiz,\n Question: Question,\n Ajax: Ajax,\n setText: setText\n };\n\n});\n"],"file":"core.min.js"} \ No newline at end of file +{"version":3,"file":"core.min.js","sources":["../src/core.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * @package mod_jazzquiz\n * @author Sebastian S. Gundersen \n * @copyright 2014 University of Wisconsin - Madison\n * @copyright 2018 NTNU\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(['jquery', 'core/config', 'core/str', 'core/yui', 'core/event'], function ($, mConfig, mString, Y, mEvent) {\n\n // Contains the needed values for using the ajax script.\n let session = {\n courseModuleId: 0,\n activityId: 0, // TODO: Remove activityId? Unsure if used.\n sessionId: 0,\n attemptId: 0,\n sessionKey: ''\n };\n\n // Used for caching the latex of maxima input.\n let cache = [];\n\n // TODO: Migrate to core/ajax module?\n class Ajax {\n\n /**\n * Send a request using AJAX, with method specified.\n * @param {string} method Which HTTP method to use.\n * @param {string} url Relative to root of jazzquiz module. Does not start with /.\n * @param {Object} data Object with parameters as properties. Reserved: id, quizid, sessionid, attemptid, sesskey\n * @param {function} success Callback function for when the request was completed successfully.\n * @return {jqXHR} The jQuery XHR object\n */\n static request(method, url, data, success) {\n data.id = session.courseModuleId;\n data.sessionid = session.sessionId;\n data.attemptid = session.attemptId;\n data.sesskey = session.sessionKey;\n return $.ajax({\n type: method,\n url: url,\n data: data,\n dataType: 'json',\n success: success,\n error: function (xhr, status, error) {\n //console.error('XHR Error: ' + error + '. Status: ' + status);\n }\n }).fail(() => setText(Quiz.info, 'error_with_request'));\n }\n\n /**\n * Send a GET request using AJAX.\n * @param {string} action Which action to query.\n * @param {Object} data Object with parameters as properties. Reserved: id, quizid, sessionid, attemptid, sesskey\n * @param {function} success Callback function for when the request was completed successfully.\n * @return {jqXHR} The jQuery XHR object\n */\n static get(action, data, success) {\n data.action = action;\n return Ajax.request('get', 'ajax.php', data, success);\n }\n\n /**\n * Send a POST request using AJAX.\n * @param {string} action Which action to query.\n * @param {Object} data Object with parameters as properties. Reserved: id, quizid, sessionid, attemptid, sesskey\n * @param {function} success Callback function for when the request was completed successfully.\n * @return {jqXHR} The jQuery XHR object\n */\n static post(action, data, success) {\n data.action = action;\n return Ajax.request('post', 'ajax.php', data, success);\n }\n\n }\n\n class Question {\n\n constructor(quiz) {\n this.quiz = quiz;\n this.isRunning = false;\n this.isSaving = false;\n this.endTime = 0;\n this.isVoteRunning = false;\n this.hasVotes = false;\n this.countdownTimeLeft = 0;\n this.questionTime = 0;\n this.countdownInterval = 0;\n this.timerInterval = 0;\n }\n\n static get box() {\n return $('#jazzquiz_question_box');\n }\n\n static get timer() {\n return $('#jazzquiz_question_timer');\n }\n\n static get form() {\n return $('#jazzquiz_question_form');\n }\n\n /**\n * Request the current question form.\n */\n refresh() {\n Ajax.get('get_question_form', {}, data => {\n if (data.is_already_submitted) {\n setText(Quiz.info, 'wait_for_instructor');\n return;\n }\n Quiz.show(Question.box.html(data.html));\n eval(data.js);\n data.css.forEach(cssUrl => {\n let head = document.getElementsByTagName('head')[0];\n let style = document.createElement('link');\n style.rel = 'stylesheet';\n style.type = 'text/css';\n style.href = cssUrl;\n head.appendChild(style);\n });\n this.quiz.role.onQuestionRefreshed(data);\n Quiz.renderAllMathjax();\n });\n }\n\n /**\n * Hide the question \"ending in\" timer, and clears the interval.\n */\n hideTimer() {\n Quiz.hide(Question.timer);\n clearInterval(this.timerInterval);\n this.timerInterval = 0;\n }\n\n /**\n * Is called for every second of the question countdown.\n * @param {number} questionTime in seconds\n */\n onCountdownTick(questionTime) {\n this.countdownTimeLeft--;\n if (this.countdownTimeLeft <= 0) {\n clearInterval(this.countdownInterval);\n this.countdownInterval = 0;\n this.startAttempt(questionTime);\n } else if (this.countdownTimeLeft !== 0) {\n setText(Quiz.info, 'question_will_start_in_x_seconds', 'jazzquiz', this.countdownTimeLeft);\n } else {\n setText(Quiz.info, 'question_will_start_now');\n }\n }\n\n /**\n * Start a countdown for the question which will eventually start the question attempt.\n * The question attempt might start before this function return, depending on the arguments.\n * If a countdown has already been started, this call will return true and the current countdown will continue.\n * @param {number} questionTime\n * @param {number} countdownTimeLeft\n * @return {boolean} true if countdown is active\n */\n startCountdown(questionTime, countdownTimeLeft) {\n if (this.countdownInterval !== 0) {\n return true;\n }\n questionTime = parseInt(questionTime);\n countdownTimeLeft = parseInt(countdownTimeLeft);\n this.countdownTimeLeft = countdownTimeLeft;\n if (countdownTimeLeft < 1) {\n // Check if the question has already ended.\n if (questionTime > 0 && countdownTimeLeft < -questionTime) {\n return false;\n }\n // No need to start the countdown. Just start the question.\n if (questionTime > 1) {\n this.startAttempt(questionTime + countdownTimeLeft);\n } else {\n this.startAttempt(0);\n }\n return true;\n }\n this.countdownInterval = setInterval(() => this.onCountdownTick(questionTime), 1000);\n return true;\n }\n\n /**\n * When the question \"ending in\" timer reaches 0 seconds, this will be called.\n */\n onTimerEnding() {\n this.isRunning = false;\n this.quiz.role.onTimerEnding();\n }\n\n /**\n * Is called for every second of the \"ending in\" timer.\n */\n onTimerTick() {\n const currentTime = new Date().getTime();\n if (currentTime > this.endTime) {\n this.hideTimer();\n this.onTimerEnding();\n } else {\n const timeLeft = parseInt((this.endTime - currentTime) / 1000);\n this.quiz.role.onTimerTick(timeLeft);\n }\n }\n\n /**\n * Request the current question from the server.\n * @param {number} questionTime\n */\n startAttempt(questionTime) {\n Quiz.hide(Quiz.info);\n this.refresh();\n // Set this to true so that we don't keep calling this over and over.\n this.isRunning = true;\n questionTime = parseInt(questionTime);\n if (questionTime === 0) {\n // 0 means no timer.\n return;\n }\n this.quiz.role.onTimerTick(questionTime); // TODO: Is it worth having this line?\n this.endTime = new Date().getTime() + questionTime * 1000;\n this.timerInterval = setInterval(() => this.onTimerTick(), 1000);\n }\n\n static isLoaded() {\n return Question.box.html() !== '';\n }\n\n }\n\n class Quiz {\n\n constructor(Role) {\n this.state = '';\n this.isNewState = false;\n this.question = new Question(this);\n this.role = new Role(this);\n this.events = {\n notrunning: 'onNotRunning',\n preparing: 'onPreparing',\n running: 'onRunning',\n reviewing: 'onReviewing',\n sessionclosed: 'onSessionClosed',\n voting: 'onVoting'\n };\n }\n\n changeQuizState(state, data) {\n this.isNewState = (this.state !== state);\n this.state = state;\n this.role.onStateChange(state);\n const event = this.events[state];\n this.role[event](data);\n }\n\n /**\n * Initiate the chained session info calls to ajax.php\n * @param {number} ms interval in milliseconds\n */\n poll(ms) {\n Ajax.get('info', {}, data => {\n this.changeQuizState(data.status, data);\n setTimeout(() => this.poll(ms), ms);\n });\n }\n\n static get main() {\n return $('#jazzquiz');\n }\n\n static get info() {\n return $('#jazzquiz_info_container');\n }\n\n static get responded() {\n return $('#jazzquiz_responded_container');\n }\n\n static get responses() {\n return $('#jazzquiz_responses_container');\n }\n\n static get responseInfo() {\n return $('#jazzquiz_response_info_container');\n }\n\n static hide($element) {\n $element.addClass('hidden');\n }\n\n static show($element) {\n $element.removeClass('hidden');\n }\n\n static uncheck($element) {\n $element.children('.fa').removeClass('fa-check-square-o').addClass('fa-square-o');\n }\n\n static check($element) {\n $element.children('.fa').removeClass('fa-square-o').addClass('fa-check-square-o');\n }\n\n /**\n * Triggers a dynamic content update event, which MathJax listens to.\n */\n static renderAllMathjax() {\n mEvent.notifyFilterContentUpdated(document.getElementsByClassName('jazzquiz-response-container'));\n }\n\n /**\n * Sets the body of the target, and triggers an event letting MathJax know about the element.\n * @param {*} $target\n * @param {string} latex\n */\n static addMathjaxElement($target, latex) {\n $target.html('' + latex + '');\n Quiz.renderAllMathjax();\n }\n\n /**\n * Converts the input to LaTeX and renders it to the target with MathJax.\n * @param {string} input\n * @param {string} targetId\n */\n static renderMaximaEquation(input, targetId) {\n const target = document.getElementById(targetId);\n if (target === null) {\n //console.error('Target element #' + targetId + ' not found.');\n return;\n }\n if (cache[input] !== undefined) {\n Quiz.addMathjaxElement($('#' + targetId), cache[input]);\n return;\n }\n Ajax.get('stack', {input: encodeURIComponent(input)}, data => {\n cache[data.original] = data.latex;\n Quiz.addMathjaxElement($('#' + targetId), data.latex);\n });\n }\n\n }\n\n /**\n * Retrieve a language string that was sent along with the page.\n * @param $element\n * @param {string} key Which string in the language file we want.\n * @param {string} [from=jazzquiz] Which language file we want the string from. Default is jazzquiz.\n * @param [args] This is {$a} in the string for the key.\n */\n function setText($element, key, from, args) {\n from = (from !== undefined) ? from : 'jazzquiz';\n args = (args !== undefined) ? args : [];\n $.when(mString.get_string(key, from, args)).done(text => Quiz.show($element.html(text)));\n }\n\n return {\n initialize: (courseModuleId, activityId, sessionId, attemptId, sessionKey) => {\n session.courseModuleId = courseModuleId;\n session.activityId = activityId;\n session.sessionId = sessionId;\n session.attemptId = attemptId;\n session.sessionKey = sessionKey;\n },\n Quiz: Quiz,\n Question: Question,\n Ajax: Ajax,\n setText: setText\n };\n\n});\n"],"names":["define","$","mConfig","mString","Y","mEvent","session","courseModuleId","activityId","sessionId","attemptId","sessionKey","cache","Ajax","method","url","data","success","id","sessionid","attemptid","sesskey","ajax","type","dataType","error","xhr","status","fail","setText","Quiz","info","action","request","Question","constructor","quiz","isRunning","isSaving","endTime","isVoteRunning","hasVotes","countdownTimeLeft","questionTime","countdownInterval","timerInterval","box","timer","form","refresh","get","is_already_submitted","show","html","eval","js","css","forEach","cssUrl","head","document","getElementsByTagName","style","createElement","rel","href","appendChild","role","onQuestionRefreshed","renderAllMathjax","hideTimer","hide","clearInterval","this","onCountdownTick","startAttempt","startCountdown","parseInt","setInterval","onTimerEnding","onTimerTick","currentTime","Date","getTime","timeLeft","Role","state","isNewState","question","events","notrunning","preparing","running","reviewing","sessionclosed","voting","changeQuizState","onStateChange","event","poll","ms","setTimeout","main","responded","responses","responseInfo","$element","addClass","removeClass","children","notifyFilterContentUpdated","getElementsByClassName","$target","latex","input","targetId","getElementById","undefined","encodeURIComponent","original","addMathjaxElement","key","from","args","when","get_string","done","text","initialize"],"mappings":"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"} \ No newline at end of file diff --git a/amd/build/edit.min.js b/amd/build/edit.min.js index 2a1372f..d533120 100644 --- a/amd/build/edit.min.js +++ b/amd/build/edit.min.js @@ -1,2 +1,10 @@ -function _createForOfIteratorHelper(a){if("undefined"==typeof Symbol||null==a[Symbol.iterator]){if(Array.isArray(a)||(a=_unsupportedIterableToArray(a))){var b=0,c=function(){};return{s:c,n:function n(){if(b>=a.length)return{done:!0};return{done:!1,value:a[b++]}},e:function e(a){throw a},f:c}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var d,e=!0,f=!1,g;return{s:function s(){d=a[Symbol.iterator]()},n:function n(){var a=d.next();e=a.done;return a},e:function e(a){f=!0;g=a},f:function f(){try{if(!e&&null!=d.return)d.return()}finally{if(f)throw g}}}}function _unsupportedIterableToArray(a,b){if(!a)return;if("string"==typeof a)return _arrayLikeToArray(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);if("Object"===c&&a.constructor)c=a.constructor.name;if("Map"===c||"Set"===c)return Array.from(c);if("Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c))return _arrayLikeToArray(a,b)}function _arrayLikeToArray(a,b){if(null==b||b>a.length)b=a.length;for(var c=0,d=Array(b);c + * @copyright 2015 University of Wisconsin - Madison + * @copyright 2018 NTNU + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define("mod_jazzquiz/edit",["jquery"],(function($){function submitQuestionOrder(order,courseModuleId){$.post("edit.php",{id:courseModuleId,action:"order",order:JSON.stringify(order)},(()=>location.reload()))}function getQuestionOrder(){let order=[];return $(".questionlist li").each((function(){order.push($(this).data("question-id"))})),order}function offsetQuestion(questionId,offset){let order=getQuestionOrder(),originalIndex=order.indexOf(questionId);if(-1===originalIndex)return order;for(let i=0;i{$(".edit-question-action").on("click",(function(){const action=$(this).data("action"),questionId=$(this).data("question-id");let order=[];switch(action){case"up":order=offsetQuestion(questionId,1);break;case"down":order=offsetQuestion(questionId,-1);break;case"delete":order=getQuestionOrder();const index=order.indexOf(questionId);-1!==index&&order.splice(index,1);break;default:return}submitQuestionOrder(order,courseModuleId)}));let questionList=document.getElementsByClassName("questionlist")[0];Sortable.create(questionList,{handle:".dragquestion",onSort:()=>submitQuestionOrder(getQuestionOrder(),courseModuleId)}),function(courseModuleId){$(".jazzquiz-add-selected-questions").on("click",(function(){const $checkboxes=$("#categoryquestions td input[type=checkbox]:checked");let questionIds="";for(const checkbox of $checkboxes)questionIds+=checkbox.getAttribute("name").slice(1)+",";$.post("edit.php",{id:courseModuleId,action:"addquestion",questionids:questionIds},(()=>location.reload()))}))}(courseModuleId)}}})); + +//# sourceMappingURL=edit.min.js.map \ No newline at end of file diff --git a/amd/build/edit.min.js.map b/amd/build/edit.min.js.map index 42630b1..a48f986 100644 --- a/amd/build/edit.min.js.map +++ b/amd/build/edit.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/edit.js"],"names":["define","$","submitQuestionOrder","order","courseModuleId","post","id","action","JSON","stringify","location","reload","getQuestionOrder","each","push","data","offsetQuestion","questionId","offset","originalIndex","indexOf","i","length","listenAddToQuiz","on","$checkboxes","questionIds","checkbox","getAttribute","slice","questionids","initialize","index","splice","questionList","document","getElementsByClassName","Sortable","create","handle","onSort"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * @package mod_jazzquiz\n * @author Sebastian S. Gundersen \n * @copyright 2015 University of Wisconsin - Madison\n * @copyright 2018 NTNU\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(['jquery'], function ($) {\n\n /**\n * Submit the question order to the server. An empty array will delete all questions.\n * @param {Array.} order\n * @param {number} courseModuleId\n */\n function submitQuestionOrder(order, courseModuleId) {\n $.post('edit.php', {\n id: courseModuleId,\n action: 'order',\n order: JSON.stringify(order)\n }, () => location.reload()); // TODO: Correct locally instead, but for now just refresh.\n }\n\n /**\n * @returns {Array} The current question order.\n */\n function getQuestionOrder() {\n let order = [];\n $('.questionlist li').each(function () {\n order.push($(this).data('question-id'));\n });\n return order;\n }\n\n /**\n * Move a question up or down by a specified offset.\n * @param {number} questionId\n * @param {number} offset Negative to move down, positive to move up\n * @returns {Array}\n */\n function offsetQuestion(questionId, offset) {\n let order = getQuestionOrder();\n let originalIndex = order.indexOf(questionId);\n if (originalIndex === -1) {\n return order;\n }\n for (let i = 0; i < order.length; i++) {\n if (i + offset === originalIndex) {\n order[originalIndex] = order[i];\n order[i] = questionId;\n break;\n }\n }\n return order;\n }\n\n function listenAddToQuiz(courseModuleId) {\n $('.jazzquiz-add-selected-questions').on('click', function () {\n const $checkboxes = $('#categoryquestions td input[type=checkbox]:checked');\n let questionIds = '';\n for (const checkbox of $checkboxes) {\n questionIds += checkbox.getAttribute('name').slice(1) + ',';\n }\n $.post('edit.php', {\n id: courseModuleId,\n action: 'addquestion',\n questionids: questionIds,\n }, () => location.reload());\n });\n }\n\n return {\n initialize: courseModuleId => {\n $('.edit-question-action').on('click', function () {\n const action = $(this).data('action');\n const questionId = $(this).data('question-id');\n let order = [];\n switch (action) {\n case 'up':\n order = offsetQuestion(questionId, 1);\n break;\n case 'down':\n order = offsetQuestion(questionId, -1);\n break;\n case 'delete':\n order = getQuestionOrder();\n const index = order.indexOf(questionId);\n if (index !== -1) {\n order.splice(index, 1);\n }\n break;\n default:\n return;\n }\n submitQuestionOrder(order, courseModuleId);\n });\n let questionList = document.getElementsByClassName('questionlist')[0];\n Sortable.create(questionList, {\n handle: '.dragquestion',\n onSort: () => submitQuestionOrder(getQuestionOrder(), courseModuleId)\n });\n listenAddToQuiz(courseModuleId);\n }\n };\n\n});\n"],"file":"edit.min.js"} \ No newline at end of file +{"version":3,"file":"edit.min.js","sources":["../src/edit.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * @package mod_jazzquiz\n * @author Sebastian S. Gundersen \n * @copyright 2015 University of Wisconsin - Madison\n * @copyright 2018 NTNU\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(['jquery'], function ($) {\n\n /**\n * Submit the question order to the server. An empty array will delete all questions.\n * @param {Array.} order\n * @param {number} courseModuleId\n */\n function submitQuestionOrder(order, courseModuleId) {\n $.post('edit.php', {\n id: courseModuleId,\n action: 'order',\n order: JSON.stringify(order)\n }, () => location.reload()); // TODO: Correct locally instead, but for now just refresh.\n }\n\n /**\n * @returns {Array} The current question order.\n */\n function getQuestionOrder() {\n let order = [];\n $('.questionlist li').each(function () {\n order.push($(this).data('question-id'));\n });\n return order;\n }\n\n /**\n * Move a question up or down by a specified offset.\n * @param {number} questionId\n * @param {number} offset Negative to move down, positive to move up\n * @returns {Array}\n */\n function offsetQuestion(questionId, offset) {\n let order = getQuestionOrder();\n let originalIndex = order.indexOf(questionId);\n if (originalIndex === -1) {\n return order;\n }\n for (let i = 0; i < order.length; i++) {\n if (i + offset === originalIndex) {\n order[originalIndex] = order[i];\n order[i] = questionId;\n break;\n }\n }\n return order;\n }\n\n function listenAddToQuiz(courseModuleId) {\n $('.jazzquiz-add-selected-questions').on('click', function () {\n const $checkboxes = $('#categoryquestions td input[type=checkbox]:checked');\n let questionIds = '';\n for (const checkbox of $checkboxes) {\n questionIds += checkbox.getAttribute('name').slice(1) + ',';\n }\n $.post('edit.php', {\n id: courseModuleId,\n action: 'addquestion',\n questionids: questionIds,\n }, () => location.reload());\n });\n }\n\n return {\n initialize: courseModuleId => {\n $('.edit-question-action').on('click', function () {\n const action = $(this).data('action');\n const questionId = $(this).data('question-id');\n let order = [];\n switch (action) {\n case 'up':\n order = offsetQuestion(questionId, 1);\n break;\n case 'down':\n order = offsetQuestion(questionId, -1);\n break;\n case 'delete':\n order = getQuestionOrder();\n const index = order.indexOf(questionId);\n if (index !== -1) {\n order.splice(index, 1);\n }\n break;\n default:\n return;\n }\n submitQuestionOrder(order, courseModuleId);\n });\n let questionList = document.getElementsByClassName('questionlist')[0];\n Sortable.create(questionList, {\n handle: '.dragquestion',\n onSort: () => submitQuestionOrder(getQuestionOrder(), courseModuleId)\n });\n listenAddToQuiz(courseModuleId);\n }\n };\n\n});\n"],"names":["define","$","submitQuestionOrder","order","courseModuleId","post","id","action","JSON","stringify","location","reload","getQuestionOrder","each","push","this","data","offsetQuestion","questionId","offset","originalIndex","indexOf","i","length","initialize","on","index","splice","questionList","document","getElementsByClassName","Sortable","create","handle","onSort","$checkboxes","questionIds","checkbox","getAttribute","slice","questionids","listenAddToQuiz"],"mappings":";;;;;;;AAuBAA,2BAAO,CAAC,WAAW,SAAUC,YAOhBC,oBAAoBC,MAAOC,gBAChCH,EAAEI,KAAK,WAAY,CACfC,GAAIF,eACJG,OAAQ,QACRJ,MAAOK,KAAKC,UAAUN,SACvB,IAAMO,SAASC,oBAMbC,uBACDT,MAAQ,UACZF,EAAE,oBAAoBY,MAAK,WACvBV,MAAMW,KAAKb,EAAEc,MAAMC,KAAK,mBAErBb,eASFc,eAAeC,WAAYC,YAC5BhB,MAAQS,mBACRQ,cAAgBjB,MAAMkB,QAAQH,gBACX,IAAnBE,qBACOjB,UAEN,IAAImB,EAAI,EAAGA,EAAInB,MAAMoB,OAAQD,OAC1BA,EAAIH,SAAWC,cAAe,CAC9BjB,MAAMiB,eAAiBjB,MAAMmB,GAC7BnB,MAAMmB,GAAKJ,wBAIZf,YAkBJ,CACHqB,WAAYpB,iBACRH,EAAE,yBAAyBwB,GAAG,SAAS,iBAC7BlB,OAASN,EAAEc,MAAMC,KAAK,UACtBE,WAAajB,EAAEc,MAAMC,KAAK,mBAC5Bb,MAAQ,UACJI,YACC,KACDJ,MAAQc,eAAeC,WAAY,aAElC,OACDf,MAAQc,eAAeC,YAAa,aAEnC,SACDf,MAAQS,yBACFc,MAAQvB,MAAMkB,QAAQH,aACb,IAAXQ,OACAvB,MAAMwB,OAAOD,MAAO,wBAMhCxB,oBAAoBC,MAAOC,uBAE3BwB,aAAeC,SAASC,uBAAuB,gBAAgB,GACnEC,SAASC,OAAOJ,aAAc,CAC1BK,OAAQ,gBACRC,OAAQ,IAAMhC,oBAAoBU,mBAAoBR,2BA3CzCA,gBACrBH,EAAE,oCAAoCwB,GAAG,SAAS,iBACxCU,YAAclC,EAAE,0DAClBmC,YAAc,OACb,MAAMC,YAAYF,YACnBC,aAAeC,SAASC,aAAa,QAAQC,MAAM,GAAK,IAE5DtC,EAAEI,KAAK,WAAY,CACfC,GAAIF,eACJG,OAAQ,cACRiC,YAAaJ,cACd,IAAM1B,SAASC,cAkClB8B,CAAgBrC"} \ No newline at end of file diff --git a/amd/build/instructor.min.js b/amd/build/instructor.min.js index 5e36e8f..f8db5a4 100644 --- a/amd/build/instructor.min.js +++ b/amd/build/instructor.min.js @@ -1,2 +1,10 @@ -function _classCallCheck(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function _defineProperties(a,b){for(var c=0,d;c").children("h4"),"showing_vote_results");c.responseInfo.append("
");f(a("#review_show_normal_results"),"click_to_show_original_results");e.remove()}}else if("current_response"===b){if(0===e.length){f(c.responseInfo.html("

").children("h4"),"showing_original_results");c.responseInfo.append("
");f(a("#review_show_vote_results"),"click_to_show_vote_results");d.remove()}}}}},{key:"createBarGraph",value:function createBarGraph(b,d,e,f,g){var h=document.getElementById(e);if(null===h){return}for(var k=0,l=0,m=0,n;ml){l=n}}if(0===k){k=1}if(g){h.innerHTML=""}for(var u=0,v;uo){x.classList.add("outside")}var s=""+b[j].count+"",t=x.insertCell(0);t.onclick=function(){a(this).parent().toggleClass("selected-vote-option")};var y=x.insertCell(1);y.classList.add("bar");y.id=d+"_bar_"+p;y.innerHTML="
"+s+"
";var z=d+"_latex_"+p;t.innerHTML="";c.addMathjaxElement(a("#"+z),b[j].response);if("stack"===b[j].qtype){c.renderMaximaEquation(b[j].response,z)}}else{var A=h.rows[q];A.dataset.row_i=p;A.dataset.response_i=j;A.dataset.percent=o;A.dataset.count=b[j].count;var B=A.classList.contains("outside");if(15o&&!B){A.classList.add("outside")}var C=document.getElementById(d+"_count_"+p);if(null!==C){C.innerHTML=b[j].count}var D=document.getElementById(d+"_bar_"+p);if(null!==D){D.firstElementChild.style.width=o+"%"}}}}},{key:"set",value:function set(d,e,g,h,k,l,m){if(g===void 0){return}if(0===g.length){c.show(c.responded);f(c.responded.find("h4"),"a_out_of_b_responded","jazzquiz",{a:0,b:this.totalStudents});return}switch(k){case"shortanswer":for(var p=0;p"))}this.createBarGraph(this.currentResponses,"current_response",e,l,m);b.sortBarGraph(e)}},{key:"refresh",value:function refresh(b){var d=this;e.get("get_results",{},function(e){d.quiz.question.hasVotes=e.has_votes;d.totalStudents=parseInt(e.total_students);d.set("jazzquiz_responses_container","current_responses_wrapper",e.responses,e.responded,e.question_type,"results",b);if(0"))}a.createBarGraph(h,"vote_response",g,"vote",!1);b.sortBarGraph(g)})}}],[{key:"sortBarGraph",value:function sortBarGraph(a){var b=document.getElementById(a);if(null===b){return}var c=!0;while(c){c=!1;for(var f=0;f");c.addMathjaxElement(i,j[k].name);i.data({time:j[k].time,"question-id":j[k].questionid,"jazzquiz-question-id":j[k].jazzquizquestionid});i.data("test",1);i.on("click",function(){var b=a(this).data("question-id"),c=a(this).data("time"),d=a(this).data("jazzquiz-question-id");f.jumpQuestion(b,c,d);e.html("").removeClass("active");g.removeClass("active")});e.append(i)}})}},{key:"runVoting",value:function runVoting(){var a=b.getSelectedAnswersForVote(),c={questions:encodeURIComponent(JSON.stringify(a))};e.post("run_voting",c,function(){})}},{key:"startQuestion",value:function startQuestion(a,b,d,f){var g=this;c.hide(c.info);this.responses.clear();this.hideCorrectAnswer();e.post("start_question",{method:a,questionid:b,questiontime:d,jazzquizquestionid:f},function(a){return g.quiz.question.startCountdown(a.questiontime,a.delay)})}},{key:"jumpQuestion",value:function jumpQuestion(a,b,c){this.startQuestion("jump",a,b,c)}},{key:"repollQuestion",value:function repollQuestion(){this.startQuestion("repoll",0,0,0)}},{key:"nextQuestion",value:function nextQuestion(){this.startQuestion("next",0,0,0)}},{key:"randomQuestion",value:function randomQuestion(){this.startQuestion("random",0,0,0)}},{key:"closeSession",value:function closeSession(){c.hide(a("#jazzquiz_undo_merge"));c.hide(d.box);c.hide(b.controls);f(c.info,"closing_session");e.post("close_session",{},function(){return window.location=location.href.split("&")[0]})}},{key:"hideCorrectAnswer",value:function hideCorrectAnswer(){if(this.isShowingCorrectAnswer){c.hide(b.correctAnswer);c.uncheck(b.control("answer"));this.isShowingCorrectAnswer=!1}}},{key:"showCorrectAnswer",value:function showCorrectAnswer(){var a=this;this.hideCorrectAnswer();e.get("get_right_response",{},function(d){c.show(b.correctAnswer.html(d.right_answer));c.renderAllMathjax();c.check(b.control("answer"));a.isShowingCorrectAnswer=!0})}}],[{key:"addHotkeys",value:function addHotkeys(c){var d=function(d){if(c.hasOwnProperty(d)){c[d]={action:c[d],repeat:!1};a(document).on("keydown",function(e){if(c[d].repeat||e.ctrlKey){return}if(String.fromCharCode(e.which).toLowerCase()!==d){return}var f=a(":focus").prop("tagName");if(f!==void 0){f=f.toLowerCase();if("input"===f||"textarea"===f){return}}e.preventDefault();c[d].repeat=!0;var g=b.control(c[d].action);if(g.length&&!g.prop("disabled")){g.click()}});a(document).on("keyup",function(a){if(String.fromCharCode(a.which).toLowerCase()===d){c[d].repeat=!1}})}};for(var e in c){d(e)}}},{key:"addEvents",value:function addEvents(c){var d=function(d){if(c.hasOwnProperty(d)){a(document).on("click","#jazzquiz_control_"+d,function(){b.enableControls([]);c[d]()})}};for(var e in c){d(e)}}},{key:"controls",get:function get(){return a("#jazzquiz_controls_box")}},{key:"controlButtons",get:function get(){return b.controls.find(".quiz-control-buttons")}},{key:"control",value:function control(b){return a("#jazzquiz_control_"+b)}},{key:"side",get:function get(){return a("#jazzquiz_side_container")}},{key:"correctAnswer",get:function get(){return a("#jazzquiz_correct_answer_container")}},{key:"isMerging",get:function get(){return 0!==a(".merge-from").length}},{key:"getSelectedAnswersForVote",value:function getSelectedAnswersForVote(){var b=[];a(".selected-vote-option").each(function(a,c){b.push({text:c.dataset.response,count:c.dataset.count})});return b}},{key:"enableControls",value:function enableControls(a){b.controlButtons.children("button").each(function(b,c){var d=c.getAttribute("id").replace("jazzquiz_control_","");c.disabled=-1===a.indexOf(d)})}},{key:"showFullscreenView",value:function showFullscreenView(){if(c.main.hasClass("jazzquiz-fullscreen")){b.closeFullscreenView();return}document.documentElement.style.overflowY="hidden";c.main.addClass("jazzquiz-fullscreen")}},{key:"closeFullscreenView",value:function closeFullscreenView(){document.documentElement.style.overflowY="auto";c.main.removeClass("jazzquiz-fullscreen")}},{key:"closeQuestionListMenu",value:function closeQuestionListMenu(c,d){var e="#jazzquiz_"+d+"_menu",f=a(c.target).closest(e);if(!f.length){a(e).html("").removeClass("active");b.control(d).removeClass("active")}}},{key:"addReportEventHandlers",value:function addReportEventHandlers(){a(document).on("click","#report_overview_controls button",function(){var b=a(this).data("action");if("attendance"===b){a("#report_overview_responded").fadeIn();a("#report_overview_responses").fadeOut()}else if("responses"===b){a("#report_overview_responses").fadeIn();a("#report_overview_responded").fadeOut()}})}}]);return b}();return{initialize:function initialize(a,b,d){var e=new c(h);e.role.totalQuestions=a;if(b){h.addReportEventHandlers();e.role.responses.showResponses=!0;d.forEach(function(a){var b="jazzquiz_wrapper_responses_"+a.num,c="responses_wrapper_table_"+a.num,d="report_"+a.num;e.role.responses.set(b,c,a.responses,void 0,a.type,d,!1)})}else{e.poll(500)}}}}); -//# sourceMappingURL=instructor.min.js.map +/** + * @package mod_jazzquiz + * @author Sebastian S. Gundersen + * @copyright 2014 University of Wisconsin - Madison + * @copyright 2018 NTNU + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define("mod_jazzquiz/instructor",["jquery","mod_jazzquiz/core"],(function($,Jazz){const Quiz=Jazz.Quiz,Question=Jazz.Question,Ajax=Jazz.Ajax,setText=Jazz.setText;class ResponseView{constructor(quiz){this.quiz=quiz,this.currentResponses=[],this.showVotesUponReview=!1,this.respondedCount=0,this.showResponses=!1,this.totalStudents=0,$(document).on("click","#jazzquiz_undo_merge",(()=>this.undoMerge())),$(document).on("click",(event=>{event.target.classList.contains("bar")?this.startMerge(event.target.id):event.target.parentNode&&event.target.parentNode.classList.contains("bar")&&this.startMerge(event.target.parentNode.id)})),$(document).on("click","#review_show_normal_results",(()=>this.refresh(!1))),$(document).on("click","#review_show_vote_results",(()=>this.refreshVotes()))}clear(){Quiz.responses.html(""),Quiz.responseInfo.html("")}hide(){Quiz.uncheck(Instructor.control("responses")),Quiz.hide(Quiz.responses),Quiz.hide(Quiz.responseInfo)}show(){Quiz.check(Instructor.control("responses")),Quiz.show(Quiz.responses),Quiz.show(Quiz.responseInfo),this.showVotesUponReview?(this.refreshVotes(),this.showVotesUponReview=!1):this.refresh(!1)}toggle(){this.showResponses=!this.showResponses,this.showResponses?this.show():this.hide()}endMerge(){$(".merge-into").removeClass("merge-into"),$(".merge-from").removeClass("merge-from")}undoMerge(){Ajax.post("undo_merge",{},(()=>this.refresh(!0)))}merge(from,into){Ajax.post("merge_responses",{from:from,into:into},(()=>this.refresh(!1)))}startMerge(fromRowBarId){const $barCell=$("#"+fromRowBarId);let $row=$barCell.parent();if($row.hasClass("merge-from"))this.endMerge();else{if($row.hasClass("merge-into")){const $fromRow=$(".merge-from");return this.merge($fromRow.data("response"),$row.data("response")),void this.endMerge()}$row.addClass("merge-from"),$row.parent().parent().find("tr").each((function(){$(this).find("td")[1].id!==$barCell.attr("id")&&$(this).addClass("merge-into")}))}}createControls(name){if(this.quiz.question.hasVotes){if("reviewing"===this.quiz.state){let $showNormalResult=$("#review_show_normal_results"),$showVoteResult=$("#review_show_vote_results");Quiz.show(Quiz.responseInfo),"vote_response"===name?0===$showNormalResult.length&&(setText(Quiz.responseInfo.html('

').children("h4"),"showing_vote_results"),Quiz.responseInfo.append('
'),setText($("#review_show_normal_results"),"click_to_show_original_results"),$showVoteResult.remove()):"current_response"===name&&0===$showVoteResult.length&&(setText(Quiz.responseInfo.html('

').children("h4"),"showing_original_results"),Quiz.responseInfo.append('
'),setText($("#review_show_vote_results"),"click_to_show_vote_results"),$showNormalResult.remove())}}else Quiz.hide(Quiz.responseInfo)}createBarGraph(responses,name,targetId,graphId,rebuild){let target=document.getElementById(targetId);if(null===target)return;let total=0,highestResponseCount=0;for(let i=0;ihighestResponseCount&&(highestResponseCount=count)}0===total&&(total=1),rebuild&&(target.innerHTML="");for(let i=0;i'+responses[i].count+"";let responseCell=row.insertCell(0);responseCell.onclick=function(){$(this).parent().toggleClass("selected-vote-option")};let barCell=row.insertCell(1);barCell.classList.add("bar"),barCell.id=name+"_bar_"+rowIndex,barCell.innerHTML='
'+countHtml+"
";const latexId=name+"_latex_"+rowIndex;responseCell.innerHTML='',Quiz.addMathjaxElement($("#"+latexId),responses[i].response),"stack"===responses[i].qtype&&Quiz.renderMaximaEquation(responses[i].response,latexId)}else{let currentRow=target.rows[currentRowIndex];currentRow.dataset.row_i=rowIndex,currentRow.dataset.response_i=i,currentRow.dataset.percent=percent,currentRow.dataset.count=responses[i].count;const containsOutside=currentRow.classList.contains("outside");percent>15&&containsOutside?currentRow.classList.remove("outside"):percent<15&&!containsOutside&¤tRow.classList.add("outside");let countElement=document.getElementById(name+"_count_"+rowIndex);null!==countElement&&(countElement.innerHTML=responses[i].count);let barElement=document.getElementById(name+"_bar_"+rowIndex);null!==barElement&&(barElement.firstElementChild.style.width=percent+"%")}}}static sortBarGraph(targetId){let target=document.getElementById(targetId);if(null===target)return;let isSorting=!0;for(;isSorting;){isSorting=!1;for(let i=0;i';Quiz.show($("#"+wrapperId).html(html))}this.createBarGraph(this.currentResponses,"current_response",tableId,graphId,rebuild),ResponseView.sortBarGraph(tableId)}}refresh(rebuild){Ajax.get("get_results",{},(data=>{this.quiz.question.hasVotes=data.has_votes,this.totalStudents=parseInt(data.total_students),this.set("jazzquiz_responses_container","current_responses_wrapper",data.responses,data.responded,data.question_type,"results",rebuild),data.merge_count>0?Quiz.show($("#jazzquiz_undo_merge")):Quiz.hide($("#jazzquiz_undo_merge"))}))}refreshVotes(){if(!this.showResponses&&"reviewing"!==this.quiz.state)return Quiz.hide(Quiz.responseInfo),void Quiz.hide(Quiz.responses);Ajax.get("get_vote_results",{},(data=>{const answers=data.answers,targetId="wrapper_vote_responses";let responses=[];this.respondedCount=0,this.totalStudents=parseInt(data.total_students);for(let i in answers)answers.hasOwnProperty(i)&&(responses.push({response:answers[i].attempt,count:answers[i].finalcount,qtype:answers[i].qtype,slot:answers[i].slot}),this.respondedCount+=parseInt(answers[i].finalcount));if(setText(Quiz.responded.find("h4"),"a_out_of_b_voted","jazzquiz",{a:this.respondedCount,b:this.totalStudents}),null===document.getElementById(targetId)){const html='
';Quiz.show(Quiz.responses.html(html))}this.createBarGraph(responses,"vote_response",targetId,"vote",!1),ResponseView.sortBarGraph(targetId)}))}}class Instructor{constructor(quiz){this.quiz=quiz,this.responses=new ResponseView(quiz),this.isShowingCorrectAnswer=!1,this.totalQuestions=0,this.allowVote=!1,$(document).on("keyup",(event=>{27===event.keyCode&&Instructor.closeFullscreenView()})),$(document).on("click",(event=>{Instructor.closeQuestionListMenu(event,"improvise"),Instructor.closeQuestionListMenu(event,"jump")})),Instructor.addEvents({repoll:()=>this.repollQuestion(),vote:()=>this.runVoting(),improvise:()=>this.showQuestionListSetup("improvise"),jump:()=>this.showQuestionListSetup("jump"),next:()=>this.nextQuestion(),random:()=>this.randomQuestion(),end:()=>this.endQuestion(),fullscreen:()=>Instructor.showFullscreenView(),answer:()=>this.showCorrectAnswer(),responses:()=>this.responses.toggle(),exit:()=>this.closeSession(),quit:()=>this.closeSession(),startquiz:()=>this.startQuiz()}),Instructor.addHotkeys({t:"responses",r:"repoll",a:"answer",e:"end",j:"jump",i:"improvise",v:"vote",n:"next",m:"random",f:"fullscreen"})}static addHotkeys(keys){for(let key in keys)keys.hasOwnProperty(key)&&(keys[key]={action:keys[key],repeat:!1},$(document).on("keydown",(event=>{if(keys[key].repeat||event.ctrlKey)return;if(String.fromCharCode(event.which).toLowerCase()!==key)return;let focusedTag=$(":focus").prop("tagName");if(void 0!==focusedTag&&(focusedTag=focusedTag.toLowerCase(),"input"===focusedTag||"textarea"===focusedTag))return;event.preventDefault(),keys[key].repeat=!0;let $control=Instructor.control(keys[key].action);$control.length&&!$control.prop("disabled")&&$control.click()})),$(document).on("keyup",(event=>{String.fromCharCode(event.which).toLowerCase()===key&&(keys[key].repeat=!1)})))}static addEvents(events){for(let key in events)events.hasOwnProperty(key)&&$(document).on("click","#jazzquiz_control_"+key,(()=>{Instructor.enableControls([]),events[key]()}))}static get controls(){return $("#jazzquiz_controls_box")}static get controlButtons(){return Instructor.controls.find(".quiz-control-buttons")}static control(key){return $("#jazzquiz_control_"+key)}static get side(){return $("#jazzquiz_side_container")}static get correctAnswer(){return $("#jazzquiz_correct_answer_container")}static get isMerging(){return 0!==$(".merge-from").length}onNotRunning(data){this.responses.totalStudents=data.student_count,Quiz.hide(Instructor.side),setText(Quiz.info,"instructions_for_instructor"),Instructor.enableControls([]),Quiz.hide(Instructor.controlButtons);let $studentsJoined=Instructor.control("startquiz").next();1===data.student_count?setText($studentsJoined,"one_student_has_joined"):data.student_count>1?setText($studentsJoined,"x_students_have_joined","jazzquiz",data.student_count):setText($studentsJoined,"no_students_have_joined"),Quiz.show(Instructor.control("startquiz").parent())}onPreparing(data){Quiz.hide(Instructor.side),setText(Quiz.info,"instructions_for_instructor");let enabledButtons=["improvise","jump","random","fullscreen","quit"];data.slot0&&data.delay<-data.questiontime&&this.endQuestion(),this.responses.refresh(!Instructor.isMerging);else{this.quiz.question.startCountdown(data.questiontime,data.delay)&&(this.quiz.question.isRunning=!0)}}onReviewing(data){Quiz.show(Instructor.side);let enabledButtons=["answer","repoll","fullscreen","improvise","jump","random","quit"];this.allowVote&&enabledButtons.push("vote"),data.slot$("#jazzquiz_controls").removeClass("btn-hide")))}endQuestion(){this.quiz.question.hideTimer(),Ajax.post("end_question",{},(()=>{"voting"===this.quiz.state?this.responses.showVotesUponReview=!0:(this.quiz.question.isRunning=!1,Instructor.enableControls([]))}))}showQuestionListSetup(name){let $controlButton=Instructor.control(name);$controlButton.hasClass("active")||Ajax.get("list_"+name+"_questions",{},(data=>{let self=this,$menu=$("#jazzquiz_"+name+"_menu");const menuMargin=$controlButton.offset().left-$controlButton.parent().offset().left;$menu.html("").addClass("active").css("margin-left",menuMargin+"px"),$controlButton.addClass("active");const questions=data.questions;for(let i in questions){if(!questions.hasOwnProperty(i))continue;let $questionButton=$('');Quiz.addMathjaxElement($questionButton,questions[i].name),$questionButton.data({time:questions[i].time,"question-id":questions[i].questionid,"jazzquiz-question-id":questions[i].jazzquizquestionid}),$questionButton.data("test",1),$questionButton.on("click",(function(){const questionId=$(this).data("question-id"),time=$(this).data("time"),jazzQuestionId=$(this).data("jazzquiz-question-id");self.jumpQuestion(questionId,time,jazzQuestionId),$menu.html("").removeClass("active"),$controlButton.removeClass("active")})),$menu.append($questionButton)}}))}static getSelectedAnswersForVote(){let result=[];return $(".selected-vote-option").each(((i,option)=>{result.push({text:option.dataset.response,count:option.dataset.count})})),result}runVoting(){const options=Instructor.getSelectedAnswersForVote(),data={questions:encodeURIComponent(JSON.stringify(options))};Ajax.post("run_voting",data,(()=>{}))}startQuestion(method,questionId,questionTime,jazzquizQuestionId){Quiz.hide(Quiz.info),this.responses.clear(),this.hideCorrectAnswer(),Ajax.post("start_question",{method:method,questionid:questionId,questiontime:questionTime,jazzquizquestionid:jazzquizQuestionId},(data=>this.quiz.question.startCountdown(data.questiontime,data.delay)))}jumpQuestion(questionId,questionTime,jazzquizQuestionId){this.startQuestion("jump",questionId,questionTime,jazzquizQuestionId)}repollQuestion(){this.startQuestion("repoll",0,0,0)}nextQuestion(){this.startQuestion("next",0,0,0)}randomQuestion(){this.startQuestion("random",0,0,0)}closeSession(){Quiz.hide($("#jazzquiz_undo_merge")),Quiz.hide(Question.box),Quiz.hide(Instructor.controls),setText(Quiz.info,"closing_session"),Ajax.post("close_session",{},(()=>window.location=location.href.split("&")[0]))}hideCorrectAnswer(){this.isShowingCorrectAnswer&&(Quiz.hide(Instructor.correctAnswer),Quiz.uncheck(Instructor.control("answer")),this.isShowingCorrectAnswer=!1)}showCorrectAnswer(){this.hideCorrectAnswer(),Ajax.get("get_right_response",{},(data=>{Quiz.show(Instructor.correctAnswer.html(data.right_answer)),Quiz.renderAllMathjax(),Quiz.check(Instructor.control("answer")),this.isShowingCorrectAnswer=!0}))}static enableControls(buttons){Instructor.controlButtons.children("button").each(((index,child)=>{const id=child.getAttribute("id").replace("jazzquiz_control_","");child.disabled=-1===buttons.indexOf(id)}))}static showFullscreenView(){Quiz.main.hasClass("jazzquiz-fullscreen")?Instructor.closeFullscreenView():(document.documentElement.style.overflowY="hidden",Quiz.main.addClass("jazzquiz-fullscreen"))}static closeFullscreenView(){document.documentElement.style.overflowY="auto",Quiz.main.removeClass("jazzquiz-fullscreen")}static closeQuestionListMenu(event,name){const menuId="#jazzquiz_"+name+"_menu";$(event.target).closest(menuId).length||($(menuId).html("").removeClass("active"),Instructor.control(name).removeClass("active"))}static addReportEventHandlers(){$(document).on("click","#report_overview_controls button",(function(){const action=$(this).data("action");"attendance"===action?($("#report_overview_responded").fadeIn(),$("#report_overview_responses").fadeOut()):"responses"===action&&($("#report_overview_responses").fadeIn(),$("#report_overview_responded").fadeOut())}))}}return{initialize:function(totalQuestions,reportView,slots){let quiz=new Quiz(Instructor);quiz.role.totalQuestions=totalQuestions,reportView?(Instructor.addReportEventHandlers(),quiz.role.responses.showResponses=!0,slots.forEach((slot=>{const wrapper="jazzquiz_wrapper_responses_"+slot.num,table="responses_wrapper_table_"+slot.num,graph="report_"+slot.num;quiz.role.responses.set(wrapper,table,slot.responses,void 0,slot.type,graph,!1)}))):quiz.poll(500)}}})); + +//# sourceMappingURL=instructor.min.js.map \ No newline at end of file diff --git a/amd/build/instructor.min.js.map b/amd/build/instructor.min.js.map index 3012fcb..697f263 100644 --- a/amd/build/instructor.min.js.map +++ b/amd/build/instructor.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/instructor.js"],"names":["define","$","Jazz","Quiz","Question","Ajax","setText","ResponseView","quiz","currentResponses","showVotesUponReview","respondedCount","showResponses","totalStudents","document","on","undoMerge","event","target","classList","contains","startMerge","id","parentNode","refresh","refreshVotes","responses","html","responseInfo","uncheck","Instructor","control","hide","check","show","removeClass","post","from","into","fromRowBarId","$barCell","$row","parent","hasClass","endMerge","$fromRow","merge","data","addClass","$table","find","each","$cells","attr","name","question","hasVotes","state","$showNormalResult","$showVoteResult","length","children","append","remove","targetId","graphId","rebuild","getElementById","total","highestResponseCount","i","count","parseInt","innerHTML","prune","rows","j","dataset","response","deleteRow","createControls","percent","rowIndex","currentRowIndex","row_i","row","insertRow","response_i","add","countHtml","responseCell","insertCell","onclick","toggleClass","barCell","latexId","addMathjaxElement","qtype","renderMaximaEquation","currentRow","containsOutside","countElement","barElement","firstElementChild","style","width","wrapperId","tableId","responded","questionType","a","b","trim","replace","exists","push","createBarGraph","sortBarGraph","get","has_votes","total_students","set","question_type","merge_count","answers","hasOwnProperty","attempt","finalcount","slot","isSorting","current","next","insertBefore","isShowingCorrectAnswer","totalQuestions","allowVote","keyCode","closeFullscreenView","closeQuestionListMenu","addEvents","repollQuestion","runVoting","showQuestionListSetup","nextQuestion","randomQuestion","endQuestion","showFullscreenView","showCorrectAnswer","toggle","closeSession","startQuiz","addHotkeys","student_count","side","info","enableControls","controlButtons","$studentsJoined","enabledButtons","questionTime","questiontime","isRunning","delay","isMerging","started","startCountdown","isLoaded","isNewState","correctAnswer","clear","css","voteable","timeLeft","timer","hideTimer","$controlButton","$menu","menuMargin","offset","left","questions","$questionButton","time","questionid","jazzquizquestionid","questionId","jazzQuestionId","jumpQuestion","options","getSelectedAnswersForVote","encodeURIComponent","JSON","stringify","method","jazzquizQuestionId","hideCorrectAnswer","startQuestion","box","controls","window","location","href","split","right_answer","renderAllMathjax","keys","key","action","repeat","ctrlKey","String","fromCharCode","which","toLowerCase","focusedTag","prop","preventDefault","$control","click","events","result","option","text","buttons","index","child","getAttribute","disabled","indexOf","main","documentElement","overflowY","menuId","menu","closest","fadeIn","fadeOut","initialize","reportView","slots","role","addReportEventHandlers","forEach","wrapper","num","table","graph","type","poll"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * @package mod_jazzquiz\n * @author Sebastian S. Gundersen \n * @copyright 2014 University of Wisconsin - Madison\n * @copyright 2018 NTNU\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(['jquery', 'mod_jazzquiz/core'], function ($, Jazz) {\n\n const Quiz = Jazz.Quiz;\n const Question = Jazz.Question;\n const Ajax = Jazz.Ajax;\n const setText = Jazz.setText;\n\n class ResponseView {\n\n /**\n * @param {Quiz} quiz\n */\n constructor(quiz) {\n this.quiz = quiz;\n this.currentResponses = [];\n this.showVotesUponReview = false;\n this.respondedCount = 0;\n this.showResponses = false;\n this.totalStudents = 0;\n $(document).on('click', '#jazzquiz_undo_merge', () => this.undoMerge());\n $(document).on('click', event => {\n // Clicking a row to merge.\n if (event.target.classList.contains('bar')) {\n this.startMerge(event.target.id);\n } else if (event.target.parentNode && event.target.parentNode.classList.contains('bar')) {\n this.startMerge(event.target.parentNode.id);\n }\n });\n $(document).on('click', '#review_show_normal_results', () => this.refresh(false));\n $(document).on('click', '#review_show_vote_results', () => this.refreshVotes());\n }\n\n /**\n * Clear, but not hide responses.\n */\n clear() {\n Quiz.responses.html('');\n Quiz.responseInfo.html('');\n }\n\n /**\n * Hides the responses\n */\n hide() {\n Quiz.uncheck(Instructor.control('responses'));\n Quiz.hide(Quiz.responses);\n Quiz.hide(Quiz.responseInfo);\n }\n\n /**\n * Shows the responses\n */\n show() {\n Quiz.check(Instructor.control('responses'));\n Quiz.show(Quiz.responses);\n Quiz.show(Quiz.responseInfo);\n if (this.showVotesUponReview) {\n this.refreshVotes();\n this.showVotesUponReview = false;\n } else {\n this.refresh(false);\n }\n }\n\n /**\n * Toggle whether to show or hide the responses\n */\n toggle() {\n this.showResponses = !this.showResponses;\n if (this.showResponses) {\n this.show();\n } else {\n this.hide();\n }\n }\n\n /**\n * End the response merge.\n */\n endMerge() {\n $('.merge-into').removeClass('merge-into');\n $('.merge-from').removeClass('merge-from');\n }\n\n /**\n * Undo the last response merge.\n */\n undoMerge() {\n Ajax.post('undo_merge', {}, () => this.refresh(true));\n }\n\n /**\n * Merges responses based on response string.\n * @param {string} from\n * @param {string} into\n */\n merge(from, into) {\n Ajax.post('merge_responses', {from: from, into: into}, () => this.refresh(false));\n }\n\n /**\n * Start a merge between two responses.\n * @param {string} fromRowBarId\n */\n startMerge(fromRowBarId) {\n const $barCell = $('#' + fromRowBarId);\n let $row = $barCell.parent();\n if ($row.hasClass('merge-from')) {\n this.endMerge();\n return;\n }\n if ($row.hasClass('merge-into')) {\n const $fromRow = $('.merge-from');\n this.merge($fromRow.data('response'), $row.data('response'));\n this.endMerge();\n return;\n }\n $row.addClass('merge-from');\n let $table = $row.parent().parent();\n $table.find('tr').each(function () {\n const $cells = $(this).find('td');\n if ($cells[1].id !== $barCell.attr('id')) {\n $(this).addClass('merge-into');\n }\n });\n }\n\n /**\n * Create controls to toggle between the responses of the actual question and the vote that followed.\n * @param {string} name Can be either 'vote_response' or 'current_response'\n */\n createControls(name) {\n if (!this.quiz.question.hasVotes) {\n Quiz.hide(Quiz.responseInfo);\n return;\n }\n // Add button for instructor to change what to review.\n if (this.quiz.state === 'reviewing') {\n let $showNormalResult = $('#review_show_normal_results');\n let $showVoteResult = $('#review_show_vote_results');\n Quiz.show(Quiz.responseInfo);\n if (name === 'vote_response') {\n if ($showNormalResult.length === 0) {\n setText(Quiz.responseInfo.html('

').children('h4'), 'showing_vote_results');\n Quiz.responseInfo.append('
');\n setText($('#review_show_normal_results'), 'click_to_show_original_results');\n $showVoteResult.remove();\n }\n } else if (name === 'current_response') {\n if ($showVoteResult.length === 0) {\n setText(Quiz.responseInfo.html('

').children('h4'), 'showing_original_results');\n Quiz.responseInfo.append('
');\n setText($('#review_show_vote_results'), 'click_to_show_vote_results');\n $showNormalResult.remove();\n }\n }\n }\n }\n\n /**\n * Create a new and unsorted response bar graph.\n * @param {Array.} responses\n * @param {string} name\n * @param {string} targetId\n * @param {string} graphId\n * @param {boolean} rebuild If the table should be completely rebuilt or not\n */\n createBarGraph(responses, name, targetId, graphId, rebuild) {\n let target = document.getElementById(targetId);\n if (target === null) {\n return;\n }\n let total = 0;\n let highestResponseCount = 0;\n for (let i = 0; i < responses.length; i++) {\n let count = parseInt(responses[i].count); // In case count is a string.\n total += count;\n if (count > highestResponseCount) {\n highestResponseCount = count;\n }\n\n }\n if (total === 0) {\n total = 1;\n }\n\n // Remove the rows if it should be rebuilt.\n if (rebuild) {\n target.innerHTML = '';\n }\n\n // Prune rows.\n for (let i = 0; i < target.rows.length; i++) {\n let prune = true;\n for (let j = 0; j < responses.length; j++) {\n if (target.rows[i].dataset.response === responses[j].response) {\n prune = false;\n break;\n }\n }\n if (prune) {\n target.deleteRow(i);\n i--;\n }\n }\n\n this.createControls(name);\n\n name += graphId;\n\n // Add rows.\n for (let i = 0; i < responses.length; i++) {\n //const percent = (parseInt(responses[i].count) / total) * 100;\n const percent = (parseInt(responses[i].count) / highestResponseCount) * 100;\n\n // Check if row with same response already exists.\n let rowIndex = -1;\n let currentRowIndex = -1;\n for (let j = 0; j < target.rows.length; j++) {\n if (target.rows[j].dataset.response === responses[i].response) {\n rowIndex = target.rows[j].dataset.row_i;\n currentRowIndex = j;\n break;\n }\n }\n\n if (rowIndex === -1) {\n rowIndex = target.rows.length;\n let row = target.insertRow();\n row.dataset.response_i = i;\n row.dataset.response = responses[i].response;\n row.dataset.percent = percent;\n row.dataset.row_i = rowIndex;\n row.dataset.count = responses[i].count;\n row.classList.add('selected-vote-option');\n if (percent < 15) {\n row.classList.add('outside');\n }\n\n const countHtml = '' + responses[i].count + '';\n let responseCell = row.insertCell(0);\n responseCell.onclick = function () {\n $(this).parent().toggleClass('selected-vote-option');\n };\n\n let barCell = row.insertCell(1);\n barCell.classList.add('bar');\n barCell.id = name + '_bar_' + rowIndex;\n barCell.innerHTML = '
' + countHtml + '
';\n\n const latexId = name + '_latex_' + rowIndex;\n responseCell.innerHTML = '';\n Quiz.addMathjaxElement($('#' + latexId), responses[i].response);\n if (responses[i].qtype === 'stack') {\n Quiz.renderMaximaEquation(responses[i].response, latexId);\n }\n } else {\n let currentRow = target.rows[currentRowIndex];\n currentRow.dataset.row_i = rowIndex;\n currentRow.dataset.response_i = i;\n currentRow.dataset.percent = percent;\n currentRow.dataset.count = responses[i].count;\n const containsOutside = currentRow.classList.contains('outside');\n if (percent > 15 && containsOutside) {\n currentRow.classList.remove('outside');\n } else if (percent < 15 && !containsOutside) {\n currentRow.classList.add('outside');\n }\n let countElement = document.getElementById(name + '_count_' + rowIndex);\n if (countElement !== null) {\n countElement.innerHTML = responses[i].count;\n }\n let barElement = document.getElementById(name + '_bar_' + rowIndex);\n if (barElement !== null) {\n barElement.firstElementChild.style.width = percent + '%';\n }\n }\n }\n };\n\n /**\n * Sort the responses in the graph by how many had the same response.\n * @param {string} targetId\n */\n static sortBarGraph(targetId) {\n let target = document.getElementById(targetId);\n if (target === null) {\n return;\n }\n let isSorting = true;\n while (isSorting) {\n isSorting = false;\n for (let i = 0; i < (target.rows.length - 1); i++) {\n const current = parseInt(target.rows[i].dataset.percent);\n const next = parseInt(target.rows[i + 1].dataset.percent);\n if (current < next) {\n target.rows[i].parentNode.insertBefore(target.rows[i + 1], target.rows[i]);\n isSorting = true;\n break;\n }\n }\n }\n }\n\n /**\n * Create and sort a bar graph based on the responses passed.\n * @param {string} wrapperId\n * @param {string} tableId\n * @param {Array.} responses\n * @param {number|undefined} responded How many students responded to the question\n * @param {string} questionType\n * @param {string} graphId\n * @param {boolean} rebuild If the graph should be rebuilt or not.\n */\n set(wrapperId, tableId, responses, responded, questionType, graphId, rebuild) {\n if (responses === undefined) {\n return;\n }\n\n // Check if any responses to show.\n if (responses.length === 0) {\n Quiz.show(Quiz.responded);\n setText(Quiz.responded.find('h4'), 'a_out_of_b_responded', 'jazzquiz', {\n a: 0,\n b: this.totalStudents\n });\n return;\n }\n\n // Question type specific.\n switch (questionType) {\n case 'shortanswer':\n for (let i = 0; i < responses.length; i++) {\n responses[i].response = responses[i].response.trim();\n }\n break;\n case 'stack':\n // Remove all spaces from responses.\n for (let i = 0; i < responses.length; i++) {\n responses[i].response = responses[i].response.replace(/\\s/g, '');\n }\n break;\n default:\n break;\n }\n\n // Update data.\n this.currentResponses = [];\n this.respondedCount = 0;\n for (let i = 0; i < responses.length; i++) {\n let exists = false;\n let count = 1;\n if (responses[i].count !== undefined) {\n count = parseInt(responses[i].count);\n }\n this.respondedCount += count;\n // Check if response is a duplicate.\n for (let j = 0; j < this.currentResponses.length; j++) {\n if (this.currentResponses[j].response === responses[i].response) {\n this.currentResponses[j].count += count;\n exists = true;\n break;\n }\n }\n // Add element if not a duplicate.\n if (!exists) {\n this.currentResponses.push({\n response: responses[i].response,\n count: count,\n qtype: questionType\n });\n }\n }\n\n // Update responded container.\n if (Quiz.responded.length !== 0 && responded !== undefined) {\n Quiz.show(Quiz.responded);\n setText(Quiz.responded.find('h4'), 'a_out_of_b_responded', 'jazzquiz', {\n a: responded,\n b: this.totalStudents\n });\n }\n\n // Should we show the responses?\n if (!this.showResponses && this.quiz.state !== 'reviewing') {\n Quiz.hide(Quiz.responseInfo);\n Quiz.hide(Quiz.responses);\n return;\n }\n\n if (document.getElementById(tableId) === null) {\n const html = '
';\n Quiz.show($('#' + wrapperId).html(html));\n }\n this.createBarGraph(this.currentResponses, 'current_response', tableId, graphId, rebuild);\n ResponseView.sortBarGraph(tableId);\n }\n\n /**\n * Fetch and show results for the ongoing or previous question.\n * @param {boolean} rebuild If the response graph should be rebuilt or not.\n */\n refresh(rebuild) {\n Ajax.get('get_results', {}, data => {\n this.quiz.question.hasVotes = data.has_votes;\n this.totalStudents = parseInt(data.total_students);\n\n this.set('jazzquiz_responses_container', 'current_responses_wrapper',\n data.responses, data.responded, data.question_type, 'results', rebuild);\n\n if (data.merge_count > 0) {\n Quiz.show($('#jazzquiz_undo_merge'));\n } else {\n Quiz.hide($('#jazzquiz_undo_merge'));\n }\n });\n }\n\n /**\n * refresh() equivalent for votes.\n */\n refreshVotes() {\n // Should we show the results?\n if (!this.showResponses && this.quiz.state !== 'reviewing') {\n Quiz.hide(Quiz.responseInfo);\n Quiz.hide(Quiz.responses);\n return;\n }\n Ajax.get('get_vote_results', {}, data => {\n const answers = data.answers;\n const targetId = 'wrapper_vote_responses';\n let responses = [];\n\n this.respondedCount = 0;\n this.totalStudents = parseInt(data.total_students);\n\n for (let i in answers) {\n if (!answers.hasOwnProperty(i)) {\n continue;\n }\n responses.push({\n response: answers[i].attempt,\n count: answers[i].finalcount,\n qtype: answers[i].qtype,\n slot: answers[i].slot\n });\n this.respondedCount += parseInt(answers[i].finalcount);\n }\n\n setText(Quiz.responded.find('h4'), 'a_out_of_b_voted', 'jazzquiz', {\n a: this.respondedCount,\n b: this.totalStudents\n });\n\n if (document.getElementById(targetId) === null) {\n const html = '
';\n Quiz.show(Quiz.responses.html(html));\n }\n\n this.createBarGraph(responses, 'vote_response', targetId, 'vote', false);\n ResponseView.sortBarGraph(targetId);\n });\n }\n\n }\n\n class Instructor {\n\n /**\n * @param {Quiz} quiz\n */\n constructor(quiz) {\n this.quiz = quiz;\n this.responses = new ResponseView(quiz);\n this.isShowingCorrectAnswer = false;\n this.totalQuestions = 0;\n this.allowVote = false;\n\n $(document).on('keyup', event => {\n if (event.keyCode === 27) { // Escape key.\n Instructor.closeFullscreenView();\n }\n });\n\n $(document).on('click', event => {\n Instructor.closeQuestionListMenu(event, 'improvise');\n Instructor.closeQuestionListMenu(event, 'jump');\n });\n\n Instructor.addEvents({\n 'repoll': () => this.repollQuestion(),\n 'vote': () => this.runVoting(),\n 'improvise': () => this.showQuestionListSetup('improvise'),\n 'jump': () => this.showQuestionListSetup('jump'),\n 'next': () => this.nextQuestion(),\n 'random': () => this.randomQuestion(),\n 'end': () => this.endQuestion(),\n 'fullscreen': () => Instructor.showFullscreenView(),\n 'answer': () => this.showCorrectAnswer(),\n 'responses': () => this.responses.toggle(),\n 'exit': () => this.closeSession(),\n 'quit': () => this.closeSession(),\n 'startquiz': () => this.startQuiz()\n });\n\n Instructor.addHotkeys({\n 't': 'responses',\n 'r': 'repoll',\n 'a': 'answer',\n 'e': 'end',\n 'j': 'jump',\n 'i': 'improvise',\n 'v': 'vote',\n 'n': 'next',\n 'm': 'random',\n 'f': 'fullscreen'\n });\n }\n\n static addHotkeys(keys) {\n for (let key in keys) {\n if (keys.hasOwnProperty(key)) {\n keys[key] = {\n action: keys[key],\n repeat: false // TODO: Maybe event.repeat becomes more standard?\n };\n $(document).on('keydown', event => {\n if (keys[key].repeat || event.ctrlKey) {\n return;\n }\n if (String.fromCharCode(event.which).toLowerCase() !== key) {\n return;\n }\n let focusedTag = $(':focus').prop('tagName');\n if (focusedTag !== undefined) {\n focusedTag = focusedTag.toLowerCase();\n if (focusedTag === 'input' || focusedTag === 'textarea') {\n return;\n }\n }\n event.preventDefault();\n keys[key].repeat = true;\n let $control = Instructor.control(keys[key].action);\n if ($control.length && !$control.prop('disabled')) {\n $control.click();\n }\n });\n $(document).on('keyup', event => {\n if (String.fromCharCode(event.which).toLowerCase() === key) {\n keys[key].repeat = false;\n }\n });\n }\n }\n }\n\n static addEvents(events) {\n for (let key in events) {\n if (events.hasOwnProperty(key)) {\n $(document).on('click', '#jazzquiz_control_' + key, () => {\n Instructor.enableControls([]);\n events[key]();\n });\n }\n }\n }\n\n static get controls() {\n return $('#jazzquiz_controls_box');\n }\n\n static get controlButtons() {\n return Instructor.controls.find('.quiz-control-buttons');\n }\n\n static control(key) {\n return $('#jazzquiz_control_' + key);\n }\n\n static get side() {\n return $('#jazzquiz_side_container');\n }\n\n static get correctAnswer() {\n return $('#jazzquiz_correct_answer_container');\n }\n\n static get isMerging() {\n return $('.merge-from').length !== 0;\n }\n\n onNotRunning(data) {\n this.responses.totalStudents = data.student_count;\n Quiz.hide(Instructor.side);\n setText(Quiz.info, 'instructions_for_instructor');\n Instructor.enableControls([]);\n Quiz.hide(Instructor.controlButtons);\n let $studentsJoined = Instructor.control('startquiz').next();\n if (data.student_count === 1) {\n setText($studentsJoined, 'one_student_has_joined');\n } else if (data.student_count > 1) {\n setText($studentsJoined, 'x_students_have_joined', 'jazzquiz', data.student_count);\n } else {\n setText($studentsJoined, 'no_students_have_joined');\n }\n Quiz.show(Instructor.control('startquiz').parent());\n }\n\n onPreparing(data) {\n Quiz.hide(Instructor.side);\n setText(Quiz.info, 'instructions_for_instructor');\n let enabledButtons = ['improvise', 'jump', 'random', 'fullscreen', 'quit'];\n if (data.slot < this.totalQuestions) {\n enabledButtons.push('next');\n }\n Instructor.enableControls(enabledButtons);\n }\n\n onRunning(data) {\n if (!this.responses.showResponses) {\n this.responses.hide();\n }\n Quiz.show(Instructor.side);\n Instructor.enableControls(['end', 'responses', 'fullscreen']);\n this.quiz.question.questionTime = data.questiontime;\n if (this.quiz.question.isRunning) {\n // Check if the question has already ended.\n // We need to do this because the state does not update unless an instructor is connected.\n if (data.questionTime > 0 && data.delay < -data.questiontime) {\n this.endQuestion();\n }\n // Only rebuild results if we are not merging.\n this.responses.refresh(!Instructor.isMerging);\n } else {\n const started = this.quiz.question.startCountdown(data.questiontime, data.delay);\n if (started) {\n this.quiz.question.isRunning = true;\n }\n }\n }\n\n onReviewing(data) {\n Quiz.show(Instructor.side);\n let enabledButtons = ['answer', 'repoll', 'fullscreen', 'improvise', 'jump', 'random', 'quit'];\n if (this.allowVote) {\n enabledButtons.push('vote');\n }\n if (data.slot < this.totalQuestions) {\n enabledButtons.push('next');\n }\n Instructor.enableControls(enabledButtons);\n\n // In case page was refreshed, we should ensure the question is showing.\n if (!Question.isLoaded()) {\n this.quiz.question.refresh();\n }\n\n // For now, just always show responses while reviewing.\n // In the future, there should be an additional toggle.\n if (this.quiz.isNewState) {\n this.responses.show();\n }\n // No longer in question.\n this.quiz.question.isRunning = false;\n }\n\n onSessionClosed(data) {\n Quiz.hide(Instructor.side);\n Quiz.hide(Instructor.correctAnswer);\n Instructor.enableControls([]);\n this.responses.clear();\n this.quiz.question.isRunning = false;\n }\n\n onVoting(data) {\n if (!this.responses.showResponses) {\n this.responses.hide();\n }\n Quiz.show(Instructor.side);\n Instructor.enableControls(['quit', 'fullscreen', 'answer', 'responses', 'end']);\n this.responses.refreshVotes();\n }\n\n onStateChange(state) {\n $('#region-main').find('ul.nav.nav-tabs').css('display', 'none');\n $('#region-main-settings-menu').css('display', 'none');\n $('.region_main_settings_menu_proxy').css('display', 'none');\n Quiz.show(Instructor.controlButtons);\n Quiz.hide(Instructor.control('startquiz').parent());\n }\n\n onQuestionRefreshed(data) {\n this.allowVote = data.voteable;\n }\n\n onTimerEnding() {\n this.endQuestion();\n }\n\n onTimerTick(timeLeft) {\n setText(Question.timer, 'x_seconds_left', 'jazzquiz', timeLeft);\n }\n\n /**\n * Start the quiz. Does not start any questions.\n */\n startQuiz() {\n Quiz.hide(Instructor.control('startquiz').parent());\n Ajax.post('start_quiz', {}, () => $('#jazzquiz_controls').removeClass('btn-hide'));\n }\n\n /**\n * End the currently ongoing question or vote.\n */\n endQuestion() {\n this.quiz.question.hideTimer();\n Ajax.post('end_question', {}, () => {\n if (this.quiz.state === 'voting') {\n this.responses.showVotesUponReview = true;\n } else {\n this.quiz.question.isRunning = false;\n Instructor.enableControls([]);\n }\n });\n }\n\n /**\n * Show a question list dropdown.\n * @param {string} name\n */\n showQuestionListSetup(name) {\n let $controlButton = Instructor.control(name);\n if ($controlButton.hasClass('active')) {\n // It's already open. Let's not send another request.\n return;\n }\n Ajax.get('list_' + name + '_questions', {}, data => {\n let self = this;\n let $menu = $('#jazzquiz_' + name + '_menu');\n const menuMargin = $controlButton.offset().left - $controlButton.parent().offset().left;\n $menu.html('').addClass('active').css('margin-left', menuMargin + 'px');\n $controlButton.addClass('active');\n const questions = data.questions;\n for (let i in questions) {\n if (!questions.hasOwnProperty(i)) {\n continue;\n }\n let $questionButton = $('');\n Quiz.addMathjaxElement($questionButton, questions[i].name);\n $questionButton.data({\n 'time': questions[i].time,\n 'question-id': questions[i].questionid,\n 'jazzquiz-question-id': questions[i].jazzquizquestionid\n });\n $questionButton.data('test', 1);\n $questionButton.on('click', function () {\n const questionId = $(this).data('question-id');\n const time = $(this).data('time');\n const jazzQuestionId = $(this).data('jazzquiz-question-id');\n self.jumpQuestion(questionId, time, jazzQuestionId);\n $menu.html('').removeClass('active');\n $controlButton.removeClass('active');\n });\n $menu.append($questionButton);\n }\n });\n }\n\n /**\n * Get the selected responses.\n * @returns {Array.} Vote options\n */\n static getSelectedAnswersForVote() {\n let result = [];\n $('.selected-vote-option').each((i, option) => {\n result.push({\n text: option.dataset.response,\n count: option.dataset.count\n });\n });\n return result;\n }\n\n /**\n * Start a vote with the responses that are currently selected.\n */\n runVoting() {\n const options = Instructor.getSelectedAnswersForVote();\n const data = {questions: encodeURIComponent(JSON.stringify(options))};\n Ajax.post('run_voting', data, () => {});\n }\n\n /**\n * Start a new question in this session.\n * @param {string} method\n * @param {number} questionId\n * @param {number} questionTime\n * @param {number} jazzquizQuestionId\n */\n startQuestion(method, questionId, questionTime, jazzquizQuestionId) {\n Quiz.hide(Quiz.info);\n this.responses.clear();\n this.hideCorrectAnswer();\n Ajax.post('start_question', {\n method: method,\n questionid: questionId,\n questiontime: questionTime,\n jazzquizquestionid: jazzquizQuestionId\n }, data => this.quiz.question.startCountdown(data.questiontime, data.delay));\n }\n\n /**\n * Jump to a planned question in the quiz.\n * @param {number} questionId\n * @param {number} questionTime\n * @param {number} jazzquizQuestionId\n */\n jumpQuestion(questionId, questionTime, jazzquizQuestionId) {\n this.startQuestion('jump', questionId, questionTime, jazzquizQuestionId);\n }\n\n /**\n * Repoll the previously asked question.\n */\n repollQuestion() {\n this.startQuestion('repoll', 0, 0, 0);\n }\n\n /**\n * Continue on to the next preplanned question.\n */\n nextQuestion() {\n this.startQuestion('next', 0, 0, 0);\n }\n\n /**\n * Start a random question.\n */\n randomQuestion() {\n this.startQuestion('random', 0, 0, 0);\n }\n\n /**\n * Close the current session.\n */\n closeSession() {\n Quiz.hide($('#jazzquiz_undo_merge'));\n Quiz.hide(Question.box);\n Quiz.hide(Instructor.controls);\n setText(Quiz.info, 'closing_session');\n Ajax.post('close_session', {}, () => window.location = location.href.split('&')[0]);\n }\n\n /**\n * Hide the correct answer if showing.\n */\n hideCorrectAnswer() {\n if (this.isShowingCorrectAnswer) {\n Quiz.hide(Instructor.correctAnswer);\n Quiz.uncheck(Instructor.control('answer'));\n this.isShowingCorrectAnswer = false;\n }\n }\n\n /**\n * Request and show the correct answer for the ongoing or previous question.\n */\n showCorrectAnswer() {\n this.hideCorrectAnswer();\n Ajax.get('get_right_response', {}, data => {\n Quiz.show(Instructor.correctAnswer.html(data.right_answer));\n Quiz.renderAllMathjax();\n Quiz.check(Instructor.control('answer'));\n this.isShowingCorrectAnswer = true;\n });\n }\n\n /**\n * Enables all buttons passed in arguments, but disables all others.\n * @param {Array.} buttons The unique part of the IDs of the buttons to be enabled.\n */\n static enableControls(buttons) {\n Instructor.controlButtons.children('button').each((index, child) => {\n const id = child.getAttribute('id').replace('jazzquiz_control_', '');\n child.disabled = (buttons.indexOf(id) === -1);\n });\n }\n\n /**\n * Enter fullscreen mode for better use with projectors.\n */\n static showFullscreenView() {\n if (Quiz.main.hasClass('jazzquiz-fullscreen')) {\n Instructor.closeFullscreenView();\n return;\n }\n // Hide the scrollbar - remember to always set back to auto when closing.\n document.documentElement.style.overflowY = 'hidden';\n // Sets the quiz view to an absolute position that covers the viewport.\n Quiz.main.addClass('jazzquiz-fullscreen');\n }\n\n /**\n * Exit the fullscreen mode.\n */\n static closeFullscreenView() {\n document.documentElement.style.overflowY = 'auto';\n Quiz.main.removeClass('jazzquiz-fullscreen');\n }\n\n /**\n * Close the dropdown menu for choosing a question.\n * @param {Event} event\n * @param {string} name\n */\n static closeQuestionListMenu(event, name) {\n const menuId = '#jazzquiz_' + name + '_menu';\n // Close the menu if the click was not inside.\n const menu = $(event.target).closest(menuId);\n if (!menu.length) {\n $(menuId).html('').removeClass('active');\n Instructor.control(name).removeClass('active');\n }\n }\n\n static addReportEventHandlers() {\n $(document).on('click', '#report_overview_controls button', function () {\n const action = $(this).data('action');\n if (action === 'attendance') {\n $('#report_overview_responded').fadeIn();\n $('#report_overview_responses').fadeOut();\n } else if (action === 'responses') {\n $('#report_overview_responses').fadeIn();\n $('#report_overview_responded').fadeOut();\n }\n });\n }\n\n }\n\n return {\n initialize: function (totalQuestions, reportView, slots) {\n let quiz = new Quiz(Instructor);\n quiz.role.totalQuestions = totalQuestions;\n if (reportView) {\n Instructor.addReportEventHandlers();\n quiz.role.responses.showResponses = true;\n slots.forEach(slot => {\n const wrapper = 'jazzquiz_wrapper_responses_' + slot.num;\n const table = 'responses_wrapper_table_' + slot.num;\n const graph = 'report_' + slot.num;\n quiz.role.responses.set(wrapper, table, slot.responses, undefined, slot.type, graph, false);\n });\n } else {\n quiz.poll(500);\n }\n }\n }\n\n});\n"],"file":"instructor.min.js"} \ No newline at end of file +{"version":3,"file":"instructor.min.js","sources":["../src/instructor.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * @package mod_jazzquiz\n * @author Sebastian S. Gundersen \n * @copyright 2014 University of Wisconsin - Madison\n * @copyright 2018 NTNU\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(['jquery', 'mod_jazzquiz/core'], function ($, Jazz) {\n\n const Quiz = Jazz.Quiz;\n const Question = Jazz.Question;\n const Ajax = Jazz.Ajax;\n const setText = Jazz.setText;\n\n class ResponseView {\n\n /**\n * @param {Quiz} quiz\n */\n constructor(quiz) {\n this.quiz = quiz;\n this.currentResponses = [];\n this.showVotesUponReview = false;\n this.respondedCount = 0;\n this.showResponses = false;\n this.totalStudents = 0;\n $(document).on('click', '#jazzquiz_undo_merge', () => this.undoMerge());\n $(document).on('click', event => {\n // Clicking a row to merge.\n if (event.target.classList.contains('bar')) {\n this.startMerge(event.target.id);\n } else if (event.target.parentNode && event.target.parentNode.classList.contains('bar')) {\n this.startMerge(event.target.parentNode.id);\n }\n });\n $(document).on('click', '#review_show_normal_results', () => this.refresh(false));\n $(document).on('click', '#review_show_vote_results', () => this.refreshVotes());\n }\n\n /**\n * Clear, but not hide responses.\n */\n clear() {\n Quiz.responses.html('');\n Quiz.responseInfo.html('');\n }\n\n /**\n * Hides the responses\n */\n hide() {\n Quiz.uncheck(Instructor.control('responses'));\n Quiz.hide(Quiz.responses);\n Quiz.hide(Quiz.responseInfo);\n }\n\n /**\n * Shows the responses\n */\n show() {\n Quiz.check(Instructor.control('responses'));\n Quiz.show(Quiz.responses);\n Quiz.show(Quiz.responseInfo);\n if (this.showVotesUponReview) {\n this.refreshVotes();\n this.showVotesUponReview = false;\n } else {\n this.refresh(false);\n }\n }\n\n /**\n * Toggle whether to show or hide the responses\n */\n toggle() {\n this.showResponses = !this.showResponses;\n if (this.showResponses) {\n this.show();\n } else {\n this.hide();\n }\n }\n\n /**\n * End the response merge.\n */\n endMerge() {\n $('.merge-into').removeClass('merge-into');\n $('.merge-from').removeClass('merge-from');\n }\n\n /**\n * Undo the last response merge.\n */\n undoMerge() {\n Ajax.post('undo_merge', {}, () => this.refresh(true));\n }\n\n /**\n * Merges responses based on response string.\n * @param {string} from\n * @param {string} into\n */\n merge(from, into) {\n Ajax.post('merge_responses', {from: from, into: into}, () => this.refresh(false));\n }\n\n /**\n * Start a merge between two responses.\n * @param {string} fromRowBarId\n */\n startMerge(fromRowBarId) {\n const $barCell = $('#' + fromRowBarId);\n let $row = $barCell.parent();\n if ($row.hasClass('merge-from')) {\n this.endMerge();\n return;\n }\n if ($row.hasClass('merge-into')) {\n const $fromRow = $('.merge-from');\n this.merge($fromRow.data('response'), $row.data('response'));\n this.endMerge();\n return;\n }\n $row.addClass('merge-from');\n let $table = $row.parent().parent();\n $table.find('tr').each(function () {\n const $cells = $(this).find('td');\n if ($cells[1].id !== $barCell.attr('id')) {\n $(this).addClass('merge-into');\n }\n });\n }\n\n /**\n * Create controls to toggle between the responses of the actual question and the vote that followed.\n * @param {string} name Can be either 'vote_response' or 'current_response'\n */\n createControls(name) {\n if (!this.quiz.question.hasVotes) {\n Quiz.hide(Quiz.responseInfo);\n return;\n }\n // Add button for instructor to change what to review.\n if (this.quiz.state === 'reviewing') {\n let $showNormalResult = $('#review_show_normal_results');\n let $showVoteResult = $('#review_show_vote_results');\n Quiz.show(Quiz.responseInfo);\n if (name === 'vote_response') {\n if ($showNormalResult.length === 0) {\n setText(Quiz.responseInfo.html('

').children('h4'), 'showing_vote_results');\n Quiz.responseInfo.append('
');\n setText($('#review_show_normal_results'), 'click_to_show_original_results');\n $showVoteResult.remove();\n }\n } else if (name === 'current_response') {\n if ($showVoteResult.length === 0) {\n setText(Quiz.responseInfo.html('

').children('h4'), 'showing_original_results');\n Quiz.responseInfo.append('
');\n setText($('#review_show_vote_results'), 'click_to_show_vote_results');\n $showNormalResult.remove();\n }\n }\n }\n }\n\n /**\n * Create a new and unsorted response bar graph.\n * @param {Array.} responses\n * @param {string} name\n * @param {string} targetId\n * @param {string} graphId\n * @param {boolean} rebuild If the table should be completely rebuilt or not\n */\n createBarGraph(responses, name, targetId, graphId, rebuild) {\n let target = document.getElementById(targetId);\n if (target === null) {\n return;\n }\n let total = 0;\n let highestResponseCount = 0;\n for (let i = 0; i < responses.length; i++) {\n let count = parseInt(responses[i].count); // In case count is a string.\n total += count;\n if (count > highestResponseCount) {\n highestResponseCount = count;\n }\n\n }\n if (total === 0) {\n total = 1;\n }\n\n // Remove the rows if it should be rebuilt.\n if (rebuild) {\n target.innerHTML = '';\n }\n\n // Prune rows.\n for (let i = 0; i < target.rows.length; i++) {\n let prune = true;\n for (let j = 0; j < responses.length; j++) {\n if (target.rows[i].dataset.response === responses[j].response) {\n prune = false;\n break;\n }\n }\n if (prune) {\n target.deleteRow(i);\n i--;\n }\n }\n\n this.createControls(name);\n\n name += graphId;\n\n // Add rows.\n for (let i = 0; i < responses.length; i++) {\n //const percent = (parseInt(responses[i].count) / total) * 100;\n const percent = (parseInt(responses[i].count) / highestResponseCount) * 100;\n\n // Check if row with same response already exists.\n let rowIndex = -1;\n let currentRowIndex = -1;\n for (let j = 0; j < target.rows.length; j++) {\n if (target.rows[j].dataset.response === responses[i].response) {\n rowIndex = target.rows[j].dataset.row_i;\n currentRowIndex = j;\n break;\n }\n }\n\n if (rowIndex === -1) {\n rowIndex = target.rows.length;\n let row = target.insertRow();\n row.dataset.response_i = i;\n row.dataset.response = responses[i].response;\n row.dataset.percent = percent;\n row.dataset.row_i = rowIndex;\n row.dataset.count = responses[i].count;\n row.classList.add('selected-vote-option');\n if (percent < 15) {\n row.classList.add('outside');\n }\n\n const countHtml = '' + responses[i].count + '';\n let responseCell = row.insertCell(0);\n responseCell.onclick = function () {\n $(this).parent().toggleClass('selected-vote-option');\n };\n\n let barCell = row.insertCell(1);\n barCell.classList.add('bar');\n barCell.id = name + '_bar_' + rowIndex;\n barCell.innerHTML = '
' + countHtml + '
';\n\n const latexId = name + '_latex_' + rowIndex;\n responseCell.innerHTML = '';\n Quiz.addMathjaxElement($('#' + latexId), responses[i].response);\n if (responses[i].qtype === 'stack') {\n Quiz.renderMaximaEquation(responses[i].response, latexId);\n }\n } else {\n let currentRow = target.rows[currentRowIndex];\n currentRow.dataset.row_i = rowIndex;\n currentRow.dataset.response_i = i;\n currentRow.dataset.percent = percent;\n currentRow.dataset.count = responses[i].count;\n const containsOutside = currentRow.classList.contains('outside');\n if (percent > 15 && containsOutside) {\n currentRow.classList.remove('outside');\n } else if (percent < 15 && !containsOutside) {\n currentRow.classList.add('outside');\n }\n let countElement = document.getElementById(name + '_count_' + rowIndex);\n if (countElement !== null) {\n countElement.innerHTML = responses[i].count;\n }\n let barElement = document.getElementById(name + '_bar_' + rowIndex);\n if (barElement !== null) {\n barElement.firstElementChild.style.width = percent + '%';\n }\n }\n }\n };\n\n /**\n * Sort the responses in the graph by how many had the same response.\n * @param {string} targetId\n */\n static sortBarGraph(targetId) {\n let target = document.getElementById(targetId);\n if (target === null) {\n return;\n }\n let isSorting = true;\n while (isSorting) {\n isSorting = false;\n for (let i = 0; i < (target.rows.length - 1); i++) {\n const current = parseInt(target.rows[i].dataset.percent);\n const next = parseInt(target.rows[i + 1].dataset.percent);\n if (current < next) {\n target.rows[i].parentNode.insertBefore(target.rows[i + 1], target.rows[i]);\n isSorting = true;\n break;\n }\n }\n }\n }\n\n /**\n * Create and sort a bar graph based on the responses passed.\n * @param {string} wrapperId\n * @param {string} tableId\n * @param {Array.} responses\n * @param {number|undefined} responded How many students responded to the question\n * @param {string} questionType\n * @param {string} graphId\n * @param {boolean} rebuild If the graph should be rebuilt or not.\n */\n set(wrapperId, tableId, responses, responded, questionType, graphId, rebuild) {\n if (responses === undefined) {\n return;\n }\n\n // Check if any responses to show.\n if (responses.length === 0) {\n Quiz.show(Quiz.responded);\n setText(Quiz.responded.find('h4'), 'a_out_of_b_responded', 'jazzquiz', {\n a: 0,\n b: this.totalStudents\n });\n return;\n }\n\n // Question type specific.\n switch (questionType) {\n case 'shortanswer':\n for (let i = 0; i < responses.length; i++) {\n responses[i].response = responses[i].response.trim();\n }\n break;\n case 'stack':\n // Remove all spaces from responses.\n for (let i = 0; i < responses.length; i++) {\n responses[i].response = responses[i].response.replace(/\\s/g, '');\n }\n break;\n default:\n break;\n }\n\n // Update data.\n this.currentResponses = [];\n this.respondedCount = 0;\n for (let i = 0; i < responses.length; i++) {\n let exists = false;\n let count = 1;\n if (responses[i].count !== undefined) {\n count = parseInt(responses[i].count);\n }\n this.respondedCount += count;\n // Check if response is a duplicate.\n for (let j = 0; j < this.currentResponses.length; j++) {\n if (this.currentResponses[j].response === responses[i].response) {\n this.currentResponses[j].count += count;\n exists = true;\n break;\n }\n }\n // Add element if not a duplicate.\n if (!exists) {\n this.currentResponses.push({\n response: responses[i].response,\n count: count,\n qtype: questionType\n });\n }\n }\n\n // Update responded container.\n if (Quiz.responded.length !== 0 && responded !== undefined) {\n Quiz.show(Quiz.responded);\n setText(Quiz.responded.find('h4'), 'a_out_of_b_responded', 'jazzquiz', {\n a: responded,\n b: this.totalStudents\n });\n }\n\n // Should we show the responses?\n if (!this.showResponses && this.quiz.state !== 'reviewing') {\n Quiz.hide(Quiz.responseInfo);\n Quiz.hide(Quiz.responses);\n return;\n }\n\n if (document.getElementById(tableId) === null) {\n const html = '
';\n Quiz.show($('#' + wrapperId).html(html));\n }\n this.createBarGraph(this.currentResponses, 'current_response', tableId, graphId, rebuild);\n ResponseView.sortBarGraph(tableId);\n }\n\n /**\n * Fetch and show results for the ongoing or previous question.\n * @param {boolean} rebuild If the response graph should be rebuilt or not.\n */\n refresh(rebuild) {\n Ajax.get('get_results', {}, data => {\n this.quiz.question.hasVotes = data.has_votes;\n this.totalStudents = parseInt(data.total_students);\n\n this.set('jazzquiz_responses_container', 'current_responses_wrapper',\n data.responses, data.responded, data.question_type, 'results', rebuild);\n\n if (data.merge_count > 0) {\n Quiz.show($('#jazzquiz_undo_merge'));\n } else {\n Quiz.hide($('#jazzquiz_undo_merge'));\n }\n });\n }\n\n /**\n * refresh() equivalent for votes.\n */\n refreshVotes() {\n // Should we show the results?\n if (!this.showResponses && this.quiz.state !== 'reviewing') {\n Quiz.hide(Quiz.responseInfo);\n Quiz.hide(Quiz.responses);\n return;\n }\n Ajax.get('get_vote_results', {}, data => {\n const answers = data.answers;\n const targetId = 'wrapper_vote_responses';\n let responses = [];\n\n this.respondedCount = 0;\n this.totalStudents = parseInt(data.total_students);\n\n for (let i in answers) {\n if (!answers.hasOwnProperty(i)) {\n continue;\n }\n responses.push({\n response: answers[i].attempt,\n count: answers[i].finalcount,\n qtype: answers[i].qtype,\n slot: answers[i].slot\n });\n this.respondedCount += parseInt(answers[i].finalcount);\n }\n\n setText(Quiz.responded.find('h4'), 'a_out_of_b_voted', 'jazzquiz', {\n a: this.respondedCount,\n b: this.totalStudents\n });\n\n if (document.getElementById(targetId) === null) {\n const html = '
';\n Quiz.show(Quiz.responses.html(html));\n }\n\n this.createBarGraph(responses, 'vote_response', targetId, 'vote', false);\n ResponseView.sortBarGraph(targetId);\n });\n }\n\n }\n\n class Instructor {\n\n /**\n * @param {Quiz} quiz\n */\n constructor(quiz) {\n this.quiz = quiz;\n this.responses = new ResponseView(quiz);\n this.isShowingCorrectAnswer = false;\n this.totalQuestions = 0;\n this.allowVote = false;\n\n $(document).on('keyup', event => {\n if (event.keyCode === 27) { // Escape key.\n Instructor.closeFullscreenView();\n }\n });\n\n $(document).on('click', event => {\n Instructor.closeQuestionListMenu(event, 'improvise');\n Instructor.closeQuestionListMenu(event, 'jump');\n });\n\n Instructor.addEvents({\n 'repoll': () => this.repollQuestion(),\n 'vote': () => this.runVoting(),\n 'improvise': () => this.showQuestionListSetup('improvise'),\n 'jump': () => this.showQuestionListSetup('jump'),\n 'next': () => this.nextQuestion(),\n 'random': () => this.randomQuestion(),\n 'end': () => this.endQuestion(),\n 'fullscreen': () => Instructor.showFullscreenView(),\n 'answer': () => this.showCorrectAnswer(),\n 'responses': () => this.responses.toggle(),\n 'exit': () => this.closeSession(),\n 'quit': () => this.closeSession(),\n 'startquiz': () => this.startQuiz()\n });\n\n Instructor.addHotkeys({\n 't': 'responses',\n 'r': 'repoll',\n 'a': 'answer',\n 'e': 'end',\n 'j': 'jump',\n 'i': 'improvise',\n 'v': 'vote',\n 'n': 'next',\n 'm': 'random',\n 'f': 'fullscreen'\n });\n }\n\n static addHotkeys(keys) {\n for (let key in keys) {\n if (keys.hasOwnProperty(key)) {\n keys[key] = {\n action: keys[key],\n repeat: false // TODO: Maybe event.repeat becomes more standard?\n };\n $(document).on('keydown', event => {\n if (keys[key].repeat || event.ctrlKey) {\n return;\n }\n if (String.fromCharCode(event.which).toLowerCase() !== key) {\n return;\n }\n let focusedTag = $(':focus').prop('tagName');\n if (focusedTag !== undefined) {\n focusedTag = focusedTag.toLowerCase();\n if (focusedTag === 'input' || focusedTag === 'textarea') {\n return;\n }\n }\n event.preventDefault();\n keys[key].repeat = true;\n let $control = Instructor.control(keys[key].action);\n if ($control.length && !$control.prop('disabled')) {\n $control.click();\n }\n });\n $(document).on('keyup', event => {\n if (String.fromCharCode(event.which).toLowerCase() === key) {\n keys[key].repeat = false;\n }\n });\n }\n }\n }\n\n static addEvents(events) {\n for (let key in events) {\n if (events.hasOwnProperty(key)) {\n $(document).on('click', '#jazzquiz_control_' + key, () => {\n Instructor.enableControls([]);\n events[key]();\n });\n }\n }\n }\n\n static get controls() {\n return $('#jazzquiz_controls_box');\n }\n\n static get controlButtons() {\n return Instructor.controls.find('.quiz-control-buttons');\n }\n\n static control(key) {\n return $('#jazzquiz_control_' + key);\n }\n\n static get side() {\n return $('#jazzquiz_side_container');\n }\n\n static get correctAnswer() {\n return $('#jazzquiz_correct_answer_container');\n }\n\n static get isMerging() {\n return $('.merge-from').length !== 0;\n }\n\n onNotRunning(data) {\n this.responses.totalStudents = data.student_count;\n Quiz.hide(Instructor.side);\n setText(Quiz.info, 'instructions_for_instructor');\n Instructor.enableControls([]);\n Quiz.hide(Instructor.controlButtons);\n let $studentsJoined = Instructor.control('startquiz').next();\n if (data.student_count === 1) {\n setText($studentsJoined, 'one_student_has_joined');\n } else if (data.student_count > 1) {\n setText($studentsJoined, 'x_students_have_joined', 'jazzquiz', data.student_count);\n } else {\n setText($studentsJoined, 'no_students_have_joined');\n }\n Quiz.show(Instructor.control('startquiz').parent());\n }\n\n onPreparing(data) {\n Quiz.hide(Instructor.side);\n setText(Quiz.info, 'instructions_for_instructor');\n let enabledButtons = ['improvise', 'jump', 'random', 'fullscreen', 'quit'];\n if (data.slot < this.totalQuestions) {\n enabledButtons.push('next');\n }\n Instructor.enableControls(enabledButtons);\n }\n\n onRunning(data) {\n if (!this.responses.showResponses) {\n this.responses.hide();\n }\n Quiz.show(Instructor.side);\n Instructor.enableControls(['end', 'responses', 'fullscreen']);\n this.quiz.question.questionTime = data.questiontime;\n if (this.quiz.question.isRunning) {\n // Check if the question has already ended.\n // We need to do this because the state does not update unless an instructor is connected.\n if (data.questionTime > 0 && data.delay < -data.questiontime) {\n this.endQuestion();\n }\n // Only rebuild results if we are not merging.\n this.responses.refresh(!Instructor.isMerging);\n } else {\n const started = this.quiz.question.startCountdown(data.questiontime, data.delay);\n if (started) {\n this.quiz.question.isRunning = true;\n }\n }\n }\n\n onReviewing(data) {\n Quiz.show(Instructor.side);\n let enabledButtons = ['answer', 'repoll', 'fullscreen', 'improvise', 'jump', 'random', 'quit'];\n if (this.allowVote) {\n enabledButtons.push('vote');\n }\n if (data.slot < this.totalQuestions) {\n enabledButtons.push('next');\n }\n Instructor.enableControls(enabledButtons);\n\n // In case page was refreshed, we should ensure the question is showing.\n if (!Question.isLoaded()) {\n this.quiz.question.refresh();\n }\n\n // For now, just always show responses while reviewing.\n // In the future, there should be an additional toggle.\n if (this.quiz.isNewState) {\n this.responses.show();\n }\n // No longer in question.\n this.quiz.question.isRunning = false;\n }\n\n onSessionClosed(data) {\n Quiz.hide(Instructor.side);\n Quiz.hide(Instructor.correctAnswer);\n Instructor.enableControls([]);\n this.responses.clear();\n this.quiz.question.isRunning = false;\n }\n\n onVoting(data) {\n if (!this.responses.showResponses) {\n this.responses.hide();\n }\n Quiz.show(Instructor.side);\n Instructor.enableControls(['quit', 'fullscreen', 'answer', 'responses', 'end']);\n this.responses.refreshVotes();\n }\n\n onStateChange(state) {\n $('#region-main').find('ul.nav.nav-tabs').css('display', 'none');\n $('#region-main-settings-menu').css('display', 'none');\n $('.region_main_settings_menu_proxy').css('display', 'none');\n Quiz.show(Instructor.controlButtons);\n Quiz.hide(Instructor.control('startquiz').parent());\n }\n\n onQuestionRefreshed(data) {\n this.allowVote = data.voteable;\n }\n\n onTimerEnding() {\n this.endQuestion();\n }\n\n onTimerTick(timeLeft) {\n setText(Question.timer, 'x_seconds_left', 'jazzquiz', timeLeft);\n }\n\n /**\n * Start the quiz. Does not start any questions.\n */\n startQuiz() {\n Quiz.hide(Instructor.control('startquiz').parent());\n Ajax.post('start_quiz', {}, () => $('#jazzquiz_controls').removeClass('btn-hide'));\n }\n\n /**\n * End the currently ongoing question or vote.\n */\n endQuestion() {\n this.quiz.question.hideTimer();\n Ajax.post('end_question', {}, () => {\n if (this.quiz.state === 'voting') {\n this.responses.showVotesUponReview = true;\n } else {\n this.quiz.question.isRunning = false;\n Instructor.enableControls([]);\n }\n });\n }\n\n /**\n * Show a question list dropdown.\n * @param {string} name\n */\n showQuestionListSetup(name) {\n let $controlButton = Instructor.control(name);\n if ($controlButton.hasClass('active')) {\n // It's already open. Let's not send another request.\n return;\n }\n Ajax.get('list_' + name + '_questions', {}, data => {\n let self = this;\n let $menu = $('#jazzquiz_' + name + '_menu');\n const menuMargin = $controlButton.offset().left - $controlButton.parent().offset().left;\n $menu.html('').addClass('active').css('margin-left', menuMargin + 'px');\n $controlButton.addClass('active');\n const questions = data.questions;\n for (let i in questions) {\n if (!questions.hasOwnProperty(i)) {\n continue;\n }\n let $questionButton = $('');\n Quiz.addMathjaxElement($questionButton, questions[i].name);\n $questionButton.data({\n 'time': questions[i].time,\n 'question-id': questions[i].questionid,\n 'jazzquiz-question-id': questions[i].jazzquizquestionid\n });\n $questionButton.data('test', 1);\n $questionButton.on('click', function () {\n const questionId = $(this).data('question-id');\n const time = $(this).data('time');\n const jazzQuestionId = $(this).data('jazzquiz-question-id');\n self.jumpQuestion(questionId, time, jazzQuestionId);\n $menu.html('').removeClass('active');\n $controlButton.removeClass('active');\n });\n $menu.append($questionButton);\n }\n });\n }\n\n /**\n * Get the selected responses.\n * @returns {Array.} Vote options\n */\n static getSelectedAnswersForVote() {\n let result = [];\n $('.selected-vote-option').each((i, option) => {\n result.push({\n text: option.dataset.response,\n count: option.dataset.count\n });\n });\n return result;\n }\n\n /**\n * Start a vote with the responses that are currently selected.\n */\n runVoting() {\n const options = Instructor.getSelectedAnswersForVote();\n const data = {questions: encodeURIComponent(JSON.stringify(options))};\n Ajax.post('run_voting', data, () => {});\n }\n\n /**\n * Start a new question in this session.\n * @param {string} method\n * @param {number} questionId\n * @param {number} questionTime\n * @param {number} jazzquizQuestionId\n */\n startQuestion(method, questionId, questionTime, jazzquizQuestionId) {\n Quiz.hide(Quiz.info);\n this.responses.clear();\n this.hideCorrectAnswer();\n Ajax.post('start_question', {\n method: method,\n questionid: questionId,\n questiontime: questionTime,\n jazzquizquestionid: jazzquizQuestionId\n }, data => this.quiz.question.startCountdown(data.questiontime, data.delay));\n }\n\n /**\n * Jump to a planned question in the quiz.\n * @param {number} questionId\n * @param {number} questionTime\n * @param {number} jazzquizQuestionId\n */\n jumpQuestion(questionId, questionTime, jazzquizQuestionId) {\n this.startQuestion('jump', questionId, questionTime, jazzquizQuestionId);\n }\n\n /**\n * Repoll the previously asked question.\n */\n repollQuestion() {\n this.startQuestion('repoll', 0, 0, 0);\n }\n\n /**\n * Continue on to the next preplanned question.\n */\n nextQuestion() {\n this.startQuestion('next', 0, 0, 0);\n }\n\n /**\n * Start a random question.\n */\n randomQuestion() {\n this.startQuestion('random', 0, 0, 0);\n }\n\n /**\n * Close the current session.\n */\n closeSession() {\n Quiz.hide($('#jazzquiz_undo_merge'));\n Quiz.hide(Question.box);\n Quiz.hide(Instructor.controls);\n setText(Quiz.info, 'closing_session');\n Ajax.post('close_session', {}, () => window.location = location.href.split('&')[0]);\n }\n\n /**\n * Hide the correct answer if showing.\n */\n hideCorrectAnswer() {\n if (this.isShowingCorrectAnswer) {\n Quiz.hide(Instructor.correctAnswer);\n Quiz.uncheck(Instructor.control('answer'));\n this.isShowingCorrectAnswer = false;\n }\n }\n\n /**\n * Request and show the correct answer for the ongoing or previous question.\n */\n showCorrectAnswer() {\n this.hideCorrectAnswer();\n Ajax.get('get_right_response', {}, data => {\n Quiz.show(Instructor.correctAnswer.html(data.right_answer));\n Quiz.renderAllMathjax();\n Quiz.check(Instructor.control('answer'));\n this.isShowingCorrectAnswer = true;\n });\n }\n\n /**\n * Enables all buttons passed in arguments, but disables all others.\n * @param {Array.} buttons The unique part of the IDs of the buttons to be enabled.\n */\n static enableControls(buttons) {\n Instructor.controlButtons.children('button').each((index, child) => {\n const id = child.getAttribute('id').replace('jazzquiz_control_', '');\n child.disabled = (buttons.indexOf(id) === -1);\n });\n }\n\n /**\n * Enter fullscreen mode for better use with projectors.\n */\n static showFullscreenView() {\n if (Quiz.main.hasClass('jazzquiz-fullscreen')) {\n Instructor.closeFullscreenView();\n return;\n }\n // Hide the scrollbar - remember to always set back to auto when closing.\n document.documentElement.style.overflowY = 'hidden';\n // Sets the quiz view to an absolute position that covers the viewport.\n Quiz.main.addClass('jazzquiz-fullscreen');\n }\n\n /**\n * Exit the fullscreen mode.\n */\n static closeFullscreenView() {\n document.documentElement.style.overflowY = 'auto';\n Quiz.main.removeClass('jazzquiz-fullscreen');\n }\n\n /**\n * Close the dropdown menu for choosing a question.\n * @param {Event} event\n * @param {string} name\n */\n static closeQuestionListMenu(event, name) {\n const menuId = '#jazzquiz_' + name + '_menu';\n // Close the menu if the click was not inside.\n const menu = $(event.target).closest(menuId);\n if (!menu.length) {\n $(menuId).html('').removeClass('active');\n Instructor.control(name).removeClass('active');\n }\n }\n\n static addReportEventHandlers() {\n $(document).on('click', '#report_overview_controls button', function () {\n const action = $(this).data('action');\n if (action === 'attendance') {\n $('#report_overview_responded').fadeIn();\n $('#report_overview_responses').fadeOut();\n } else if (action === 'responses') {\n $('#report_overview_responses').fadeIn();\n $('#report_overview_responded').fadeOut();\n }\n });\n }\n\n }\n\n return {\n initialize: function (totalQuestions, reportView, slots) {\n let quiz = new Quiz(Instructor);\n quiz.role.totalQuestions = totalQuestions;\n if (reportView) {\n Instructor.addReportEventHandlers();\n quiz.role.responses.showResponses = true;\n slots.forEach(slot => {\n const wrapper = 'jazzquiz_wrapper_responses_' + slot.num;\n const table = 'responses_wrapper_table_' + slot.num;\n const graph = 'report_' + slot.num;\n quiz.role.responses.set(wrapper, table, slot.responses, undefined, slot.type, graph, false);\n });\n } else {\n quiz.poll(500);\n }\n }\n }\n\n});\n"],"names":["define","$","Jazz","Quiz","Question","Ajax","setText","ResponseView","constructor","quiz","currentResponses","showVotesUponReview","respondedCount","showResponses","totalStudents","document","on","this","undoMerge","event","target","classList","contains","startMerge","id","parentNode","refresh","refreshVotes","clear","responses","html","responseInfo","hide","uncheck","Instructor","control","show","check","toggle","endMerge","removeClass","post","merge","from","into","fromRowBarId","$barCell","$row","parent","hasClass","$fromRow","data","addClass","find","each","attr","createControls","name","question","hasVotes","state","$showNormalResult","$showVoteResult","length","children","append","remove","createBarGraph","targetId","graphId","rebuild","getElementById","total","highestResponseCount","i","count","parseInt","innerHTML","rows","prune","j","dataset","response","deleteRow","percent","rowIndex","currentRowIndex","row_i","row","insertRow","response_i","add","countHtml","responseCell","insertCell","onclick","toggleClass","barCell","latexId","addMathjaxElement","qtype","renderMaximaEquation","currentRow","containsOutside","countElement","barElement","firstElementChild","style","width","isSorting","insertBefore","set","wrapperId","tableId","responded","questionType","undefined","a","b","trim","replace","exists","push","sortBarGraph","get","has_votes","total_students","question_type","merge_count","answers","hasOwnProperty","attempt","finalcount","slot","isShowingCorrectAnswer","totalQuestions","allowVote","keyCode","closeFullscreenView","closeQuestionListMenu","addEvents","repollQuestion","runVoting","showQuestionListSetup","nextQuestion","randomQuestion","endQuestion","showFullscreenView","showCorrectAnswer","closeSession","startQuiz","addHotkeys","keys","key","action","repeat","ctrlKey","String","fromCharCode","which","toLowerCase","focusedTag","prop","preventDefault","$control","click","events","enableControls","controls","controlButtons","side","correctAnswer","isMerging","onNotRunning","student_count","info","$studentsJoined","next","onPreparing","enabledButtons","onRunning","questionTime","questiontime","isRunning","delay","startCountdown","onReviewing","isLoaded","isNewState","onSessionClosed","onVoting","onStateChange","css","onQuestionRefreshed","voteable","onTimerEnding","onTimerTick","timeLeft","timer","hideTimer","$controlButton","self","$menu","menuMargin","offset","left","questions","$questionButton","time","questionid","jazzquizquestionid","questionId","jazzQuestionId","jumpQuestion","result","option","text","options","getSelectedAnswersForVote","encodeURIComponent","JSON","stringify","startQuestion","method","jazzquizQuestionId","hideCorrectAnswer","box","window","location","href","split","right_answer","renderAllMathjax","buttons","index","child","getAttribute","disabled","indexOf","main","documentElement","overflowY","menuId","closest","fadeIn","fadeOut","initialize","reportView","slots","role","addReportEventHandlers","forEach","wrapper","num","table","graph","type","poll"],"mappings":"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"} \ No newline at end of file diff --git a/amd/build/student.min.js b/amd/build/student.min.js index f2493b8..7333d64 100644 --- a/amd/build/student.min.js +++ b/amd/build/student.min.js @@ -1,2 +1,10 @@ -function _classCallCheck(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function _defineProperties(a,b){for(var c=0,d;c + * @copyright 2014 University of Wisconsin - Madison + * @copyright 2018 NTNU + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define("mod_jazzquiz/student",["jquery","mod_jazzquiz/core"],(function($,Jazz){const Quiz=Jazz.Quiz,Question=Jazz.Question,Ajax=Jazz.Ajax,setText=Jazz.setText;class Student{constructor(quiz){this.quiz=quiz,this.voteAnswer=void 0;let self=this;$(document).on("submit","#jazzquiz_question_form",(function(event){event.preventDefault(),self.submitAnswer()})).on("click","#jazzquiz_save_vote",(function(){self.saveVote()})).on("click",".jazzquiz-select-vote",(function(){self.voteAnswer=this.value}))}onNotRunning(data){setText(Quiz.info,"instructions_for_student")}onPreparing(data){setText(Quiz.info,"wait_for_instructor")}onRunning(data){if(this.quiz.question.isRunning)return;this.quiz.question.startCountdown(data.questiontime,data.delay)||setText(Quiz.info,"wait_for_instructor")}onReviewing(data){this.quiz.question.isVoteRunning=!1,this.quiz.question.isRunning=!1,this.quiz.question.hideTimer(),Quiz.hide(Question.box),setText(Quiz.info,"wait_for_instructor")}onSessionClosed(data){window.location=location.href.split("&")[0]}onVoting(data){if(this.quiz.question.isVoteRunning)return;Quiz.info.html(data.html),Quiz.show(Quiz.info);const options=data.options;for(let i=0;i{data.feedback.length>0?Quiz.show(Quiz.info.html(data.feedback)):setText(Quiz.info,"wait_for_instructor"),this.quiz.question.isSaving=!1,this.quiz.question.isRunning&&(this.quiz.question.isVoteRunning||(Quiz.hide(Question.box),this.quiz.question.hideTimer()))})).fail((()=>{this.quiz.question.isSaving=!1}))}saveVote(){Ajax.post("save_vote",{vote:this.voteAnswer},(data=>{"success"===data.status?setText(Quiz.info,"wait_for_instructor"):setText(Quiz.info,"you_already_voted")}))}}return{initialize:()=>{new Quiz(Student).poll(2e3)}}})); + +//# sourceMappingURL=student.min.js.map \ No newline at end of file diff --git a/amd/build/student.min.js.map b/amd/build/student.min.js.map index 5f1ce01..8ce49a8 100644 --- a/amd/build/student.min.js.map +++ b/amd/build/student.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/student.js"],"names":["define","$","Jazz","Quiz","Question","Ajax","setText","Student","quiz","voteAnswer","self","document","on","event","preventDefault","submitAnswer","saveVote","value","info","data","question","isRunning","started","startCountdown","questiontime","delay","isVoteRunning","hideTimer","hide","box","window","location","href","split","html","show","options","i","length","addMathjaxElement","content_id","text","question_type","renderMaximaEquation","timeLeft","timer","isSaving","tinyMCE","triggerSave","serialized","form","serializeArray","name","hasOwnProperty","post","feedback","fail","vote","status","initialize","poll"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * @package mod_jazzquiz\n * @author Sebastian S. Gundersen \n * @copyright 2014 University of Wisconsin - Madison\n * @copyright 2018 NTNU\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(['jquery', 'mod_jazzquiz/core'], function ($, Jazz) {\n\n const Quiz = Jazz.Quiz;\n const Question = Jazz.Question;\n const Ajax = Jazz.Ajax;\n const setText = Jazz.setText;\n\n class Student {\n\n /**\n * @param {Quiz} quiz\n */\n constructor(quiz) {\n this.quiz = quiz;\n this.voteAnswer = undefined;\n let self = this;\n $(document).on('submit', '#jazzquiz_question_form', function(event) {\n event.preventDefault();\n self.submitAnswer();\n }).on('click', '#jazzquiz_save_vote', function() {\n self.saveVote();\n }).on('click', '.jazzquiz-select-vote', function() {\n self.voteAnswer = this.value;\n });\n }\n\n onNotRunning(data) {\n setText(Quiz.info, 'instructions_for_student');\n }\n\n onPreparing(data) {\n setText(Quiz.info, 'wait_for_instructor');\n }\n\n onRunning(data) {\n if (this.quiz.question.isRunning) {\n return;\n }\n const started = this.quiz.question.startCountdown(data.questiontime, data.delay);\n if (!started) {\n setText(Quiz.info, 'wait_for_instructor');\n }\n }\n\n onReviewing(data) {\n this.quiz.question.isVoteRunning = false;\n this.quiz.question.isRunning = false;\n this.quiz.question.hideTimer();\n Quiz.hide(Question.box);\n setText(Quiz.info, 'wait_for_instructor');\n }\n\n onSessionClosed(data) {\n window.location = location.href.split('&')[0];\n }\n\n onVoting(data) {\n if (this.quiz.question.isVoteRunning) {\n return;\n }\n Quiz.info.html(data.html);\n Quiz.show(Quiz.info);\n const options = data.options;\n for (let i = 0; i < options.length; i++) {\n Quiz.addMathjaxElement($('#' + options[i].content_id), options[i].text);\n if (options[i].question_type === 'stack') {\n Quiz.renderMaximaEquation(options[i].text, options[i].content_id);\n }\n }\n this.quiz.question.isVoteRunning = true;\n }\n\n onStateChange(state) {\n\n }\n\n onQuestionTimerEnding() {\n\n }\n\n onTimerTick(timeLeft) {\n setText(Question.timer, 'question_will_end_in_x_seconds', 'jazzquiz', timeLeft);\n }\n\n onQuestionRefreshed(data) {\n\n }\n\n /**\n * Submit answer for the current question.\n */\n submitAnswer() {\n if (this.quiz.question.isSaving) {\n // Don't save twice.\n return;\n }\n this.quiz.question.isSaving = true;\n if (typeof tinyMCE !== 'undefined') {\n tinyMCE.triggerSave();\n }\n const serialized = Question.form.serializeArray();\n let data = {};\n for (let name in serialized) {\n if (serialized.hasOwnProperty(name)) {\n data[serialized[name].name] = serialized[name].value;\n }\n }\n Ajax.post('save_question', data, data => {\n if (data.feedback.length > 0) {\n Quiz.show(Quiz.info.html(data.feedback));\n } else {\n setText(Quiz.info, 'wait_for_instructor');\n }\n this.quiz.question.isSaving = false;\n if (!this.quiz.question.isRunning) {\n return;\n }\n if (this.quiz.question.isVoteRunning) {\n return;\n }\n Quiz.hide(Question.box);\n this.quiz.question.hideTimer();\n }).fail(() => {\n this.quiz.question.isSaving = false;\n });\n }\n\n saveVote() {\n Ajax.post('save_vote', {vote: this.voteAnswer}, data => {\n if (data.status === 'success') {\n setText(Quiz.info, 'wait_for_instructor');\n } else {\n setText(Quiz.info, 'you_already_voted');\n }\n });\n }\n\n }\n\n return {\n initialize: () => {\n let quiz = new Quiz(Student);\n quiz.poll(2000);\n }\n }\n\n});\n"],"file":"student.min.js"} \ No newline at end of file +{"version":3,"file":"student.min.js","sources":["../src/student.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * @package mod_jazzquiz\n * @author Sebastian S. Gundersen \n * @copyright 2014 University of Wisconsin - Madison\n * @copyright 2018 NTNU\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(['jquery', 'mod_jazzquiz/core'], function ($, Jazz) {\n\n const Quiz = Jazz.Quiz;\n const Question = Jazz.Question;\n const Ajax = Jazz.Ajax;\n const setText = Jazz.setText;\n\n class Student {\n\n /**\n * @param {Quiz} quiz\n */\n constructor(quiz) {\n this.quiz = quiz;\n this.voteAnswer = undefined;\n let self = this;\n $(document).on('submit', '#jazzquiz_question_form', function(event) {\n event.preventDefault();\n self.submitAnswer();\n }).on('click', '#jazzquiz_save_vote', function() {\n self.saveVote();\n }).on('click', '.jazzquiz-select-vote', function() {\n self.voteAnswer = this.value;\n });\n }\n\n onNotRunning(data) {\n setText(Quiz.info, 'instructions_for_student');\n }\n\n onPreparing(data) {\n setText(Quiz.info, 'wait_for_instructor');\n }\n\n onRunning(data) {\n if (this.quiz.question.isRunning) {\n return;\n }\n const started = this.quiz.question.startCountdown(data.questiontime, data.delay);\n if (!started) {\n setText(Quiz.info, 'wait_for_instructor');\n }\n }\n\n onReviewing(data) {\n this.quiz.question.isVoteRunning = false;\n this.quiz.question.isRunning = false;\n this.quiz.question.hideTimer();\n Quiz.hide(Question.box);\n setText(Quiz.info, 'wait_for_instructor');\n }\n\n onSessionClosed(data) {\n window.location = location.href.split('&')[0];\n }\n\n onVoting(data) {\n if (this.quiz.question.isVoteRunning) {\n return;\n }\n Quiz.info.html(data.html);\n Quiz.show(Quiz.info);\n const options = data.options;\n for (let i = 0; i < options.length; i++) {\n Quiz.addMathjaxElement($('#' + options[i].content_id), options[i].text);\n if (options[i].question_type === 'stack') {\n Quiz.renderMaximaEquation(options[i].text, options[i].content_id);\n }\n }\n this.quiz.question.isVoteRunning = true;\n }\n\n onStateChange(state) {\n\n }\n\n onQuestionTimerEnding() {\n\n }\n\n onTimerTick(timeLeft) {\n setText(Question.timer, 'question_will_end_in_x_seconds', 'jazzquiz', timeLeft);\n }\n\n onQuestionRefreshed(data) {\n\n }\n\n /**\n * Submit answer for the current question.\n */\n submitAnswer() {\n if (this.quiz.question.isSaving) {\n // Don't save twice.\n return;\n }\n this.quiz.question.isSaving = true;\n if (typeof tinyMCE !== 'undefined') {\n tinyMCE.triggerSave();\n }\n const serialized = Question.form.serializeArray();\n let data = {};\n for (let name in serialized) {\n if (serialized.hasOwnProperty(name)) {\n data[serialized[name].name] = serialized[name].value;\n }\n }\n Ajax.post('save_question', data, data => {\n if (data.feedback.length > 0) {\n Quiz.show(Quiz.info.html(data.feedback));\n } else {\n setText(Quiz.info, 'wait_for_instructor');\n }\n this.quiz.question.isSaving = false;\n if (!this.quiz.question.isRunning) {\n return;\n }\n if (this.quiz.question.isVoteRunning) {\n return;\n }\n Quiz.hide(Question.box);\n this.quiz.question.hideTimer();\n }).fail(() => {\n this.quiz.question.isSaving = false;\n });\n }\n\n saveVote() {\n Ajax.post('save_vote', {vote: this.voteAnswer}, data => {\n if (data.status === 'success') {\n setText(Quiz.info, 'wait_for_instructor');\n } else {\n setText(Quiz.info, 'you_already_voted');\n }\n });\n }\n\n }\n\n return {\n initialize: () => {\n let quiz = new Quiz(Student);\n quiz.poll(2000);\n }\n }\n\n});\n"],"names":["define","$","Jazz","Quiz","Question","Ajax","setText","Student","constructor","quiz","voteAnswer","undefined","self","this","document","on","event","preventDefault","submitAnswer","saveVote","value","onNotRunning","data","info","onPreparing","onRunning","question","isRunning","startCountdown","questiontime","delay","onReviewing","isVoteRunning","hideTimer","hide","box","onSessionClosed","window","location","href","split","onVoting","html","show","options","i","length","addMathjaxElement","content_id","text","question_type","renderMaximaEquation","onStateChange","state","onQuestionTimerEnding","onTimerTick","timeLeft","timer","onQuestionRefreshed","isSaving","tinyMCE","triggerSave","serialized","form","serializeArray","name","hasOwnProperty","post","feedback","fail","vote","status","initialize","poll"],"mappings":";;;;;;;AAuBAA,8BAAO,CAAC,SAAU,sBAAsB,SAAUC,EAAGC,YAE3CC,KAAOD,KAAKC,KACZC,SAAWF,KAAKE,SAChBC,KAAOH,KAAKG,KACZC,QAAUJ,KAAKI,cAEfC,QAKFC,YAAYC,WACHA,KAAOA,UACPC,gBAAaC,MACdC,KAAOC,KACXZ,EAAEa,UAAUC,GAAG,SAAU,2BAA2B,SAASC,OACzDA,MAAMC,iBACNL,KAAKM,kBACNH,GAAG,QAAS,uBAAuB,WAClCH,KAAKO,cACNJ,GAAG,QAAS,yBAAyB,WACpCH,KAAKF,WAAaG,KAAKO,SAI/BC,aAAaC,MACThB,QAAQH,KAAKoB,KAAM,4BAGvBC,YAAYF,MACRhB,QAAQH,KAAKoB,KAAM,uBAGvBE,UAAUH,SACFT,KAAKJ,KAAKiB,SAASC,iBAGPd,KAAKJ,KAAKiB,SAASE,eAAeN,KAAKO,aAAcP,KAAKQ,QAEtExB,QAAQH,KAAKoB,KAAM,uBAI3BQ,YAAYT,WACHb,KAAKiB,SAASM,eAAgB,OAC9BvB,KAAKiB,SAASC,WAAY,OAC1BlB,KAAKiB,SAASO,YACnB9B,KAAK+B,KAAK9B,SAAS+B,KACnB7B,QAAQH,KAAKoB,KAAM,uBAGvBa,gBAAgBd,MACZe,OAAOC,SAAWA,SAASC,KAAKC,MAAM,KAAK,GAG/CC,SAASnB,SACDT,KAAKJ,KAAKiB,SAASM,qBAGvB7B,KAAKoB,KAAKmB,KAAKpB,KAAKoB,MACpBvC,KAAKwC,KAAKxC,KAAKoB,YACTqB,QAAUtB,KAAKsB,YAChB,IAAIC,EAAI,EAAGA,EAAID,QAAQE,OAAQD,IAChC1C,KAAK4C,kBAAkB9C,EAAE,IAAM2C,QAAQC,GAAGG,YAAaJ,QAAQC,GAAGI,MACjC,UAA7BL,QAAQC,GAAGK,eACX/C,KAAKgD,qBAAqBP,QAAQC,GAAGI,KAAML,QAAQC,GAAGG,iBAGzDvC,KAAKiB,SAASM,eAAgB,EAGvCoB,cAAcC,QAIdC,yBAIAC,YAAYC,UACRlD,QAAQF,SAASqD,MAAO,iCAAkC,WAAYD,UAG1EE,oBAAoBpC,OAOpBJ,kBACQL,KAAKJ,KAAKiB,SAASiC,qBAIlBlD,KAAKiB,SAASiC,UAAW,EACP,oBAAZC,SACPA,QAAQC,oBAENC,WAAa1D,SAAS2D,KAAKC,qBAC7B1C,KAAO,OACN,IAAI2C,QAAQH,WACTA,WAAWI,eAAeD,QAC1B3C,KAAKwC,WAAWG,MAAMA,MAAQH,WAAWG,MAAM7C,OAGvDf,KAAK8D,KAAK,gBAAiB7C,MAAMA,OACzBA,KAAK8C,SAAStB,OAAS,EACvB3C,KAAKwC,KAAKxC,KAAKoB,KAAKmB,KAAKpB,KAAK8C,WAE9B9D,QAAQH,KAAKoB,KAAM,4BAElBd,KAAKiB,SAASiC,UAAW,EACzB9C,KAAKJ,KAAKiB,SAASC,YAGpBd,KAAKJ,KAAKiB,SAASM,gBAGvB7B,KAAK+B,KAAK9B,SAAS+B,UACd1B,KAAKiB,SAASO,iBACpBoC,MAAK,UACC5D,KAAKiB,SAASiC,UAAW,KAItCxC,WACId,KAAK8D,KAAK,YAAa,CAACG,KAAMzD,KAAKH,aAAaY,OACxB,YAAhBA,KAAKiD,OACLjE,QAAQH,KAAKoB,KAAM,uBAEnBjB,QAAQH,KAAKoB,KAAM,+BAO5B,CACHiD,WAAY,KACG,IAAIrE,KAAKI,SACfkE,KAAK"} \ No newline at end of file diff --git a/backup/moodle2/backup_jazzquiz_activity_task.class.php b/backup/moodle2/backup_jazzquiz_activity_task.class.php index f3846df..11107dd 100644 --- a/backup/moodle2/backup_jazzquiz_activity_task.class.php +++ b/backup/moodle2/backup_jazzquiz_activity_task.class.php @@ -45,7 +45,7 @@ protected function define_my_steps() { * @param string $content * @return string of content with the URLs encoded */ - static public function encode_content_links($content) { + public static function encode_content_links($content) { global $CFG; $base = preg_quote($CFG->wwwroot, '/'); // Link to the list of JazzQuizes. diff --git a/backup/moodle2/restore_jazzquiz_activity_task.class.php b/backup/moodle2/restore_jazzquiz_activity_task.class.php index 9d57a39..1d82d86 100644 --- a/backup/moodle2/restore_jazzquiz_activity_task.class.php +++ b/backup/moodle2/restore_jazzquiz_activity_task.class.php @@ -41,7 +41,7 @@ protected function define_my_steps() { /** * @return restore_decode_content[] */ - static public function define_decode_contents() { + public static function define_decode_contents() { return [ new restore_decode_content('jazzquiz', ['intro']) ]; @@ -50,7 +50,7 @@ static public function define_decode_contents() { /** * @return restore_decode_rule[] */ - static public function define_decode_rules() { + public static function define_decode_rules() { return [ new restore_decode_rule('JAZZQUIZVIEWBYID', '/mod/jazzquiz/view.php?id=$1', 'course_module'), new restore_decode_rule('JAZZQUIZINDEX', '/mod/jazzquiz/index.php?id=$1', 'course') @@ -60,14 +60,14 @@ static public function define_decode_rules() { /** * @return restore_log_rule[] */ - static public function define_restore_log_rules() { + public static function define_restore_log_rules() { return []; } /** * @return restore_log_rule[] */ - static public function define_restore_log_rules_for_course() { + public static function define_restore_log_rules_for_course() { return []; } diff --git a/classes/bank/jazzquiz_question_bank_view.php b/classes/bank/jazzquiz_question_bank_view.php index 208b055..e425430 100755 --- a/classes/bank/jazzquiz_question_bank_view.php +++ b/classes/bank/jazzquiz_question_bank_view.php @@ -41,20 +41,20 @@ * @copyright 2018 NTNU * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class jazzquiz_question_bank_view extends \core_question\bank\view { +class jazzquiz_question_bank_view extends \core_question\local\bank\view { /** * Define the columns we want to be displayed on the question bank * @return array */ - protected function wanted_columns() { + protected function wanted_columns(): array { // Full class names for question bank columns. $columns = [ '\\mod_jazzquiz\\bank\\question_bank_add_to_jazzquiz_action_column', - 'core_question\\bank\\checkbox_column', - 'core_question\\bank\\question_type_column', - 'core_question\\bank\\question_name_column', - 'core_question\\bank\\preview_action_column' + 'core_question\\local\\bank\\checkbox_column', + 'qbank_viewquestiontype\\question_type_column', + 'qbank_viewquestionname\\viewquestionname_column_helper', + 'qbank_previewquestion\\preview_action_column' ]; foreach ($columns as $column) { $this->requiredcolumns[$column] = new $column($this); @@ -62,34 +62,26 @@ protected function wanted_columns() { return $this->requiredcolumns; } - /** - * Display the header element for the question bank. - * This is a copy of the super class method in 3.5+, and only exists for compatibility with 3.4 and earlier. - * TODO: This override should be removed in the future. - */ - protected function display_question_bank_header() { - global $OUTPUT; - echo $OUTPUT->heading(get_string('questionbank', 'question'), 2); - } - /** * Shows the question bank editing interface. * @param string $tabname - * @param int $page - * @param int $perpage - * @param string $cat - * @param bool $recurse - * @param bool $showhidden - * @param bool $showquestiontext - * @param array $tagids + * @param array $pagevars * @throws \coding_exception */ - public function display($tabname, $page, $perpage, $cat, $recurse, $showhidden, $showquestiontext, $tagids = []) { + public function display($pagevars, $tabname): void { + $page = $pagevars['qpage']; + $perpage = $pagevars['qperpage']; + $cat = $pagevars['cat']; + $recurse = $pagevars['recurse']; + $showhidden = $pagevars['showhidden']; + $showquestiontext = $pagevars['qbshowtext']; + $tagids = []; + if (!empty($pagevars['qtagids'])) { + $tagids = $pagevars['qtagids']; + } + global $PAGE; - if ($this->process_actions_needing_ui()) { - return; - } $contexts = $this->contexts->having_one_edit_tab_cap($tabname); list($categoryid, $contextid) = explode(',', $cat); $catcontext = \context::instance_by_id($contextid); @@ -104,15 +96,11 @@ public function display($tabname, $page, $perpage, $cat, $recurse, $showhidden, // Continues with list of questions. $this->display_question_list( - $this->contexts->having_one_edit_tab_cap($tabname), $this->baseurl, $cat, - $this->cm, null, $page, - $perpage, - $showhidden, - $showquestiontext, + $perpage, $this->contexts->having_cap('moodle/question:add') ); $this->display_add_selected_questions_button(); @@ -146,7 +134,7 @@ public function get_add_to_jazzquiz_url($questionid) { * @throws \coding_exception * @throws \moodle_exception */ - protected function create_new_question_form($category, $add) { + protected function create_new_question_form($category, $add): void { echo '
'; if ($add) { $caption = get_string('create_new_question', 'jazzquiz'); diff --git a/classes/bank/question_bank_add_to_jazzquiz_action_column.php b/classes/bank/question_bank_add_to_jazzquiz_action_column.php index ab92389..e6a501f 100755 --- a/classes/bank/question_bank_add_to_jazzquiz_action_column.php +++ b/classes/bank/question_bank_add_to_jazzquiz_action_column.php @@ -34,7 +34,7 @@ * @copyright 2014 University of Wisconsin - Madison * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class question_bank_add_to_jazzquiz_action_column extends \core_question\bank\action_column_base { +class question_bank_add_to_jazzquiz_action_column extends \core_question\local\bank\action_column_base { /** * Get the name of the column. @@ -61,7 +61,7 @@ protected function display_content($question, $rowclasses) { * Get the required fields. * @return string[] */ - public function get_required_fields() { + public function get_required_fields(): array { return ['q.id']; } diff --git a/classes/improviser.php b/classes/improviser.php index b3847df..cab8960 100755 --- a/classes/improviser.php +++ b/classes/improviser.php @@ -60,13 +60,19 @@ public function get_all_improvised_question_definitions() { $questions = []; $context = \context_module::instance($this->jazzquiz->cm->id); $parts = explode('/', $context->path); + debugging( "get_all_improvised: ".$parts ) ; foreach ($parts as $part) { // Selecting name first, to prevent duplicate improvise questions. + debugging( "get_all_improvised: ".$part ) ; $sql = "SELECT q.name, q.id FROM {question} q + JOIN {question_versions} qv + ON q.id = qv.questionid + JOIN {question_bank_entries} qbe + ON qbe.id = qv.questionbankentryid JOIN {question_categories} qc - ON qc.id = q.category + ON qc.id = qbe.questioncategoryid JOIN {context} ctx ON ctx.id = qc.contextid AND ctx.path LIKE :path @@ -88,10 +94,13 @@ private function get_improvised_question_definition(string $name) { if (!$category) { return false; } - $questions = $DB->get_records('question', [ - 'category' => $category->id, - 'name' => '{IMPROV}' . $name - ]); + $sql = "SELECT qbe.id + FROM {question_bank_entries} qbe + JOIN {question} q + ON q.id = qbe.id + WHERE qbe.questioncategoryid = :catid + AND q.name LIKE :name"; + $questions = $DB->get_records_sql($sql, ['catid' => $category->id, 'name' => '{IMPROV}' . $name]); if (!$questions) { return false; } @@ -117,12 +126,30 @@ private function get_default_question_category() { $context = \context_module::instance($this->jazzquiz->cm->id); $category = question_get_default_category($context->id); if (!$category) { - $contexts = new \question_edit_contexts($context); + $contexts = new \core_question\local\bank\question_edit_contexts($context); $category = question_make_default_categories($contexts->all()); } return $category; } + /** + * Create a question bank entry for the database. + * @return \stdClass | null + */ + private function make_generic_question_bank_entry() { + $category = $this->get_default_question_category(); + if (!$category) { + return null; + } + + /* debugging( "Making generic question bank entry." ) ; */ + $question = new \stdClass(); + $question->questioncategoryid = $category->id; + $question->ownerid = null; + $question->idnumber = null; + return $question; + } + /** * Create a question database object. * @param string $qtype What question type to create @@ -131,18 +158,15 @@ private function get_default_question_category() { */ private function make_generic_question_definition(string $qtype, string $name) { if (!$this->question_type_exists($qtype)) { + /* debugging( "make_generic_question_definition: question type does not exist" ) ; */ return null; } $existing = $this->get_improvised_question_definition($name); if ($existing !== false) { - return null; - } - $category = $this->get_default_question_category(); - if (!$category) { + /* debugging( "make_generic_question_definition: existing: ".$name ) ; */ return null; } $question = new \stdClass(); - $question->category = $category->id; $question->parent = 0; $question->name = '{IMPROV}' . $name; $question->questiontext = ' '; @@ -154,8 +178,6 @@ private function make_generic_question_definition(string $qtype, string $name) { $question->qtype = $qtype; $question->length = 1; $question->stamp = ''; - $question->version = ''; - $question->hidden = 0; $question->timecreated = time(); $question->timemodified = $question->timecreated; $question->createdby = null; @@ -222,11 +244,19 @@ private function make_generic_question_answer($questionid, string $format, strin */ private function insert_multichoice_question_definition(string $name, array $answers) { global $DB; + /* debugging("insert_multichoice_question_definition: ".$name ) ; */ $question = $this->make_generic_question_definition('multichoice', $name); if (!$question) { return; } + /* debugging("insert_multichoice_question_definition 2") ; */ + $qbankentry = $this->make_generic_question_bank_entry(); + if (!$qbankentry) { + return; + } $question->id = $DB->insert_record('question', $question); + $qbankentry->id = $DB->insert_record('question_bank_entries', $qbankentry); + $this->insert_question_version( $qbankentry->id, $question->id ) ; // Add options. $options = $this->make_multichoice_options($question->id); $DB->insert_record('qtype_multichoice_options', $options); @@ -235,6 +265,23 @@ private function insert_multichoice_question_definition(string $name, array $ans $qanswer = $this->make_generic_question_answer($question->id, 1, $answer); $DB->insert_record('question_answers', $qanswer); } + /* debugging( "Question ID ".$question->id ); */ + } + + /* Create a question version database object, linking the given question + * and question bank entry. + * @param int $qbankid The ID of the question banke entry + * @param int $qid The ID of the question + * @return \stdClass + */ + private function insert_question_version(int $qbankid, int $qid) { + global $DB; + $qv = new \stdClass(); + $qv->questionbankentryid = $qbankid ; + $qv->version = 1 ; + $qv->questionid = $qid ; + $qv->id = $DB->insert_record('question_versions', $qv); + return $qv; } /** @@ -243,11 +290,19 @@ private function insert_multichoice_question_definition(string $name, array $ans */ private function insert_shortanswer_question_definition(string $name) { global $DB; + /* debugging("insert_shortanswer_question_definition: ".$name ) ; */ $question = $this->make_generic_question_definition('shortanswer', $name); if (!$question) { return; } + $qbankentry = $this->make_generic_question_bank_entry(); + if (!$qbankentry) { + return; + } $question->id = $DB->insert_record('question', $question); + $qbankentry->id = $DB->insert_record('question_bank_entries', $qbankentry); + $this->insert_question_version( $qbankentry->id, $question->id ) ; + // Add options. $options = $this->make_shortanswer_options($question->id); $DB->insert_record('qtype_shortanswer_options', $options); @@ -258,11 +313,18 @@ private function insert_shortanswer_question_definition(string $name) { private function insert_shortmath_question_definition(string $name) { global $DB; + /* debugging("insert_shortmath_question_definition: ".$name ) ; */ $question = $this->make_generic_question_definition('shortmath', $name); if (!$question) { return; } + $qbankentry = $this->make_generic_question_bank_entry(); + if (!$qbankentry) { + return; + } $question->id = $DB->insert_record('question', $question); + $qbankentry->id = $DB->insert_record('question_bank_entries', $qbankentry); + $this->insert_question_version( $qbankentry->id, $question->id ) ; // Add options. Important: If shortmath changes options table in the future, this must be changed too. $options = $this->make_shortanswer_options($question->id); $DB->insert_record('qtype_shortmath_options', $options); diff --git a/edit.php b/edit.php index f6860c6..888c3c2 100755 --- a/edit.php +++ b/edit.php @@ -50,33 +50,41 @@ function jazzquiz_session_open($jazzquizid) { /** * Gets the question bank view based on the options passed in at the page setup. - * @param \question_edit_contexts $contexts + * @param \core_question\local\bank\question_edit_contexts $contexts * @param jazzquiz $jazzquiz * @param \moodle_url $url * @param array $pagevars * @return string * @throws \coding_exception */ -function get_qbank_view(\question_edit_contexts $contexts, jazzquiz $jazzquiz, \moodle_url $url, array $pagevars) { +function get_qbank_view(\core_question\local\bank\question_edit_contexts $contexts, jazzquiz $jazzquiz, \moodle_url $url, array $pagevars) { $qperpage = optional_param('qperpage', 10, PARAM_INT); $qpage = optional_param('qpage', 0, PARAM_INT); + $new_pagevars = [ + 'qpage' => $qpage, + 'qperpage' => $qperpage, + 'cat' => $pagevars['cat'], + 'recurse' => $pagevars['recurse'], + 'showhidden' => $pagevars['showhidden'], + 'qbshowtext' => $pagevars['qbshowtext'] + ]; // Capture question bank display in buffer to have the renderer render output. ob_start(); $questionbank = new bank\jazzquiz_question_bank_view($contexts, $url, $jazzquiz->course, $jazzquiz->cm); - $questionbank->display('editq', $qpage, $qperpage, $pagevars['cat'], true, true, true); + $questionbank->display($new_pagevars, 'editq'); return ob_get_clean(); } /** * Echos the list of questions using the renderer for jazzquiz. - * @param \question_edit_contexts $contexts + * @param \core_question\local\bank\question_edit_contexts $contexts * @param jazzquiz $jazzquiz * @param \moodle_url $url * @param array $pagevars * @throws \coding_exception * @throws \moodle_exception */ -function list_questions(\question_edit_contexts $contexts, jazzquiz $jazzquiz, \moodle_url $url, array $pagevars) { +function list_questions(\core_question\local\bank\question_edit_contexts $contexts, jazzquiz $jazzquiz, \moodle_url $url, array $pagevars) { $qbankview = get_qbank_view($contexts, $jazzquiz, $url, $pagevars); $jazzquiz->renderer->list_questions($jazzquiz, $jazzquiz->questions, $qbankview, $url); } @@ -119,13 +127,13 @@ function jazzquiz_edit_edit_question(jazzquiz $jazzquiz) { /** * @param jazzquiz $jazzquiz - * @param \question_edit_contexts $contexts + * @param \core_question\local\bank\question_edit_contexts $contexts * @param \moodle_url $url * @param $pagevars * @throws \coding_exception * @throws \moodle_exception */ -function jazzquiz_edit_qlist(jazzquiz $jazzquiz, \question_edit_contexts $contexts, \moodle_url $url, array $pagevars) { +function jazzquiz_edit_qlist(jazzquiz $jazzquiz, \core_question\local\bank\question_edit_contexts $contexts, \moodle_url $url, array $pagevars) { $jazzquiz->renderer->header($jazzquiz, 'edit'); list_questions($contexts, $jazzquiz, $url, $pagevars); $jazzquiz->renderer->footer(); @@ -173,8 +181,7 @@ function jazzquiz_edit() { } // Process moving, deleting and unhiding questions... - $questionbank = new \core_question\bank\view($contexts, $url, $COURSE, $cm); - $questionbank->process_actions(); + $questionbank = new \core_question\local\bank\view($contexts, $url, $COURSE, $cm); switch ($action) { case 'order': diff --git a/pix/icon.svg b/pix/icon.svg old mode 100755 new mode 100644 index dcec1d9..314d5ec --- a/pix/icon.svg +++ b/pix/icon.svg @@ -1,23 +1,282 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/reports.php b/reports.php index 6c76726..79e25a2 100755 --- a/reports.php +++ b/reports.php @@ -136,7 +136,7 @@ function jazzquiz_reports() { if (!$isdownload) { $jazzquiz->renderer->header($jazzquiz, 'reports'); } - $sessionid = optional_param('sessionid', 0, PARAM_INT); + $sessionid = optional_param('sessionid', 0, PARAM_INT); switch ($action) { case 'view': jazzquiz_view_session_report($jazzquiz, $url, $sessionid);