feat(wiki): 新增 GHC06 任务页与图库发布体系,级联更新既有页面
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
if (window.__kspMissionGalleryRuntimeV1) { return; }
|
||||
window.__kspMissionGalleryRuntimeV1 = true;
|
||||
|
||||
var selector = '.wiki-article .gallery-grid img[data-wiki-asset]';
|
||||
var overlay = document.createElement('div');
|
||||
overlay.className = 'wiki-image-lightbox';
|
||||
overlay.hidden = true;
|
||||
overlay.innerHTML = '<figure class="wiki-image-lightbox-panel" role="dialog" aria-modal="true" aria-label="Mission gallery image preview">' +
|
||||
'<button class="wiki-image-lightbox-close" type="button" aria-label="Close image preview">×</button>' +
|
||||
'<button class="wiki-image-lightbox-nav wiki-image-lightbox-prev" type="button" aria-label="Previous image">‹</button>' +
|
||||
'<img alt="">' +
|
||||
'<button class="wiki-image-lightbox-nav wiki-image-lightbox-next" type="button" aria-label="Next image">›</button>' +
|
||||
'<span class="wiki-image-lightbox-counter" aria-live="polite"></span>' +
|
||||
'<figcaption class="thumbcaption"></figcaption></figure>';
|
||||
|
||||
var previewImage = overlay.querySelector('img');
|
||||
var previewCaption = overlay.querySelector('figcaption');
|
||||
var counter = overlay.querySelector('.wiki-image-lightbox-counter');
|
||||
var closeButton = overlay.querySelector('.wiki-image-lightbox-close');
|
||||
var previousButton = overlay.querySelector('.wiki-image-lightbox-prev');
|
||||
var nextButton = overlay.querySelector('.wiki-image-lightbox-next');
|
||||
var images = [];
|
||||
var activeIndex = 0;
|
||||
var lastTrigger = null;
|
||||
|
||||
function captionFor(image) {
|
||||
var container = image.closest('.gallery-item, figure, td, tr, .infobox-image');
|
||||
var caption = container && container.querySelector('.thumbcaption');
|
||||
return caption ? caption.textContent.trim() : (image.alt || '');
|
||||
}
|
||||
|
||||
function enhanceImages(root) {
|
||||
var scope = root && root.querySelectorAll ? root : document;
|
||||
Array.prototype.forEach.call(scope.querySelectorAll(selector), function (image) {
|
||||
image.tabIndex = 0;
|
||||
image.setAttribute('role', 'button');
|
||||
image.setAttribute('aria-label', 'Open image preview: ' + (image.alt || 'mission image'));
|
||||
var article = image.closest('.wiki-article');
|
||||
if (article) { article.dataset.galleryLightboxReady = '1'; }
|
||||
});
|
||||
}
|
||||
|
||||
function render(index) {
|
||||
activeIndex = (index + images.length) % images.length;
|
||||
var image = images[activeIndex];
|
||||
previewImage.src = image.dataset.wikiAsset || image.currentSrc || image.src;
|
||||
previewImage.alt = image.alt || '';
|
||||
previewCaption.textContent = captionFor(image);
|
||||
counter.textContent = (activeIndex + 1) + ' / ' + images.length;
|
||||
previousButton.hidden = images.length < 2;
|
||||
nextButton.hidden = images.length < 2;
|
||||
}
|
||||
|
||||
function openPreview(image, event) {
|
||||
var article = image.closest('.wiki-article');
|
||||
images = Array.prototype.slice.call(article.querySelectorAll('.gallery-grid img[data-wiki-asset]'));
|
||||
if (!images.length) { return; }
|
||||
if (event) { event.preventDefault(); event.stopPropagation(); }
|
||||
lastTrigger = image;
|
||||
render(images.indexOf(image));
|
||||
overlay.hidden = false;
|
||||
document.body.classList.add('wiki-image-lightbox-open');
|
||||
closeButton.focus();
|
||||
}
|
||||
|
||||
function closePreview() {
|
||||
overlay.hidden = true;
|
||||
previewImage.removeAttribute('src');
|
||||
document.body.classList.remove('wiki-image-lightbox-open');
|
||||
if (lastTrigger && lastTrigger.isConnected) { lastTrigger.focus(); }
|
||||
}
|
||||
|
||||
document.body.appendChild(overlay);
|
||||
enhanceImages(document);
|
||||
|
||||
document.addEventListener('click', function (event) {
|
||||
var image = event.target.closest && event.target.closest(selector);
|
||||
if (image) { openPreview(image, event); }
|
||||
});
|
||||
document.addEventListener('keydown', function (event) {
|
||||
if (!overlay.hidden) {
|
||||
if (event.key === 'Escape') { closePreview(); }
|
||||
if (event.key === 'ArrowLeft') { render(activeIndex - 1); }
|
||||
if (event.key === 'ArrowRight') { render(activeIndex + 1); }
|
||||
return;
|
||||
}
|
||||
if ((event.key === 'Enter' || event.key === ' ') && document.activeElement.matches(selector)) {
|
||||
openPreview(document.activeElement, event);
|
||||
}
|
||||
});
|
||||
previousButton.addEventListener('click', function () { render(activeIndex - 1); });
|
||||
nextButton.addEventListener('click', function () { render(activeIndex + 1); });
|
||||
closeButton.addEventListener('click', closePreview);
|
||||
overlay.addEventListener('click', function (event) {
|
||||
if (event.target === overlay) { closePreview(); }
|
||||
});
|
||||
|
||||
new MutationObserver(function (mutations) {
|
||||
mutations.forEach(function (mutation) {
|
||||
Array.prototype.forEach.call(mutation.addedNodes, function (node) {
|
||||
if (node.nodeType === 1) { enhanceImages(node); }
|
||||
});
|
||||
});
|
||||
}).observe(document.body, { childList: true, subtree: true });
|
||||
}());
|
||||
Reference in New Issue
Block a user