Fix a bug in tab's javascript and cleanup the code

This commit is contained in:
2026-01-07 23:24:16 +01:00
parent b8d10a68ca
commit a16801eb4b
7 changed files with 27 additions and 25 deletions

View File

@@ -3,4 +3,4 @@
* Copyright 2011-2023 The Bootstrap Authors * Copyright 2011-2023 The Bootstrap Authors
* Licensed under the Creative Commons Attribution 3.0 Unported License. * Licensed under the Creative Commons Attribution 3.0 Unported License.
*/ */
(()=>{"use strict";const e=()=>localStorage.getItem("theme"),t=()=>{const t=e();return t||(window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light")},a=e=>{"auto"===e&&window.matchMedia("(prefers-color-scheme: dark)").matches?document.documentElement.setAttribute("data-bs-theme","dark"):document.documentElement.setAttribute("data-bs-theme",e)};a(t());const r=(e,t=!1)=>{const a=document.querySelector("#bd-theme");if(!a)return;const r=document.querySelector(".theme-icon-active i"),o=document.querySelector(`[data-bs-theme-value="${e}"]`),s=o.querySelector(".theme-icon i").getAttribute("class");document.querySelectorAll("[data-bs-theme-value]").forEach(e=>{e.classList.remove("active"),e.setAttribute("aria-pressed","false")}),o.classList.add("active"),o.setAttribute("aria-pressed","true"),r.setAttribute("class",s),t&&a.focus()};window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{const r=e();"light"!==r&&"dark"!==r&&a(t())}),window.addEventListener("DOMContentLoaded",()=>{r(t()),document.querySelectorAll("[data-bs-theme-value]").forEach(e=>{e.addEventListener("click",()=>{const t=e.getAttribute("data-bs-theme-value");(e=>{localStorage.setItem("theme",e)})(t),a(t),r(t,!0)})})})})(),document.addEventListener("DOMContentLoaded",function(){const e=window.location.hash.substring(1);if(e){const t=document.querySelector(`[data-bs-target="#nav-${e}"]`);t&&bootstrap.Tab.getOrCreateInstance(t).show()}document.querySelectorAll('button[data-bs-toggle="tab"]').forEach(e=>{e.addEventListener("shown.bs.tab",e=>{const t=e.target.getAttribute("data-bs-target").replace("nav-","");history.replaceState(null,null,t)})});const t=document.getElementById("tabSelector");t&&(t.addEventListener("change",function(){const e=this.value,t=document.querySelector(`[data-bs-target="#${e}"]`);if(t){bootstrap.Tab.getOrCreateInstance(t).show()}}),document.querySelectorAll('[data-bs-toggle="tab"]').forEach(e=>{e.addEventListener("shown.bs.tab",e=>{const a=e.target.getAttribute("data-bs-target");t.value=a.substring(1)})}))}); (()=>{"use strict";const e=()=>localStorage.getItem("theme"),t=()=>{const t=e();return t||(window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light")},a=e=>{"auto"===e&&window.matchMedia("(prefers-color-scheme: dark)").matches?document.documentElement.setAttribute("data-bs-theme","dark"):document.documentElement.setAttribute("data-bs-theme",e)};a(t());const r=(e,t=!1)=>{const a=document.querySelector("#bd-theme");if(!a)return;const r=document.querySelector(".theme-icon-active i"),o=document.querySelector(`[data-bs-theme-value="${e}"]`),s=o.querySelector(".theme-icon i").getAttribute("class");document.querySelectorAll("[data-bs-theme-value]").forEach(e=>{e.classList.remove("active"),e.setAttribute("aria-pressed","false")}),o.classList.add("active"),o.setAttribute("aria-pressed","true"),r.setAttribute("class",s),t&&a.focus()};window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{const r=e();"light"!==r&&"dark"!==r&&a(t())}),window.addEventListener("DOMContentLoaded",()=>{r(t()),document.querySelectorAll("[data-bs-theme-value]").forEach(e=>{e.addEventListener("click",()=>{const t=e.getAttribute("data-bs-theme-value");(e=>{localStorage.setItem("theme",e)})(t),a(t),r(t,!0)})})})})(),document.addEventListener("DOMContentLoaded",function(){const e=document.getElementById("tabSelector"),t=window.location.hash.substring(1);if(t){const a=`#nav-${t}`,r=document.querySelector(`[data-bs-target="${a}"]`);r&&(bootstrap.Tab.getOrCreateInstance(r).show(),e.value=a)}document.querySelectorAll('button[data-bs-toggle="tab"]').forEach(e=>{e.addEventListener("shown.bs.tab",e=>{const t=e.target.getAttribute("data-bs-target").replace("nav-","");history.replaceState(null,null,t)})}),e&&(e.addEventListener("change",function(){const e=this.value,t=document.querySelector(`[data-bs-target="${e}"]`);if(t){bootstrap.Tab.getOrCreateInstance(t).show()}}),document.querySelectorAll('[data-bs-toggle="tab"]').forEach(t=>{t.addEventListener("shown.bs.tab",t=>{const a=t.target.getAttribute("data-bs-target");e.value=a})}))});

View File

@@ -1,13 +1,17 @@
// use Bootstrap 5's Tab component to manage tab navigation and synchronize with URL hash
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
const selectElement = document.getElementById('tabSelector');
// code to handle tab selection and URL hash synchronization // code to handle tab selection and URL hash synchronization
const hash = window.location.hash.substring(1) // remove the '#' prefix const hash = window.location.hash.substring(1) // remove the '#' prefix
if (hash) { if (hash) {
const trigger = document.querySelector(`[data-bs-target="#nav-${hash}"]`); const target = `#nav-${hash}`;
const trigger = document.querySelector(`[data-bs-target="${target}"]`);
if (trigger) { if (trigger) {
bootstrap.Tab.getOrCreateInstance(trigger).show(); bootstrap.Tab.getOrCreateInstance(trigger).show();
selectElement.value = target // keep the dropdown in sync
} }
} }
//
// update the URL hash when a tab is shown // update the URL hash when a tab is shown
document.querySelectorAll('button[data-bs-toggle="tab"]').forEach(btn => { document.querySelectorAll('button[data-bs-toggle="tab"]').forEach(btn => {
btn.addEventListener('shown.bs.tab', event => { btn.addEventListener('shown.bs.tab', event => {
@@ -17,14 +21,12 @@ document.addEventListener("DOMContentLoaded", function () {
}); });
// allow tab selection via a dropdown on small screens // allow tab selection via a dropdown on small screens
const selectElement = document.getElementById('tabSelector');
if (!selectElement) return; if (!selectElement) return;
selectElement.addEventListener('change', function () { selectElement.addEventListener('change', function () {
const targetSelector = this.value; const target = this.value;
const triggerEl = document.querySelector(`[data-bs-target="#${targetSelector}"]`); const trigger = document.querySelector(`[data-bs-target="${target}"]`);
if (triggerEl) { if (trigger) {
// Use Bootstrap 5.3's API — ensures transitions + ARIA updates const tabInstance = bootstrap.Tab.getOrCreateInstance(trigger);
const tabInstance = bootstrap.Tab.getOrCreateInstance(triggerEl);
tabInstance.show(); tabInstance.show();
} }
}); });
@@ -33,7 +35,7 @@ document.addEventListener("DOMContentLoaded", function () {
document.querySelectorAll('[data-bs-toggle="tab"]').forEach(btn => { document.querySelectorAll('[data-bs-toggle="tab"]').forEach(btn => {
btn.addEventListener('shown.bs.tab', event => { btn.addEventListener('shown.bs.tab', event => {
const target = event.target.getAttribute('data-bs-target'); const target = event.target.getAttribute('data-bs-target');
selectElement.value = target.substring(1); // remove the '#' character selectElement.value = target
}); });
}); });
}); });

View File

@@ -53,9 +53,9 @@
{% if documents %}<button class="nav-link" id="nav-documents-tab" data-bs-toggle="tab" data-bs-target="#nav-documents" type="button" role="tab" aria-controls="nav-documents" aria-selected="false">Documents</button>{% endif %} {% if documents %}<button class="nav-link" id="nav-documents-tab" data-bs-toggle="tab" data-bs-target="#nav-documents" type="button" role="tab" aria-controls="nav-documents" aria-selected="false">Documents</button>{% endif %}
</nav> </nav>
<select class="form-select d-lg-none mb-2" id="tabSelector" aria-label="Tab selector"> <select class="form-select d-lg-none mb-2" id="tabSelector" aria-label="Tab selector">
<option value="nav-summary" selected>Summary</option> <option value="#nav-summary" selected>Summary</option>
{% if data.toc.all %}<option value="nav-toc">Table of contents</option>{% endif %} {% if data.toc.all %}<option value="#nav-toc">Table of contents</option>{% endif %}
{% if documents %}<option value="nav-documents">Documents</option>{% endif %} {% if documents %}<option value="#nav-documents">Documents</option>{% endif %}
</select> </select>
<div class="tab-content" id="nav-tabContent"> <div class="tab-content" id="nav-tabContent">
<div class="tab-pane show active" id="nav-summary" role="tabpanel" aria-labelledby="nav-summary-tab"> <div class="tab-pane show active" id="nav-summary" role="tabpanel" aria-labelledby="nav-summary-tab">

View File

@@ -73,7 +73,7 @@
<button class="nav-link active" id="nav-summary-tab" data-bs-toggle="tab" data-bs-target="#nav-summary" type="button" role="tab" aria-controls="nav-summary" aria-selected="true">Summary</button> <button class="nav-link active" id="nav-summary-tab" data-bs-toggle="tab" data-bs-target="#nav-summary" type="button" role="tab" aria-controls="nav-summary" aria-selected="true">Summary</button>
</nav> </nav>
<select class="form-select d-lg-none mb-2" id="tabSelector" aria-label="Tab selector"> <select class="form-select d-lg-none mb-2" id="tabSelector" aria-label="Tab selector">
<option value="nav-summary" selected>Summary</option> <option value="#nav-summary" selected>Summary</option>
</select> </select>
<div class="tab-content" id="nav-tabContent"> <div class="tab-content" id="nav-tabContent">
<div class="tab-pane show active" id="nav-summary" role="tabpanel" aria-labelledby="nav-summary-tab"> <div class="tab-pane show active" id="nav-summary" role="tabpanel" aria-labelledby="nav-summary-tab">

View File

@@ -102,7 +102,7 @@
<button class="nav-link active" id="nav-summary-tab" data-bs-toggle="tab" data-bs-target="#nav-summary" type="button" role="tab" aria-controls="nav-summary" aria-selected="true">Summary</button> <button class="nav-link active" id="nav-summary-tab" data-bs-toggle="tab" data-bs-target="#nav-summary" type="button" role="tab" aria-controls="nav-summary" aria-selected="true">Summary</button>
</nav> </nav>
<select class="form-select d-lg-none mb-2" id="tabSelector" aria-label="Tab selector"> <select class="form-select d-lg-none mb-2" id="tabSelector" aria-label="Tab selector">
<option value="nav-summary" selected>Summary</option> <option value="#nav-summary" selected>Summary</option>
</select> </select>
<div class="tab-content" id="nav-tabContent"> <div class="tab-content" id="nav-tabContent">
<div class="tab-pane show active table-responsive" id="nav-summary" role="tabpanel" aria-labelledby="nav-summary-tab"> <div class="tab-pane show active table-responsive" id="nav-summary" role="tabpanel" aria-labelledby="nav-summary-tab">

View File

@@ -59,15 +59,15 @@
{% if consists %}<button class="nav-link" id="nav-consists-tab" data-bs-toggle="tab" data-bs-target="#nav-consists" type="button" role="tab" aria-controls="nav-consists" aria-selected="false">Consists</button>{% endif %} {% if consists %}<button class="nav-link" id="nav-consists-tab" data-bs-toggle="tab" data-bs-target="#nav-consists" type="button" role="tab" aria-controls="nav-consists" aria-selected="false">Consists</button>{% endif %}
</nav> </nav>
<select class="form-select d-lg-none mb-2" id="tabSelector" aria-label="Tab selector"> <select class="form-select d-lg-none mb-2" id="tabSelector" aria-label="Tab selector">
<option value="nav-summary" selected>Summary</option> <option value="#nav-summary" selected>Summary</option>
<option value="nav-model">Model</option> <option value="#nav-model">Model</option>
<option value="nav-class">Class</option> <option value="#nav-class">Class</option>
<option value="nav-company">Company</option> <option value="#nav-company">Company</option>
{% if rolling_stock.decoder or rolling_stock.decoder_interface %}<option value="nav-dcc">DCC</option>{% endif %} {% if rolling_stock.decoder or rolling_stock.decoder_interface %}<option value="#nav-dcc">DCC</option>{% endif %}
{% if documents or decoder_documents %}<option value="nav-documents">Documents</option>{% endif %} {% if documents or decoder_documents %}<option value="#nav-documents">Documents</option>{% endif %}
{% if journal %}<option value="nav-journal">Journal</option>{% endif %} {% if journal %}<option value="#nav-journal">Journal</option>{% endif %}
{% if set %}<option value="nav-set">Set</option>{% endif %} {% if set %}<option value="#nav-set">Set</option>{% endif %}
{% if consists %}<option value="nav-consists">Consists</option>{% endif %} {% if consists %}<option value="#nav-consists">Consists</option>{% endif %}
</select> </select>
{% with class=rolling_stock.rolling_class company=rolling_stock.rolling_class.company %} {% with class=rolling_stock.rolling_class company=rolling_stock.rolling_class.company %}
<div class="tab-content" id="nav-tabContent"> <div class="tab-content" id="nav-tabContent">

View File

@@ -1,4 +1,4 @@
from ram.utils import git_suffix from ram.utils import git_suffix
__version__ = "0.19.9" __version__ = "0.19.10"
__version__ += git_suffix(__file__) __version__ += git_suffix(__file__)