Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions games/static/css/matching.css
Original file line number Diff line number Diff line change
Expand Up @@ -435,9 +435,7 @@
}

.matching-box:focus-visible {
outline: 2px solid var(--primary-500, #00262B);
outline-offset: 2px;
box-shadow: 0 0 0 4px rgba(0, 38, 43, 0.2);
outline: none;

Copilot AI Apr 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the :focus-visible outline from .matching-box leaves keyboard users without a visible focus indicator (and the JS explicitly calls .focus() on these elements). Please keep a clear non-color-dependent focus style (e.g., outline/box-shadow) that meets WCAG focus appearance requirements instead of outline: none.

Suggested change
outline: none;
outline: 3px solid var(--primary-500, #00262B);
outline-offset: 2px;

Copilot uses AI. Check for mistakes.
}

.matching-end-screen-content:focus {
Expand Down
54 changes: 54 additions & 0 deletions games/static/js/src/matching.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ function GamesXBlockMatchingInit(runtime, element) {

let timerInterval = null;
let timeSeconds = 0;
const isPreviewMode = new URLSearchParams(window.location.search).get('preview') === '1';

function formatTime(seconds) {
const hours = Math.floor(seconds / 3600);
Expand Down Expand Up @@ -60,6 +61,45 @@ function GamesXBlockMatchingInit(runtime, element) {
}

function refreshGame() {
if (isPreviewMode) {
currentPageIndex = 0;
matchCount = 0;
firstSelection = null;
timeSeconds = 0;
stopTimer();
$('.matching-end-screen', element).removeClass('active');
$('.matching-new-best', element).removeClass('active');
$('.matching-grid', element).show().addClass('active');
$('.matching-footer', element).show().addClass('active');
Comment on lines +72 to +73

Copilot AI Apr 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In preview mode, using jQuery .show() on .matching-grid / .matching-footer will set an inline display: block, which overrides the CSS that expects .matching-grid.active { display: grid } and .matching-footer.active { display: flex }. This can break layout after completing once (because hide() sets inline styles too). Prefer toggling the active class (and removing any inline style from prior hide()), instead of show()/hide() here.

Suggested change
$('.matching-grid', element).show().addClass('active');
$('.matching-footer', element).show().addClass('active');
$('.matching-grid', element).removeAttr('style').addClass('active');
$('.matching-footer', element).removeAttr('style').addClass('active');

Copilot uses AI. Check for mistakes.
$('#matching-timer', element).text('0:00');
const page = allPages[0];
currentPagePairs = page.left_items.length;
updateProgress();
$('.matching-column-left', element).empty();
$('.matching-column-right', element).empty();
page.left_items.forEach(function(item) {
const wrapper = $('<div class="matching-box-wrapper"></div>');
const box = $('<div class="matching-box"></div>')
.attr('data-item-type', 'term').attr('data-match', item.match)
.attr('title', item.text).attr('role', 'button').attr('tabindex', '0');
box.append($('<span class="matching-box-text"></span>').text(item.text));
wrapper.append(box);
$('.matching-column-left', element).append(wrapper);
});
page.right_items.forEach(function(item) {
const wrapper = $('<div class="matching-box-wrapper"></div>');
const box = $('<div class="matching-box"></div>')
.attr('data-item-type', 'definition').attr('data-hash', item.hash)
.attr('title', item.text).attr('role', 'button').attr('tabindex', '0');
box.append($('<span class="matching-box-text"></span>').text(item.text));
wrapper.append(box);
$('.matching-column-right', element).append(wrapper);
});
attachBoxClickHandlers();
if (has_timer) { startTimer(); }
$('.matching-box', element).first().focus();
return;
}
$.ajax({
type: 'GET',
url: runtime.handlerUrl(element, 'refresh_game'),
Expand Down Expand Up @@ -280,6 +320,20 @@ function GamesXBlockMatchingInit(runtime, element) {
return;
}

if (isPreviewMode) {
$('.matching-end-screen', element).addClass('active');
$('.matching-new-best', element).addClass('active');
$('.matching-grid', element).hide();
$('.matching-footer', element).hide();
$('#matching-current-result', element).text(formatTime(timeSeconds));
Comment on lines +325 to +328

Copilot AI Apr 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preview-mode completion always activates .matching-new-best, which renders the copy “A new personal best!” even though preview mode has no persisted best-time data. Consider showing a neutral results state for preview (e.g., reuse .matching-prev-best with adjusted copy, or add a dedicated preview block) so the end screen doesn’t present incorrect information.

Suggested change
$('.matching-new-best', element).addClass('active');
$('.matching-grid', element).hide();
$('.matching-footer', element).hide();
$('#matching-current-result', element).text(formatTime(timeSeconds));
$('.matching-new-best', element).removeClass('active');
$('.matching-prev-best', element).removeClass('active');
$('.matching-grid', element).hide();
$('.matching-footer', element).hide();

Copilot uses AI. Check for mistakes.
if (typeof GamesConfetti !== 'undefined') {
GamesConfetti.trigger($('.confetti-container', element), 20);
}
announce('Congratulations! You matched all items.');
$('.matching-end-screen-content', element).focus();
return;
}

$.ajax({
type: 'POST',
url: runtime.handlerUrl(element, 'complete_matching_game'),
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def package_data(pkg, roots):

setup(
name="edx-games",
version="1.0.16",
version="1.0.17",
description="Interactive games XBlock for Open edX - Create flashcards and matching games with image support",
author="edX",
author_email="edx@edx.org",
Expand Down
Loading