/* score-reader.js — Page navigation, zoom and pan for the full score reader.
Configuration is read from #score-reader-stage data attributes:
data-page-count — total number of score pages
data-pages — comma-separated list of absolute page SVG URLs
Pages are fetched and inlined as live SVG rather than pointed at with an
. Three things follow from that, and they are the reason for it:
the notation inherits the theme's `color` (an
-loaded SVG resolves
`currentColor` against its own root, so it can only ever draw black);
zooming is a width change on a vector, not a rescaled bitmap; and the
elements are in the DOM, which is what any later staff- or measure-level
feature will need. */
(function () {
'use strict';
var stage = document.getElementById('score-reader-stage');
var viewport = document.getElementById('score-reader-viewport');
var pageEl = document.getElementById('score-page');
var folio = document.getElementById('score-folio');
var prevBtn = document.getElementById('score-prev');
var nextBtn = document.getElementById('score-next');
var bar = document.getElementById('score-reader-bar');
if (!stage || !viewport || !pageEl || !folio || !prevBtn || !nextBtn) return;
var pages = (stage.dataset.pages || '').split(',').filter(function (p) {
return p.length > 0;
});
var pageCount = pages.length;
if (pageCount === 0) return; /* nothing to display */
var currentPage = 1;
var ratio = null; /* page width / height, learned from page 1 */
var naturalW = null; /* page width in CSS px at 100 % */
var cache = new Map();
/* ------------------------------------------------------------------
Fetching and inlining
------------------------------------------------------------------ */
/* An ordinary web link, a fragment, or a relative path. Mirrors the
convention Catalog.safeHref applies on the Haskell side. */
var SAFE_HREF = /^(https?:|\/|#|\.)/i;
/* innerHTML and adoptNode never execute a