emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Devin Prater <r.d.t.prater@gmail.com>
To: Richard Lawrence <wyley.r@gmail.com>
Cc: Phil Regier <phil.regier@gmail.com>,
	emacs-orgmode <emacs-orgmode@gnu.org>
Subject: Re: Get Grades Done: the joys of Org's simple power
Date: Sun, 14 Jun 2020 11:05:24 -0500	[thread overview]
Message-ID: <CE273E08-2EEC-4D75-963B-3E0B295AC5EB@gmail.com> (raw)
In-Reply-To: <871rmic94x.fsf@aquinas>

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	other threads:[~2020-06-14 16:06 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-06-10 20:38 Get Grades Done: the joys of Org's simple power Devin Prater
2020-06-11  3:22 ` Russell Adams
2020-06-11  3:55   ` George Mauer
2020-06-11  5:47     ` Steven Harris
2020-06-12 23:23     ` Phil Regier
2020-06-13  0:22       ` Devin Prater
2020-06-13  2:17         ` Phil Regier
2020-06-13  2:45           ` Devin Prater
2020-06-14  9:02             ` Richard Lawrence
2020-06-14 16:05               ` Devin Prater [this message]
2020-06-14 16:59                 ` Richard Lawrence
2020-06-14 20:53                   ` Devin Prater
2020-06-20  4:10                     ` Richard Lawrence
2020-09-03 10:09               ` Bastien
2020-06-11  5:36 ` Diego Zamboni
2020-06-12 15:54   ` Leo Okawa Ericson
2020-06-12 17:01     ` Diego Zamboni
2020-06-13  9:10       ` Leo Okawa Ericson
2020-06-13 11:16         ` Diego Zamboni

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CE273E08-2EEC-4D75-963B-3E0B295AC5EB@gmail.com \
    --to=r.d.t.prater@gmail.com \
    --cc=emacs-orgmode@gnu.org \
    --cc=phil.regier@gmail.com \
    --cc=wyley.r@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).