Hi Devin and all, Devin Prater <r.d.t.pra...@gmail.com> writes:
> Yeah, I was hoping to just have an HTML page or something that could > be put on Github or just sent in an email attachment, where checking > checkboxes would update the fraction cookie. I hacked together a quick solution for this. You should be able to just drop this Javascript into an Org file. When it is included in HTML that has been exported via the standard Org exporter, it replaces the static "[ ]" and "[X]" code elements with actual HTML checkboxes, and updates any progress cookies in the relevant headlines when those boxes are checked or unchecked. I haven't tested it extensively, and the code can surely be improved, but it works for the cases I could think to test. #+begin_export html <script type="text/javascript"> function updateCookiesIn(div) { const headline = div.querySelector("h1, h2, h3, h4, h5, h6"); if (!headline) return; const cookies = Array.from(headline.querySelectorAll("code")) .filter(c => c.innerText.startsWith("[") && c.innerText.endsWith("]")); const fracCookies = cookies.filter(c => c.innerText.includes("/")); const pctCookies = cookies.filter(c => c.innerText.includes("%")); // The ugly query strings here restrict the selection to checkboxes at *this* level of the hierarchy const allTasks = div.querySelectorAll(`#${div.id} > div > ul input[type=checkbox], #${div.id} > div > ol input[type=checkbox]`); const completedTasks = div.querySelectorAll(`#${div.id} > div > ul input[type=checkbox]:checked, #${div.id} > div > ol input[type=checkbox]:checked`); const newFrac = `[${completedTasks.length}/${allTasks.length}]`; const newPctText = allTasks.length ? (100 * completedTasks.length / allTasks.length).toFixed(0) : "100"; // Org shows 100% for a cookie when there are no checkboxes const newPct = `[${newPctText}%]`; fracCookies.forEach(c => c.innerText = newFrac); pctCookies.forEach(c => c.innerText = newPct); } function replaceWithCheckbox(code) { const isChecked = code.innerText.includes("X"); const checkbox = document.createElement("input"); checkbox.setAttribute("type", "checkbox"); if (isChecked) checkbox.setAttribute("checked", "checked"); checkbox.onclick = function (e) { const container = findContainingSection(e.target); if (!container) return; updateCookiesIn(container); }; code.replaceWith(checkbox); } function findContainingSection(el) { if (!el.parentElement) return null; const parent = el.parentElement; const classes = Array.from(parent.classList); if (classes.some(cl => cl.startsWith("outline") && !cl.startsWith("outline-text"))) { return parent; } else { return findContainingSection(parent); } } const orgCheckboxes = document.querySelectorAll(".off > code, .on > code"); orgCheckboxes.forEach(replaceWithCheckbox); const orgSections = document.querySelectorAll("div.outline-1, div.outline-2, div.outline-3, div.outline-4, div.outline-5, div.outline-6"); orgSections.forEach(updateCookiesIn); </script> #+end_export Hope that helps! -- Best, Richard