Hacking Org Mode Drawers


2021-03-23T23:33:38+01:00
org mode emacs emacs lisp

It wasn’t on top of the priority list, but it was simple enough, so I did that first.

Org doesn’t do much in terms of export when it comes to drawers. The default HTML backend translator just… exports their contents. It even drops their name on the way.

I’ve attended a few MOOCs recently that were well-funded enough to feature transcripts for most of the videos. Now, as such, those don’t exactly qualify as quality note-taking. But they’re very handy to keep around, if only to have plain text available for keyword search. So I usually copy-paste them to an Org drawer.

So yeah, when exported, it sucks by default. Very noisy, kills the flow. The appropriate export would have them invisible by default, and revealed on demand.

So here’s a bit of code to that effect.

(defun my-format-drawer (name contents &rest args?)
  (if (string= name "TRANSCRIPTION")
      (let ((h (format "%x" (sxhash contents))))
        (concat
         "<a id=\"show-" h "\" "
         "onclick='"
         "document.getElementById(\"ts-" h "\").style.display = \"block\"; "
         "document.getElementById(\"show-" h "\").style.display = \"none\"; "
         "document.getElementById(\"hide-" h "\").style.display = null; "
         "return false;' "
         "href=\"#ts-" h "\">"
         "[show transcript]"
         "</a>"
         "<a id=\"hide-" h "\" "
         "onclick='"
         "document.getElementById(\"ts-" h "\").style.display = \"none\"; "
         "document.getElementById(\"show-" h "\").style.display = null; "
         "document.getElementById(\"hide-" h "\").style.display = \"none\"; "
         "return false;' "
         "style='display: none;' "
         "href=\"#show-" h "\">"
         "[hide transcript]"
         "</a>"
         "<div id='ts-" h "' style='display: none;'>"
         contents
         "</div>"))
    (apply org-html-format-drawer-function name contents args?)))

Nothing too fancy, just two <a> elements and a <div>. The anchors have an onclick event handler to toggle the div’s visibility. And hide self, show the other one.

Inline scripts instead of something factored in a separate JavaScript file because… I’m not too sure, actually. It makes for totally localized Elisp, which is something. I’m not sure how a factored-out variant would look.

Activate by customizing `org-html-format-drawer-function’, or by setting the appropriate property at publish-project level:

;; I'm not quite sure why this isn't in by default :-/
;; Possibly the ambiguous list-head modifying specification?
(gv-define-simple-setter plist-get plist-put)

(setf (plist-get (cdr zk-notes) :html-format-drawer-function) #'my-format-drawer)

I’d really like to get rid of the JavaScript, but I’m not sure it can actually be done in this case. Please tell me!