Material

Custom spans in Org mode

Org mode's HTML export lets you use #+BEGIN_... and #+END_... blocks for custom <div> classes, but what about custom <span> classes? There are some ways to do it, but they all move the text out of the normal document flow, which makes reading the source difficult. Instead, you can use org-add-link-type, usually a way to register custom link schemes. Org links are inline and quite readable, and there is a notion of a link that isn't clickable, so it's not too much semantic abuse.

(defun jw/html-escape-attribute (value)
  "Entity-escape VALUE and wrap it in quotes."
  ;; http://www.w3.org/TR/2009/WD-html5-20090212/serializing-html-fragments.html
  ;;
  ;; "Escaping a string... consists of replacing any occurrences of
  ;; the "&amp;" character by the string "&amp;amp;", any occurrences of the
  ;; U+00A0 NO-BREAK SPACE character by the string "&amp;nbsp;", and, if
  ;; the algorithm was invoked in the attribute mode, any occurrences
  ;; of the """ character by the string "&amp;quot;"..."
  (let* ((value (replace-regexp-in-string "&amp;" "&amp;amp;" value))
         (value (replace-regexp-in-string "\u00a0" "&amp;nbsp;" value))
         (value (replace-regexp-in-string "\"" "&amp;quot;" value)))
    value))


(eval-after-load "org"
  '(org-add-link-type
    "span" #'ignore ; not an 'openable' link
    #'(lambda (class desc format)
        (pcase format
          (`html (format "&lt;span class=\"%s\"&gt;%s&lt;/span&gt;"
                         (jw/html-escape-attribute class)
                         (or desc "")))
          (_ (or desc ""))))))

Now you can type links such as:

Check out this [[span:special][text block]].

Which generates HTML output like:

&lt;p&gt;Check out this &lt;span class="special"&gt;text block&lt;/span&gt;.&lt;/p&gt;