emacs-orgmode
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Get Grades Done: the joys of Org's simple power


From: Devin Prater
Subject: Re: Get Grades Done: the joys of Org's simple power
Date: Sun, 14 Jun 2020 11:05:24 -0500

I tried that on my file, but the checkboxes didn’t update. I’ll give you the 
kind of file I’m working with:

#+title: Performance 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

* Performance test
**  Student Name [0/10] [0%]

Date

The student will perform the following features:

1. [ ] 
2. [ ] 
3. [ ] 
4. [ ] 
5. [ ] 
6. [ ] 
7. [ ] 
8. [ ] 
9. [ ] 
10. [ ] 

When I do C-E h o, and check one of the boxes, the grade isn’t updated.

> On Jun 14, 2020, at 4:02 AM, Richard Lawrence <wyley.r@gmail.com> wrote:
> 
> Hi Devin and all,
> 
> Devin Prater <r.d.t.prater@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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]