Wave changes
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
/**
|
||||
* cookbook.js
|
||||
* Works both as a direct page load AND when injected as a stacked pane
|
||||
* by script.js (which fetches pages and injects only #content).
|
||||
* cookbook.js — fixed for the new tab-based layout
|
||||
*
|
||||
* Changes vs original:
|
||||
* 1. initCookbook() is exported so script.js can call it after tab content loads
|
||||
* 2. cellValue() scans ALL tr elements (not just tbody) — org-mode hides thead via CSS
|
||||
* but the rows are still in the DOM under thead
|
||||
* 3. watchForPanes() now watches #content-area (the new tab container) instead of .stack-track
|
||||
* 4. Toolbar falls back to inserting before the first .outline-3 if .outline-2 is absent
|
||||
*/
|
||||
|
||||
(function () {
|
||||
@@ -10,7 +15,6 @@
|
||||
// ── Core init — scoped to a content root ──────────────────────────────────
|
||||
|
||||
function initCookbook(root) {
|
||||
// Already initialised on this root?
|
||||
if (root.dataset.cbInit) return;
|
||||
root.dataset.cbInit = "1";
|
||||
|
||||
@@ -22,7 +26,9 @@
|
||||
// ── Helpers ─────────────────────────────────────────────────────────────
|
||||
|
||||
function cellValue(table, label) {
|
||||
for (const row of table.querySelectorAll("tbody tr")) {
|
||||
// Scan ALL tr elements — org-mode thead is hidden via CSS but rows are
|
||||
// still in the DOM there; relying only on tbody misses them.
|
||||
for (const row of table.querySelectorAll("tr")) {
|
||||
const cells = row.querySelectorAll("td");
|
||||
if (cells.length >= 2 && cells[0].textContent.trim() === label)
|
||||
return cells[1].textContent.trim();
|
||||
@@ -61,8 +67,17 @@
|
||||
<span class="cb-count" aria-live="polite"></span>
|
||||
</div>`;
|
||||
|
||||
const firstSection = root.querySelector(".outline-2");
|
||||
if (firstSection) firstSection.parentNode.insertBefore(toolbar, firstSection);
|
||||
// Insert before first .outline-2; fall back to first .outline-3
|
||||
const insertTarget =
|
||||
root.querySelector(".outline-2") ||
|
||||
root.querySelector(".outline-3");
|
||||
|
||||
if (insertTarget) {
|
||||
insertTarget.parentNode.insertBefore(toolbar, insertTarget);
|
||||
} else {
|
||||
// Last resort: prepend into root
|
||||
root.prepend(toolbar);
|
||||
}
|
||||
|
||||
const searchInput = toolbar.querySelector(".cb-search");
|
||||
const filterBtns = toolbar.querySelectorAll(".cb-filter-btn");
|
||||
@@ -95,7 +110,7 @@
|
||||
const cooked = isCooked(table);
|
||||
const title = (block.querySelector("h3")?.textContent ?? "").toLowerCase();
|
||||
const kwRaw = cellValue(table, "Keywords");
|
||||
const kwLow = kwRaw.toLowerCase();
|
||||
const kwLow = kwLow = kwRaw.toLowerCase();
|
||||
|
||||
if (activeFilter === "cooked" && !cooked) { hide(block); return; }
|
||||
if (activeFilter === "uncooked" && cooked) { hide(block); return; }
|
||||
@@ -113,7 +128,6 @@
|
||||
shown++;
|
||||
});
|
||||
|
||||
// Hide category headings with no visible recipes
|
||||
root.querySelectorAll(".outline-2").forEach(section => {
|
||||
const hasVisible = Array.from(section.querySelectorAll(".outline-3"))
|
||||
.some(b => b.style.display !== "none");
|
||||
@@ -184,7 +198,6 @@
|
||||
|
||||
// ── Entry points ──────────────────────────────────────────────────────────
|
||||
|
||||
// 1. Direct page load — #content is already in the DOM
|
||||
function tryInitOnContent() {
|
||||
const content = document.getElementById("content");
|
||||
if (content && content.querySelector("table.recipe-meta")) {
|
||||
@@ -192,39 +205,57 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Stacked pane — script.js fetches a page and appends a new <article>
|
||||
// with the #content inside it. Watch for that.
|
||||
function watchForPanes() {
|
||||
const track = document.querySelector(".stack-track");
|
||||
if (!track) return;
|
||||
// Watch #content-area — this is where script.js appends new .tab-content divs.
|
||||
// Falls back to watching document.body if #content-area isn't ready yet.
|
||||
const getTrack = () =>
|
||||
document.getElementById("content-area") || document.body;
|
||||
|
||||
const observer = new MutationObserver(mutations => {
|
||||
mutations.forEach(m => {
|
||||
m.addedNodes.forEach(node => {
|
||||
if (node.nodeType !== 1) return;
|
||||
// script.js appends an <article class="stack-pane">
|
||||
// containing a div#content
|
||||
const content = node.id === "content"
|
||||
? node
|
||||
: node.querySelector("#content, .content");
|
||||
if (content && content.querySelector("table.recipe-meta")) {
|
||||
initCookbook(content);
|
||||
}
|
||||
const observe = (track) => {
|
||||
const observer = new MutationObserver(mutations => {
|
||||
mutations.forEach(m => {
|
||||
m.addedNodes.forEach(node => {
|
||||
if (node.nodeType !== 1) return;
|
||||
// script.js appends .tab-content divs containing a div#content
|
||||
const content =
|
||||
(node.id === "content" ? node : null) ||
|
||||
node.querySelector("#content, .content");
|
||||
if (content && content.querySelector("table.recipe-meta")) {
|
||||
initCookbook(content);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
observer.observe(track, { childList: true, subtree: true });
|
||||
};
|
||||
|
||||
observer.observe(track, { childList: true, subtree: true });
|
||||
const track = document.getElementById("content-area");
|
||||
if (track) {
|
||||
observe(track);
|
||||
} else {
|
||||
// content-area is built by script.js after DOMContentLoaded;
|
||||
// wait for it to appear then start observing.
|
||||
const bodyObserver = new MutationObserver(() => {
|
||||
const area = document.getElementById("content-area");
|
||||
if (area) {
|
||||
bodyObserver.disconnect();
|
||||
observe(area);
|
||||
}
|
||||
});
|
||||
bodyObserver.observe(document.body, { childList: true, subtree: false });
|
||||
}
|
||||
}
|
||||
|
||||
// Run both
|
||||
// Expose for direct calls from script.js if needed:
|
||||
// window.initCookbook(contentEl);
|
||||
window.initCookbook = initCookbook;
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
tryInitOnContent();
|
||||
watchForPanes();
|
||||
});
|
||||
} else {
|
||||
// Already parsed (script has `defer` but DOM may already be ready)
|
||||
tryInitOnContent();
|
||||
watchForPanes();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user