From 5fcf1ffeb1c870a5389cea5efe3cbd62d313b86a Mon Sep 17 00:00:00 2001 From: Ruben Carlo Benante Date: Sun, 28 Jun 2026 17:09:56 -0300 Subject: [PATCH] js feature add top horizontal scroll bar t2 --- Asset/js/top-scrollbar.js | 68 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 Asset/js/top-scrollbar.js diff --git a/Asset/js/top-scrollbar.js b/Asset/js/top-scrollbar.js new file mode 100644 index 0000000..341e039 --- /dev/null +++ b/Asset/js/top-scrollbar.js @@ -0,0 +1,68 @@ +/* + * ShrinkVertically -- optional horizontal scrollbar above the board. + * + * Kanboard's board scrolls horizontally inside #board-container (overflow-x: auto), + * so the only horizontal scrollbar sits at the very bottom of the board. On a wide + * board you have to scroll all the way down to reach it. This adds a second, mirrored + * scrollbar just above the columns and keeps the two scroll positions in sync. + * + * Loaded only when the "Add a top horizontal scrollbar" setting is enabled. + */ +(function () { + "use strict"; + + function init() { + var container = document.getElementById("board-container"); + + // Only on the board, and never add it twice. + if (!container || document.querySelector(".sv-top-scroll")) { + return; + } + + var bar = document.createElement("div"); + bar.className = "sv-top-scroll"; + + var inner = document.createElement("div"); + inner.className = "sv-top-scroll-inner"; + bar.appendChild(inner); + + container.parentNode.insertBefore(bar, container); + + function sync() { + // Match the dummy bar's content width to the board's scrollable width + // so its scrollbar has the same range as the board's own scrollbar. + inner.style.width = container.scrollWidth + "px"; + } + + var lock = false; + + bar.addEventListener("scroll", function () { + if (lock) { return; } + lock = true; + container.scrollLeft = bar.scrollLeft; + lock = false; + }); + + container.addEventListener("scroll", function () { + if (lock) { return; } + lock = true; + bar.scrollLeft = container.scrollLeft; + lock = false; + }); + + window.addEventListener("resize", sync); + + // The board can be redrawn by the AJAX polling/refresh; keep the width current. + if (window.MutationObserver) { + new MutationObserver(sync).observe(container, { childList: true, subtree: true }); + } + + sync(); + } + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", init); + } else { + init(); + } +})();