Skip to content

fix: guard TOC navigation against re-entry (#63)#69

Open
erseco wants to merge 3 commits into
mainfrom
63-fix-toc-navigation-loop
Open

fix: guard TOC navigation against re-entry (#63)#69
erseco wants to merge 3 commits into
mainfrom
63-fix-toc-navigation-loop

Conversation

@erseco
Copy link
Copy Markdown
Collaborator

@erseco erseco commented May 9, 2026

Summary

Speculative fix for #63. Tagging this draft because I have not been able to reproduce the issue locally on Moodle 5.0, but the code path I'm patching is the only thing in module.js that matches every detail of the bug report.

Root-cause hypothesis

`exescorm_activate_item()` (the function that loads the SCO matching the clicked TOC entry) calls `exescorm_tree_node.closeAll()` and later `exescorm_tree_node.openAll()` to collapse and re-expand the whole YUI TreeView. Those calls mutate node selection state and YUI fires additional `select` events while the tree settles, which the `tree.after('select', ...)` handler then interprets as a fresh navigation request and calls `exescorm_activate_item()` again with a different node (typically a sibling).

That maps cleanly onto every detail Ignacio described:

  • "in many cases you don't see the section you clicked on" → second `activate_item()` call replaces the iframe src.
  • "the iframe content is loaded more than once: a page seems to load and then the content is refreshed" → exactly two iframe creations per click.
  • "clicking 'a 2 1' loads 'a 2 2'" → next sibling is the most likely target of a spurious `select` after a closeAll/openAll on a parent.

It also explains why I can't reproduce on Moodle 5.0: YUI TreeView's exact event ordering changed between versions, and the spurious `select` may simply not fire on the build I tested.

Fix

Single-flag re-entry guard:

  • `exescorm_navigating = true` set right before `closeAll()` (covers the `select()`/`closeAll()`/`openAll()` window).
  • `tree.after('select', ...)` returns early when the flag is set, so only the genuine user click drives navigation.
  • `exescorm_navigating = false` cleared right after `openAll()`.

17 added lines, no behavioural change for the non-buggy path.

Test plan

  • Reproduce on Moodle 4.5 first: install the example SCORM ZIP, open it, click "a 2 1" and verify the iframe stops at `html/a-2-1.html` (no second load to `a-2-2.html`).
  • Click each TOC entry once and verify the iframe loads exactly once per click (DevTools → Network).
  • Click a parent that has children (e.g. "a 2"): the parent's content loads once and the tree stays expanded.
  • Repeat the previous three checks on Moodle 5.0 to make sure the guard doesn't break the working flow.

Sibling repo

`mod_exeweb` doesn't share this code path (its viewer renders the package as a single iframe with no TOC), so no parallel PR is needed there. Per `AGENTS.md`'s twin-plugin checklist, audited `mod_exeweb/amd/src/editor_modal.js` and confirmed.


Moodle Playground Preview

The changes in this pull request can be previewed and tested using a Moodle Playground instance.

Preview in Moodle Playground

⚠️ The embedded eXeLearning editor is not included in this preview. You can install it from Modules > eXeLearning SCORM > Configure using the "Download & Install Editor" button. All other module features (ELPX upload, viewer, preview) work normally.

When the user clicks a TOC entry, `exescorm_activate_item()` calls
`exescorm_tree_node.closeAll()` and later `openAll()` to collapse and
re-expand the entire YUI TreeView. Those operations mutate node
selection state and YUI fires additional `select` events while the
tree settles, which the `tree.after('select', ...)` handler then
interprets as a fresh navigation request and calls
`exescorm_activate_item()` again with a *different* node (typically a
sibling). The visible symptoms reported in #63 — the iframe loading
twice and "click X, see Y" — line up with that pattern.

Add an `exescorm_navigating` flag set right before the first state
change and cleared after `openAll()`. The select handler returns early
when the flag is set, so only the original user click drives the
navigation.

The fix is defensive: I have not been able to reproduce locally on
Moodle 5.0, but every signal in the report (intermittent, multiple
iframe loads, sibling shown instead of clicked item) points at
re-entry through this code path. If the symptom persists after
upgrading we'll need to capture a console trace inside the failing
session.
@erseco erseco requested a review from ignaciogros May 9, 2026 17:16
@erseco erseco self-assigned this May 9, 2026
@erseco erseco added the bug Something isn't working label May 9, 2026
Copy link
Copy Markdown
Collaborator

@ignaciogros ignaciogros left a comment

Choose a reason for hiding this comment

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

The navigation menu works correctly, including keyboard support. Thank you!

But there are still some issues with the pagination buttons:

“Previous”, “Next”, and “Level up” work as expected, but “Previous within this level” and “Next within this level” do not.

Example:
Publish the sample SCORM and go to section “b”. The expected behavior when clicking “Next within this level” would be to navigate to section “c”, but this does not happen (in my tests, nothing happens). Additionally, when being on “b”, “Previous within this level” is disabled. This may be because index.html is not at the same level. In other cases, those buttons behave like “Previous” and “Next”, without respecting the hierarchical level.

If this becomes too problematic, I suggest temporarily hiding these buttons and releasing the next version with only “Previous” and “Next”.

There is also a JavaScript error when loading the page, but it does not appear to affect functionality:
[moodle-exe-bridge] Missing __MOODLE_EXE_CONFIG__

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants