Skip to content
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
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ jobs:

- name: Format
run: npm run fmt:check

- name: Compile
run: npm run compile:check

- name: Build
run: npm run build
Expand Down
23 changes: 13 additions & 10 deletions src/Elastic.Documentation.Site/Assets/applies-switch.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
// TODO: refactor to typescript. this was copied from the tabs implementation

// @ts-check
import { $$ } from 'select-dom'

// Extra JS capability for selected applies switches to be synced
// The selection is stored in local storage so that it persists across page loads.

const as_id_to_elements = {}
const storageKeyPrefix = 'sphinx-design-applies-switch-id-'
const as_id_to_elements: { [key: string]: HTMLElement[] } = {}
const storageKeyPrefix = 'applies-switch-id-'

function create_key(el: HTMLElement) {
const syncId = el.getAttribute('data-sync-id')
Expand All @@ -22,16 +21,16 @@ function create_key(el: HTMLElement) {
function ready() {
// Find all applies switches with sync data

const groups = []
const groups: string[] = []

document.querySelectorAll('.applies-switch-label').forEach((label) => {
$$('.applies-switch-label').forEach((label) => {
if (label instanceof HTMLElement) {
const data = create_key(label)
if (data) {
const [group, id, key] = data

// add click event listener
label.onclick = onAppliesSwitchLabelClick
label.addEventListener('click', onAppliesSwitchLabelClick)

// store map of key to elements
if (!as_id_to_elements[key]) {
Expand Down Expand Up @@ -72,13 +71,17 @@ function ready() {
*
* @this {HTMLElement} - The element that was clicked.
*/
function onAppliesSwitchLabelClick() {
function onAppliesSwitchLabelClick(this: HTMLLabelElement) {
const data = create_key(this)
if (!data) return
const [group, id, key] = data
for (const label of as_id_to_elements[key]) {
if (label === this) continue
label.previousElementSibling.checked = true
if (label === this) {
continue
}
if (label.previousElementSibling instanceof HTMLInputElement) {
label.previousElementSibling.checked = true
}
}
window.sessionStorage.setItem(storageKeyPrefix + group, id)
}
Expand Down
3 changes: 3 additions & 0 deletions src/Elastic.Documentation.Site/Assets/copybutton.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
// This is copied from legacy. It works, but we should rework this if we ever need to change it
import { $$ } from 'select-dom'

const DOCUMENTATION_OPTIONS = {
Expand Down
2 changes: 2 additions & 0 deletions src/Elastic.Documentation.Site/Assets/eui-icons-cache.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck: EUI icons do not have types
import { icon as EuiIconVisualizeApp } from '@elastic/eui/es/components/icon/assets/app_visualize'
import { icon as EuiIconArrowDown } from '@elastic/eui/es/components/icon/assets/arrow_down'
import { icon as EuiIconArrowLeft } from '@elastic/eui/es/components/icon/assets/arrow_left'
Expand Down
5 changes: 5 additions & 0 deletions src/Elastic.Documentation.Site/Assets/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
declare module '@elastic/highlightjs-esql' {
import { LanguageFn } from 'highlight.js'
const esql: LanguageFn
export default esql
}
26 changes: 15 additions & 11 deletions src/Elastic.Documentation.Site/Assets/image-carousel.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { $$ } from 'select-dom'

class ImageCarousel {
private container: HTMLElement
private slides: HTMLElement[]
private indicators: HTMLElement[]
private prevButton: HTMLElement | null
private nextButton: HTMLElement | null
private slides: HTMLElement[] = []
private indicators: HTMLElement[] = []
private prevButton: HTMLElement | null = null
private nextButton: HTMLElement | null = null
private currentIndex: number = 0
private touchStartX: number = 0
private touchEndX: number = 0
Expand Down Expand Up @@ -245,9 +247,7 @@ export function initImageCarousel(): void {
if (!section) return

// First, collect all images we want in the carousel
const allImageLinks = Array.from(
section.querySelectorAll('a[href*="epr.elastic.co"]')
)
const allImageLinks = $$('a[href*="epr.elastic.co"]', section)

// Track URLs to prevent duplicates
const processedUrls = new Set()
Expand Down Expand Up @@ -329,7 +329,11 @@ export function initImageCarousel(): void {
parent.style.display = 'none'
break
}
parent = parent.parentElement

if (parent.parentElement) {
parent = parent.parentElement
}

maxAttempts--
}

Expand Down Expand Up @@ -397,9 +401,9 @@ export function initImageCarousel(): void {

// Helper to find a suitable container for an image
function findClosestContainer(
element: Element,
carousel: Element
): Element | null {
element: HTMLElement,
carousel: HTMLElement
): HTMLElement | null {
let current = element
while (
current &&
Expand Down
133 changes: 77 additions & 56 deletions src/Elastic.Documentation.Site/Assets/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ import { initTabs } from './tabs'
import { initTocNav } from './toc-nav'
import 'htmx-ext-head-support'
import 'htmx-ext-preload'
import katex from 'katex'
import * as katex from 'katex'
import { $, $$ } from 'select-dom'
import { UAParser } from 'ua-parser-js'

const { getOS } = new UAParser()
const isLazyLoadNavigationEnabled =
$('meta[property="docs:feature:lazy-load-navigation"]')?.content === 'true'

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type HtmxEvent = any

/**
* Initialize KaTeX math rendering for elements with class 'math'
*/
Expand Down Expand Up @@ -71,7 +74,7 @@ document.addEventListener('DOMContentLoaded', function () {
initMath()
})

document.addEventListener('htmx:load', function (event) {
document.addEventListener('htmx:load', function (event: HtmxEvent) {
initTocNav()
initHighlight()
initCopyButton()
Expand Down Expand Up @@ -99,14 +102,17 @@ document.addEventListener('htmx:load', function (event) {
})

// Don't remove style tags because they are used by the elastic global nav.
document.addEventListener('htmx:removingHeadElement', function (event) {
const tagName = event.detail.headElement.tagName
if (tagName === 'STYLE') {
event.preventDefault()
document.addEventListener(
'htmx:removingHeadElement',
function (event: HtmxEvent) {
const tagName = event.detail.headElement.tagName
if (tagName === 'STYLE') {
event.preventDefault()
}
}
})
)

document.addEventListener('htmx:beforeRequest', function (event) {
document.addEventListener('htmx:beforeRequest', function (event: HtmxEvent) {
if (
event.detail.requestConfig.verb === 'get' &&
event.detail.requestConfig.triggeringEvent
Expand All @@ -126,60 +132,75 @@ document.addEventListener('htmx:beforeRequest', function (event) {
}
})

document.body.addEventListener('htmx:oobBeforeSwap', function (event) {
// This is needed to scroll to the top of the page when the content is swapped
if (
event.target.id === 'main-container' ||
event.target.id === 'markdown-content' ||
event.target.id === 'content-container'
) {
window.scrollTo(0, 0)
document.body.addEventListener(
'htmx:oobBeforeSwap',
function (event: HtmxEvent) {
// This is needed to scroll to the top of the page when the content is swapped
if (
event.target?.id === 'main-container' ||
event.target?.id === 'markdown-content' ||
event.target?.id === 'content-container'
) {
window.scrollTo(0, 0)
}
}
})

document.body.addEventListener('htmx:pushedIntoHistory', function (event) {
const pagesNav = $('#pages-nav')
const currentNavItem = $$('.current', pagesNav)
currentNavItem.forEach((el) => {
el.classList.remove('current')
})
const navItems = $$('a[href="' + event.detail.path + '"]', pagesNav)
navItems.forEach((navItem) => {
navItem.classList.add('current')
})
})

document.body.addEventListener('htmx:responseError', function (event) {
// If you get a 404 error while clicking on a hx-get link, actually open the link
// This is needed because the browser doesn't update the URL when the response is a 404
// In production, cloudfront handles serving the 404 page.
// Locally, the DocumentationWebHost handles it.
// On previews, a generic 404 page is shown.
if (event.detail.xhr.status === 404) {
window.location.assign(event.detail.pathInfo.requestPath)
)

document.body.addEventListener(
'htmx:pushedIntoHistory',
function (event: HtmxEvent) {
const pagesNav = $('#pages-nav')
const currentNavItem = $$('.current', pagesNav)
currentNavItem.forEach((el) => {
el.classList.remove('current')
})
const navItems = $$('a[href="' + event.detail.path + '"]', pagesNav)
navItems.forEach((navItem) => {
navItem.classList.add('current')
})
}
})
)

document.body.addEventListener(
'htmx:responseError',
function (event: HtmxEvent) {
// If you get a 404 error while clicking on a hx-get link, actually open the link
// This is needed because the browser doesn't update the URL when the response is a 404
// In production, cloudfront handles serving the 404 page.
// Locally, the DocumentationWebHost handles it.
// On previews, a generic 404 page is shown.
if (event.detail.xhr.status === 404) {
window.location.assign(event.detail.pathInfo.requestPath)
}
}
)

// We add a query string to the get request to make sure the requested page is up to date
const docsBuilderVersion = $('body').dataset.docsBuilderVersion
document.body.addEventListener('htmx:configRequest', function (event) {
if (event.detail.verb === 'get') {
event.detail.parameters['v'] = docsBuilderVersion
const docsBuilderVersion = $('body')?.dataset.docsBuilderVersion
document.body.addEventListener(
'htmx:configRequest',
function (event: HtmxEvent) {
if (event.detail.verb === 'get' && docsBuilderVersion) {
event.detail.parameters['v'] = docsBuilderVersion
}
}
})
)

// Here we need to strip the v parameter from the URL so
// that the browser doesn't show the v parameter in the address bar
document.body.addEventListener('htmx:beforeHistoryUpdate', function (event) {
const params = new URLSearchParams(
event.detail.history.path.split('?')[1] ?? ''
)
params.delete('v')
const pathWithoutQueryString = event.detail.history.path.split('?')[0]
if (params.size === 0) {
event.detail.history.path = pathWithoutQueryString
} else {
event.detail.history.path =
pathWithoutQueryString + '?' + params.toString()
document.body.addEventListener(
'htmx:beforeHistoryUpdate',
function (event: HtmxEvent) {
const params = new URLSearchParams(
event.detail.history.path.split('?')[1] ?? ''
)
params.delete('v')
const pathWithoutQueryString = event.detail.history.path.split('?')[0]
if (params.size === 0) {
event.detail.history.path = pathWithoutQueryString
} else {
event.detail.history.path =
pathWithoutQueryString + '?' + params.toString()
}
}
})
)
21 changes: 14 additions & 7 deletions src/Elastic.Documentation.Site/Assets/pages-nav.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import { $, $$ } from 'select-dom'

function expandAllParents(navItem: HTMLElement) {
let parent = navItem?.closest('li')
let parent: HTMLLIElement | null | undefined = navItem?.closest('li')
while (parent) {
const input = parent.querySelector('input')
if (input) {
;(input as HTMLInputElement).checked = true
if (input instanceof HTMLInputElement) {
input.checked = true
}
parent = parent.parentElement?.closest('li')
}
}

function scrollCurrentNaviItemIntoView(nav: HTMLElement) {
const currentNavItem = $('.current', nav)
expandAllParents(currentNavItem)

if (currentNavItem) {
expandAllParents(currentNavItem)
}

if (currentNavItem && !isElementInViewport(nav, currentNavItem)) {
const navRect = nav.getBoundingClientRect()
const currentNavItemRect = currentNavItem.getBoundingClientRect()
Expand Down Expand Up @@ -65,10 +69,13 @@ export function initNav() {
}

const pagesDropdown = $('#pages-dropdown')
if (pagesDropdown) {
setDropdown(pagesDropdown)
}
const pageVersionDropdown = $('#page-version-dropdown')
setDropdown(pagesDropdown)
setDropdown(pageVersionDropdown)

if (pageVersionDropdown) {
setDropdown(pageVersionDropdown)
}
const navItems = $$(
'a[href="' +
window.location.pathname +
Expand Down
6 changes: 3 additions & 3 deletions src/Elastic.Documentation.Site/Assets/smooth-scroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { $$ } from 'select-dom'
export function initSmoothScroll() {
$$('#markdown-content a[href^="#"]').forEach((el) => {
el.addEventListener('click', (e) => {
const target = document.getElementById(
el.getAttribute('href').slice(1)
)
// Using ! because href is guaranteed to be present due to the selector
const id = el.getAttribute('href')!.slice(1) // remove the '#' character
const target = document.getElementById(id)
if (target) {
e.preventDefault()
target.scrollIntoView({ behavior: 'smooth' })
Expand Down
Loading
Loading