Files
ROCm/docs/extension/rocm_docs_custom/static/selector.js
peterjunpark 39783dcee0 [docs/7.9.0] Fix GPU marketing names in 7.9.0 release.md and compatibility matrix / Add SD3.5 ComfyUI example (#5552)
* Add SD3.5 example to comfyui doc

* Fix Ryzen AI Max (PRO) SKU names

* Add names in multi line format
2025-10-21 11:02:48 -04:00

306 lines
8.3 KiB
JavaScript

const READY_EVENT = "ROCmDocsSelectorsReady";
const STATE_CHANGE_EVENT = "ROCmDocsSelectorStateChanged";
const GROUP_QUERY = ".rocm-docs-selector-group";
const OPTION_QUERY = ".rocm-docs-selector-option";
const COND_QUERY = "[data-show-when]";
const TOC2_OPTIONS_LIST_QUERY = ".rocm-docs-selector-toc2-options";
const TOC2_CONTENTS_LIST_QUERY = ".rocm-docs-selector-toc2-contents";
const HEADING_QUERY = ".rocm-docs-selected-content h1,h2,h3,h4,h5,h6[id]";
const isDefaultOption = (elem) =>
elem.classList.contains("rocm-docs-selector-option-default");
const DISABLED_CLASS = "rocm-docs-disabled";
const disable = (elem) => {
elem.classList.add(DISABLED_CLASS);
elem.setAttribute("aria-disabled", "true");
elem.setAttribute("tabindex", "-1");
};
// const enable = (elem) => {
// elem.classList.remove(DISABLED_CLASS);
// elem.setAttribute("aria-disabled", "false");
// elem.setAttribute("tabindex", "0");
// };
const HIDDEN_CLASS = "rocm-docs-hidden";
const hide = (elem) => {
elem.classList.add(HIDDEN_CLASS);
elem.setAttribute("aria-hidden", "true");
};
const show = (elem) => {
elem.classList.remove(HIDDEN_CLASS);
elem.setAttribute("aria-hidden", "false");
};
const SELECTED_CLASS = "rocm-docs-selected";
const select = (elem) => {
elem.classList.add(SELECTED_CLASS);
elem.setAttribute("aria-checked", "true");
};
const deselect = (elem) => {
elem.classList.remove(SELECTED_CLASS);
elem.setAttribute("aria-checked", "false");
};
const state = {};
function getState() {
return { ...state };
}
function setState(updates) {
const previousState = getState();
Object.assign(state, updates);
const event = new CustomEvent(STATE_CHANGE_EVENT, {
detail: {
previousState,
currentState: getState(),
changes: updates,
},
});
document.dispatchEvent(event);
}
function validateOptionElem(optionElem) {
const key = optionElem.dataset.selectorKey;
const value = optionElem.dataset.selectorValue;
const errors = [];
if (!key) errors.push("Missing 'data-selector-key'");
if (!value) errors.push("Missing 'data-selector-value'");
if (errors.length === 0) return;
const label = optionElem.textContent.trim() || "<unnamed option>";
console.error(
`[ROCmDocsSelector] Invalid selector option '${label}': ${
errors.join(", ")
}!`,
);
disable(optionElem);
}
function handleOptionSelect(e) {
const option = e.currentTarget;
const parentGroup = option.closest(GROUP_QUERY);
const siblingOptions = parentGroup.querySelectorAll(OPTION_QUERY);
siblingOptions.forEach((elem) => deselect(elem));
select(option);
// Update global state
const key = option.dataset.selectorKey;
const value = option.dataset.selectorValue;
if (key && value) setState({ [key]: value });
updateVisibility();
}
function shouldBeShown(elem) {
const conditionsData = elem.dataset.showWhen;
if (!conditionsData) return true; // Default visible
try {
const conditions = JSON.parse(conditionsData);
// Ensure it's an object
if (typeof conditions !== "object" || Array.isArray(conditions)) {
console.warn(
"[ROCmDocsSelector] Invalid 'show-when' format (must be key/value object):",
conditionsData,
);
return true;
}
for (const [key, value] of Object.entries(conditions)) {
const currentValue = state[key];
if (currentValue === undefined) return false;
if (Array.isArray(value)) {
if (!value.includes(currentValue)) return false;
continue;
}
if (state[key] !== value) {
return false;
}
}
return true;
} catch (err) {
console.error(
"[ROCmDocsSelector] Couldn't parse 'show-when' conditions:",
err,
);
return true;
}
}
function updateTOC2OptionsList() {
const tocOptionsList = document.querySelector(TOC2_OPTIONS_LIST_QUERY);
if (!tocOptionsList) return;
// Clear previous entries
tocOptionsList.innerHTML = "";
// Get only visible selector groups
const groups = Array.from(document.querySelectorAll(GROUP_QUERY)).filter(
(g) => g.offsetParent !== null,
);
if (groups.length === 0) {
const li = document.createElement("li");
li.className =
"nav-item toc-entry toc-h3 rocm-docs-selector-toc2-item empty";
const span = document.createElement("span");
span.textContent = "(no visible selectors)";
li.appendChild(span);
tocOptionsList.appendChild(li);
return;
}
groups.forEach((group) => {
// ✅ Find group heading span
const headingSpan = group.querySelector(
".rocm-docs-selector-group-heading-text",
);
const headingText = headingSpan
? headingSpan.textContent.trim()
: "(Unnamed Selector)";
// Find currently selected option
const selectedOption = group.querySelector(`.${SELECTED_CLASS}`);
let optionText = "(none selected)";
if (selectedOption) {
const clone = selectedOption.cloneNode(true);
// Remove all <i> elements
clone.querySelectorAll("i, svg").forEach((el) => el.remove());
optionText = clone.innerHTML.trim();
}
// Build list item
const li = document.createElement("li");
li.className = "nav-item toc-entry toc-h3 rocm-docs-selector-toc2-item";
const link = document.createElement("a");
link.className = "nav-link";
link.href = `#${group.id}`;
link.innerHTML = `<strong>${headingText}</strong>: ${optionText}`;
li.appendChild(link);
tocOptionsList.appendChild(li);
});
}
function updateTOC2ContentsList() {
const tocOptionsList = document.querySelector(TOC2_OPTIONS_LIST_QUERY);
const tocContentsList = document.querySelector(TOC2_CONTENTS_LIST_QUERY);
if (!tocContentsList || !tocOptionsList) return;
const visibleHeaders = [...document.querySelectorAll(HEADING_QUERY)]
.filter((h) => h.offsetParent !== null); // only visible headings
tocContentsList
.querySelectorAll("li.toc-entry.rocm-docs-selector-toc2-item")
.forEach((node) => node.remove());
if (visibleHeaders.length === 0) return;
let lastH2Li = null;
visibleHeaders.forEach((h) => {
const level = parseInt(h.tagName.substring(1), 10);
const li = document.createElement("li");
li.className =
`nav-item toc-entry toc-${h.tagName.toLowerCase()} rocm-docs-selector-toc2-item`;
const a = document.createElement("a");
a.className = "reference internal nav-link";
const section = h.closest("section");
const fallbackId = section ? section.id : "";
a.href = h.id ? `#${h.id}` : fallbackId ? `#${fallbackId}` : "#";
a.textContent = h.cloneNode(true).childNodes[0].textContent.trim();
li.appendChild(a);
// Nest logic: h3+ belong to last h2's inner list
if (level === 2) {
tocContentsList.appendChild(li);
lastH2Li = li;
} else if (level === 3 && lastH2Li) {
// ensure nested UL exists
let innerUl = lastH2Li.querySelector("ul");
if (!innerUl) {
innerUl = document.createElement("ul");
innerUl.className = "nav section-nav flex-column";
lastH2Li.appendChild(innerUl);
}
innerUl.appendChild(li);
} else {
tocContentsList.appendChild(li);
}
});
}
function updateVisibility() {
document.querySelectorAll(COND_QUERY).forEach((elem) => {
if (shouldBeShown(elem)) {
show(elem);
} else {
hide(elem);
}
});
updateTOC2OptionsList();
updateTOC2ContentsList();
}
function init() {
const selectorOptions = document.querySelectorAll(OPTION_QUERY);
const initialState = {};
// Attach listeners and gather defaults
selectorOptions.forEach((option) => {
validateOptionElem(option);
option.addEventListener("click", handleOptionSelect);
option.addEventListener("keydown", (e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
handleOptionSelect(e);
}
});
if (isDefaultOption(option)) {
select(option);
const { selectorKey: key, selectorValue: value } = option.dataset;
if (key && value) {
initialState[key] = value;
}
}
});
setState(initialState);
updateVisibility();
document.dispatchEvent(new CustomEvent(READY_EVENT));
}
function domReady(callback) {
if (document.readyState !== "loading") {
callback();
} else {
document.addEventListener("DOMContentLoaded", callback, { once: true });
}
}
// window.rocmDocsSelector = {
// setState,
// getState,
// };
// Initialize when DOM is ready
domReady(init);