This is some sample text with annotations.[fn::This is an annotation, aka a “footnote”.] “Footnotes” actually appear on the side when exported to HTML.
(setq org-html-head-include-default-style t)
(setq org-html-htmlize-output-type nil)We’ll define a new backend derived from html.
(org-export-define-derived-backend 'annotated-html 'html
:translate-alist '((footnote-reference . annotated-footnote-reference)
(src-block . pygments-org-html-code)
(example-block . pygments-org-html-code)))The following function has been clobbered together from code inspired by ox-tufte and jnboehm’s Tufte CSS backend.
(defun annotated-footnote-reference (footnote-reference _contents info)
"Transcode a FOOTNOTE-REFERENCE element from Org to HTML.
CONTENTS is nil. INFO is a plist holding contextual information."
(concat
;; Insert separator between two footnotes in a row.
(let ((prev (org-export-get-previous-element footnote-reference info)))
(when (eq (org-element-type prev) 'footnote-reference)
(plist-get info :html-footnote-separator)))
(let* ((n (org-export-get-footnote-number footnote-reference info))
(fnr-id (format "fnr.%d%s" n
(if (org-export-footnote-first-reference-p
footnote-reference info)
""
".100")))
(fn-id (format "fn.%d" n))
(raw-text (org-trim
(org-export-data
(org-export-get-footnote-definition footnote-reference info)
info)))
;; footnotes must have spurious <p> tags removed or they will not work
(text (replace-regexp-in-string "</?p.*>" "" raw-text)))
(concat
;; Format the footnote reference in the main text.
(format
;; Format as per :html-footnote-format (typically within <sup> tags).
(plist-get info :html-footnote-format)
;; Construct a link to the actual footnote.
(org-html--anchor
fnr-id n
(format " class=\"footref\" href=\"#%s\" role=\"doc-backlink\" onmouseover=\"textHLOn(this, '%s')\" onmouseout=\"textHLOff(this, '%s')\"" fn-id fn-id fn-id) info))
;; Format the footnote number and text.
(format
"<span class=\"annot\" id=\"%s\" onmouseover=\"sidenoteHLOn(this,'%s')\" onmouseout=\"sidenoteHLOff(this, '%s')\">%d. %s</span>"
fn-id
fnr-id
fnr-id
n
text)
))))The following function is based on code from Anton Linevych’s blog.
(defvar pygments-path "pygmentize")
(defun pygments-org-html-code (code contents info)
;; Generating tmp file path.
;; Current date and time hash will ideally pass our needs.
(setq temp-source-file (format "/tmp/pygmentize-%s.txt"(md5 (current-time-string))))
;; Writing block contents to the file.
(with-temp-file temp-source-file (insert (org-element-property :value code)))
(let* ((lang (or (org-element-property :language code) ""))
;; Executing the shell-command and reading an output
(pygments-output (shell-command-to-string
(format "%s -l \"%s\" -f html %s"
pygments-path
lang
temp-source-file)))
(pre-replacement (if (string-equal lang "")
"<pre class=\"src\""
(format "<pre class=\"src src-%s\"" lang))))
;; Add language name to the <pre> tag. Now displays language name on hover.
(replace-regexp-in-string "<pre>" pre-replacement pygments-output)))Export functions for the new backend. Once again inspired by ox-tufte and jnboehm’s Tufte CSS backend.
<<derived-backend>>
<<annotated-footnote-reference>>
<<pyments-org-html-code>>
(defun org-annotated-export-to-buffer
(&optional async subtreep visible-only body-only ext-plist)
"Export current buffer as an html buffer with annotation customisations.
If narrowing is active in the current buffer, only export its
narrowed part.
If a region is active, export that region.
A non-nil optional argument ASYNC means the process should happen
asynchronously. The resulting buffer should be accessible
through the `org-export-stack' interface.
When optional argument SUBTREEP is non-nil, export the sub-tree
at point, extracting information from the headline properties
first.
When optional argument VISIBLE-ONLY is non-nil, don't export
contents of hidden elements.
When optional argument BODY-ONLY is non-nil, only write code
between the bo
EXT-PLIST, when provided, is a property list with external
parameters overriding Org default settings, but still inferior to
file-local settings.
Export is done in a buffer named \"*Org annotated html export*\", which
will be displayed when `org-export-show-temporary-export-buffer'
is non-nil."
(interactive)
(org-export-to-buffer 'annotated-html "*Org annotated html export*"
async subtreep visible-only body-only ext-plist (lambda () (html-mode))))
(defun org-annotated-export-to-file (&optional async subtreep visible-only)
"Export current buffer to an annotated HTML file.
If narrowing is active in the current buffer, only export its
narrowed part.
If a region is active, export that region.
A non-nil optional argument ASYNC means the process should happen
asynchronously. The resulting file should be accessible through
the `org-export-stack' interface.
When optional argument SUBTREEP is non-nil, export the sub-tree
at point, extracting information from the headline properties
first.
When optional argument VISIBLE-ONLY is non-nil, don't export
contents of hidden elements.
Return output file's name."
(interactive)
(let ((outfile (org-export-output-file-name ".html" subtreep))
;; need to bind this because we don't want to display list of footnotes
;; at the bottom
(org-html-footnotes-section "<!-- %s --><!-- %s -->"))
(org-export-to-file 'annotated-html outfile async subtreep visible-only)))Convert the chosen pygments style (in the variable style) to css.
We have (once again) used gruvbox-light.
pygmentize -S $style -f html -a .highlightBasic CSS stylesheet to include in the html headers. We begin with some variables to set up the theme, which is based on gruvbox. We then override the default css used by ox-html.
@media screen and (max-width: 480px) {
body {
max-width:95%;
font-size:90%;
}
#content { margin-right: 0em;}
.annot { display: block;}
}
@media screen and (min-width: 480px) {
body {
max-width:80%;
font-size:90%
}
#content {
margin-right:20%;
}
.annot {float: right;
clear: right; margin-left: 5%; margin-right: -25%; width: 20%;}
}
@media screen and (min-width: 550px) {
body {
}
}
@media screen and (min-width: 1000px) {
body {
max-width:1000px;
}
#content {
margin-right:30%;
}
.annot {float: right;
clear: right; margin-left: 5%; margin-right: -35%; width: 30%;}
}
body {
font-family: 'Roboto Slab', sans-serif;
background: <<bg-color>>;
color: <<fg-color>>;
margin-top: 0em;
margin-left:auto;
margin-right:auto;
}
.title {
text-align: left;
margin: 0em;
padding: 0.5em 0em;
}
h1 > .title {
font-size: 110%;
}
* a {
color: <<link-color>>;
text-decoration: none;
}
* a:hover {
text-decoration: underline;
}
h1, h2, h3, h4 {
}
ul {
padding-left: 1em;
}
ol {
padding-left: 1em;
}
.annot {
font-size: 75%;
}
pre {
background-color: inherit;
border: none;
margin: 0;
}
.highlight {
border: solid 1px <<link-color>>75;
}
.todo, .done, .priority {
font-size: 90%;
font-weight: bold;
}This section will contain scripts that do fancy things when we hover over annotations.
Output HTML headers containing the stylesheet and (eventually) javascript.
(concat "<style>"
"
<<pygments-style()>>
<<annotated-css>>
"
"</style>")I am not entirely sure why this is necessary. This StackOverflow post has more details. This won’t render in html for now because I have not added org support to pygments.
<<html-headers>>