PageSourceSearch

https://docs.delivr.to/assets/js/lightbox.js

js delivr.to collected 2026-10-03 22:10:34 UTC 2,919 bytes, 97 lines download raw bytes

1/**
2 * Lightbox for themed images
3 * Opens expanded view when clicking themed-image-container elements
4 */
5(function () {
6  let overlay = null;
7
8  function open(container) {
9    var srcLight = container.getAttribute('data-lightbox-src-light');
10    var srcDark = container.getAttribute('data-lightbox-src-dark');
11    var alt = container.getAttribute('data-lightbox-alt') || '';
12
13    // Build overlay
14    overlay = document.createElement('div');
15    overlay.className = 'themed-image-lightbox';
16    overlay.setAttribute('role', 'dialog');
17    overlay.setAttribute('aria-label', alt);
18
19    var closeBtn = document.createElement('button');
20    closeBtn.className = 'lightbox-close';
21    closeBtn.setAttribute('aria-label', 'Close');
22    closeBtn.innerHTML = '✕';
23
24    var wrapper = document.createElement('div');
25    wrapper.className = 'lightbox-image-wrapper';
26
27    var imgLight = document.createElement('img');
28    imgLight.src = srcLight;
29    imgLight.alt = alt;
30    imgLight.className = 'lightbox-light';
31
32    var imgDark = document.createElement('img');
33    imgDark.src = srcDark;
34    imgDark.alt = alt;
35    imgDark.className = 'lightbox-dark';
36
37    wrapper.appendChild(imgDark);
38    wrapper.appendChild(imgLight);
39    overlay.appendChild(closeBtn);
40    overlay.appendChild(wrapper);
41    document.body.appendChild(overlay);
42
43    // Prevent background scroll
44    document.body.style.overflow = 'hidden';
45
46    // Trigger enter animation on next frame
47    requestAnimationFrame(function () {
48      overlay.classList.add('lightbox-visible');
49    });
50
51    // Close handlers
52    closeBtn.addEventListener('click', close);
53    overlay.addEventListener('click', function (e) {
54      if (e.target === overlay) close();
55    });
56    document.addEventListener('keydown', onKey);
57  }
58
59  function close() {
60    if (!overlay) return;
61
62    overlay.classList.remove('lightbox-visible');
63    document.body.style.overflow = '';
64
65    // Wait for exit animation then remove
66    overlay.addEventListener('transitionend', function handler() {
67      overlay.removeEventListener('transitionend', handler);
68      if (overlay && overlay.parentNode) {
69        overlay.parentNode.removeChild(overlay);
70      }
71      overlay = null;
72    });
73
74    document.removeEventListener('keydown', onKey);
75  }
76
77  function onKey(e) {
78    if (e.key === 'Escape') close();
79  }
80
81  // Bind to all themed image containers
82  document.addEventListener('click', function (e) {
83    var container = e.target.closest('.themed-image-container[data-lightbox-src-light]');
84    if (container) open(container);
85  });
86
87  // Keyboard support (Enter/Space on focused container)
88  document.addEventListener('keydown', function (e) {
89    if (e.key === 'Enter' || e.key === ' ') {
90      var container = e.target.closest('.themed-image-container[data-lightbox-src-light]');
91      if (container) {
92        e.preventDefault();
93        open(container);
94      }
95    }
96  });
97})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.