138 lines
5.3 KiB
JavaScript
138 lines
5.3 KiB
JavaScript
// MNote debug /tree shell DOM patch and hydration helpers.
|
|
|
|
export function patchTreeShellPageActiveDom(context) {
|
|
if (context.mode !== "page") return;
|
|
context.appElement.querySelectorAll('[data-rust-rendered-row="page"]').forEach((row) => {
|
|
if (!(row instanceof HTMLElement)) return;
|
|
const nodeId = context.normalizeText(row.dataset.nodeId);
|
|
const isFocused = nodeId === context.focusedNodeId;
|
|
row.dataset.active = String(nodeId === context.currentActiveDocumentId);
|
|
row.dataset.focused = String(isFocused);
|
|
row.tabIndex = isFocused ? 0 : -1;
|
|
row.dataset.dropFeedback = String(context.activePageDropNodeId === nodeId);
|
|
});
|
|
}
|
|
|
|
export function patchTreeShellPageExpansionDom(context, nodeId) {
|
|
if (context.mode !== "page") return false;
|
|
const normalizedNodeId = context.normalizeText(nodeId);
|
|
if (!normalizedNodeId) return false;
|
|
const item = context.itemById.get(normalizedNodeId);
|
|
if (!item) return false;
|
|
const nodeElement = context.appElement.querySelector(
|
|
`.tree-node[data-node-id="${CSS.escape(normalizedNodeId)}"]`,
|
|
);
|
|
if (!(nodeElement instanceof HTMLElement)) return false;
|
|
const row = nodeElement.querySelector(
|
|
`:scope > .tree-row[data-node-id="${CSS.escape(normalizedNodeId)}"]`,
|
|
);
|
|
const children = context.getSiblings(normalizedNodeId);
|
|
const hasChildren = item.childCount > 0 && children.length > 0;
|
|
const isExpanded = hasChildren && context.expanded.has(normalizedNodeId);
|
|
if (row instanceof HTMLElement) {
|
|
row.setAttribute("aria-expanded", hasChildren ? String(isExpanded) : "false");
|
|
const toggleButton = row.querySelector('[data-testid="tree-node-toggle"]');
|
|
if (toggleButton instanceof HTMLButtonElement) {
|
|
toggleButton.textContent = isExpanded ? "▾" : "▸";
|
|
toggleButton.setAttribute(
|
|
"aria-label",
|
|
`${isExpanded ? "折叠" : "展开"} ${item.title}`,
|
|
);
|
|
}
|
|
}
|
|
if (!hasChildren) {
|
|
context.patchPageTreeActiveDom();
|
|
return true;
|
|
}
|
|
let childrenList = Array.from(nodeElement.children).find(
|
|
(child) => child instanceof HTMLElement && child.classList.contains("tree-children"),
|
|
);
|
|
if (isExpanded) {
|
|
if (!(childrenList instanceof HTMLElement)) {
|
|
childrenList = document.createElement("ul");
|
|
childrenList.className = "tree-children";
|
|
children.forEach((child) => {
|
|
childrenList.appendChild(context.renderNode(child));
|
|
});
|
|
nodeElement.appendChild(childrenList);
|
|
}
|
|
childrenList.hidden = false;
|
|
childrenList.style.display = "";
|
|
} else if (childrenList instanceof HTMLElement) {
|
|
childrenList.hidden = true;
|
|
childrenList.style.display = "none";
|
|
}
|
|
context.patchPageTreeActiveDom();
|
|
return true;
|
|
}
|
|
|
|
export function hydrateTreeShellInitialPageTree(context) {
|
|
if (context.mode !== "page") return false;
|
|
const root = context.appElement.querySelector('[data-rust-page-renderer="initial_v1"]');
|
|
if (!(root instanceof HTMLElement)) {
|
|
return false;
|
|
}
|
|
root.querySelectorAll('[data-rust-rendered-row="page"]').forEach((row) => {
|
|
if (!(row instanceof HTMLElement)) return;
|
|
const nodeId = context.normalizeText(row.dataset.nodeId);
|
|
const item = context.itemById.get(nodeId);
|
|
if (!item) return;
|
|
context.bindPageRowEvents(row, item);
|
|
});
|
|
if (context.focusedNodeId) {
|
|
context.focusRowElement(context.focusedNodeId);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
export function focusTreeShellPickerRowElement(context, pickerItemKey) {
|
|
const normalizedItemKey = context.normalizeText(pickerItemKey);
|
|
window.requestAnimationFrame(() => {
|
|
const row =
|
|
normalizedItemKey === "__root__"
|
|
? context.appElement.querySelector('[data-rust-rendered-row="picker-root"]')
|
|
: context.appElement.querySelector(
|
|
`.tree-row[data-node-id="${CSS.escape(normalizedItemKey)}"]`,
|
|
);
|
|
if (!(row instanceof HTMLElement)) return;
|
|
row.focus({ preventScroll: true });
|
|
row.scrollIntoView({ block: "nearest" });
|
|
});
|
|
}
|
|
|
|
export function patchTreeShellPickerActiveDom(context) {
|
|
if (context.mode !== "picker") return;
|
|
context.appElement
|
|
.querySelectorAll('[data-rust-rendered-row="picker"], [data-rust-rendered-row="picker-root"]')
|
|
.forEach((row) => {
|
|
if (!(row instanceof HTMLElement)) return;
|
|
const nodeId = context.normalizeText(row.dataset.nodeId);
|
|
const isRoot = row.dataset.rustRenderedRow === "picker-root";
|
|
const isFocused = isRoot
|
|
? context.currentActivePickerItemKey === "__root__"
|
|
: context.currentActivePickerItemKey === nodeId ||
|
|
(!context.currentActivePickerItemKey && context.currentActiveDocumentId === nodeId);
|
|
row.dataset.focused = String(isFocused);
|
|
row.tabIndex = isFocused ? 0 : -1;
|
|
});
|
|
}
|
|
|
|
export function hydrateTreeShellInitialPickerTree(context) {
|
|
if (context.mode !== "picker") return false;
|
|
const root = context.appElement.querySelector('[data-rust-picker-renderer="initial_v1"]');
|
|
if (!(root instanceof HTMLElement)) {
|
|
return false;
|
|
}
|
|
root.querySelectorAll('[data-rust-rendered-row="picker-root"]').forEach((row) => {
|
|
context.bindPickerRootEvents(row);
|
|
});
|
|
root.querySelectorAll('[data-rust-rendered-row="picker"]').forEach((row) => {
|
|
if (!(row instanceof HTMLElement)) return;
|
|
const nodeId = context.normalizeText(row.dataset.nodeId);
|
|
const item = context.itemById.get(nodeId);
|
|
if (!item) return;
|
|
context.bindPickerRowEvents(row, item);
|
|
});
|
|
return true;
|
|
}
|