Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged linear equations into arithmetic quiz (HFP-1509) #8

Merged
merged 13 commits into from
May 2, 2019
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ H5P Arithmetic Quiz

Arithmetic quiz containing addition, division, multiplication and subtraction of numbers where the answer is between 0 and 100.

Choosing Linear Equations Quiz different types of equation will be generated.
You can also configure if fractions should be used and the difficulty of the equations:
* Basic [ 3x = 12 ]
* Intermediate [ 4x - 3 = 13 ]
* Advanced [ 5x + 3 = 3x + 15 ]

It rely on algebra.js by nicolewhite to build, display, and solve algebraic equations.

## License

(The MIT License)
Expand Down
1 change: 1 addition & 0 deletions js/algebra.min.js

Large diffs are not rendered by default.

31 changes: 29 additions & 2 deletions js/arithmetic-quiz.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ H5P.ArithmeticQuiz = (function ($) {
// Extend defaults with provided options
self.options = $.extend(true, {}, {
intro: '',
quizType: 'arithmetic',
arithmeticType: 'addition',
equationType: undefined,
useFractions: undefined,
maxQuestions: undefined,
UI: {
score: 'Score @score',
Expand All @@ -36,17 +39,20 @@ H5P.ArithmeticQuiz = (function ($) {
incorrectText: 'Incorrect. Correct answer was :num',
durationLabel: 'Duration in hours, minutes and seconds.',
humanizedQuestion: 'What does :arithmetic equal?',
humanizedEquation: 'For the equation :equation, what does :item equal?',
humanizedVariable: 'What does :item equal?',
plusOperator: 'plus',
minusOperator: 'minus',
multiplicationOperator: 'times',
divisionOperator: 'divided by',
equalitySign: 'equal',
slideOfTotal: 'Slide :num of :total'
}
}, options);
self.currentWidth = 0;

self.gamePage = new H5P.ArithmeticQuiz.GamePage(self.options.arithmeticType, self.options.maxQuestions, self.options.UI, id);

self.gamePage = new H5P.ArithmeticQuiz.GamePage(self.options.quizType, self.options, id);
self.gamePage.on('last-slide', function (e) {
self.triggerXAPIScored(e.data.score, e.data.numQuestions, 'answered');
});
Expand Down Expand Up @@ -150,3 +156,24 @@ H5P.ArithmeticQuiz.ArithmeticType = {
MULTIPLICATION: 'multiplication',
DIVISION: 'division'
};

/**
* Enum defining the different equation types
* @readonly
* @enum {string}
*/
H5P.ArithmeticQuiz.EquationType = {
BASIC: 'basic',
INTERMEDIATE: 'intermediate',
ADVANCED: 'advanced'
};

/**
* Enum defining the different quiz types
* @readonly
* @enum {string}
*/
H5P.ArithmeticQuiz.QuizType = {
ARITHMETIC: 'arithmetic',
LINEAREQUATION: 'linearEquation'
};
125 changes: 68 additions & 57 deletions js/game-page.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,50 @@
/**
* Defines the H5P.ArithmeticQuiz.GamePage class
*/
H5P.ArithmeticQuiz.GamePage = (function ($, UI, ArithmeticType, QuestionsGenerator) {
H5P.ArithmeticQuiz.GamePage = (function ($, UI, QuizType) {

/**
* Creates a new GamePage instance
*
* @class
* @augments H5P.EventDispatcher
* @namespace H5P
* @param {arithmeticType} type
* @param {number} maxQuestions Maximum number of questions
* @param {Object} t Object containing translation texts
* @param {quizType} quizType
* @param {Object} t Object containing all options
* @param {number} id Unique id to identify this quiz
* @fires H5P.XAPIEvent
*/
function GamePage(type, maxQuestions, t, id) {
function GamePage(quizType, options, id) {
H5P.EventDispatcher.call(this);

var self = this;
self.quizType = quizType;
self.id = id;
self.translations = t;
self.type = type;
self.maxQuestions = maxQuestions;
self.translations = options.UI;
self.arithmeticType = options.arithmeticType;
self.equationType = options.equationType;
self.useFractions = options.useFractions;
self.maxQuestions = options.maxQuestions;
self.sliding = false;

self.$gamepage = $('<div>', {
'class': 'h5p-baq-game counting-down'
});

self.questionsGenerator = new QuestionsGenerator(self.type, self.maxQuestions);
if (self.quizType === H5P.ArithmeticQuiz.QuizType.ARITHMETIC) {
self.questionsGenerator = new H5P.ArithmeticQuiz.ArithmeticGenerator(self.arithmeticType, self.maxQuestions);
} else {
self.questionsGenerator = new H5P.ArithmeticQuiz.EquationsGenerator(self.arithmeticType, self.equationType, self.maxQuestions, self.useFractions);
}
self.score = 0;
self.scoreWidget = new ScoreWidget(t);
self.scoreWidget = new ScoreWidget(self.translations);
self.scoreWidget.appendTo(self.$gamepage);

self.timer = new H5P.ArithmeticQuiz.TimerWidget(t);
self.timer = new H5P.ArithmeticQuiz.TimerWidget(self.translations);
self.timer.appendTo(self.$gamepage);

self.slider = UI.createSlider();

self.countdownWidget = new H5P.ArithmeticQuiz.CountdownWidget(4, t);
self.countdownWidget = new H5P.ArithmeticQuiz.CountdownWidget(4, self.translations);
self.slider.addSlide(self.countdownWidget.create());
self.countdownWidget.on('ignition', function () {
self.$gamepage.removeClass('counting-down');
Expand All @@ -59,12 +64,12 @@ H5P.ArithmeticQuiz.GamePage = (function ($, UI, ArithmeticType, QuestionsGenerat

// Create progressbar
self.progressbar = UI.createProgressbar(numQuestions, {
progressText: t.slideOfTotal
progressText: self.translations.slideOfTotal
});
self.progressbar.appendTo(self.$gamepage);

// Add result page:
self.resultPage = new H5P.ArithmeticQuiz.ResultPage(numQuestions, t);
self.resultPage = new H5P.ArithmeticQuiz.ResultPage(numQuestions, self.translations);
self.slider.addSlide(self.resultPage.create());

self.resultPage.on('retry', function () {
Expand Down Expand Up @@ -144,41 +149,62 @@ H5P.ArithmeticQuiz.GamePage = (function ($, UI, ArithmeticType, QuestionsGenerat
this.$gamepage.find('.h5p-joubelui-button:first-child, .h5p-joubelui-button:last-child').attr('tabindex', 0);
};

GamePage.prototype.makeSignsReadable = function (questionTextual) {
var self = this;
questionTextual = String(questionTextual);
return questionTextual
.replaceAll('\\+', self.translations.plusOperator)
.replaceAll('−', self.translations.minusOperator)
.replaceAll('-', self.translations.minusOperator)
.replaceAll('×', self.translations.multiplicationOperator)
.replaceAll('/', self.translations.divisionOperator)
.replaceAll('÷', self.translations.divisionOperator)
.replaceAll('=', self.translations.equalitySign);
};

/**
* Creates a question slide
*
* @param {Object} question
* @param {string} question.q The question
* @param {number} question.correct The correct answer
* @param {number} i Index of question
* @param {number} i Index of question
* @return {H5P.jQuery} The jquery dom element generated
*/
GamePage.prototype.createSlide = function (question, i) {
var self = this;

var readableSigns = undefined;
var readableQuestion = undefined;
var readableText = undefined;
var $slide = $('<div>', {
'class': 'question-page'
});

// Make arithmetic readable, e.g. plus signs are not read by ChromeVox.
var readableArithmetic = question.textual
.replace('+', self.translations.plusOperator)
.replace('−', self.translations.minusOperator)
.replace('×', self.translations.multiplicationOperator)
.replace('÷', self.translations.divisionOperator);

var readableQuestion = self.translations.humanizedQuestion
.replace(':arithmetic', readableArithmetic);

// Make equations readable, e.g. plus signs are not read by ChromeVox.
readableSigns = self.makeSignsReadable(question.textual);
readableQuestion = self.questionsGenerator.readableQuestion(self.translations, readableSigns, question);
readableText = self.questionsGenerator.readableText(question);

var questionId = 'arithmetic-quiz-' + self.id + '-question-' + i;

$('<div>', {
'class': 'question',
'text': question.textual + ' = ?',
'text': readableText,
'aria-label': readableQuestion,
'id': questionId
}).appendTo($slide);

if (question.expression !== undefined) {
var readableVariable = self.translations.humanizedVariable
.replace(':item', question.variable);
$('<div>', {
'class': 'question',
'text': question.variable + ' = ?',
'aria-label': readableVariable,
'id': questionId
}).appendTo($slide);
}

var $alternatives = $('<ul>', {
'class': 'h5p-baq-alternatives',
'role': 'radiogroup',
Expand Down Expand Up @@ -228,9 +254,12 @@ H5P.ArithmeticQuiz.GamePage = (function ($, UI, ArithmeticType, QuestionsGenerat
};

var alternatives = [];
var readableAlternative = undefined;
for (var k = 0; k < question.alternatives.length; k++) {
alternatives.push(new Alternative(question.alternatives[k], question.alternatives[k]===question.correct, self.translations));
readableAlternative = self.makeSignsReadable(question.alternatives[k]);
alternatives.push(new Alternative(question.alternatives[k], readableAlternative, question.alternatives[k]===question.correct, self.translations));
}

alternatives.forEach(function (alternative, index) {
if (index === 0 || index === alternatives.length - 1) {
alternative.tabbable();
Expand Down Expand Up @@ -260,7 +289,7 @@ H5P.ArithmeticQuiz.GamePage = (function ($, UI, ArithmeticType, QuestionsGenerat

alternatives.forEach(function (alt) {
if (alt.correct && alternative !== alt) {
alternative.announce(self.translations.incorrectText.replace(':num', alt.number));
alternative.announce(self.translations.incorrectText.replace(':num', alt.readableResult));
}
alt.reveal();
});
Expand All @@ -285,6 +314,12 @@ H5P.ArithmeticQuiz.GamePage = (function ($, UI, ArithmeticType, QuestionsGenerat
this.$gamepage.appendTo($container);
};

String.prototype.replaceAll = function(target, replacement) {
//var target = this;
return this.split(target).join(replacement);
//return target.replace(new RegExp(search, 'g'), replacement);
};

/**
* Creates a ScoreWidget instance
*
Expand Down Expand Up @@ -340,11 +375,12 @@ H5P.ArithmeticQuiz.GamePage = (function ($, UI, ArithmeticType, QuestionsGenerat
* @param {boolean} correct Correct or not
* @param {Object} t Translations
*/
function Alternative(number, correct, t) {
function Alternative(number, readableResult, correct, t) {
H5P.EventDispatcher.call(this);
var self = this;

self.number = number;
self.readableResult = readableResult;
self.correct = correct;

var answer = function (event) {
Expand Down Expand Up @@ -460,29 +496,4 @@ H5P.ArithmeticQuiz.GamePage = (function ($, UI, ArithmeticType, QuestionsGenerat
Alternative.prototype.constructor = Alternative;

return GamePage;
})(H5P.jQuery, H5P.JoubelUI, H5P.ArithmeticQuiz.ArithmeticType, H5P.ArithmeticQuiz.QuestionsGenerator);

/*function GridResultsView(rows, cols) {
var $grid = $('<table>', {
'class': 'h5p-baq-grid-results',
cellspacing: 0,
cellpadding: 0,
'border-collapse': 'collapse'
});

for (var i = 0; i < rows; i++) {
var $tr = $('<tr>');
for (var j = 0; j < rows; j++) {
$tr.append($('<td>'));
}
$grid.append($tr);
}

this.appendTo = function ($container) {
$grid.appendTo($container);
}

this.getCell = function (row, col) {
return $grid.find('tr:nth-child('+row+')').find('td:nth-child('+col+')');
}
}*/
})(H5P.jQuery, H5P.JoubelUI, H5P.ArithmeticQuiz.QuizType);
22 changes: 16 additions & 6 deletions js/qa-generator.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* Defines the H5P.ArithmeticQuiz.QuestionsGenerator class
* Defines the H5P.ArithmeticQuiz.ArithmeticGenerator class
*/
H5P.ArithmeticQuiz.QuestionsGenerator = (function (ArithmeticType) {
H5P.ArithmeticQuiz.ArithmeticGenerator = (function (ArithmeticType) {

// Helper functions for creating wrong alternatives
function add (question, param) {
Expand Down Expand Up @@ -87,13 +87,13 @@ H5P.ArithmeticQuiz.QuestionsGenerator = (function (ArithmeticType) {
}

/**
* Questions generator classes
* @method QuestionsGenerator
* Arithmetic Questions generator classes
* @method ArithmeticGenerator
* @constructor
* @param {H5P.ArithmeticQuiz.ArithmeticType} type
* @param {number} maxQuestions
*/
function QuestionsGenerator(type, maxQuestions) {
function ArithmeticGenerator(type, maxQuestions) {
var self = this;
var questions = [];
var i, j;
Expand Down Expand Up @@ -192,7 +192,17 @@ H5P.ArithmeticQuiz.QuestionsGenerator = (function (ArithmeticType) {
self.get = function () {
return questions;
};

}

return QuestionsGenerator;
ArithmeticGenerator.prototype.readableQuestion = function (translations, readableSigns, question) {
return translations.humanizedQuestion
.replace(':arithmetic', readableSigns);
};

ArithmeticGenerator.prototype.readableText = function (question) {
return question.textual + ' = ?';
};

return ArithmeticGenerator;
}(H5P.ArithmeticQuiz.ArithmeticType));
Loading