From 0bc76c6ce8855f57c71def57637d2ab94163990b Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Mon, 13 Feb 2017 14:42:34 +0100 Subject: [PATCH] Add support for try again --- card.js | 19 +++++++- counter.js | 18 +++++++- library.json | 9 ++-- memory-game.css | 14 ++++++ memory-game.js | 117 ++++++++++++++++++++++++++++++++++++++---------- popup.js | 1 + timer.js | 50 +++++++++++++++++++++ 7 files changed, 200 insertions(+), 28 deletions(-) create mode 100644 timer.js diff --git a/card.js b/card.js index 58bfcfb..9b1aa90 100644 --- a/card.js +++ b/card.js @@ -4,11 +4,13 @@ * Controls all the operations for each card. * * @class H5P.MemoryGame.Card + * @extends H5P.EventDispatcher * @param {Object} image * @param {number} id * @param {string} [description] */ MemoryGame.Card = function (image, id, description) { + /** @alias H5P.MemoryGame.Card# */ var self = this; // Initialize event inheritance @@ -53,6 +55,13 @@ $card.addClass('h5p-matched'); }; + /** + * Reset card to natural state + */ + self.reset = function () { + $card[0].classList.remove('h5p-flipped', 'h5p-matched'); + }; + /** * Get card description. * @@ -91,7 +100,15 @@ self.flip(); }) .end(); - }; + }; + + /** + * Re-append to parent container + */ + self.reAppend = function () { + var parent = $card[0].parentElement.parentElement; + parent.appendChild($card[0].parentElement); + }; }; // Extends the event dispatcher diff --git a/counter.js b/counter.js index 39343c8..d0e6c75 100644 --- a/counter.js +++ b/counter.js @@ -7,16 +7,32 @@ * @param {H5P.jQuery} $container */ MemoryGame.Counter = function ($container) { + /** @alias H5P.MemoryGame.Counter# */ var self = this; var current = 0; + /** + * @private + */ + var update = function () { + $container[0].innerText = current; + }; + /** * Increment the counter. */ self.increment = function () { current++; - $container.text(current); + update(); + }; + + /** + * Revert counter back to its natural state + */ + self.reset = function () { + current = 0; + update(); }; }; diff --git a/library.json b/library.json index 411aab1..79cb421 100644 --- a/library.json +++ b/library.json @@ -3,9 +3,9 @@ "description": "See how many cards you can remember!", "majorVersion": 1, "minorVersion": 2, - "patchVersion": 1, + "patchVersion": 2, "runnable": 1, - "author": "Amendor AS", + "author": "Joubel AS", "license": "MIT", "machineName": "H5P.MemoryGame", "preloadedCss": [ @@ -25,6 +25,9 @@ }, { "path": "popup.js" + }, + { + "path": "timer.js" } ], "preloadedDependencies": [ @@ -34,4 +37,4 @@ "minorVersion": 4 } ] -} \ No newline at end of file +} diff --git a/memory-game.css b/memory-game.css index afe44ce..cb3f9ef 100644 --- a/memory-game.css +++ b/memory-game.css @@ -198,3 +198,17 @@ .h5p-memory-game .h5p-memory-desc { margin-left: 7em; } +.h5p-memory-reset { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%,-50%); + cursor: pointer; + font-style: italic; + text-shadow: 0 0 0.5em white; + padding: 0.125em 0.25em; + line-height: 1; +} +.h5p-memory-reset:focus { + outline: dashed pink; +} diff --git a/memory-game.js b/memory-game.js index e3d8794..d102067 100644 --- a/memory-game.js +++ b/memory-game.js @@ -9,11 +9,13 @@ H5P.MemoryGame = (function (EventDispatcher, $) { /** * Memory Game Constructor * - * @class + * @class H5P.MemoryGame + * @extends H5P.EventDispatcher * @param {Object} parameters * @param {Number} id */ function MemoryGame(parameters, id) { + /** @alias H5P.MemoryGame# */ var self = this; // Initialize event inheritance @@ -39,10 +41,10 @@ H5P.MemoryGame = (function (EventDispatcher, $) { removed += 2; - var finished = (removed === cards.length); + var isFinished = (removed === cards.length); var desc = card.getDescription(); - if (finished) { + if (isFinished) { self.triggerXAPIScored(1, 1, 'completed'); } @@ -50,10 +52,9 @@ H5P.MemoryGame = (function (EventDispatcher, $) { // Pause timer and show desciption. timer.pause(); popup.show(desc, card.getImage(), function () { - if (finished) { - // Game has finished - $feedback.addClass('h5p-show'); - if (parameters.behaviour && parameters.behaviour.allowRetry) { /* TODO */ } + if (isFinished) { + // Game done + finished(); } else { // Popup is closed, continue. @@ -61,11 +62,9 @@ H5P.MemoryGame = (function (EventDispatcher, $) { } }); } - else if (finished) { - // Game has finished - timer.stop(); - $feedback.addClass('h5p-show'); - if (parameters.behaviour && parameters.behaviour.allowRetry) { /* TODO */ } + else if (isFinished) { + // Game done + finished(); } } else { @@ -75,6 +74,88 @@ H5P.MemoryGame = (function (EventDispatcher, $) { } }; + /** + * Game has finished! + * @private + */ + var finished = function () { + timer.stop(); + $feedback.addClass('h5p-show'); + if (parameters.behaviour && parameters.behaviour.allowRetry) { + // Create retry button + var retryButton = createButton('reset', 'Try again?', function () { + // Trigger handler (action) + + resetGame(); + + // Remove button from DOM + $wrapper[0].removeChild(this); + }); + + // Same size as cards + retryButton.style.fontSize = $wrapper.children('ul')[0].style.fontSize; + + $wrapper[0].appendChild(retryButton); // Add to DOM + } + }; + + /** + * Shuffle the cards and restart the game! + * @private + */ + var resetGame = function () { + + // Reset cards + removed = 0; + for (var i = 0; i < cards.length; i++) { + cards[i].reset(); + } + + // Remove feedback + $feedback[0].classList.remove('h5p-show'); + + // Reset timer and counter + timer.reset(); + counter.reset(); + + // Randomize cards + H5P.shuffleArray(cards); + + setTimeout(function () { + // Re-append to DOM after flipping back + for (var i = 0; i < cards.length; i++) { + cards[i].reAppend(); + } + + // Scale new layout + $wrapper.children('ul').children('.h5p-row-break').removeClass('h5p-row-break'); + maxWidth = -1; + self.trigger('resize'); + }, 600); + }; + + /** + * Game has finished! + * @private + */ + var createButton = function (name, label, action) { + var buttonElement = document.createElement('div'); + buttonElement.classList.add('h5p-memory-' + name); + buttonElement.innerHTML = label; + buttonElement.setAttribute('role', 'button'); + buttonElement.tabIndex = 0; + buttonElement.addEventListener('click', function (event) { + action.apply(buttonElement); + }, false); + buttonElement.addEventListener('keypress', function (event) { + if (event.which === 13 || event.which === 32) { // Enter or Space key + event.preventDefault(); + action.apply(buttonElement); + } + }, false); + return buttonElement; + }; + /** * Adds card to card list and set up a flip listener. * @@ -191,17 +272,7 @@ H5P.MemoryGame = (function (EventDispatcher, $) { '
0
' + '').appendTo($container); - timer = new H5P.Timer(100); - timer.notify('every_tenth_second', function () { - var time = timer.getTime(); - var minutes = H5P.Timer.extractTimeElement(time, 'minutes'); - var seconds = H5P.Timer.extractTimeElement(time, 'seconds') % 60; - if (seconds < 10) { - seconds = '0' + seconds; - } - $status.find('.h5p-time-spent').text(minutes + ':' + seconds); - }); - + timer = new MemoryGame.Timer($status.find('.h5p-time-spent')[0]); counter = new MemoryGame.Counter($status.find('.h5p-card-turns')); popup = new MemoryGame.Popup($container); diff --git a/popup.js b/popup.js index 6ef14b9..bee3ceb 100644 --- a/popup.js +++ b/popup.js @@ -7,6 +7,7 @@ * @param {H5P.jQuery} $container */ MemoryGame.Popup = function ($container) { + /** @alias H5P.MemoryGame.Popup# */ var self = this; var closed; diff --git a/timer.js b/timer.js new file mode 100644 index 0000000..339392e --- /dev/null +++ b/timer.js @@ -0,0 +1,50 @@ +(function (MemoryGame, Timer) { + + /** + * Adapter between memory game and H5P.Timer + * + * @class H5P.MemoryGame.Timer + * @extends H5P.Timer + * @param {Element} element + */ + MemoryGame.Timer = function (element) { + /** @alias H5P.MemoryGame.Timer# */ + var self = this; + + // Initialize event inheritance + Timer.call(self, 100); + + /** @private {string} */ + var naturalState = element.innerText; + + /** + * Set up callback for time updates. + * Formats time stamp for humans. + * + * @private + */ + var update = function () { + var time = self.getTime(); + + var minutes = Timer.extractTimeElement(time, 'minutes'); + var seconds = Timer.extractTimeElement(time, 'seconds') % 60; + if (seconds < 10) { + seconds = '0' + seconds; + } + + element.innerText = minutes + ':' + seconds; + }; + + // Setup default behavior + self.notify('every_tenth_second', update); + self.on('reset', function () { + element.innerText = naturalState; + self.notify('every_tenth_second', update); + }); + }; + + // Inheritance + MemoryGame.Timer.prototype = Object.create(Timer.prototype); + MemoryGame.Timer.prototype.constructor = MemoryGame.Timer; + +})(H5P.MemoryGame, H5P.Timer);