/* Shared enhancement for .hhec-media-suite. No libraries or external APIs. */
(function () {
‘use strict’;
function safeImageURL(value) {
if (!value) return ”;
try {
var url = new URL(value, document.baseURI);
return /^https?:$/.test(url.protocol) ? url.href : ”;
} catch (_) { return ”; }
}
function boot() {
document.querySelectorAll(‘.hhec-media-suite’).forEach(function (root) {
if (root.dataset.hmsReady) return;
root.dataset.hmsReady = ‘true’;
var photos = Array.from(root.querySelectorAll(‘[data-hms-photo]’));
var dialog = root.querySelector(‘[data-hms-dialog]’);
var current = 0;
var opener = null;
var loadVersion = 0;
var savedScroll = null;
var image = dialog.querySelector(‘[data-hms-full-image]’);
var placeholder = dialog.querySelector(‘[data-hms-full-placeholder]’);
var number = dialog.querySelector(‘[data-hms-full-number]’);
var status = dialog.querySelector(‘[data-hms-full-status]’);
var caption = dialog.querySelector(‘[data-hms-caption]’);
var credit = dialog.querySelector(‘[data-hms-credit]’);
var counter = dialog.querySelector(‘[data-hms-counter]’);
var closer = dialog.querySelector(‘[data-hms-close]’);
var stage = dialog.querySelector(‘[data-hms-stage]’);
photos.forEach(function (photo, index) {
var src = safeImageURL(photo.dataset.thumb || photo.dataset.full);
if (src) {
var thumb = document.createElement(‘img’);
thumb.className = ‘hms-photo-img’;
thumb.alt = photo.dataset.alt || photo.dataset.caption || ‘Gallery photo ‘ + (index + 1);
thumb.width = 900;
thumb.height = 675;
thumb.loading = ‘lazy’;
thumb.decoding = ‘async’;
thumb.addEventListener(‘load’, function () {
photo.querySelector(‘.hms-photo-placeholder’).hidden = true;
photo.querySelector(‘.hms-photo-state’).textContent = ‘View photo’;
});
thumb.addEventListener(‘error’, function () {
thumb.hidden = true;
photo.querySelector(‘.hms-photo-state’).textContent = ‘Preview unavailable’;
});
thumb.src = src;
photo.querySelector(‘.hms-photo-media’).appendChild(thumb);
}
photo.setAttribute(‘aria-haspopup’, ‘dialog’);
photo.setAttribute(‘aria-controls’, dialog.id);
photo.addEventListener(‘click’, function () {
if (typeof dialog.showModal !== ‘function’) {
var full = safeImageURL(photo.dataset.full || photo.dataset.thumb);
if (full) window.open(full, ‘_blank’, ‘noopener,noreferrer’);
return;
}
opener = photo;
render(index);
savedScroll = {
x: window.scrollX,
y: window.scrollY,
overflow: document.documentElement.style.overflow,
paddingRight: document.documentElement.style.paddingRight
};
var scrollbar = window.innerWidth – document.documentElement.clientWidth;
if (scrollbar > 0) {
document.documentElement.style.paddingRight = (parseFloat(getComputedStyle(document.documentElement).paddingRight) + scrollbar) + ‘px’;
}
document.documentElement.style.overflow = ‘hidden’;
dialog.showModal();
closer.focus({ preventScroll: true });
});
});
function render(index) {
current = (index + photos.length) % photos.length;
var photo = photos[current];
var version = ++loadVersion;
var src = safeImageURL(photo.dataset.full || photo.dataset.thumb);
image.hidden = true;
image.onload = null;
image.onerror = null;
image.removeAttribute(‘src’);
placeholder.hidden = false;
number.textContent = String(current + 1).padStart(2, ‘0’);
status.textContent = src ? ‘Loading photo…’ : ‘Photo coming soon’;
caption.textContent = photo.dataset.caption || photo.querySelector(‘.hms-photo-name’).textContent;
credit.textContent = photo.dataset.credit ? ‘Photo: ‘ + photo.dataset.credit : ”;
credit.hidden = !photo.dataset.credit;
counter.textContent = (current + 1) + ‘ / ‘ + photos.length;
image.alt = photo.dataset.alt || caption.textContent;
if (!src) return;
image.onload = function () {
if (version !== loadVersion) return;
image.hidden = false;
placeholder.hidden = true;
};
image.onerror = function () {
if (version !== loadVersion) return;
image.hidden = true;
status.textContent = ‘Photo could not load’;
};
image.src = src;
}
closer.addEventListener(‘click’, function () { dialog.close(); });
dialog.querySelector(‘[data-hms-prev]’).addEventListener(‘click’, function () { render(current – 1); });
dialog.querySelector(‘[data-hms-next]’).addEventListener(‘click’, function () { render(current + 1); });
dialog.addEventListener(‘keydown’, function (event) {
if (event.key === ‘ArrowRight’) { event.preventDefault(); render(current + 1); }
if (event.key === ‘ArrowLeft’) { event.preventDefault(); render(current – 1); }
});
var backdropDown = false;
dialog.addEventListener(‘pointerdown’, function (event) {
var rect = dialog.getBoundingClientRect();
backdropDown = event.target === dialog && (event.clientX < rect.left || event.clientX > rect.right || event.clientY < rect.top || event.clientY > rect.bottom);
});
dialog.addEventListener(‘click’, function (event) {
var rect = dialog.getBoundingClientRect();
if (backdropDown && event.target === dialog && (event.clientX < rect.left || event.clientX > rect.right || event.clientY < rect.top || event.clientY > rect.bottom)) dialog.close();
backdropDown = false;
});
dialog.addEventListener(‘close’, function () {
++loadVersion;
image.onload = null;
image.onerror = null;
image.hidden = true;
image.removeAttribute(‘src’);
if (savedScroll) {
document.documentElement.style.overflow = savedScroll.overflow;
document.documentElement.style.paddingRight = savedScroll.paddingRight;
window.scrollTo(savedScroll.x, savedScroll.y);
savedScroll = null;
}
if (opener && opener.isConnected) opener.focus({ preventScroll: true });
});
var touchStart = null;
stage.addEventListener(‘touchstart’, function (event) {
touchStart = event.touches.length === 1 ? { x: event.touches[0].clientX, y: event.touches[0].clientY } : null;
}, { passive: true });
stage.addEventListener(‘touchend’, function (event) {
if (!touchStart || !event.changedTouches.length) return;
var dx = event.changedTouches[0].clientX – touchStart.x;
var dy = event.changedTouches[0].clientY – touchStart.y;
if (Math.abs(dx) > 60 && Math.abs(dx) > Math.abs(dy) * 1.5) render(current + (dx < 0 ? 1 : -1));
touchStart = null;
}, { passive: true });
stage.addEventListener('touchcancel', function () { touchStart = null; }, { passive: true });
root.querySelectorAll('[data-youtube-id]').forEach(function (shell) {
var id = shell.dataset.youtubeId.trim();
if (!/^[A-Za-z0-9_-]{11}$/.test(id)) return;
var title = shell.dataset.title || 'HHEC video';
var button = document.createElement('button');
button.type = 'button';
button.className = 'hms-video-load';
button.setAttribute('aria-label', 'Play ' + title);
var art = shell.querySelector('.hms-play-disc').cloneNode(true);
var posterURL = safeImageURL(shell.dataset.poster);
if (posterURL) {
var poster = document.createElement('img');
poster.src = posterURL;
poster.className = 'hms-video-poster';
poster.alt = '';
poster.loading = 'lazy';
poster.decoding = 'async';
poster.addEventListener('error', function () { poster.remove(); });
button.appendChild(poster);
}
var playText = document.createElement('span');
playText.className = 'hms-video-status';
playText.textContent = 'Play video';
button.append(art, playText);
shell.replaceChildren(button);
var card = shell.closest('article');
var cardStatus = card && card.querySelector('[data-hms-video-state]');
if (cardStatus) cardStatus.textContent = 'Ready to watch';
button.addEventListener('click', function () {
var frame = document.createElement('iframe');
frame.title = title;
frame.width = '640';
frame.height = '360';
frame.referrerPolicy = 'strict-origin-when-cross-origin';
frame.allow = 'autoplay; encrypted-media; picture-in-picture; fullscreen';
frame.allowFullscreen = true;
frame.tabIndex = 0;
frame.src = 'https://www.youtube.com/embed/' + id + '?autoplay=1&playsinline=1&rel=0';
shell.replaceChildren(frame);
frame.focus({ preventScroll: true });
});
});
});
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot, { once: true });
else boot();
})();