Skip to content

Fix Navbar responsive controls for shadow DOM hosts#1539

Open
jbuckner wants to merge 1 commit intomasterfrom
fix/navbar-shadow-dom-compat
Open

Fix Navbar responsive controls for shadow DOM hosts#1539
jbuckner wants to merge 1 commit intomasterfrom
fix/navbar-shadow-dom-compat

Conversation

@jbuckner
Copy link
Copy Markdown
Contributor

Summary

Fix Navbar.showMobileControls / showDesktopControls to work when BookReader is hosted inside a shadow-DOM ancestor (e.g. archive.org's offshoot details page, or any web-component host).

Problem

Both methods use document.querySelector to find the view-mode buttons and the mobile-nav wrapper:

showDesktopControls() {
  this.maximumControls.forEach((control) => {
    const element = document.querySelector(`.BRnavMain .controls .${control}`);
    if (element) element.classList.remove('hide');
  });
  // ...
  const mobileNav = document.querySelector(`.BRnavMobile`);
  if (mobileNav) mobileNav.classList.add('hide');
}

document.querySelector can't cross shadow DOM boundaries. When BookReader renders inside a shadow-scoped ancestor, every lookup returns null, no .hide class is ever toggled, and both sets of controls render simultaneously — the mobile-only viewmode button shows next to the three desktop view-mode buttons (onepg, twopg, thumb), producing a duplicate thumbnail icon in the navbar at desktop widths.

Fix

Scope the queries to this.$nav (the navbar's own jQuery-wrapped root element) instead of document. $nav is built from a fragment containing two top-level sibling divs (.BRnavMobile + .BRnavMain), so:

  • .find('.controls .${name}') scoped inside .filter('.BRnavMain') for the inner control buttons
  • .filter('.BRnavMobile') for the outer mobile nav (not .find('.BRnavMobile'), which is descendants-only and would silently miss the top-level sibling)

This makes both methods shadow-DOM-agnostic while preserving identical behavior in the light-DOM case.

Verification

  • Unit-verified offshoot-side in https://git.archive.org/www/offshoot/-/merge_requests/1049 — a live regression test constructs a jQuery-wrapped navbar fragment, invokes showDesktopControls / showMobileControls, and asserts the expected .hide class transitions.
  • Manually verified in offshoot's review app: duplicate thumbnail icon disappears at desktop widths; mobile nav still toggles correctly on resize.

Risk

Low. The jQuery .filter() / .find() chain produces the same DOM set that the document.querySelector versions were reaching in the document-case, and the method surface is unchanged.

Related: addresses the same class of shadow-DOM bug as #1520.

Navbar.showMobileControls and showDesktopControls used
`document.querySelector('.BRnavMain .controls ...')` and
`document.querySelector('.BRnavMobile')` to toggle the `.hide` class
on view-mode buttons at different viewport widths. Those lookups
cannot cross shadow DOM boundaries — so when BookReader is embedded
inside a shadow-DOM host (e.g. archive.org's offshoot details page),
every query returns null, no class gets toggled, and the mobile-only
viewmode button stays visible alongside the three desktop view-mode
buttons (one-page, two-page, thumbnail). Users see a duplicate
thumbnail icon in the navbar.

Scope the queries to `this.$nav` (the navbar's own jQuery-wrapped
root) instead. $nav is a wrapped set with `.BRnavMain` and
`.BRnavMobile` as top-level sibling elements, so the outer classes
must be matched with `.filter()` — `.find()` only traverses
descendants and would silently match nothing.
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 20, 2026

Codecov Report

❌ Patch coverage is 50.00000% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.00%. Comparing base (2908b1e) to head (f079a3f).

Files with missing lines Patch % Lines
src/BookReader/Navbar/Navbar.js 50.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1539      +/-   ##
==========================================
+ Coverage   68.98%   69.00%   +0.01%     
==========================================
  Files          65       65              
  Lines        5556     5552       -4     
  Branches     1229     1223       -6     
==========================================
- Hits         3833     3831       -2     
+ Misses       1689     1687       -2     
  Partials       34       34              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant