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
20 changes: 16 additions & 4 deletions games/static/js/src/matching.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ function GamesXBlockMatchingInit(runtime, element, pages, matching_key) {
}

function refreshGame() {
MatchInit = null;
$.ajax({
type: 'GET',
url: runtime.handlerUrl(element, 'refresh_game'),
Expand All @@ -61,9 +60,22 @@ function GamesXBlockMatchingInit(runtime, element, pages, matching_key) {
var scriptContent = decoderScript.text();
decoderScript.remove();
try {
eval(scriptContent);
if (typeof MatchingInit === 'function') {
MatchingInit(runtime, element);
var match = scriptContent.match(/function\s+(\w+)\s*\(/);
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

The regex pattern used to extract the function name is too simplistic and may fail in edge cases. For example, it won't handle function names with leading/trailing whitespace variations, comments within the function declaration, or multiline function declarations. Consider using a more robust pattern or adding validation to ensure the extracted function name matches expected patterns.

Suggested change
var match = scriptContent.match(/function\s+(\w+)\s*\(/);
var match = scriptContent.match(/function\s+(?:\/\*[\s\S]*?\*\/\s*|\/\/[^\n]*\n\s*)*([A-Za-z_$][0-9A-Za-z_$]*)\s*\(/m);

Copilot uses AI. Check for mistakes.
if (match) {
var initFuncName = match[1];
eval(scriptContent);
if (typeof window[initFuncName] === 'function') {
window[initFuncName](runtime, element);
setTimeout(function() {
$('.matching-start-button', element).click();
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

The selector '.matching-start-button' may not exist immediately after the initialization, or could match multiple elements if the DOM structure contains duplicates. Consider adding validation to ensure the button exists and is unique before attempting to trigger the click event, or handle the case where the button is not found gracefully.

Suggested change
$('.matching-start-button', element).click();
const $startButtons = $('.matching-start-button', element);
if ($startButtons.length === 1) {
$startButtons.click();
} else if ($startButtons.length > 1) {
console.warn('Expected a single .matching-start-button but found', $startButtons.length);
$startButtons.first().click();
} else {
console.warn('No .matching-start-button found for auto-start; game will not be started automatically.');
}

Copilot uses AI. Check for mistakes.
}, 100);
Comment on lines +69 to +71
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

The hardcoded 100ms delay for triggering the start button click is a magic number that lacks documentation. This arbitrary timeout could cause race conditions if the initialization takes longer than 100ms on slower devices or network conditions. Consider either documenting why 100ms is sufficient, or implementing a more robust mechanism such as waiting for a specific initialization event or checking for element readiness before triggering the click.

Suggested change
setTimeout(function() {
$('.matching-start-button', element).click();
}, 100);
// Automatically start the game once the start button is available.
var $startButton = $('.matching-start-button', element);
if ($startButton.length) {
$startButton.click();
} else {
// Poll briefly for the button in case initialization is asynchronous.
var attempts = 0;
var maxAttempts = 20; // ~2 seconds with 100ms interval
var pollInterval = 100;
var pollId = setInterval(function() {
var $btn = $('.matching-start-button', element);
if ($btn.length) {
clearInterval(pollId);
$btn.click();
} else if (++attempts >= maxAttempts) {
clearInterval(pollId);
console.warn('Matching start button not found after waiting for initialization.');
}
}, pollInterval);
}

Copilot uses AI. Check for mistakes.
} else {
console.error('Init function not found:', initFuncName);
window.location.reload();
}
} else {
console.error('Could not extract function name');
window.location.reload();
Comment on lines +73 to +78
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

Falling back to a full page reload on initialization failure may result in poor user experience and potential infinite reload loops if the underlying issue persists. The error handling should provide more user-friendly feedback or retry mechanisms rather than silently reloading the page, which could disorient users and lose their context.

Copilot uses AI. Check for mistakes.
}
} catch (err) {
console.error('Failed to initialize game:', err);
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.8",
version="1.0.9",
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