fix: add null checks and error handling to docs JS controllers

clipboard_controller.js:
- Check if clipboard API is available before using
- Handle clipboard write promise rejection
- Show error icon on failure

prev-next_controller.js:
- Guard against missing navigation element
- Guard against missing span element in links

anchor_controller.js:
- Guard against missing ul element
This commit is contained in:
Younes ENNAJI
2026-03-01 20:11:07 +00:00
parent 162ea87330
commit 30de24f054
3 changed files with 29 additions and 3 deletions
@@ -15,6 +15,12 @@ export default class extends Controller {
createAnchorNavigation() { createAnchorNavigation() {
const ul = this.container.querySelector('ul') const ul = this.container.querySelector('ul')
// Guard against missing ul element
if (!ul) {
return
}
const anchors = document.querySelectorAll('#main-article h3, #main-article h2, #main-article a.anchor') const anchors = document.querySelectorAll('#main-article h3, #main-article h2, #main-article a.anchor')
if (anchors.length === 0) { if (anchors.length === 0) {
@@ -20,7 +20,7 @@ export default class extends Controller {
parent.append(button) parent.append(button)
button.addEventListener('click', () => { button.addEventListener('click', async () => {
let code = codeBlock.textContent.trim() let code = codeBlock.textContent.trim()
if (code.startsWith('#')) { if (code.startsWith('#')) {
const parts = code.split('\n') const parts = code.split('\n')
@@ -28,9 +28,19 @@ export default class extends Controller {
code = parts.join('\n') code = parts.join('\n')
} }
window.navigator.clipboard.writeText(code) // Check if clipboard API is available
if (!window.navigator?.clipboard?.writeText) {
console.warn('Clipboard API not available')
return
}
button.innerHTML = '<i class="fa-duotone fa-clipboard-check"></i>' try {
await window.navigator.clipboard.writeText(code)
button.innerHTML = '<i class="fa-duotone fa-clipboard-check"></i>'
} catch (error) {
console.error('Failed to copy to clipboard:', error)
button.innerHTML = '<i class="fa-duotone fa-clipboard-question"></i>'
}
setTimeout(() => { setTimeout(() => {
button.innerHTML = icon button.innerHTML = icon
@@ -4,6 +4,12 @@ export default class extends Controller {
connect() { connect() {
const prevNext = document.querySelectorAll('.prev-next') const prevNext = document.querySelectorAll('.prev-next')
const navigation = document.getElementById('main-navigation') const navigation = document.getElementById('main-navigation')
// Guard against missing navigation element
if (!navigation) {
return
}
const navigationLinks = navigation.querySelectorAll('a') const navigationLinks = navigation.querySelectorAll('a')
let previous let previous
@@ -15,6 +21,10 @@ export default class extends Controller {
links.forEach((link) => { links.forEach((link) => {
const label = link.querySelector('span') const label = link.querySelector('span')
// Guard against missing span element
if (!label) {
return
}
label.innerHTML = originalLink.innerHTML.replace(/\d+\. /, '').replace(/<(\S*?)[^>]*>.*?<\/\1>|<.*?\/>/, '') label.innerHTML = originalLink.innerHTML.replace(/\d+\. /, '').replace(/<(\S*?)[^>]*>.*?<\/\1>|<.*?\/>/, '')
link.href = originalLink.href link.href = originalLink.href
link.classList.remove('hidden') link.classList.remove('hidden')