Files
integration/website/public/api/v1/gaufre.js
Emmanuel Pelletier 087bc5a889 api/gaufre: stop using an iframe
iframe was great because we controlled our page context to style things
easily, handle assets easily.

But since it's not on the same domain as the services consuming it, it
implied configuration here and there. Also some behaviors were annoying
to implement (for example, keyboard navigation). I'm sure everything we
do is possible via iframe but I feel like I'll go from barrier to
barrier at every new thing we want to do…

I feel like, at the cost of handling style-conflicts, just rendering
everything in the real page context is more future-proof.
2024-05-07 21:59:58 +02:00

126 lines
3.8 KiB
JavaScript

;(function () {
const BUTTON_CLASS = "js-lasuite-gaufre-btn"
let lastFocusedButton = null
if ("requestIdleCallback" in window) {
requestIdleCallback(() => {
appendPopup()
})
}
document.body.addEventListener("click", (event) => {
if (!event.target.classList || !event.target.classList.contains(BUTTON_CLASS)) {
const buttons = document.querySelectorAll(`.${BUTTON_CLASS}`)
buttons.forEach((b) => b.classList.remove("lasuite--gaufre-opened"))
hidePopup()
return
}
const button = event.target
button.classList.toggle("lasuite--gaufre-opened")
if (button.classList.contains("lasuite--gaufre-opened")) {
showPopup(button)
} else {
hidePopup()
}
})
document.addEventListener("keyup", (event) => {
if (event.key === "Escape" && document.activeElement.closest(".lagaufre")) {
hidePopup()
}
})
window.addEventListener("resize", () => {
const popup = document.querySelector(`#lasuite-gaufre-popup.lasuite--gaufre-opened`)
if (!popup) {
return
}
const button = document.querySelector(`.${BUTTON_CLASS}.lasuite--gaufre-opened`)
if (!button) {
return
}
popup.style.cssText = getPopupPositionStyle(button)
})
const appendPopup = () => {
if (document.querySelector(`#lasuite-gaufre-popup`)) {
return
}
const scriptTag = document.querySelector(`#lasuite-gaufre-script`)
if (!scriptTag) {
console.log(
"La Suite numérique: Gaufre script tag not found, make sure the script has id 'lasuite-gaufre-script'.",
)
return
}
const popup = document.createElement("div")
popup.id = "lasuite-gaufre-popup"
popup.width = "304"
popup.height = "360"
popup.style.cssText = "display: none !important"
const { host, protocol, searchParams, origin } = new URL(scriptTag.src)
const local = searchParams.get("type") === "local"
const lang = ["en"].includes(searchParams.get("lang")) ? searchParams.get("lang") : null
fetch(
`${protocol}//${host}/api/v1/${(!!lang && `${lang}/`) || ""}gaufre${(!!local && "/local") || ""}`,
)
.then((res) => res.text())
.then((html) => {
html = html.replace(/(src=|href=|url\()"\//g, `$1"${origin}/`)
const parser = new DOMParser()
const popupDocument = parser.parseFromString(html, "text/html")
popup.innerHTML = popupDocument.body.innerHTML
document.body.appendChild(popup)
})
}
const getPopupPositionStyle = (button) => {
const buttonCoords = button.getBoundingClientRect()
const isSmallScreen = window.innerWidth <= 400
return `
position: absolute !important;
top: ${buttonCoords.top + buttonCoords.height + 8}px;
${
isSmallScreen
? `
left: 5px;
right: 5px;
margin: 0 auto;
`
: `
left: ${buttonCoords.right - 304 + document.documentElement.scrollLeft}px;`
}
border: 0 !important;
display: block !important;
z-index: 100000;
`
}
const showPopup = (button) => {
const popup = document.querySelector(`#lasuite-gaufre-popup`)
if (!popup) {
appendPopup()
}
popup.style.cssText = getPopupPositionStyle(button)
popup.classList.add("lasuite--gaufre-opened")
lastFocusedButton = button
setTimeout(() => {
popup.querySelector(".js-lagaufre-keyboard-anchor").focus()
}, 0)
}
const hidePopup = () => {
const popup = document.querySelector(`#lasuite-gaufre-popup`)
if (popup) {
popup.style.cssText = "display: none !important"
popup.classList.remove("lasuite--gaufre-opened")
}
if (lastFocusedButton) {
lastFocusedButton.classList.remove("lasuite--gaufre-opened")
lastFocusedButton.focus()
lastFocusedButton = null
}
}
})()