diff --git a/README.md b/README.md
index e110c8a5c..ee9bb8c34 100644
--- a/README.md
+++ b/README.md
@@ -370,6 +370,8 @@ docs: [
]
```
+On the JavaScript side, ExDoc emits the `"exdoc:loaded"` event. This event may be called multiple times, as you navigate across pages, so initialization that should happen only once must be conditional. We recommend external scripts to use `defer`, not `async`, as shown in the examples below.
+
### Rendering Math
If you write TeX-style math in your Markdown, such as `$\sum_{i}^{N} x_i$`, it ends up as raw text on the generated pages. To render expressions, we recommend using [KaTeX](https://katex.org/), a JavaScript library that turns expressions into graphics. To load and trigger KaTeX on every documentation page, we can insert the following HTML:
@@ -381,13 +383,17 @@ If you write TeX-style math in your Markdown, such as `$\sum_{i}^{N} x_i$`, it e
-
+
+
+
```
@@ -402,7 +408,7 @@ Snippets are also objects you may want to render in a special manner. For exampl
-
```
For more details and configuration options, see the [Mermaid usage docs](https://mermaid-js.github.io/mermaid/#/usage).
diff --git a/assets/js/content.js b/assets/js/content.js
index 8a2d5c698..e04f09eb0 100644
--- a/assets/js/content.js
+++ b/assets/js/content.js
@@ -6,8 +6,7 @@ import { settingsStore } from './settings-store'
* corresponding to the current documentation page.
*/
-window.addEventListener('swup:page:view', initialize)
-initialize()
+window.addEventListener('exdoc:loaded', initialize)
function initialize () {
const notebookPath = window.location.pathname.replace(/(\.html)?$/, '.livemd')
diff --git a/assets/js/copy-button.js b/assets/js/copy-button.js
index 2272d3546..a3171e9dd 100644
--- a/assets/js/copy-button.js
+++ b/assets/js/copy-button.js
@@ -8,8 +8,7 @@ let buttonTemplate
* Initializes copy buttons.
*/
-window.addEventListener('swup:page:view', initialize)
-initialize()
+window.addEventListener('exdoc:loaded', initialize)
function initialize () {
if (!('clipboard' in navigator)) return
diff --git a/assets/js/makeup.js b/assets/js/makeup.js
index cb867aa44..758255af2 100644
--- a/assets/js/makeup.js
+++ b/assets/js/makeup.js
@@ -6,8 +6,7 @@ const HIGHLIGHT_CLASS = 'hll'
* Sets up dynamic behaviour for code blocks processed with *makeup*.
*/
-window.addEventListener('swup:page:view', initialize)
-initialize()
+window.addEventListener('exdoc:loaded', initialize)
export function initialize () {
// Hovering over a delimiter (bracket, parenthesis, do/end)
diff --git a/assets/js/quick-switch.js b/assets/js/quick-switch.js
index c36ef034a..08ab4b340 100644
--- a/assets/js/quick-switch.js
+++ b/assets/js/quick-switch.js
@@ -74,8 +74,7 @@ const state = {
*/
if (!isEmbedded) {
- window.addEventListener('swup:page:view', initialize)
- initialize()
+ window.addEventListener('exdoc:loaded', initialize)
}
function initialize () {
diff --git a/assets/js/search-bar.js b/assets/js/search-bar.js
index 25e555c97..2e50e04e4 100644
--- a/assets/js/search-bar.js
+++ b/assets/js/search-bar.js
@@ -21,8 +21,7 @@ const SEARCH_CLOSE_BUTTON_SELECTOR = 'form.search-bar .search-close-button'
*/
if (!isEmbedded) {
- window.addEventListener('swup:page:view', initialize)
- initialize()
+ window.addEventListener('exdoc:loaded', initialize)
}
function initialize () {
diff --git a/assets/js/search-page.js b/assets/js/search-page.js
index a60b95c72..7f647b4bd 100644
--- a/assets/js/search-page.js
+++ b/assets/js/search-page.js
@@ -20,8 +20,7 @@ lunr.Pipeline.registerFunction(docTrimmerFunction, 'docTrimmer')
* Activates only on the `/search.html` page.
*/
-window.addEventListener('swup:page:view', initialize)
-initialize()
+window.addEventListener('exdoc:loaded', initialize)
function initialize () {
const pathname = window.location.pathname
diff --git a/assets/js/settings.js b/assets/js/settings.js
index e77cee4d7..4e21d82fe 100644
--- a/assets/js/settings.js
+++ b/assets/js/settings.js
@@ -26,8 +26,7 @@ const modalTabs = [
* Sets up the settings modal.
*/
-window.addEventListener('swup:page:view', initialize)
-initialize()
+window.addEventListener('exdoc:loaded', initialize)
function initialize () {
qsAll(SETTINGS_LINK_SELECTOR).forEach(element => {
diff --git a/assets/js/sidebar/sidebar-drawer.js b/assets/js/sidebar/sidebar-drawer.js
index 00bb25130..b6f0022c8 100644
--- a/assets/js/sidebar/sidebar-drawer.js
+++ b/assets/js/sidebar/sidebar-drawer.js
@@ -11,9 +11,7 @@ const SIDEBAR_TOGGLE_SELECTOR = '.sidebar-toggle'
const smallScreenQuery = window.matchMedia(`screen and (max-width: ${SMALL_SCREEN_BREAKPOINT}px)`)
if (!isEmbedded) {
- setDefaultSidebarState()
-
- window.addEventListener('swup:page:view', setDefaultSidebarState)
+ window.addEventListener('exdoc:loaded', setDefaultSidebarState)
const sidebar = document.getElementById('sidebar')
const sidebarToggle = qs(SIDEBAR_TOGGLE_SELECTOR)
@@ -49,6 +47,7 @@ if (!isEmbedded) {
sessionStorage.setItem(SIDEBAR_WIDTH_KEY, width)
document.body.style.setProperty('--sidebarWidth', `${width}px`)
})
+
// We observe on mousedown because we only care about user resize.
sidebar.addEventListener('mousedown', () => resizeObserver.observe(sidebar))
sidebar.addEventListener('mouseup', () => resizeObserver.unobserve(sidebar))
diff --git a/assets/js/sidebar/sidebar-list.js b/assets/js/sidebar/sidebar-list.js
index 5838d61f3..a76b0dfdf 100644
--- a/assets/js/sidebar/sidebar-list.js
+++ b/assets/js/sidebar/sidebar-list.js
@@ -89,9 +89,12 @@ export function initialize () {
})
window.addEventListener('hashchange', markCurrentHashInSidebar)
- window.addEventListener('swup:page:view', markCurrentHashInSidebar)
+ // We listen to swup:page:view event because we need to trigger
+ // markCurrentHashInSidebar() before scollNodeListToCurrentCategory.
+ window.addEventListener('swup:page:view', markCurrentHashInSidebar)
markCurrentHashInSidebar()
+
// Triggers layout, defer.
requestAnimationFrame(scrollNodeListToCurrentCategory)
}
diff --git a/assets/js/swup.js b/assets/js/swup.js
index b56789733..6f9fccd6b 100644
--- a/assets/js/swup.js
+++ b/assets/js/swup.js
@@ -3,6 +3,10 @@ import SwupA11yPlugin from '@swup/a11y-plugin'
import SwupProgressPlugin from '@swup/progress-plugin'
import { isEmbedded } from './globals'
+window.addEventListener('DOMContentLoaded', () => {
+ window.dispatchEvent(new Event('exdoc:loaded'))
+})
+
if (!isEmbedded && window.location.protocol !== 'file:') {
new Swup({
animationSelector: false,
@@ -15,4 +19,8 @@ if (!isEmbedded && window.location.protocol !== 'file:') {
linkSelector: 'a[href]:not([href^="/"]):not([href^="http"])',
plugins: [new SwupA11yPlugin(), new SwupProgressPlugin({delay: 500})]
})
+
+ window.addEventListener('swup:page:view', () => {
+ window.dispatchEvent(new Event('exdoc:loaded'))
+ })
}
diff --git a/assets/js/tabsets.js b/assets/js/tabsets.js
index 18d722f0a..6d60eb142 100644
--- a/assets/js/tabsets.js
+++ b/assets/js/tabsets.js
@@ -6,8 +6,7 @@ const TABSET_CLOSE_COMMENT = 'tabs-close'
const TABPANEL_HEADING_NODENAME = 'H3'
const TABSET_CONTAINER_CLASS = 'tabset'
-window.addEventListener('swup:page:view', initialize)
-initialize()
+window.addEventListener('exdoc:loaded', initialize)
function initialize () {
/** @type {[Node, [NodeList, HTMLElement[]][]][]} */
diff --git a/assets/js/tooltips/tooltips.js b/assets/js/tooltips/tooltips.js
index b37b756a7..8bb5ef1b5 100644
--- a/assets/js/tooltips/tooltips.js
+++ b/assets/js/tooltips/tooltips.js
@@ -40,8 +40,7 @@ const state = {
* Initializes tooltips handling.
*/
-window.addEventListener('swup:page:view', initialize)
-initialize()
+window.addEventListener('exdoc:loaded', initialize)
function initialize () {
qsAll(TOOLTIP_ACTIVATORS_SELECTOR).forEach(element => {