// version-picker.js
//
// Shows the current spec version in the mdBook menu bar. On a deployed
// multi-version site (path like //) it upgrades
// into a dropdown that switches between versions. On a single-version
// or local build (file:// or no versions.json reachable) it just
// renders a static "version: " label so the reader can always
// see which version they're reading.
(function () {
'use strict';
// Match the version segment in a path. Accepts "latest" or "vX[.Y[.Z]][-pre]".
var VERSION_RE = /\/(latest|v\d+(?:\.\d+){0,2}(?:-[A-Za-z0-9.]+)?)(\/|$)/;
function labelFor(version) {
return (version === 'latest') ? 'latest (main)' : version;
}
function parseLocation() {
var path = window.location.pathname;
var m = path.match(VERSION_RE);
if (!m) return null;
var version = m[1];
var versionStart = m.index;
var basePath = path.substring(0, versionStart + 1);
var pagePath = path.substring(versionStart + 1 + version.length);
return { version: version, basePath: basePath, pagePath: pagePath };
}
function buildLabel(version) {
var wrap = document.createElement('div');
wrap.className = 'version-picker version-picker-label-only';
wrap.setAttribute('role', 'group');
wrap.setAttribute('aria-label', 'Spec version');
var prefix = document.createElement('span');
prefix.className = 'version-picker-label';
prefix.textContent = 'version:';
wrap.appendChild(prefix);
var name = document.createElement('span');
name.className = 'version-picker-name';
name.textContent = labelFor(version);
wrap.appendChild(name);
return wrap;
}
function buildDropdown(versions, current, basePath, pagePath) {
var wrap = document.createElement('div');
wrap.className = 'version-picker';
wrap.setAttribute('role', 'group');
wrap.setAttribute('aria-label', 'Spec version');
var prefix = document.createElement('span');
prefix.className = 'version-picker-label';
prefix.textContent = 'version:';
wrap.appendChild(prefix);
var select = document.createElement('select');
select.className = 'version-picker-select';
select.setAttribute('aria-label', 'Choose spec version');
for (var i = 0; i < versions.length; i++) {
var v = versions[i];
var opt = document.createElement('option');
opt.value = v;
opt.textContent = labelFor(v);
if (v === current) opt.selected = true;
select.appendChild(opt);
}
select.addEventListener('change', function (e) {
var next = e.target.value;
if (!next || next === current) return;
window.location.pathname = basePath + next + pagePath;
});
wrap.appendChild(select);
return wrap;
}
function mount(picker) {
var slot = document.querySelector('.right-buttons');
if (slot) {
slot.insertBefore(picker, slot.firstChild);
} else {
picker.classList.add('version-picker-floating');
document.body.appendChild(picker);
}
}
function install() {
var loc = parseLocation();
var current = loc ? loc.version : 'latest';
// Always mount the label first — visible immediately, even before
// (or without) a versions.json fetch.
var picker = buildLabel(current);
mount(picker);
// Only attempt the upgrade-to-dropdown path when we have a real
// version segment in the URL. Without one (e.g., file:// or local
// `just build` opened directly), we can't compute navigation
// targets, so leave the label as-is.
if (!loc) return;
fetch(loc.basePath + 'versions.json', { cache: 'no-cache' })
.then(function (r) { return r.ok ? r.json() : null; })
.then(function (data) {
if (!data) return;
// Accepted shapes:
// ["latest", "v0.1.0"]
// { "versions": ["latest", "v0.1.0"] }
var versions = Array.isArray(data) ? data : (data && data.versions);
if (!versions || versions.length < 2) return;
var dropdown = buildDropdown(versions, current, loc.basePath, loc.pagePath);
picker.replaceWith(dropdown);
})
.catch(function (err) {
// Non-fatal: keep the label-only widget mounted.
if (window.console) console.warn('version-picker:', err);
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', install);
} else {
install();
}
})();