Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add exdoc:loaded event #2069

Merged
merged 7 commits into from
Jan 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 27 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -381,13 +383,17 @@ If you write TeX-style math in your Markdown, such as `$\sum_{i}^{N} x_i$`, it e
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex-copytex.min.css" rel="stylesheet" type="text/css">
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex-copytex.min.js" crossorigin="anonymous"></script>

<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"
onload="renderMathInElement(document.body, {
delimiters: [
{left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false},
]
});"></script>
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"></script>

<script>
window.addEventListener("exdoc:loaded", () => {
renderMathInElement(document.body, {
delimiters: [
{left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false},
]
})
})
</script>
```

Expand All @@ -402,7 +408,7 @@ Snippets are also objects you may want to render in a special manner. For exampl
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
window.addEventListener("exdoc:loaded", () => {
for (const codeEl of document.querySelectorAll("pre code.vega-lite")) {
try {
const preEl = codeEl.parentElement;
Expand All @@ -426,12 +432,19 @@ For more details and configuration options, see [vega/vega-embed](https://github
Similarly to the example above, if your Markdown includes Mermaid graph specification in `mermaid` code snippets:

```html
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/mermaid.min.js"></script>
<script>
function mermaidLoaded() {
mermaid.initialize({
startOnLoad: false,
theme: document.body.className.includes("dark") ? "dark" : "default"
});
let initialized = false;

window.addEventListener("exdoc:loaded", () => {
if (!initialized) {
mermaid.initialize({
startOnLoad: false,
theme: document.body.className.includes("dark") ? "dark" : "default"
});
initialized = true;
}

let id = 0;
for (const codeEl of document.querySelectorAll("pre code.mermaid")) {
const preEl = codeEl.parentElement;
Expand All @@ -445,9 +458,8 @@ Similarly to the example above, if your Markdown includes Mermaid graph specific
preEl.remove();
});
}
}
});
</script>
<script async src="https://cdn.jsdelivr.net/npm/[email protected]/dist/mermaid.min.js" onload="mermaidLoaded();"></script>
```

For more details and configuration options, see the [Mermaid usage docs](https://mermaid-js.github.io/mermaid/#/usage).
Expand Down
3 changes: 1 addition & 2 deletions assets/js/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
3 changes: 1 addition & 2 deletions assets/js/copy-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions assets/js/makeup.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 1 addition & 2 deletions assets/js/quick-switch.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ const state = {
*/

if (!isEmbedded) {
window.addEventListener('swup:page:view', initialize)
initialize()
window.addEventListener('exdoc:loaded', initialize)
}

function initialize () {
Expand Down
3 changes: 1 addition & 2 deletions assets/js/search-bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand Down
3 changes: 1 addition & 2 deletions assets/js/search-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions assets/js/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down
5 changes: 2 additions & 3 deletions assets/js/sidebar/sidebar-drawer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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))
Expand Down
5 changes: 4 additions & 1 deletion assets/js/sidebar/sidebar-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now duplicated and could be removed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. I will push it soon. And to be clear, the next line does:

  // Triggers layout, defer.
  requestAnimationFrame(scrollNodeListToCurrentCategory)

That would still be fine, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I can confirm this one breaks it and nothing is being marked on the sidebar. :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will ship a new version with this still using swup:page:view. If you have suggestions on how to unify it, it would be very welcome. :) Thank you ❤️

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I missed that this init is lazy and will always come after the first exdoc:loaded. Pushed changes to unify and make more clear in #2070


// Triggers layout, defer.
requestAnimationFrame(scrollNodeListToCurrentCategory)
}
Expand Down
8 changes: 8 additions & 0 deletions assets/js/swup.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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'))
})
}
3 changes: 1 addition & 2 deletions assets/js/tabsets.js
Original file line number Diff line number Diff line change
Expand Up @@ -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[]][]][]} */
Expand Down
3 changes: 1 addition & 2 deletions assets/js/tooltips/tooltips.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down