in DS, they have a footer that makes the website have a width larger than viewport (creating horizontal scroll); this case was not handled well by the gaufre on mobile. This rather rare case is now handled and the gaufre doesn't care of the size of other content now.
249 lines
8.3 KiB
JavaScript
249 lines
8.3 KiB
JavaScript
;(function () {
|
|
const BUTTON_CLASS = "js-lasuite-gaufre-btn"
|
|
const POPUP_ID = "lasuite-gaufre-popup"
|
|
const DIMENSIONS = { width: 304, height: 352, margin: 8 }
|
|
|
|
let lastFocusedButton = null
|
|
|
|
window.document.documentElement.classList.add("lasuite--gaufre-loaded")
|
|
|
|
if ("requestIdleCallback" in window) {
|
|
requestIdleCallback(() => {
|
|
appendPopup()
|
|
enhanceButtonsA11y()
|
|
})
|
|
}
|
|
|
|
const enhanceButtonsA11y = () => {
|
|
const buttons = document.querySelectorAll(`.${BUTTON_CLASS}`)
|
|
buttons.forEach((b) => {
|
|
b.setAttribute("aria-controls", POPUP_ID)
|
|
b.setAttribute("aria-expanded", "false")
|
|
})
|
|
}
|
|
|
|
document.body.addEventListener("click", (event) => {
|
|
if (!event.target.classList || !event.target.classList.contains(BUTTON_CLASS)) {
|
|
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(`#${POPUP_ID}.lasuite--gaufre-opened`)
|
|
if (!popup) {
|
|
return
|
|
}
|
|
const button = document.querySelector(`.${BUTTON_CLASS}.lasuite--gaufre-opened`)
|
|
if (!button) {
|
|
return
|
|
}
|
|
updatePopupStyle(popup, button)
|
|
})
|
|
|
|
const appendPopup = () => {
|
|
if (document.getElementById(POPUP_ID)) {
|
|
return Promise.resolve(document.getElementById(POPUP_ID))
|
|
}
|
|
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 = POPUP_ID
|
|
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
|
|
return 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 = addStatisticsParams(popupDocument.body)
|
|
document.body.appendChild(popup)
|
|
return popup
|
|
})
|
|
}
|
|
|
|
const getPopupCoords = (button) => {
|
|
const buttonCoords = button.getBoundingClientRect()
|
|
|
|
const documentWidth = document.body.clientWidth
|
|
const spaceLeft = buttonCoords.left + window.scrollX
|
|
const spaceRight = documentWidth - buttonCoords.right + window.scrollX
|
|
const hasHorizontalSpace = spaceLeft > DIMENSIONS.width || spaceRight > DIMENSIONS.width
|
|
let modalMode = false
|
|
|
|
// by default, the popup is displayed anchored to the right of the button (taking space on the left)
|
|
let leftPos = buttonCoords.right - DIMENSIONS.width + document.documentElement.scrollLeft
|
|
let isAnchoredToRight = true
|
|
// if there is not enough space on the left, or if there is more space on the right,
|
|
// we anchor it to the left of the button, taking space on the right
|
|
if (spaceLeft < DIMENSIONS.width || spaceRight > spaceLeft) {
|
|
leftPos = buttonCoords.left + document.documentElement.scrollLeft
|
|
isAnchoredToRight = false
|
|
}
|
|
// if there is no space at all, we use a "modal" mode, taking all the screen space
|
|
if (!hasHorizontalSpace) {
|
|
modalMode = true
|
|
}
|
|
|
|
const spaceTop = buttonCoords.top
|
|
const spaceBottom = window.innerHeight - buttonCoords.bottom
|
|
const hasVerticalSpace = spaceTop > DIMENSIONS.height || spaceBottom > DIMENSIONS.height
|
|
// by default, the popup is displayed anchored to the bottom of the button (taking space on the bottom)
|
|
let topPos = buttonCoords.bottom + 8 + document.documentElement.scrollTop
|
|
// if there is not enough space on the bottom, or if there is more space on the top,
|
|
// we anchor it to the top of the button, taking space on the top
|
|
if (spaceBottom < DIMENSIONS.height || spaceTop > spaceBottom) {
|
|
topPos =
|
|
buttonCoords.top -
|
|
DIMENSIONS.height -
|
|
DIMENSIONS.margin +
|
|
document.documentElement.scrollTop
|
|
}
|
|
|
|
// if there is no space below or above the button, but there is space on the sides,
|
|
// we show the popup next to the button
|
|
if (!hasVerticalSpace && window.innerHeight > DIMENSIONS.height) {
|
|
topPos = (window.innerHeight - DIMENSIONS.height) / 2
|
|
leftPos = isAnchoredToRight
|
|
? leftPos - buttonCoords.width - DIMENSIONS.margin
|
|
: leftPos + buttonCoords.width + DIMENSIONS.margin
|
|
}
|
|
|
|
// if there is no space at all, we use a "modal" mode, taking all the screen space
|
|
if (!hasVerticalSpace && window.innerHeight <= DIMENSIONS.height) {
|
|
modalMode = true
|
|
}
|
|
|
|
return {
|
|
modalMode,
|
|
top: !modalMode ? topPos : null,
|
|
left: !modalMode ? leftPos : null,
|
|
}
|
|
}
|
|
|
|
const defaultPopupStyle = `
|
|
border: 0 !important;
|
|
display: block !important;
|
|
z-index: 100000;
|
|
box-sizing: border-box !important;
|
|
`
|
|
|
|
const getPopupPositionStyle = (coords) => {
|
|
if (coords.modalMode) {
|
|
return `
|
|
${defaultPopupStyle}
|
|
position: fixed !important;
|
|
top: 0;
|
|
left: 0;
|
|
bottom: 0;
|
|
right: 0;
|
|
width: 100%;
|
|
width: 100svw;
|
|
height: 100%;
|
|
height: 100svh;
|
|
margin: 0;
|
|
`
|
|
}
|
|
return `
|
|
${defaultPopupStyle}
|
|
position: absolute !important;
|
|
top: ${coords.top}px !important;
|
|
left: ${coords.left}px !important;
|
|
max-width: calc(100vw - 30px);
|
|
width: ${DIMENSIONS.width}px;
|
|
height: ${DIMENSIONS.height}px;
|
|
margin: 0;
|
|
`
|
|
}
|
|
|
|
const updatePopupStyle = (popup, button) => {
|
|
const popupCoords = getPopupCoords(button)
|
|
popup.style.cssText = getPopupPositionStyle(popupCoords)
|
|
popup.classList[popupCoords.modalMode ? "add" : "remove"]("lasuite--gaufre-modal")
|
|
window.document.documentElement.classList[popupCoords.modalMode ? "add" : "remove"](
|
|
"lasuite--gaufre-modal-opened",
|
|
)
|
|
}
|
|
|
|
const showPopup = (button) => {
|
|
let popup = document.getElementById(POPUP_ID)
|
|
const show = (el) => {
|
|
updatePopupStyle(el, button)
|
|
el.classList.add("lasuite--gaufre-opened")
|
|
button.setAttribute("aria-expanded", "true")
|
|
lastFocusedButton = button
|
|
setTimeout(() => {
|
|
el.querySelector(".js-lagaufre-keyboard-anchor").focus()
|
|
}, 0)
|
|
}
|
|
if (popup) {
|
|
show(popup)
|
|
} else {
|
|
appendPopup().then(show)
|
|
}
|
|
}
|
|
|
|
const hidePopup = () => {
|
|
const popup = document.getElementById(POPUP_ID)
|
|
if (popup) {
|
|
popup.style.cssText = "display: none !important"
|
|
popup.classList.remove("lasuite--gaufre-opened")
|
|
}
|
|
document.querySelectorAll(`.${BUTTON_CLASS}`).forEach((b) => {
|
|
b.classList.remove("lasuite--gaufre-opened")
|
|
b.setAttribute("aria-expanded", "false")
|
|
})
|
|
if (lastFocusedButton) {
|
|
lastFocusedButton.focus()
|
|
lastFocusedButton = null
|
|
}
|
|
window.document.documentElement.classList.remove("lasuite--gaufre-modal-opened")
|
|
}
|
|
|
|
const addStatisticsParams = (popupBody) => {
|
|
const serviceAnchors = popupBody.querySelectorAll(".lagaufre-service__name")
|
|
const currentHostname = new URL(window.location.href).hostname
|
|
const currentHostnameInGaufre = Array.from(serviceAnchors).find(
|
|
(anchor) => new URL(anchor.href).hostname === currentHostname,
|
|
)
|
|
const currentServiceId = currentHostnameInGaufre
|
|
? currentHostnameInGaufre.getAttribute("data-gaufre-service-id")
|
|
: null
|
|
if (!currentServiceId) {
|
|
return popupBody.innerHTML
|
|
}
|
|
serviceAnchors.forEach((anchor) => {
|
|
const url = new URL(anchor.href)
|
|
url.searchParams.set("mtm_campaign", `${currentServiceId}-gaufre`)
|
|
url.searchParams.set("utm_source", `${currentServiceId}-gaufre`)
|
|
anchor.href = url.toString()
|
|
})
|
|
return popupBody.innerHTML
|
|
}
|
|
})()
|