From c0958bafe7b149bd74b5ec1332003ab5908cd46f Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Fri, 21 Aug 2015 16:38:26 +0200 Subject: [PATCH 1/5] Added French language support. --- language/fr.json | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 language/fr.json diff --git a/language/fr.json b/language/fr.json new file mode 100644 index 0000000..68fee8c --- /dev/null +++ b/language/fr.json @@ -0,0 +1,37 @@ +{ + "semantics": [ + { + "label": "Cartes", + "entity": "card", + "field": { + "label": "Carte", + "fields": [ + { + "label": "Image" + }, + { + "label": "Description", + "description": "Petit texte affiché quand deux cartes identiques sont trouvées." + } + ] + } + }, + { + "label": "Localisation", + "fields": [ + { + "label": "Texte pour une carte retournée", + "default": "Retourner" + }, + { + "label": "Texte pour le temps passé", + "default": "Durée écoulée" + }, + { + "label": "Texte de feedback", + "default": "Bon travail!" + } + ] + } + ] +} \ No newline at end of file From b7f64fa3467740b3887592bb337d5c72bfa7f044 Mon Sep 17 00:00:00 2001 From: Stephlabaraque Date: Tue, 25 Aug 2015 18:32:00 +0200 Subject: [PATCH 2/5] Update fr.json Tested and working. --- language/fr.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/language/fr.json b/language/fr.json index 68fee8c..96828bb 100644 --- a/language/fr.json +++ b/language/fr.json @@ -2,7 +2,7 @@ "semantics": [ { "label": "Cartes", - "entity": "card", + "entity": "une carte", "field": { "label": "Carte", "fields": [ @@ -20,7 +20,7 @@ "label": "Localisation", "fields": [ { - "label": "Texte pour une carte retournée", + "label": "Texte pour une carte à retourner", "default": "Retourner" }, { @@ -34,4 +34,4 @@ ] } ] -} \ No newline at end of file +} From 34e774aad4858e4c292a5aa569e0613fe33180f7 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Wed, 26 Aug 2015 15:51:43 +0200 Subject: [PATCH 3/5] Replaced nbsp with normal space. --- memory-game.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/memory-game.js b/memory-game.js index 7f38263..0271e42 100644 --- a/memory-game.js +++ b/memory-game.js @@ -255,7 +255,7 @@ H5P.MemoryGame = (function ($) { if (desc !== undefined) { // Pause timer and show desciption. timer.stop(); - popup.show(desc, card.getImage(), function () { + popup.show(desc, card.getImage(), function () { if (finished) { // Game has finished $feedback.addClass('h5p-show'); From a58411cdcfc191c5d6b52516c2a05fa85388897c Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Mon, 19 Oct 2015 11:17:38 +0200 Subject: [PATCH 4/5] Split up into multiple files. Updated docs. --- card.js | 102 +++++++++++++++ counter.js | 23 ++++ library.json | 14 ++- memory-game.js | 328 +++++++++---------------------------------------- popup.js | 44 +++++++ timer.js | 94 ++++++++++++++ 6 files changed, 335 insertions(+), 270 deletions(-) create mode 100644 card.js create mode 100644 counter.js create mode 100644 popup.js create mode 100644 timer.js diff --git a/card.js b/card.js new file mode 100644 index 0000000..0c0a608 --- /dev/null +++ b/card.js @@ -0,0 +1,102 @@ +(function (MemoryGame, EventDispatcher, $) { + + /** + * Controls all the operations for each card. + * + * @class H5P.MemoryGame.Card + * @param {Object} parameters + * @param {Number} id + */ + MemoryGame.Card = function (parameters, id) { + var self = this; + + // Initialize event inheritance + EventDispatcher.call(self); + + var path = H5P.getPath(parameters.image.path, id); + var width, height, margin, $card; + + var a = 96; + if (parameters.image.width !== undefined && parameters.image.height !== undefined) { + if (parameters.image.width > parameters.image.height) { + width = a; + height = parameters.image.height * (width / parameters.image.width); + margin = '' + ((a - height) / 2) + 'px 0 0 0'; + } + else { + height = a; + width = parameters.image.width * (height / parameters.image.height); + margin = '0 0 0 ' + ((a - width) / 2) + 'px'; + } + } + else { + width = height = a; + } + + /** + * Flip card. + */ + self.flip = function () { + $card.addClass('h5p-flipped'); + self.trigger('flip'); + }; + + /** + * Flip card back. + */ + self.flipBack = function () { + $card.removeClass('h5p-flipped'); + }; + + /** + * Remove. + */ + self.remove = function () { + $card.addClass('h5p-matched'); + }; + + /** + * Get card description. + * + * @returns {string} + */ + self.getDescription = function () { + return parameters.description; + }; + + /** + * Get image clone. + * + * @returns {H5P.jQuery} + */ + self.getImage = function () { + return $card.find('img').clone(); + }; + + /** + * Append card to the given container. + * + * @param {H5P.jQuery} $container + */ + self.appendTo = function ($container) { + // TODO: Translate alt attr + $card = $('
  • ' + + '
    ' + + '
    ' + + 'Memory Card' + + '
    ' + + '
  • ') + .appendTo($container) + .children('.h5p-front') + .click(function () { + self.flip(); + }) + .end(); + }; + }; + + // Extends the event dispatcher + MemoryGame.Card.prototype = Object.create(EventDispatcher.prototype); + MemoryGame.Card.prototype.constructor = MemoryGame.Card; + +})(H5P.MemoryGame, H5P.EventDispatcher, H5P.jQuery); diff --git a/counter.js b/counter.js new file mode 100644 index 0000000..39343c8 --- /dev/null +++ b/counter.js @@ -0,0 +1,23 @@ +(function (MemoryGame) { + + /** + * Keeps track of the number of cards that has been turned + * + * @class H5P.MemoryGame.Counter + * @param {H5P.jQuery} $container + */ + MemoryGame.Counter = function ($container) { + var self = this; + + var current = 0; + + /** + * Increment the counter. + */ + self.increment = function () { + current++; + $container.text(current); + }; + }; + +})(H5P.MemoryGame); diff --git a/library.json b/library.json index 2d0dd69..a9a2c3b 100644 --- a/library.json +++ b/library.json @@ -16,6 +16,18 @@ "preloadedJs": [ { "path": "memory-game.js" + }, + { + "path": "card.js" + }, + { + "path": "timer.js" + }, + { + "path": "counter.js" + }, + { + "path": "popup.js" } ] -} \ No newline at end of file +} diff --git a/memory-game.js b/memory-game.js index 7f38263..540df0c 100644 --- a/memory-game.js +++ b/memory-game.js @@ -1,257 +1,41 @@ -var H5P = H5P || {}; - -/** - * H5P Memory Game Module. - */ -H5P.MemoryGame = (function ($) { - - /** - * Memory Card Constructor - * - * @param {Object} parameters - * @param {Number} id - */ - function MemoryCard(parameters, id) { - var self = this; - var path = H5P.getPath(parameters.image.path, id); - var width, height, margin, $card; - - var a = 96; - if (parameters.image.width !== undefined && parameters.image.height !== undefined) { - if (parameters.image.width > parameters.image.height) { - width = a; - height = parameters.image.height * (width / parameters.image.width); - margin = '' + ((a - height) / 2) + 'px 0 0 0'; - } - else { - height = a; - width = parameters.image.width * (height / parameters.image.height); - margin = '0 0 0 ' + ((a - width) / 2) + 'px'; - } - } - else { - width = height = a; - } - - // Public jQuery wrapper. - this.$ = $(this); - - /** - * Public. Flip card. - */ - this.flip = function () { - $card.addClass('h5p-flipped'); - }; - - /** - * Public. Flip card back. - */ - this.flipBack = function () { - $card.removeClass('h5p-flipped'); - }; - - /** - * Public. Remove. - */ - this.remove = function () { - $card.addClass('h5p-matched'); - }; - - /** - * Public. Get card description. - */ - this.getDescription = function () { - return parameters.description; - }; - - /** - * Public. Get image clone. - */ - this.getImage = function () { - return $card.find('img').clone(); - }; - - /** - * Public. Append card to the given container. - * - * @param {jQuery} $container - */ - this.appendTo = function ($container) { - $card = $('
  • \ -
    \ -
    \ - Memory Card\ -
    \ -
  • ') - .appendTo($container) - .children('.h5p-front') - .click(function () { - self.$.trigger('flip'); - }) - .end(); - }; - }; - - function MemoryTimer($container) { - var interval, started, totalTime = 0; - - /** - * Private. Make timer more readable for humans. - * - * @param {Number} seconds - * @returns {String} - */ - var humanizeTime = function (seconds) { - var minutes = Math.floor(seconds / 60); - var hours = Math.floor(minutes / 60); - - minutes = minutes % 60; - seconds = Math.floor(seconds % 60); - - var time = ''; - - if (hours !== 0) { - time += hours + ':'; - - if (minutes < 10) { - time += '0'; - } - } - - time += minutes + ':'; - - if (seconds < 10) { - time += '0'; - } - - time += seconds; - - return time; - }; - - /** - * Private. Update the timer element. - */ - var update = function (last) { - var currentTime = (new Date().getTime() - started); - $container.text(humanizeTime(Math.floor((totalTime + currentTime) / 1000))); - - if (last === true) { - // This is the last update, stop timing interval. - clearTimeout(interval); - } - else { - // Use setTimeout since setInterval isn't safe. - interval = setTimeout(function () { - update(); - }, 1000); - } - - return currentTime; - }; - - /** - * Public. Starts the counter. - */ - this.start = function () { - if (started === undefined) { - started = new Date(); - update(); - } - }; - - /** - * Public. Stops the counter. - */ - this.stop = function () { - if (started !== undefined) { - totalTime += update(true); - started = undefined; - } - }; - }; - - /** - * Memory Counter Constructor - * - * @param {jQuery} $container - */ - function MemoryCounter($container) { - var current = 0; - - this.increment = function () { - current++; - $container.text(current); - }; - } - - /** - * Memory Popup Dialog Constructor - * - * @param {jQuery} $container - */ - function MemoryPop($container) { - var closed; - - var $popup = $('
    ').appendTo($container); - var $desc = $popup.find('.h5p-memory-desc'); - var $image = $popup.find('.h5p-memory-image'); - - /** - * Public. Show the popup. - * - * @param {String} desc - * @param {jQuery} $img - * @param {Function} done - * @returns {undefined} - */ - this.show = function (desc, $img, done) { - $desc.text(desc); - $img.appendTo($image.html('')); - $popup.show(); - closed = done; - }; - - /** - * Public. Close the popup. - * @returns {undefined} - */ - this.close = function () { - if (closed !== undefined) { - $popup.hide(); - closed(); - closed = undefined; - } - }; - } +H5P.MemoryGame = (function (EventDispatcher, $) { /** * Memory Game Constructor * + * @class * @param {Object} parameters * @param {Number} id */ function MemoryGame(parameters, id) { - var flipped, timer, counter, popup, $feedback, cards = [], removed = 0; - + var self = this; + + // Initialize event inheritance + EventDispatcher.call(self); + + var flipped, timer, counter, popup, $feedback; + var cards = []; + var removed = 0; + /** - * Private. Check if these two cards belongs together. + * Check if these two cards belongs together. * - * @param {MemoryCard} card - * @param {MemoryCard} mate - * @param {MemoryCard} correct + * @private + * @param {H5P.MemoryGame.Card} card + * @param {H5P.MemoryGame.Card} mate + * @param {H5P.MemoryGame.Card} correct */ var check = function (card, mate, correct) { if (mate === correct) { // Remove them from the game. card.remove(); mate.remove(); - + removed += 2; - + var finished = (removed === cards.length); var desc = card.getDescription(); - + if (desc !== undefined) { // Pause timer and show desciption. timer.stop(); @@ -278,23 +62,24 @@ H5P.MemoryGame = (function ($) { mate.flipBack(); } }; - + /** - * Private. Adds card to card list and set up a flip listener. + * Adds card to card list and set up a flip listener. * - * @param {MemoryCard} card - * @param {MemoryCard} mate + * @private + * @param {H5P.MemoryGame.Card} card + * @param {H5P.MemoryGame.Card} mate */ var addCard = function (card, mate) { - card.$.on('flip', function () { + card.on('flip', function () { // Keep track of time spent timer.start(); - + if (flipped !== undefined) { var matie = flipped; // Reset the flipped card. flipped = undefined; - + setTimeout(function () { check(card, matie, mate); }, 800); @@ -303,61 +88,66 @@ H5P.MemoryGame = (function ($) { // Keep track of the flipped card. flipped = card; } - + // Count number of cards turned counter.increment(); }); - + cards.push(card); }; - + // Initialize cards. for (var i = 0; i < parameters.cards.length; i++) { // Add two of each card - var cardOne = new MemoryCard(parameters.cards[i], id); - var cardTwo = new MemoryCard(parameters.cards[i], id); + var cardOne = new MemoryGame.Card(parameters.cards[i], id); + var cardTwo = new MemoryGame.Card(parameters.cards[i], id); addCard(cardOne, cardTwo); addCard(cardTwo, cardOne); } H5P.shuffleArray(cards); - + /** - * Public. Attach this game's html to the given container. + * Attach this game's html to the given container. * - * @param {jQuery} $container + * @param {H5P.jQuery} $container */ - this.attach = function ($container) { + self.attach = function ($container) { + // TODO: Only create on first! $container.addClass('h5p-memory-game').html(''); - + // Add cards to list var $list = $('
      '); for (var i = 0; i < cards.length; i++) { cards[i].appendTo($list); } - + if ($list.children().length) { $list.appendTo($container); - + $feedback = $('
      ' + parameters.l10n.feedback + '
      ').appendTo($container); - + // Add status bar - var $status = $('
      \ -
      ' + parameters.l10n.timeSpent + '
      \ -
      0:00
      \ -
      ' + parameters.l10n.cardTurns + '
      \ -
      0
      \ -
      ').appendTo($container); - - timer = new MemoryTimer($status.find('.h5p-time-spent')); - counter = new MemoryCounter($status.find('.h5p-card-turns')); - popup = new MemoryPop($container); - + var $status = $('
      ' + + '
      ' + parameters.l10n.timeSpent + '
      ' + + '
      0:00
      ' + + '
      ' + parameters.l10n.cardTurns + '
      ' + + '
      0
      ' + + '
      ').appendTo($container); + + timer = new MemoryGame.Timer($status.find('.h5p-time-spent')); + counter = new MemoryGame.Counter($status.find('.h5p-card-turns')); + popup = new MemoryGame.Popup($container); + $container.click(function () { popup.close(); }); } }; - }; - + } + + // Extends the event dispatcher + MemoryGame.prototype = Object.create(EventDispatcher.prototype); + MemoryGame.prototype.constructor = MemoryGame; + return MemoryGame; -})(H5P.jQuery); +})(H5P.EventDispatcher, H5P.jQuery); diff --git a/popup.js b/popup.js new file mode 100644 index 0000000..2973974 --- /dev/null +++ b/popup.js @@ -0,0 +1,44 @@ +(function (MemoryGame, $) { + + /** + * A dialog for reading the description of a card. + * + * @class H5P.MemoryGame.Popup + * @param {H5P.jQuery} $container + */ + MemoryGame.Popup = function ($container) { + var self = this; + + var closed; + + var $popup = $('
      ').appendTo($container); + var $desc = $popup.find('.h5p-memory-desc'); + var $image = $popup.find('.h5p-memory-image'); + + /** + * Show the popup. + * + * @param {string} desc + * @param {H5P.jQuery} $img + * @param {function} done + */ + self.show = function (desc, $img, done) { + $desc.text(desc); + $img.appendTo($image.html('')); + $popup.show(); + closed = done; + }; + + /** + * Close the popup. + */ + self.close = function () { + if (closed !== undefined) { + $popup.hide(); + closed(); + closed = undefined; + } + }; + }; + +})(H5P.MemoryGame, H5P.jQuery); diff --git a/timer.js b/timer.js new file mode 100644 index 0000000..39ca1f4 --- /dev/null +++ b/timer.js @@ -0,0 +1,94 @@ +(function (MemoryGame) { + + /** + * Keeps track of the time spent. + * + * @class H5P.MemoryGame.Timer + * @param {H5P.jQuery} $container + */ + MemoryGame.Timer = function ($container) { + var self = this; + var interval, started, totalTime = 0; + + /** + * Make timer more readable for humans. + * @private + * @param {Number} seconds + * @returns {String} + */ + var humanizeTime = function (seconds) { + var minutes = Math.floor(seconds / 60); + var hours = Math.floor(minutes / 60); + + minutes = minutes % 60; + seconds = Math.floor(seconds % 60); + + var time = ''; + + if (hours !== 0) { + time += hours + ':'; + + if (minutes < 10) { + time += '0'; + } + } + + time += minutes + ':'; + + if (seconds < 10) { + time += '0'; + } + + time += seconds; + + return time; + }; + + /** + * Update the timer element. + * + * @private + * @param {boolean} last + * @returns {number} + */ + var update = function (last) { + var currentTime = (new Date().getTime() - started); + $container.text(humanizeTime(Math.floor((totalTime + currentTime) / 1000))); + + if (last === true) { + // This is the last update, stop timing interval. + clearTimeout(interval); + } + else { + // Use setTimeout since setInterval isn't safe. + interval = setTimeout(function () { + update(); + }, 1000); + } + + return currentTime; + }; + + /** + * Starts the counter. + */ + self.start = function () { + if (started === undefined) { + started = new Date(); + update(); + } + }; + + /** + * Stops the counter. + */ + self.stop = function () { + if (started !== undefined) { + totalTime += update(true); + started = undefined; + } + }; + + }; + +})(H5P.MemoryGame); From 2ed388abee0bb9fed3a4fb53c1eae44f9992d541 Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sat, 28 Nov 2015 22:06:19 +0100 Subject: [PATCH 5/5] Add attempted, interacted and completed statements - HFJ-1402 --- memory-game.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/memory-game.js b/memory-game.js index 3f22418..98166b8 100644 --- a/memory-game.js +++ b/memory-game.js @@ -41,6 +41,7 @@ H5P.MemoryGame = (function (EventDispatcher, $) { timer.stop(); popup.show(desc, card.getImage(), function () { if (finished) { + self.triggerXAPIScored(1, 1, 'completed'); // Game has finished $feedback.addClass('h5p-show'); } @@ -51,6 +52,7 @@ H5P.MemoryGame = (function (EventDispatcher, $) { }); } else if (finished) { + self.triggerXAPIScored(1, 1, 'completed'); // Game has finished timer.stop(); $feedback.addClass('h5p-show'); @@ -72,6 +74,7 @@ H5P.MemoryGame = (function (EventDispatcher, $) { */ var addCard = function (card, mate) { card.on('flip', function () { + self.triggerXAPI('interacted'); // Keep track of time spent timer.start(); @@ -112,6 +115,7 @@ H5P.MemoryGame = (function (EventDispatcher, $) { * @param {H5P.jQuery} $container */ self.attach = function ($container) { + this.triggerXAPI('attempted'); // TODO: Only create on first! $container.addClass('h5p-memory-game').html('');