From 996b5e31f3357462f862f71ea23a957848e10ecc Mon Sep 17 00:00:00 2001 From: otacke Date: Sun, 2 Oct 2016 16:09:34 +0200 Subject: [PATCH 01/17] use H5P-Timer --- library.json | 12 ++++--- memory-game.js | 26 +++++++++++--- timer.js | 94 -------------------------------------------------- 3 files changed, 30 insertions(+), 102 deletions(-) delete mode 100644 timer.js diff --git a/library.json b/library.json index 38bfd60..ec6159c 100644 --- a/library.json +++ b/library.json @@ -20,14 +20,18 @@ { "path": "card.js" }, - { - "path": "timer.js" - }, { "path": "counter.js" }, { "path": "popup.js" } + ], + "preloadedDependencies": [ + { + "machineName": "H5P.Timer", + "majorVersion": 0, + "minorVersion": 2 + } ] -} \ No newline at end of file +} diff --git a/memory-game.js b/memory-game.js index 845fe3b..9e1fcf8 100644 --- a/memory-game.js +++ b/memory-game.js @@ -17,6 +17,23 @@ H5P.MemoryGame = (function (EventDispatcher, $) { var cards = []; var removed = 0; + /** + * Update the time on the screen + * + * @private + * @param {H5P.jQuery} $container - element to be updated + * @param {H5P.Timer} timer - the timer containing the time + */ + var updateDisplayTime = function($container, timer) { + var time = timer.getTime(); + var minutes = H5P.Timer.extractTimeElement(time, 'minutes'); + var seconds = H5P.Timer.extractTimeElement(time, 'seconds'); + if (seconds < 10) { + seconds = '0' + seconds; + } + $container.text(minutes + ':' + seconds); + } + /** * Check if these two cards belongs together. * @@ -42,7 +59,7 @@ H5P.MemoryGame = (function (EventDispatcher, $) { if (desc !== undefined) { // Pause timer and show desciption. - timer.stop(); + timer.pause(); popup.show(desc, card.getImage(), function () { if (finished) { // Game has finished @@ -50,7 +67,7 @@ H5P.MemoryGame = (function (EventDispatcher, $) { } else { // Popup is closed, continue. - timer.start(); + timer.play(); } }); } @@ -78,7 +95,7 @@ H5P.MemoryGame = (function (EventDispatcher, $) { card.on('flip', function () { self.triggerXAPI('interacted'); // Keep track of time spent - timer.start(); + timer.play(); if (flipped !== undefined) { var matie = flipped; @@ -142,7 +159,8 @@ H5P.MemoryGame = (function (EventDispatcher, $) { '
0
' + '').appendTo($container); - timer = new MemoryGame.Timer($status.find('.h5p-time-spent')); + timer = new H5P.Timer(100); + timer.notifyEvery(H5P.Timer.TYPE_CLOCK, 0, 1000, updateDisplayTime, [$status.find('.h5p-time-spent'), timer]); counter = new MemoryGame.Counter($status.find('.h5p-card-turns')); popup = new MemoryGame.Popup($container); diff --git a/timer.js b/timer.js deleted file mode 100644 index 39ca1f4..0000000 --- a/timer.js +++ /dev/null @@ -1,94 +0,0 @@ -(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 3b04b43972a0c720b880752a642fba2876698936 Mon Sep 17 00:00:00 2001 From: otacke Date: Mon, 3 Oct 2016 17:07:41 +0200 Subject: [PATCH 02/17] adhere to JSDoc style --- memory-game.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/memory-game.js b/memory-game.js index 9e1fcf8..8ab7648 100644 --- a/memory-game.js +++ b/memory-game.js @@ -18,11 +18,11 @@ H5P.MemoryGame = (function (EventDispatcher, $) { var removed = 0; /** - * Update the time on the screen + * Update the time on the screen. * * @private - * @param {H5P.jQuery} $container - element to be updated - * @param {H5P.Timer} timer - the timer containing the time + * @param {H5P.jQuery} $container - element to be updated. + * @param {H5P.Timer} timer - the timer containing the time. */ var updateDisplayTime = function($container, timer) { var time = timer.getTime(); @@ -160,7 +160,7 @@ H5P.MemoryGame = (function (EventDispatcher, $) { '').appendTo($container); timer = new H5P.Timer(100); - timer.notifyEvery(H5P.Timer.TYPE_CLOCK, 0, 1000, updateDisplayTime, [$status.find('.h5p-time-spent'), timer]); + timer.notifyEvery(H5P.Timer.TYPE_CLOCK, 0, 500, updateDisplayTime, [$status.find('.h5p-time-spent'), timer]); counter = new MemoryGame.Counter($status.find('.h5p-card-turns')); popup = new MemoryGame.Popup($container); From 8718f5d584b9add36baa15972d931916407a6ed2 Mon Sep 17 00:00:00 2001 From: otacke Date: Tue, 4 Oct 2016 19:50:44 +0200 Subject: [PATCH 03/17] increase required version of H5P-Timer --- library.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.json b/library.json index ec6159c..75ed150 100644 --- a/library.json +++ b/library.json @@ -31,7 +31,7 @@ { "machineName": "H5P.Timer", "majorVersion": 0, - "minorVersion": 2 + "minorVersion": 3 } ] } From d18cd343adb95ca54c22fb6ed33c06479a7e8ad4 Mon Sep 17 00:00:00 2001 From: otacke Date: Tue, 11 Oct 2016 18:47:26 +0200 Subject: [PATCH 04/17] change API calls to v0.4 of H5P-Timer --- memory-game.js | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/memory-game.js b/memory-game.js index 8ab7648..d5479e8 100644 --- a/memory-game.js +++ b/memory-game.js @@ -17,23 +17,6 @@ H5P.MemoryGame = (function (EventDispatcher, $) { var cards = []; var removed = 0; - /** - * Update the time on the screen. - * - * @private - * @param {H5P.jQuery} $container - element to be updated. - * @param {H5P.Timer} timer - the timer containing the time. - */ - var updateDisplayTime = function($container, timer) { - var time = timer.getTime(); - var minutes = H5P.Timer.extractTimeElement(time, 'minutes'); - var seconds = H5P.Timer.extractTimeElement(time, 'seconds'); - if (seconds < 10) { - seconds = '0' + seconds; - } - $container.text(minutes + ':' + seconds); - } - /** * Check if these two cards belongs together. * @@ -160,7 +143,16 @@ H5P.MemoryGame = (function (EventDispatcher, $) { '').appendTo($container); timer = new H5P.Timer(100); - timer.notifyEvery(H5P.Timer.TYPE_CLOCK, 0, 500, updateDisplayTime, [$status.find('.h5p-time-spent'), timer]); + timer.notify('every_tenth_second', function () { + var time = timer.getTime(); + var minutes = H5P.Timer.extractTimeElement(time, 'minutes'); + var seconds = H5P.Timer.extractTimeElement(time, 'seconds'); + if (seconds < 10) { + seconds = '0' + seconds; + } + $status.find('.h5p-time-spent').text(minutes + ':' + seconds); + }); + counter = new MemoryGame.Counter($status.find('.h5p-card-turns')); popup = new MemoryGame.Popup($container); From b21bcf552bbe99333fb3ba6e6c2c9e34a143af28 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Fri, 20 Jan 2017 11:15:45 +0100 Subject: [PATCH 05/17] Bump Timer required version --- library.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.json b/library.json index c9d9573..609534c 100644 --- a/library.json +++ b/library.json @@ -31,7 +31,7 @@ { "machineName": "H5P.Timer", "majorVersion": 0, - "minorVersion": 3 + "minorVersion": 4 } ] } From 20850b63467a1c830772ab27bcd76b8825a8315c Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Fri, 20 Jan 2017 11:58:08 +0100 Subject: [PATCH 06/17] Match two different images instead of clones This will resolve #5 --- card.js | 32 +++++++++++++++++++++++--------- language/nb.json | 10 ++++++++-- memory-game.js | 21 ++++++++++++++++----- semantics.json | 10 +++++++++- 4 files changed, 56 insertions(+), 17 deletions(-) diff --git a/card.js b/card.js index dca1639..dac20c2 100644 --- a/card.js +++ b/card.js @@ -4,28 +4,29 @@ * Controls all the operations for each card. * * @class H5P.MemoryGame.Card - * @param {Object} parameters - * @param {Number} id + * @param {Object} image + * @param {number} id + * @param {string} [description] */ - MemoryGame.Card = function (parameters, id) { + MemoryGame.Card = function (image, id, description) { var self = this; // Initialize event inheritance EventDispatcher.call(self); - var path = H5P.getPath(parameters.image.path, id); + var path = H5P.getPath(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) { + if (image.width !== undefined && image.height !== undefined) { + if (image.width > image.height) { width = a; - height = parameters.image.height * (width / parameters.image.width); + height = image.height * (width / image.width); margin = '' + ((a - height) / 2) + 'px 0 0 0'; } else { height = a; - width = parameters.image.width * (height / parameters.image.height); + width = image.width * (height / image.height); margin = '0 0 0 ' + ((a - width) / 2) + 'px'; } } @@ -61,7 +62,7 @@ * @returns {string} */ self.getDescription = function () { - return parameters.description; + return description; }; /** @@ -112,4 +113,17 @@ params.image.path !== undefined); }; + /** + * Checks to see if the card parameters should create cards with different + * images. + * + * @param {object} params + * @returns {boolean} + */ + MemoryGame.Card.hasTwoImages = function (params) { + return (params !== undefined && + params.match !== undefined && + params.match.path !== undefined); + }; + })(H5P.MemoryGame, H5P.EventDispatcher, H5P.jQuery); diff --git a/language/nb.json b/language/nb.json index b56939a..37bd07e 100644 --- a/language/nb.json +++ b/language/nb.json @@ -13,11 +13,17 @@ "englishLabel": "Image", "label": "Bilde" }, + { + "englishLabel": "Matching Image", + "label": "", + "englishDescription": "An optional image to match against instead of using two cards with the same image.", + "description": "Et valgfritt bilde som brukes av kort nummer to istedenfor å bruke to kort med samme bilde." + }, { "englishLabel": "Description", "label": "Beskrivelse", - "englishDescription": "A short text that is displayed once the two equal cards are found.", - "description": "En kort tekst som vises hver gang et kort-par er funnet." + "englishDescription": "An optional short text that will pop up once the two matching cards are found.", + "description": "En valgfri kort tekst som spretter opp når kort-paret er funnet." } ] } diff --git a/memory-game.js b/memory-game.js index d5479e8..a424e93 100644 --- a/memory-game.js +++ b/memory-game.js @@ -103,10 +103,21 @@ H5P.MemoryGame = (function (EventDispatcher, $) { // Initialize cards. for (var i = 0; i < parameters.cards.length; i++) { - if (MemoryGame.Card.isValid(parameters.cards[i])) { - // Add two of each card - var cardOne = new MemoryGame.Card(parameters.cards[i], id); - var cardTwo = new MemoryGame.Card(parameters.cards[i], id); + var cardParams = parameters.cards[i]; + if (MemoryGame.Card.isValid(cardParams)) { + // Create first card + var cardTwo, cardOne = new MemoryGame.Card(cardParams.image, id, cardParams.description); + + if (MemoryGame.Card.hasTwoImages(cardParams)) { + // Use matching image for card two + cardTwo = new MemoryGame.Card(cardParams.match, id, cardParams.description); + } + else { + // Add two cards with the same image + cardTwo = new MemoryGame.Card(cardParams.image, id, cardParams.description); + } + + // Add cards to card list for shuffeling addCard(cardOne, cardTwo); addCard(cardTwo, cardOne); } @@ -120,7 +131,7 @@ H5P.MemoryGame = (function (EventDispatcher, $) { */ self.attach = function ($container) { this.triggerXAPI('attempted'); - // TODO: Only create on first! + // TODO: Only create on first attach! $container.addClass('h5p-memory-game').html(''); // Add cards to list diff --git a/semantics.json b/semantics.json index 71eabad..7bfb801 100644 --- a/semantics.json +++ b/semantics.json @@ -19,6 +19,14 @@ "label": "Image", "importance": "high" }, + { + "name": "match", + "type": "image", + "label": "Matching Image", + "importance": "low", + "optional": true, + "description": "An optional image to match against instead of using two cards with the same image." + }, { "name": "description", "type": "text", @@ -26,7 +34,7 @@ "importance": "low", "maxLength": 150, "optional": true, - "description": "A short text that is displayed once the two equal cards are found." + "description": "An optional short text that will pop up once the two matching cards are found." } ] } From 9b6b2ba0e36eac7d0e6ff0826ee441dada53c994 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Fri, 20 Jan 2017 13:33:58 +0100 Subject: [PATCH 07/17] Fix cards disappearing when found in Firefox --- memory-game.css | 3 --- 1 file changed, 3 deletions(-) diff --git a/memory-game.css b/memory-game.css index 157ab81..33be0e2 100644 --- a/memory-game.css +++ b/memory-game.css @@ -30,9 +30,6 @@ html .h5p-memory-game > ul { -webkit-perspective: 400px; -moz-perspective: 400px; perspective: 400px; - -webkit-transform-style: preserve-3d; - -moz-transform-style: preserve-3d; - transform-style: preserve-3d; -webkit-transition: opacity 0.4s; -moz-transition: opacity 0.4s; transition: opacity 0.4s; From e60a425f2c5e260eb95aca3ee19d2ca8d3c973e0 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Fri, 20 Jan 2017 13:42:35 +0100 Subject: [PATCH 08/17] Add greyscale to matched pairs Makes them less distractive. --- memory-game.css | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/memory-game.css b/memory-game.css index 33be0e2..99c88b5 100644 --- a/memory-game.css +++ b/memory-game.css @@ -30,9 +30,9 @@ html .h5p-memory-game > ul { -webkit-perspective: 400px; -moz-perspective: 400px; perspective: 400px; - -webkit-transition: opacity 0.4s; - -moz-transition: opacity 0.4s; - transition: opacity 0.4s; + -webkit-transition: opacity 0.4s, filter 0.4s; + -moz-transition: opacity 0.4s, filter 0.4s; + transition: opacity 0.4s, filter 0.4s; } .h5p-memory-game .h5p-memory-card .h5p-back, .h5p-memory-game .h5p-memory-card .h5p-front { @@ -109,7 +109,8 @@ html .h5p-memory-game > ul { -ms-transform: scale(0,1.1); } .h5p-memory-game .h5p-memory-card.h5p-matched { - opacity: 0.25; + opacity: 0.3; + filter: grayscale(100%); } .h5p-memory-game .h5p-feedback { From 2ef07b2b206d19366f8259a98e1f0db82ad554e5 Mon Sep 17 00:00:00 2001 From: Oliver Tacke Date: Fri, 20 Jan 2017 14:15:59 +0100 Subject: [PATCH 09/17] fix bug --- memory-game.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/memory-game.js b/memory-game.js index d5479e8..16bfcfe 100644 --- a/memory-game.js +++ b/memory-game.js @@ -146,7 +146,7 @@ H5P.MemoryGame = (function (EventDispatcher, $) { timer.notify('every_tenth_second', function () { var time = timer.getTime(); var minutes = H5P.Timer.extractTimeElement(time, 'minutes'); - var seconds = H5P.Timer.extractTimeElement(time, 'seconds'); + var seconds = H5P.Timer.extractTimeElement(time, 'seconds') % 60; if (seconds < 10) { seconds = '0' + seconds; } From 7f800195e2886b994780161b057358e18b701594 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Mon, 23 Jan 2017 14:12:33 +0100 Subject: [PATCH 10/17] Put cards in square grid and add scaling --- card.js | 30 ++++++++++----------- memory-game.css | 57 ++++++++++++++++++++++++--------------- memory-game.js | 71 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 119 insertions(+), 39 deletions(-) diff --git a/card.js b/card.js index dac20c2..58bfcfb 100644 --- a/card.js +++ b/card.js @@ -17,21 +17,18 @@ var path = H5P.getPath(image.path, id); var width, height, margin, $card; - var a = 96; if (image.width !== undefined && image.height !== undefined) { if (image.width > image.height) { - width = a; - height = image.height * (width / image.width); - margin = '' + ((a - height) / 2) + 'px 0 0 0'; + width = '100%'; + height = 'auto'; } else { - height = a; - width = image.width * (height / image.height); - margin = '0 0 0 ' + ((a - width) / 2) + 'px'; + height = '100%'; + width = 'auto'; } } else { - width = height = a; + width = height = '100%'; } /** @@ -81,18 +78,19 @@ */ self.appendTo = function ($container) { // TODO: Translate alt attr - $card = $('
  • ' + + $card = $('
  • ' + '
    ' + '
    ' + - 'Memory Card' + + 'Memory Card' + '
    ' + - '
  • ') + '') .appendTo($container) - .children('.h5p-front') - .click(function () { - self.flip(); - }) - .end(); + .children('.h5p-memory-card') + .children('.h5p-front') + .click(function () { + self.flip(); + }) + .end(); }; }; diff --git a/memory-game.css b/memory-game.css index 99c88b5..e447afd 100644 --- a/memory-game.css +++ b/memory-game.css @@ -1,17 +1,21 @@ .h5p-memory-game { overflow: hidden; } -html .h5p-memory-game > ul { - list-style: none; - padding: 0; - margin: 0; - overflow: hidden; +.h5p-memory-game > ul { + list-style: none !important; + padding: 0.25em 0.5em !important; + /*padding: 0 !important;*/ + margin: 0 !important; + overflow: hidden !important; + font-size: 16px; + box-sizing: border-box; + -moz-box-sizing: border-box; } .h5p-memory-game .h5p-memory-card, .h5p-memory-game .h5p-memory-card .h5p-back, .h5p-memory-game .h5p-memory-card .h5p-front { - width: 100px; - height: 100px; + width: 6.25em; + height: 6.25em; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; @@ -19,17 +23,24 @@ html .h5p-memory-game > ul { } .h5p-memory-game img { -webkit-user-drag: none; + display: inline-block !important; + margin: auto !important; + vertical-align: middle; +} +.h5p-memory-game .h5p-memory-wrap { + float: left; + text-align: center; } .h5p-memory-game .h5p-memory-card { - float: left; + display: inline-block; outline: none; position: relative; - margin: 1em; + margin: 0.75em 0.5em; padding: 0; background: transparent; - -webkit-perspective: 400px; - -moz-perspective: 400px; - perspective: 400px; + -webkit-perspective: 25em; + -moz-perspective: 25em; + perspective: 25em; -webkit-transition: opacity 0.4s, filter 0.4s; -moz-transition: opacity 0.4s, filter 0.4s; transition: opacity 0.4s, filter 0.4s; @@ -61,17 +72,16 @@ html .h5p-memory-game > ul { } .h5p-memory-game .h5p-memory-card .h5p-front { cursor: pointer; + text-align: center; } .h5p-memory-game .h5p-memory-card .h5p-front:hover { background: #dfdfdf; } .h5p-memory-game .h5p-memory-card .h5p-front:before { - position: absolute; content: "?"; - font-size: 60px; + font-size: 3.75em; color: #909090; - line-height: 100px; - left: 35px; + line-height: 1.67em; } .h5p-memory-game .h5p-memory-card .h5p-front:after { content: ""; @@ -88,6 +98,8 @@ html .h5p-memory-game > ul { background-image: radial-gradient(ellipse closest-side, rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0) 100%); } .h5p-memory-game .h5p-memory-card .h5p-back { + line-height: 5.9em; + text-align: center; background: #f0f0f0; -webkit-transform: rotateY(-180deg); -moz-transform: rotateY(-180deg); @@ -163,9 +175,9 @@ html .h5p-memory-game > ul { left: 50%; margin-left: -10em; box-shadow: 0 0 1em #666; - -webkit-transform: translateZ(24px); - -moz-transform: translateZ(24px); - transform: translateZ(24px); + -webkit-transform: translateZ(1.5em); + -moz-transform: translateZ(1.5em); + transform: translateZ(1.5em); } .h5p-memory-game .h5p-memory-image { float: left; @@ -175,6 +187,9 @@ html .h5p-memory-game > ul { -moz-box-sizing: border-box; border-radius: 4px; background: #f0f0f0; - width: 100px; - height: 100px; + width: 6.25em; + height: 6.25em; +} +.h5p-memory-game .h5p-row-break { + clear: left; } diff --git a/memory-game.js b/memory-game.js index a424e93..2b42e5f 100644 --- a/memory-game.js +++ b/memory-game.js @@ -1,5 +1,11 @@ H5P.MemoryGame = (function (EventDispatcher, $) { + // We don't want to go smaller than 100px per card(including the required margin) + var CARD_MIN_SIZE = 100; // PX + var CARD_STD_SIZE = 116; // PX + var STD_FONT_SIZE = 16; // PX + var LIST_PADDING = 1; // EMs + /** * Memory Game Constructor * @@ -13,7 +19,7 @@ H5P.MemoryGame = (function (EventDispatcher, $) { // Initialize event inheritance EventDispatcher.call(self); - var flipped, timer, counter, popup, $feedback; + var flipped, timer, counter, popup, $feedback, $wrapper, maxWidth, numCols; var cards = []; var removed = 0; @@ -132,7 +138,7 @@ H5P.MemoryGame = (function (EventDispatcher, $) { self.attach = function ($container) { this.triggerXAPI('attempted'); // TODO: Only create on first attach! - $container.addClass('h5p-memory-game').html(''); + $wrapper = $container.addClass('h5p-memory-game').html(''); // Add cards to list var $list = $('
      '); @@ -172,6 +178,67 @@ H5P.MemoryGame = (function (EventDispatcher, $) { }); } }; + + /** + * Will try to scale the game so that it fits within its container. + * Puts the cards into a grid layout to make it as square as possible –  + * which improves the playability on multiple devices. + * + * @private + */ + function scaleGameSize() { + + // Check how much space we have available + var $list = $wrapper.children('ul'); + var newMaxWidth = parseFloat(window.getComputedStyle($list[0]).width); + if (maxWidth === newMaxWidth) { + return; // Same size, no need to recalculate + } + else { + maxWidth = newMaxWidth; + } + + // Get the card holders + var $elements = $list.children(); + if ($elements.length < 4) { + return; // No need to proceed + } + + // Determine the optimal number of columns + var newNumCols = Math.ceil(Math.sqrt($elements.length)); + + // Do not exceed the max number of columns + var maxCols = Math.floor(maxWidth / CARD_MIN_SIZE); + if (newNumCols > maxCols) { + newNumCols = maxCols; + } + + if (numCols !== newNumCols) { + // We need to change layout + numCols = newNumCols; + + // Calculate new column size in percentage and round it down (we don't + // want things sticking out…) + var colSize = Math.floor((100 / numCols) * 10000) / 10000; + $elements.css('width', colSize + '%').each(function (i, e) { + if (i === numCols) { + $(e).addClass('h5p-row-break'); + } + }); + } + + // Calculate how much one percentage of the standard/default size is + var onePercentage = ((CARD_STD_SIZE * numCols) + STD_FONT_SIZE) / 100; + var paddingSize = (STD_FONT_SIZE * LIST_PADDING) / onePercentage; + var cardSize = (100 - paddingSize) / numCols; + var fontSize = (((maxWidth * (cardSize / 100)) * STD_FONT_SIZE) / CARD_STD_SIZE); + + // We use font size to evenly scale all parts of the cards. + $list.css('font-size', fontSize + 'px'); + // due to rounding errors in browsers the margins may vary a bit… + } + + self.on('resize', scaleGameSize); } // Extends the event dispatcher From 4a53203247e034f06199a15e688b9881b1a07a35 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Mon, 23 Jan 2017 14:32:33 +0100 Subject: [PATCH 11/17] Clean up --- memory-game.css | 1 - 1 file changed, 1 deletion(-) diff --git a/memory-game.css b/memory-game.css index e447afd..2e61518 100644 --- a/memory-game.css +++ b/memory-game.css @@ -4,7 +4,6 @@ .h5p-memory-game > ul { list-style: none !important; padding: 0.25em 0.5em !important; - /*padding: 0 !important;*/ margin: 0 !important; overflow: hidden !important; font-size: 16px; From 0f0f1c693a57ab522b2660e4fd842ce5296237de Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Mon, 23 Jan 2017 14:41:41 +0100 Subject: [PATCH 12/17] Set crop ratio for images to 1:1 --- semantics.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/semantics.json b/semantics.json index 7bfb801..352e123 100644 --- a/semantics.json +++ b/semantics.json @@ -17,7 +17,8 @@ "name": "image", "type": "image", "label": "Image", - "importance": "high" + "importance": "high", + "ratio": 1 }, { "name": "match", @@ -25,7 +26,8 @@ "label": "Matching Image", "importance": "low", "optional": true, - "description": "An optional image to match against instead of using two cards with the same image." + "description": "An optional image to match against instead of using two cards with the same image.", + "ratio": 1 }, { "name": "description", From e308d4a69e3a0a888116f9a1d2db7e6a1cb29125 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Mon, 23 Jan 2017 14:45:55 +0100 Subject: [PATCH 13/17] Help avoid markup for list items --- memory-game.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/memory-game.css b/memory-game.css index 2e61518..87f96a6 100644 --- a/memory-game.css +++ b/memory-game.css @@ -29,6 +29,9 @@ .h5p-memory-game .h5p-memory-wrap { float: left; text-align: center; + background-image: none !important; + margin: 0 !important; + padding: 0 !important; } .h5p-memory-game .h5p-memory-card { display: inline-block; From 6d1ceccecd7b9e334290c4ef56fcc9dc0365875c Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Mon, 23 Jan 2017 15:46:06 +0100 Subject: [PATCH 14/17] Add behavioural settings for the game Option to use grid (implemented earlier). Option for picking a given number of images. Option to retry (currently, not working). Add upgrade script to preserve old behavior for old games. --- library.json | 4 ++-- memory-game.js | 45 ++++++++++++++++++++++++++++++++++++++++----- semantics.json | 35 ++++++++++++++++++++++++++++++++++- upgrades.js | 47 ++++++++++++++++++++++++++++++++++++----------- 4 files changed, 112 insertions(+), 19 deletions(-) diff --git a/library.json b/library.json index 609534c..c0e81c0 100644 --- a/library.json +++ b/library.json @@ -2,8 +2,8 @@ "title": "Memory Game", "description": "See how many cards you can remember!", "majorVersion": 1, - "minorVersion": 1, - "patchVersion": 11, + "minorVersion": 2, + "patchVersion": 0, "runnable": 1, "author": "Amendor AS", "license": "MIT", diff --git a/memory-game.js b/memory-game.js index b4d757a..5165c1c 100644 --- a/memory-game.js +++ b/memory-game.js @@ -53,6 +53,7 @@ H5P.MemoryGame = (function (EventDispatcher, $) { if (finished) { // Game has finished $feedback.addClass('h5p-show'); + if (parameters.behaviour && parameters.behaviour.allowRetry) { /* TODO */ } } else { // Popup is closed, continue. @@ -64,6 +65,7 @@ H5P.MemoryGame = (function (EventDispatcher, $) { // Game has finished timer.stop(); $feedback.addClass('h5p-show'); + if (parameters.behaviour && parameters.behaviour.allowRetry) { /* TODO */ } } } else { @@ -107,9 +109,39 @@ H5P.MemoryGame = (function (EventDispatcher, $) { cards.push(card); }; + /** + * @private + */ + var getCardsToUse = function () { + var numCardsToUse = (parameters.behaviour && parameters.behaviour.numCardsToUse ? parseInt(parameters.behaviour.numCardsToUse) : 0); + if (numCardsToUse <= 2 || numCardsToUse >= parameters.cards.length) { + // Use all cards + return parameters.cards; + } + + // Pick random cards from pool + var cardsToUse = []; + var pickedCardsMap = {}; + + var numPicket = 0; + while (numPicket < numCardsToUse) { + var pickIndex = Math.floor(Math.random() * parameters.cards.length); + if (pickedCardsMap[pickIndex]) { + continue; // Already picked, try again! + } + + cardsToUse.push(parameters.cards[pickIndex]); + pickedCardsMap[pickIndex] = true; + numPicket++; + } + + return cardsToUse; + }; + // Initialize cards. - for (var i = 0; i < parameters.cards.length; i++) { - var cardParams = parameters.cards[i]; + var cardsToUse = getCardsToUse(); + for (var i = 0; i < cardsToUse.length; i++) { + var cardParams = cardsToUse[i]; if (MemoryGame.Card.isValid(cardParams)) { // Create first card var cardTwo, cardOne = new MemoryGame.Card(cardParams.image, id, cardParams.description); @@ -186,10 +218,11 @@ H5P.MemoryGame = (function (EventDispatcher, $) { * * @private */ - function scaleGameSize() { + var scaleGameSize = function () { // Check how much space we have available var $list = $wrapper.children('ul'); + var newMaxWidth = parseFloat(window.getComputedStyle($list[0]).width); if (maxWidth === newMaxWidth) { return; // Same size, no need to recalculate @@ -236,9 +269,11 @@ H5P.MemoryGame = (function (EventDispatcher, $) { // We use font size to evenly scale all parts of the cards. $list.css('font-size', fontSize + 'px'); // due to rounding errors in browsers the margins may vary a bit… - } + }; - self.on('resize', scaleGameSize); + if (parameters.behaviour && parameters.behaviour.useGrid && cardsToUse.length) { + self.on('resize', scaleGameSize); + } } // Extends the event dispatcher diff --git a/semantics.json b/semantics.json index 352e123..4faf9bf 100644 --- a/semantics.json +++ b/semantics.json @@ -5,7 +5,7 @@ "label": "Cards", "importance": "high", "entity": "card", - "min": 1, + "min": 2, "max": 100, "field": { "type": "group", @@ -41,6 +41,39 @@ ] } }, + { + "name": "behaviour", + "type": "group", + "label": "Behavioural settings", + "importance": "low", + "description": "These options will let you control how the game behaves.", + "optional": true, + "fields": [ + { + "name": "useGrid", + "type": "boolean", + "label": "Put the cards in a grid layout", + "importance": "low", + "default": true + }, + { + "name": "numCardsToUse", + "type": "number", + "label": "Number of cards to use", + "description": "Setting this to a number greater than 2 will make the game pick random cards from the list of cards.", + "importance": "low", + "optional": true, + "min": 2 + }, + { + "name": "allowRetry", + "type": "boolean", + "label": "Add button for retrying when the game is over", + "importance": "low", + "default": true + } + ] + }, { "label": "Localization", "importance": "low", diff --git a/upgrades.js b/upgrades.js index f359e53..42c39bd 100644 --- a/upgrades.js +++ b/upgrades.js @@ -3,18 +3,43 @@ var H5PUpgrades = H5PUpgrades || {}; H5PUpgrades['H5P.MemoryGame'] = (function ($) { return { 1: { - 1: { - contentUpgrade: function (parameters, finished) { - // Move card images into card objects, allows for additonal properties. - for (var i = 0; i < parameters.cards.length; i++) { - parameters.cards[i] = { - image: parameters.cards[i] - }; - } - - finished(null, parameters); + /** + * Asynchronous content upgrade hook. + * Upgrades content parameters to support Memory Game 1.1. + * + * Move card images into card object as this allows for additonal + * properties for each card. + * + * @params {object} parameters + * @params {function} finished + */ + 1: function (parameters, finished) { + for (var i = 0; i < parameters.cards.length; i++) { + parameters.cards[i] = { + image: parameters.cards[i] + }; } + + finished(null, parameters); + }, + + /** + * Asynchronous content upgrade hook. + * Upgrades content parameters to support Memory Game 1.2. + * + * Add default behavioural settings for the new options. + * + * @params {object} parameters + * @params {function} finished + */ + 2: function (parameters, finished) { + + parameters.behaviour = {}; + parameters.behaviour.useGrid = false; + parameters.behaviour.allowRetry = false; + + finished(null, parameters); } } }; -})(H5P.jQuery); \ No newline at end of file +})(H5P.jQuery); From e8622a3f42458bd1826f0b291e69a88e806fbad0 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Tue, 24 Jan 2017 08:35:21 +0100 Subject: [PATCH 15/17] Improve positioning of description dialog --- memory-game.css | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/memory-game.css b/memory-game.css index 87f96a6..f491184 100644 --- a/memory-game.css +++ b/memory-game.css @@ -173,13 +173,12 @@ padding: 1em; width: 20em; position: absolute; - top: 2em; + top: 50%; left: 50%; - margin-left: -10em; box-shadow: 0 0 1em #666; - -webkit-transform: translateZ(1.5em); - -moz-transform: translateZ(1.5em); - transform: translateZ(1.5em); + -webkit-transform: translate(-50%,-50%); + -moz-transform: translate(-50%,-50%); + transform: translate(-50%,-50%); } .h5p-memory-game .h5p-memory-image { float: left; From 34ac93cce88148e5aa2c0082cf85939365c1f124 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Tue, 24 Jan 2017 08:47:18 +0100 Subject: [PATCH 16/17] Update translations with new semantic fields --- language/ar.json | 28 ++++++++++++++++++++++++++++ language/de.json | 30 +++++++++++++++++++++++++++++- language/fr.json | 28 ++++++++++++++++++++++++++++ language/it.json | 30 +++++++++++++++++++++++++++++- language/nb.json | 22 ++++++++++++++++++++++ 5 files changed, 136 insertions(+), 2 deletions(-) diff --git a/language/ar.json b/language/ar.json index 6ae0267..6b999ef 100644 --- a/language/ar.json +++ b/language/ar.json @@ -9,6 +9,12 @@ { "label": "الصورة" }, + { + "englishLabel": "Matching Image", + "label": "Matching Image", + "englishDescription": "An optional image to match against instead of using two cards with the same image.", + "description": "An optional image to match against instead of using two cards with the same image." + }, { "label": "الوصف", "description": "نص قصير يتم عرضه مرة واحدة علي اثنين من البطاقات متساوية" @@ -16,6 +22,28 @@ ] } }, + { + "englishLabel": "Behavioural settings", + "label": "Behavioural settings", + "englishDescription": "These options will let you control how the game behaves.", + "description": "These options will let you control how the game behaves.", + "fields": [ + { + "englishLabel": "Put the cards in a grid layout", + "label": "Put the cards in a grid layout" + }, + { + "englishLabel": "Number of cards to use", + "label": "Number of cards to use", + "englishDescription": "Setting this to a number greater than 2 will make the game pick random cards from the list of cards.", + "description": "Setting this to a number greater than 2 will make the game pick random cards from the list of cards." + }, + { + "englishLabel": "Add button for retrying when the game is over", + "label": "Add button for retrying when the game is over" + } + ] + }, { "label": "الأقلمة", "fields": [ diff --git a/language/de.json b/language/de.json index 95c034e..e84760f 100644 --- a/language/de.json +++ b/language/de.json @@ -9,6 +9,12 @@ { "label": "Bild" }, + { + "englishLabel": "Matching Image", + "label": "Matching Image", + "englishDescription": "An optional image to match against instead of using two cards with the same image.", + "description": "An optional image to match against instead of using two cards with the same image." + }, { "label": "Beschreibung", "description": "Ein kurzer Text, der angezeigt wird, sobald zwei identische Karten gefunden werden." @@ -16,6 +22,28 @@ ] } }, + { + "englishLabel": "Behavioural settings", + "label": "Behavioural settings", + "englishDescription": "These options will let you control how the game behaves.", + "description": "These options will let you control how the game behaves.", + "fields": [ + { + "englishLabel": "Put the cards in a grid layout", + "label": "Put the cards in a grid layout" + }, + { + "englishLabel": "Number of cards to use", + "label": "Number of cards to use", + "englishDescription": "Setting this to a number greater than 2 will make the game pick random cards from the list of cards.", + "description": "Setting this to a number greater than 2 will make the game pick random cards from the list of cards." + }, + { + "englishLabel": "Add button for retrying when the game is over", + "label": "Add button for retrying when the game is over" + } + ] + }, { "label": "Übersetzung", "fields": [ @@ -34,4 +62,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/language/fr.json b/language/fr.json index e00969e..aa3b53b 100644 --- a/language/fr.json +++ b/language/fr.json @@ -9,6 +9,12 @@ { "label": "Image" }, + { + "englishLabel": "Matching Image", + "label": "Matching Image", + "englishDescription": "An optional image to match against instead of using two cards with the same image.", + "description": "An optional image to match against instead of using two cards with the same image." + }, { "label": "Description", "description": "Petit texte affiché quand deux cartes identiques sont trouvées." @@ -16,6 +22,28 @@ ] } }, + { + "englishLabel": "Behavioural settings", + "label": "Behavioural settings", + "englishDescription": "These options will let you control how the game behaves.", + "description": "These options will let you control how the game behaves.", + "fields": [ + { + "englishLabel": "Put the cards in a grid layout", + "label": "Put the cards in a grid layout" + }, + { + "englishLabel": "Number of cards to use", + "label": "Number of cards to use", + "englishDescription": "Setting this to a number greater than 2 will make the game pick random cards from the list of cards.", + "description": "Setting this to a number greater than 2 will make the game pick random cards from the list of cards." + }, + { + "englishLabel": "Add button for retrying when the game is over", + "label": "Add button for retrying when the game is over" + } + ] + }, { "label": "Interface", "fields": [ diff --git a/language/it.json b/language/it.json index 4adb03f..5b58c96 100644 --- a/language/it.json +++ b/language/it.json @@ -9,6 +9,12 @@ { "label": "Immagine" }, + { + "englishLabel": "Matching Image", + "label": "Matching Image", + "englishDescription": "An optional image to match against instead of using two cards with the same image.", + "description": "An optional image to match against instead of using two cards with the same image." + }, { "label": "Descrizione", "description": "Breve testo visualizzato quando due carte uguali vengono trovate." @@ -16,6 +22,28 @@ ] } }, + { + "englishLabel": "Behavioural settings", + "label": "Behavioural settings", + "englishDescription": "These options will let you control how the game behaves.", + "description": "These options will let you control how the game behaves.", + "fields": [ + { + "englishLabel": "Put the cards in a grid layout", + "label": "Put the cards in a grid layout" + }, + { + "englishLabel": "Number of cards to use", + "label": "Number of cards to use", + "englishDescription": "Setting this to a number greater than 2 will make the game pick random cards from the list of cards.", + "description": "Setting this to a number greater than 2 will make the game pick random cards from the list of cards." + }, + { + "englishLabel": "Add button for retrying when the game is over", + "label": "Add button for retrying when the game is over" + } + ] + }, { "label": "Localizzazione", "fields": [ @@ -31,4 +59,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/language/nb.json b/language/nb.json index 37bd07e..a8b0946 100644 --- a/language/nb.json +++ b/language/nb.json @@ -28,6 +28,28 @@ ] } }, + { + "englishLabel": "Behavioural settings", + "label": "Innstillinger for oppførsel", + "englishDescription": "These options will let you control how the game behaves.", + "description": "Disse instillingene lar deg bestemme hvordan spillet skal oppføre seg.", + "fields": [ + { + "englishLabel": "Put the cards in a grid layout", + "label": "Putt kortene i et rutenett" + }, + { + "englishLabel": "Number of cards to use", + "label": "Antall kort som skal brukes", + "englishDescription": "Setting this to a number greater than 2 will make the game pick random cards from the list of cards.", + "description": "Ved å sette antallet høyere enn 2 vil spillet plukke tilfeldige kort fra listen over kort." + }, + { + "englishLabel": "Add button for retrying when the game is over", + "label": "Legg til knapp for å prøve på nytt når spillet er over" + } + ] + }, { "englishLabel": "Localization", "label": "Oversettelser", From 9306ec6a3e0db7c542e71fda2a9048ea41a71248 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Tue, 24 Jan 2017 08:49:30 +0100 Subject: [PATCH 17/17] Add missing norwegian label --- language/nb.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/language/nb.json b/language/nb.json index a8b0946..b90dd68 100644 --- a/language/nb.json +++ b/language/nb.json @@ -15,7 +15,7 @@ }, { "englishLabel": "Matching Image", - "label": "", + "label": "Tilhørende bilde", "englishDescription": "An optional image to match against instead of using two cards with the same image.", "description": "Et valgfritt bilde som brukes av kort nummer to istedenfor å bruke to kort med samme bilde." },