Start improving accessibility

pull/30/head^2
Frode Petterson 2017-06-20 16:47:07 +02:00
parent aead8728d8
commit 196c112243
3 changed files with 126 additions and 16 deletions

86
card.js
View File

@ -7,10 +7,11 @@
* @extends H5P.EventDispatcher * @extends H5P.EventDispatcher
* @param {Object} image * @param {Object} image
* @param {number} id * @param {number} id
* @param {string} alt
* @param {string} [description] * @param {string} [description]
* @param {Object} [styles] * @param {Object} [styles]
*/ */
MemoryGame.Card = function (image, id, description, styles) { MemoryGame.Card = function (image, id, alt, description, styles) {
/** @alias H5P.MemoryGame.Card# */ /** @alias H5P.MemoryGame.Card# */
var self = this; var self = this;
@ -18,7 +19,7 @@
EventDispatcher.call(self); EventDispatcher.call(self);
var path = H5P.getPath(image.path, id); var path = H5P.getPath(image.path, id);
var width, height, margin, $card; var width, height, margin, $card, $wrapper, removedState, flippedState;
if (image.width !== undefined && image.height !== undefined) { if (image.width !== undefined && image.height !== undefined) {
if (image.width > image.height) { if (image.width > image.height) {
@ -40,6 +41,7 @@
self.flip = function () { self.flip = function () {
$card.addClass('h5p-flipped'); $card.addClass('h5p-flipped');
self.trigger('flip'); self.trigger('flip');
flippedState = true;
}; };
/** /**
@ -47,6 +49,7 @@
*/ */
self.flipBack = function () { self.flipBack = function () {
$card.removeClass('h5p-flipped'); $card.removeClass('h5p-flipped');
flippedState = false;
}; };
/** /**
@ -54,6 +57,7 @@
*/ */
self.remove = function () { self.remove = function () {
$card.addClass('h5p-matched'); $card.addClass('h5p-matched');
removedState = true;
}; };
/** /**
@ -88,27 +92,85 @@
*/ */
self.appendTo = function ($container) { self.appendTo = function ($container) {
// TODO: Translate alt attr // TODO: Translate alt attr
$card = $('<li class="h5p-memory-wrap"><div class="h5p-memory-card" role="button" tabindex="1">' + $wrapper = $('<li class="h5p-memory-wrap" tabindex="-1" role="button"><div class="h5p-memory-card">' +
'<div class="h5p-front"' + (styles && styles.front ? styles.front : '') + '>' + (styles && styles.backImage ? '' : '<span></span>') + '</div>' + '<div class="h5p-front"' + (styles && styles.front ? styles.front : '') + '>' + (styles && styles.backImage ? '' : '<span></span>') + '</div>' +
'<div class="h5p-back"' + (styles && styles.back ? styles.back : '') + '>' + '<div class="h5p-back"' + (styles && styles.back ? styles.back : '') + '>' +
'<img src="' + path + '" alt="Memory Card" style="width:' + width + ';height:' + height + '"/>' + '<img src="' + path + '" alt="' + (alt || 'Memory Image') + '" style="width:' + width + ';height:' + height + '"/>' +
'</div>' + '</div>' +
'</div></li>') '</div></li>')
.appendTo($container) .appendTo($container)
.children('.h5p-memory-card') .on('keydown', function (event) {
.children('.h5p-front') switch (event.which) {
.click(function () { case 13: // Enter
self.flip(); case 32: // Space
}) if (!flippedState) {
.end(); self.flip();
event.preventDefault();
}
return;
case 39: // Right
case 40: // Down
// Move focus forward
self.trigger('next');
event.preventDefault();
return;
case 37: // Left
case 38: // Up
// Move focus back
self.trigger('prev');
event.preventDefault();
return;
}
});
$card = $wrapper.children('.h5p-memory-card')
.children('.h5p-front')
.click(function () {
self.flip();
})
.end();
}; };
/** /**
* Re-append to parent container * Re-append to parent container
*/ */
self.reAppend = function () { self.reAppend = function () {
var parent = $card[0].parentElement.parentElement; var parent = $wrapper[0].parentElement;
parent.appendChild($card[0].parentElement); parent.appendChild($wrapper[0]);
};
/**
*
*/
self.makeTabbable = function () {
if ($wrapper) {
$wrapper.attr('tabindex', '0');
}
};
/**
*
*/
self.makeUntabbable = function () {
if ($wrapper) {
$wrapper.attr('tabindex', '-1');
}
};
/**
*
*/
self.setFocus = function () {
self.makeTabbable();
if ($wrapper) {
$wrapper.focus();
}
};
/**
*
*/
self.isFlipped = function () {
return flippedState;
}; };
}; };

View File

@ -220,6 +220,38 @@ H5P.MemoryGame = (function (EventDispatcher, $) {
counter.increment(); counter.increment();
}); });
/**
* @private
* @param {number} direction
*/
var createCardChangeFocusHandler = function (direction) {
return function () {
// Locate next card
for (var i = 0; i < cards.length; i++) {
if (cards[i] === card) {
// Found current card
var nextCard, fails = 0;
do {
fails++;
nextCard = cards[i + (direction * fails)];
if (!nextCard) {
return; // No more cards
}
}
while (nextCard.isFlipped());
card.makeUntabbable();
nextCard.setFocus();
return;
}
}
};
};
card.on('next', createCardChangeFocusHandler(1));
card.on('prev', createCardChangeFocusHandler(-1));
cards.push(card); cards.push(card);
}; };
@ -277,16 +309,16 @@ H5P.MemoryGame = (function (EventDispatcher, $) {
var cardParams = cardsToUse[i]; var cardParams = cardsToUse[i];
if (MemoryGame.Card.isValid(cardParams)) { if (MemoryGame.Card.isValid(cardParams)) {
// Create first card // Create first card
var cardTwo, cardOne = new MemoryGame.Card(cardParams.image, id, cardParams.description, cardStyles); var cardTwo, cardOne = new MemoryGame.Card(cardParams.image, id, cardParams.imageAlt, cardParams.description, cardStyles);
if (MemoryGame.Card.hasTwoImages(cardParams)) { if (MemoryGame.Card.hasTwoImages(cardParams)) {
// Use matching image for card two // Use matching image for card two
cardTwo = new MemoryGame.Card(cardParams.match, id, cardParams.description, cardStyles); cardTwo = new MemoryGame.Card(cardParams.match, id, cardParams.matchAlt, cardParams.description, cardStyles);
cardOne.hasTwoImages = cardTwo.hasTwoImages = true; cardOne.hasTwoImages = cardTwo.hasTwoImages = true;
} }
else { else {
// Add two cards with the same image // Add two cards with the same image
cardTwo = new MemoryGame.Card(cardParams.image, id, cardParams.description, cardStyles); cardTwo = new MemoryGame.Card(cardParams.image, id, cardParams.imageAlt, cardParams.description, cardStyles);
} }
// Add cards to card list for shuffeling // Add cards to card list for shuffeling
@ -314,6 +346,7 @@ H5P.MemoryGame = (function (EventDispatcher, $) {
for (var i = 0; i < cards.length; i++) { for (var i = 0; i < cards.length; i++) {
cards[i].appendTo($list); cards[i].appendTo($list);
} }
cards[0].makeTabbable();
if ($list.children().length) { if ($list.children().length) {
$list.appendTo($container); $list.appendTo($container);

View File

@ -26,6 +26,13 @@
"importance": "high", "importance": "high",
"ratio": 1 "ratio": 1
}, },
{
"name": "imageAlt",
"type": "text",
"label": "Alternative text for Image",
"importance": "high",
"description": "Describe what can be seen in the photo. The text is read by text-to-speech tools needed by visually impaired users."
},
{ {
"name": "match", "name": "match",
"type": "image", "type": "image",
@ -35,6 +42,14 @@
"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 "ratio": 1
}, },
{
"name": "matchAlt",
"type": "text",
"label": "Alternative text for Matching Image",
"importance": "low",
"optional": true,
"description": "Describe what can be seen in the photo. The text is read by text-to-speech tools needed by visually impaired users."
},
{ {
"name": "description", "name": "description",
"type": "text", "type": "text",
@ -146,7 +161,7 @@
"importance": "low", "importance": "low",
"name": "tryAgain", "name": "tryAgain",
"type": "text", "type": "text",
"default": "Try again?" "default": "Reset"
}, },
{ {
"label": "Close button label", "label": "Close button label",