Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/jeffkreeftmeijer/ox-html-markdown-style-footnotes.el
ox-html-markdown-style-footnotes.el: Markdown-style footnotes for ox-html.el
https://github.com/jeffkreeftmeijer/ox-html-markdown-style-footnotes.el
emacs html org-mode org-mode-export
Last synced: 28 days ago
JSON representation
ox-html-markdown-style-footnotes.el: Markdown-style footnotes for ox-html.el
- Host: GitHub
- URL: https://github.com/jeffkreeftmeijer/ox-html-markdown-style-footnotes.el
- Owner: jeffkreeftmeijer
- License: gpl-3.0
- Created: 2023-05-03T16:27:19.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2023-05-28T20:29:00.000Z (over 1 year ago)
- Last Synced: 2024-10-20T02:44:29.325Z (3 months ago)
- Topics: emacs, html, org-mode, org-mode-export
- Language: Emacs Lisp
- Homepage: https://jeffkreeftmeijer.com/ox-html-markdown-style-footnotes/
- Size: 356 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# ox-html-markdown-style-footnotes: Markdown-style footnotes for ox-html.el
Ox-html-markdown-style footnotes is an Emacs extension that provides an option to export Org mode files to HTML with footnotes that resemble those typical in documents generated from Markdown files.
## Overview
```org
Hello, world![fn:1][fn:1] A footnote.
With a second paragraph.
```The Org document above produces the following footnotes when exported to HTML:
```html
Footnotes:
```Footnotes consist of a link back to the place the footnote was referenced in the document and a `
` with the footnote's contents. The contents div, being a block element, is printed on a seperate line unless the default styling is loaded. The styling makes the footnotes appear inline, which places them behind the footnote link, but also inlines each paragraph for multi-paragraph footnotes:![img](./before.png "Org's default footnote styling")
Some flavors of Markdown use [ordered lists for footnotes](https://www.markdownguide.org/extended-syntax/#footnotes). These don't rely on styling, and they don't inline paragraphs in the footnotes.
To use Markdown-style footnotes in Org, ox-html-markdown footnotes advises the `org-html-footnote-section` function to overwrite its implementation. This new function keeps most of the output the same, but uses an ordered list instead of nested `
` elements. It also uses a backlink with an arrow, which resembles the Markdown tradition:```html
```This results in footnotes with support for multiple paragraphs, that work without additional styling:
![img](./after.png "Footnotes with ox-html-markdown-style-footnotes")
## Implementation
In [Org mode 9.6.5](https://git.savannah.gnu.org/cgit/emacs/org-mode.git/tree/lisp/ox-html.el?h=release_9.6.5#n1858), the `org-html-footnote-section` looks like this:
```emacs-lisp
(defun org-html-footnote-section (info)
"Format the footnote section.
INFO is a plist used as a communication channel."
(pcase (org-export-collect-footnote-definitions info)
(`nil nil)
(definitions
(format
(plist-get info :html-footnotes-section)
(org-html--translate "Footnotes" info)
(format
"\n%s\n"
(mapconcat
(lambda (definition)
(pcase definition
(`(,n ,_ ,def)
(let ((inline? (not (org-element-map def org-element-all-elements
#'identity nil t)))
(anchor (org-html--anchor
(format "fn.%d" n)
n
(format " class=\"footnum\" href=\"#fnr.%d\" role=\"doc-backlink\"" n)
info))
(contents (org-trim (org-export-data def info))))
(format "%s %s\n"
(format (plist-get info :html-footnote-format) anchor)
(format "%s"
(if (not inline?) contents
(format "%s
"
contents))))))))
definitions
"\n"))))))
```The function returns nothing if there are no footnotes in the document, or uses the format set in `:html-footnotes-section` to print each footnote. The interesting part is executed for each footnote, and wraps each footnote in a `div` element with a link back to where the footnote is referenced from:
```emacs-lisp
(let ((inline? (not (org-element-map def org-element-all-elements
#'identity nil t)))
(anchor (org-html--anchor
(format "fn.%d" n)
n
(format " class=\"footnum\" href=\"#fnr.%d\" role=\"doc-backlink\"" n)
info))
(contents (org-trim (org-export-data def info))))
(format "%s %s\n"
(format (plist-get info :html-footnote-format) anchor)
(format "%s"
(if (not inline?) contents
(format "%s
"
contents)))))
```### Advising `org-html-footnote-section`
To override the footnotes function, first require `ox-html`, the HTML exporter:
```emacs-lisp
(require 'ox-html)
```Define the `org-html-markdown-style-footnotes` variable, which is used to enable and disable the package after it's included:
```emacs-lisp
(defgroup org-export-html-markdown-style-footnotes nil
"Options for org-html-markdown-style-footnotes."
:tag "Org HTML Markdown-style footnotes"
:group 'org-export
:version "24.4"
:package-version '(Org . "8.0"))(defcustom org-html-markdown-style-footnotes nil
"Non-nil means to use Markdown-style footnotes in the exported document."
:group 'org-export-html-markdown-style-footnotes
:version "24.4"
:package-version '(Org . "8.0")
:type 'boolean)
```Then, define an updated version of `org-html-footnote-section`, which is mostly a copy of the original. If the `org-html-markdown-style-footnotes` variable is non-nil, the updated copy is used, which is different from the original in multiple ways:
- It turns the footnote section into an ordered list by wrapping it in `
` tags
- It switches from a `` element to a list by wrapping each footnote in `- ` tags
- It moves the anchor link, which points back at the footnote reference, to the end of the footnote, and uses a Unicode arrow (↩︎) instead of the footnote's number
- Removes the logic checking if a footnote can be inlined, as it always prints the contents as-isThe updated copy is defined as `org-html-markdown-style-footnotes--section`:
```emacs-lisp
(defun org-html-markdown-style-footnotes--section (orig-fun info)
(if org-html-markdown-style-footnotes
(pcase (org-export-collect-footnote-definitions info)
(`nil nil)
(definitions
(format
(plist-get info :html-footnotes-section)
(org-html--translate "Footnotes" info)
(format
"\n%s
\n"
(mapconcat
(lambda (definition)
(pcase definition
(`(,n ,_ ,def)
(format
"- %s %s
\n"
n
(org-trim (org-export-data def info))
(format "↩︎" n)))))
definitions
"\n")))))
(funcall orig-fun info)))
```To replace the original, the new function is added as advice. The package includes functions to easily enable and disable itself through adding and removing its advice:
```emacs-lisp
;;;###autoload
(defun org-html-markdown-style-footnotes-add ()
(interactive)
(advice-add 'org-html-footnote-section
:around #'org-html-markdown-style-footnotes--section))(defun org-html-markdown-style-footnotes-remove ()
(interactive)
(advice-remove 'org-html-footnote-section
#'org-html-markdown-style-footnotes--section))
```The `:around` [advice strategy](https://www.gnu.org/software/emacs/manual/html_node/elisp/Advice-Combinators.html) is used instead of the more obvious `:override`, because it needs to be possible to disable the override through setting `org-html-markdown-style-footnotes` to `nil`. This isn't possible when using the `:override` strategy, which doesn't call the advice with a reference to the original function.
Finally, the package provides itself as `ox-html-markdown-style-footnotes`:
```emacs-lisp
(provide 'ox-html-markdown-style-footnotes)
```## Installation and usage
Ox-html-markdown-style-footnotes is currently not available through any of the package registries. Instead, install it from the git repository directly. Install the package with [use-package](https://github.com/jwiegley/use-package) and [straight.el](https://github.com/radian-software/straight.el), and enable it by calling `org-html-markdown-style-footnotes-add`:
```emacs-lisp
(use-package ox-md-title
:straight
(ox-html-markown-style-footnotes :type git :host codeberg :repo "jkreeftmeijer/ox-html-markdown-style-footnotes.el")
:config
(org-html-markdown-style-footnotes-add))
```After calling `org-html-markdown-style-footnotes-add`, set the `org-html-markdown-style-footnotes` variable to to enable the package while exporting:
```emacs-lisp
(let ((org-html-markdown-style-footnotes t))
(org-html-publish-to-html))
```## Contributing
The git repository for ox-html-markdown-style-footnotes.el is hosted on [Codeberg](https://codeberg.org/jkreeftmeijer/ox-html-markdown-style-footnotes.el), and mirrored on [GitHub](https://github.com/jeffkreeftmeijer/ox-html-markdown-style-footnotes.el). Contributions are welcome via either platform.
### Tests
Regression tests are written with [ERT](https://www.gnu.org/software/emacs/manual/html_mono/ert.html) and included in `test.el`. To run the tests in batch mode, use `scripts/test`, or run the emacs batch command directly:
```shell
emacs -batch -l ert -l test.el -f ert-run-tests-batch-and-exit
```### Screenshots
The README file for ox-html-markdown-style-footnotes includes screenshots to show what footnotes look like in an HTML page. A script is included to generate these in `scripts/screenshots.js`, which can be run by sourcing it in a shell:
```shell
./scripts/screenshots.js
```The script loads puppeteer, then launches a headless browser, navigates to `test/fixtures/footnote.html`, takes the screenshot, and closes the browser:
```js
const puppeteer = require('puppeteer');(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();await page.setViewport({
width: 800,
height: 200,
deviceScaleFactor: 4
});await page.goto(`file://${__dirname}/../test/fixtures/footnote.html`);
await page.waitForSelector('body');
body = await page.$('body');
await page.evaluate(() => { document.querySelector('body').style.padding = '32px'; });
await body.screenshot({path: "./before.png"});await page.goto(`file://${__dirname}/../test/fixtures/footnote-2.html`);
await page.waitForSelector('body');
body = await page.$('body');
await page.evaluate(() => { document.querySelector('body').style.padding = '32px'; });
await body.screenshot({path: "./after.png"});await page.close();
await browser.close();
})()
```