Several changes:

Added h5pQuestionsetFinished event trigger
Use H5P.jQuery
Added result page.
Initial code for endGame (results, animations)
Revised code for showing current question.
Added passPercentage option (default 50)
Intro page and endGame in schema. (Only endGame has been implemented in code yet)
d3summaryChart
Frank Ronny Larsen 2013-01-13 09:43:55 +01:00
parent c57e0d5921
commit b4d4944e12
4 changed files with 256 additions and 22 deletions

View File

@ -7,12 +7,17 @@
// answers: [{text: "Answer text", correct: false}, ...],
// singleAnswer: true, // or false, will change rendered output slightly.
// }
//
// Events provided:
// - h5pQuestionSetFinished: Triggered when a question is finished. (User presses Finish-button)
window.H5P = window.H5P || {};
H5P.QuestionSet = function (options) {
if ( !(this instanceof H5P.QuestionSet) )
return new H5P.QuestionSet(options);
var $ = H5P.jQuery;
var texttemplate = '' +
'<style type="text/css">' +
'.dots-container {' +
@ -60,22 +65,63 @@ H5P.QuestionSet = function (options) {
'</div>' +
'';
var resulttemplate = '' +
'<div class="questionset-results">' +
' <div class="greeting"><%= greeting %></div>' +
' <div class="score <%= scoreclass %>"><%= score %></div>' +
' <div class="resulttext"><%= resulttext %></div>' +
' <div><button class="qs-finishbutton"><%= finishButtonText %></button></div>' +
'</div>' +
'';
var that = this;
var defaults = {
title: "",
randomOrder: false,
initialQuestion: 0,
backgroundImage: "",
progressType: 'textual',
passPercentage: 50,
questions: [],
introPage: {
showIntroPage: true,
title: "Welcome",
introduction: "Click start to start.",
startButtonText: "Start"
},
texts: {
prevButton: "Previous",
nextButton: "Next",
finishButton: "Finish",
textualProgress: "Question: @current of @total questions"
},
endGame: {
showResultPage: true,
resultPage: {
succesGreeting: "Congratulations!",
successComment: "You have enough correct answers to pass the test.",
failGreeting: "Sorry!",
failComment: "You don't have enough correct answers to pass this test.",
scoreString: "@score/@total",
finishButtonText: "Finish"
},
animations: {
showAnimations: false,
succesResultAnimation: {
machineName: "H5P.Image",
options: {image: ""}
},
failedResultAnimation: {
machineName: "H5P.Image",
options: {image: ""}
}
}
}
};
var template = new EJS({text: texttemplate});
var params = jQuery.extend({}, defaults, options);
var endTemplate = new EJS({text: resulttemplate});
var params = $.extend({}, defaults, options);
var currentQuestion = 0;
var questionInstances = new Array();
@ -87,12 +133,21 @@ H5P.QuestionSet = function (options) {
console.log("TODO: Randomize order of questions");
}
var _allQuestionsAnswered = function () {
// Instantiate question instances
for (var i=0; i<params.questions.length; i++) {
var quest = params.questions[i];
// TODO: Render on init, inject in template.
var tmp = new (H5P.classFromName(quest.machineName))(quest.options);
questionInstances.push(tmp);
}
var _updateFinishButton = function () {
var answered = true;
for (var i = questionInstances.length - 1; i >= 0; i--) {
answered = answered && (questionInstances[i]).getAnswerGiven();
}
return answered;
$('.finish.button', myDom).attr({'disabled': !answered});
};
var _showQuestion = function (questionNumber) {
@ -102,7 +157,7 @@ H5P.QuestionSet = function (options) {
$('.prev.button', myDom).attr({'disabled': (questionNumber === 0)});
$('.next.button', myDom).attr({'disabled': (questionNumber == params.questions.length-1)});
$('.finish.button', myDom).attr({'disabled': !(_allQuestionsAnswered())});
// Hide all questions
$('.question-container', myDom).hide();
@ -114,14 +169,10 @@ H5P.QuestionSet = function (options) {
// Test if current has been answered.
if (params.progressType == 'textual') {
$('.progress-text', myDom).text(params.texts.textualProgress.replace("@current", questionNumber+1).replace("@total", params.questions.length));
// $('.progress-current', myDom).text("" + (questionNumber+1));
} else {
// Set currentNess
$('.progress-dot.current', myDom).removeClass('current');
// Set answered/unanswered for current.
$('#qdot-' + questionNumber, myDom).addClass('current');
if (questionInstances[currentQuestion].getAnswerGiven()) {
$('#qdot-' + currentQuestion, myDom).removeClass('unanswered').addClass('answered');
}
}
// Remember where we are
@ -133,14 +184,17 @@ H5P.QuestionSet = function (options) {
var attach = function (targetId) {
// Render own DOM into target.
template.update(targetId, params);
myDom = jQuery('#' + targetId);
myDom = $('#' + targetId);
// Attach questions
for (var i=0; i<params.questions.length; i++) {
var quest = params.questions[i];
for (var i=0; i<questionInstances.length; i++) {
var quest = questionInstances[i];
// TODO: Render on init, inject in template.
var tmp = new (H5P.classFromName(quest.machineName))(quest.options).attach('q-' + i);
questionInstances.push(tmp);
quest.attach('q-' + i);
$(quest).on('h5pQuestionAnswered', function (ev) {
$('#qdot-' + currentQuestion, myDom).removeClass('unanswered').addClass('answered');
_updateFinishButton();
});
}
// Set event listeners.
@ -151,19 +205,47 @@ H5P.QuestionSet = function (options) {
_showQuestion(currentQuestion - 1);
});
$('.finish.button', myDom).click(function (ev) {
// get total score.
// Get total score.
var finals = getScore();
var totals = totalScore();
var scoreString = params.endGame.resultPage.scoreString.replace("@score", finals).replace("@total", totals);
var success = ((100 * finals / totals) >= params.passPercentage);
// Display result page.
// Display animation if present.
// Remove DOM. (delete container)
myDom.remove();
if (params.endGame.showResultPage) {
// Render result page into.
var eparams = {
greeting: (success ? params.endGame.resultPage.succesGreeting : params.endGame.resultPage.failGreeting),
score: scoreString,
scoreclass: (success ? 'success' : 'fail'),
resulttext: (success ? params.endGame.resultPage.successComment : params.endGame.resultPage.failComment),
finishButtonText: params.endGame.resultPage.finishButtonText
};
endTemplate.update(targetId, eparams);
$('.qs-finishbutton').click(function (ev) {
// Display animation if present.
if (params.endGame.animations.showAnimations) {
// Init anims.
console.log("Now we should have started some anims...");
// On animation finished:
$(returnObject).trigger('h5pQuestionSetFinished');
} else {
// Trigger finished event.
$(returnObject).trigger('h5pQuestionSetFinished');
}
});
} else {
$(returnObject).trigger('h5pQuestionSetFinished');
}
});
// Hide all but initial Question.
_showQuestion(params.initialQuestion);
_updateFinishButton();
return this;
};
// Get current score for questionset.
var getScore = function () {
var score = 0;
for (var i = questionInstances.length - 1; i >= 0; i--) {
@ -172,10 +254,24 @@ H5P.QuestionSet = function (options) {
return score;
};
return {
// Get total score possible for questionset.
var totalScore = function () {
return questionInstances.length;
// FIXME: questions need to get totalScore function.
var score = 0;
for (var i = questionInstances.length - 1; i >= 0; i--) {
score += questionInstances[i].totalScore();
}
return score;
};
// Masquerade the main object to hide inner properties and functions.
var returnObject = {
attach: attach, // Attach to DOM object
getQuestions: function () {return questionInstances;},
getScore: getScore,
totalScore: totalScore,
defaults: defaults // Provide defaults for inspection
};
return returnObject;
};

View File

@ -20,7 +20,8 @@
"backgroundImage": {
"name": "Background image",
"description": "An optional background image for the Question set.",
"type": "image"
"type": "image",
"default": ""
},
"progressType": {
"name": "Progress indicator",
@ -29,13 +30,139 @@
"values": [{"text": "Textual", "value": "textual"}, {"text": "Dots", "value": "dots"}],
"default": "textual"
},
"passPercentage": {
"name": "Pass percentage",
"description": "Percentage of total score required for passing the quiz.",
"type": "integer",
"minValue": 0,
"maxValue": 100,
"default": 50
},
"questions": {
"name": "Questions",
"description": "List of questions in this set.",
"type": "h5p-library",
"validLibs": ["H5P.MultiChoice"],
"validLibs": ["H5P.MultiChoice", "H5P.DragTextMatch", "H5PDragImageIntoPosition"],
"array": true,
"minEntries": 1,
"maxEntries": -1
},
"introPage": {
"name": "Intro page",
"description": "Data for the intro page",
"type": "combined",
"fields": {
"showIntroPage": {
"name": "Show intro page?",
"type": "boolean"
},
"title": {
"name": "Title",
"type": "text"
},
"introduction": {
"name": "Introduction text",
"type": "text"
},
"startButtonText": {
"name": "Start button text",
"type": "text"
}
}
},
"texts": {
"name": "Interface texts in quiz",
"type": "combined"
"fields": {
"prevButton": {
"name": "Back button",
"type": "text",
"default": "Previous"
},
"nextButton": {
"name": "Next button",
"type": "text",
"default": "Next"
},
"finishButton": {
"name": "Finish button",
"type": "text",
"default": "Finish"
},
"textualProgress": {
"name": "Progress text",
"description": "Text used if textual progress is selected.",
"type": "text",
"default": "Question: @current of @total questions"
}
}
},
"endGame": {
"name": "End game data",
"type": "combined",
"fields" {
"showResultPage": {
"name": "Show result page",
"type": "boolean",
"default": true
},
"resultPage": {
"name": "Result page",
"description": "Data and texts for the result page",
"type": "combined",
"fields": {
"successGreeting": {
"name": "Success greeting",
"description": "Title in result page on success",
"type": "text"
},
"successComment": {
"name": "Success comment",
"description": "Comment shown after the score",
"type": "text"
},
"failGreeting": {
"name": "Failed greeting",
"description": "Title in result page on failed quiz",
"type": "text"
},
"failComment": {
"name": "Failed comment",
"description": "Comment shown after the score on failed quiz",
"type": "text"
},
"finishButtonText": {
"name": "Finish button text",
"description": "Text for the finish button",
"type": "text"
}
}
},
"animations": {
"name": "Animations",
"type": "combined"
"fields": {
"showAnimations": {
"name": "Show animations",
"type": "boolean",
"default": false
}
"successResultAnimation": {
"name": "Result animation for success",
"description": "Add animation for successful completion of the quiz",
"optional": true,
"type": "h5p-library",
"validLibs": ["H5P.Animation", "H5P.Video", "H5P.Image"]
},
"failedResultAnimation": {
"name": "Result animation for failed quiz",
"description": "Add animation for failed completion of the quiz",
"optional": true,
"type": "h5p-library",
"validLibs": ["H5P.Animation", "H5P.Video", "H5P.Image"]
}
}
}
}
}
}

View File

@ -0,0 +1,5 @@
<div class="questionset-intro">
<div class="title"><%= title %></div>
<div class="introduction"><%= introduction %></div>
<div class="buttons"><button id='qs-startbutton'><%= startButtonText %></button></div>
</div>

View File

@ -0,0 +1,6 @@
<div class="questionset-results">
<div class="greeting"><%= greeting %></div>
<div class="score <%= scoreclass %>"><%= score %></div>
<div class="resulttext"><%= resulttext %></div>
<div><button class="qs-finishbutton"><%= finishButtonText %></button></div>
</div>