|
// retoor <retoor@molodetz.nl>
|
|
|
|
import { Component } from "./Component.js";
|
|
import { assetUrl } from "../assetVersion.js";
|
|
|
|
const LB_CSS_ID = "lightbox-css";
|
|
|
|
export class AppLightbox extends Component {
|
|
connectedCallback() {
|
|
if (this._built) {
|
|
return;
|
|
}
|
|
this._built = true;
|
|
this._ensureCss();
|
|
this.lastFocus = null;
|
|
this.bodyOverflow = "";
|
|
this.build();
|
|
this.bind();
|
|
}
|
|
|
|
_ensureCss() {
|
|
if (document.getElementById(LB_CSS_ID)) return;
|
|
const link = document.createElement("link");
|
|
link.id = LB_CSS_ID;
|
|
link.rel = "stylesheet";
|
|
link.href = assetUrl("/static/css/lightbox.css");
|
|
document.head.appendChild(link);
|
|
}
|
|
|
|
build() {
|
|
const overlay = document.createElement("div");
|
|
overlay.className = "lightbox-overlay";
|
|
overlay.setAttribute("role", "dialog");
|
|
overlay.setAttribute("aria-modal", "true");
|
|
overlay.setAttribute("aria-label", "Image viewer");
|
|
overlay.innerHTML =
|
|
'<button type="button" class="lightbox-close" aria-label="Close">×</button>' +
|
|
'<img class="lightbox-image" src="" alt="">';
|
|
this.appendChild(overlay);
|
|
|
|
this.overlay = overlay;
|
|
this.image = overlay.querySelector(".lightbox-image");
|
|
this.closeBtn = overlay.querySelector(".lightbox-close");
|
|
}
|
|
|
|
bind() {
|
|
this.overlay.addEventListener("click", (e) => {
|
|
if (e.target !== this.image) this.close();
|
|
});
|
|
this.closeBtn.addEventListener("click", () => this.close());
|
|
document.addEventListener("keydown", (e) => {
|
|
if (e.key === "Escape" && this.overlay.classList.contains("visible")) {
|
|
e.preventDefault();
|
|
this.close();
|
|
}
|
|
});
|
|
this.overlay.addEventListener("keydown", (e) => {
|
|
if (e.key === "Tab" && this.overlay.classList.contains("visible")) {
|
|
e.preventDefault();
|
|
this.closeBtn.focus();
|
|
}
|
|
});
|
|
document.addEventListener("click", (e) => {
|
|
const thumb = e.target.closest("img[data-lightbox]");
|
|
if (!thumb || thumb.closest("a")) return;
|
|
e.preventDefault();
|
|
this.open(thumb.dataset.full || thumb.currentSrc || thumb.src, { alt: thumb.alt });
|
|
});
|
|
}
|
|
|
|
open(src, options) {
|
|
const opts = options || {};
|
|
if (!src) return;
|
|
this.image.src = src;
|
|
this.image.alt = opts.alt || "Enlarged image";
|
|
this.lastFocus = document.activeElement;
|
|
this.bodyOverflow = document.body.style.overflow;
|
|
document.body.style.overflow = "hidden";
|
|
this.overlay.classList.add("visible");
|
|
setTimeout(() => this.closeBtn.focus(), 20);
|
|
}
|
|
|
|
close() {
|
|
this.overlay.classList.remove("visible");
|
|
this.image.src = "";
|
|
document.body.style.overflow = this.bodyOverflow;
|
|
if (this.lastFocus && this.lastFocus.focus) this.lastFocus.focus();
|
|
}
|
|
}
|
|
|
|
customElements.define("dp-lightbox", AppLightbox);
|