[tabs] Update tabs.
This commit is contained in:
220
public/assets/scaffolding-min.js
vendored
220
public/assets/scaffolding-min.js
vendored
@@ -3194,9 +3194,9 @@ __webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
||||
/* harmony export */ init: function() { return /* binding */ init; }
|
||||
/* harmony export */ });
|
||||
/* DS2 core (c) 2024 Alexander McIlwraith
|
||||
Released under Creative Commons Attribution-ShareAlike 4.0 International
|
||||
*/
|
||||
/* DS2 core (c) 2024-2026 Alexander McIlwraith
|
||||
Released under Creative Commons Attribution-ShareAlike 4.0 International
|
||||
*/
|
||||
|
||||
// create a pure JS mouse click event
|
||||
var click = new MouseEvent('click', {
|
||||
@@ -3204,70 +3204,67 @@ var click = new MouseEvent('click', {
|
||||
bubbles: false,
|
||||
cancelable: true
|
||||
});
|
||||
|
||||
// wait for an element to appear in the DOM
|
||||
var waitForElement = function waitForElement(selector) {
|
||||
return new Promise(function (resolve) {
|
||||
if (document.querySelector(selector)) {
|
||||
return resolve(document.querySelector(selector));
|
||||
}
|
||||
var observer = new MutationObserver(function (mutations) {
|
||||
var observer = new MutationObserver(function () {
|
||||
if (document.querySelector(selector)) {
|
||||
observer.disconnect();
|
||||
resolve(document.querySelector(selector));
|
||||
}
|
||||
});
|
||||
|
||||
// If you get "parameter 1 is not of type 'Node'" error, see https://stackoverflow.com/a/77855838/492336
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Tab logic
|
||||
var tabNamespace = "#tab:";
|
||||
var chooseTab = function chooseTab(tab) {
|
||||
var siblings = Array.from(tab.parentNode.children);
|
||||
var siblings = Array.from(tab.closest('[role="tablist"]').querySelectorAll('[role="tab"]'));
|
||||
siblings.forEach(function (sibling) {
|
||||
return sibling.classList.remove("selected");
|
||||
});
|
||||
tab.classList.add("selected");
|
||||
var tabPanels = Array.from(tab.parentNode.parentNode.children);
|
||||
var tabGroup = tab.closest("tabset, .tab-group");
|
||||
var tabPanels = Array.from(tabGroup.querySelectorAll('[role="tabpanel"]'));
|
||||
tabPanels.forEach(function (panel) {
|
||||
return panel.classList.remove("open");
|
||||
});
|
||||
var tabPanelId = tab.getAttribute("id").replace("tab", "tab-panel");
|
||||
document.getElementById(tabPanelId).classList.add("open");
|
||||
};
|
||||
var pushState = 0;
|
||||
var pushStateCount = 0;
|
||||
var tabsetCount = 0;
|
||||
function init() {
|
||||
var container = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : document;
|
||||
var spacer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
||||
var args = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
||||
container.querySelectorAll(".tab-group, tabset").forEach(function (tabGroup) {
|
||||
if (tabGroup.querySelector("[role=tablist]") === null) {
|
||||
if (tabGroup.querySelector('[role="tablist"]') === null) {
|
||||
var _ul$querySelector;
|
||||
if (tabGroup.getAttribute("id") == null) {
|
||||
tabGroup.setAttribute("id", "tab-group-" + tabsetCount);
|
||||
tabsetCount++;
|
||||
tabGroup.setAttribute("id", "tab-group-".concat(tabsetCount++));
|
||||
}
|
||||
var tabgroup = tabGroup.getAttribute("id");
|
||||
var tablist = "";
|
||||
Array.from(tabGroup.children).forEach(function (child) {
|
||||
// is details?
|
||||
var dtls = child.nodeName == "DETAILS" ? true : false;
|
||||
|
||||
// get the tab text
|
||||
var tab = dtls ? child.querySelector("summary").innerHTML : child.getAttribute("tab") || child.getAttribute("data-tab");
|
||||
|
||||
// if the tab text is not blank
|
||||
if (tab !== null) {
|
||||
var tabID = tab.replace(/\W+/g, "-").toLowerCase();
|
||||
|
||||
// define the tab panel content
|
||||
var tabPanel = null;
|
||||
if (dtls) {
|
||||
var _child$querySelector;
|
||||
var isDetails = child.nodeName === "DETAILS";
|
||||
var tabLabel = isDetails ? (_child$querySelector = child.querySelector("summary")) === null || _child$querySelector === void 0 ? void 0 : _child$querySelector.innerHTML : child.getAttribute("tab") || child.getAttribute("data-tab");
|
||||
if (tabLabel !== null) {
|
||||
var tabID = tabLabel.replace(/\W+/g, "-").toLowerCase();
|
||||
var tabPanel;
|
||||
if (isDetails) {
|
||||
tabPanel = child;
|
||||
tabPanel.setAttribute("open", "");
|
||||
} else {
|
||||
tabPanel = document.createElement('div');
|
||||
tabPanel = document.createElement("div");
|
||||
tabPanel.appendChild(child.cloneNode(true));
|
||||
}
|
||||
tabPanel.id = "tab-panel-".concat(tabgroup, "-").concat(tabID);
|
||||
@@ -3276,75 +3273,166 @@ function init() {
|
||||
tabPanel.setAttribute("tabindex", "0");
|
||||
tabPanel.setAttribute("aria-labelledby", "tab-".concat(tabgroup, "-").concat(tabID));
|
||||
child.parentNode.replaceChild(tabPanel, child);
|
||||
tablist += "<li tabindex=\"0\" role=\"tab\" id=\"tab-".concat(tabgroup, "-").concat(tabID, "\"><span>").concat(tab, "</span></li>");
|
||||
tablist += "<li tabindex=\"0\" role=\"tab\" id=\"tab-".concat(tabgroup, "-").concat(tabID, "\">\n\t\t\t\t\t\t\t<span>").concat(tabLabel, "</span>\n\t\t\t\t\t\t</li>");
|
||||
} else {
|
||||
child.classList.add("tab-hidden");
|
||||
}
|
||||
});
|
||||
var ul = document.createElement('ul');
|
||||
var ul = document.createElement("ul");
|
||||
ul.setAttribute("role", "tablist");
|
||||
tabGroup.insertBefore(ul, tabGroup.firstChild);
|
||||
ul.innerHTML = spacer != true ? "".concat(tablist) : "".concat(tablist, "<li role=\"separator\" class=\"separator\"></li>");
|
||||
var wrapper = document.createElement("div");
|
||||
wrapper.className = "tab-scroll-wrapper";
|
||||
var scroller = document.createElement("div");
|
||||
scroller.className = "tab-scroll";
|
||||
var leftArrow = document.createElement("div");
|
||||
leftArrow.className = "tab-scroll-arrow left";
|
||||
leftArrow.setAttribute("aria-hidden", "true");
|
||||
leftArrow.innerHTML = "\n\t\t\t\t<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 -960 960 960\" width=\"24\" height=\"24\">\n\t\t\t\t\t<path d=\"M400-80 0-480l400-400 71 71-329 329 329 329-71 71Z\"/>\n\t\t\t\t</svg>\n\t\t\t";
|
||||
var rightArrow = document.createElement("div");
|
||||
rightArrow.className = "tab-scroll-arrow right";
|
||||
rightArrow.setAttribute("aria-hidden", "true");
|
||||
rightArrow.innerHTML = "\n\t\t\t\t<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 -960 960 960\" width=\"24\" height=\"24\">\n\t\t\t\t\t<path d=\"m321-80-71-71 329-329-329-329 71-71 400 400L321-80Z\"/>\n\t\t\t\t</svg>\n\t\t\t";
|
||||
ul.parentNode.insertBefore(wrapper, ul);
|
||||
wrapper.appendChild(scroller);
|
||||
wrapper.appendChild(leftArrow);
|
||||
wrapper.appendChild(rightArrow);
|
||||
scroller.appendChild(ul);
|
||||
var updateScrollState = function updateScrollState() {
|
||||
var isOverflowing = scroller.scrollWidth > scroller.clientWidth;
|
||||
wrapper.classList.toggle("is-overflowing", isOverflowing);
|
||||
var atStart = scroller.scrollLeft <= 1;
|
||||
var atEnd = scroller.scrollLeft + scroller.clientWidth >= scroller.scrollWidth - 2;
|
||||
leftArrow.classList.toggle("hidden", !isOverflowing || atStart);
|
||||
rightArrow.classList.toggle("hidden", !isOverflowing || atEnd);
|
||||
wrapper.classList.toggle("show-left", isOverflowing && !atStart);
|
||||
wrapper.classList.toggle("show-right", isOverflowing && !atEnd);
|
||||
};
|
||||
var scrollAmount = 15; // smaller = smoother per frame
|
||||
var scrollInterval = 16; // ~60fps
|
||||
|
||||
var scrollTimer = null;
|
||||
var startScrolling = function startScrolling(direction) {
|
||||
if (scrollTimer) return;
|
||||
var speed = 0.1;
|
||||
scrollTimer = setInterval(function () {
|
||||
speed = Math.min(speed + 0.01, 5); // ramp up
|
||||
scroller.scrollBy({
|
||||
left: direction * scrollAmount * speed,
|
||||
behavior: "auto"
|
||||
});
|
||||
}, scrollInterval);
|
||||
};
|
||||
var stopScrolling = function stopScrolling() {
|
||||
clearInterval(scrollTimer);
|
||||
scrollTimer = null;
|
||||
};
|
||||
leftArrow.addEventListener("mousedown", function () {
|
||||
return startScrolling(-1);
|
||||
});
|
||||
leftArrow.addEventListener("mouseup", stopScrolling);
|
||||
leftArrow.addEventListener("mouseleave", stopScrolling);
|
||||
leftArrow.addEventListener("touchstart", function () {
|
||||
return startScrolling(-1);
|
||||
});
|
||||
leftArrow.addEventListener("touchend", stopScrolling);
|
||||
rightArrow.addEventListener("mousedown", function () {
|
||||
return startScrolling(1);
|
||||
});
|
||||
rightArrow.addEventListener("mouseup", stopScrolling);
|
||||
rightArrow.addEventListener("mouseleave", stopScrolling);
|
||||
rightArrow.addEventListener("touchstart", function () {
|
||||
return startScrolling(1);
|
||||
});
|
||||
rightArrow.addEventListener("touchend", stopScrolling);
|
||||
var ARROW_ZONE = 40;
|
||||
wrapper.addEventListener("contextmenu", function (e) {
|
||||
var isOverflowing = wrapper.classList.contains("is-overflowing");
|
||||
if (!isOverflowing) return;
|
||||
var rect = wrapper.getBoundingClientRect();
|
||||
var isLeftZone = e.clientX < rect.left + ARROW_ZONE;
|
||||
var isRightZone = e.clientX > rect.right - ARROW_ZONE;
|
||||
if (isLeftZone || isRightZone) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
var scrollClickAmount = 150;
|
||||
leftArrow.addEventListener("click", function () {
|
||||
scroller.scrollBy({
|
||||
left: -scrollClickAmount,
|
||||
behavior: "smooth"
|
||||
});
|
||||
});
|
||||
rightArrow.addEventListener("click", function () {
|
||||
scroller.scrollBy({
|
||||
left: scrollClickAmount,
|
||||
behavior: "smooth"
|
||||
});
|
||||
});
|
||||
scroller.addEventListener("scroll", updateScrollState);
|
||||
window.addEventListener("resize", updateScrollState);
|
||||
updateScrollState();
|
||||
ul.innerHTML = spacer !== true ? tablist : "".concat(tablist, "<li role=\"separator\" class=\"separator\"></li>");
|
||||
requestAnimationFrame(updateScrollState);
|
||||
setTimeout(updateScrollState, 50);
|
||||
ul.innerHTML = spacer !== true ? tablist : "".concat(tablist, "<li role=\"separator\" class=\"separator\"></li>");
|
||||
|
||||
// Tab ordering
|
||||
if (tabGroup.hasAttribute("order") || tabGroup.hasAttribute("data-order")) {
|
||||
var order = (tabGroup.getAttribute("order") || tabGroup.getAttribute("data-order")).split(",");
|
||||
var items = Array.from(ul.getElementsByTagName("li"));
|
||||
items.sort(function (a, b) {
|
||||
console.log("here");
|
||||
var aa = order.indexOf(a.textContent.trim());
|
||||
var bb = order.indexOf(b.textContent.trim());
|
||||
|
||||
// Check if both items exist in orderArray
|
||||
if (aa === -1) return 1; // Move to the end if not found
|
||||
if (bb === -1) return -1; // Move to the end if not found
|
||||
|
||||
return aa - bb; // Sort based on the defined order
|
||||
if (aa === -1) return 1;
|
||||
if (bb === -1) return -1;
|
||||
return aa - bb;
|
||||
});
|
||||
ul.innerHTML = '';
|
||||
ul.innerHTML = "";
|
||||
items.forEach(function (item) {
|
||||
return ul.appendChild(item);
|
||||
});
|
||||
chooseTab(items[0]);
|
||||
}
|
||||
|
||||
// Tab event handlers
|
||||
tabGroup.querySelectorAll('[role="tab"]').forEach(function (tab) {
|
||||
tab.addEventListener("click", function (evt) {
|
||||
if (pushState == 0) {
|
||||
window.history.pushState({
|
||||
rand: Math.random(),
|
||||
pushState: pushState,
|
||||
tab: tab.parentNode.firstChild.getAttribute("id")
|
||||
}, "", "#".concat(tab.parentNode.firstChild.getAttribute("id")));
|
||||
pushState++;
|
||||
}
|
||||
var tabId = tab.getAttribute("id");
|
||||
var hash = "".concat(tabNamespace).concat(tabId);
|
||||
chooseTab(evt.currentTarget);
|
||||
window.history.pushState({
|
||||
rand: Math.random(),
|
||||
pushState: pushState,
|
||||
tab: tab.getAttribute("id")
|
||||
}, "", "#".concat(tab.getAttribute("id")));
|
||||
pushState++;
|
||||
tab: tabId
|
||||
}, "", "".concat(location.pathname).concat(location.search).concat(hash));
|
||||
pushStateCount++;
|
||||
});
|
||||
tab.addEventListener("keypress", function (e) {
|
||||
e.preventDefault();
|
||||
if (e.which == 32 || e.which == 13) {
|
||||
if (e.which === 32 || e.which === 13) {
|
||||
e.preventDefault();
|
||||
e.currentTarget.dispatchEvent(click);
|
||||
}
|
||||
});
|
||||
});
|
||||
ul.querySelector("li").classList.add("selected");
|
||||
}
|
||||
if (document.location.hash != "" && document.location.hash.substring(0, 5) == "#tab-") {
|
||||
waitForElement(document.location.hash).then(function (el) {
|
||||
//el.scrollIntoView();
|
||||
el.focus();
|
||||
el.dispatchEvent(click);
|
||||
});
|
||||
(_ul$querySelector = ul.querySelector("li")) === null || _ul$querySelector === void 0 || _ul$querySelector.classList.add("selected");
|
||||
}
|
||||
});
|
||||
|
||||
// Initial hash handling (tabs only)
|
||||
if (location.hash.startsWith(tabNamespace)) {
|
||||
var tabId = location.hash.replace(tabNamespace, "");
|
||||
waitForElement("#".concat(tabId)).then(function (el) {
|
||||
el.focus();
|
||||
el.dispatchEvent(click);
|
||||
});
|
||||
}
|
||||
|
||||
// History navigation (tabs only)
|
||||
window.addEventListener("popstate", function (e) {
|
||||
e.preventDefault();
|
||||
if (e.state != null) {
|
||||
chooseTab(document.querySelector("#".concat(e.state.tab)));
|
||||
} else {
|
||||
history.go(-1);
|
||||
var _e$state;
|
||||
if (!location.hash.startsWith(tabNamespace)) return;
|
||||
if ((_e$state = e.state) !== null && _e$state !== void 0 && _e$state.tab) {
|
||||
var tab = document.querySelector("#".concat(e.state.tab));
|
||||
if (tab) chooseTab(tab);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user